blob: 8230fb3928f6394dbe9ad48445a65378a38300d3 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040026#include "SkMSAN.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040031#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000032#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000033#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050034#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000035#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040037#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050047#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050050#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050051#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052
reede3b38ce2016-01-08 09:18:44 -080053#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050054#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080055
Mike Reed139e5e02017-03-08 11:29:33 -050056///////////////////////////////////////////////////////////////////////////////////////////////////
57
reedc83a2972015-07-16 07:40:45 -070058/*
59 * Return true if the drawing this rect would hit every pixels in the canvas.
60 *
61 * Returns false if
62 * - rect does not contain the canvas' bounds
63 * - paint is not fill
64 * - paint would blur or otherwise change the coverage of the rect
65 */
66bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
67 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070068 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
69 (int)kNone_ShaderOverrideOpacity,
70 "need_matching_enums0");
71 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
72 (int)kOpaque_ShaderOverrideOpacity,
73 "need_matching_enums1");
74 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
75 (int)kNotOpaque_ShaderOverrideOpacity,
76 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070077
78 const SkISize size = this->getBaseLayerSize();
79 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050080
81 // if we're clipped at all, we can't overwrite the entire surface
82 {
83 SkBaseDevice* base = this->getDevice();
84 SkBaseDevice* top = this->getTopDevice();
85 if (base != top) {
86 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
87 }
88 if (!base->clipIsWideOpen()) {
89 return false;
90 }
reedc83a2972015-07-16 07:40:45 -070091 }
92
93 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070094 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070095 return false; // conservative
96 }
halcanaryc5769b22016-08-10 07:13:21 -070097
98 SkRect devRect;
99 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
100 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700101 return false;
102 }
103 }
104
105 if (paint) {
106 SkPaint::Style paintStyle = paint->getStyle();
107 if (!(paintStyle == SkPaint::kFill_Style ||
108 paintStyle == SkPaint::kStrokeAndFill_Style)) {
109 return false;
110 }
111 if (paint->getMaskFilter() || paint->getLooper()
112 || paint->getPathEffect() || paint->getImageFilter()) {
113 return false; // conservative
114 }
115 }
116 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
117}
118
119///////////////////////////////////////////////////////////////////////////////////////////////////
120
reed@google.comda17f752012-08-16 18:27:05 +0000121// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122//#define SK_TRACE_SAVERESTORE
123
124#ifdef SK_TRACE_SAVERESTORE
125 static int gLayerCounter;
126 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
127 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
128
129 static int gRecCounter;
130 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
131 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
132
133 static int gCanvasCounter;
134 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
135 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
136#else
137 #define inc_layer()
138 #define dec_layer()
139 #define inc_rec()
140 #define dec_rec()
141 #define inc_canvas()
142 #define dec_canvas()
143#endif
144
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000145typedef SkTLazy<SkPaint> SkLazyPaint;
146
reedc83a2972015-07-16 07:40:45 -0700147void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000148 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700149 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
150 ? SkSurface::kDiscard_ContentChangeMode
151 : SkSurface::kRetain_ContentChangeMode);
152 }
153}
154
155void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
156 ShaderOverrideOpacity overrideOpacity) {
157 if (fSurfaceBase) {
158 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
159 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
160 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
161 // and therefore we don't care which mode we're in.
162 //
163 if (fSurfaceBase->outstandingImageSnapshot()) {
164 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
165 mode = SkSurface::kDiscard_ContentChangeMode;
166 }
167 }
168 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000169 }
170}
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000174/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 The clip/matrix/proc are fields that reflect the top of the save/restore
176 stack. Whenever the canvas changes, it marks a dirty flag, and then before
177 these are used (assuming we're not on a layer) we rebuild these cache
178 values: they reflect the top of the save stack, but translated and clipped
179 by the device's XY offset and bitmap-bounds.
180*/
181struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400182 DeviceCM* fNext;
183 sk_sp<SkBaseDevice> fDevice;
184 SkRasterClip fClip;
185 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
186 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400187 sk_sp<SkImage> fClipImage;
188 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000191 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700192 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400193 , fDevice(std::move(device))
194 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700195 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000196 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400197 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400198 {}
reed@google.com4b226022011-01-11 18:32:13 +0000199
mtkleinfeaadee2015-04-08 11:25:48 -0700200 void reset(const SkIRect& bounds) {
201 SkASSERT(!fPaint);
202 SkASSERT(!fNext);
203 SkASSERT(fDevice);
204 fClip.setRect(bounds);
205 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206};
207
208/* This is the record we keep for each save/restore level in the stack.
209 Since a level optionally copies the matrix and/or stack, we have pointers
210 for these fields. If the value is copied for this level, the copy is
211 stored in the ...Storage field, and the pointer points to that. If the
212 value is not copied for this level, we ignore ...Storage, and just point
213 at the corresponding value in the previous level in the stack.
214*/
215class SkCanvas::MCRec {
216public:
reed1f836ee2014-07-07 07:49:34 -0700217 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700218 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 /* If there are any layers in the stack, this points to the top-most
220 one that is at or below this level in the stack (so we know what
221 bitmap/device to draw into from this level. This value is NOT
222 reference counted, since the real owner is either our fLayer field,
223 or a previous one in a lower level.)
224 */
Mike Reeda1361362017-03-07 09:37:29 -0500225 DeviceCM* fTopLayer;
226 SkConservativeClip fRasterClip;
227 SkMatrix fMatrix;
228 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
Mike Reeda1361362017-03-07 09:37:29 -0500230 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700231 fFilter = nullptr;
232 fLayer = nullptr;
233 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800234 fMatrix.reset();
235 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700236
reedd9544982014-09-09 18:46:22 -0700237 // don't bother initializing fNext
238 inc_rec();
239 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400240 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700241 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700242 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700243 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 // don't bother initializing fNext
247 inc_rec();
248 }
249 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000250 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700251 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 dec_rec();
253 }
mtkleinfeaadee2015-04-08 11:25:48 -0700254
255 void reset(const SkIRect& bounds) {
256 SkASSERT(fLayer);
257 SkASSERT(fDeferredSaveCount == 0);
258
259 fMatrix.reset();
260 fRasterClip.setRect(bounds);
261 fLayer->reset(bounds);
262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263};
264
Mike Reeda1361362017-03-07 09:37:29 -0500265class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266public:
Mike Reeda1361362017-03-07 09:37:29 -0500267 SkDrawIter(SkCanvas* canvas)
268 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
269 {}
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000272 const DeviceCM* rec = fCurrLayer;
273 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400274 fDevice = rec->fDevice.get();
275 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700277 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 return true;
279 }
280 return false;
281 }
reed@google.com4b226022011-01-11 18:32:13 +0000282
reed@google.com6f8f2922011-03-04 22:27:10 +0000283 int getX() const { return fDevice->getOrigin().x(); }
284 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286
Mike Reed99330ba2017-02-22 11:01:08 -0500287 SkBaseDevice* fDevice;
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const DeviceCM* fCurrLayer;
291 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292};
293
Florin Malita713b8ef2017-04-28 10:57:24 -0400294#define FOR_EACH_TOP_DEVICE( code ) \
295 do { \
296 DeviceCM* layer = fMCRec->fTopLayer; \
297 while (layer) { \
298 SkBaseDevice* device = layer->fDevice.get(); \
299 if (device) { \
300 code; \
301 } \
302 layer = layer->fNext; \
303 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500304 } while (0)
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306/////////////////////////////////////////////////////////////////////////////
307
reeddbc3cef2015-04-29 12:18:57 -0700308static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
309 return lazy->isValid() ? lazy->get() : lazy->set(orig);
310}
311
312/**
313 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700314 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700315 */
reedd053ce92016-03-22 10:17:23 -0700316static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700317 SkImageFilter* imgf = paint.getImageFilter();
318 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700320 }
321
reedd053ce92016-03-22 10:17:23 -0700322 SkColorFilter* imgCFPtr;
323 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
reedd053ce92016-03-22 10:17:23 -0700326 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700327
328 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700330 // there is no existing paint colorfilter, so we can just return the imagefilter's
331 return imgCF;
332 }
333
334 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
335 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500336 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700337}
338
senorblanco87e066e2015-10-28 11:23:36 -0700339/**
340 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
341 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
342 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
343 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
344 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
345 * conservative "effective" bounds based on the settings in the paint... with one exception. This
346 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
347 * deliberately ignored.
348 */
349static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
350 const SkRect& rawBounds,
351 SkRect* storage) {
352 SkPaint tmpUnfiltered(paint);
353 tmpUnfiltered.setImageFilter(nullptr);
354 if (tmpUnfiltered.canComputeFastBounds()) {
355 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
356 } else {
357 return rawBounds;
358 }
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361class AutoDrawLooper {
362public:
senorblanco87e066e2015-10-28 11:23:36 -0700363 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
364 // paint. It's used to determine the size of the offscreen layer for filters.
365 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700366 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700367 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000368 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800369#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800371#else
372 fFilter = nullptr;
373#endif
reed4a8126e2014-09-22 07:29:03 -0700374 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000375 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700376 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000377 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378
reedd053ce92016-03-22 10:17:23 -0700379 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700380 if (simplifiedCF) {
381 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700382 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700383 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700384 fPaint = paint;
385 }
386
387 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700388 /**
389 * We implement ImageFilters for a given draw by creating a layer, then applying the
390 * imagefilter to the pixels of that layer (its backing surface/image), and then
391 * we call restore() to xfer that layer to the main canvas.
392 *
393 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
394 * 2. Generate the src pixels:
395 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
396 * return (fPaint). We then draw the primitive (using srcover) into a cleared
397 * buffer/surface.
398 * 3. Restore the layer created in #1
399 * The imagefilter is passed the buffer/surface from the layer (now filled with the
400 * src pixels of the primitive). It returns a new "filtered" buffer, which we
401 * draw onto the previous layer using the xfermode from the original paint.
402 */
reed@google.com8926b162012-03-23 15:36:36 +0000403 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500404 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700405 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700406 SkRect storage;
407 if (rawBounds) {
408 // Make rawBounds include all paint outsets except for those due to image filters.
409 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
410 }
reedbfd5f172016-01-07 11:28:08 -0800411 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700412 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700413 fTempLayerForImageFilter = true;
414 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000415 }
416
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000417 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500418 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000419 fIsSimple = false;
420 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700421 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000422 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700423 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000424 }
425 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700428 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000429 fCanvas->internalRestore();
430 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000431 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000433
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 const SkPaint& paint() const {
435 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400436 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000439
reed@google.com129ec222012-05-15 13:24:09 +0000440 bool next(SkDrawFilter::Type drawType) {
441 if (fDone) {
442 return false;
443 } else if (fIsSimple) {
444 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000445 return !fPaint->nothingToDraw();
446 } else {
447 return this->doNext(drawType);
448 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000449 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000450
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500452 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700453 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 SkCanvas* fCanvas;
455 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000456 SkDrawFilter* fFilter;
457 const SkPaint* fPaint;
458 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700459 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000460 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000461 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000462 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400463 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000464
465 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466};
467
reed@google.com129ec222012-05-15 13:24:09 +0000468bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700469 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000470 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700471 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000472
reeddbc3cef2015-04-29 12:18:57 -0700473 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
474 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400475 // never want our downstream clients (i.e. devices) to see loopers
476 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000477
reed5c476fb2015-04-20 08:04:21 -0700478 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700479 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700480 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000481 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000484 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000485 return false;
486 }
487 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000488 if (!fFilter->filter(paint, drawType)) {
489 fDone = true;
Mike Reed59af19f2018-04-12 17:26:40 -0400490 return false; // can we really do this, if we haven't finished fLooperContext?
reed@google.com971aca72012-11-26 20:26:54 +0000491 }
halcanary96fcdcc2015-08-27 07:41:13 -0700492 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000493 // no looper means we only draw once
494 fDone = true;
495 }
496 }
497 fPaint = paint;
498
499 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000500 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000501 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000502 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000503 return true;
504}
505
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506////////// macros to place around the internal draw calls //////////////////
507
reed3aafe112016-08-18 12:45:34 -0700508#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
509 this->predrawNotify(); \
510 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
511 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800512 SkDrawIter iter(this);
513
514
reed@google.com8926b162012-03-23 15:36:36 +0000515#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000516 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700517 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000518 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000519 SkDrawIter iter(this);
520
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000521#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000522 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700523 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000524 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000526
reedc83a2972015-07-16 07:40:45 -0700527#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
528 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700529 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700530 while (looper.next(type)) { \
531 SkDrawIter iter(this);
532
reed@google.com4e2b3d32011-04-07 14:18:59 +0000533#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
535////////////////////////////////////////////////////////////////////////////
536
msarettfbfa2582016-08-12 08:29:08 -0700537static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
538 if (bounds.isEmpty()) {
539 return SkRect::MakeEmpty();
540 }
541
542 // Expand bounds out by 1 in case we are anti-aliasing. We store the
543 // bounds as floats to enable a faster quick reject implementation.
544 SkRect dst;
545 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
546 return dst;
547}
548
mtkleinfeaadee2015-04-08 11:25:48 -0700549void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
550 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700551 fMCRec->reset(bounds);
552
553 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500554 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400555 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700556 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700557 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700558}
559
Herb Derbyefe39bc2018-05-01 17:06:20 -0400560void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800561 if (device && device->forceConservativeRasterClip()) {
562 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
563 }
reed42b73eb2015-11-20 13:42:42 -0800564
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000565 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800566 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700567 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000568
569 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500570 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500571 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700572 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573
reeda499f902015-05-01 09:34:31 -0700574 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
575 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400576 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700577
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579
halcanary96fcdcc2015-08-27 07:41:13 -0700580 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000581
reedf92c8662014-08-18 08:02:43 -0700582 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700583 // The root device and the canvas should always have the same pixel geometry
584 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800585 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700586 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500587
Mike Reedc42a1cd2017-02-14 14:25:14 -0500588 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700589 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590}
591
reed@google.comcde92112011-07-06 20:00:52 +0000592SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000593 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700594 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000595{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000596 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000597
halcanary96fcdcc2015-08-27 07:41:13 -0700598 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000599}
600
reed96a857e2015-01-25 10:33:58 -0800601SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800603 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000604{
605 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400606 this->init(sk_make_sp<SkNoPixelsDevice>(
607 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700608}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000609
reed78e27682014-11-19 08:04:34 -0800610SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700612 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700613{
614 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700615
Mike Reed566e53c2017-03-10 10:49:45 -0500616 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400617 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700618}
619
Herb Derbyefe39bc2018-05-01 17:06:20 -0400620SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000621 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700622 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000623{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700625
reedd9544982014-09-09 18:46:22 -0700626 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627}
628
Herb Derbyefe39bc2018-05-01 17:06:20 -0400629SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700630 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700631 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700632{
633 inc_canvas();
634
635 this->init(device, flags);
636}
637
reed4a8126e2014-09-22 07:29:03 -0700638SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700639 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700640 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700641{
642 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700643
Mike Reed910ca0f2018-04-25 13:04:05 -0400644 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400645 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700646}
reed29c857d2014-09-21 10:25:07 -0700647
Mike Reed356f7c22017-01-10 11:58:39 -0500648SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
649 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700650 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
651 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500652 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700653{
654 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700655
Mike Reed910ca0f2018-04-25 13:04:05 -0400656 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400657 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658}
659
Mike Reed356f7c22017-01-10 11:58:39 -0500660SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
661
Matt Sarett31f99ce2017-04-11 08:46:01 -0400662#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
663SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
666 , fAllocator(nullptr)
667{
668 inc_canvas();
669
670 SkBitmap tmp(bitmap);
671 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400672 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400673 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400674}
675#endif
676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677SkCanvas::~SkCanvas() {
678 // free up the contents of our deque
679 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000680
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681 this->internalRestore(); // restore the last, since we're going away
682
halcanary385fe4d2015-08-26 13:07:48 -0700683 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000684
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 dec_canvas();
686}
687
fmalita53d9f1c2016-01-25 06:23:54 -0800688#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689SkDrawFilter* SkCanvas::getDrawFilter() const {
690 return fMCRec->fFilter;
691}
692
693SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700694 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
696 return filter;
697}
fmalita77650002016-01-21 18:47:11 -0800698#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000700SkMetaData& SkCanvas::getMetaData() {
701 // metadata users are rare, so we lazily allocate it. If that changes we
702 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700703 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000704 fMetaData = new SkMetaData;
705 }
706 return *fMetaData;
707}
708
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709///////////////////////////////////////////////////////////////////////////////
710
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000711void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700712 this->onFlush();
713}
714
715void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000716 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000717 if (device) {
718 device->flush();
719 }
720}
721
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000722SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000723 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000724 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
725}
726
senorblancoafc7cce2016-02-02 18:44:15 -0800727SkIRect SkCanvas::getTopLayerBounds() const {
728 SkBaseDevice* d = this->getTopDevice();
729 if (!d) {
730 return SkIRect::MakeEmpty();
731 }
732 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
733}
734
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000735SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000737 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400739 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740}
741
Florin Malita0ed3b642017-01-13 16:56:38 +0000742SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400743 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000744}
745
Mike Reed353196f2017-07-21 11:01:18 -0400746bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000747 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400748 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000749}
750
Mike Reed353196f2017-07-21 11:01:18 -0400751bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
752 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400753}
754
755bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
756 SkPixmap pm;
757 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
758}
759
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000760bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400761 SkPixmap pm;
762 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700763 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000764 }
765 return false;
766}
767
Matt Sarett03dd6d52017-01-23 12:15:09 -0500768bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000769 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000770 SkBaseDevice* device = this->getDevice();
771 if (!device) {
772 return false;
773 }
774
Matt Sarett03dd6d52017-01-23 12:15:09 -0500775 // This check gives us an early out and prevents generation ID churn on the surface.
776 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
777 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
778 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
779 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000780 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000781
Matt Sarett03dd6d52017-01-23 12:15:09 -0500782 // Tell our owning surface to bump its generation ID.
783 const bool completeOverwrite =
784 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700785 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700786
Matt Sarett03dd6d52017-01-23 12:15:09 -0500787 // This can still fail, most notably in the case of a invalid color type or alpha type
788 // conversion. We could pull those checks into this function and avoid the unnecessary
789 // generation ID bump. But then we would be performing those checks twice, since they
790 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400791 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000792}
reed@google.com51df9e32010-12-23 19:29:18 +0000793
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794//////////////////////////////////////////////////////////////////////////////
795
reed2ff1fce2014-12-11 07:07:37 -0800796void SkCanvas::checkForDeferredSave() {
797 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800798 this->doSave();
799 }
800}
801
reedf0090cb2014-11-26 08:55:51 -0800802int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800803#ifdef SK_DEBUG
804 int count = 0;
805 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
806 for (;;) {
807 const MCRec* rec = (const MCRec*)iter.next();
808 if (!rec) {
809 break;
810 }
811 count += 1 + rec->fDeferredSaveCount;
812 }
813 SkASSERT(count == fSaveCount);
814#endif
815 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800816}
817
818int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800819 fSaveCount += 1;
820 fMCRec->fDeferredSaveCount += 1;
821 return this->getSaveCount() - 1; // return our prev value
822}
823
824void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800825 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700826
827 SkASSERT(fMCRec->fDeferredSaveCount > 0);
828 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800829 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800830}
831
832void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800833 if (fMCRec->fDeferredSaveCount > 0) {
834 SkASSERT(fSaveCount > 1);
835 fSaveCount -= 1;
836 fMCRec->fDeferredSaveCount -= 1;
837 } else {
838 // check for underflow
839 if (fMCStack.count() > 1) {
840 this->willRestore();
841 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700842 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800843 this->internalRestore();
844 this->didRestore();
845 }
reedf0090cb2014-11-26 08:55:51 -0800846 }
847}
848
849void SkCanvas::restoreToCount(int count) {
850 // sanity check
851 if (count < 1) {
852 count = 1;
853 }
mtkleinf0f14112014-12-12 08:46:25 -0800854
reedf0090cb2014-11-26 08:55:51 -0800855 int n = this->getSaveCount() - count;
856 for (int i = 0; i < n; ++i) {
857 this->restore();
858 }
859}
860
reed2ff1fce2014-12-11 07:07:37 -0800861void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700863 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000865
Mike Reedc42a1cd2017-02-14 14:25:14 -0500866 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867}
868
reed4960eee2015-12-18 07:09:18 -0800869bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400870 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871}
872
reed4960eee2015-12-18 07:09:18 -0800873bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700874 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500875 SkIRect clipBounds = this->getDeviceClipBounds();
876 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000877 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000878 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000879
reed96e657d2015-03-10 17:30:07 -0700880 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
881
Robert Phillips12078432018-05-17 11:17:39 -0400882 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
883 // If the image filter DAG affects transparent black then we will need to render
884 // out to the clip bounds
885 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000886 }
Robert Phillips12078432018-05-17 11:17:39 -0400887
888 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700889 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000890 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700891 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400892 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000893 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400894 inputSaveLayerBounds = clipBounds;
895 }
896
897 if (imageFilter) {
898 // expand the clip bounds by the image filter DAG to include extra content that might
899 // be required by the image filters.
900 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
901 SkImageFilter::kReverse_MapDirection,
902 &inputSaveLayerBounds);
903 }
904
905 SkIRect clippedSaveLayerBounds;
906 if (bounds) {
907 // For better or for worse, user bounds currently act as a hard clip on the layer's
908 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
909 clippedSaveLayerBounds = inputSaveLayerBounds;
910 } else {
911 // If there are no user bounds, we don't want to artificially restrict the resulting
912 // layer bounds, so allow the expanded clip bounds free reign.
913 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000914 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800915
916 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400917 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800918 if (BoundsAffectsClip(saveLayerFlags)) {
919 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
920 fMCRec->fRasterClip.setEmpty();
921 fDeviceClipBounds.setEmpty();
922 }
923 return false;
924 }
Robert Phillips12078432018-05-17 11:17:39 -0400925 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926
reed4960eee2015-12-18 07:09:18 -0800927 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700928 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400929 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
930 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000931 }
932
933 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400934 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000935 }
Robert Phillips12078432018-05-17 11:17:39 -0400936
junov@chromium.orga907ac32012-02-24 21:54:07 +0000937 return true;
938}
939
reed4960eee2015-12-18 07:09:18 -0800940int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
941 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000942}
943
reed70ee31b2015-12-10 13:44:45 -0800944int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800945 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
946}
947
Cary Clarke041e312018-03-06 13:00:52 -0500948int SkCanvas::saveLayer(const SaveLayerRec& rec) {
949 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800950 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500951 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800952 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800953}
954
reeda2217ef2016-07-20 06:04:34 -0700955void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500956 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500957 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700958 SkDraw draw;
959 SkRasterClip rc;
960 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
961 if (!dst->accessPixels(&draw.fDst)) {
962 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800963 }
reeda2217ef2016-07-20 06:04:34 -0700964 draw.fMatrix = &SkMatrix::I();
965 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800966
967 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500968 if (filter) {
969 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
970 }
reeda2217ef2016-07-20 06:04:34 -0700971
Mike Reedc42a1cd2017-02-14 14:25:14 -0500972 int x = src->getOrigin().x() - dstOrigin.x();
973 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700974 auto special = src->snapSpecial();
975 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400976 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700977 }
robertphillips7354a4b2015-12-16 05:08:27 -0800978}
reed70ee31b2015-12-10 13:44:45 -0800979
Mike Kleine083f7c2018-02-07 12:54:27 -0500980static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500981 // Need to force L32 for now if we have an image filter.
982 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
983 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500984 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800985 }
Mike Klein649fb732018-02-26 15:09:16 -0500986
987 SkColorType ct = prev.colorType();
988 if (prev.bytesPerPixel() <= 4) {
989 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
990 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
991 ct = kN32_SkColorType;
992 }
993 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800994}
995
reed4960eee2015-12-18 07:09:18 -0800996void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
997 const SkRect* bounds = rec.fBounds;
998 const SkPaint* paint = rec.fPaint;
999 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1000
reed8c30a812016-04-20 16:36:51 -07001001 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -04001002 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -07001003 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -04001004 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -07001005 SkMatrix remainder;
1006 SkSize scale;
1007 /*
1008 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1009 * but they do handle scaling. To accommodate this, we do the following:
1010 *
1011 * 1. Stash off the current CTM
1012 * 2. Decompose the CTM into SCALE and REMAINDER
1013 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1014 * contains the REMAINDER
1015 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1016 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1017 * of the original imagefilter, and draw that (via drawSprite)
1018 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1019 *
1020 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1021 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1022 */
reed96a04f32016-04-25 09:25:15 -07001023 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001024 stashedMatrix.decomposeScale(&scale, &remainder))
1025 {
1026 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001027 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001028 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1029 SkPaint* p = lazyP.set(*paint);
1030 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1031 SkFilterQuality::kLow_SkFilterQuality,
1032 sk_ref_sp(imageFilter)));
1033 imageFilter = p->getImageFilter();
1034 paint = p;
1035 }
reed8c30a812016-04-20 16:36:51 -07001036
junov@chromium.orga907ac32012-02-24 21:54:07 +00001037 // do this before we create the layer. We don't call the public save() since
1038 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001039 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001040
junov@chromium.orga907ac32012-02-24 21:54:07 +00001041 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001042 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001043 if (modifiedRec) {
1044 // In this case there will be no layer in which to stash the matrix so we need to
1045 // revert the prior MCRec to its earlier state.
1046 modifiedRec->fMatrix = stashedMatrix;
1047 }
reed2ff1fce2014-12-11 07:07:37 -08001048 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049 }
1050
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001051 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1052 // the clipRectBounds() call above?
1053 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001054 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001055 }
1056
reed8dc0ccb2015-03-20 06:32:52 -07001057 SkPixelGeometry geo = fProps.pixelGeometry();
1058 if (paint) {
reed76033be2015-03-14 10:54:31 -07001059 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001060 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001061 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001062 }
1063 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064
robertphillips5139e502016-07-19 05:10:40 -07001065 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001066 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001067 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001068 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001069 }
reedb2db8982014-11-13 12:41:02 -08001070
Mike Kleine083f7c2018-02-07 12:54:27 -05001071 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001072
Hal Canary704cd322016-11-07 14:13:52 -05001073 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001074 {
reed70ee31b2015-12-10 13:44:45 -08001075 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001076 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001077 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Mike Reed910ca0f2018-04-25 13:04:05 -04001078 const bool trackCoverage = SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001079 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001080 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001081 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001082 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001083 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1084 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001085 return;
reed61f501f2015-04-29 08:34:00 -07001086 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001087 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001088 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089
Mike Reedb43a3e02017-02-11 10:18:58 -05001090 // only have a "next" if this new layer doesn't affect the clip (rare)
1091 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092 fMCRec->fLayer = layer;
1093 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001094
Mike Reedc61abee2017-02-28 17:45:27 -05001095 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001096 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001097 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001098 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001099
Mike Reedc42a1cd2017-02-14 14:25:14 -05001100 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1101
1102 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1103 if (layer->fNext) {
1104 // need to punch a hole in the previous device, so we don't draw there, given that
1105 // the new top-layer will allow drawing to happen "below" it.
1106 SkRegion hole(ir);
1107 do {
1108 layer = layer->fNext;
1109 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1110 } while (layer->fNext);
1111 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112}
1113
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001114int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001115 if (0xFF == alpha) {
1116 return this->saveLayer(bounds, nullptr);
1117 } else {
1118 SkPaint tmpPaint;
1119 tmpPaint.setAlpha(alpha);
1120 return this->saveLayer(bounds, &tmpPaint);
1121 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001122}
1123
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124void SkCanvas::internalRestore() {
1125 SkASSERT(fMCStack.count() != 0);
1126
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001127 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128 DeviceCM* layer = fMCRec->fLayer; // may be null
1129 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001130 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001131
1132 // now do the normal restore()
1133 fMCRec->~MCRec(); // balanced in save()
1134 fMCStack.pop_back();
1135 fMCRec = (MCRec*)fMCStack.back();
1136
Mike Reedc42a1cd2017-02-14 14:25:14 -05001137 if (fMCRec) {
1138 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1139 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001140
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1142 since if we're being recorded, we don't want to record this (the
1143 recorder will have already recorded the restore).
1144 */
bsalomon49f085d2014-09-05 13:34:00 -07001145 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001146 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001147 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001148 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001149 layer->fPaint.get(),
1150 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001151 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001152 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001153 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001154 delete layer;
reedb679ca82015-04-07 04:40:48 -07001155 } else {
1156 // we're at the root
reeda499f902015-05-01 09:34:31 -07001157 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001158 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001159 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001161 }
msarettfbfa2582016-08-12 08:29:08 -07001162
1163 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001164 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001165 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1166 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001167}
1168
reede8f30622016-03-23 18:59:25 -07001169sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001170 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001171 props = &fProps;
1172 }
1173 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001174}
1175
reede8f30622016-03-23 18:59:25 -07001176sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001177 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001178 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001179}
1180
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001181SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001182 return this->onImageInfo();
1183}
1184
1185SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001186 SkBaseDevice* dev = this->getDevice();
1187 if (dev) {
1188 return dev->imageInfo();
1189 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001190 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001191 }
1192}
1193
brianosman898235c2016-04-06 07:38:23 -07001194bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001195 return this->onGetProps(props);
1196}
1197
1198bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001199 SkBaseDevice* dev = this->getDevice();
1200 if (dev) {
1201 if (props) {
1202 *props = fProps;
1203 }
1204 return true;
1205 } else {
1206 return false;
1207 }
1208}
1209
reed6ceeebd2016-03-09 14:26:26 -08001210bool SkCanvas::peekPixels(SkPixmap* pmap) {
1211 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001212}
1213
reed884e97c2015-05-26 11:31:54 -07001214bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001215 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001216 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001217}
1218
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001219void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001220 SkPixmap pmap;
1221 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001222 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001223 }
1224 if (info) {
1225 *info = pmap.info();
1226 }
1227 if (rowBytes) {
1228 *rowBytes = pmap.rowBytes();
1229 }
1230 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001231 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001232 }
reed884e97c2015-05-26 11:31:54 -07001233 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001234}
1235
reed884e97c2015-05-26 11:31:54 -07001236bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001237 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001238 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001239}
1240
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242
Florin Malita53f77bd2017-04-28 13:48:37 -04001243void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1244 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001246 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 paint = &tmp;
1248 }
reed@google.com4b226022011-01-11 18:32:13 +00001249
reed@google.com8926b162012-03-23 15:36:36 +00001250 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001251
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001253 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001254 paint = &looper.paint();
1255 SkImageFilter* filter = paint->getImageFilter();
1256 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001257 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001258 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1259 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001260 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1261 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001262 }
reed@google.com76dd2772012-01-05 21:15:07 +00001263 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001264 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266 }
reeda2217ef2016-07-20 06:04:34 -07001267
reed@google.com4e2b3d32011-04-07 14:18:59 +00001268 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269}
1270
reed32704672015-12-16 08:27:10 -08001271/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001272
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001273void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001274 if (dx || dy) {
1275 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001276 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001277
reedfe69b502016-09-12 06:31:48 -07001278 // Translate shouldn't affect the is-scale-translateness of the matrix.
1279 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001280
Mike Reedc42a1cd2017-02-14 14:25:14 -05001281 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001282
reedfe69b502016-09-12 06:31:48 -07001283 this->didTranslate(dx,dy);
1284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285}
1286
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001287void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001288 SkMatrix m;
1289 m.setScale(sx, sy);
1290 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291}
1292
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001293void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001294 SkMatrix m;
1295 m.setRotate(degrees);
1296 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297}
1298
bungeman7438bfc2016-07-12 15:01:19 -07001299void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1300 SkMatrix m;
1301 m.setRotate(degrees, px, py);
1302 this->concat(m);
1303}
1304
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001305void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001306 SkMatrix m;
1307 m.setSkew(sx, sy);
1308 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001309}
1310
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001311void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001312 if (matrix.isIdentity()) {
1313 return;
1314 }
1315
reed2ff1fce2014-12-11 07:07:37 -08001316 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001317 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001318 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001319
Mike Reed7627fa52017-02-08 10:07:53 -05001320 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001321
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001322 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001323}
1324
reed8c30a812016-04-20 16:36:51 -07001325void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001326 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001327 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001328
Mike Reedc42a1cd2017-02-14 14:25:14 -05001329 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001330}
1331
1332void SkCanvas::setMatrix(const SkMatrix& matrix) {
1333 this->checkForDeferredSave();
1334 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001335 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336}
1337
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001339 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
1342//////////////////////////////////////////////////////////////////////////////
1343
Mike Reedc1f77742016-12-09 09:00:50 -05001344void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001345 if (!rect.isFinite()) {
1346 return;
1347 }
reed2ff1fce2014-12-11 07:07:37 -08001348 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001349 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1350 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001351}
1352
Mike Reedc1f77742016-12-09 09:00:50 -05001353void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001354 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001355
Mike Reed7627fa52017-02-08 10:07:53 -05001356 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001357
reedc64eff52015-11-21 12:39:45 -08001358 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001359 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1360 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001361 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001362}
1363
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001364void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1365 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001366 if (fClipRestrictionRect.isEmpty()) {
1367 // we notify the device, but we *dont* resolve deferred saves (since we're just
1368 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001369 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001370 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001371 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001372 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001373 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001374 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001375 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1376 }
1377}
1378
Mike Reedc1f77742016-12-09 09:00:50 -05001379void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001380 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001381 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001382 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001383 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1384 } else {
1385 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001386 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001387}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001388
Mike Reedc1f77742016-12-09 09:00:50 -05001389void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001390 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001391
Brian Salomona3b45d42016-10-03 11:36:16 -04001392 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001393
Mike Reed7627fa52017-02-08 10:07:53 -05001394 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001395
Mike Reed20800c82017-11-15 16:09:04 -05001396 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1397 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001398 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001399}
1400
Mike Reedc1f77742016-12-09 09:00:50 -05001401void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001402 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001403 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001404
1405 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1406 SkRect r;
1407 if (path.isRect(&r)) {
1408 this->onClipRect(r, op, edgeStyle);
1409 return;
1410 }
1411 SkRRect rrect;
1412 if (path.isOval(&r)) {
1413 rrect.setOval(r);
1414 this->onClipRRect(rrect, op, edgeStyle);
1415 return;
1416 }
1417 if (path.isRRect(&rrect)) {
1418 this->onClipRRect(rrect, op, edgeStyle);
1419 return;
1420 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001421 }
robertphillips39f05382015-11-24 09:30:12 -08001422
1423 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001424}
1425
Mike Reedc1f77742016-12-09 09:00:50 -05001426void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001427 AutoValidateClip avc(this);
1428
Brian Salomona3b45d42016-10-03 11:36:16 -04001429 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001430
Mike Reed7627fa52017-02-08 10:07:53 -05001431 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432
Brian Salomona3b45d42016-10-03 11:36:16 -04001433 const SkPath* rasterClipPath = &path;
1434 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001435 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1436 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001437 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
Mike Reedc1f77742016-12-09 09:00:50 -05001440void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001441 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001442 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001443}
1444
Mike Reedc1f77742016-12-09 09:00:50 -05001445void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001446 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001447
reed@google.com5c3d1472011-02-22 19:12:23 +00001448 AutoValidateClip avc(this);
1449
Mike Reed20800c82017-11-15 16:09:04 -05001450 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001451 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452}
1453
reed@google.com819c9212011-02-23 18:56:55 +00001454#ifdef SK_DEBUG
1455void SkCanvas::validateClip() const {
1456 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001457 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001458 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001459 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001460 return;
1461 }
reed@google.com819c9212011-02-23 18:56:55 +00001462}
1463#endif
1464
Mike Reeda1361362017-03-07 09:37:29 -05001465bool SkCanvas::androidFramework_isClipAA() const {
1466 bool containsAA = false;
1467
1468 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1469
1470 return containsAA;
1471}
1472
1473class RgnAccumulator {
1474 SkRegion* fRgn;
1475public:
1476 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1477 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1478 SkIPoint origin = device->getOrigin();
1479 if (origin.x() | origin.y()) {
1480 rgn->translate(origin.x(), origin.y());
1481 }
1482 fRgn->op(*rgn, SkRegion::kUnion_Op);
1483 }
1484};
1485
1486void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1487 RgnAccumulator accum(rgn);
1488 SkRegion tmp;
1489
1490 rgn->setEmpty();
1491 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001492}
1493
reed@google.com5c3d1472011-02-22 19:12:23 +00001494///////////////////////////////////////////////////////////////////////////////
1495
reed@google.com754de5f2014-02-24 19:38:20 +00001496bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001497 return fMCRec->fRasterClip.isEmpty();
1498
1499 // TODO: should we only use the conservative answer in a recording canvas?
1500#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001501 SkBaseDevice* dev = this->getTopDevice();
1502 // if no device we return true
1503 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001504#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001505}
1506
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001507bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001508 SkBaseDevice* dev = this->getTopDevice();
1509 // if no device we return false
1510 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001511}
1512
msarettfbfa2582016-08-12 08:29:08 -07001513static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1514#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1515 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1516 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1517 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1518 return 0xF != _mm_movemask_ps(mask);
1519#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1520 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1521 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1522 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1523 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1524#else
1525 SkRect devRectAsRect;
1526 SkRect devClipAsRect;
1527 devRect.store(&devRectAsRect.fLeft);
1528 devClip.store(&devClipAsRect.fLeft);
1529 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1530#endif
1531}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001532
msarettfbfa2582016-08-12 08:29:08 -07001533// It's important for this function to not be inlined. Otherwise the compiler will share code
1534// between the fast path and the slow path, resulting in two slow paths.
1535static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1536 const SkMatrix& matrix) {
1537 SkRect deviceRect;
1538 matrix.mapRect(&deviceRect, src);
1539 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1540}
1541
1542bool SkCanvas::quickReject(const SkRect& src) const {
1543#ifdef SK_DEBUG
1544 // Verify that fDeviceClipBounds are set properly.
1545 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001546 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001547 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001548 } else {
msarettfbfa2582016-08-12 08:29:08 -07001549 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001550 }
msarettfbfa2582016-08-12 08:29:08 -07001551
msarett9637ea92016-08-18 14:03:30 -07001552 // Verify that fIsScaleTranslate is set properly.
1553 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001554#endif
1555
msarett9637ea92016-08-18 14:03:30 -07001556 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001557 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1558 }
1559
1560 // We inline the implementation of mapScaleTranslate() for the fast path.
1561 float sx = fMCRec->fMatrix.getScaleX();
1562 float sy = fMCRec->fMatrix.getScaleY();
1563 float tx = fMCRec->fMatrix.getTranslateX();
1564 float ty = fMCRec->fMatrix.getTranslateY();
1565 Sk4f scale(sx, sy, sx, sy);
1566 Sk4f trans(tx, ty, tx, ty);
1567
1568 // Apply matrix.
1569 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1570
1571 // Make sure left < right, top < bottom.
1572 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1573 Sk4f min = Sk4f::Min(ltrb, rblt);
1574 Sk4f max = Sk4f::Max(ltrb, rblt);
1575 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1576 // ARM this sequence generates the fastest (a single instruction).
1577 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1578
1579 // Check if the device rect is NaN or outside the clip.
1580 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001581}
1582
reed@google.com3b3e8952012-08-16 20:53:31 +00001583bool SkCanvas::quickReject(const SkPath& path) const {
1584 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
Mike Klein83c8dd92017-11-28 17:08:45 -05001587SkRect SkCanvas::getLocalClipBounds() const {
1588 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001589 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001590 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591 }
1592
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001593 SkMatrix inverse;
1594 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001595 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001596 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001597 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001598
Mike Reed42e8c532017-01-23 14:09:13 -05001599 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001600 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001601 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001602
Mike Reedb57b9312018-04-23 12:12:54 -04001603 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001604 inverse.mapRect(&bounds, r);
1605 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606}
1607
Mike Klein83c8dd92017-11-28 17:08:45 -05001608SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001609 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001610}
1611
reed@android.com8a1c16f2008-12-17 15:59:43 +00001612const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001613 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614}
1615
Brian Osman11052242016-10-27 14:47:55 -04001616GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001617 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001618 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001619}
1620
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001621GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001622 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001623 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001624}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001625
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001626void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1627 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001628 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001629 if (outer.isEmpty()) {
1630 return;
1631 }
1632 if (inner.isEmpty()) {
1633 this->drawRRect(outer, paint);
1634 return;
1635 }
1636
1637 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001638 // be able to return ...
1639 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001640 //
1641 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001642 if (!outer.getBounds().contains(inner.getBounds())) {
1643 return;
1644 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001645
1646 this->onDrawDRRect(outer, inner, paint);
1647}
1648
reed41af9662015-01-05 07:49:08 -08001649void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001650 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001651 this->onDrawPaint(paint);
1652}
1653
1654void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001655 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001656 // To avoid redundant logic in our culling code and various backends, we always sort rects
1657 // before passing them along.
1658 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001659}
1660
msarettdca352e2016-08-26 06:37:45 -07001661void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001662 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001663 if (region.isEmpty()) {
1664 return;
1665 }
1666
1667 if (region.isRect()) {
1668 return this->drawIRect(region.getBounds(), paint);
1669 }
1670
1671 this->onDrawRegion(region, paint);
1672}
1673
reed41af9662015-01-05 07:49:08 -08001674void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001675 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001676 // To avoid redundant logic in our culling code and various backends, we always sort rects
1677 // before passing them along.
1678 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001679}
1680
1681void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001682 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001683 this->onDrawRRect(rrect, paint);
1684}
1685
1686void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001687 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001688 this->onDrawPoints(mode, count, pts, paint);
1689}
1690
Mike Reede88a1cb2017-03-17 09:50:46 -04001691void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1692 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001693 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001694 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001695 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1696 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Mike Reede88a1cb2017-03-17 09:50:46 -04001697 this->onDrawVerticesObject(vertices.get(), mode, paint);
1698}
1699
1700void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001701 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001702 RETURN_ON_NULL(vertices);
1703 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001704}
1705
1706void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001707 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001708 this->onDrawPath(path, paint);
1709}
1710
reeda85d4d02015-05-06 12:56:48 -07001711void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001712 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001713 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001714 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001715}
1716
Mike Reedc4e31092018-01-30 11:15:27 -05001717// Returns true if the rect can be "filled" : non-empty and finite
1718static bool fillable(const SkRect& r) {
1719 SkScalar w = r.width();
1720 SkScalar h = r.height();
1721 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1722}
1723
reede47829b2015-08-06 10:02:53 -07001724void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1725 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001727 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001728 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001729 return;
1730 }
1731 this->onDrawImageRect(image, &src, dst, paint, constraint);
1732}
reed41af9662015-01-05 07:49:08 -08001733
reed84984ef2015-07-17 07:09:43 -07001734void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1735 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001736 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001737 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001738}
1739
reede47829b2015-08-06 10:02:53 -07001740void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1741 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001742 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001743 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1744 constraint);
1745}
reede47829b2015-08-06 10:02:53 -07001746
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001747namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001748class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001749public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001750 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1751 if (!origPaint) {
1752 return;
1753 }
1754 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1755 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1756 }
1757 if (origPaint->getMaskFilter()) {
1758 fPaint.writable()->setMaskFilter(nullptr);
1759 }
1760 if (origPaint->isAntiAlias()) {
1761 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001762 }
1763 }
1764
1765 const SkPaint* get() const {
1766 return fPaint;
1767 }
1768
1769private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001770 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001771};
1772} // namespace
1773
reed4c21dc52015-06-25 12:32:03 -07001774void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1775 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001776 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001777 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001778 if (dst.isEmpty()) {
1779 return;
1780 }
msarett552bca92016-08-03 06:53:26 -07001781 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001782 LatticePaint latticePaint(paint);
1783 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001784 } else {
reede47829b2015-08-06 10:02:53 -07001785 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001786 }
reed4c21dc52015-06-25 12:32:03 -07001787}
1788
msarett16882062016-08-16 09:31:08 -07001789void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1790 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001791 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001792 RETURN_ON_NULL(image);
1793 if (dst.isEmpty()) {
1794 return;
1795 }
msarett71df2d72016-09-30 12:41:42 -07001796
1797 SkIRect bounds;
1798 Lattice latticePlusBounds = lattice;
1799 if (!latticePlusBounds.fBounds) {
1800 bounds = SkIRect::MakeWH(image->width(), image->height());
1801 latticePlusBounds.fBounds = &bounds;
1802 }
1803
1804 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001805 LatticePaint latticePaint(paint);
1806 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001807 } else {
1808 this->drawImageRect(image, dst, paint);
1809 }
1810}
1811
reed41af9662015-01-05 07:49:08 -08001812void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001813 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001814 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001815 return;
1816 }
reed41af9662015-01-05 07:49:08 -08001817 this->onDrawBitmap(bitmap, dx, dy, paint);
1818}
1819
reede47829b2015-08-06 10:02:53 -07001820void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001821 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001822 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001823 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001824 return;
1825 }
reede47829b2015-08-06 10:02:53 -07001826 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001827}
1828
reed84984ef2015-07-17 07:09:43 -07001829void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1830 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001831 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001832}
1833
reede47829b2015-08-06 10:02:53 -07001834void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1835 SrcRectConstraint constraint) {
1836 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1837 constraint);
1838}
reede47829b2015-08-06 10:02:53 -07001839
reed41af9662015-01-05 07:49:08 -08001840void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1841 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001843 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001844 return;
1845 }
msarett552bca92016-08-03 06:53:26 -07001846 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001847 LatticePaint latticePaint(paint);
1848 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001849 } else {
reeda5517e22015-07-14 10:54:12 -07001850 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001851 }
reed41af9662015-01-05 07:49:08 -08001852}
1853
msarettc573a402016-08-02 08:05:56 -07001854void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1855 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001856 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001857 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001858 return;
1859 }
msarett71df2d72016-09-30 12:41:42 -07001860
1861 SkIRect bounds;
1862 Lattice latticePlusBounds = lattice;
1863 if (!latticePlusBounds.fBounds) {
1864 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1865 latticePlusBounds.fBounds = &bounds;
1866 }
1867
1868 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001869 LatticePaint latticePaint(paint);
1870 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001871 } else {
msarett16882062016-08-16 09:31:08 -07001872 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001873 }
msarettc573a402016-08-02 08:05:56 -07001874}
1875
reed71c3c762015-06-24 10:29:17 -07001876void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001877 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001878 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001879 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001880 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001881 if (count <= 0) {
1882 return;
1883 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001884 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001885 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001886 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001887}
1888
reedf70b5312016-03-04 16:36:20 -08001889void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001890 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001891 if (key) {
1892 this->onDrawAnnotation(rect, key, value);
1893 }
1894}
1895
reede47829b2015-08-06 10:02:53 -07001896void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1897 const SkPaint* paint, SrcRectConstraint constraint) {
1898 if (src) {
1899 this->drawImageRect(image, *src, dst, paint, constraint);
1900 } else {
1901 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1902 dst, paint, constraint);
1903 }
1904}
1905void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1906 const SkPaint* paint, SrcRectConstraint constraint) {
1907 if (src) {
1908 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1909 } else {
1910 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1911 dst, paint, constraint);
1912 }
1913}
1914
Mike Reed4204da22017-05-17 08:53:36 -04001915void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001916 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001917 this->onDrawShadowRec(path, rec);
1918}
1919
1920void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1921 SkPaint paint;
1922 const SkRect& pathBounds = path.getBounds();
1923
1924 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1925 while (iter.next()) {
1926 iter.fDevice->drawShadow(path, rec);
1927 }
1928 LOOPER_END
1929}
1930
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931//////////////////////////////////////////////////////////////////////////////
1932// These are the virtual drawing methods
1933//////////////////////////////////////////////////////////////////////////////
1934
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001935void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001936 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001937 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1938 }
1939}
1940
reed41af9662015-01-05 07:49:08 -08001941void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001942 this->internalDrawPaint(paint);
1943}
1944
1945void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001946 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001947
1948 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001949 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001950 }
1951
reed@google.com4e2b3d32011-04-07 14:18:59 +00001952 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953}
1954
reed41af9662015-01-05 07:49:08 -08001955void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1956 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957 if ((long)count <= 0) {
1958 return;
1959 }
1960
Mike Reed822128b2017-02-28 16:41:03 -05001961 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001962 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001963 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001964 // special-case 2 points (common for drawing a single line)
1965 if (2 == count) {
1966 r.set(pts[0], pts[1]);
1967 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001968 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001969 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001970 if (!r.isFinite()) {
1971 return;
1972 }
Mike Reed822128b2017-02-28 16:41:03 -05001973 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001974 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1975 return;
1976 }
1977 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001978 }
reed@google.coma584aed2012-05-16 14:06:02 +00001979
halcanary96fcdcc2015-08-27 07:41:13 -07001980 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001982 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001983
reed@android.com8a1c16f2008-12-17 15:59:43 +00001984 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001985 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001986 }
reed@google.com4b226022011-01-11 18:32:13 +00001987
reed@google.com4e2b3d32011-04-07 14:18:59 +00001988 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001989}
1990
reed4a167172016-08-18 17:15:25 -07001991static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1992 return ((intptr_t)paint.getImageFilter() |
1993#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1994 (intptr_t)canvas->getDrawFilter() |
1995#endif
1996 (intptr_t)paint.getLooper() ) != 0;
1997}
1998
reed41af9662015-01-05 07:49:08 -08001999void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002000 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002002 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002003 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002004 return;
2005 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 }
reed@google.com4b226022011-01-11 18:32:13 +00002007
reed4a167172016-08-18 17:15:25 -07002008 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002009 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010
reed4a167172016-08-18 17:15:25 -07002011 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002012 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002013 }
2014
2015 LOOPER_END
2016 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002017 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002018 SkDrawIter iter(this);
2019 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002020 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002021 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023}
2024
msarett44df6512016-08-25 13:54:30 -07002025void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002026 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002027 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002028 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002029 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2030 return;
2031 }
msarett44df6512016-08-25 13:54:30 -07002032 }
2033
Mike Reed822128b2017-02-28 16:41:03 -05002034 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002035
2036 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002037 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002038 }
2039
2040 LOOPER_END
2041}
2042
reed41af9662015-01-05 07:49:08 -08002043void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002044 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002045 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002046 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002047 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002048 return;
2049 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002050 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002051
Mike Reed822128b2017-02-28 16:41:03 -05002052 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002053
2054 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002055 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002056 }
2057
2058 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002059}
2060
bsalomonac3aa242016-08-19 11:25:19 -07002061void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2062 SkScalar sweepAngle, bool useCenter,
2063 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002065 if (paint.canComputeFastBounds()) {
2066 SkRect storage;
2067 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002068 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002069 return;
2070 }
bsalomonac3aa242016-08-19 11:25:19 -07002071 }
2072
Mike Reed822128b2017-02-28 16:41:03 -05002073 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002074
2075 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002076 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002077 }
2078
2079 LOOPER_END
2080}
2081
reed41af9662015-01-05 07:49:08 -08002082void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002083 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002084 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002085 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2086 return;
2087 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002088 }
2089
2090 if (rrect.isRect()) {
2091 // call the non-virtual version
2092 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002093 return;
2094 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002095 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002096 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2097 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002099
Mike Reed822128b2017-02-28 16:41:03 -05002100 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002101
2102 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002103 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002104 }
2105
2106 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002107}
2108
Mike Reed822128b2017-02-28 16:41:03 -05002109void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002110 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002111 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002112 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2113 return;
2114 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002115 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002116
Mike Reed822128b2017-02-28 16:41:03 -05002117 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002118
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002119 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002120 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002121 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002122
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002123 LOOPER_END
2124}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002125
reed41af9662015-01-05 07:49:08 -08002126void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002127 if (!path.isFinite()) {
2128 return;
2129 }
2130
Mike Reed822128b2017-02-28 16:41:03 -05002131 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002132 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002133 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002134 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2135 return;
2136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002138
Mike Reed822128b2017-02-28 16:41:03 -05002139 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002140 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002141 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002142 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002143 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002144 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145
Mike Reed822128b2017-02-28 16:41:03 -05002146 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147
2148 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002149 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002150 }
2151
reed@google.com4e2b3d32011-04-07 14:18:59 +00002152 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002153}
2154
reed262a71b2015-12-05 13:07:27 -08002155bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002156 if (!paint.getImageFilter()) {
2157 return false;
2158 }
2159
2160 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002161 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002162 return false;
2163 }
2164
2165 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2166 // Once we can filter and the filter will return a result larger than itself, we should be
2167 // able to remove this constraint.
2168 // skbug.com/4526
2169 //
2170 SkPoint pt;
2171 ctm.mapXY(x, y, &pt);
2172 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2173 return ir.contains(fMCRec->fRasterClip.getBounds());
2174}
2175
Mike Reedf441cfc2018-04-11 14:50:16 -04002176// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2177// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2178// null.
2179static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2180 if (paintParam) {
2181 *real = *paintParam;
2182 real->setStyle(SkPaint::kFill_Style);
2183 real->setPathEffect(nullptr);
2184 paintParam = real;
2185 }
2186 return paintParam;
2187}
2188
reeda85d4d02015-05-06 12:56:48 -07002189void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002190 SkPaint realPaint;
2191 paint = init_image_paint(&realPaint, paint);
2192
reeda85d4d02015-05-06 12:56:48 -07002193 SkRect bounds = SkRect::MakeXYWH(x, y,
2194 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002195 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002196 SkRect tmp = bounds;
2197 if (paint) {
2198 paint->computeFastBounds(tmp, &tmp);
2199 }
2200 if (this->quickReject(tmp)) {
2201 return;
2202 }
reeda85d4d02015-05-06 12:56:48 -07002203 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002204 // At this point we need a real paint object. If the caller passed null, then we should
2205 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2206 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2207 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002208
reeda2217ef2016-07-20 06:04:34 -07002209 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002210 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2211 *paint);
2212 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002213 special = this->getDevice()->makeSpecial(image);
2214 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002215 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002216 }
2217 }
2218
reed262a71b2015-12-05 13:07:27 -08002219 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2220
reeda85d4d02015-05-06 12:56:48 -07002221 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002222 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002223 if (special) {
2224 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002225 iter.fDevice->ctm().mapXY(x, y, &pt);
2226 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002227 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002228 SkScalarRoundToInt(pt.fY), pnt,
2229 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002230 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002231 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002232 }
reeda85d4d02015-05-06 12:56:48 -07002233 }
halcanary9d524f22016-03-29 09:03:52 -07002234
reeda85d4d02015-05-06 12:56:48 -07002235 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002236}
2237
reed41af9662015-01-05 07:49:08 -08002238void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002239 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002240 SkPaint realPaint;
2241 paint = init_image_paint(&realPaint, paint);
2242
halcanary96fcdcc2015-08-27 07:41:13 -07002243 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002244 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002245 if (paint) {
2246 paint->computeFastBounds(dst, &storage);
2247 }
2248 if (this->quickReject(storage)) {
2249 return;
2250 }
reeda85d4d02015-05-06 12:56:48 -07002251 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002252 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002253
senorblancoc41e7e12015-12-07 12:51:30 -08002254 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002255 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002256
reeda85d4d02015-05-06 12:56:48 -07002257 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002258 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002259 }
halcanary9d524f22016-03-29 09:03:52 -07002260
reeda85d4d02015-05-06 12:56:48 -07002261 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002262}
2263
reed41af9662015-01-05 07:49:08 -08002264void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002265 SkDEBUGCODE(bitmap.validate();)
2266
reed33366972015-10-08 09:22:02 -07002267 if (bitmap.drawsNothing()) {
2268 return;
2269 }
2270
Mike Reedf441cfc2018-04-11 14:50:16 -04002271 SkPaint realPaint;
2272 init_image_paint(&realPaint, paint);
2273 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002274
Mike Reed822128b2017-02-28 16:41:03 -05002275 SkRect bounds;
2276 bitmap.getBounds(&bounds);
2277 bounds.offset(x, y);
2278 bool canFastBounds = paint->canComputeFastBounds();
2279 if (canFastBounds) {
2280 SkRect storage;
2281 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002282 return;
2283 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002284 }
reed@google.com4b226022011-01-11 18:32:13 +00002285
reeda2217ef2016-07-20 06:04:34 -07002286 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002287 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2288 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002289 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002290 special = this->getDevice()->makeSpecial(bitmap);
2291 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002292 drawAsSprite = false;
2293 }
2294 }
2295
Mike Reed822128b2017-02-28 16:41:03 -05002296 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002297
2298 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002299 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002300 if (special) {
reed262a71b2015-12-05 13:07:27 -08002301 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002302 iter.fDevice->ctm().mapXY(x, y, &pt);
2303 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002304 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002305 SkScalarRoundToInt(pt.fY), pnt,
2306 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002307 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002308 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002309 }
reed33366972015-10-08 09:22:02 -07002310 }
msarettfbfa2582016-08-12 08:29:08 -07002311
reed33366972015-10-08 09:22:02 -07002312 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313}
2314
reed@google.com9987ec32011-09-07 11:57:52 +00002315// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002316void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002317 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002318 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002319 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 return;
2321 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002322
halcanary96fcdcc2015-08-27 07:41:13 -07002323 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002324 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002325 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2326 return;
2327 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 }
reed@google.com3d608122011-11-21 15:16:16 +00002329
reed@google.com33535f32012-09-25 15:37:50 +00002330 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002331 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002332 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002334
senorblancoc41e7e12015-12-07 12:51:30 -08002335 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002336 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002337
reed@google.com33535f32012-09-25 15:37:50 +00002338 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002339 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002340 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002341
reed@google.com33535f32012-09-25 15:37:50 +00002342 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002343}
2344
reed41af9662015-01-05 07:49:08 -08002345void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002346 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002347 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002348 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002349}
2350
reed4c21dc52015-06-25 12:32:03 -07002351void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2352 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002353 SkPaint realPaint;
2354 paint = init_image_paint(&realPaint, paint);
2355
halcanary96fcdcc2015-08-27 07:41:13 -07002356 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002357 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002358 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2359 return;
2360 }
reed@google.com3d608122011-11-21 15:16:16 +00002361 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002362 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002363
senorblancoc41e7e12015-12-07 12:51:30 -08002364 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002365
reed4c21dc52015-06-25 12:32:03 -07002366 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002367 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002368 }
halcanary9d524f22016-03-29 09:03:52 -07002369
reed4c21dc52015-06-25 12:32:03 -07002370 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002371}
2372
reed41af9662015-01-05 07:49:08 -08002373void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2374 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002375 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002376 SkPaint realPaint;
2377 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002378
halcanary96fcdcc2015-08-27 07:41:13 -07002379 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002380 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002381 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2382 return;
2383 }
reed4c21dc52015-06-25 12:32:03 -07002384 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002385 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002386
senorblancoc41e7e12015-12-07 12:51:30 -08002387 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002388
reed4c21dc52015-06-25 12:32:03 -07002389 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002390 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002391 }
halcanary9d524f22016-03-29 09:03:52 -07002392
reed4c21dc52015-06-25 12:32:03 -07002393 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002394}
2395
msarett16882062016-08-16 09:31:08 -07002396void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2397 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002398 SkPaint realPaint;
2399 paint = init_image_paint(&realPaint, paint);
2400
msarett16882062016-08-16 09:31:08 -07002401 if (nullptr == paint || paint->canComputeFastBounds()) {
2402 SkRect storage;
2403 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2404 return;
2405 }
2406 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002407 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002408
2409 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2410
2411 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002412 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002413 }
2414
2415 LOOPER_END
2416}
2417
2418void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2419 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002420 SkPaint realPaint;
2421 paint = init_image_paint(&realPaint, paint);
2422
msarett16882062016-08-16 09:31:08 -07002423 if (nullptr == paint || paint->canComputeFastBounds()) {
2424 SkRect storage;
2425 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2426 return;
2427 }
2428 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002429 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002430
2431 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2432
2433 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002434 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002435 }
2436
2437 LOOPER_END
2438}
2439
reed@google.come0d9ce82014-04-23 04:00:17 +00002440void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2441 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002442 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443
2444 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002445 iter.fDevice->drawText(text, byteLength, x, y, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 }
2447
reed@google.com4e2b3d32011-04-07 14:18:59 +00002448 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449}
2450
reed@google.come0d9ce82014-04-23 04:00:17 +00002451void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2452 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002453 SkPoint textOffset = SkPoint::Make(0, 0);
2454
halcanary96fcdcc2015-08-27 07:41:13 -07002455 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002456
reed@android.com8a1c16f2008-12-17 15:59:43 +00002457 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002458 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002460
reed@google.com4e2b3d32011-04-07 14:18:59 +00002461 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002462}
2463
reed@google.come0d9ce82014-04-23 04:00:17 +00002464void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2465 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002466
2467 SkPoint textOffset = SkPoint::Make(0, constY);
2468
halcanary96fcdcc2015-08-27 07:41:13 -07002469 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002470
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002472 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002474
reed@google.com4e2b3d32011-04-07 14:18:59 +00002475 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476}
2477
reed@google.come0d9ce82014-04-23 04:00:17 +00002478void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2479 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002480 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002481
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002483 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002485
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002486 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002487}
2488
reed45561a02016-07-07 12:47:17 -07002489void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2490 const SkRect* cullRect, const SkPaint& paint) {
2491 if (cullRect && this->quickReject(*cullRect)) {
2492 return;
2493 }
2494
2495 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2496
2497 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002498 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002499 }
2500
2501 LOOPER_END
2502}
2503
fmalita00d5c2c2014-08-21 08:53:26 -07002504void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2505 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002506 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002507 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002508 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002509 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002510 SkRect tmp;
2511 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2512 return;
2513 }
2514 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002515 }
2516
fmalita024f9962015-03-03 19:08:17 -08002517 // We cannot filter in the looper as we normally do, because the paint is
2518 // incomplete at this point (text-related attributes are embedded within blob run paints).
2519 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002520 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002521
fmalita85d5eb92015-03-04 11:20:12 -08002522 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002523
fmalitaaa1b9122014-08-28 14:32:24 -07002524 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002525 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002526 }
2527
fmalitaaa1b9122014-08-28 14:32:24 -07002528 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002529
2530 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002531}
2532
Cary Clark2a475ea2017-04-28 15:35:12 -04002533void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2534 this->drawText(string.c_str(), string.size(), x, y, paint);
2535}
2536
reed@google.come0d9ce82014-04-23 04:00:17 +00002537// These will become non-virtual, so they always call the (virtual) onDraw... method
2538void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2539 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002540 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002541 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002542 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002543 this->onDrawText(text, byteLength, x, y, paint);
2544 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002545}
2546void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2547 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002548 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002549 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002550 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002551 this->onDrawPosText(text, byteLength, pos, paint);
2552 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002553}
2554void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2555 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002556 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002557 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002558 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002559 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2560 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002561}
2562void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2563 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002564 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002565 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002566 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002567 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2568 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002569}
reed45561a02016-07-07 12:47:17 -07002570void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2571 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002572 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002573 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002574 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002575 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2576 }
2577}
fmalita00d5c2c2014-08-21 08:53:26 -07002578void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2579 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002580 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002581 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002582 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002583 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002584}
reed@google.come0d9ce82014-04-23 04:00:17 +00002585
Mike Reede88a1cb2017-03-17 09:50:46 -04002586void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2587 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002588 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2589
2590 while (iter.next()) {
2591 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002592 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002593 }
2594
2595 LOOPER_END
2596}
2597
dandovb3c9d1c2014-08-12 08:34:29 -07002598void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002599 const SkPoint texCoords[4], SkBlendMode bmode,
2600 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002601 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002602 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002603 return;
2604 }
mtklein6cfa73a2014-08-13 13:33:49 -07002605
Mike Reedfaba3712016-11-03 14:45:31 -04002606 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002607}
2608
2609void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002610 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002611 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002612 // Since a patch is always within the convex hull of the control points, we discard it when its
2613 // bounding rectangle is completely outside the current clip.
2614 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002615 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002616 if (this->quickReject(bounds)) {
2617 return;
2618 }
mtklein6cfa73a2014-08-13 13:33:49 -07002619
Mike Reed435071e2017-05-23 11:22:56 -04002620 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2621
halcanary96fcdcc2015-08-27 07:41:13 -07002622 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002623
dandovecfff212014-08-04 10:02:00 -07002624 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002625 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002626 }
mtklein6cfa73a2014-08-13 13:33:49 -07002627
dandovecfff212014-08-04 10:02:00 -07002628 LOOPER_END
2629}
2630
reeda8db7282015-07-07 10:22:31 -07002631void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002632#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002633 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002634#endif
reede3b38ce2016-01-08 09:18:44 -08002635 RETURN_ON_NULL(dr);
2636 if (x || y) {
2637 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2638 this->onDrawDrawable(dr, &matrix);
2639 } else {
2640 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002641 }
2642}
2643
reeda8db7282015-07-07 10:22:31 -07002644void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002645#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002646 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002647#endif
reede3b38ce2016-01-08 09:18:44 -08002648 RETURN_ON_NULL(dr);
2649 if (matrix && matrix->isIdentity()) {
2650 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002651 }
reede3b38ce2016-01-08 09:18:44 -08002652 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002653}
2654
2655void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002656 // drawable bounds are no longer reliable (e.g. android displaylist)
2657 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002658 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002659}
2660
reed71c3c762015-06-24 10:29:17 -07002661void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002662 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002663 const SkRect* cull, const SkPaint* paint) {
2664 if (cull && this->quickReject(*cull)) {
2665 return;
2666 }
2667
2668 SkPaint pnt;
2669 if (paint) {
2670 pnt = *paint;
2671 }
halcanary9d524f22016-03-29 09:03:52 -07002672
halcanary96fcdcc2015-08-27 07:41:13 -07002673 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002674 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002675 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002676 }
2677 LOOPER_END
2678}
2679
reedf70b5312016-03-04 16:36:20 -08002680void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2681 SkASSERT(key);
2682
2683 SkPaint paint;
2684 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2685 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002686 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002687 }
2688 LOOPER_END
2689}
2690
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691//////////////////////////////////////////////////////////////////////////////
2692// These methods are NOT virtual, and therefore must call back into virtual
2693// methods, rather than actually drawing themselves.
2694//////////////////////////////////////////////////////////////////////////////
2695
reed374772b2016-10-05 17:33:02 -07002696void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002699 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700 this->drawPaint(paint);
2701}
2702
2703void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002704 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2706}
2707
Mike Reed3661bc92017-02-22 13:21:42 -05002708void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710 pts[0].set(x0, y0);
2711 pts[1].set(x1, y1);
2712 this->drawPoints(kLines_PointMode, 2, pts, paint);
2713}
2714
Mike Reed3661bc92017-02-22 13:21:42 -05002715void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 if (radius < 0) {
2717 radius = 0;
2718 }
2719
2720 SkRect r;
2721 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002722 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723}
2724
2725void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2726 const SkPaint& paint) {
2727 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002728 SkRRect rrect;
2729 rrect.setRectXY(r, rx, ry);
2730 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 } else {
2732 this->drawRect(r, paint);
2733 }
2734}
2735
reed@android.com8a1c16f2008-12-17 15:59:43 +00002736void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2737 SkScalar sweepAngle, bool useCenter,
2738 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002739 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002740 if (oval.isEmpty() || !sweepAngle) {
2741 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 }
bsalomon21af9ca2016-08-25 12:29:23 -07002743 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744}
2745
2746void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2747 const SkPath& path, SkScalar hOffset,
2748 SkScalar vOffset, const SkPaint& paint) {
2749 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002750
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 matrix.setTranslate(hOffset, vOffset);
2752 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2753}
2754
reed@android.comf76bacf2009-05-13 14:00:33 +00002755///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002756
Mike Klein88d90712018-01-27 17:30:04 +00002757/**
2758 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2759 * against the playback cost of recursing into the subpicture to get at its actual ops.
2760 *
2761 * For now we pick a conservatively small value, though measurement (and other heuristics like
2762 * the type of ops contained) may justify changing this value.
2763 */
2764#define kMaxPictureOpsToUnrollInsteadOfRef 1
2765
reedd5fa1a42014-08-09 11:08:05 -07002766void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002767 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002768 RETURN_ON_NULL(picture);
2769
reede3b38ce2016-01-08 09:18:44 -08002770 if (matrix && matrix->isIdentity()) {
2771 matrix = nullptr;
2772 }
Mike Klein88d90712018-01-27 17:30:04 +00002773 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2774 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2775 picture->playback(this);
2776 } else {
2777 this->onDrawPicture(picture, matrix, paint);
2778 }
reedd5fa1a42014-08-09 11:08:05 -07002779}
robertphillips9b14f262014-06-04 05:40:44 -07002780
reedd5fa1a42014-08-09 11:08:05 -07002781void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2782 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002783 if (!paint || paint->canComputeFastBounds()) {
2784 SkRect bounds = picture->cullRect();
2785 if (paint) {
2786 paint->computeFastBounds(bounds, &bounds);
2787 }
2788 if (matrix) {
2789 matrix->mapRect(&bounds);
2790 }
2791 if (this->quickReject(bounds)) {
2792 return;
2793 }
2794 }
2795
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002796 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002797 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798}
2799
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800///////////////////////////////////////////////////////////////////////////////
2801///////////////////////////////////////////////////////////////////////////////
2802
reed3aafe112016-08-18 12:45:34 -07002803SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002804 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805
2806 SkASSERT(canvas);
2807
reed3aafe112016-08-18 12:45:34 -07002808 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 fDone = !fImpl->next();
2810}
2811
2812SkCanvas::LayerIter::~LayerIter() {
2813 fImpl->~SkDrawIter();
2814}
2815
2816void SkCanvas::LayerIter::next() {
2817 fDone = !fImpl->next();
2818}
2819
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002820SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002821 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822}
2823
2824const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002825 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826}
2827
2828const SkPaint& SkCanvas::LayerIter::paint() const {
2829 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002830 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831 paint = &fDefaultPaint;
2832 }
2833 return *paint;
2834}
2835
Mike Reedca37f322018-03-08 13:22:16 -05002836SkIRect SkCanvas::LayerIter::clipBounds() const {
2837 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002838}
2839
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2841int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002842
2843///////////////////////////////////////////////////////////////////////////////
2844
Brian Osman10fc6fd2018-03-02 11:01:10 -05002845// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002846static bool supported_for_raster_canvas(const SkImageInfo& info) {
2847 switch (info.alphaType()) {
2848 case kPremul_SkAlphaType:
2849 case kOpaque_SkAlphaType:
2850 break;
2851 default:
2852 return false;
2853 }
2854
2855 switch (info.colorType()) {
2856 case kAlpha_8_SkColorType:
2857 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002858 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002859 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002860 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002861 break;
2862 default:
2863 return false;
2864 }
2865
2866 return true;
2867}
2868
Mike Reed5df49342016-11-12 08:06:55 -06002869std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002870 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002871 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002872 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002873 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002874
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002875 SkBitmap bitmap;
2876 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002877 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002878 }
Mike Reed12f77342017-11-08 11:19:52 -05002879
2880 return props ?
2881 skstd::make_unique<SkCanvas>(bitmap, *props) :
2882 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002883}
reedd5fa1a42014-08-09 11:08:05 -07002884
2885///////////////////////////////////////////////////////////////////////////////
2886
Florin Malitaee424ac2016-12-01 12:47:59 -05002887SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2888 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2889
Florin Malita439ace92016-12-02 12:05:41 -05002890SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2891 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2892
Herb Derbyefe39bc2018-05-01 17:06:20 -04002893SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002894 : INHERITED(device) {}
2895
Florin Malitaee424ac2016-12-01 12:47:59 -05002896SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2897 (void)this->INHERITED::getSaveLayerStrategy(rec);
2898 return kNoLayer_SaveLayerStrategy;
2899}
2900
2901///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002902
reed73603f32016-09-20 08:42:38 -07002903static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2904static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2905static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2906static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2907static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2908static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002909
2910///////////////////////////////////////////////////////////////////////////////////////////////////
2911
2912SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2913 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002914 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002915 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2916 SkIPoint origin = dev->getOrigin();
2917 SkMatrix ctm = this->getTotalMatrix();
2918 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2919
2920 SkIRect clip = fMCRec->fRasterClip.getBounds();
2921 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002922 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002923 clip.setEmpty();
2924 }
2925
2926 fAllocator->updateHandle(handle, ctm, clip);
2927 return handle;
2928 }
2929 return nullptr;
2930}
2931
2932static bool install(SkBitmap* bm, const SkImageInfo& info,
2933 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002934 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002935}
2936
2937SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2938 SkBitmap* bm) {
2939 SkRasterHandleAllocator::Rec rec;
2940 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2941 return nullptr;
2942 }
2943 return rec.fHandle;
2944}
2945
2946std::unique_ptr<SkCanvas>
2947SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2948 const SkImageInfo& info, const Rec* rec) {
2949 if (!alloc || !supported_for_raster_canvas(info)) {
2950 return nullptr;
2951 }
2952
2953 SkBitmap bm;
2954 Handle hndl;
2955
2956 if (rec) {
2957 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2958 } else {
2959 hndl = alloc->allocBitmap(info, &bm);
2960 }
2961 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2962}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002963
2964///////////////////////////////////////////////////////////////////////////////////////////////////
2965
2966