blob: 803b3709019b1f8ac8834dcaa6f3cafe46610830 [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);
436 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000438
reed@google.com129ec222012-05-15 13:24:09 +0000439 bool next(SkDrawFilter::Type drawType) {
440 if (fDone) {
441 return false;
442 } else if (fIsSimple) {
443 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000444 return !fPaint->nothingToDraw();
445 } else {
446 return this->doNext(drawType);
447 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000448 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000449
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500451 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700452 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000453 SkCanvas* fCanvas;
454 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000455 SkDrawFilter* fFilter;
456 const SkPaint* fPaint;
457 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700458 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000459 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000460 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000461 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400462 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000463
464 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465};
466
reed@google.com129ec222012-05-15 13:24:09 +0000467bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700468 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000469 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700470 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000471
reeddbc3cef2015-04-29 12:18:57 -0700472 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
473 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000474
reed5c476fb2015-04-20 08:04:21 -0700475 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700476 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700477 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000479
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000480 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000481 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000482 return false;
483 }
484 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000485 if (!fFilter->filter(paint, drawType)) {
486 fDone = true;
487 return false;
488 }
halcanary96fcdcc2015-08-27 07:41:13 -0700489 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000490 // no looper means we only draw once
491 fDone = true;
492 }
493 }
494 fPaint = paint;
495
496 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000497 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000498 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000499 }
500
501 // call this after any possible paint modifiers
502 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700503 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000504 return false;
505 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000506 return true;
507}
508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509////////// macros to place around the internal draw calls //////////////////
510
reed3aafe112016-08-18 12:45:34 -0700511#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
512 this->predrawNotify(); \
513 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
514 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800515 SkDrawIter iter(this);
516
517
reed@google.com8926b162012-03-23 15:36:36 +0000518#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000519 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700520 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000521 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000522 SkDrawIter iter(this);
523
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000524#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000525 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700526 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000527 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000529
reedc83a2972015-07-16 07:40:45 -0700530#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
531 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700532 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700533 while (looper.next(type)) { \
534 SkDrawIter iter(this);
535
reed@google.com4e2b3d32011-04-07 14:18:59 +0000536#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537
538////////////////////////////////////////////////////////////////////////////
539
msarettfbfa2582016-08-12 08:29:08 -0700540static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
541 if (bounds.isEmpty()) {
542 return SkRect::MakeEmpty();
543 }
544
545 // Expand bounds out by 1 in case we are anti-aliasing. We store the
546 // bounds as floats to enable a faster quick reject implementation.
547 SkRect dst;
548 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
549 return dst;
550}
551
mtkleinfeaadee2015-04-08 11:25:48 -0700552void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
553 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700554 fMCRec->reset(bounds);
555
556 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500557 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400558 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700559 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700560 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700561}
562
reedd9544982014-09-09 18:46:22 -0700563SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800564 if (device && device->forceConservativeRasterClip()) {
565 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
566 }
reed42b73eb2015-11-20 13:42:42 -0800567
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000568 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800569 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700570 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571
572 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500573 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500574 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700575 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576
reeda499f902015-05-01 09:34:31 -0700577 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
578 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400579 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700580
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582
halcanary96fcdcc2015-08-27 07:41:13 -0700583 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000584
reedf92c8662014-08-18 08:02:43 -0700585 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700586 // The root device and the canvas should always have the same pixel geometry
587 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800588 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700589 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500590
Mike Reedc42a1cd2017-02-14 14:25:14 -0500591 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700592 }
msarettfbfa2582016-08-12 08:29:08 -0700593
reedf92c8662014-08-18 08:02:43 -0700594 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595}
596
reed@google.comcde92112011-07-06 20:00:52 +0000597SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000598 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700599 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000600{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000601 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000602
halcanary96fcdcc2015-08-27 07:41:13 -0700603 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000604}
605
reed96a857e2015-01-25 10:33:58 -0800606SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800608 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609{
610 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700611
Mike Reed566e53c2017-03-10 10:49:45 -0500612 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700613 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700614}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000615
reed78e27682014-11-19 08:04:34 -0800616SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700617 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700618 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700619{
620 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700621
Mike Reed566e53c2017-03-10 10:49:45 -0500622 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
623 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700624}
625
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000626SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000627 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700628 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000629{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700631
reedd9544982014-09-09 18:46:22 -0700632 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633}
634
robertphillipsfcf78292015-06-19 11:49:52 -0700635SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
636 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700637 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700638{
639 inc_canvas();
640
641 this->init(device, flags);
642}
643
reed4a8126e2014-09-22 07:29:03 -0700644SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700645 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700646 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700647{
648 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700649
Hal Canary704cd322016-11-07 14:13:52 -0500650 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
651 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700652}
reed29c857d2014-09-21 10:25:07 -0700653
Mike Reed356f7c22017-01-10 11:58:39 -0500654SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
655 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700656 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
657 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500658 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700659{
660 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700661
Mike Reed356f7c22017-01-10 11:58:39 -0500662 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500663 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664}
665
Mike Reed356f7c22017-01-10 11:58:39 -0500666SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
667
Matt Sarett31f99ce2017-04-11 08:46:01 -0400668#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
669SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
670 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
671 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
672 , fAllocator(nullptr)
673{
674 inc_canvas();
675
676 SkBitmap tmp(bitmap);
677 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
678 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
679 this->init(device.get(), kDefault_InitFlags);
680}
681#endif
682
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683SkCanvas::~SkCanvas() {
684 // free up the contents of our deque
685 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000686
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 this->internalRestore(); // restore the last, since we're going away
688
halcanary385fe4d2015-08-26 13:07:48 -0700689 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000690
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691 dec_canvas();
692}
693
fmalita53d9f1c2016-01-25 06:23:54 -0800694#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695SkDrawFilter* SkCanvas::getDrawFilter() const {
696 return fMCRec->fFilter;
697}
698
699SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700700 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
702 return filter;
703}
fmalita77650002016-01-21 18:47:11 -0800704#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000706SkMetaData& SkCanvas::getMetaData() {
707 // metadata users are rare, so we lazily allocate it. If that changes we
708 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700709 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000710 fMetaData = new SkMetaData;
711 }
712 return *fMetaData;
713}
714
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715///////////////////////////////////////////////////////////////////////////////
716
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000717void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700718 this->onFlush();
719}
720
721void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000722 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000723 if (device) {
724 device->flush();
725 }
726}
727
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000728SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000729 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000730 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
731}
732
senorblancoafc7cce2016-02-02 18:44:15 -0800733SkIRect SkCanvas::getTopLayerBounds() const {
734 SkBaseDevice* d = this->getTopDevice();
735 if (!d) {
736 return SkIRect::MakeEmpty();
737 }
738 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
739}
740
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000741SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000743 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400745 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746}
747
Florin Malita0ed3b642017-01-13 16:56:38 +0000748SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400749 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000750}
751
Mike Reed353196f2017-07-21 11:01:18 -0400752bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000753 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400754 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000755}
756
Mike Reed353196f2017-07-21 11:01:18 -0400757bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
758 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400759}
760
761bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
762 SkPixmap pm;
763 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
764}
765
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000766bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400767 SkPixmap pm;
768 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700769 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000770 }
771 return false;
772}
773
Matt Sarett03dd6d52017-01-23 12:15:09 -0500774bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000775 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000776 SkBaseDevice* device = this->getDevice();
777 if (!device) {
778 return false;
779 }
780
Matt Sarett03dd6d52017-01-23 12:15:09 -0500781 // This check gives us an early out and prevents generation ID churn on the surface.
782 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
783 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
784 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
785 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000786 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000787
Matt Sarett03dd6d52017-01-23 12:15:09 -0500788 // Tell our owning surface to bump its generation ID.
789 const bool completeOverwrite =
790 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700791 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700792
Matt Sarett03dd6d52017-01-23 12:15:09 -0500793 // This can still fail, most notably in the case of a invalid color type or alpha type
794 // conversion. We could pull those checks into this function and avoid the unnecessary
795 // generation ID bump. But then we would be performing those checks twice, since they
796 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400797 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000798}
reed@google.com51df9e32010-12-23 19:29:18 +0000799
reed@android.com8a1c16f2008-12-17 15:59:43 +0000800//////////////////////////////////////////////////////////////////////////////
801
reed2ff1fce2014-12-11 07:07:37 -0800802void SkCanvas::checkForDeferredSave() {
803 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800804 this->doSave();
805 }
806}
807
reedf0090cb2014-11-26 08:55:51 -0800808int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800809#ifdef SK_DEBUG
810 int count = 0;
811 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
812 for (;;) {
813 const MCRec* rec = (const MCRec*)iter.next();
814 if (!rec) {
815 break;
816 }
817 count += 1 + rec->fDeferredSaveCount;
818 }
819 SkASSERT(count == fSaveCount);
820#endif
821 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800822}
823
824int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800825 fSaveCount += 1;
826 fMCRec->fDeferredSaveCount += 1;
827 return this->getSaveCount() - 1; // return our prev value
828}
829
830void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800831 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700832
833 SkASSERT(fMCRec->fDeferredSaveCount > 0);
834 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800835 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800836}
837
838void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800839 if (fMCRec->fDeferredSaveCount > 0) {
840 SkASSERT(fSaveCount > 1);
841 fSaveCount -= 1;
842 fMCRec->fDeferredSaveCount -= 1;
843 } else {
844 // check for underflow
845 if (fMCStack.count() > 1) {
846 this->willRestore();
847 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700848 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800849 this->internalRestore();
850 this->didRestore();
851 }
reedf0090cb2014-11-26 08:55:51 -0800852 }
853}
854
855void SkCanvas::restoreToCount(int count) {
856 // sanity check
857 if (count < 1) {
858 count = 1;
859 }
mtkleinf0f14112014-12-12 08:46:25 -0800860
reedf0090cb2014-11-26 08:55:51 -0800861 int n = this->getSaveCount() - count;
862 for (int i = 0; i < n; ++i) {
863 this->restore();
864 }
865}
866
reed2ff1fce2014-12-11 07:07:37 -0800867void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700869 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000871
Mike Reedc42a1cd2017-02-14 14:25:14 -0500872 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873}
874
reed4960eee2015-12-18 07:09:18 -0800875bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400876 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877}
878
reed4960eee2015-12-18 07:09:18 -0800879bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700880 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500881 SkIRect clipBounds = this->getDeviceClipBounds();
882 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000883 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000884 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000885
reed96e657d2015-03-10 17:30:07 -0700886 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
887
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000888 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700889 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800890 if (bounds && !imageFilter->canComputeFastBounds()) {
891 bounds = nullptr;
892 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000893 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000894 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700895 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700897 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899 } else { // no user bounds, so just use the clip
900 ir = clipBounds;
901 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800902
903 // early exit if the layer's bounds are clipped out
904 if (!ir.intersect(clipBounds)) {
905 if (BoundsAffectsClip(saveLayerFlags)) {
906 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
907 fMCRec->fRasterClip.setEmpty();
908 fDeviceClipBounds.setEmpty();
909 }
910 return false;
911 }
reed180aec42015-03-11 10:39:04 -0700912 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913
reed4960eee2015-12-18 07:09:18 -0800914 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700915 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700916 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700917 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000918 }
919
920 if (intersection) {
921 *intersection = ir;
922 }
923 return true;
924}
925
reed4960eee2015-12-18 07:09:18 -0800926int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
927 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000928}
929
reed70ee31b2015-12-10 13:44:45 -0800930int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800931 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
932}
933
Cary Clarke041e312018-03-06 13:00:52 -0500934int SkCanvas::saveLayer(const SaveLayerRec& rec) {
935 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800936 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500937 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800938 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800939}
940
reeda2217ef2016-07-20 06:04:34 -0700941void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500942 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500943 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700944 SkDraw draw;
945 SkRasterClip rc;
946 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
947 if (!dst->accessPixels(&draw.fDst)) {
948 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800949 }
reeda2217ef2016-07-20 06:04:34 -0700950 draw.fMatrix = &SkMatrix::I();
951 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800952
953 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500954 if (filter) {
955 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
956 }
reeda2217ef2016-07-20 06:04:34 -0700957
Mike Reedc42a1cd2017-02-14 14:25:14 -0500958 int x = src->getOrigin().x() - dstOrigin.x();
959 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700960 auto special = src->snapSpecial();
961 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400962 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700963 }
robertphillips7354a4b2015-12-16 05:08:27 -0800964}
reed70ee31b2015-12-10 13:44:45 -0800965
Mike Kleine083f7c2018-02-07 12:54:27 -0500966static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500967 // Need to force L32 for now if we have an image filter.
968 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
969 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500970 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800971 }
Mike Klein649fb732018-02-26 15:09:16 -0500972
973 SkColorType ct = prev.colorType();
974 if (prev.bytesPerPixel() <= 4) {
975 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
976 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
977 ct = kN32_SkColorType;
978 }
979 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800980}
981
reed4960eee2015-12-18 07:09:18 -0800982void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
983 const SkRect* bounds = rec.fBounds;
984 const SkPaint* paint = rec.fPaint;
985 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
986
reed8c30a812016-04-20 16:36:51 -0700987 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400988 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700989 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -0700990 SkMatrix remainder;
991 SkSize scale;
992 /*
993 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
994 * but they do handle scaling. To accommodate this, we do the following:
995 *
996 * 1. Stash off the current CTM
997 * 2. Decompose the CTM into SCALE and REMAINDER
998 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
999 * contains the REMAINDER
1000 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1001 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1002 * of the original imagefilter, and draw that (via drawSprite)
1003 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1004 *
1005 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1006 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1007 */
reed96a04f32016-04-25 09:25:15 -07001008 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001009 stashedMatrix.decomposeScale(&scale, &remainder))
1010 {
1011 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1012 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1013 SkPaint* p = lazyP.set(*paint);
1014 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1015 SkFilterQuality::kLow_SkFilterQuality,
1016 sk_ref_sp(imageFilter)));
1017 imageFilter = p->getImageFilter();
1018 paint = p;
1019 }
reed8c30a812016-04-20 16:36:51 -07001020
junov@chromium.orga907ac32012-02-24 21:54:07 +00001021 // do this before we create the layer. We don't call the public save() since
1022 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001023 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001024
junov@chromium.orga907ac32012-02-24 21:54:07 +00001025 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001026 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001027 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028 }
1029
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001030 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1031 // the clipRectBounds() call above?
1032 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001033 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001034 }
1035
reed8dc0ccb2015-03-20 06:32:52 -07001036 SkPixelGeometry geo = fProps.pixelGeometry();
1037 if (paint) {
reed76033be2015-03-14 10:54:31 -07001038 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001039 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001040 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001041 }
1042 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043
robertphillips5139e502016-07-19 05:10:40 -07001044 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001045 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001046 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001047 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001048 }
reedb2db8982014-11-13 12:41:02 -08001049
Mike Kleine083f7c2018-02-07 12:54:27 -05001050 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001051
Hal Canary704cd322016-11-07 14:13:52 -05001052 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001053 {
reed70ee31b2015-12-10 13:44:45 -08001054 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001055 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001056 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001057 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001058 preserveLCDText,
1059 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001060 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1061 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001062 return;
reed61f501f2015-04-29 08:34:00 -07001063 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001064 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001065 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066
Mike Reedb43a3e02017-02-11 10:18:58 -05001067 // only have a "next" if this new layer doesn't affect the clip (rare)
1068 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069 fMCRec->fLayer = layer;
1070 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001071
Mike Reedc61abee2017-02-28 17:45:27 -05001072 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001073 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001074 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001075 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001076
Mike Reedc42a1cd2017-02-14 14:25:14 -05001077 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1078
1079 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1080 if (layer->fNext) {
1081 // need to punch a hole in the previous device, so we don't draw there, given that
1082 // the new top-layer will allow drawing to happen "below" it.
1083 SkRegion hole(ir);
1084 do {
1085 layer = layer->fNext;
1086 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1087 } while (layer->fNext);
1088 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089}
1090
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001091int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001092 if (0xFF == alpha) {
1093 return this->saveLayer(bounds, nullptr);
1094 } else {
1095 SkPaint tmpPaint;
1096 tmpPaint.setAlpha(alpha);
1097 return this->saveLayer(bounds, &tmpPaint);
1098 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001099}
1100
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101void SkCanvas::internalRestore() {
1102 SkASSERT(fMCStack.count() != 0);
1103
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001104 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105 DeviceCM* layer = fMCRec->fLayer; // may be null
1106 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001107 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108
1109 // now do the normal restore()
1110 fMCRec->~MCRec(); // balanced in save()
1111 fMCStack.pop_back();
1112 fMCRec = (MCRec*)fMCStack.back();
1113
Mike Reedc42a1cd2017-02-14 14:25:14 -05001114 if (fMCRec) {
1115 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1116 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001117
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1119 since if we're being recorded, we don't want to record this (the
1120 recorder will have already recorded the restore).
1121 */
bsalomon49f085d2014-09-05 13:34:00 -07001122 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001123 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001124 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001125 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001126 layer->fPaint.get(),
1127 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001128 // restore what we smashed in internalSaveLayer
1129 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001130 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001131 delete layer;
reedb679ca82015-04-07 04:40:48 -07001132 } else {
1133 // we're at the root
reeda499f902015-05-01 09:34:31 -07001134 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001135 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001136 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001138 }
msarettfbfa2582016-08-12 08:29:08 -07001139
1140 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001141 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001142 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1143 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144}
1145
reede8f30622016-03-23 18:59:25 -07001146sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001147 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001148 props = &fProps;
1149 }
1150 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001151}
1152
reede8f30622016-03-23 18:59:25 -07001153sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001154 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001155 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001156}
1157
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001158SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001159 return this->onImageInfo();
1160}
1161
1162SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001163 SkBaseDevice* dev = this->getDevice();
1164 if (dev) {
1165 return dev->imageInfo();
1166 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001167 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001168 }
1169}
1170
brianosman898235c2016-04-06 07:38:23 -07001171bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001172 return this->onGetProps(props);
1173}
1174
1175bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001176 SkBaseDevice* dev = this->getDevice();
1177 if (dev) {
1178 if (props) {
1179 *props = fProps;
1180 }
1181 return true;
1182 } else {
1183 return false;
1184 }
1185}
1186
reed6ceeebd2016-03-09 14:26:26 -08001187bool SkCanvas::peekPixels(SkPixmap* pmap) {
1188 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001189}
1190
reed884e97c2015-05-26 11:31:54 -07001191bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001192 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001193 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001194}
1195
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001196void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001197 SkPixmap pmap;
1198 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001199 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001200 }
1201 if (info) {
1202 *info = pmap.info();
1203 }
1204 if (rowBytes) {
1205 *rowBytes = pmap.rowBytes();
1206 }
1207 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001208 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001209 }
reed884e97c2015-05-26 11:31:54 -07001210 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001211}
1212
reed884e97c2015-05-26 11:31:54 -07001213bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001214 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001215 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001216}
1217
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219
Florin Malita53f77bd2017-04-28 13:48:37 -04001220void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1221 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001223 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 paint = &tmp;
1225 }
reed@google.com4b226022011-01-11 18:32:13 +00001226
reed@google.com8926b162012-03-23 15:36:36 +00001227 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001228
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001230 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001231 paint = &looper.paint();
1232 SkImageFilter* filter = paint->getImageFilter();
1233 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001234 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001235 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1236 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001237 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1238 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001239 }
reed@google.com76dd2772012-01-05 21:15:07 +00001240 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001241 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001242 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243 }
reeda2217ef2016-07-20 06:04:34 -07001244
reed@google.com4e2b3d32011-04-07 14:18:59 +00001245 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246}
1247
reed32704672015-12-16 08:27:10 -08001248/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001249
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001250void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001251 if (dx || dy) {
1252 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001253 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001254
reedfe69b502016-09-12 06:31:48 -07001255 // Translate shouldn't affect the is-scale-translateness of the matrix.
1256 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001257
Mike Reedc42a1cd2017-02-14 14:25:14 -05001258 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001259
reedfe69b502016-09-12 06:31:48 -07001260 this->didTranslate(dx,dy);
1261 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262}
1263
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001264void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001265 SkMatrix m;
1266 m.setScale(sx, sy);
1267 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268}
1269
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001270void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001271 SkMatrix m;
1272 m.setRotate(degrees);
1273 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274}
1275
bungeman7438bfc2016-07-12 15:01:19 -07001276void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1277 SkMatrix m;
1278 m.setRotate(degrees, px, py);
1279 this->concat(m);
1280}
1281
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001282void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001283 SkMatrix m;
1284 m.setSkew(sx, sy);
1285 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001286}
1287
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001288void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001289 if (matrix.isIdentity()) {
1290 return;
1291 }
1292
reed2ff1fce2014-12-11 07:07:37 -08001293 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001294 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001295 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001296
Mike Reed7627fa52017-02-08 10:07:53 -05001297 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001298
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001299 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001300}
1301
reed8c30a812016-04-20 16:36:51 -07001302void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001303 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001304 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001305
Mike Reedc42a1cd2017-02-14 14:25:14 -05001306 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001307}
1308
1309void SkCanvas::setMatrix(const SkMatrix& matrix) {
1310 this->checkForDeferredSave();
1311 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001312 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313}
1314
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001316 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
1319//////////////////////////////////////////////////////////////////////////////
1320
Mike Reedc1f77742016-12-09 09:00:50 -05001321void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001322 if (!rect.isFinite()) {
1323 return;
1324 }
reed2ff1fce2014-12-11 07:07:37 -08001325 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001326 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1327 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001328}
1329
Mike Reedc1f77742016-12-09 09:00:50 -05001330void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001331 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001332
Mike Reed7627fa52017-02-08 10:07:53 -05001333 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001334
reedc64eff52015-11-21 12:39:45 -08001335 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001336 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1337 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001338 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339}
1340
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001341void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1342 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001343 if (fClipRestrictionRect.isEmpty()) {
1344 // we notify the device, but we *dont* resolve deferred saves (since we're just
1345 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001346 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001347 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001348 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001349 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001350 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001351 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001352 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1353 }
1354}
1355
Mike Reedc1f77742016-12-09 09:00:50 -05001356void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001357 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001358 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001359 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001360 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1361 } else {
1362 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001363 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001364}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001365
Mike Reedc1f77742016-12-09 09:00:50 -05001366void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001367 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001368
Brian Salomona3b45d42016-10-03 11:36:16 -04001369 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001370
Mike Reed7627fa52017-02-08 10:07:53 -05001371 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001372
Mike Reed20800c82017-11-15 16:09:04 -05001373 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1374 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001375 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001376}
1377
Mike Reedc1f77742016-12-09 09:00:50 -05001378void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001379 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001380 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001381
1382 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1383 SkRect r;
1384 if (path.isRect(&r)) {
1385 this->onClipRect(r, op, edgeStyle);
1386 return;
1387 }
1388 SkRRect rrect;
1389 if (path.isOval(&r)) {
1390 rrect.setOval(r);
1391 this->onClipRRect(rrect, op, edgeStyle);
1392 return;
1393 }
1394 if (path.isRRect(&rrect)) {
1395 this->onClipRRect(rrect, op, edgeStyle);
1396 return;
1397 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001398 }
robertphillips39f05382015-11-24 09:30:12 -08001399
1400 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401}
1402
Mike Reedc1f77742016-12-09 09:00:50 -05001403void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001404 AutoValidateClip avc(this);
1405
Brian Salomona3b45d42016-10-03 11:36:16 -04001406 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001407
Mike Reed7627fa52017-02-08 10:07:53 -05001408 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409
Brian Salomona3b45d42016-10-03 11:36:16 -04001410 const SkPath* rasterClipPath = &path;
1411 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001412 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1413 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001414 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415}
1416
Mike Reedc1f77742016-12-09 09:00:50 -05001417void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001418 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001419 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001420}
1421
Mike Reedc1f77742016-12-09 09:00:50 -05001422void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001423 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001424
reed@google.com5c3d1472011-02-22 19:12:23 +00001425 AutoValidateClip avc(this);
1426
Mike Reed20800c82017-11-15 16:09:04 -05001427 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001428 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429}
1430
reed@google.com819c9212011-02-23 18:56:55 +00001431#ifdef SK_DEBUG
1432void SkCanvas::validateClip() const {
1433 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001434 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001435 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001436 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001437 return;
1438 }
reed@google.com819c9212011-02-23 18:56:55 +00001439}
1440#endif
1441
Mike Reeda1361362017-03-07 09:37:29 -05001442bool SkCanvas::androidFramework_isClipAA() const {
1443 bool containsAA = false;
1444
1445 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1446
1447 return containsAA;
1448}
1449
1450class RgnAccumulator {
1451 SkRegion* fRgn;
1452public:
1453 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1454 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1455 SkIPoint origin = device->getOrigin();
1456 if (origin.x() | origin.y()) {
1457 rgn->translate(origin.x(), origin.y());
1458 }
1459 fRgn->op(*rgn, SkRegion::kUnion_Op);
1460 }
1461};
1462
1463void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1464 RgnAccumulator accum(rgn);
1465 SkRegion tmp;
1466
1467 rgn->setEmpty();
1468 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001469}
1470
reed@google.com5c3d1472011-02-22 19:12:23 +00001471///////////////////////////////////////////////////////////////////////////////
1472
reed@google.com754de5f2014-02-24 19:38:20 +00001473bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001474 return fMCRec->fRasterClip.isEmpty();
1475
1476 // TODO: should we only use the conservative answer in a recording canvas?
1477#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001478 SkBaseDevice* dev = this->getTopDevice();
1479 // if no device we return true
1480 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001481#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001482}
1483
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001484bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001485 SkBaseDevice* dev = this->getTopDevice();
1486 // if no device we return false
1487 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001488}
1489
msarettfbfa2582016-08-12 08:29:08 -07001490static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1491#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1492 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1493 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1494 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1495 return 0xF != _mm_movemask_ps(mask);
1496#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1497 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1498 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1499 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1500 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1501#else
1502 SkRect devRectAsRect;
1503 SkRect devClipAsRect;
1504 devRect.store(&devRectAsRect.fLeft);
1505 devClip.store(&devClipAsRect.fLeft);
1506 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1507#endif
1508}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001509
msarettfbfa2582016-08-12 08:29:08 -07001510// It's important for this function to not be inlined. Otherwise the compiler will share code
1511// between the fast path and the slow path, resulting in two slow paths.
1512static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1513 const SkMatrix& matrix) {
1514 SkRect deviceRect;
1515 matrix.mapRect(&deviceRect, src);
1516 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1517}
1518
1519bool SkCanvas::quickReject(const SkRect& src) const {
1520#ifdef SK_DEBUG
1521 // Verify that fDeviceClipBounds are set properly.
1522 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001523 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001524 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001525 } else {
msarettfbfa2582016-08-12 08:29:08 -07001526 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527 }
msarettfbfa2582016-08-12 08:29:08 -07001528
msarett9637ea92016-08-18 14:03:30 -07001529 // Verify that fIsScaleTranslate is set properly.
1530 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001531#endif
1532
msarett9637ea92016-08-18 14:03:30 -07001533 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001534 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1535 }
1536
1537 // We inline the implementation of mapScaleTranslate() for the fast path.
1538 float sx = fMCRec->fMatrix.getScaleX();
1539 float sy = fMCRec->fMatrix.getScaleY();
1540 float tx = fMCRec->fMatrix.getTranslateX();
1541 float ty = fMCRec->fMatrix.getTranslateY();
1542 Sk4f scale(sx, sy, sx, sy);
1543 Sk4f trans(tx, ty, tx, ty);
1544
1545 // Apply matrix.
1546 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1547
1548 // Make sure left < right, top < bottom.
1549 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1550 Sk4f min = Sk4f::Min(ltrb, rblt);
1551 Sk4f max = Sk4f::Max(ltrb, rblt);
1552 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1553 // ARM this sequence generates the fastest (a single instruction).
1554 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1555
1556 // Check if the device rect is NaN or outside the clip.
1557 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558}
1559
reed@google.com3b3e8952012-08-16 20:53:31 +00001560bool SkCanvas::quickReject(const SkPath& path) const {
1561 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562}
1563
Mike Klein83c8dd92017-11-28 17:08:45 -05001564SkRect SkCanvas::getLocalClipBounds() const {
1565 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001566 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001567 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568 }
1569
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001570 SkMatrix inverse;
1571 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001572 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001573 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001574 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001575
Mike Reed42e8c532017-01-23 14:09:13 -05001576 SkRect bounds;
1577 SkRect r;
1578 // adjust it outwards in case we are antialiasing
1579 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001580
Mike Reed42e8c532017-01-23 14:09:13 -05001581 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1582 ibounds.fRight + inset, ibounds.fBottom + inset);
1583 inverse.mapRect(&bounds, r);
1584 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
Mike Klein83c8dd92017-11-28 17:08:45 -05001587SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001588 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001589}
1590
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001592 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593}
1594
Brian Osman11052242016-10-27 14:47:55 -04001595GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001596 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001597 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001598}
1599
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001600GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001601 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001602 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001603}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001604
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001605void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1606 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001607 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001608 if (outer.isEmpty()) {
1609 return;
1610 }
1611 if (inner.isEmpty()) {
1612 this->drawRRect(outer, paint);
1613 return;
1614 }
1615
1616 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001617 // be able to return ...
1618 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001619 //
1620 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001621 if (!outer.getBounds().contains(inner.getBounds())) {
1622 return;
1623 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001624
1625 this->onDrawDRRect(outer, inner, paint);
1626}
1627
reed41af9662015-01-05 07:49:08 -08001628void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001629 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001630 this->onDrawPaint(paint);
1631}
1632
1633void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001634 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001635 // To avoid redundant logic in our culling code and various backends, we always sort rects
1636 // before passing them along.
1637 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001638}
1639
msarettdca352e2016-08-26 06:37:45 -07001640void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001641 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001642 if (region.isEmpty()) {
1643 return;
1644 }
1645
1646 if (region.isRect()) {
1647 return this->drawIRect(region.getBounds(), paint);
1648 }
1649
1650 this->onDrawRegion(region, paint);
1651}
1652
reed41af9662015-01-05 07:49:08 -08001653void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001654 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001655 // To avoid redundant logic in our culling code and various backends, we always sort rects
1656 // before passing them along.
1657 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001658}
1659
1660void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001661 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001662 this->onDrawRRect(rrect, paint);
1663}
1664
1665void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001666 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001667 this->onDrawPoints(mode, count, pts, paint);
1668}
1669
Mike Reede88a1cb2017-03-17 09:50:46 -04001670void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1671 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001672 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001673 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001674 this->onDrawVerticesObject(vertices.get(), mode, paint);
1675}
1676
1677void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001678 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001679 RETURN_ON_NULL(vertices);
1680 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001681}
1682
1683void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001684 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001685 this->onDrawPath(path, paint);
1686}
1687
reeda85d4d02015-05-06 12:56:48 -07001688void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001689 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001690 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001691 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001692}
1693
Mike Reedc4e31092018-01-30 11:15:27 -05001694// Returns true if the rect can be "filled" : non-empty and finite
1695static bool fillable(const SkRect& r) {
1696 SkScalar w = r.width();
1697 SkScalar h = r.height();
1698 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1699}
1700
reede47829b2015-08-06 10:02:53 -07001701void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1702 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001703 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001704 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001705 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001706 return;
1707 }
1708 this->onDrawImageRect(image, &src, dst, paint, constraint);
1709}
reed41af9662015-01-05 07:49:08 -08001710
reed84984ef2015-07-17 07:09:43 -07001711void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1712 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001713 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001714 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001715}
1716
reede47829b2015-08-06 10:02:53 -07001717void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1718 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001719 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001720 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1721 constraint);
1722}
reede47829b2015-08-06 10:02:53 -07001723
reed4c21dc52015-06-25 12:32:03 -07001724void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1725 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001727 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001728 if (dst.isEmpty()) {
1729 return;
1730 }
msarett552bca92016-08-03 06:53:26 -07001731 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1732 this->onDrawImageNine(image, center, dst, paint);
1733 } else {
reede47829b2015-08-06 10:02:53 -07001734 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001735 }
reed4c21dc52015-06-25 12:32:03 -07001736}
1737
msarett16882062016-08-16 09:31:08 -07001738void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1739 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001740 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001741 RETURN_ON_NULL(image);
1742 if (dst.isEmpty()) {
1743 return;
1744 }
msarett71df2d72016-09-30 12:41:42 -07001745
1746 SkIRect bounds;
1747 Lattice latticePlusBounds = lattice;
1748 if (!latticePlusBounds.fBounds) {
1749 bounds = SkIRect::MakeWH(image->width(), image->height());
1750 latticePlusBounds.fBounds = &bounds;
1751 }
1752
1753 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1754 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001755 } else {
1756 this->drawImageRect(image, dst, paint);
1757 }
1758}
1759
reed41af9662015-01-05 07:49:08 -08001760void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001761 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001762 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001763 return;
1764 }
reed41af9662015-01-05 07:49:08 -08001765 this->onDrawBitmap(bitmap, dx, dy, paint);
1766}
1767
reede47829b2015-08-06 10:02:53 -07001768void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001769 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001770 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001771 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001772 return;
1773 }
reede47829b2015-08-06 10:02:53 -07001774 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001775}
1776
reed84984ef2015-07-17 07:09:43 -07001777void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1778 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001779 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001780}
1781
reede47829b2015-08-06 10:02:53 -07001782void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1783 SrcRectConstraint constraint) {
1784 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1785 constraint);
1786}
reede47829b2015-08-06 10:02:53 -07001787
reed41af9662015-01-05 07:49:08 -08001788void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1789 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001790 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001791 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001792 return;
1793 }
msarett552bca92016-08-03 06:53:26 -07001794 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1795 this->onDrawBitmapNine(bitmap, center, dst, paint);
1796 } else {
reeda5517e22015-07-14 10:54:12 -07001797 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001798 }
reed41af9662015-01-05 07:49:08 -08001799}
1800
msarettc573a402016-08-02 08:05:56 -07001801void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1802 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001803 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001804 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001805 return;
1806 }
msarett71df2d72016-09-30 12:41:42 -07001807
1808 SkIRect bounds;
1809 Lattice latticePlusBounds = lattice;
1810 if (!latticePlusBounds.fBounds) {
1811 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1812 latticePlusBounds.fBounds = &bounds;
1813 }
1814
1815 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1816 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001817 } else {
msarett16882062016-08-16 09:31:08 -07001818 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001819 }
msarettc573a402016-08-02 08:05:56 -07001820}
1821
reed71c3c762015-06-24 10:29:17 -07001822void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001823 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001824 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001825 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001826 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001827 if (count <= 0) {
1828 return;
1829 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001830 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001831 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001832 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001833}
1834
reedf70b5312016-03-04 16:36:20 -08001835void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001836 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001837 if (key) {
1838 this->onDrawAnnotation(rect, key, value);
1839 }
1840}
1841
reede47829b2015-08-06 10:02:53 -07001842void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1843 const SkPaint* paint, SrcRectConstraint constraint) {
1844 if (src) {
1845 this->drawImageRect(image, *src, dst, paint, constraint);
1846 } else {
1847 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1848 dst, paint, constraint);
1849 }
1850}
1851void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1852 const SkPaint* paint, SrcRectConstraint constraint) {
1853 if (src) {
1854 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1855 } else {
1856 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1857 dst, paint, constraint);
1858 }
1859}
1860
Mike Reed4204da22017-05-17 08:53:36 -04001861void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001862 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001863 this->onDrawShadowRec(path, rec);
1864}
1865
1866void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1867 SkPaint paint;
1868 const SkRect& pathBounds = path.getBounds();
1869
1870 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1871 while (iter.next()) {
1872 iter.fDevice->drawShadow(path, rec);
1873 }
1874 LOOPER_END
1875}
1876
reed@android.com8a1c16f2008-12-17 15:59:43 +00001877//////////////////////////////////////////////////////////////////////////////
1878// These are the virtual drawing methods
1879//////////////////////////////////////////////////////////////////////////////
1880
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001881void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001882 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001883 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1884 }
1885}
1886
reed41af9662015-01-05 07:49:08 -08001887void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001888 this->internalDrawPaint(paint);
1889}
1890
1891void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001892 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001893
1894 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001895 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001896 }
1897
reed@google.com4e2b3d32011-04-07 14:18:59 +00001898 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899}
1900
reed41af9662015-01-05 07:49:08 -08001901void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1902 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001903 if ((long)count <= 0) {
1904 return;
1905 }
1906
Mike Reed822128b2017-02-28 16:41:03 -05001907 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001908 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001909 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001910 // special-case 2 points (common for drawing a single line)
1911 if (2 == count) {
1912 r.set(pts[0], pts[1]);
1913 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001914 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001915 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001916 if (!r.isFinite()) {
1917 return;
1918 }
Mike Reed822128b2017-02-28 16:41:03 -05001919 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001920 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1921 return;
1922 }
1923 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001924 }
reed@google.coma584aed2012-05-16 14:06:02 +00001925
halcanary96fcdcc2015-08-27 07:41:13 -07001926 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001927
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001928 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001929
reed@android.com8a1c16f2008-12-17 15:59:43 +00001930 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001931 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001932 }
reed@google.com4b226022011-01-11 18:32:13 +00001933
reed@google.com4e2b3d32011-04-07 14:18:59 +00001934 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001935}
1936
reed4a167172016-08-18 17:15:25 -07001937static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1938 return ((intptr_t)paint.getImageFilter() |
1939#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1940 (intptr_t)canvas->getDrawFilter() |
1941#endif
1942 (intptr_t)paint.getLooper() ) != 0;
1943}
1944
reed41af9662015-01-05 07:49:08 -08001945void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001946 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001947 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001948 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001949 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001950 return;
1951 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001952 }
reed@google.com4b226022011-01-11 18:32:13 +00001953
reed4a167172016-08-18 17:15:25 -07001954 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05001955 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956
reed4a167172016-08-18 17:15:25 -07001957 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001958 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07001959 }
1960
1961 LOOPER_END
1962 } else {
Mike Reed822128b2017-02-28 16:41:03 -05001963 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07001964 SkDrawIter iter(this);
1965 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001966 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07001967 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001969}
1970
msarett44df6512016-08-25 13:54:30 -07001971void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07001972 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07001973 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001974 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07001975 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
1976 return;
1977 }
msarett44df6512016-08-25 13:54:30 -07001978 }
1979
Mike Reed822128b2017-02-28 16:41:03 -05001980 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07001981
1982 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001983 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07001984 }
1985
1986 LOOPER_END
1987}
1988
reed41af9662015-01-05 07:49:08 -08001989void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001990 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001991 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001992 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001993 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001994 return;
1995 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001996 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001997
Mike Reed822128b2017-02-28 16:41:03 -05001998 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001999
2000 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002001 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002002 }
2003
2004 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002005}
2006
bsalomonac3aa242016-08-19 11:25:19 -07002007void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2008 SkScalar sweepAngle, bool useCenter,
2009 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002010 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002011 if (paint.canComputeFastBounds()) {
2012 SkRect storage;
2013 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002014 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002015 return;
2016 }
bsalomonac3aa242016-08-19 11:25:19 -07002017 }
2018
Mike Reed822128b2017-02-28 16:41:03 -05002019 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002020
2021 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002022 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002023 }
2024
2025 LOOPER_END
2026}
2027
reed41af9662015-01-05 07:49:08 -08002028void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002029 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002030 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002031 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2032 return;
2033 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002034 }
2035
2036 if (rrect.isRect()) {
2037 // call the non-virtual version
2038 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002039 return;
2040 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002041 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002042 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2043 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002044 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002045
Mike Reed822128b2017-02-28 16:41:03 -05002046 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002047
2048 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002049 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002050 }
2051
2052 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002053}
2054
Mike Reed822128b2017-02-28 16:41:03 -05002055void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002056 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002057 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002058 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2059 return;
2060 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002061 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002062
Mike Reed822128b2017-02-28 16:41:03 -05002063 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002064
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002065 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002066 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002067 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002068
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002069 LOOPER_END
2070}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002071
reed41af9662015-01-05 07:49:08 -08002072void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002073 if (!path.isFinite()) {
2074 return;
2075 }
2076
Mike Reed822128b2017-02-28 16:41:03 -05002077 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002078 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002079 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002080 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2081 return;
2082 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002083 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002084
Mike Reed822128b2017-02-28 16:41:03 -05002085 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002086 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002087 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002088 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002089 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002090 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002091
Mike Reed822128b2017-02-28 16:41:03 -05002092 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093
2094 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002095 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 }
2097
reed@google.com4e2b3d32011-04-07 14:18:59 +00002098 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099}
2100
reed262a71b2015-12-05 13:07:27 -08002101bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002102 if (!paint.getImageFilter()) {
2103 return false;
2104 }
2105
2106 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002107 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002108 return false;
2109 }
2110
2111 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2112 // Once we can filter and the filter will return a result larger than itself, we should be
2113 // able to remove this constraint.
2114 // skbug.com/4526
2115 //
2116 SkPoint pt;
2117 ctm.mapXY(x, y, &pt);
2118 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2119 return ir.contains(fMCRec->fRasterClip.getBounds());
2120}
2121
Mike Reedf441cfc2018-04-11 14:50:16 -04002122// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2123// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2124// null.
2125static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2126 if (paintParam) {
2127 *real = *paintParam;
2128 real->setStyle(SkPaint::kFill_Style);
2129 real->setPathEffect(nullptr);
2130 paintParam = real;
2131 }
2132 return paintParam;
2133}
2134
reeda85d4d02015-05-06 12:56:48 -07002135void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002136 SkPaint realPaint;
2137 paint = init_image_paint(&realPaint, paint);
2138
reeda85d4d02015-05-06 12:56:48 -07002139 SkRect bounds = SkRect::MakeXYWH(x, y,
2140 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002141 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002142 SkRect tmp = bounds;
2143 if (paint) {
2144 paint->computeFastBounds(tmp, &tmp);
2145 }
2146 if (this->quickReject(tmp)) {
2147 return;
2148 }
reeda85d4d02015-05-06 12:56:48 -07002149 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002150 // At this point we need a real paint object. If the caller passed null, then we should
2151 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2152 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2153 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002154
reeda2217ef2016-07-20 06:04:34 -07002155 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002156 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2157 *paint);
2158 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002159 special = this->getDevice()->makeSpecial(image);
2160 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002161 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002162 }
2163 }
2164
reed262a71b2015-12-05 13:07:27 -08002165 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2166
reeda85d4d02015-05-06 12:56:48 -07002167 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002168 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002169 if (special) {
2170 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002171 iter.fDevice->ctm().mapXY(x, y, &pt);
2172 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002173 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002174 SkScalarRoundToInt(pt.fY), pnt,
2175 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002176 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002177 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002178 }
reeda85d4d02015-05-06 12:56:48 -07002179 }
halcanary9d524f22016-03-29 09:03:52 -07002180
reeda85d4d02015-05-06 12:56:48 -07002181 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002182}
2183
reed41af9662015-01-05 07:49:08 -08002184void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002185 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002186 SkPaint realPaint;
2187 paint = init_image_paint(&realPaint, paint);
2188
halcanary96fcdcc2015-08-27 07:41:13 -07002189 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002190 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002191 if (paint) {
2192 paint->computeFastBounds(dst, &storage);
2193 }
2194 if (this->quickReject(storage)) {
2195 return;
2196 }
reeda85d4d02015-05-06 12:56:48 -07002197 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002198 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002199
senorblancoc41e7e12015-12-07 12:51:30 -08002200 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002201 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002202
reeda85d4d02015-05-06 12:56:48 -07002203 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002204 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002205 }
halcanary9d524f22016-03-29 09:03:52 -07002206
reeda85d4d02015-05-06 12:56:48 -07002207 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002208}
2209
reed41af9662015-01-05 07:49:08 -08002210void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211 SkDEBUGCODE(bitmap.validate();)
2212
reed33366972015-10-08 09:22:02 -07002213 if (bitmap.drawsNothing()) {
2214 return;
2215 }
2216
Mike Reedf441cfc2018-04-11 14:50:16 -04002217 SkPaint realPaint;
2218 init_image_paint(&realPaint, paint);
2219 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002220
Mike Reed822128b2017-02-28 16:41:03 -05002221 SkRect bounds;
2222 bitmap.getBounds(&bounds);
2223 bounds.offset(x, y);
2224 bool canFastBounds = paint->canComputeFastBounds();
2225 if (canFastBounds) {
2226 SkRect storage;
2227 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002228 return;
2229 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002230 }
reed@google.com4b226022011-01-11 18:32:13 +00002231
reeda2217ef2016-07-20 06:04:34 -07002232 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002233 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2234 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002235 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002236 special = this->getDevice()->makeSpecial(bitmap);
2237 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002238 drawAsSprite = false;
2239 }
2240 }
2241
Mike Reed822128b2017-02-28 16:41:03 -05002242 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002243
2244 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002245 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002246 if (special) {
reed262a71b2015-12-05 13:07:27 -08002247 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002248 iter.fDevice->ctm().mapXY(x, y, &pt);
2249 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002250 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002251 SkScalarRoundToInt(pt.fY), pnt,
2252 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002253 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002254 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002255 }
reed33366972015-10-08 09:22:02 -07002256 }
msarettfbfa2582016-08-12 08:29:08 -07002257
reed33366972015-10-08 09:22:02 -07002258 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259}
2260
reed@google.com9987ec32011-09-07 11:57:52 +00002261// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002262void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002263 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002264 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002265 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002266 return;
2267 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002268
halcanary96fcdcc2015-08-27 07:41:13 -07002269 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002270 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002271 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2272 return;
2273 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002274 }
reed@google.com3d608122011-11-21 15:16:16 +00002275
reed@google.com33535f32012-09-25 15:37:50 +00002276 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002277 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002278 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002280
senorblancoc41e7e12015-12-07 12:51:30 -08002281 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002282 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002283
reed@google.com33535f32012-09-25 15:37:50 +00002284 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002285 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002286 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002287
reed@google.com33535f32012-09-25 15:37:50 +00002288 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289}
2290
reed41af9662015-01-05 07:49:08 -08002291void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002292 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002293 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002294 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002295}
2296
reed4c21dc52015-06-25 12:32:03 -07002297void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2298 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002299 SkPaint realPaint;
2300 paint = init_image_paint(&realPaint, paint);
2301
halcanary96fcdcc2015-08-27 07:41:13 -07002302 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002303 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002304 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2305 return;
2306 }
reed@google.com3d608122011-11-21 15:16:16 +00002307 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002308 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002309
senorblancoc41e7e12015-12-07 12:51:30 -08002310 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002311
reed4c21dc52015-06-25 12:32:03 -07002312 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002313 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002314 }
halcanary9d524f22016-03-29 09:03:52 -07002315
reed4c21dc52015-06-25 12:32:03 -07002316 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002317}
2318
reed41af9662015-01-05 07:49:08 -08002319void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2320 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002321 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002322 SkPaint realPaint;
2323 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002324
halcanary96fcdcc2015-08-27 07:41:13 -07002325 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002326 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002327 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2328 return;
2329 }
reed4c21dc52015-06-25 12:32:03 -07002330 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002331 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002332
senorblancoc41e7e12015-12-07 12:51:30 -08002333 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002334
reed4c21dc52015-06-25 12:32:03 -07002335 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002336 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002337 }
halcanary9d524f22016-03-29 09:03:52 -07002338
reed4c21dc52015-06-25 12:32:03 -07002339 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002340}
2341
msarett16882062016-08-16 09:31:08 -07002342void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2343 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002344 SkPaint realPaint;
2345 paint = init_image_paint(&realPaint, paint);
2346
msarett16882062016-08-16 09:31:08 -07002347 if (nullptr == paint || paint->canComputeFastBounds()) {
2348 SkRect storage;
2349 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2350 return;
2351 }
2352 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002353 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002354
2355 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2356
2357 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002358 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002359 }
2360
2361 LOOPER_END
2362}
2363
2364void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2365 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002366 SkPaint realPaint;
2367 paint = init_image_paint(&realPaint, paint);
2368
msarett16882062016-08-16 09:31:08 -07002369 if (nullptr == paint || paint->canComputeFastBounds()) {
2370 SkRect storage;
2371 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2372 return;
2373 }
2374 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002375 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002376
2377 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2378
2379 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002380 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002381 }
2382
2383 LOOPER_END
2384}
2385
reed@google.comf67e4cf2011-03-15 20:56:58 +00002386class SkDeviceFilteredPaint {
2387public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002388 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002389 uint32_t filteredFlags = device->filterTextFlags(paint);
2390 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002391 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002392 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002393 fPaint = newPaint;
2394 } else {
2395 fPaint = &paint;
2396 }
2397 }
2398
reed@google.comf67e4cf2011-03-15 20:56:58 +00002399 const SkPaint& paint() const { return *fPaint; }
2400
2401private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002402 const SkPaint* fPaint;
2403 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002404};
2405
reed@google.come0d9ce82014-04-23 04:00:17 +00002406void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2407 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002408 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409
2410 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002411 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002412 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002413 }
2414
reed@google.com4e2b3d32011-04-07 14:18:59 +00002415 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002416}
2417
reed@google.come0d9ce82014-04-23 04:00:17 +00002418void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2419 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002420 SkPoint textOffset = SkPoint::Make(0, 0);
2421
halcanary96fcdcc2015-08-27 07:41:13 -07002422 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002423
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002425 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002426 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002427 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002428 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002429
reed@google.com4e2b3d32011-04-07 14:18:59 +00002430 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002431}
2432
reed@google.come0d9ce82014-04-23 04:00:17 +00002433void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2434 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002435
2436 SkPoint textOffset = SkPoint::Make(0, constY);
2437
halcanary96fcdcc2015-08-27 07:41:13 -07002438 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002439
reed@android.com8a1c16f2008-12-17 15:59:43 +00002440 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002441 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002442 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002443 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002445
reed@google.com4e2b3d32011-04-07 14:18:59 +00002446 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002447}
2448
reed@google.come0d9ce82014-04-23 04:00:17 +00002449void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2450 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002451 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002452
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002454 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002455 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002457
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002458 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002459}
2460
reed45561a02016-07-07 12:47:17 -07002461void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2462 const SkRect* cullRect, const SkPaint& paint) {
2463 if (cullRect && this->quickReject(*cullRect)) {
2464 return;
2465 }
2466
2467 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2468
2469 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002470 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002471 }
2472
2473 LOOPER_END
2474}
2475
fmalita00d5c2c2014-08-21 08:53:26 -07002476void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2477 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002478
fmalita85d5eb92015-03-04 11:20:12 -08002479 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002480 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002481 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002482 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002483 SkRect tmp;
2484 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2485 return;
2486 }
2487 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002488 }
2489
fmalita024f9962015-03-03 19:08:17 -08002490 // We cannot filter in the looper as we normally do, because the paint is
2491 // incomplete at this point (text-related attributes are embedded within blob run paints).
2492 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002493 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002494
fmalita85d5eb92015-03-04 11:20:12 -08002495 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002496
fmalitaaa1b9122014-08-28 14:32:24 -07002497 while (iter.next()) {
2498 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002499 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002500 }
2501
fmalitaaa1b9122014-08-28 14:32:24 -07002502 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002503
2504 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002505}
2506
Cary Clark2a475ea2017-04-28 15:35:12 -04002507void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2508 this->drawText(string.c_str(), string.size(), x, y, paint);
2509}
2510
reed@google.come0d9ce82014-04-23 04:00:17 +00002511// These will become non-virtual, so they always call the (virtual) onDraw... method
2512void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2513 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002514 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002515 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002516 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002517 this->onDrawText(text, byteLength, x, y, paint);
2518 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002519}
2520void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2521 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002522 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002523 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002524 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002525 this->onDrawPosText(text, byteLength, pos, paint);
2526 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002527}
2528void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2529 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002530 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002531 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002532 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002533 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2534 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002535}
2536void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2537 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002538 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002539 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002540 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002541 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2542 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002543}
reed45561a02016-07-07 12:47:17 -07002544void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2545 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002546 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002547 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002548 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002549 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2550 }
2551}
fmalita00d5c2c2014-08-21 08:53:26 -07002552void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2553 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002554 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002555 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002556 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002557 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002558}
reed@google.come0d9ce82014-04-23 04:00:17 +00002559
Mike Reede88a1cb2017-03-17 09:50:46 -04002560void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2561 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002562 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2563
2564 while (iter.next()) {
2565 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002566 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002567 }
2568
2569 LOOPER_END
2570}
2571
dandovb3c9d1c2014-08-12 08:34:29 -07002572void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002573 const SkPoint texCoords[4], SkBlendMode bmode,
2574 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002575 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002576 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002577 return;
2578 }
mtklein6cfa73a2014-08-13 13:33:49 -07002579
Mike Reedfaba3712016-11-03 14:45:31 -04002580 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002581}
2582
2583void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002584 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002585 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002586 // Since a patch is always within the convex hull of the control points, we discard it when its
2587 // bounding rectangle is completely outside the current clip.
2588 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002589 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002590 if (this->quickReject(bounds)) {
2591 return;
2592 }
mtklein6cfa73a2014-08-13 13:33:49 -07002593
Mike Reed435071e2017-05-23 11:22:56 -04002594 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2595
halcanary96fcdcc2015-08-27 07:41:13 -07002596 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002597
dandovecfff212014-08-04 10:02:00 -07002598 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002599 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002600 }
mtklein6cfa73a2014-08-13 13:33:49 -07002601
dandovecfff212014-08-04 10:02:00 -07002602 LOOPER_END
2603}
2604
reeda8db7282015-07-07 10:22:31 -07002605void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002606#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002607 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002608#endif
reede3b38ce2016-01-08 09:18:44 -08002609 RETURN_ON_NULL(dr);
2610 if (x || y) {
2611 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2612 this->onDrawDrawable(dr, &matrix);
2613 } else {
2614 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002615 }
2616}
2617
reeda8db7282015-07-07 10:22:31 -07002618void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002619#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002620 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002621#endif
reede3b38ce2016-01-08 09:18:44 -08002622 RETURN_ON_NULL(dr);
2623 if (matrix && matrix->isIdentity()) {
2624 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002625 }
reede3b38ce2016-01-08 09:18:44 -08002626 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002627}
2628
2629void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002630 // drawable bounds are no longer reliable (e.g. android displaylist)
2631 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002632 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002633}
2634
reed71c3c762015-06-24 10:29:17 -07002635void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002636 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002637 const SkRect* cull, const SkPaint* paint) {
2638 if (cull && this->quickReject(*cull)) {
2639 return;
2640 }
2641
2642 SkPaint pnt;
2643 if (paint) {
2644 pnt = *paint;
2645 }
halcanary9d524f22016-03-29 09:03:52 -07002646
halcanary96fcdcc2015-08-27 07:41:13 -07002647 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002648 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002649 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002650 }
2651 LOOPER_END
2652}
2653
reedf70b5312016-03-04 16:36:20 -08002654void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2655 SkASSERT(key);
2656
2657 SkPaint paint;
2658 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2659 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002660 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002661 }
2662 LOOPER_END
2663}
2664
reed@android.com8a1c16f2008-12-17 15:59:43 +00002665//////////////////////////////////////////////////////////////////////////////
2666// These methods are NOT virtual, and therefore must call back into virtual
2667// methods, rather than actually drawing themselves.
2668//////////////////////////////////////////////////////////////////////////////
2669
reed374772b2016-10-05 17:33:02 -07002670void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002671 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002672 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002673 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674 this->drawPaint(paint);
2675}
2676
2677void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002678 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2680}
2681
Mike Reed3661bc92017-02-22 13:21:42 -05002682void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684 pts[0].set(x0, y0);
2685 pts[1].set(x1, y1);
2686 this->drawPoints(kLines_PointMode, 2, pts, paint);
2687}
2688
Mike Reed3661bc92017-02-22 13:21:42 -05002689void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002690 if (radius < 0) {
2691 radius = 0;
2692 }
2693
2694 SkRect r;
2695 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002696 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697}
2698
2699void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2700 const SkPaint& paint) {
2701 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002702 SkRRect rrect;
2703 rrect.setRectXY(r, rx, ry);
2704 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705 } else {
2706 this->drawRect(r, paint);
2707 }
2708}
2709
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2711 SkScalar sweepAngle, bool useCenter,
2712 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002713 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002714 if (oval.isEmpty() || !sweepAngle) {
2715 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 }
bsalomon21af9ca2016-08-25 12:29:23 -07002717 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718}
2719
2720void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2721 const SkPath& path, SkScalar hOffset,
2722 SkScalar vOffset, const SkPaint& paint) {
2723 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002724
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 matrix.setTranslate(hOffset, vOffset);
2726 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2727}
2728
reed@android.comf76bacf2009-05-13 14:00:33 +00002729///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002730
Mike Klein88d90712018-01-27 17:30:04 +00002731/**
2732 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2733 * against the playback cost of recursing into the subpicture to get at its actual ops.
2734 *
2735 * For now we pick a conservatively small value, though measurement (and other heuristics like
2736 * the type of ops contained) may justify changing this value.
2737 */
2738#define kMaxPictureOpsToUnrollInsteadOfRef 1
2739
reedd5fa1a42014-08-09 11:08:05 -07002740void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002741 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002742 RETURN_ON_NULL(picture);
2743
reede3b38ce2016-01-08 09:18:44 -08002744 if (matrix && matrix->isIdentity()) {
2745 matrix = nullptr;
2746 }
Mike Klein88d90712018-01-27 17:30:04 +00002747 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2748 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2749 picture->playback(this);
2750 } else {
2751 this->onDrawPicture(picture, matrix, paint);
2752 }
reedd5fa1a42014-08-09 11:08:05 -07002753}
robertphillips9b14f262014-06-04 05:40:44 -07002754
reedd5fa1a42014-08-09 11:08:05 -07002755void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2756 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002757 if (!paint || paint->canComputeFastBounds()) {
2758 SkRect bounds = picture->cullRect();
2759 if (paint) {
2760 paint->computeFastBounds(bounds, &bounds);
2761 }
2762 if (matrix) {
2763 matrix->mapRect(&bounds);
2764 }
2765 if (this->quickReject(bounds)) {
2766 return;
2767 }
2768 }
2769
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002770 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002771 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772}
2773
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774///////////////////////////////////////////////////////////////////////////////
2775///////////////////////////////////////////////////////////////////////////////
2776
reed3aafe112016-08-18 12:45:34 -07002777SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002778 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779
2780 SkASSERT(canvas);
2781
reed3aafe112016-08-18 12:45:34 -07002782 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 fDone = !fImpl->next();
2784}
2785
2786SkCanvas::LayerIter::~LayerIter() {
2787 fImpl->~SkDrawIter();
2788}
2789
2790void SkCanvas::LayerIter::next() {
2791 fDone = !fImpl->next();
2792}
2793
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002794SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002795 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796}
2797
2798const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002799 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800}
2801
2802const SkPaint& SkCanvas::LayerIter::paint() const {
2803 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002804 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 paint = &fDefaultPaint;
2806 }
2807 return *paint;
2808}
2809
Mike Reedca37f322018-03-08 13:22:16 -05002810SkIRect SkCanvas::LayerIter::clipBounds() const {
2811 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002812}
2813
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2815int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002816
2817///////////////////////////////////////////////////////////////////////////////
2818
Brian Osman10fc6fd2018-03-02 11:01:10 -05002819// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002820static bool supported_for_raster_canvas(const SkImageInfo& info) {
2821 switch (info.alphaType()) {
2822 case kPremul_SkAlphaType:
2823 case kOpaque_SkAlphaType:
2824 break;
2825 default:
2826 return false;
2827 }
2828
2829 switch (info.colorType()) {
2830 case kAlpha_8_SkColorType:
2831 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002832 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002833 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002834 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002835 break;
2836 default:
2837 return false;
2838 }
2839
2840 return true;
2841}
2842
Mike Reed5df49342016-11-12 08:06:55 -06002843std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002844 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002845 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002846 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002847 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002848
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002849 SkBitmap bitmap;
2850 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002851 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002852 }
Mike Reed12f77342017-11-08 11:19:52 -05002853
2854 return props ?
2855 skstd::make_unique<SkCanvas>(bitmap, *props) :
2856 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002857}
reedd5fa1a42014-08-09 11:08:05 -07002858
2859///////////////////////////////////////////////////////////////////////////////
2860
Florin Malitaee424ac2016-12-01 12:47:59 -05002861SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2862 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2863
Florin Malita439ace92016-12-02 12:05:41 -05002864SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2865 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2866
Herb Derby76d69b42018-03-15 17:34:40 -04002867SkNoDrawCanvas::SkNoDrawCanvas(SkBaseDevice *device)
2868 : INHERITED(device) {}
2869
Florin Malitaee424ac2016-12-01 12:47:59 -05002870SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2871 (void)this->INHERITED::getSaveLayerStrategy(rec);
2872 return kNoLayer_SaveLayerStrategy;
2873}
2874
2875///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002876
reed73603f32016-09-20 08:42:38 -07002877static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2878static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2879static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2880static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2881static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2882static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002883
2884///////////////////////////////////////////////////////////////////////////////////////////////////
2885
2886SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2887 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002888 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002889 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2890 SkIPoint origin = dev->getOrigin();
2891 SkMatrix ctm = this->getTotalMatrix();
2892 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2893
2894 SkIRect clip = fMCRec->fRasterClip.getBounds();
2895 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002896 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002897 clip.setEmpty();
2898 }
2899
2900 fAllocator->updateHandle(handle, ctm, clip);
2901 return handle;
2902 }
2903 return nullptr;
2904}
2905
2906static bool install(SkBitmap* bm, const SkImageInfo& info,
2907 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002908 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002909}
2910
2911SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2912 SkBitmap* bm) {
2913 SkRasterHandleAllocator::Rec rec;
2914 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2915 return nullptr;
2916 }
2917 return rec.fHandle;
2918}
2919
2920std::unique_ptr<SkCanvas>
2921SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2922 const SkImageInfo& info, const Rec* rec) {
2923 if (!alloc || !supported_for_raster_canvas(info)) {
2924 return nullptr;
2925 }
2926
2927 SkBitmap bm;
2928 Handle hndl;
2929
2930 if (rec) {
2931 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2932 } else {
2933 hndl = alloc->allocBitmap(info, &bm);
2934 }
2935 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2936}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002937
2938///////////////////////////////////////////////////////////////////////////////////////////////////
2939
2940