blob: 82237cf823264853193c0163f689efa20b768767 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040026#include "SkMSAN.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040031#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000032#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000033#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050034#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000035#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040037#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050047#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050050#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050051#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052
reede3b38ce2016-01-08 09:18:44 -080053#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050054#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080055
Mike Reed139e5e02017-03-08 11:29:33 -050056///////////////////////////////////////////////////////////////////////////////////////////////////
57
reedc83a2972015-07-16 07:40:45 -070058/*
59 * Return true if the drawing this rect would hit every pixels in the canvas.
60 *
61 * Returns false if
62 * - rect does not contain the canvas' bounds
63 * - paint is not fill
64 * - paint would blur or otherwise change the coverage of the rect
65 */
66bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
67 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070068 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
69 (int)kNone_ShaderOverrideOpacity,
70 "need_matching_enums0");
71 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
72 (int)kOpaque_ShaderOverrideOpacity,
73 "need_matching_enums1");
74 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
75 (int)kNotOpaque_ShaderOverrideOpacity,
76 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070077
78 const SkISize size = this->getBaseLayerSize();
79 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050080
81 // if we're clipped at all, we can't overwrite the entire surface
82 {
83 SkBaseDevice* base = this->getDevice();
84 SkBaseDevice* top = this->getTopDevice();
85 if (base != top) {
86 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
87 }
88 if (!base->clipIsWideOpen()) {
89 return false;
90 }
reedc83a2972015-07-16 07:40:45 -070091 }
92
93 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070094 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070095 return false; // conservative
96 }
halcanaryc5769b22016-08-10 07:13:21 -070097
98 SkRect devRect;
99 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
100 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700101 return false;
102 }
103 }
104
105 if (paint) {
106 SkPaint::Style paintStyle = paint->getStyle();
107 if (!(paintStyle == SkPaint::kFill_Style ||
108 paintStyle == SkPaint::kStrokeAndFill_Style)) {
109 return false;
110 }
111 if (paint->getMaskFilter() || paint->getLooper()
112 || paint->getPathEffect() || paint->getImageFilter()) {
113 return false; // conservative
114 }
115 }
116 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
117}
118
119///////////////////////////////////////////////////////////////////////////////////////////////////
120
reed@google.comda17f752012-08-16 18:27:05 +0000121// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122//#define SK_TRACE_SAVERESTORE
123
124#ifdef SK_TRACE_SAVERESTORE
125 static int gLayerCounter;
126 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
127 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
128
129 static int gRecCounter;
130 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
131 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
132
133 static int gCanvasCounter;
134 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
135 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
136#else
137 #define inc_layer()
138 #define dec_layer()
139 #define inc_rec()
140 #define dec_rec()
141 #define inc_canvas()
142 #define dec_canvas()
143#endif
144
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000145typedef SkTLazy<SkPaint> SkLazyPaint;
146
reedc83a2972015-07-16 07:40:45 -0700147void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000148 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700149 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
150 ? SkSurface::kDiscard_ContentChangeMode
151 : SkSurface::kRetain_ContentChangeMode);
152 }
153}
154
155void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
156 ShaderOverrideOpacity overrideOpacity) {
157 if (fSurfaceBase) {
158 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
159 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
160 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
161 // and therefore we don't care which mode we're in.
162 //
163 if (fSurfaceBase->outstandingImageSnapshot()) {
164 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
165 mode = SkSurface::kDiscard_ContentChangeMode;
166 }
167 }
168 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000169 }
170}
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000174/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 The clip/matrix/proc are fields that reflect the top of the save/restore
176 stack. Whenever the canvas changes, it marks a dirty flag, and then before
177 these are used (assuming we're not on a layer) we rebuild these cache
178 values: they reflect the top of the save stack, but translated and clipped
179 by the device's XY offset and bitmap-bounds.
180*/
181struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400182 DeviceCM* fNext;
183 sk_sp<SkBaseDevice> fDevice;
184 SkRasterClip fClip;
185 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
186 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400187 sk_sp<SkImage> fClipImage;
188 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000191 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700192 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400193 , fDevice(std::move(device))
194 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700195 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000196 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400197 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400198 {}
reed@google.com4b226022011-01-11 18:32:13 +0000199
mtkleinfeaadee2015-04-08 11:25:48 -0700200 void reset(const SkIRect& bounds) {
201 SkASSERT(!fPaint);
202 SkASSERT(!fNext);
203 SkASSERT(fDevice);
204 fClip.setRect(bounds);
205 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206};
207
208/* This is the record we keep for each save/restore level in the stack.
209 Since a level optionally copies the matrix and/or stack, we have pointers
210 for these fields. If the value is copied for this level, the copy is
211 stored in the ...Storage field, and the pointer points to that. If the
212 value is not copied for this level, we ignore ...Storage, and just point
213 at the corresponding value in the previous level in the stack.
214*/
215class SkCanvas::MCRec {
216public:
reed1f836ee2014-07-07 07:49:34 -0700217 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700218 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 /* If there are any layers in the stack, this points to the top-most
220 one that is at or below this level in the stack (so we know what
221 bitmap/device to draw into from this level. This value is NOT
222 reference counted, since the real owner is either our fLayer field,
223 or a previous one in a lower level.)
224 */
Mike Reeda1361362017-03-07 09:37:29 -0500225 DeviceCM* fTopLayer;
226 SkConservativeClip fRasterClip;
227 SkMatrix fMatrix;
228 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
Mike Reeda1361362017-03-07 09:37:29 -0500230 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700231 fFilter = nullptr;
232 fLayer = nullptr;
233 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800234 fMatrix.reset();
235 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700236
reedd9544982014-09-09 18:46:22 -0700237 // don't bother initializing fNext
238 inc_rec();
239 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400240 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700241 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700242 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700243 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 // don't bother initializing fNext
247 inc_rec();
248 }
249 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000250 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700251 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 dec_rec();
253 }
mtkleinfeaadee2015-04-08 11:25:48 -0700254
255 void reset(const SkIRect& bounds) {
256 SkASSERT(fLayer);
257 SkASSERT(fDeferredSaveCount == 0);
258
259 fMatrix.reset();
260 fRasterClip.setRect(bounds);
261 fLayer->reset(bounds);
262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263};
264
Mike Reeda1361362017-03-07 09:37:29 -0500265class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266public:
Mike Reeda1361362017-03-07 09:37:29 -0500267 SkDrawIter(SkCanvas* canvas)
268 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
269 {}
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000272 const DeviceCM* rec = fCurrLayer;
273 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400274 fDevice = rec->fDevice.get();
275 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700277 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 return true;
279 }
280 return false;
281 }
reed@google.com4b226022011-01-11 18:32:13 +0000282
reed@google.com6f8f2922011-03-04 22:27:10 +0000283 int getX() const { return fDevice->getOrigin().x(); }
284 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286
Mike Reed99330ba2017-02-22 11:01:08 -0500287 SkBaseDevice* fDevice;
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const DeviceCM* fCurrLayer;
291 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292};
293
Florin Malita713b8ef2017-04-28 10:57:24 -0400294#define FOR_EACH_TOP_DEVICE( code ) \
295 do { \
296 DeviceCM* layer = fMCRec->fTopLayer; \
297 while (layer) { \
298 SkBaseDevice* device = layer->fDevice.get(); \
299 if (device) { \
300 code; \
301 } \
302 layer = layer->fNext; \
303 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500304 } while (0)
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306/////////////////////////////////////////////////////////////////////////////
307
reeddbc3cef2015-04-29 12:18:57 -0700308static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
309 return lazy->isValid() ? lazy->get() : lazy->set(orig);
310}
311
312/**
313 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700314 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700315 */
reedd053ce92016-03-22 10:17:23 -0700316static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700317 SkImageFilter* imgf = paint.getImageFilter();
318 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700320 }
321
reedd053ce92016-03-22 10:17:23 -0700322 SkColorFilter* imgCFPtr;
323 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
reedd053ce92016-03-22 10:17:23 -0700326 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700327
328 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700330 // there is no existing paint colorfilter, so we can just return the imagefilter's
331 return imgCF;
332 }
333
334 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
335 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500336 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700337}
338
senorblanco87e066e2015-10-28 11:23:36 -0700339/**
340 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
341 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
342 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
343 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
344 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
345 * conservative "effective" bounds based on the settings in the paint... with one exception. This
346 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
347 * deliberately ignored.
348 */
349static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
350 const SkRect& rawBounds,
351 SkRect* storage) {
352 SkPaint tmpUnfiltered(paint);
353 tmpUnfiltered.setImageFilter(nullptr);
354 if (tmpUnfiltered.canComputeFastBounds()) {
355 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
356 } else {
357 return rawBounds;
358 }
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361class AutoDrawLooper {
362public:
senorblanco87e066e2015-10-28 11:23:36 -0700363 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
364 // paint. It's used to determine the size of the offscreen layer for filters.
365 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700366 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700367 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000368 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800369#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800371#else
372 fFilter = nullptr;
373#endif
reed4a8126e2014-09-22 07:29:03 -0700374 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000375 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700376 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000377 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378
reedd053ce92016-03-22 10:17:23 -0700379 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700380 if (simplifiedCF) {
381 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700382 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700383 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700384 fPaint = paint;
385 }
386
387 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700388 /**
389 * We implement ImageFilters for a given draw by creating a layer, then applying the
390 * imagefilter to the pixels of that layer (its backing surface/image), and then
391 * we call restore() to xfer that layer to the main canvas.
392 *
393 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
394 * 2. Generate the src pixels:
395 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
396 * return (fPaint). We then draw the primitive (using srcover) into a cleared
397 * buffer/surface.
398 * 3. Restore the layer created in #1
399 * The imagefilter is passed the buffer/surface from the layer (now filled with the
400 * src pixels of the primitive). It returns a new "filtered" buffer, which we
401 * draw onto the previous layer using the xfermode from the original paint.
402 */
reed@google.com8926b162012-03-23 15:36:36 +0000403 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500404 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700405 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700406 SkRect storage;
407 if (rawBounds) {
408 // Make rawBounds include all paint outsets except for those due to image filters.
409 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
410 }
reedbfd5f172016-01-07 11:28:08 -0800411 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700412 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700413 fTempLayerForImageFilter = true;
414 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000415 }
416
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000417 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500418 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000419 fIsSimple = false;
420 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700421 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000422 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700423 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000424 }
425 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000426
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700428 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000429 fCanvas->internalRestore();
430 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000431 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000433
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 const SkPaint& paint() const {
435 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400436 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000439
reed@google.com129ec222012-05-15 13:24:09 +0000440 bool next(SkDrawFilter::Type drawType) {
441 if (fDone) {
442 return false;
443 } else if (fIsSimple) {
444 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000445 return !fPaint->nothingToDraw();
446 } else {
447 return this->doNext(drawType);
448 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000449 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000450
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500452 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700453 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 SkCanvas* fCanvas;
455 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000456 SkDrawFilter* fFilter;
457 const SkPaint* fPaint;
458 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700459 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000460 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000461 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000462 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400463 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000464
465 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466};
467
reed@google.com129ec222012-05-15 13:24:09 +0000468bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700469 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000470 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700471 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000472
reeddbc3cef2015-04-29 12:18:57 -0700473 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
474 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400475 // never want our downstream clients (i.e. devices) to see loopers
476 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000477
reed5c476fb2015-04-20 08:04:21 -0700478 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700479 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700480 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000481 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000484 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000485 return false;
486 }
487 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000488 if (!fFilter->filter(paint, drawType)) {
489 fDone = true;
Mike Reed59af19f2018-04-12 17:26:40 -0400490 return false; // can we really do this, if we haven't finished fLooperContext?
reed@google.com971aca72012-11-26 20:26:54 +0000491 }
halcanary96fcdcc2015-08-27 07:41:13 -0700492 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000493 // no looper means we only draw once
494 fDone = true;
495 }
496 }
497 fPaint = paint;
498
499 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000500 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000501 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000502 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000503 return true;
504}
505
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506////////// macros to place around the internal draw calls //////////////////
507
reed3aafe112016-08-18 12:45:34 -0700508#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
509 this->predrawNotify(); \
510 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
511 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800512 SkDrawIter iter(this);
513
514
reed@google.com8926b162012-03-23 15:36:36 +0000515#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000516 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700517 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000518 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000519 SkDrawIter iter(this);
520
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000521#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000522 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700523 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000524 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000526
reedc83a2972015-07-16 07:40:45 -0700527#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
528 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700529 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700530 while (looper.next(type)) { \
531 SkDrawIter iter(this);
532
reed@google.com4e2b3d32011-04-07 14:18:59 +0000533#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
535////////////////////////////////////////////////////////////////////////////
536
msarettfbfa2582016-08-12 08:29:08 -0700537static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
538 if (bounds.isEmpty()) {
539 return SkRect::MakeEmpty();
540 }
541
542 // Expand bounds out by 1 in case we are anti-aliasing. We store the
543 // bounds as floats to enable a faster quick reject implementation.
544 SkRect dst;
545 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
546 return dst;
547}
548
mtkleinfeaadee2015-04-08 11:25:48 -0700549void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
550 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700551 fMCRec->reset(bounds);
552
553 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500554 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400555 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700556 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700557 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700558}
559
Herb Derbyefe39bc2018-05-01 17:06:20 -0400560void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800561 if (device && device->forceConservativeRasterClip()) {
562 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
563 }
reed42b73eb2015-11-20 13:42:42 -0800564
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000565 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800566 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700567 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000568
569 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500570 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500571 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700572 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573
reeda499f902015-05-01 09:34:31 -0700574 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
575 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400576 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700577
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579
halcanary96fcdcc2015-08-27 07:41:13 -0700580 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000581
reedf92c8662014-08-18 08:02:43 -0700582 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700583 // The root device and the canvas should always have the same pixel geometry
584 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800585 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700586 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500587
Mike Reedc42a1cd2017-02-14 14:25:14 -0500588 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700589 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590}
591
reed@google.comcde92112011-07-06 20:00:52 +0000592SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000593 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700594 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000595{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000596 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000597
halcanary96fcdcc2015-08-27 07:41:13 -0700598 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000599}
600
reed96a857e2015-01-25 10:33:58 -0800601SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800603 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000604{
605 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400606 this->init(sk_make_sp<SkNoPixelsDevice>(
607 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700608}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000609
reed78e27682014-11-19 08:04:34 -0800610SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700612 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700613{
614 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700615
Mike Reed566e53c2017-03-10 10:49:45 -0500616 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400617 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700618}
619
Herb Derbyefe39bc2018-05-01 17:06:20 -0400620SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000621 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700622 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000623{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700625
reedd9544982014-09-09 18:46:22 -0700626 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627}
628
Herb Derbyefe39bc2018-05-01 17:06:20 -0400629SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700630 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700631 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700632{
633 inc_canvas();
634
635 this->init(device, flags);
636}
637
reed4a8126e2014-09-22 07:29:03 -0700638SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700639 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700640 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700641{
642 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700643
Mike Reed910ca0f2018-04-25 13:04:05 -0400644 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400645 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700646}
reed29c857d2014-09-21 10:25:07 -0700647
Mike Reed356f7c22017-01-10 11:58:39 -0500648SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
649 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700650 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
651 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500652 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700653{
654 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700655
Mike Reed910ca0f2018-04-25 13:04:05 -0400656 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400657 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658}
659
Mike Reed356f7c22017-01-10 11:58:39 -0500660SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
661
Matt Sarett31f99ce2017-04-11 08:46:01 -0400662#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
663SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
666 , fAllocator(nullptr)
667{
668 inc_canvas();
669
670 SkBitmap tmp(bitmap);
671 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400672 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400673 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400674}
675#endif
676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677SkCanvas::~SkCanvas() {
678 // free up the contents of our deque
679 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000680
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681 this->internalRestore(); // restore the last, since we're going away
682
halcanary385fe4d2015-08-26 13:07:48 -0700683 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000684
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 dec_canvas();
686}
687
fmalita53d9f1c2016-01-25 06:23:54 -0800688#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689SkDrawFilter* SkCanvas::getDrawFilter() const {
690 return fMCRec->fFilter;
691}
692
693SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700694 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
696 return filter;
697}
fmalita77650002016-01-21 18:47:11 -0800698#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000700SkMetaData& SkCanvas::getMetaData() {
701 // metadata users are rare, so we lazily allocate it. If that changes we
702 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700703 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000704 fMetaData = new SkMetaData;
705 }
706 return *fMetaData;
707}
708
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709///////////////////////////////////////////////////////////////////////////////
710
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000711void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700712 this->onFlush();
713}
714
715void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000716 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000717 if (device) {
718 device->flush();
719 }
720}
721
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000722SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000723 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000724 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
725}
726
senorblancoafc7cce2016-02-02 18:44:15 -0800727SkIRect SkCanvas::getTopLayerBounds() const {
728 SkBaseDevice* d = this->getTopDevice();
729 if (!d) {
730 return SkIRect::MakeEmpty();
731 }
732 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
733}
734
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000735SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000737 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400739 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740}
741
Florin Malita0ed3b642017-01-13 16:56:38 +0000742SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400743 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000744}
745
Mike Reed353196f2017-07-21 11:01:18 -0400746bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000747 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400748 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000749}
750
Mike Reed353196f2017-07-21 11:01:18 -0400751bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
752 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400753}
754
755bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
756 SkPixmap pm;
757 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
758}
759
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000760bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400761 SkPixmap pm;
762 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700763 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000764 }
765 return false;
766}
767
Matt Sarett03dd6d52017-01-23 12:15:09 -0500768bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000769 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000770 SkBaseDevice* device = this->getDevice();
771 if (!device) {
772 return false;
773 }
774
Matt Sarett03dd6d52017-01-23 12:15:09 -0500775 // This check gives us an early out and prevents generation ID churn on the surface.
776 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
777 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
778 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
779 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000780 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000781
Matt Sarett03dd6d52017-01-23 12:15:09 -0500782 // Tell our owning surface to bump its generation ID.
783 const bool completeOverwrite =
784 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700785 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700786
Matt Sarett03dd6d52017-01-23 12:15:09 -0500787 // This can still fail, most notably in the case of a invalid color type or alpha type
788 // conversion. We could pull those checks into this function and avoid the unnecessary
789 // generation ID bump. But then we would be performing those checks twice, since they
790 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400791 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000792}
reed@google.com51df9e32010-12-23 19:29:18 +0000793
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794//////////////////////////////////////////////////////////////////////////////
795
reed2ff1fce2014-12-11 07:07:37 -0800796void SkCanvas::checkForDeferredSave() {
797 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800798 this->doSave();
799 }
800}
801
reedf0090cb2014-11-26 08:55:51 -0800802int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800803#ifdef SK_DEBUG
804 int count = 0;
805 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
806 for (;;) {
807 const MCRec* rec = (const MCRec*)iter.next();
808 if (!rec) {
809 break;
810 }
811 count += 1 + rec->fDeferredSaveCount;
812 }
813 SkASSERT(count == fSaveCount);
814#endif
815 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800816}
817
818int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800819 fSaveCount += 1;
820 fMCRec->fDeferredSaveCount += 1;
821 return this->getSaveCount() - 1; // return our prev value
822}
823
824void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800825 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700826
827 SkASSERT(fMCRec->fDeferredSaveCount > 0);
828 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800829 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800830}
831
832void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800833 if (fMCRec->fDeferredSaveCount > 0) {
834 SkASSERT(fSaveCount > 1);
835 fSaveCount -= 1;
836 fMCRec->fDeferredSaveCount -= 1;
837 } else {
838 // check for underflow
839 if (fMCStack.count() > 1) {
840 this->willRestore();
841 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700842 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800843 this->internalRestore();
844 this->didRestore();
845 }
reedf0090cb2014-11-26 08:55:51 -0800846 }
847}
848
849void SkCanvas::restoreToCount(int count) {
850 // sanity check
851 if (count < 1) {
852 count = 1;
853 }
mtkleinf0f14112014-12-12 08:46:25 -0800854
reedf0090cb2014-11-26 08:55:51 -0800855 int n = this->getSaveCount() - count;
856 for (int i = 0; i < n; ++i) {
857 this->restore();
858 }
859}
860
reed2ff1fce2014-12-11 07:07:37 -0800861void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700863 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000865
Mike Reedc42a1cd2017-02-14 14:25:14 -0500866 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867}
868
reed4960eee2015-12-18 07:09:18 -0800869bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400870 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871}
872
reed4960eee2015-12-18 07:09:18 -0800873bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700874 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500875 SkIRect clipBounds = this->getDeviceClipBounds();
876 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000877 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000878 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000879
reed96e657d2015-03-10 17:30:07 -0700880 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
881
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000882 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700883 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800884 if (bounds && !imageFilter->canComputeFastBounds()) {
885 bounds = nullptr;
886 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000887 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000888 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700889 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000890 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700891 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000892 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000893 } else { // no user bounds, so just use the clip
894 ir = clipBounds;
895 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800896
897 // early exit if the layer's bounds are clipped out
898 if (!ir.intersect(clipBounds)) {
899 if (BoundsAffectsClip(saveLayerFlags)) {
900 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
901 fMCRec->fRasterClip.setEmpty();
902 fDeviceClipBounds.setEmpty();
903 }
904 return false;
905 }
reed180aec42015-03-11 10:39:04 -0700906 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000907
reed4960eee2015-12-18 07:09:18 -0800908 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700909 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700910 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700911 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000912 }
913
914 if (intersection) {
915 *intersection = ir;
916 }
917 return true;
918}
919
reed4960eee2015-12-18 07:09:18 -0800920int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
921 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000922}
923
reed70ee31b2015-12-10 13:44:45 -0800924int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800925 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
926}
927
Cary Clarke041e312018-03-06 13:00:52 -0500928int SkCanvas::saveLayer(const SaveLayerRec& rec) {
929 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800930 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500931 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800932 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800933}
934
reeda2217ef2016-07-20 06:04:34 -0700935void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500936 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500937 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700938 SkDraw draw;
939 SkRasterClip rc;
940 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
941 if (!dst->accessPixels(&draw.fDst)) {
942 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800943 }
reeda2217ef2016-07-20 06:04:34 -0700944 draw.fMatrix = &SkMatrix::I();
945 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800946
947 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500948 if (filter) {
949 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
950 }
reeda2217ef2016-07-20 06:04:34 -0700951
Mike Reedc42a1cd2017-02-14 14:25:14 -0500952 int x = src->getOrigin().x() - dstOrigin.x();
953 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700954 auto special = src->snapSpecial();
955 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400956 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700957 }
robertphillips7354a4b2015-12-16 05:08:27 -0800958}
reed70ee31b2015-12-10 13:44:45 -0800959
Mike Kleine083f7c2018-02-07 12:54:27 -0500960static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500961 // Need to force L32 for now if we have an image filter.
962 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
963 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500964 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800965 }
Mike Klein649fb732018-02-26 15:09:16 -0500966
967 SkColorType ct = prev.colorType();
968 if (prev.bytesPerPixel() <= 4) {
969 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
970 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
971 ct = kN32_SkColorType;
972 }
973 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800974}
975
reed4960eee2015-12-18 07:09:18 -0800976void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
977 const SkRect* bounds = rec.fBounds;
978 const SkPaint* paint = rec.fPaint;
979 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
980
reed8c30a812016-04-20 16:36:51 -0700981 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400982 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700983 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400984 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700985 SkMatrix remainder;
986 SkSize scale;
987 /*
988 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
989 * but they do handle scaling. To accommodate this, we do the following:
990 *
991 * 1. Stash off the current CTM
992 * 2. Decompose the CTM into SCALE and REMAINDER
993 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
994 * contains the REMAINDER
995 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
996 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
997 * of the original imagefilter, and draw that (via drawSprite)
998 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
999 *
1000 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1001 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1002 */
reed96a04f32016-04-25 09:25:15 -07001003 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001004 stashedMatrix.decomposeScale(&scale, &remainder))
1005 {
1006 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001007 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001008 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1009 SkPaint* p = lazyP.set(*paint);
1010 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1011 SkFilterQuality::kLow_SkFilterQuality,
1012 sk_ref_sp(imageFilter)));
1013 imageFilter = p->getImageFilter();
1014 paint = p;
1015 }
reed8c30a812016-04-20 16:36:51 -07001016
junov@chromium.orga907ac32012-02-24 21:54:07 +00001017 // do this before we create the layer. We don't call the public save() since
1018 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001019 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001020
junov@chromium.orga907ac32012-02-24 21:54:07 +00001021 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001022 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001023 if (modifiedRec) {
1024 // In this case there will be no layer in which to stash the matrix so we need to
1025 // revert the prior MCRec to its earlier state.
1026 modifiedRec->fMatrix = stashedMatrix;
1027 }
reed2ff1fce2014-12-11 07:07:37 -08001028 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 }
1030
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001031 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1032 // the clipRectBounds() call above?
1033 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001034 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001035 }
1036
reed8dc0ccb2015-03-20 06:32:52 -07001037 SkPixelGeometry geo = fProps.pixelGeometry();
1038 if (paint) {
reed76033be2015-03-14 10:54:31 -07001039 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001040 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001041 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001042 }
1043 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044
robertphillips5139e502016-07-19 05:10:40 -07001045 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001046 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001047 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001048 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001049 }
reedb2db8982014-11-13 12:41:02 -08001050
Mike Kleine083f7c2018-02-07 12:54:27 -05001051 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001052
Hal Canary704cd322016-11-07 14:13:52 -05001053 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001054 {
reed70ee31b2015-12-10 13:44:45 -08001055 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001056 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001057 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Mike Reed910ca0f2018-04-25 13:04:05 -04001058 const bool trackCoverage = SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001059 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001060 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001061 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001062 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001063 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1064 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001065 return;
reed61f501f2015-04-29 08:34:00 -07001066 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001067 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001068 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069
Mike Reedb43a3e02017-02-11 10:18:58 -05001070 // only have a "next" if this new layer doesn't affect the clip (rare)
1071 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072 fMCRec->fLayer = layer;
1073 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001074
Mike Reedc61abee2017-02-28 17:45:27 -05001075 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001076 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001077 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001078 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001079
Mike Reedc42a1cd2017-02-14 14:25:14 -05001080 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1081
1082 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1083 if (layer->fNext) {
1084 // need to punch a hole in the previous device, so we don't draw there, given that
1085 // the new top-layer will allow drawing to happen "below" it.
1086 SkRegion hole(ir);
1087 do {
1088 layer = layer->fNext;
1089 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1090 } while (layer->fNext);
1091 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092}
1093
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001094int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001095 if (0xFF == alpha) {
1096 return this->saveLayer(bounds, nullptr);
1097 } else {
1098 SkPaint tmpPaint;
1099 tmpPaint.setAlpha(alpha);
1100 return this->saveLayer(bounds, &tmpPaint);
1101 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001102}
1103
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104void SkCanvas::internalRestore() {
1105 SkASSERT(fMCStack.count() != 0);
1106
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001107 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108 DeviceCM* layer = fMCRec->fLayer; // may be null
1109 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001110 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111
1112 // now do the normal restore()
1113 fMCRec->~MCRec(); // balanced in save()
1114 fMCStack.pop_back();
1115 fMCRec = (MCRec*)fMCStack.back();
1116
Mike Reedc42a1cd2017-02-14 14:25:14 -05001117 if (fMCRec) {
1118 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1119 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001120
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1122 since if we're being recorded, we don't want to record this (the
1123 recorder will have already recorded the restore).
1124 */
bsalomon49f085d2014-09-05 13:34:00 -07001125 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001126 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001127 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001128 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001129 layer->fPaint.get(),
1130 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001131 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001132 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001133 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001134 delete layer;
reedb679ca82015-04-07 04:40:48 -07001135 } else {
1136 // we're at the root
reeda499f902015-05-01 09:34:31 -07001137 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001138 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001139 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001141 }
msarettfbfa2582016-08-12 08:29:08 -07001142
1143 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001144 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001145 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147}
1148
reede8f30622016-03-23 18:59:25 -07001149sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001150 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001151 props = &fProps;
1152 }
1153 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001154}
1155
reede8f30622016-03-23 18:59:25 -07001156sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001157 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001158 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001159}
1160
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001161SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001162 return this->onImageInfo();
1163}
1164
1165SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001166 SkBaseDevice* dev = this->getDevice();
1167 if (dev) {
1168 return dev->imageInfo();
1169 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001170 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001171 }
1172}
1173
brianosman898235c2016-04-06 07:38:23 -07001174bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001175 return this->onGetProps(props);
1176}
1177
1178bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001179 SkBaseDevice* dev = this->getDevice();
1180 if (dev) {
1181 if (props) {
1182 *props = fProps;
1183 }
1184 return true;
1185 } else {
1186 return false;
1187 }
1188}
1189
reed6ceeebd2016-03-09 14:26:26 -08001190bool SkCanvas::peekPixels(SkPixmap* pmap) {
1191 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001192}
1193
reed884e97c2015-05-26 11:31:54 -07001194bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001195 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001196 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001197}
1198
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001199void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001200 SkPixmap pmap;
1201 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001202 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001203 }
1204 if (info) {
1205 *info = pmap.info();
1206 }
1207 if (rowBytes) {
1208 *rowBytes = pmap.rowBytes();
1209 }
1210 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001211 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001212 }
reed884e97c2015-05-26 11:31:54 -07001213 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001214}
1215
reed884e97c2015-05-26 11:31:54 -07001216bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001217 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001218 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001219}
1220
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222
Florin Malita53f77bd2017-04-28 13:48:37 -04001223void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1224 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001226 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227 paint = &tmp;
1228 }
reed@google.com4b226022011-01-11 18:32:13 +00001229
reed@google.com8926b162012-03-23 15:36:36 +00001230 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001231
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001233 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001234 paint = &looper.paint();
1235 SkImageFilter* filter = paint->getImageFilter();
1236 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001237 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001238 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1239 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001240 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1241 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001242 }
reed@google.com76dd2772012-01-05 21:15:07 +00001243 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001244 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001245 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246 }
reeda2217ef2016-07-20 06:04:34 -07001247
reed@google.com4e2b3d32011-04-07 14:18:59 +00001248 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249}
1250
reed32704672015-12-16 08:27:10 -08001251/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001252
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001253void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001254 if (dx || dy) {
1255 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001256 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001257
reedfe69b502016-09-12 06:31:48 -07001258 // Translate shouldn't affect the is-scale-translateness of the matrix.
1259 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001260
Mike Reedc42a1cd2017-02-14 14:25:14 -05001261 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001262
reedfe69b502016-09-12 06:31:48 -07001263 this->didTranslate(dx,dy);
1264 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265}
1266
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001267void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001268 SkMatrix m;
1269 m.setScale(sx, sy);
1270 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271}
1272
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001273void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001274 SkMatrix m;
1275 m.setRotate(degrees);
1276 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277}
1278
bungeman7438bfc2016-07-12 15:01:19 -07001279void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1280 SkMatrix m;
1281 m.setRotate(degrees, px, py);
1282 this->concat(m);
1283}
1284
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001285void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001286 SkMatrix m;
1287 m.setSkew(sx, sy);
1288 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001289}
1290
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001291void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001292 if (matrix.isIdentity()) {
1293 return;
1294 }
1295
reed2ff1fce2014-12-11 07:07:37 -08001296 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001297 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001298 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001299
Mike Reed7627fa52017-02-08 10:07:53 -05001300 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001301
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001302 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001303}
1304
reed8c30a812016-04-20 16:36:51 -07001305void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001306 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001307 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001308
Mike Reedc42a1cd2017-02-14 14:25:14 -05001309 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001310}
1311
1312void SkCanvas::setMatrix(const SkMatrix& matrix) {
1313 this->checkForDeferredSave();
1314 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001315 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316}
1317
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001319 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320}
1321
1322//////////////////////////////////////////////////////////////////////////////
1323
Mike Reedc1f77742016-12-09 09:00:50 -05001324void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001325 if (!rect.isFinite()) {
1326 return;
1327 }
reed2ff1fce2014-12-11 07:07:37 -08001328 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001329 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1330 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001331}
1332
Mike Reedc1f77742016-12-09 09:00:50 -05001333void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001334 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001335
Mike Reed7627fa52017-02-08 10:07:53 -05001336 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001337
reedc64eff52015-11-21 12:39:45 -08001338 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001339 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1340 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001341 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001344void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1345 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001346 if (fClipRestrictionRect.isEmpty()) {
1347 // we notify the device, but we *dont* resolve deferred saves (since we're just
1348 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001349 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001350 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001351 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001352 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001353 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001354 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001355 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1356 }
1357}
1358
Mike Reedc1f77742016-12-09 09:00:50 -05001359void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001360 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001361 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001362 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001363 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1364 } else {
1365 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001366 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001367}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001368
Mike Reedc1f77742016-12-09 09:00:50 -05001369void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001370 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001371
Brian Salomona3b45d42016-10-03 11:36:16 -04001372 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001373
Mike Reed7627fa52017-02-08 10:07:53 -05001374 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001375
Mike Reed20800c82017-11-15 16:09:04 -05001376 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1377 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001378 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001379}
1380
Mike Reedc1f77742016-12-09 09:00:50 -05001381void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001382 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001383 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001384
1385 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1386 SkRect r;
1387 if (path.isRect(&r)) {
1388 this->onClipRect(r, op, edgeStyle);
1389 return;
1390 }
1391 SkRRect rrect;
1392 if (path.isOval(&r)) {
1393 rrect.setOval(r);
1394 this->onClipRRect(rrect, op, edgeStyle);
1395 return;
1396 }
1397 if (path.isRRect(&rrect)) {
1398 this->onClipRRect(rrect, op, edgeStyle);
1399 return;
1400 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401 }
robertphillips39f05382015-11-24 09:30:12 -08001402
1403 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001404}
1405
Mike Reedc1f77742016-12-09 09:00:50 -05001406void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001407 AutoValidateClip avc(this);
1408
Brian Salomona3b45d42016-10-03 11:36:16 -04001409 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001410
Mike Reed7627fa52017-02-08 10:07:53 -05001411 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412
Brian Salomona3b45d42016-10-03 11:36:16 -04001413 const SkPath* rasterClipPath = &path;
1414 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001415 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1416 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001417 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418}
1419
Mike Reedc1f77742016-12-09 09:00:50 -05001420void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001421 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001422 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423}
1424
Mike Reedc1f77742016-12-09 09:00:50 -05001425void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001426 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001427
reed@google.com5c3d1472011-02-22 19:12:23 +00001428 AutoValidateClip avc(this);
1429
Mike Reed20800c82017-11-15 16:09:04 -05001430 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001431 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432}
1433
reed@google.com819c9212011-02-23 18:56:55 +00001434#ifdef SK_DEBUG
1435void SkCanvas::validateClip() const {
1436 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001437 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001438 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001439 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001440 return;
1441 }
reed@google.com819c9212011-02-23 18:56:55 +00001442}
1443#endif
1444
Mike Reeda1361362017-03-07 09:37:29 -05001445bool SkCanvas::androidFramework_isClipAA() const {
1446 bool containsAA = false;
1447
1448 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1449
1450 return containsAA;
1451}
1452
1453class RgnAccumulator {
1454 SkRegion* fRgn;
1455public:
1456 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1457 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1458 SkIPoint origin = device->getOrigin();
1459 if (origin.x() | origin.y()) {
1460 rgn->translate(origin.x(), origin.y());
1461 }
1462 fRgn->op(*rgn, SkRegion::kUnion_Op);
1463 }
1464};
1465
1466void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1467 RgnAccumulator accum(rgn);
1468 SkRegion tmp;
1469
1470 rgn->setEmpty();
1471 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001472}
1473
reed@google.com5c3d1472011-02-22 19:12:23 +00001474///////////////////////////////////////////////////////////////////////////////
1475
reed@google.com754de5f2014-02-24 19:38:20 +00001476bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001477 return fMCRec->fRasterClip.isEmpty();
1478
1479 // TODO: should we only use the conservative answer in a recording canvas?
1480#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001481 SkBaseDevice* dev = this->getTopDevice();
1482 // if no device we return true
1483 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001484#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001485}
1486
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001487bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001488 SkBaseDevice* dev = this->getTopDevice();
1489 // if no device we return false
1490 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001491}
1492
msarettfbfa2582016-08-12 08:29:08 -07001493static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1494#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1495 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1496 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1497 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1498 return 0xF != _mm_movemask_ps(mask);
1499#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1500 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1501 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1502 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1503 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1504#else
1505 SkRect devRectAsRect;
1506 SkRect devClipAsRect;
1507 devRect.store(&devRectAsRect.fLeft);
1508 devClip.store(&devClipAsRect.fLeft);
1509 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1510#endif
1511}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001512
msarettfbfa2582016-08-12 08:29:08 -07001513// It's important for this function to not be inlined. Otherwise the compiler will share code
1514// between the fast path and the slow path, resulting in two slow paths.
1515static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1516 const SkMatrix& matrix) {
1517 SkRect deviceRect;
1518 matrix.mapRect(&deviceRect, src);
1519 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1520}
1521
1522bool SkCanvas::quickReject(const SkRect& src) const {
1523#ifdef SK_DEBUG
1524 // Verify that fDeviceClipBounds are set properly.
1525 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001526 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001527 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001528 } else {
msarettfbfa2582016-08-12 08:29:08 -07001529 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530 }
msarettfbfa2582016-08-12 08:29:08 -07001531
msarett9637ea92016-08-18 14:03:30 -07001532 // Verify that fIsScaleTranslate is set properly.
1533 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001534#endif
1535
msarett9637ea92016-08-18 14:03:30 -07001536 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001537 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1538 }
1539
1540 // We inline the implementation of mapScaleTranslate() for the fast path.
1541 float sx = fMCRec->fMatrix.getScaleX();
1542 float sy = fMCRec->fMatrix.getScaleY();
1543 float tx = fMCRec->fMatrix.getTranslateX();
1544 float ty = fMCRec->fMatrix.getTranslateY();
1545 Sk4f scale(sx, sy, sx, sy);
1546 Sk4f trans(tx, ty, tx, ty);
1547
1548 // Apply matrix.
1549 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1550
1551 // Make sure left < right, top < bottom.
1552 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1553 Sk4f min = Sk4f::Min(ltrb, rblt);
1554 Sk4f max = Sk4f::Max(ltrb, rblt);
1555 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1556 // ARM this sequence generates the fastest (a single instruction).
1557 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1558
1559 // Check if the device rect is NaN or outside the clip.
1560 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561}
1562
reed@google.com3b3e8952012-08-16 20:53:31 +00001563bool SkCanvas::quickReject(const SkPath& path) const {
1564 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565}
1566
Mike Klein83c8dd92017-11-28 17:08:45 -05001567SkRect SkCanvas::getLocalClipBounds() const {
1568 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001569 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001570 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001571 }
1572
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001573 SkMatrix inverse;
1574 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001575 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001576 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001577 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001578
Mike Reed42e8c532017-01-23 14:09:13 -05001579 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001580 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001581 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001582
Mike Reedb57b9312018-04-23 12:12:54 -04001583 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001584 inverse.mapRect(&bounds, r);
1585 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001586}
1587
Mike Klein83c8dd92017-11-28 17:08:45 -05001588SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001589 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001590}
1591
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001593 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001594}
1595
Brian Osman11052242016-10-27 14:47:55 -04001596GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001597 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001598 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001599}
1600
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001601GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001602 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001603 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001604}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001605
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001606void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1607 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001608 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001609 if (outer.isEmpty()) {
1610 return;
1611 }
1612 if (inner.isEmpty()) {
1613 this->drawRRect(outer, paint);
1614 return;
1615 }
1616
1617 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001618 // be able to return ...
1619 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001620 //
1621 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001622 if (!outer.getBounds().contains(inner.getBounds())) {
1623 return;
1624 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001625
1626 this->onDrawDRRect(outer, inner, paint);
1627}
1628
reed41af9662015-01-05 07:49:08 -08001629void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001630 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001631 this->onDrawPaint(paint);
1632}
1633
1634void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001635 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001636 // To avoid redundant logic in our culling code and various backends, we always sort rects
1637 // before passing them along.
1638 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001639}
1640
msarettdca352e2016-08-26 06:37:45 -07001641void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001642 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001643 if (region.isEmpty()) {
1644 return;
1645 }
1646
1647 if (region.isRect()) {
1648 return this->drawIRect(region.getBounds(), paint);
1649 }
1650
1651 this->onDrawRegion(region, paint);
1652}
1653
reed41af9662015-01-05 07:49:08 -08001654void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001655 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001656 // To avoid redundant logic in our culling code and various backends, we always sort rects
1657 // before passing them along.
1658 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001659}
1660
1661void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001662 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001663 this->onDrawRRect(rrect, paint);
1664}
1665
1666void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001667 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001668 this->onDrawPoints(mode, count, pts, paint);
1669}
1670
Mike Reede88a1cb2017-03-17 09:50:46 -04001671void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1672 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001673 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001674 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001675 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1676 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Mike Reede88a1cb2017-03-17 09:50:46 -04001677 this->onDrawVerticesObject(vertices.get(), mode, paint);
1678}
1679
1680void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001681 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001682 RETURN_ON_NULL(vertices);
1683 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001684}
1685
1686void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001687 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001688 this->onDrawPath(path, paint);
1689}
1690
reeda85d4d02015-05-06 12:56:48 -07001691void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001692 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001693 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001694 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001695}
1696
Mike Reedc4e31092018-01-30 11:15:27 -05001697// Returns true if the rect can be "filled" : non-empty and finite
1698static bool fillable(const SkRect& r) {
1699 SkScalar w = r.width();
1700 SkScalar h = r.height();
1701 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1702}
1703
reede47829b2015-08-06 10:02:53 -07001704void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1705 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001706 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001707 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001708 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001709 return;
1710 }
1711 this->onDrawImageRect(image, &src, dst, paint, constraint);
1712}
reed41af9662015-01-05 07:49:08 -08001713
reed84984ef2015-07-17 07:09:43 -07001714void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1715 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001716 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001717 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001718}
1719
reede47829b2015-08-06 10:02:53 -07001720void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1721 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001722 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001723 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1724 constraint);
1725}
reede47829b2015-08-06 10:02:53 -07001726
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001727namespace {
1728class NoneOrLowQualityFilterPaint : SkNoncopyable {
1729public:
1730 NoneOrLowQualityFilterPaint(const SkPaint* origPaint) {
1731 if (origPaint && origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1732 fLazyPaint.set(*origPaint);
1733 fLazyPaint.get()->setFilterQuality(kLow_SkFilterQuality);
1734 fPaint = fLazyPaint.get();
1735 } else {
1736 fPaint = origPaint;
1737 }
1738 }
1739
1740 const SkPaint* get() const {
1741 return fPaint;
1742 }
1743
1744private:
1745 const SkPaint* fPaint;
1746 SkLazyPaint fLazyPaint;
1747};
1748} // namespace
1749
reed4c21dc52015-06-25 12:32:03 -07001750void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1751 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001752 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001753 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001754 if (dst.isEmpty()) {
1755 return;
1756 }
msarett552bca92016-08-03 06:53:26 -07001757 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001758 NoneOrLowQualityFilterPaint lowPaint(paint);
1759 this->onDrawImageNine(image, center, dst, lowPaint.get());
msarett552bca92016-08-03 06:53:26 -07001760 } else {
reede47829b2015-08-06 10:02:53 -07001761 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001762 }
reed4c21dc52015-06-25 12:32:03 -07001763}
1764
msarett16882062016-08-16 09:31:08 -07001765void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1766 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001767 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001768 RETURN_ON_NULL(image);
1769 if (dst.isEmpty()) {
1770 return;
1771 }
msarett71df2d72016-09-30 12:41:42 -07001772
1773 SkIRect bounds;
1774 Lattice latticePlusBounds = lattice;
1775 if (!latticePlusBounds.fBounds) {
1776 bounds = SkIRect::MakeWH(image->width(), image->height());
1777 latticePlusBounds.fBounds = &bounds;
1778 }
1779
1780 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001781 NoneOrLowQualityFilterPaint lowPaint(paint);
1782 this->onDrawImageLattice(image, latticePlusBounds, dst, lowPaint.get());
msarett16882062016-08-16 09:31:08 -07001783 } else {
1784 this->drawImageRect(image, dst, paint);
1785 }
1786}
1787
reed41af9662015-01-05 07:49:08 -08001788void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001789 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001790 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001791 return;
1792 }
reed41af9662015-01-05 07:49:08 -08001793 this->onDrawBitmap(bitmap, dx, dy, paint);
1794}
1795
reede47829b2015-08-06 10:02:53 -07001796void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001797 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001798 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001799 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001800 return;
1801 }
reede47829b2015-08-06 10:02:53 -07001802 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001803}
1804
reed84984ef2015-07-17 07:09:43 -07001805void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1806 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001807 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001808}
1809
reede47829b2015-08-06 10:02:53 -07001810void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1811 SrcRectConstraint constraint) {
1812 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1813 constraint);
1814}
reede47829b2015-08-06 10:02:53 -07001815
reed41af9662015-01-05 07:49:08 -08001816void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1817 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001818 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001819 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001820 return;
1821 }
msarett552bca92016-08-03 06:53:26 -07001822 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001823 NoneOrLowQualityFilterPaint lowPaint(paint);
1824 this->onDrawBitmapNine(bitmap, center, dst, lowPaint.get());
msarett552bca92016-08-03 06:53:26 -07001825 } else {
reeda5517e22015-07-14 10:54:12 -07001826 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001827 }
reed41af9662015-01-05 07:49:08 -08001828}
1829
msarettc573a402016-08-02 08:05:56 -07001830void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1831 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001832 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001833 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001834 return;
1835 }
msarett71df2d72016-09-30 12:41:42 -07001836
1837 SkIRect bounds;
1838 Lattice latticePlusBounds = lattice;
1839 if (!latticePlusBounds.fBounds) {
1840 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1841 latticePlusBounds.fBounds = &bounds;
1842 }
1843
1844 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001845 NoneOrLowQualityFilterPaint lowPaint(paint);
1846 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, lowPaint.get());
msarett552bca92016-08-03 06:53:26 -07001847 } else {
msarett16882062016-08-16 09:31:08 -07001848 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001849 }
msarettc573a402016-08-02 08:05:56 -07001850}
1851
reed71c3c762015-06-24 10:29:17 -07001852void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001853 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001854 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001855 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001856 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001857 if (count <= 0) {
1858 return;
1859 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001860 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001861 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001862 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001863}
1864
reedf70b5312016-03-04 16:36:20 -08001865void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001866 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001867 if (key) {
1868 this->onDrawAnnotation(rect, key, value);
1869 }
1870}
1871
reede47829b2015-08-06 10:02:53 -07001872void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1873 const SkPaint* paint, SrcRectConstraint constraint) {
1874 if (src) {
1875 this->drawImageRect(image, *src, dst, paint, constraint);
1876 } else {
1877 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1878 dst, paint, constraint);
1879 }
1880}
1881void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1882 const SkPaint* paint, SrcRectConstraint constraint) {
1883 if (src) {
1884 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1885 } else {
1886 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1887 dst, paint, constraint);
1888 }
1889}
1890
Mike Reed4204da22017-05-17 08:53:36 -04001891void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001892 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001893 this->onDrawShadowRec(path, rec);
1894}
1895
1896void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1897 SkPaint paint;
1898 const SkRect& pathBounds = path.getBounds();
1899
1900 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1901 while (iter.next()) {
1902 iter.fDevice->drawShadow(path, rec);
1903 }
1904 LOOPER_END
1905}
1906
reed@android.com8a1c16f2008-12-17 15:59:43 +00001907//////////////////////////////////////////////////////////////////////////////
1908// These are the virtual drawing methods
1909//////////////////////////////////////////////////////////////////////////////
1910
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001911void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001912 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001913 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1914 }
1915}
1916
reed41af9662015-01-05 07:49:08 -08001917void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001918 this->internalDrawPaint(paint);
1919}
1920
1921void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001922 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001923
1924 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001925 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926 }
1927
reed@google.com4e2b3d32011-04-07 14:18:59 +00001928 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929}
1930
reed41af9662015-01-05 07:49:08 -08001931void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1932 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001933 if ((long)count <= 0) {
1934 return;
1935 }
1936
Mike Reed822128b2017-02-28 16:41:03 -05001937 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001938 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001939 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001940 // special-case 2 points (common for drawing a single line)
1941 if (2 == count) {
1942 r.set(pts[0], pts[1]);
1943 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001944 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001945 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001946 if (!r.isFinite()) {
1947 return;
1948 }
Mike Reed822128b2017-02-28 16:41:03 -05001949 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001950 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1951 return;
1952 }
1953 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001954 }
reed@google.coma584aed2012-05-16 14:06:02 +00001955
halcanary96fcdcc2015-08-27 07:41:13 -07001956 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001958 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001959
reed@android.com8a1c16f2008-12-17 15:59:43 +00001960 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001961 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962 }
reed@google.com4b226022011-01-11 18:32:13 +00001963
reed@google.com4e2b3d32011-04-07 14:18:59 +00001964 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965}
1966
reed4a167172016-08-18 17:15:25 -07001967static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1968 return ((intptr_t)paint.getImageFilter() |
1969#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1970 (intptr_t)canvas->getDrawFilter() |
1971#endif
1972 (intptr_t)paint.getLooper() ) != 0;
1973}
1974
reed41af9662015-01-05 07:49:08 -08001975void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001976 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001978 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001979 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001980 return;
1981 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982 }
reed@google.com4b226022011-01-11 18:32:13 +00001983
reed4a167172016-08-18 17:15:25 -07001984 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05001985 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001986
reed4a167172016-08-18 17:15:25 -07001987 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001988 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07001989 }
1990
1991 LOOPER_END
1992 } else {
Mike Reed822128b2017-02-28 16:41:03 -05001993 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07001994 SkDrawIter iter(this);
1995 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001996 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07001997 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999}
2000
msarett44df6512016-08-25 13:54:30 -07002001void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002002 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002003 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002004 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002005 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2006 return;
2007 }
msarett44df6512016-08-25 13:54:30 -07002008 }
2009
Mike Reed822128b2017-02-28 16:41:03 -05002010 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002011
2012 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002013 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002014 }
2015
2016 LOOPER_END
2017}
2018
reed41af9662015-01-05 07:49:08 -08002019void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002020 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002021 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002022 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002023 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002024 return;
2025 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002026 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002027
Mike Reed822128b2017-02-28 16:41:03 -05002028 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002029
2030 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002031 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002032 }
2033
2034 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002035}
2036
bsalomonac3aa242016-08-19 11:25:19 -07002037void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2038 SkScalar sweepAngle, bool useCenter,
2039 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002040 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002041 if (paint.canComputeFastBounds()) {
2042 SkRect storage;
2043 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002044 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002045 return;
2046 }
bsalomonac3aa242016-08-19 11:25:19 -07002047 }
2048
Mike Reed822128b2017-02-28 16:41:03 -05002049 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002050
2051 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002052 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002053 }
2054
2055 LOOPER_END
2056}
2057
reed41af9662015-01-05 07:49:08 -08002058void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002059 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002060 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002061 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2062 return;
2063 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002064 }
2065
2066 if (rrect.isRect()) {
2067 // call the non-virtual version
2068 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002069 return;
2070 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002071 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002072 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2073 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002074 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002075
Mike Reed822128b2017-02-28 16:41:03 -05002076 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002077
2078 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002079 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002080 }
2081
2082 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002083}
2084
Mike Reed822128b2017-02-28 16:41:03 -05002085void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002086 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002087 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002088 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2089 return;
2090 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002091 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002092
Mike Reed822128b2017-02-28 16:41:03 -05002093 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002094
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002095 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002096 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002097 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002098
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002099 LOOPER_END
2100}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101
reed41af9662015-01-05 07:49:08 -08002102void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002103 if (!path.isFinite()) {
2104 return;
2105 }
2106
Mike Reed822128b2017-02-28 16:41:03 -05002107 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002108 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002109 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002110 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2111 return;
2112 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002113 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002114
Mike Reed822128b2017-02-28 16:41:03 -05002115 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002116 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002117 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002118 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002119 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002120 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121
Mike Reed822128b2017-02-28 16:41:03 -05002122 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123
2124 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002125 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126 }
2127
reed@google.com4e2b3d32011-04-07 14:18:59 +00002128 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129}
2130
reed262a71b2015-12-05 13:07:27 -08002131bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002132 if (!paint.getImageFilter()) {
2133 return false;
2134 }
2135
2136 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002137 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002138 return false;
2139 }
2140
2141 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2142 // Once we can filter and the filter will return a result larger than itself, we should be
2143 // able to remove this constraint.
2144 // skbug.com/4526
2145 //
2146 SkPoint pt;
2147 ctm.mapXY(x, y, &pt);
2148 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2149 return ir.contains(fMCRec->fRasterClip.getBounds());
2150}
2151
Mike Reedf441cfc2018-04-11 14:50:16 -04002152// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2153// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2154// null.
2155static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2156 if (paintParam) {
2157 *real = *paintParam;
2158 real->setStyle(SkPaint::kFill_Style);
2159 real->setPathEffect(nullptr);
2160 paintParam = real;
2161 }
2162 return paintParam;
2163}
2164
reeda85d4d02015-05-06 12:56:48 -07002165void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002166 SkPaint realPaint;
2167 paint = init_image_paint(&realPaint, paint);
2168
reeda85d4d02015-05-06 12:56:48 -07002169 SkRect bounds = SkRect::MakeXYWH(x, y,
2170 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002171 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002172 SkRect tmp = bounds;
2173 if (paint) {
2174 paint->computeFastBounds(tmp, &tmp);
2175 }
2176 if (this->quickReject(tmp)) {
2177 return;
2178 }
reeda85d4d02015-05-06 12:56:48 -07002179 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002180 // At this point we need a real paint object. If the caller passed null, then we should
2181 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2182 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2183 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002184
reeda2217ef2016-07-20 06:04:34 -07002185 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002186 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2187 *paint);
2188 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002189 special = this->getDevice()->makeSpecial(image);
2190 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002191 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002192 }
2193 }
2194
reed262a71b2015-12-05 13:07:27 -08002195 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2196
reeda85d4d02015-05-06 12:56:48 -07002197 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002198 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002199 if (special) {
2200 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002201 iter.fDevice->ctm().mapXY(x, y, &pt);
2202 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002203 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002204 SkScalarRoundToInt(pt.fY), pnt,
2205 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002206 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002207 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002208 }
reeda85d4d02015-05-06 12:56:48 -07002209 }
halcanary9d524f22016-03-29 09:03:52 -07002210
reeda85d4d02015-05-06 12:56:48 -07002211 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002212}
2213
reed41af9662015-01-05 07:49:08 -08002214void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002215 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002216 SkPaint realPaint;
2217 paint = init_image_paint(&realPaint, paint);
2218
halcanary96fcdcc2015-08-27 07:41:13 -07002219 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002220 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002221 if (paint) {
2222 paint->computeFastBounds(dst, &storage);
2223 }
2224 if (this->quickReject(storage)) {
2225 return;
2226 }
reeda85d4d02015-05-06 12:56:48 -07002227 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002228 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002229
senorblancoc41e7e12015-12-07 12:51:30 -08002230 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002231 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002232
reeda85d4d02015-05-06 12:56:48 -07002233 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002234 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002235 }
halcanary9d524f22016-03-29 09:03:52 -07002236
reeda85d4d02015-05-06 12:56:48 -07002237 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002238}
2239
reed41af9662015-01-05 07:49:08 -08002240void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002241 SkDEBUGCODE(bitmap.validate();)
2242
reed33366972015-10-08 09:22:02 -07002243 if (bitmap.drawsNothing()) {
2244 return;
2245 }
2246
Mike Reedf441cfc2018-04-11 14:50:16 -04002247 SkPaint realPaint;
2248 init_image_paint(&realPaint, paint);
2249 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002250
Mike Reed822128b2017-02-28 16:41:03 -05002251 SkRect bounds;
2252 bitmap.getBounds(&bounds);
2253 bounds.offset(x, y);
2254 bool canFastBounds = paint->canComputeFastBounds();
2255 if (canFastBounds) {
2256 SkRect storage;
2257 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002258 return;
2259 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002260 }
reed@google.com4b226022011-01-11 18:32:13 +00002261
reeda2217ef2016-07-20 06:04:34 -07002262 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002263 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2264 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002265 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002266 special = this->getDevice()->makeSpecial(bitmap);
2267 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002268 drawAsSprite = false;
2269 }
2270 }
2271
Mike Reed822128b2017-02-28 16:41:03 -05002272 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002273
2274 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002275 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002276 if (special) {
reed262a71b2015-12-05 13:07:27 -08002277 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002278 iter.fDevice->ctm().mapXY(x, y, &pt);
2279 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002280 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002281 SkScalarRoundToInt(pt.fY), pnt,
2282 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002283 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002284 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002285 }
reed33366972015-10-08 09:22:02 -07002286 }
msarettfbfa2582016-08-12 08:29:08 -07002287
reed33366972015-10-08 09:22:02 -07002288 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289}
2290
reed@google.com9987ec32011-09-07 11:57:52 +00002291// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002292void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002293 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002294 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002295 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296 return;
2297 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002298
halcanary96fcdcc2015-08-27 07:41:13 -07002299 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002300 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002301 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2302 return;
2303 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304 }
reed@google.com3d608122011-11-21 15:16:16 +00002305
reed@google.com33535f32012-09-25 15:37:50 +00002306 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002307 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002308 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002309 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002310
senorblancoc41e7e12015-12-07 12:51:30 -08002311 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002312 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002313
reed@google.com33535f32012-09-25 15:37:50 +00002314 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002315 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002316 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002317
reed@google.com33535f32012-09-25 15:37:50 +00002318 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319}
2320
reed41af9662015-01-05 07:49:08 -08002321void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002322 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002323 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002324 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002325}
2326
reed4c21dc52015-06-25 12:32:03 -07002327void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2328 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002329 SkPaint realPaint;
2330 paint = init_image_paint(&realPaint, paint);
2331
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002333 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002334 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2335 return;
2336 }
reed@google.com3d608122011-11-21 15:16:16 +00002337 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002338 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002339
senorblancoc41e7e12015-12-07 12:51:30 -08002340 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002341
reed4c21dc52015-06-25 12:32:03 -07002342 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002343 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002344 }
halcanary9d524f22016-03-29 09:03:52 -07002345
reed4c21dc52015-06-25 12:32:03 -07002346 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002347}
2348
reed41af9662015-01-05 07:49:08 -08002349void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2350 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002351 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002352 SkPaint realPaint;
2353 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002354
halcanary96fcdcc2015-08-27 07:41:13 -07002355 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002356 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002357 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2358 return;
2359 }
reed4c21dc52015-06-25 12:32:03 -07002360 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002361 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002362
senorblancoc41e7e12015-12-07 12:51:30 -08002363 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002364
reed4c21dc52015-06-25 12:32:03 -07002365 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002366 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002367 }
halcanary9d524f22016-03-29 09:03:52 -07002368
reed4c21dc52015-06-25 12:32:03 -07002369 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002370}
2371
msarett16882062016-08-16 09:31:08 -07002372void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2373 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002374 SkPaint realPaint;
2375 paint = init_image_paint(&realPaint, paint);
2376
msarett16882062016-08-16 09:31:08 -07002377 if (nullptr == paint || paint->canComputeFastBounds()) {
2378 SkRect storage;
2379 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2380 return;
2381 }
2382 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002383 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002384
2385 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2386
2387 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002388 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002389 }
2390
2391 LOOPER_END
2392}
2393
2394void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2395 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002396 SkPaint realPaint;
2397 paint = init_image_paint(&realPaint, paint);
2398
msarett16882062016-08-16 09:31:08 -07002399 if (nullptr == paint || paint->canComputeFastBounds()) {
2400 SkRect storage;
2401 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2402 return;
2403 }
2404 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002405 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002406
2407 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2408
2409 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002410 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002411 }
2412
2413 LOOPER_END
2414}
2415
reed@google.come0d9ce82014-04-23 04:00:17 +00002416void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2417 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002418 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002419
2420 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002421 iter.fDevice->drawText(text, byteLength, x, y, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002422 }
2423
reed@google.com4e2b3d32011-04-07 14:18:59 +00002424 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002425}
2426
reed@google.come0d9ce82014-04-23 04:00:17 +00002427void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2428 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002429 SkPoint textOffset = SkPoint::Make(0, 0);
2430
halcanary96fcdcc2015-08-27 07:41:13 -07002431 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002432
reed@android.com8a1c16f2008-12-17 15:59:43 +00002433 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002434 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002435 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002436
reed@google.com4e2b3d32011-04-07 14:18:59 +00002437 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002438}
2439
reed@google.come0d9ce82014-04-23 04:00:17 +00002440void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2441 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002442
2443 SkPoint textOffset = SkPoint::Make(0, constY);
2444
halcanary96fcdcc2015-08-27 07:41:13 -07002445 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002446
reed@android.com8a1c16f2008-12-17 15:59:43 +00002447 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002448 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002450
reed@google.com4e2b3d32011-04-07 14:18:59 +00002451 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452}
2453
reed@google.come0d9ce82014-04-23 04:00:17 +00002454void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2455 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002456 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002457
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002459 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002461
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002462 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002463}
2464
reed45561a02016-07-07 12:47:17 -07002465void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2466 const SkRect* cullRect, const SkPaint& paint) {
2467 if (cullRect && this->quickReject(*cullRect)) {
2468 return;
2469 }
2470
2471 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2472
2473 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002474 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002475 }
2476
2477 LOOPER_END
2478}
2479
fmalita00d5c2c2014-08-21 08:53:26 -07002480void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2481 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002482 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002483 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002484 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002485 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002486 SkRect tmp;
2487 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2488 return;
2489 }
2490 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002491 }
2492
fmalita024f9962015-03-03 19:08:17 -08002493 // We cannot filter in the looper as we normally do, because the paint is
2494 // incomplete at this point (text-related attributes are embedded within blob run paints).
2495 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002496 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002497
fmalita85d5eb92015-03-04 11:20:12 -08002498 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002499
fmalitaaa1b9122014-08-28 14:32:24 -07002500 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002501 iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002502 }
2503
fmalitaaa1b9122014-08-28 14:32:24 -07002504 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002505
2506 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002507}
2508
Cary Clark2a475ea2017-04-28 15:35:12 -04002509void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2510 this->drawText(string.c_str(), string.size(), x, y, paint);
2511}
2512
reed@google.come0d9ce82014-04-23 04:00:17 +00002513// These will become non-virtual, so they always call the (virtual) onDraw... method
2514void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2515 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002516 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002517 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002518 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002519 this->onDrawText(text, byteLength, x, y, paint);
2520 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002521}
2522void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2523 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002524 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002525 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002526 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002527 this->onDrawPosText(text, byteLength, pos, paint);
2528 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002529}
2530void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2531 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002532 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002533 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002534 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002535 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2536 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002537}
2538void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2539 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002540 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002541 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002542 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002543 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2544 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002545}
reed45561a02016-07-07 12:47:17 -07002546void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2547 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002548 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002549 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002550 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002551 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2552 }
2553}
fmalita00d5c2c2014-08-21 08:53:26 -07002554void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2555 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002556 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002557 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002558 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002559 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002560}
reed@google.come0d9ce82014-04-23 04:00:17 +00002561
Mike Reede88a1cb2017-03-17 09:50:46 -04002562void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2563 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002564 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2565
2566 while (iter.next()) {
2567 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002568 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002569 }
2570
2571 LOOPER_END
2572}
2573
dandovb3c9d1c2014-08-12 08:34:29 -07002574void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002575 const SkPoint texCoords[4], SkBlendMode bmode,
2576 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002577 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002578 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002579 return;
2580 }
mtklein6cfa73a2014-08-13 13:33:49 -07002581
Mike Reedfaba3712016-11-03 14:45:31 -04002582 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002583}
2584
2585void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002586 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002587 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002588 // Since a patch is always within the convex hull of the control points, we discard it when its
2589 // bounding rectangle is completely outside the current clip.
2590 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002591 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002592 if (this->quickReject(bounds)) {
2593 return;
2594 }
mtklein6cfa73a2014-08-13 13:33:49 -07002595
Mike Reed435071e2017-05-23 11:22:56 -04002596 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2597
halcanary96fcdcc2015-08-27 07:41:13 -07002598 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002599
dandovecfff212014-08-04 10:02:00 -07002600 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002601 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002602 }
mtklein6cfa73a2014-08-13 13:33:49 -07002603
dandovecfff212014-08-04 10:02:00 -07002604 LOOPER_END
2605}
2606
reeda8db7282015-07-07 10:22:31 -07002607void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002608#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002609 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002610#endif
reede3b38ce2016-01-08 09:18:44 -08002611 RETURN_ON_NULL(dr);
2612 if (x || y) {
2613 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2614 this->onDrawDrawable(dr, &matrix);
2615 } else {
2616 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002617 }
2618}
2619
reeda8db7282015-07-07 10:22:31 -07002620void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002621#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002622 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002623#endif
reede3b38ce2016-01-08 09:18:44 -08002624 RETURN_ON_NULL(dr);
2625 if (matrix && matrix->isIdentity()) {
2626 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002627 }
reede3b38ce2016-01-08 09:18:44 -08002628 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002629}
2630
2631void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002632 // drawable bounds are no longer reliable (e.g. android displaylist)
2633 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002634 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002635}
2636
reed71c3c762015-06-24 10:29:17 -07002637void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002638 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002639 const SkRect* cull, const SkPaint* paint) {
2640 if (cull && this->quickReject(*cull)) {
2641 return;
2642 }
2643
2644 SkPaint pnt;
2645 if (paint) {
2646 pnt = *paint;
2647 }
halcanary9d524f22016-03-29 09:03:52 -07002648
halcanary96fcdcc2015-08-27 07:41:13 -07002649 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002650 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002651 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002652 }
2653 LOOPER_END
2654}
2655
reedf70b5312016-03-04 16:36:20 -08002656void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2657 SkASSERT(key);
2658
2659 SkPaint paint;
2660 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2661 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002662 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002663 }
2664 LOOPER_END
2665}
2666
reed@android.com8a1c16f2008-12-17 15:59:43 +00002667//////////////////////////////////////////////////////////////////////////////
2668// These methods are NOT virtual, and therefore must call back into virtual
2669// methods, rather than actually drawing themselves.
2670//////////////////////////////////////////////////////////////////////////////
2671
reed374772b2016-10-05 17:33:02 -07002672void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002673 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002675 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676 this->drawPaint(paint);
2677}
2678
2679void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002680 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002681 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2682}
2683
Mike Reed3661bc92017-02-22 13:21:42 -05002684void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 pts[0].set(x0, y0);
2687 pts[1].set(x1, y1);
2688 this->drawPoints(kLines_PointMode, 2, pts, paint);
2689}
2690
Mike Reed3661bc92017-02-22 13:21:42 -05002691void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692 if (radius < 0) {
2693 radius = 0;
2694 }
2695
2696 SkRect r;
2697 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002698 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002699}
2700
2701void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2702 const SkPaint& paint) {
2703 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002704 SkRRect rrect;
2705 rrect.setRectXY(r, rx, ry);
2706 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 } else {
2708 this->drawRect(r, paint);
2709 }
2710}
2711
reed@android.com8a1c16f2008-12-17 15:59:43 +00002712void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2713 SkScalar sweepAngle, bool useCenter,
2714 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002715 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002716 if (oval.isEmpty() || !sweepAngle) {
2717 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 }
bsalomon21af9ca2016-08-25 12:29:23 -07002719 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720}
2721
2722void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2723 const SkPath& path, SkScalar hOffset,
2724 SkScalar vOffset, const SkPaint& paint) {
2725 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002726
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 matrix.setTranslate(hOffset, vOffset);
2728 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2729}
2730
reed@android.comf76bacf2009-05-13 14:00:33 +00002731///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002732
Mike Klein88d90712018-01-27 17:30:04 +00002733/**
2734 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2735 * against the playback cost of recursing into the subpicture to get at its actual ops.
2736 *
2737 * For now we pick a conservatively small value, though measurement (and other heuristics like
2738 * the type of ops contained) may justify changing this value.
2739 */
2740#define kMaxPictureOpsToUnrollInsteadOfRef 1
2741
reedd5fa1a42014-08-09 11:08:05 -07002742void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002743 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002744 RETURN_ON_NULL(picture);
2745
reede3b38ce2016-01-08 09:18:44 -08002746 if (matrix && matrix->isIdentity()) {
2747 matrix = nullptr;
2748 }
Mike Klein88d90712018-01-27 17:30:04 +00002749 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2750 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2751 picture->playback(this);
2752 } else {
2753 this->onDrawPicture(picture, matrix, paint);
2754 }
reedd5fa1a42014-08-09 11:08:05 -07002755}
robertphillips9b14f262014-06-04 05:40:44 -07002756
reedd5fa1a42014-08-09 11:08:05 -07002757void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2758 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002759 if (!paint || paint->canComputeFastBounds()) {
2760 SkRect bounds = picture->cullRect();
2761 if (paint) {
2762 paint->computeFastBounds(bounds, &bounds);
2763 }
2764 if (matrix) {
2765 matrix->mapRect(&bounds);
2766 }
2767 if (this->quickReject(bounds)) {
2768 return;
2769 }
2770 }
2771
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002772 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002773 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774}
2775
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776///////////////////////////////////////////////////////////////////////////////
2777///////////////////////////////////////////////////////////////////////////////
2778
reed3aafe112016-08-18 12:45:34 -07002779SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002780 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781
2782 SkASSERT(canvas);
2783
reed3aafe112016-08-18 12:45:34 -07002784 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785 fDone = !fImpl->next();
2786}
2787
2788SkCanvas::LayerIter::~LayerIter() {
2789 fImpl->~SkDrawIter();
2790}
2791
2792void SkCanvas::LayerIter::next() {
2793 fDone = !fImpl->next();
2794}
2795
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002796SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002797 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798}
2799
2800const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002801 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802}
2803
2804const SkPaint& SkCanvas::LayerIter::paint() const {
2805 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002806 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 paint = &fDefaultPaint;
2808 }
2809 return *paint;
2810}
2811
Mike Reedca37f322018-03-08 13:22:16 -05002812SkIRect SkCanvas::LayerIter::clipBounds() const {
2813 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002814}
2815
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2817int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002818
2819///////////////////////////////////////////////////////////////////////////////
2820
Brian Osman10fc6fd2018-03-02 11:01:10 -05002821// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002822static bool supported_for_raster_canvas(const SkImageInfo& info) {
2823 switch (info.alphaType()) {
2824 case kPremul_SkAlphaType:
2825 case kOpaque_SkAlphaType:
2826 break;
2827 default:
2828 return false;
2829 }
2830
2831 switch (info.colorType()) {
2832 case kAlpha_8_SkColorType:
2833 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002834 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002835 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002836 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002837 break;
2838 default:
2839 return false;
2840 }
2841
2842 return true;
2843}
2844
Mike Reed5df49342016-11-12 08:06:55 -06002845std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002846 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002847 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002848 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002849 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002850
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002851 SkBitmap bitmap;
2852 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002853 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002854 }
Mike Reed12f77342017-11-08 11:19:52 -05002855
2856 return props ?
2857 skstd::make_unique<SkCanvas>(bitmap, *props) :
2858 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002859}
reedd5fa1a42014-08-09 11:08:05 -07002860
2861///////////////////////////////////////////////////////////////////////////////
2862
Florin Malitaee424ac2016-12-01 12:47:59 -05002863SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2864 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2865
Florin Malita439ace92016-12-02 12:05:41 -05002866SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2867 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2868
Herb Derbyefe39bc2018-05-01 17:06:20 -04002869SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002870 : INHERITED(device) {}
2871
Florin Malitaee424ac2016-12-01 12:47:59 -05002872SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2873 (void)this->INHERITED::getSaveLayerStrategy(rec);
2874 return kNoLayer_SaveLayerStrategy;
2875}
2876
2877///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002878
reed73603f32016-09-20 08:42:38 -07002879static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2880static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2881static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2882static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2883static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2884static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002885
2886///////////////////////////////////////////////////////////////////////////////////////////////////
2887
2888SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2889 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002890 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002891 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2892 SkIPoint origin = dev->getOrigin();
2893 SkMatrix ctm = this->getTotalMatrix();
2894 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2895
2896 SkIRect clip = fMCRec->fRasterClip.getBounds();
2897 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002898 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002899 clip.setEmpty();
2900 }
2901
2902 fAllocator->updateHandle(handle, ctm, clip);
2903 return handle;
2904 }
2905 return nullptr;
2906}
2907
2908static bool install(SkBitmap* bm, const SkImageInfo& info,
2909 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002910 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002911}
2912
2913SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2914 SkBitmap* bm) {
2915 SkRasterHandleAllocator::Rec rec;
2916 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2917 return nullptr;
2918 }
2919 return rec.fHandle;
2920}
2921
2922std::unique_ptr<SkCanvas>
2923SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2924 const SkImageInfo& info, const Rec* rec) {
2925 if (!alloc || !supported_for_raster_canvas(info)) {
2926 return nullptr;
2927 }
2928
2929 SkBitmap bm;
2930 Handle hndl;
2931
2932 if (rec) {
2933 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2934 } else {
2935 hndl = alloc->allocBitmap(info, &bm);
2936 }
2937 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2938}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002939
2940///////////////////////////////////////////////////////////////////////////////////////////////////
2941
2942