blob: 487aa41386ad3a09b590c209ec004ba8f3949e58 [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
reedd9544982014-09-09 18:46:22 -0700560SkBaseDevice* SkCanvas::init(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;
Florin Malita53f77bd2017-04-28 13:48:37 -0400576 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(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 }
msarettfbfa2582016-08-12 08:29:08 -0700590
reedf92c8662014-08-18 08:02:43 -0700591 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000592}
593
reed@google.comcde92112011-07-06 20:00:52 +0000594SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000595 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700596 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000597{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000598 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000599
halcanary96fcdcc2015-08-27 07:41:13 -0700600 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000601}
602
reed96a857e2015-01-25 10:33:58 -0800603SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000604 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800605 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000606{
607 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700608
Mike Reed566e53c2017-03-10 10:49:45 -0500609 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700610 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700611}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000612
reed78e27682014-11-19 08:04:34 -0800613SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700614 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700615 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700616{
617 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700618
Mike Reed566e53c2017-03-10 10:49:45 -0500619 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
620 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700621}
622
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000623SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000624 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700625 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000626{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700628
reedd9544982014-09-09 18:46:22 -0700629 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630}
631
robertphillipsfcf78292015-06-19 11:49:52 -0700632SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
633 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700634 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700635{
636 inc_canvas();
637
638 this->init(device, flags);
639}
640
reed4a8126e2014-09-22 07:29:03 -0700641SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700642 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700643 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700644{
645 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700646
Hal Canary704cd322016-11-07 14:13:52 -0500647 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
648 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700649}
reed29c857d2014-09-21 10:25:07 -0700650
Mike Reed356f7c22017-01-10 11:58:39 -0500651SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
652 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700653 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
654 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500655 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700656{
657 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700658
Mike Reed356f7c22017-01-10 11:58:39 -0500659 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500660 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
Mike Reed356f7c22017-01-10 11:58:39 -0500663SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
664
Matt Sarett31f99ce2017-04-11 08:46:01 -0400665#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
666SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
667 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
668 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
669 , fAllocator(nullptr)
670{
671 inc_canvas();
672
673 SkBitmap tmp(bitmap);
674 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
675 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
676 this->init(device.get(), kDefault_InitFlags);
677}
678#endif
679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680SkCanvas::~SkCanvas() {
681 // free up the contents of our deque
682 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000683
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684 this->internalRestore(); // restore the last, since we're going away
685
halcanary385fe4d2015-08-26 13:07:48 -0700686 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000687
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 dec_canvas();
689}
690
fmalita53d9f1c2016-01-25 06:23:54 -0800691#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692SkDrawFilter* SkCanvas::getDrawFilter() const {
693 return fMCRec->fFilter;
694}
695
696SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700697 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
699 return filter;
700}
fmalita77650002016-01-21 18:47:11 -0800701#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000703SkMetaData& SkCanvas::getMetaData() {
704 // metadata users are rare, so we lazily allocate it. If that changes we
705 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700706 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000707 fMetaData = new SkMetaData;
708 }
709 return *fMetaData;
710}
711
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712///////////////////////////////////////////////////////////////////////////////
713
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000714void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700715 this->onFlush();
716}
717
718void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000719 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000720 if (device) {
721 device->flush();
722 }
723}
724
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000725SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000726 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000727 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
728}
729
senorblancoafc7cce2016-02-02 18:44:15 -0800730SkIRect SkCanvas::getTopLayerBounds() const {
731 SkBaseDevice* d = this->getTopDevice();
732 if (!d) {
733 return SkIRect::MakeEmpty();
734 }
735 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
736}
737
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000738SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000740 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400742 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743}
744
Florin Malita0ed3b642017-01-13 16:56:38 +0000745SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400746 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000747}
748
Mike Reed353196f2017-07-21 11:01:18 -0400749bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000750 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400751 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000752}
753
Mike Reed353196f2017-07-21 11:01:18 -0400754bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
755 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400756}
757
758bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
759 SkPixmap pm;
760 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
761}
762
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000763bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400764 SkPixmap pm;
765 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700766 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000767 }
768 return false;
769}
770
Matt Sarett03dd6d52017-01-23 12:15:09 -0500771bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000772 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000773 SkBaseDevice* device = this->getDevice();
774 if (!device) {
775 return false;
776 }
777
Matt Sarett03dd6d52017-01-23 12:15:09 -0500778 // This check gives us an early out and prevents generation ID churn on the surface.
779 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
780 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
781 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
782 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000783 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000784
Matt Sarett03dd6d52017-01-23 12:15:09 -0500785 // Tell our owning surface to bump its generation ID.
786 const bool completeOverwrite =
787 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700788 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700789
Matt Sarett03dd6d52017-01-23 12:15:09 -0500790 // This can still fail, most notably in the case of a invalid color type or alpha type
791 // conversion. We could pull those checks into this function and avoid the unnecessary
792 // generation ID bump. But then we would be performing those checks twice, since they
793 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400794 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000795}
reed@google.com51df9e32010-12-23 19:29:18 +0000796
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797//////////////////////////////////////////////////////////////////////////////
798
reed2ff1fce2014-12-11 07:07:37 -0800799void SkCanvas::checkForDeferredSave() {
800 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800801 this->doSave();
802 }
803}
804
reedf0090cb2014-11-26 08:55:51 -0800805int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800806#ifdef SK_DEBUG
807 int count = 0;
808 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
809 for (;;) {
810 const MCRec* rec = (const MCRec*)iter.next();
811 if (!rec) {
812 break;
813 }
814 count += 1 + rec->fDeferredSaveCount;
815 }
816 SkASSERT(count == fSaveCount);
817#endif
818 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800819}
820
821int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800822 fSaveCount += 1;
823 fMCRec->fDeferredSaveCount += 1;
824 return this->getSaveCount() - 1; // return our prev value
825}
826
827void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800828 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700829
830 SkASSERT(fMCRec->fDeferredSaveCount > 0);
831 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800832 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800833}
834
835void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800836 if (fMCRec->fDeferredSaveCount > 0) {
837 SkASSERT(fSaveCount > 1);
838 fSaveCount -= 1;
839 fMCRec->fDeferredSaveCount -= 1;
840 } else {
841 // check for underflow
842 if (fMCStack.count() > 1) {
843 this->willRestore();
844 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700845 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800846 this->internalRestore();
847 this->didRestore();
848 }
reedf0090cb2014-11-26 08:55:51 -0800849 }
850}
851
852void SkCanvas::restoreToCount(int count) {
853 // sanity check
854 if (count < 1) {
855 count = 1;
856 }
mtkleinf0f14112014-12-12 08:46:25 -0800857
reedf0090cb2014-11-26 08:55:51 -0800858 int n = this->getSaveCount() - count;
859 for (int i = 0; i < n; ++i) {
860 this->restore();
861 }
862}
863
reed2ff1fce2014-12-11 07:07:37 -0800864void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000865 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700866 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000868
Mike Reedc42a1cd2017-02-14 14:25:14 -0500869 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870}
871
reed4960eee2015-12-18 07:09:18 -0800872bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400873 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874}
875
reed4960eee2015-12-18 07:09:18 -0800876bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700877 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500878 SkIRect clipBounds = this->getDeviceClipBounds();
879 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000880 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000881 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000882
reed96e657d2015-03-10 17:30:07 -0700883 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
884
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000885 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700886 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800887 if (bounds && !imageFilter->canComputeFastBounds()) {
888 bounds = nullptr;
889 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000890 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000891 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700892 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000893 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700894 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896 } else { // no user bounds, so just use the clip
897 ir = clipBounds;
898 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800899
900 // early exit if the layer's bounds are clipped out
901 if (!ir.intersect(clipBounds)) {
902 if (BoundsAffectsClip(saveLayerFlags)) {
903 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
904 fMCRec->fRasterClip.setEmpty();
905 fDeviceClipBounds.setEmpty();
906 }
907 return false;
908 }
reed180aec42015-03-11 10:39:04 -0700909 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000910
reed4960eee2015-12-18 07:09:18 -0800911 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700912 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700913 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700914 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000915 }
916
917 if (intersection) {
918 *intersection = ir;
919 }
920 return true;
921}
922
reed4960eee2015-12-18 07:09:18 -0800923int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
924 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000925}
926
reed70ee31b2015-12-10 13:44:45 -0800927int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800928 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
929}
930
Cary Clarke041e312018-03-06 13:00:52 -0500931int SkCanvas::saveLayer(const SaveLayerRec& rec) {
932 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800933 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500934 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800935 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800936}
937
reeda2217ef2016-07-20 06:04:34 -0700938void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500939 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500940 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700941 SkDraw draw;
942 SkRasterClip rc;
943 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
944 if (!dst->accessPixels(&draw.fDst)) {
945 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800946 }
reeda2217ef2016-07-20 06:04:34 -0700947 draw.fMatrix = &SkMatrix::I();
948 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800949
950 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500951 if (filter) {
952 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
953 }
reeda2217ef2016-07-20 06:04:34 -0700954
Mike Reedc42a1cd2017-02-14 14:25:14 -0500955 int x = src->getOrigin().x() - dstOrigin.x();
956 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700957 auto special = src->snapSpecial();
958 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400959 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700960 }
robertphillips7354a4b2015-12-16 05:08:27 -0800961}
reed70ee31b2015-12-10 13:44:45 -0800962
Mike Kleine083f7c2018-02-07 12:54:27 -0500963static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500964 // Need to force L32 for now if we have an image filter.
965 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
966 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500967 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800968 }
Mike Klein649fb732018-02-26 15:09:16 -0500969
970 SkColorType ct = prev.colorType();
971 if (prev.bytesPerPixel() <= 4) {
972 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
973 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
974 ct = kN32_SkColorType;
975 }
976 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800977}
978
reed4960eee2015-12-18 07:09:18 -0800979void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
980 const SkRect* bounds = rec.fBounds;
981 const SkPaint* paint = rec.fPaint;
982 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
983
reed8c30a812016-04-20 16:36:51 -0700984 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400985 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700986 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400987 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700988 SkMatrix remainder;
989 SkSize scale;
990 /*
991 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
992 * but they do handle scaling. To accommodate this, we do the following:
993 *
994 * 1. Stash off the current CTM
995 * 2. Decompose the CTM into SCALE and REMAINDER
996 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
997 * contains the REMAINDER
998 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
999 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1000 * of the original imagefilter, and draw that (via drawSprite)
1001 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1002 *
1003 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1004 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1005 */
reed96a04f32016-04-25 09:25:15 -07001006 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001007 stashedMatrix.decomposeScale(&scale, &remainder))
1008 {
1009 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001010 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001011 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1012 SkPaint* p = lazyP.set(*paint);
1013 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1014 SkFilterQuality::kLow_SkFilterQuality,
1015 sk_ref_sp(imageFilter)));
1016 imageFilter = p->getImageFilter();
1017 paint = p;
1018 }
reed8c30a812016-04-20 16:36:51 -07001019
junov@chromium.orga907ac32012-02-24 21:54:07 +00001020 // do this before we create the layer. We don't call the public save() since
1021 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001022 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001023
junov@chromium.orga907ac32012-02-24 21:54:07 +00001024 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001025 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001026 if (modifiedRec) {
1027 // In this case there will be no layer in which to stash the matrix so we need to
1028 // revert the prior MCRec to its earlier state.
1029 modifiedRec->fMatrix = stashedMatrix;
1030 }
reed2ff1fce2014-12-11 07:07:37 -08001031 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032 }
1033
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001034 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1035 // the clipRectBounds() call above?
1036 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001037 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001038 }
1039
reed8dc0ccb2015-03-20 06:32:52 -07001040 SkPixelGeometry geo = fProps.pixelGeometry();
1041 if (paint) {
reed76033be2015-03-14 10:54:31 -07001042 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001043 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001044 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001045 }
1046 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047
robertphillips5139e502016-07-19 05:10:40 -07001048 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001049 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001050 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001051 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001052 }
reedb2db8982014-11-13 12:41:02 -08001053
Mike Kleine083f7c2018-02-07 12:54:27 -05001054 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001055
Hal Canary704cd322016-11-07 14:13:52 -05001056 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001057 {
reed70ee31b2015-12-10 13:44:45 -08001058 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001059 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001060 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001061 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001062 preserveLCDText,
1063 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001064 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1065 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001066 return;
reed61f501f2015-04-29 08:34:00 -07001067 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001068 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001069 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001070
Mike Reedb43a3e02017-02-11 10:18:58 -05001071 // only have a "next" if this new layer doesn't affect the clip (rare)
1072 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 fMCRec->fLayer = layer;
1074 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001075
Mike Reedc61abee2017-02-28 17:45:27 -05001076 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001077 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001078 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001079 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001080
Mike Reedc42a1cd2017-02-14 14:25:14 -05001081 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1082
1083 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1084 if (layer->fNext) {
1085 // need to punch a hole in the previous device, so we don't draw there, given that
1086 // the new top-layer will allow drawing to happen "below" it.
1087 SkRegion hole(ir);
1088 do {
1089 layer = layer->fNext;
1090 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1091 } while (layer->fNext);
1092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093}
1094
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001095int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001096 if (0xFF == alpha) {
1097 return this->saveLayer(bounds, nullptr);
1098 } else {
1099 SkPaint tmpPaint;
1100 tmpPaint.setAlpha(alpha);
1101 return this->saveLayer(bounds, &tmpPaint);
1102 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001103}
1104
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105void SkCanvas::internalRestore() {
1106 SkASSERT(fMCStack.count() != 0);
1107
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001108 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109 DeviceCM* layer = fMCRec->fLayer; // may be null
1110 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001111 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112
1113 // now do the normal restore()
1114 fMCRec->~MCRec(); // balanced in save()
1115 fMCStack.pop_back();
1116 fMCRec = (MCRec*)fMCStack.back();
1117
Mike Reedc42a1cd2017-02-14 14:25:14 -05001118 if (fMCRec) {
1119 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1120 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001121
reed@android.com8a1c16f2008-12-17 15:59:43 +00001122 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1123 since if we're being recorded, we don't want to record this (the
1124 recorder will have already recorded the restore).
1125 */
bsalomon49f085d2014-09-05 13:34:00 -07001126 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001127 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001128 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001129 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001130 layer->fPaint.get(),
1131 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001132 // restore what we smashed in internalSaveLayer
1133 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001134 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001135 delete layer;
reedb679ca82015-04-07 04:40:48 -07001136 } else {
1137 // we're at the root
reeda499f902015-05-01 09:34:31 -07001138 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001139 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001140 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001142 }
msarettfbfa2582016-08-12 08:29:08 -07001143
1144 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001145 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001146 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1147 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148}
1149
reede8f30622016-03-23 18:59:25 -07001150sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001151 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001152 props = &fProps;
1153 }
1154 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001155}
1156
reede8f30622016-03-23 18:59:25 -07001157sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001158 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001159 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001160}
1161
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001162SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001163 return this->onImageInfo();
1164}
1165
1166SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001167 SkBaseDevice* dev = this->getDevice();
1168 if (dev) {
1169 return dev->imageInfo();
1170 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001171 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001172 }
1173}
1174
brianosman898235c2016-04-06 07:38:23 -07001175bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001176 return this->onGetProps(props);
1177}
1178
1179bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001180 SkBaseDevice* dev = this->getDevice();
1181 if (dev) {
1182 if (props) {
1183 *props = fProps;
1184 }
1185 return true;
1186 } else {
1187 return false;
1188 }
1189}
1190
reed6ceeebd2016-03-09 14:26:26 -08001191bool SkCanvas::peekPixels(SkPixmap* pmap) {
1192 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001193}
1194
reed884e97c2015-05-26 11:31:54 -07001195bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001196 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001197 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001198}
1199
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001200void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001201 SkPixmap pmap;
1202 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001203 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001204 }
1205 if (info) {
1206 *info = pmap.info();
1207 }
1208 if (rowBytes) {
1209 *rowBytes = pmap.rowBytes();
1210 }
1211 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001212 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001213 }
reed884e97c2015-05-26 11:31:54 -07001214 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001215}
1216
reed884e97c2015-05-26 11:31:54 -07001217bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001218 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001219 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001220}
1221
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223
Florin Malita53f77bd2017-04-28 13:48:37 -04001224void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1225 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001227 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 paint = &tmp;
1229 }
reed@google.com4b226022011-01-11 18:32:13 +00001230
reed@google.com8926b162012-03-23 15:36:36 +00001231 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001232
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001234 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001235 paint = &looper.paint();
1236 SkImageFilter* filter = paint->getImageFilter();
1237 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001238 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001239 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1240 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001241 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1242 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001243 }
reed@google.com76dd2772012-01-05 21:15:07 +00001244 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001245 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001246 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 }
reeda2217ef2016-07-20 06:04:34 -07001248
reed@google.com4e2b3d32011-04-07 14:18:59 +00001249 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250}
1251
reed32704672015-12-16 08:27:10 -08001252/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001253
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001254void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001255 if (dx || dy) {
1256 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001257 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001258
reedfe69b502016-09-12 06:31:48 -07001259 // Translate shouldn't affect the is-scale-translateness of the matrix.
1260 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001261
Mike Reedc42a1cd2017-02-14 14:25:14 -05001262 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001263
reedfe69b502016-09-12 06:31:48 -07001264 this->didTranslate(dx,dy);
1265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001268void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001269 SkMatrix m;
1270 m.setScale(sx, sy);
1271 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001274void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001275 SkMatrix m;
1276 m.setRotate(degrees);
1277 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278}
1279
bungeman7438bfc2016-07-12 15:01:19 -07001280void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1281 SkMatrix m;
1282 m.setRotate(degrees, px, py);
1283 this->concat(m);
1284}
1285
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001286void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001287 SkMatrix m;
1288 m.setSkew(sx, sy);
1289 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001290}
1291
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001292void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001293 if (matrix.isIdentity()) {
1294 return;
1295 }
1296
reed2ff1fce2014-12-11 07:07:37 -08001297 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001298 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001299 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001300
Mike Reed7627fa52017-02-08 10:07:53 -05001301 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001302
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001303 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001304}
1305
reed8c30a812016-04-20 16:36:51 -07001306void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001307 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001308 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001309
Mike Reedc42a1cd2017-02-14 14:25:14 -05001310 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001311}
1312
1313void SkCanvas::setMatrix(const SkMatrix& matrix) {
1314 this->checkForDeferredSave();
1315 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001316 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001320 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
1323//////////////////////////////////////////////////////////////////////////////
1324
Mike Reedc1f77742016-12-09 09:00:50 -05001325void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001326 if (!rect.isFinite()) {
1327 return;
1328 }
reed2ff1fce2014-12-11 07:07:37 -08001329 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001330 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1331 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001332}
1333
Mike Reedc1f77742016-12-09 09:00:50 -05001334void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001335 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001336
Mike Reed7627fa52017-02-08 10:07:53 -05001337 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001338
reedc64eff52015-11-21 12:39:45 -08001339 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001340 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1341 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001342 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001345void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1346 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001347 if (fClipRestrictionRect.isEmpty()) {
1348 // we notify the device, but we *dont* resolve deferred saves (since we're just
1349 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001350 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001351 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001352 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001353 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001354 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001355 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001356 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1357 }
1358}
1359
Mike Reedc1f77742016-12-09 09:00:50 -05001360void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001361 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001362 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001363 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001364 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1365 } else {
1366 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001367 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001368}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001369
Mike Reedc1f77742016-12-09 09:00:50 -05001370void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001371 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001372
Brian Salomona3b45d42016-10-03 11:36:16 -04001373 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001374
Mike Reed7627fa52017-02-08 10:07:53 -05001375 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001376
Mike Reed20800c82017-11-15 16:09:04 -05001377 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1378 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001379 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001380}
1381
Mike Reedc1f77742016-12-09 09:00:50 -05001382void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001383 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001384 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001385
1386 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1387 SkRect r;
1388 if (path.isRect(&r)) {
1389 this->onClipRect(r, op, edgeStyle);
1390 return;
1391 }
1392 SkRRect rrect;
1393 if (path.isOval(&r)) {
1394 rrect.setOval(r);
1395 this->onClipRRect(rrect, op, edgeStyle);
1396 return;
1397 }
1398 if (path.isRRect(&rrect)) {
1399 this->onClipRRect(rrect, op, edgeStyle);
1400 return;
1401 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001402 }
robertphillips39f05382015-11-24 09:30:12 -08001403
1404 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405}
1406
Mike Reedc1f77742016-12-09 09:00:50 -05001407void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001408 AutoValidateClip avc(this);
1409
Brian Salomona3b45d42016-10-03 11:36:16 -04001410 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001411
Mike Reed7627fa52017-02-08 10:07:53 -05001412 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413
Brian Salomona3b45d42016-10-03 11:36:16 -04001414 const SkPath* rasterClipPath = &path;
1415 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001416 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1417 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001418 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419}
1420
Mike Reedc1f77742016-12-09 09:00:50 -05001421void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001422 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001424}
1425
Mike Reedc1f77742016-12-09 09:00:50 -05001426void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001427 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001428
reed@google.com5c3d1472011-02-22 19:12:23 +00001429 AutoValidateClip avc(this);
1430
Mike Reed20800c82017-11-15 16:09:04 -05001431 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001432 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433}
1434
reed@google.com819c9212011-02-23 18:56:55 +00001435#ifdef SK_DEBUG
1436void SkCanvas::validateClip() const {
1437 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001438 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001439 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001440 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001441 return;
1442 }
reed@google.com819c9212011-02-23 18:56:55 +00001443}
1444#endif
1445
Mike Reeda1361362017-03-07 09:37:29 -05001446bool SkCanvas::androidFramework_isClipAA() const {
1447 bool containsAA = false;
1448
1449 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1450
1451 return containsAA;
1452}
1453
1454class RgnAccumulator {
1455 SkRegion* fRgn;
1456public:
1457 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1458 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1459 SkIPoint origin = device->getOrigin();
1460 if (origin.x() | origin.y()) {
1461 rgn->translate(origin.x(), origin.y());
1462 }
1463 fRgn->op(*rgn, SkRegion::kUnion_Op);
1464 }
1465};
1466
1467void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1468 RgnAccumulator accum(rgn);
1469 SkRegion tmp;
1470
1471 rgn->setEmpty();
1472 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001473}
1474
reed@google.com5c3d1472011-02-22 19:12:23 +00001475///////////////////////////////////////////////////////////////////////////////
1476
reed@google.com754de5f2014-02-24 19:38:20 +00001477bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001478 return fMCRec->fRasterClip.isEmpty();
1479
1480 // TODO: should we only use the conservative answer in a recording canvas?
1481#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001482 SkBaseDevice* dev = this->getTopDevice();
1483 // if no device we return true
1484 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001485#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001486}
1487
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001488bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001489 SkBaseDevice* dev = this->getTopDevice();
1490 // if no device we return false
1491 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001492}
1493
msarettfbfa2582016-08-12 08:29:08 -07001494static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1495#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1496 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1497 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1498 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1499 return 0xF != _mm_movemask_ps(mask);
1500#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1501 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1502 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1503 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1504 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1505#else
1506 SkRect devRectAsRect;
1507 SkRect devClipAsRect;
1508 devRect.store(&devRectAsRect.fLeft);
1509 devClip.store(&devClipAsRect.fLeft);
1510 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1511#endif
1512}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001513
msarettfbfa2582016-08-12 08:29:08 -07001514// It's important for this function to not be inlined. Otherwise the compiler will share code
1515// between the fast path and the slow path, resulting in two slow paths.
1516static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1517 const SkMatrix& matrix) {
1518 SkRect deviceRect;
1519 matrix.mapRect(&deviceRect, src);
1520 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1521}
1522
1523bool SkCanvas::quickReject(const SkRect& src) const {
1524#ifdef SK_DEBUG
1525 // Verify that fDeviceClipBounds are set properly.
1526 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001527 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001528 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001529 } else {
msarettfbfa2582016-08-12 08:29:08 -07001530 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531 }
msarettfbfa2582016-08-12 08:29:08 -07001532
msarett9637ea92016-08-18 14:03:30 -07001533 // Verify that fIsScaleTranslate is set properly.
1534 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001535#endif
1536
msarett9637ea92016-08-18 14:03:30 -07001537 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001538 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1539 }
1540
1541 // We inline the implementation of mapScaleTranslate() for the fast path.
1542 float sx = fMCRec->fMatrix.getScaleX();
1543 float sy = fMCRec->fMatrix.getScaleY();
1544 float tx = fMCRec->fMatrix.getTranslateX();
1545 float ty = fMCRec->fMatrix.getTranslateY();
1546 Sk4f scale(sx, sy, sx, sy);
1547 Sk4f trans(tx, ty, tx, ty);
1548
1549 // Apply matrix.
1550 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1551
1552 // Make sure left < right, top < bottom.
1553 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1554 Sk4f min = Sk4f::Min(ltrb, rblt);
1555 Sk4f max = Sk4f::Max(ltrb, rblt);
1556 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1557 // ARM this sequence generates the fastest (a single instruction).
1558 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1559
1560 // Check if the device rect is NaN or outside the clip.
1561 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562}
1563
reed@google.com3b3e8952012-08-16 20:53:31 +00001564bool SkCanvas::quickReject(const SkPath& path) const {
1565 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001566}
1567
Mike Klein83c8dd92017-11-28 17:08:45 -05001568SkRect SkCanvas::getLocalClipBounds() const {
1569 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001570 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001571 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001572 }
1573
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001574 SkMatrix inverse;
1575 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001576 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001577 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001578 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579
Mike Reed42e8c532017-01-23 14:09:13 -05001580 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001581 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001582 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001583
Mike Reedb57b9312018-04-23 12:12:54 -04001584 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001585 inverse.mapRect(&bounds, r);
1586 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587}
1588
Mike Klein83c8dd92017-11-28 17:08:45 -05001589SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001590 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001591}
1592
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001594 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595}
1596
Brian Osman11052242016-10-27 14:47:55 -04001597GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001598 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001599 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001600}
1601
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001602GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001603 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001604 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001605}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001606
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001607void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1608 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001609 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001610 if (outer.isEmpty()) {
1611 return;
1612 }
1613 if (inner.isEmpty()) {
1614 this->drawRRect(outer, paint);
1615 return;
1616 }
1617
1618 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001619 // be able to return ...
1620 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001621 //
1622 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001623 if (!outer.getBounds().contains(inner.getBounds())) {
1624 return;
1625 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001626
1627 this->onDrawDRRect(outer, inner, paint);
1628}
1629
reed41af9662015-01-05 07:49:08 -08001630void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001631 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001632 this->onDrawPaint(paint);
1633}
1634
1635void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001636 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001637 // To avoid redundant logic in our culling code and various backends, we always sort rects
1638 // before passing them along.
1639 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001640}
1641
msarettdca352e2016-08-26 06:37:45 -07001642void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001643 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001644 if (region.isEmpty()) {
1645 return;
1646 }
1647
1648 if (region.isRect()) {
1649 return this->drawIRect(region.getBounds(), paint);
1650 }
1651
1652 this->onDrawRegion(region, paint);
1653}
1654
reed41af9662015-01-05 07:49:08 -08001655void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001656 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001657 // To avoid redundant logic in our culling code and various backends, we always sort rects
1658 // before passing them along.
1659 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001660}
1661
1662void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001663 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001664 this->onDrawRRect(rrect, paint);
1665}
1666
1667void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001668 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001669 this->onDrawPoints(mode, count, pts, paint);
1670}
1671
Mike Reede88a1cb2017-03-17 09:50:46 -04001672void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1673 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001674 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001675 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001676 this->onDrawVerticesObject(vertices.get(), mode, paint);
1677}
1678
1679void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001681 RETURN_ON_NULL(vertices);
1682 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001683}
1684
1685void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001687 this->onDrawPath(path, paint);
1688}
1689
reeda85d4d02015-05-06 12:56:48 -07001690void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001691 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001692 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001693 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001694}
1695
Mike Reedc4e31092018-01-30 11:15:27 -05001696// Returns true if the rect can be "filled" : non-empty and finite
1697static bool fillable(const SkRect& r) {
1698 SkScalar w = r.width();
1699 SkScalar h = r.height();
1700 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1701}
1702
reede47829b2015-08-06 10:02:53 -07001703void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1704 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001705 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001706 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001707 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001708 return;
1709 }
1710 this->onDrawImageRect(image, &src, dst, paint, constraint);
1711}
reed41af9662015-01-05 07:49:08 -08001712
reed84984ef2015-07-17 07:09:43 -07001713void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1714 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001715 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001716 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001717}
1718
reede47829b2015-08-06 10:02:53 -07001719void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1720 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001721 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001722 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1723 constraint);
1724}
reede47829b2015-08-06 10:02:53 -07001725
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001726namespace {
1727class NoneOrLowQualityFilterPaint : SkNoncopyable {
1728public:
1729 NoneOrLowQualityFilterPaint(const SkPaint* origPaint) {
1730 if (origPaint && origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1731 fLazyPaint.set(*origPaint);
1732 fLazyPaint.get()->setFilterQuality(kLow_SkFilterQuality);
1733 fPaint = fLazyPaint.get();
1734 } else {
1735 fPaint = origPaint;
1736 }
1737 }
1738
1739 const SkPaint* get() const {
1740 return fPaint;
1741 }
1742
1743private:
1744 const SkPaint* fPaint;
1745 SkLazyPaint fLazyPaint;
1746};
1747} // namespace
1748
reed4c21dc52015-06-25 12:32:03 -07001749void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1750 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001752 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001753 if (dst.isEmpty()) {
1754 return;
1755 }
msarett552bca92016-08-03 06:53:26 -07001756 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001757 NoneOrLowQualityFilterPaint lowPaint(paint);
1758 this->onDrawImageNine(image, center, dst, lowPaint.get());
msarett552bca92016-08-03 06:53:26 -07001759 } else {
reede47829b2015-08-06 10:02:53 -07001760 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001761 }
reed4c21dc52015-06-25 12:32:03 -07001762}
1763
msarett16882062016-08-16 09:31:08 -07001764void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1765 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001766 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001767 RETURN_ON_NULL(image);
1768 if (dst.isEmpty()) {
1769 return;
1770 }
msarett71df2d72016-09-30 12:41:42 -07001771
1772 SkIRect bounds;
1773 Lattice latticePlusBounds = lattice;
1774 if (!latticePlusBounds.fBounds) {
1775 bounds = SkIRect::MakeWH(image->width(), image->height());
1776 latticePlusBounds.fBounds = &bounds;
1777 }
1778
1779 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001780 NoneOrLowQualityFilterPaint lowPaint(paint);
1781 this->onDrawImageLattice(image, latticePlusBounds, dst, lowPaint.get());
msarett16882062016-08-16 09:31:08 -07001782 } else {
1783 this->drawImageRect(image, dst, paint);
1784 }
1785}
1786
reed41af9662015-01-05 07:49:08 -08001787void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001788 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001789 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001790 return;
1791 }
reed41af9662015-01-05 07:49:08 -08001792 this->onDrawBitmap(bitmap, dx, dy, paint);
1793}
1794
reede47829b2015-08-06 10:02:53 -07001795void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001796 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001797 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001798 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001799 return;
1800 }
reede47829b2015-08-06 10:02:53 -07001801 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001802}
1803
reed84984ef2015-07-17 07:09:43 -07001804void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1805 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001806 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001807}
1808
reede47829b2015-08-06 10:02:53 -07001809void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1810 SrcRectConstraint constraint) {
1811 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1812 constraint);
1813}
reede47829b2015-08-06 10:02:53 -07001814
reed41af9662015-01-05 07:49:08 -08001815void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1816 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001817 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001818 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001819 return;
1820 }
msarett552bca92016-08-03 06:53:26 -07001821 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001822 NoneOrLowQualityFilterPaint lowPaint(paint);
1823 this->onDrawBitmapNine(bitmap, center, dst, lowPaint.get());
msarett552bca92016-08-03 06:53:26 -07001824 } else {
reeda5517e22015-07-14 10:54:12 -07001825 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001826 }
reed41af9662015-01-05 07:49:08 -08001827}
1828
msarettc573a402016-08-02 08:05:56 -07001829void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1830 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001831 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001832 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001833 return;
1834 }
msarett71df2d72016-09-30 12:41:42 -07001835
1836 SkIRect bounds;
1837 Lattice latticePlusBounds = lattice;
1838 if (!latticePlusBounds.fBounds) {
1839 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1840 latticePlusBounds.fBounds = &bounds;
1841 }
1842
1843 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001844 NoneOrLowQualityFilterPaint lowPaint(paint);
1845 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, lowPaint.get());
msarett552bca92016-08-03 06:53:26 -07001846 } else {
msarett16882062016-08-16 09:31:08 -07001847 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001848 }
msarettc573a402016-08-02 08:05:56 -07001849}
1850
reed71c3c762015-06-24 10:29:17 -07001851void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001852 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001853 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001854 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001855 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001856 if (count <= 0) {
1857 return;
1858 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001859 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001860 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001861 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001862}
1863
reedf70b5312016-03-04 16:36:20 -08001864void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001865 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001866 if (key) {
1867 this->onDrawAnnotation(rect, key, value);
1868 }
1869}
1870
reede47829b2015-08-06 10:02:53 -07001871void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1872 const SkPaint* paint, SrcRectConstraint constraint) {
1873 if (src) {
1874 this->drawImageRect(image, *src, dst, paint, constraint);
1875 } else {
1876 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1877 dst, paint, constraint);
1878 }
1879}
1880void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1881 const SkPaint* paint, SrcRectConstraint constraint) {
1882 if (src) {
1883 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1884 } else {
1885 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1886 dst, paint, constraint);
1887 }
1888}
1889
Mike Reed4204da22017-05-17 08:53:36 -04001890void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001891 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001892 this->onDrawShadowRec(path, rec);
1893}
1894
1895void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1896 SkPaint paint;
1897 const SkRect& pathBounds = path.getBounds();
1898
1899 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1900 while (iter.next()) {
1901 iter.fDevice->drawShadow(path, rec);
1902 }
1903 LOOPER_END
1904}
1905
reed@android.com8a1c16f2008-12-17 15:59:43 +00001906//////////////////////////////////////////////////////////////////////////////
1907// These are the virtual drawing methods
1908//////////////////////////////////////////////////////////////////////////////
1909
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001910void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001911 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001912 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1913 }
1914}
1915
reed41af9662015-01-05 07:49:08 -08001916void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001917 this->internalDrawPaint(paint);
1918}
1919
1920void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001921 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001922
1923 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001924 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001925 }
1926
reed@google.com4e2b3d32011-04-07 14:18:59 +00001927 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001928}
1929
reed41af9662015-01-05 07:49:08 -08001930void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1931 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001932 if ((long)count <= 0) {
1933 return;
1934 }
1935
Mike Reed822128b2017-02-28 16:41:03 -05001936 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001937 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001938 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001939 // special-case 2 points (common for drawing a single line)
1940 if (2 == count) {
1941 r.set(pts[0], pts[1]);
1942 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001943 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001944 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001945 if (!r.isFinite()) {
1946 return;
1947 }
Mike Reed822128b2017-02-28 16:41:03 -05001948 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001949 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1950 return;
1951 }
1952 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001953 }
reed@google.coma584aed2012-05-16 14:06:02 +00001954
halcanary96fcdcc2015-08-27 07:41:13 -07001955 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001957 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001958
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001960 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001961 }
reed@google.com4b226022011-01-11 18:32:13 +00001962
reed@google.com4e2b3d32011-04-07 14:18:59 +00001963 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001964}
1965
reed4a167172016-08-18 17:15:25 -07001966static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1967 return ((intptr_t)paint.getImageFilter() |
1968#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1969 (intptr_t)canvas->getDrawFilter() |
1970#endif
1971 (intptr_t)paint.getLooper() ) != 0;
1972}
1973
reed41af9662015-01-05 07:49:08 -08001974void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001975 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001977 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001978 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001979 return;
1980 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981 }
reed@google.com4b226022011-01-11 18:32:13 +00001982
reed4a167172016-08-18 17:15:25 -07001983 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05001984 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985
reed4a167172016-08-18 17:15:25 -07001986 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001987 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07001988 }
1989
1990 LOOPER_END
1991 } else {
Mike Reed822128b2017-02-28 16:41:03 -05001992 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07001993 SkDrawIter iter(this);
1994 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001995 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07001996 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998}
1999
msarett44df6512016-08-25 13:54:30 -07002000void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002001 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002002 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002003 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002004 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2005 return;
2006 }
msarett44df6512016-08-25 13:54:30 -07002007 }
2008
Mike Reed822128b2017-02-28 16:41:03 -05002009 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002010
2011 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002012 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002013 }
2014
2015 LOOPER_END
2016}
2017
reed41af9662015-01-05 07:49:08 -08002018void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002019 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002020 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002021 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002022 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002023 return;
2024 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002025 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002026
Mike Reed822128b2017-02-28 16:41:03 -05002027 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002028
2029 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002030 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002031 }
2032
2033 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002034}
2035
bsalomonac3aa242016-08-19 11:25:19 -07002036void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2037 SkScalar sweepAngle, bool useCenter,
2038 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002039 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002040 if (paint.canComputeFastBounds()) {
2041 SkRect storage;
2042 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002043 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002044 return;
2045 }
bsalomonac3aa242016-08-19 11:25:19 -07002046 }
2047
Mike Reed822128b2017-02-28 16:41:03 -05002048 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002049
2050 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002051 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002052 }
2053
2054 LOOPER_END
2055}
2056
reed41af9662015-01-05 07:49:08 -08002057void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002058 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002059 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002060 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2061 return;
2062 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002063 }
2064
2065 if (rrect.isRect()) {
2066 // call the non-virtual version
2067 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002068 return;
2069 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002070 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002071 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2072 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002073 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002074
Mike Reed822128b2017-02-28 16:41:03 -05002075 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002076
2077 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002078 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002079 }
2080
2081 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002082}
2083
Mike Reed822128b2017-02-28 16:41:03 -05002084void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002085 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002086 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002087 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2088 return;
2089 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002090 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002091
Mike Reed822128b2017-02-28 16:41:03 -05002092 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002093
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002094 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002095 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002096 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002097
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002098 LOOPER_END
2099}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002100
reed41af9662015-01-05 07:49:08 -08002101void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002102 if (!path.isFinite()) {
2103 return;
2104 }
2105
Mike Reed822128b2017-02-28 16:41:03 -05002106 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002107 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002108 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002109 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2110 return;
2111 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002112 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002113
Mike Reed822128b2017-02-28 16:41:03 -05002114 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002115 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002116 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002117 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002118 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120
Mike Reed822128b2017-02-28 16:41:03 -05002121 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002122
2123 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002124 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125 }
2126
reed@google.com4e2b3d32011-04-07 14:18:59 +00002127 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002128}
2129
reed262a71b2015-12-05 13:07:27 -08002130bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002131 if (!paint.getImageFilter()) {
2132 return false;
2133 }
2134
2135 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002136 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002137 return false;
2138 }
2139
2140 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2141 // Once we can filter and the filter will return a result larger than itself, we should be
2142 // able to remove this constraint.
2143 // skbug.com/4526
2144 //
2145 SkPoint pt;
2146 ctm.mapXY(x, y, &pt);
2147 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2148 return ir.contains(fMCRec->fRasterClip.getBounds());
2149}
2150
Mike Reedf441cfc2018-04-11 14:50:16 -04002151// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2152// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2153// null.
2154static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2155 if (paintParam) {
2156 *real = *paintParam;
2157 real->setStyle(SkPaint::kFill_Style);
2158 real->setPathEffect(nullptr);
2159 paintParam = real;
2160 }
2161 return paintParam;
2162}
2163
reeda85d4d02015-05-06 12:56:48 -07002164void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002165 SkPaint realPaint;
2166 paint = init_image_paint(&realPaint, paint);
2167
reeda85d4d02015-05-06 12:56:48 -07002168 SkRect bounds = SkRect::MakeXYWH(x, y,
2169 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002170 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002171 SkRect tmp = bounds;
2172 if (paint) {
2173 paint->computeFastBounds(tmp, &tmp);
2174 }
2175 if (this->quickReject(tmp)) {
2176 return;
2177 }
reeda85d4d02015-05-06 12:56:48 -07002178 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002179 // At this point we need a real paint object. If the caller passed null, then we should
2180 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2181 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2182 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002183
reeda2217ef2016-07-20 06:04:34 -07002184 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002185 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2186 *paint);
2187 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002188 special = this->getDevice()->makeSpecial(image);
2189 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002190 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002191 }
2192 }
2193
reed262a71b2015-12-05 13:07:27 -08002194 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2195
reeda85d4d02015-05-06 12:56:48 -07002196 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002197 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002198 if (special) {
2199 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002200 iter.fDevice->ctm().mapXY(x, y, &pt);
2201 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002202 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002203 SkScalarRoundToInt(pt.fY), pnt,
2204 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002205 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002206 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002207 }
reeda85d4d02015-05-06 12:56:48 -07002208 }
halcanary9d524f22016-03-29 09:03:52 -07002209
reeda85d4d02015-05-06 12:56:48 -07002210 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002211}
2212
reed41af9662015-01-05 07:49:08 -08002213void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002214 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002215 SkPaint realPaint;
2216 paint = init_image_paint(&realPaint, paint);
2217
halcanary96fcdcc2015-08-27 07:41:13 -07002218 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002219 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002220 if (paint) {
2221 paint->computeFastBounds(dst, &storage);
2222 }
2223 if (this->quickReject(storage)) {
2224 return;
2225 }
reeda85d4d02015-05-06 12:56:48 -07002226 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002227 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002228
senorblancoc41e7e12015-12-07 12:51:30 -08002229 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002230 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002231
reeda85d4d02015-05-06 12:56:48 -07002232 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002233 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002234 }
halcanary9d524f22016-03-29 09:03:52 -07002235
reeda85d4d02015-05-06 12:56:48 -07002236 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002237}
2238
reed41af9662015-01-05 07:49:08 -08002239void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002240 SkDEBUGCODE(bitmap.validate();)
2241
reed33366972015-10-08 09:22:02 -07002242 if (bitmap.drawsNothing()) {
2243 return;
2244 }
2245
Mike Reedf441cfc2018-04-11 14:50:16 -04002246 SkPaint realPaint;
2247 init_image_paint(&realPaint, paint);
2248 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002249
Mike Reed822128b2017-02-28 16:41:03 -05002250 SkRect bounds;
2251 bitmap.getBounds(&bounds);
2252 bounds.offset(x, y);
2253 bool canFastBounds = paint->canComputeFastBounds();
2254 if (canFastBounds) {
2255 SkRect storage;
2256 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002257 return;
2258 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259 }
reed@google.com4b226022011-01-11 18:32:13 +00002260
reeda2217ef2016-07-20 06:04:34 -07002261 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002262 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2263 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002264 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002265 special = this->getDevice()->makeSpecial(bitmap);
2266 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002267 drawAsSprite = false;
2268 }
2269 }
2270
Mike Reed822128b2017-02-28 16:41:03 -05002271 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002272
2273 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002274 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002275 if (special) {
reed262a71b2015-12-05 13:07:27 -08002276 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002277 iter.fDevice->ctm().mapXY(x, y, &pt);
2278 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002279 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002280 SkScalarRoundToInt(pt.fY), pnt,
2281 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002282 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002283 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002284 }
reed33366972015-10-08 09:22:02 -07002285 }
msarettfbfa2582016-08-12 08:29:08 -07002286
reed33366972015-10-08 09:22:02 -07002287 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288}
2289
reed@google.com9987ec32011-09-07 11:57:52 +00002290// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002291void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002292 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002293 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002294 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002295 return;
2296 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002297
halcanary96fcdcc2015-08-27 07:41:13 -07002298 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002299 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002300 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2301 return;
2302 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002303 }
reed@google.com3d608122011-11-21 15:16:16 +00002304
reed@google.com33535f32012-09-25 15:37:50 +00002305 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002306 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002307 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002309
senorblancoc41e7e12015-12-07 12:51:30 -08002310 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002311 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002312
reed@google.com33535f32012-09-25 15:37:50 +00002313 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002314 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002315 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002316
reed@google.com33535f32012-09-25 15:37:50 +00002317 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318}
2319
reed41af9662015-01-05 07:49:08 -08002320void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002321 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002322 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002323 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002324}
2325
reed4c21dc52015-06-25 12:32:03 -07002326void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2327 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002328 SkPaint realPaint;
2329 paint = init_image_paint(&realPaint, paint);
2330
halcanary96fcdcc2015-08-27 07:41:13 -07002331 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002332 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002333 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2334 return;
2335 }
reed@google.com3d608122011-11-21 15:16:16 +00002336 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002337 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002338
senorblancoc41e7e12015-12-07 12:51:30 -08002339 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002340
reed4c21dc52015-06-25 12:32:03 -07002341 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002342 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002343 }
halcanary9d524f22016-03-29 09:03:52 -07002344
reed4c21dc52015-06-25 12:32:03 -07002345 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002346}
2347
reed41af9662015-01-05 07:49:08 -08002348void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2349 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002350 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002351 SkPaint realPaint;
2352 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002353
halcanary96fcdcc2015-08-27 07:41:13 -07002354 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002355 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002356 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2357 return;
2358 }
reed4c21dc52015-06-25 12:32:03 -07002359 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002360 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002361
senorblancoc41e7e12015-12-07 12:51:30 -08002362 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002363
reed4c21dc52015-06-25 12:32:03 -07002364 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002365 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002366 }
halcanary9d524f22016-03-29 09:03:52 -07002367
reed4c21dc52015-06-25 12:32:03 -07002368 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002369}
2370
msarett16882062016-08-16 09:31:08 -07002371void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2372 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002373 SkPaint realPaint;
2374 paint = init_image_paint(&realPaint, paint);
2375
msarett16882062016-08-16 09:31:08 -07002376 if (nullptr == paint || paint->canComputeFastBounds()) {
2377 SkRect storage;
2378 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2379 return;
2380 }
2381 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002382 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002383
2384 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2385
2386 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002387 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002388 }
2389
2390 LOOPER_END
2391}
2392
2393void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2394 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002395 SkPaint realPaint;
2396 paint = init_image_paint(&realPaint, paint);
2397
msarett16882062016-08-16 09:31:08 -07002398 if (nullptr == paint || paint->canComputeFastBounds()) {
2399 SkRect storage;
2400 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2401 return;
2402 }
2403 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002404 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002405
2406 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2407
2408 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002409 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002410 }
2411
2412 LOOPER_END
2413}
2414
reed@google.come0d9ce82014-04-23 04:00:17 +00002415void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2416 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002417 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002418
2419 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002420 iter.fDevice->drawText(text, byteLength, x, y, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002421 }
2422
reed@google.com4e2b3d32011-04-07 14:18:59 +00002423 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424}
2425
reed@google.come0d9ce82014-04-23 04:00:17 +00002426void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2427 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002428 SkPoint textOffset = SkPoint::Make(0, 0);
2429
halcanary96fcdcc2015-08-27 07:41:13 -07002430 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002431
reed@android.com8a1c16f2008-12-17 15:59:43 +00002432 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002433 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002434 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002435
reed@google.com4e2b3d32011-04-07 14:18:59 +00002436 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002437}
2438
reed@google.come0d9ce82014-04-23 04:00:17 +00002439void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2440 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002441
2442 SkPoint textOffset = SkPoint::Make(0, constY);
2443
halcanary96fcdcc2015-08-27 07:41:13 -07002444 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002445
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002447 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002448 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002449
reed@google.com4e2b3d32011-04-07 14:18:59 +00002450 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451}
2452
reed@google.come0d9ce82014-04-23 04:00:17 +00002453void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2454 const SkMatrix* matrix, const SkPaint& paint) {
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->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002460
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002461 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002462}
2463
reed45561a02016-07-07 12:47:17 -07002464void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2465 const SkRect* cullRect, const SkPaint& paint) {
2466 if (cullRect && this->quickReject(*cullRect)) {
2467 return;
2468 }
2469
2470 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2471
2472 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002473 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002474 }
2475
2476 LOOPER_END
2477}
2478
fmalita00d5c2c2014-08-21 08:53:26 -07002479void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2480 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002481 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002482 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002483 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002484 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002485 SkRect tmp;
2486 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2487 return;
2488 }
2489 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002490 }
2491
fmalita024f9962015-03-03 19:08:17 -08002492 // We cannot filter in the looper as we normally do, because the paint is
2493 // incomplete at this point (text-related attributes are embedded within blob run paints).
2494 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002495 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002496
fmalita85d5eb92015-03-04 11:20:12 -08002497 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002498
fmalitaaa1b9122014-08-28 14:32:24 -07002499 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002500 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002501 }
2502
fmalitaaa1b9122014-08-28 14:32:24 -07002503 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002504
2505 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002506}
2507
Cary Clark2a475ea2017-04-28 15:35:12 -04002508void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2509 this->drawText(string.c_str(), string.size(), x, y, paint);
2510}
2511
reed@google.come0d9ce82014-04-23 04:00:17 +00002512// These will become non-virtual, so they always call the (virtual) onDraw... method
2513void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2514 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002515 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002516 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002517 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002518 this->onDrawText(text, byteLength, x, y, paint);
2519 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002520}
2521void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2522 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002523 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002524 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002525 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002526 this->onDrawPosText(text, byteLength, pos, paint);
2527 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002528}
2529void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2530 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002531 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002532 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002533 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002534 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2535 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002536}
2537void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2538 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002539 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002540 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002541 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002542 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2543 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002544}
reed45561a02016-07-07 12:47:17 -07002545void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2546 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002547 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002548 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002549 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002550 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2551 }
2552}
fmalita00d5c2c2014-08-21 08:53:26 -07002553void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2554 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002555 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002556 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002557 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002558 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002559}
reed@google.come0d9ce82014-04-23 04:00:17 +00002560
Mike Reede88a1cb2017-03-17 09:50:46 -04002561void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2562 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002563 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2564
2565 while (iter.next()) {
2566 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002567 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002568 }
2569
2570 LOOPER_END
2571}
2572
dandovb3c9d1c2014-08-12 08:34:29 -07002573void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002574 const SkPoint texCoords[4], SkBlendMode bmode,
2575 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002576 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002577 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002578 return;
2579 }
mtklein6cfa73a2014-08-13 13:33:49 -07002580
Mike Reedfaba3712016-11-03 14:45:31 -04002581 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002582}
2583
2584void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002585 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002586 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002587 // Since a patch is always within the convex hull of the control points, we discard it when its
2588 // bounding rectangle is completely outside the current clip.
2589 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002590 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002591 if (this->quickReject(bounds)) {
2592 return;
2593 }
mtklein6cfa73a2014-08-13 13:33:49 -07002594
Mike Reed435071e2017-05-23 11:22:56 -04002595 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2596
halcanary96fcdcc2015-08-27 07:41:13 -07002597 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002598
dandovecfff212014-08-04 10:02:00 -07002599 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002600 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002601 }
mtklein6cfa73a2014-08-13 13:33:49 -07002602
dandovecfff212014-08-04 10:02:00 -07002603 LOOPER_END
2604}
2605
reeda8db7282015-07-07 10:22:31 -07002606void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002607#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002608 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002609#endif
reede3b38ce2016-01-08 09:18:44 -08002610 RETURN_ON_NULL(dr);
2611 if (x || y) {
2612 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2613 this->onDrawDrawable(dr, &matrix);
2614 } else {
2615 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002616 }
2617}
2618
reeda8db7282015-07-07 10:22:31 -07002619void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002620#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002621 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002622#endif
reede3b38ce2016-01-08 09:18:44 -08002623 RETURN_ON_NULL(dr);
2624 if (matrix && matrix->isIdentity()) {
2625 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002626 }
reede3b38ce2016-01-08 09:18:44 -08002627 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002628}
2629
2630void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002631 // drawable bounds are no longer reliable (e.g. android displaylist)
2632 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002633 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002634}
2635
reed71c3c762015-06-24 10:29:17 -07002636void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002637 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002638 const SkRect* cull, const SkPaint* paint) {
2639 if (cull && this->quickReject(*cull)) {
2640 return;
2641 }
2642
2643 SkPaint pnt;
2644 if (paint) {
2645 pnt = *paint;
2646 }
halcanary9d524f22016-03-29 09:03:52 -07002647
halcanary96fcdcc2015-08-27 07:41:13 -07002648 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002649 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002650 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002651 }
2652 LOOPER_END
2653}
2654
reedf70b5312016-03-04 16:36:20 -08002655void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2656 SkASSERT(key);
2657
2658 SkPaint paint;
2659 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2660 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002661 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002662 }
2663 LOOPER_END
2664}
2665
reed@android.com8a1c16f2008-12-17 15:59:43 +00002666//////////////////////////////////////////////////////////////////////////////
2667// These methods are NOT virtual, and therefore must call back into virtual
2668// methods, rather than actually drawing themselves.
2669//////////////////////////////////////////////////////////////////////////////
2670
reed374772b2016-10-05 17:33:02 -07002671void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002672 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002673 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002674 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002675 this->drawPaint(paint);
2676}
2677
2678void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002679 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002680 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2681}
2682
Mike Reed3661bc92017-02-22 13:21:42 -05002683void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 pts[0].set(x0, y0);
2686 pts[1].set(x1, y1);
2687 this->drawPoints(kLines_PointMode, 2, pts, paint);
2688}
2689
Mike Reed3661bc92017-02-22 13:21:42 -05002690void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 if (radius < 0) {
2692 radius = 0;
2693 }
2694
2695 SkRect r;
2696 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002697 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698}
2699
2700void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2701 const SkPaint& paint) {
2702 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002703 SkRRect rrect;
2704 rrect.setRectXY(r, rx, ry);
2705 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 } else {
2707 this->drawRect(r, paint);
2708 }
2709}
2710
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2712 SkScalar sweepAngle, bool useCenter,
2713 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002714 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002715 if (oval.isEmpty() || !sweepAngle) {
2716 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002717 }
bsalomon21af9ca2016-08-25 12:29:23 -07002718 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719}
2720
2721void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2722 const SkPath& path, SkScalar hOffset,
2723 SkScalar vOffset, const SkPaint& paint) {
2724 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002725
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726 matrix.setTranslate(hOffset, vOffset);
2727 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2728}
2729
reed@android.comf76bacf2009-05-13 14:00:33 +00002730///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002731
Mike Klein88d90712018-01-27 17:30:04 +00002732/**
2733 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2734 * against the playback cost of recursing into the subpicture to get at its actual ops.
2735 *
2736 * For now we pick a conservatively small value, though measurement (and other heuristics like
2737 * the type of ops contained) may justify changing this value.
2738 */
2739#define kMaxPictureOpsToUnrollInsteadOfRef 1
2740
reedd5fa1a42014-08-09 11:08:05 -07002741void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002742 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002743 RETURN_ON_NULL(picture);
2744
reede3b38ce2016-01-08 09:18:44 -08002745 if (matrix && matrix->isIdentity()) {
2746 matrix = nullptr;
2747 }
Mike Klein88d90712018-01-27 17:30:04 +00002748 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2749 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2750 picture->playback(this);
2751 } else {
2752 this->onDrawPicture(picture, matrix, paint);
2753 }
reedd5fa1a42014-08-09 11:08:05 -07002754}
robertphillips9b14f262014-06-04 05:40:44 -07002755
reedd5fa1a42014-08-09 11:08:05 -07002756void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2757 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002758 if (!paint || paint->canComputeFastBounds()) {
2759 SkRect bounds = picture->cullRect();
2760 if (paint) {
2761 paint->computeFastBounds(bounds, &bounds);
2762 }
2763 if (matrix) {
2764 matrix->mapRect(&bounds);
2765 }
2766 if (this->quickReject(bounds)) {
2767 return;
2768 }
2769 }
2770
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002771 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002772 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773}
2774
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775///////////////////////////////////////////////////////////////////////////////
2776///////////////////////////////////////////////////////////////////////////////
2777
reed3aafe112016-08-18 12:45:34 -07002778SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002779 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780
2781 SkASSERT(canvas);
2782
reed3aafe112016-08-18 12:45:34 -07002783 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 fDone = !fImpl->next();
2785}
2786
2787SkCanvas::LayerIter::~LayerIter() {
2788 fImpl->~SkDrawIter();
2789}
2790
2791void SkCanvas::LayerIter::next() {
2792 fDone = !fImpl->next();
2793}
2794
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002795SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002796 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797}
2798
2799const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002800 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002801}
2802
2803const SkPaint& SkCanvas::LayerIter::paint() const {
2804 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002805 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002806 paint = &fDefaultPaint;
2807 }
2808 return *paint;
2809}
2810
Mike Reedca37f322018-03-08 13:22:16 -05002811SkIRect SkCanvas::LayerIter::clipBounds() const {
2812 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002813}
2814
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2816int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002817
2818///////////////////////////////////////////////////////////////////////////////
2819
Brian Osman10fc6fd2018-03-02 11:01:10 -05002820// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002821static bool supported_for_raster_canvas(const SkImageInfo& info) {
2822 switch (info.alphaType()) {
2823 case kPremul_SkAlphaType:
2824 case kOpaque_SkAlphaType:
2825 break;
2826 default:
2827 return false;
2828 }
2829
2830 switch (info.colorType()) {
2831 case kAlpha_8_SkColorType:
2832 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002833 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002834 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002835 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002836 break;
2837 default:
2838 return false;
2839 }
2840
2841 return true;
2842}
2843
Mike Reed5df49342016-11-12 08:06:55 -06002844std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002845 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002846 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002847 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002848 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002849
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002850 SkBitmap bitmap;
2851 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002852 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002853 }
Mike Reed12f77342017-11-08 11:19:52 -05002854
2855 return props ?
2856 skstd::make_unique<SkCanvas>(bitmap, *props) :
2857 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002858}
reedd5fa1a42014-08-09 11:08:05 -07002859
2860///////////////////////////////////////////////////////////////////////////////
2861
Florin Malitaee424ac2016-12-01 12:47:59 -05002862SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2863 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2864
Florin Malita439ace92016-12-02 12:05:41 -05002865SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2866 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2867
Herb Derby76d69b42018-03-15 17:34:40 -04002868SkNoDrawCanvas::SkNoDrawCanvas(SkBaseDevice *device)
2869 : INHERITED(device) {}
2870
Florin Malitaee424ac2016-12-01 12:47:59 -05002871SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2872 (void)this->INHERITED::getSaveLayerStrategy(rec);
2873 return kNoLayer_SaveLayerStrategy;
2874}
2875
2876///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002877
reed73603f32016-09-20 08:42:38 -07002878static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2879static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2880static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2881static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2882static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2883static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002884
2885///////////////////////////////////////////////////////////////////////////////////////////////////
2886
2887SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2888 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002889 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002890 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2891 SkIPoint origin = dev->getOrigin();
2892 SkMatrix ctm = this->getTotalMatrix();
2893 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2894
2895 SkIRect clip = fMCRec->fRasterClip.getBounds();
2896 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002897 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002898 clip.setEmpty();
2899 }
2900
2901 fAllocator->updateHandle(handle, ctm, clip);
2902 return handle;
2903 }
2904 return nullptr;
2905}
2906
2907static bool install(SkBitmap* bm, const SkImageInfo& info,
2908 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002909 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002910}
2911
2912SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2913 SkBitmap* bm) {
2914 SkRasterHandleAllocator::Rec rec;
2915 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2916 return nullptr;
2917 }
2918 return rec.fHandle;
2919}
2920
2921std::unique_ptr<SkCanvas>
2922SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2923 const SkImageInfo& info, const Rec* rec) {
2924 if (!alloc || !supported_for_raster_canvas(info)) {
2925 return nullptr;
2926 }
2927
2928 SkBitmap bm;
2929 Handle hndl;
2930
2931 if (rec) {
2932 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2933 } else {
2934 hndl = alloc->allocBitmap(info, &bm);
2935 }
2936 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2937}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002938
2939///////////////////////////////////////////////////////////////////////////////////////////////////
2940
2941