1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2008 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkBlender.h"
11cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h"
12cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
13cb93a386Sopenharmony_ci#include "include/core/SkImageFilter.h"
14cb93a386Sopenharmony_ci#include "include/core/SkLog.h"
15cb93a386Sopenharmony_ci#include "include/core/SkPathEffect.h"
16cb93a386Sopenharmony_ci#include "include/core/SkPicture.h"
17cb93a386Sopenharmony_ci#include "include/core/SkRRect.h"
18cb93a386Sopenharmony_ci#include "include/core/SkRasterHandleAllocator.h"
19cb93a386Sopenharmony_ci#include "include/core/SkString.h"
20cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
21cb93a386Sopenharmony_ci#include "include/core/SkVertices.h"
22cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h"
23cb93a386Sopenharmony_ci#include "include/private/SkTOptional.h"
24cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
25cb93a386Sopenharmony_ci#include "include/utils/SkNoDrawCanvas.h"
26cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h"
27cb93a386Sopenharmony_ci#include "src/core/SkBitmapDevice.h"
28cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h"
29cb93a386Sopenharmony_ci#include "src/core/SkClipStack.h"
30cb93a386Sopenharmony_ci#include "src/core/SkColorFilterBase.h"
31cb93a386Sopenharmony_ci#include "src/core/SkDraw.h"
32cb93a386Sopenharmony_ci#include "src/core/SkGlyphRun.h"
33cb93a386Sopenharmony_ci#include "src/core/SkImageFilterCache.h"
34cb93a386Sopenharmony_ci#include "src/core/SkImageFilter_Base.h"
35cb93a386Sopenharmony_ci#include "src/core/SkLatticeIter.h"
36cb93a386Sopenharmony_ci#include "src/core/SkMSAN.h"
37cb93a386Sopenharmony_ci#include "src/core/SkMarkerStack.h"
38cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h"
39cb93a386Sopenharmony_ci#include "src/core/SkMatrixUtils.h"
40cb93a386Sopenharmony_ci#include "src/core/SkPaintPriv.h"
41cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h"
42cb93a386Sopenharmony_ci#include "src/core/SkSpecialImage.h"
43cb93a386Sopenharmony_ci#include "src/core/SkStrikeCache.h"
44cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h"
45cb93a386Sopenharmony_ci#include "src/core/SkTextFormatParams.h"
46cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h"
47cb93a386Sopenharmony_ci#include "src/core/SkVerticesPriv.h"
48cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h"
49cb93a386Sopenharmony_ci#include "src/image/SkSurface_Base.h"
50cb93a386Sopenharmony_ci#include "src/utils/SkPatchUtils.h"
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci#include <memory>
53cb93a386Sopenharmony_ci#include <new>
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci#ifdef SK_ENABLE_PATH_COMPLEXITY_DFX
56cb93a386Sopenharmony_ci#include "src/core/SkPathComplexityDfx.h"
57cb93a386Sopenharmony_ci#endif
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU
60cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
61cb93a386Sopenharmony_ci#include "src/gpu/BaseDevice.h"
62cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h"
63cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
64cb93a386Sopenharmony_ci#   include "src/gpu/GrRenderTarget.h"
65cb93a386Sopenharmony_ci#   include "src/gpu/GrRenderTargetProxy.h"
66cb93a386Sopenharmony_ci#endif
67cb93a386Sopenharmony_ci#endif
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci#define RETURN_ON_NULL(ptr)     do { if (nullptr == (ptr)) return; } while (0)
70cb93a386Sopenharmony_ci#define RETURN_ON_FALSE(pred)   do { if (!(pred)) return; } while (0)
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci// This is a test: static_assert with no message is a c++17 feature,
73cb93a386Sopenharmony_ci// and std::max() is constexpr only since the c++14 stdlib.
74cb93a386Sopenharmony_cistatic_assert(std::max(3,4) == 4);
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci/*
79cb93a386Sopenharmony_ci *  Return true if the drawing this rect would hit every pixels in the canvas.
80cb93a386Sopenharmony_ci *
81cb93a386Sopenharmony_ci *  Returns false if
82cb93a386Sopenharmony_ci *  - rect does not contain the canvas' bounds
83cb93a386Sopenharmony_ci *  - paint is not fill
84cb93a386Sopenharmony_ci *  - paint would blur or otherwise change the coverage of the rect
85cb93a386Sopenharmony_ci */
86cb93a386Sopenharmony_cibool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
87cb93a386Sopenharmony_ci                                           ShaderOverrideOpacity overrideOpacity) const {
88cb93a386Sopenharmony_ci    static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
89cb93a386Sopenharmony_ci                  (int)kNone_ShaderOverrideOpacity,
90cb93a386Sopenharmony_ci                  "need_matching_enums0");
91cb93a386Sopenharmony_ci    static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
92cb93a386Sopenharmony_ci                  (int)kOpaque_ShaderOverrideOpacity,
93cb93a386Sopenharmony_ci                  "need_matching_enums1");
94cb93a386Sopenharmony_ci    static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
95cb93a386Sopenharmony_ci                  (int)kNotOpaque_ShaderOverrideOpacity,
96cb93a386Sopenharmony_ci                  "need_matching_enums2");
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    const SkISize size = this->getBaseLayerSize();
99cb93a386Sopenharmony_ci    const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    // if we're clipped at all, we can't overwrite the entire surface
102cb93a386Sopenharmony_ci    {
103cb93a386Sopenharmony_ci        const SkBaseDevice* base = this->baseDevice();
104cb93a386Sopenharmony_ci        const SkBaseDevice* top = this->topDevice();
105cb93a386Sopenharmony_ci        if (base != top) {
106cb93a386Sopenharmony_ci            return false;   // we're in a saveLayer, so conservatively don't assume we'll overwrite
107cb93a386Sopenharmony_ci        }
108cb93a386Sopenharmony_ci        if (!base->clipIsWideOpen()) {
109cb93a386Sopenharmony_ci            return false;
110cb93a386Sopenharmony_ci        }
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    if (rect) {
114cb93a386Sopenharmony_ci        if (!this->getTotalMatrix().isScaleTranslate()) {
115cb93a386Sopenharmony_ci            return false; // conservative
116cb93a386Sopenharmony_ci        }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci        SkRect devRect;
119cb93a386Sopenharmony_ci        this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
120cb93a386Sopenharmony_ci        if (!devRect.contains(bounds)) {
121cb93a386Sopenharmony_ci            return false;
122cb93a386Sopenharmony_ci        }
123cb93a386Sopenharmony_ci    }
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    if (paint) {
126cb93a386Sopenharmony_ci        SkPaint::Style paintStyle = paint->getStyle();
127cb93a386Sopenharmony_ci        if (!(paintStyle == SkPaint::kFill_Style ||
128cb93a386Sopenharmony_ci              paintStyle == SkPaint::kStrokeAndFill_Style)) {
129cb93a386Sopenharmony_ci            return false;
130cb93a386Sopenharmony_ci        }
131cb93a386Sopenharmony_ci        if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
132cb93a386Sopenharmony_ci            return false; // conservative
133cb93a386Sopenharmony_ci        }
134cb93a386Sopenharmony_ci    }
135cb93a386Sopenharmony_ci    return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci// experimental for faster tiled drawing...
141cb93a386Sopenharmony_ci//#define SK_TRACE_SAVERESTORE
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci#ifdef SK_TRACE_SAVERESTORE
144cb93a386Sopenharmony_ci    static int gLayerCounter;
145cb93a386Sopenharmony_ci    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
146cb93a386Sopenharmony_ci    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci    static int gRecCounter;
149cb93a386Sopenharmony_ci    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
150cb93a386Sopenharmony_ci    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci    static int gCanvasCounter;
153cb93a386Sopenharmony_ci    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
154cb93a386Sopenharmony_ci    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
155cb93a386Sopenharmony_ci#else
156cb93a386Sopenharmony_ci    #define inc_layer()
157cb93a386Sopenharmony_ci    #define dec_layer()
158cb93a386Sopenharmony_ci    #define inc_rec()
159cb93a386Sopenharmony_ci    #define dec_rec()
160cb93a386Sopenharmony_ci    #define inc_canvas()
161cb93a386Sopenharmony_ci    #define dec_canvas()
162cb93a386Sopenharmony_ci#endif
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_cibool SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
165cb93a386Sopenharmony_ci    if (fSurfaceBase) {
166cb93a386Sopenharmony_ci        if (!fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
167cb93a386Sopenharmony_ci                                       ? SkSurface::kDiscard_ContentChangeMode
168cb93a386Sopenharmony_ci                                       : SkSurface::kRetain_ContentChangeMode)) {
169cb93a386Sopenharmony_ci            return false;
170cb93a386Sopenharmony_ci        }
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci    return true;
173cb93a386Sopenharmony_ci}
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_cibool SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
176cb93a386Sopenharmony_ci                             ShaderOverrideOpacity overrideOpacity) {
177cb93a386Sopenharmony_ci    if (fSurfaceBase) {
178cb93a386Sopenharmony_ci        SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
179cb93a386Sopenharmony_ci        // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
180cb93a386Sopenharmony_ci        // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
181cb93a386Sopenharmony_ci        // and therefore we don't care which mode we're in.
182cb93a386Sopenharmony_ci        //
183cb93a386Sopenharmony_ci        if (fSurfaceBase->outstandingImageSnapshot()) {
184cb93a386Sopenharmony_ci            if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
185cb93a386Sopenharmony_ci                mode = SkSurface::kDiscard_ContentChangeMode;
186cb93a386Sopenharmony_ci            }
187cb93a386Sopenharmony_ci        }
188cb93a386Sopenharmony_ci        if (!fSurfaceBase->aboutToDraw(mode)) {
189cb93a386Sopenharmony_ci            return false;
190cb93a386Sopenharmony_ci        }
191cb93a386Sopenharmony_ci    }
192cb93a386Sopenharmony_ci    return true;
193cb93a386Sopenharmony_ci}
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ciSkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device,
198cb93a386Sopenharmony_ci                       sk_sp<SkImageFilter> imageFilter,
199cb93a386Sopenharmony_ci                       const SkPaint& paint)
200cb93a386Sopenharmony_ci        : fDevice(std::move(device))
201cb93a386Sopenharmony_ci        , fImageFilter(std::move(imageFilter))
202cb93a386Sopenharmony_ci        , fPaint(paint)
203cb93a386Sopenharmony_ci        , fDiscard(false) {
204cb93a386Sopenharmony_ci    SkASSERT(fDevice);
205cb93a386Sopenharmony_ci    // Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint'
206cb93a386Sopenharmony_ci    // can be used as-is to draw the result of the filter to the dst device.
207cb93a386Sopenharmony_ci    SkASSERT(!fPaint.getImageFilter());
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ciSkCanvas::MCRec::MCRec(SkBaseDevice* device) : fDevice(device) {
211cb93a386Sopenharmony_ci    SkASSERT(fDevice);
212cb93a386Sopenharmony_ci    inc_rec();
213cb93a386Sopenharmony_ci}
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ciSkCanvas::MCRec::MCRec(const MCRec* prev) : fDevice(prev->fDevice), fMatrix(prev->fMatrix) {
216cb93a386Sopenharmony_ci    SkASSERT(fDevice);
217cb93a386Sopenharmony_ci    inc_rec();
218cb93a386Sopenharmony_ci}
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ciSkCanvas::MCRec::~MCRec() { dec_rec(); }
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_civoid SkCanvas::MCRec::newLayer(sk_sp<SkBaseDevice> layerDevice,
223cb93a386Sopenharmony_ci                               sk_sp<SkImageFilter> filter,
224cb93a386Sopenharmony_ci                               const SkPaint& restorePaint) {
225cb93a386Sopenharmony_ci    SkASSERT(!fBackImage);
226cb93a386Sopenharmony_ci    fLayer = std::make_unique<Layer>(std::move(layerDevice), std::move(filter), restorePaint);
227cb93a386Sopenharmony_ci    fDevice = fLayer->fDevice.get();
228cb93a386Sopenharmony_ci}
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_civoid SkCanvas::MCRec::reset(SkBaseDevice* device) {
231cb93a386Sopenharmony_ci    SkASSERT(!fLayer);
232cb93a386Sopenharmony_ci    SkASSERT(device);
233cb93a386Sopenharmony_ci    SkASSERT(fDeferredSaveCount == 0);
234cb93a386Sopenharmony_ci    fDevice = device;
235cb93a386Sopenharmony_ci    fMatrix.setIdentity();
236cb93a386Sopenharmony_ci}
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ciclass SkCanvas::AutoUpdateQRBounds {
239cb93a386Sopenharmony_cipublic:
240cb93a386Sopenharmony_ci    explicit AutoUpdateQRBounds(SkCanvas* canvas) : fCanvas(canvas) {
241cb93a386Sopenharmony_ci        // pre-condition, fQuickRejectBounds and other state should be valid before anything
242cb93a386Sopenharmony_ci        // modifies the device's clip.
243cb93a386Sopenharmony_ci        fCanvas->validateClip();
244cb93a386Sopenharmony_ci    }
245cb93a386Sopenharmony_ci    ~AutoUpdateQRBounds() {
246cb93a386Sopenharmony_ci        fCanvas->fQuickRejectBounds = fCanvas->computeDeviceClipBounds();
247cb93a386Sopenharmony_ci        // post-condition, we should remain valid after re-computing the bounds
248cb93a386Sopenharmony_ci        fCanvas->validateClip();
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ciprivate:
252cb93a386Sopenharmony_ci    SkCanvas* fCanvas;
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci    AutoUpdateQRBounds(AutoUpdateQRBounds&&) = delete;
255cb93a386Sopenharmony_ci    AutoUpdateQRBounds(const AutoUpdateQRBounds&) = delete;
256cb93a386Sopenharmony_ci    AutoUpdateQRBounds& operator=(AutoUpdateQRBounds&&) = delete;
257cb93a386Sopenharmony_ci    AutoUpdateQRBounds& operator=(const AutoUpdateQRBounds&) = delete;
258cb93a386Sopenharmony_ci};
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////
261cb93a386Sopenharmony_ci// Attempts to convert an image filter to its equivalent color filter, which if possible, modifies
262cb93a386Sopenharmony_ci// the paint to compose the image filter's color filter into the paint's color filter slot.
263cb93a386Sopenharmony_ci// Returns true if the paint has been modified.
264cb93a386Sopenharmony_ci// Requires the paint to have an image filter and the copy-on-write be initialized.
265cb93a386Sopenharmony_cistatic bool image_to_color_filter(SkPaint* paint) {
266cb93a386Sopenharmony_ci    SkASSERT(SkToBool(paint) && paint->getImageFilter());
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    SkColorFilter* imgCFPtr;
269cb93a386Sopenharmony_ci    if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) {
270cb93a386Sopenharmony_ci        return false;
271cb93a386Sopenharmony_ci    }
272cb93a386Sopenharmony_ci    sk_sp<SkColorFilter> imgCF(imgCFPtr);
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci    SkColorFilter* paintCF = paint->getColorFilter();
275cb93a386Sopenharmony_ci    if (paintCF) {
276cb93a386Sopenharmony_ci        // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF)
277cb93a386Sopenharmony_ci        // and we need to combine them into a single colorfilter.
278cb93a386Sopenharmony_ci        imgCF = imgCF->makeComposed(sk_ref_sp(paintCF));
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci    paint->setColorFilter(std::move(imgCF));
282cb93a386Sopenharmony_ci    paint->setImageFilter(nullptr);
283cb93a386Sopenharmony_ci    return true;
284cb93a386Sopenharmony_ci}
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ci/**
287cb93a386Sopenharmony_ci *  We implement ImageFilters for a given draw by creating a layer, then applying the
288cb93a386Sopenharmony_ci *  imagefilter to the pixels of that layer (its backing surface/image), and then
289cb93a386Sopenharmony_ci *  we call restore() to xfer that layer to the main canvas.
290cb93a386Sopenharmony_ci *
291cb93a386Sopenharmony_ci *  1. SaveLayer (with a paint containing the current imagefilter and xfermode)
292cb93a386Sopenharmony_ci *  2. Generate the src pixels:
293cb93a386Sopenharmony_ci *      Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
294cb93a386Sopenharmony_ci *      return (fPaint). We then draw the primitive (using srcover) into a cleared
295cb93a386Sopenharmony_ci *      buffer/surface.
296cb93a386Sopenharmony_ci *  3. Restore the layer created in #1
297cb93a386Sopenharmony_ci *      The imagefilter is passed the buffer/surface from the layer (now filled with the
298cb93a386Sopenharmony_ci *      src pixels of the primitive). It returns a new "filtered" buffer, which we
299cb93a386Sopenharmony_ci *      draw onto the previous layer using the xfermode from the original paint.
300cb93a386Sopenharmony_ci */
301cb93a386Sopenharmony_ciclass AutoLayerForImageFilter {
302cb93a386Sopenharmony_cipublic:
303cb93a386Sopenharmony_ci    // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
304cb93a386Sopenharmony_ci    // paint. It's used to determine the size of the offscreen layer for filters.
305cb93a386Sopenharmony_ci    // If null, the clip will be used instead.
306cb93a386Sopenharmony_ci    //
307cb93a386Sopenharmony_ci    // Draw functions should use layer->paint() instead of the passed-in paint.
308cb93a386Sopenharmony_ci    AutoLayerForImageFilter(SkCanvas* canvas,
309cb93a386Sopenharmony_ci                            const SkPaint& paint,
310cb93a386Sopenharmony_ci                            const SkRect* rawBounds = nullptr)
311cb93a386Sopenharmony_ci            : fPaint(paint)
312cb93a386Sopenharmony_ci            , fCanvas(canvas)
313cb93a386Sopenharmony_ci            , fTempLayerForImageFilter(false) {
314cb93a386Sopenharmony_ci        SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_ci        if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) {
317cb93a386Sopenharmony_ci            // The draw paint has an image filter that couldn't be simplified to an equivalent
318cb93a386Sopenharmony_ci            // color filter, so we have to inject an automatic saveLayer().
319cb93a386Sopenharmony_ci            SkPaint restorePaint;
320cb93a386Sopenharmony_ci            restorePaint.setImageFilter(fPaint.refImageFilter());
321cb93a386Sopenharmony_ci            restorePaint.setBlender(fPaint.refBlender());
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci            // Remove the restorePaint fields from our "working" paint
324cb93a386Sopenharmony_ci            fPaint.setImageFilter(nullptr);
325cb93a386Sopenharmony_ci            fPaint.setBlendMode(SkBlendMode::kSrcOver);
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci            SkRect storage;
328cb93a386Sopenharmony_ci            if (rawBounds && fPaint.canComputeFastBounds()) {
329cb93a386Sopenharmony_ci                // Make rawBounds include all paint outsets except for those due to image filters.
330cb93a386Sopenharmony_ci                // At this point, fPaint's image filter has been moved to 'restorePaint'.
331cb93a386Sopenharmony_ci                SkASSERT(!fPaint.getImageFilter());
332cb93a386Sopenharmony_ci                rawBounds = &fPaint.computeFastBounds(*rawBounds, &storage);
333cb93a386Sopenharmony_ci            }
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci            (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
336cb93a386Sopenharmony_ci                                            SkCanvas::kFullLayer_SaveLayerStrategy);
337cb93a386Sopenharmony_ci            fTempLayerForImageFilter = true;
338cb93a386Sopenharmony_ci        }
339cb93a386Sopenharmony_ci    }
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    AutoLayerForImageFilter(const AutoLayerForImageFilter&) = delete;
342cb93a386Sopenharmony_ci    AutoLayerForImageFilter& operator=(const AutoLayerForImageFilter&) = delete;
343cb93a386Sopenharmony_ci    AutoLayerForImageFilter(AutoLayerForImageFilter&&) = default;
344cb93a386Sopenharmony_ci    AutoLayerForImageFilter& operator=(AutoLayerForImageFilter&&) = default;
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci    ~AutoLayerForImageFilter() {
347cb93a386Sopenharmony_ci        if (fTempLayerForImageFilter) {
348cb93a386Sopenharmony_ci            fCanvas->internalRestore();
349cb93a386Sopenharmony_ci        }
350cb93a386Sopenharmony_ci        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
351cb93a386Sopenharmony_ci    }
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci    const SkPaint& paint() const { return fPaint; }
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ciprivate:
356cb93a386Sopenharmony_ci    SkPaint         fPaint;
357cb93a386Sopenharmony_ci    SkCanvas*       fCanvas;
358cb93a386Sopenharmony_ci    bool            fTempLayerForImageFilter;
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_ci    SkDEBUGCODE(int fSaveCount;)
361cb93a386Sopenharmony_ci};
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ciskstd::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw(
364cb93a386Sopenharmony_ci    SkCanvas* canvas,
365cb93a386Sopenharmony_ci    const SkPaint& paint,
366cb93a386Sopenharmony_ci    const SkRect* rawBounds,
367cb93a386Sopenharmony_ci    CheckForOverwrite checkOverwrite,
368cb93a386Sopenharmony_ci    ShaderOverrideOpacity overrideOpacity)
369cb93a386Sopenharmony_ci{
370cb93a386Sopenharmony_ci    if (checkOverwrite == CheckForOverwrite::kYes) {
371cb93a386Sopenharmony_ci        if (!this->predrawNotify(rawBounds, &paint, overrideOpacity)) {
372cb93a386Sopenharmony_ci            return skstd::nullopt;
373cb93a386Sopenharmony_ci        }
374cb93a386Sopenharmony_ci    } else {
375cb93a386Sopenharmony_ci        if (!this->predrawNotify()) {
376cb93a386Sopenharmony_ci            return skstd::nullopt;
377cb93a386Sopenharmony_ci        }
378cb93a386Sopenharmony_ci    }
379cb93a386Sopenharmony_ci    return skstd::optional<AutoLayerForImageFilter>(canvas, paint, rawBounds);
380cb93a386Sopenharmony_ci}
381cb93a386Sopenharmony_ci
382cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_civoid SkCanvas::resetForNextPicture(const SkIRect& bounds) {
385cb93a386Sopenharmony_ci    this->restoreToCount(1);
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ci    // We're peering through a lot of structs here.  Only at this scope do we
388cb93a386Sopenharmony_ci    // know that the device is a SkNoPixelsDevice.
389cb93a386Sopenharmony_ci    SkASSERT(fBaseDevice->isNoPixelsDevice());
390cb93a386Sopenharmony_ci    static_cast<SkNoPixelsDevice*>(fBaseDevice.get())->resetForNextPicture(bounds);
391cb93a386Sopenharmony_ci    fMCRec->reset(fBaseDevice.get());
392cb93a386Sopenharmony_ci    fQuickRejectBounds = this->computeDeviceClipBounds();
393cb93a386Sopenharmony_ci}
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_civoid SkCanvas::init(sk_sp<SkBaseDevice> device) {
396cb93a386Sopenharmony_ci    // SkCanvas.h declares internal storage for the hidden struct MCRec, and this
397cb93a386Sopenharmony_ci    // assert ensure it's sufficient. <= is used because the struct has pointer fields, so the
398cb93a386Sopenharmony_ci    // declared size is an upper bound across architectures. When the size is smaller, more stack
399cb93a386Sopenharmony_ci    static_assert(sizeof(MCRec) <= kMCRecSize);
400cb93a386Sopenharmony_ci
401cb93a386Sopenharmony_ci    if (!device) {
402cb93a386Sopenharmony_ci        device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps);
403cb93a386Sopenharmony_ci    }
404cb93a386Sopenharmony_ci
405cb93a386Sopenharmony_ci    // From this point on, SkCanvas will always have a device
406cb93a386Sopenharmony_ci    SkASSERT(device);
407cb93a386Sopenharmony_ci
408cb93a386Sopenharmony_ci    fSaveCount = 1;
409cb93a386Sopenharmony_ci    fMCRec = new (fMCStack.push_back()) MCRec(device.get());
410cb93a386Sopenharmony_ci    fMarkerStack = sk_make_sp<SkMarkerStack>();
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci    // The root device and the canvas should always have the same pixel geometry
413cb93a386Sopenharmony_ci    SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
414cb93a386Sopenharmony_ci    device->setMarkerStack(fMarkerStack.get());
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci    fSurfaceBase = nullptr;
417cb93a386Sopenharmony_ci    fBaseDevice = std::move(device);
418cb93a386Sopenharmony_ci    fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>();
419cb93a386Sopenharmony_ci    fQuickRejectBounds = this->computeDeviceClipBounds();
420cb93a386Sopenharmony_ci}
421cb93a386Sopenharmony_ci
422cb93a386Sopenharmony_ciSkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
423cb93a386Sopenharmony_ci    inc_canvas();
424cb93a386Sopenharmony_ci    this->init(nullptr);
425cb93a386Sopenharmony_ci}
426cb93a386Sopenharmony_ci
427cb93a386Sopenharmony_ciSkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
428cb93a386Sopenharmony_ci        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
429cb93a386Sopenharmony_ci        , fProps(SkSurfacePropsCopyOrDefault(props)) {
430cb93a386Sopenharmony_ci    inc_canvas();
431cb93a386Sopenharmony_ci    this->init(sk_make_sp<SkNoPixelsDevice>(
432cb93a386Sopenharmony_ci            SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps));
433cb93a386Sopenharmony_ci}
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkIRect& bounds)
436cb93a386Sopenharmony_ci        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
437cb93a386Sopenharmony_ci    inc_canvas();
438cb93a386Sopenharmony_ci
439cb93a386Sopenharmony_ci    SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
440cb93a386Sopenharmony_ci    this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
441cb93a386Sopenharmony_ci}
442cb93a386Sopenharmony_ci
443cb93a386Sopenharmony_ciSkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
444cb93a386Sopenharmony_ci        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
445cb93a386Sopenharmony_ci        , fProps(device->surfaceProps()) {
446cb93a386Sopenharmony_ci    inc_canvas();
447cb93a386Sopenharmony_ci
448cb93a386Sopenharmony_ci    this->init(device);
449cb93a386Sopenharmony_ci}
450cb93a386Sopenharmony_ci
451cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
452cb93a386Sopenharmony_ci        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(props) {
453cb93a386Sopenharmony_ci    inc_canvas();
454cb93a386Sopenharmony_ci
455cb93a386Sopenharmony_ci    sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
456cb93a386Sopenharmony_ci    this->init(device);
457cb93a386Sopenharmony_ci}
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap,
460cb93a386Sopenharmony_ci                   std::unique_ptr<SkRasterHandleAllocator> alloc,
461cb93a386Sopenharmony_ci                   SkRasterHandleAllocator::Handle hndl)
462cb93a386Sopenharmony_ci        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
463cb93a386Sopenharmony_ci        , fAllocator(std::move(alloc)) {
464cb93a386Sopenharmony_ci    inc_canvas();
465cb93a386Sopenharmony_ci
466cb93a386Sopenharmony_ci    sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
467cb93a386Sopenharmony_ci    this->init(device);
468cb93a386Sopenharmony_ci}
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
471cb93a386Sopenharmony_ci
472cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
473cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
474cb93a386Sopenharmony_ci        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
475cb93a386Sopenharmony_ci    inc_canvas();
476cb93a386Sopenharmony_ci
477cb93a386Sopenharmony_ci    SkBitmap tmp(bitmap);
478cb93a386Sopenharmony_ci    *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
479cb93a386Sopenharmony_ci    sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
480cb93a386Sopenharmony_ci    this->init(device);
481cb93a386Sopenharmony_ci}
482cb93a386Sopenharmony_ci#endif
483cb93a386Sopenharmony_ci
484cb93a386Sopenharmony_ciSkCanvas::~SkCanvas() {
485cb93a386Sopenharmony_ci    // Mark all pending layers to be discarded during restore (rather than drawn)
486cb93a386Sopenharmony_ci    SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
487cb93a386Sopenharmony_ci    for (;;) {
488cb93a386Sopenharmony_ci        MCRec* rec = (MCRec*)iter.next();
489cb93a386Sopenharmony_ci        if (!rec) {
490cb93a386Sopenharmony_ci            break;
491cb93a386Sopenharmony_ci        }
492cb93a386Sopenharmony_ci        if (rec->fLayer) {
493cb93a386Sopenharmony_ci            rec->fLayer->fDiscard = true;
494cb93a386Sopenharmony_ci        }
495cb93a386Sopenharmony_ci    }
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci    // free up the contents of our deque
498cb93a386Sopenharmony_ci    this->restoreToCount(1);    // restore everything but the last
499cb93a386Sopenharmony_ci    this->internalRestore();    // restore the last, since we're going away
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_ci    dec_canvas();
502cb93a386Sopenharmony_ci}
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_civoid SkCanvas::flush() {
507cb93a386Sopenharmony_ci    this->onFlush();
508cb93a386Sopenharmony_ci}
509cb93a386Sopenharmony_ci
510cb93a386Sopenharmony_civoid SkCanvas::onFlush() {
511cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU
512cb93a386Sopenharmony_ci    auto dContext = GrAsDirectContext(this->recordingContext());
513cb93a386Sopenharmony_ci
514cb93a386Sopenharmony_ci    if (dContext) {
515cb93a386Sopenharmony_ci        dContext->flushAndSubmit();
516cb93a386Sopenharmony_ci    }
517cb93a386Sopenharmony_ci#endif
518cb93a386Sopenharmony_ci}
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ciSkSurface* SkCanvas::getSurface() const {
521cb93a386Sopenharmony_ci    return fSurfaceBase;
522cb93a386Sopenharmony_ci}
523cb93a386Sopenharmony_ci
524cb93a386Sopenharmony_ciSkISize SkCanvas::getBaseLayerSize() const {
525cb93a386Sopenharmony_ci    return this->baseDevice()->imageInfo().dimensions();
526cb93a386Sopenharmony_ci}
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ciSkBaseDevice* SkCanvas::topDevice() const {
529cb93a386Sopenharmony_ci    SkASSERT(fMCRec->fDevice);
530cb93a386Sopenharmony_ci    return fMCRec->fDevice;
531cb93a386Sopenharmony_ci}
532cb93a386Sopenharmony_ci
533cb93a386Sopenharmony_cibool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
534cb93a386Sopenharmony_ci    return pm.addr() && this->baseDevice()->readPixels(pm, x, y);
535cb93a386Sopenharmony_ci}
536cb93a386Sopenharmony_ci
537cb93a386Sopenharmony_cibool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
538cb93a386Sopenharmony_ci    return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
539cb93a386Sopenharmony_ci}
540cb93a386Sopenharmony_ci
541cb93a386Sopenharmony_cibool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
542cb93a386Sopenharmony_ci    SkPixmap pm;
543cb93a386Sopenharmony_ci    return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
544cb93a386Sopenharmony_ci}
545cb93a386Sopenharmony_ci
546cb93a386Sopenharmony_cibool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
547cb93a386Sopenharmony_ci    SkPixmap pm;
548cb93a386Sopenharmony_ci    if (bitmap.peekPixels(&pm)) {
549cb93a386Sopenharmony_ci        return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
550cb93a386Sopenharmony_ci    }
551cb93a386Sopenharmony_ci    return false;
552cb93a386Sopenharmony_ci}
553cb93a386Sopenharmony_ci
554cb93a386Sopenharmony_cibool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
555cb93a386Sopenharmony_ci                           int x, int y) {
556cb93a386Sopenharmony_ci    SkBaseDevice* device = this->baseDevice();
557cb93a386Sopenharmony_ci
558cb93a386Sopenharmony_ci    // This check gives us an early out and prevents generation ID churn on the surface.
559cb93a386Sopenharmony_ci    // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
560cb93a386Sopenharmony_ci    SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
561cb93a386Sopenharmony_ci    if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
562cb93a386Sopenharmony_ci        return false;
563cb93a386Sopenharmony_ci    }
564cb93a386Sopenharmony_ci
565cb93a386Sopenharmony_ci    // Tell our owning surface to bump its generation ID.
566cb93a386Sopenharmony_ci    const bool completeOverwrite = srcRect.size() == device->imageInfo().dimensions();
567cb93a386Sopenharmony_ci    if (!this->predrawNotify(completeOverwrite)) {
568cb93a386Sopenharmony_ci        return false;
569cb93a386Sopenharmony_ci    }
570cb93a386Sopenharmony_ci
571cb93a386Sopenharmony_ci    // This can still fail, most notably in the case of a invalid color type or alpha type
572cb93a386Sopenharmony_ci    // conversion.  We could pull those checks into this function and avoid the unnecessary
573cb93a386Sopenharmony_ci    // generation ID bump.  But then we would be performing those checks twice, since they
574cb93a386Sopenharmony_ci    // are also necessary at the bitmap/pixmap entry points.
575cb93a386Sopenharmony_ci    return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
576cb93a386Sopenharmony_ci}
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
579cb93a386Sopenharmony_ci
580cb93a386Sopenharmony_civoid SkCanvas::checkForDeferredSave() {
581cb93a386Sopenharmony_ci    if (fMCRec->fDeferredSaveCount > 0) {
582cb93a386Sopenharmony_ci        this->doSave();
583cb93a386Sopenharmony_ci    }
584cb93a386Sopenharmony_ci}
585cb93a386Sopenharmony_ci
586cb93a386Sopenharmony_ciint SkCanvas::getSaveCount() const {
587cb93a386Sopenharmony_ci#ifdef SK_DEBUG
588cb93a386Sopenharmony_ci    int count = 0;
589cb93a386Sopenharmony_ci    SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
590cb93a386Sopenharmony_ci    for (;;) {
591cb93a386Sopenharmony_ci        const MCRec* rec = (const MCRec*)iter.next();
592cb93a386Sopenharmony_ci        if (!rec) {
593cb93a386Sopenharmony_ci            break;
594cb93a386Sopenharmony_ci        }
595cb93a386Sopenharmony_ci        count += 1 + rec->fDeferredSaveCount;
596cb93a386Sopenharmony_ci    }
597cb93a386Sopenharmony_ci    SkASSERT(count == fSaveCount);
598cb93a386Sopenharmony_ci#endif
599cb93a386Sopenharmony_ci    return fSaveCount;
600cb93a386Sopenharmony_ci}
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ciint SkCanvas::save() {
603cb93a386Sopenharmony_ci    fSaveCount += 1;
604cb93a386Sopenharmony_ci    fMCRec->fDeferredSaveCount += 1;
605cb93a386Sopenharmony_ci    return this->getSaveCount() - 1;  // return our prev value
606cb93a386Sopenharmony_ci}
607cb93a386Sopenharmony_ci
608cb93a386Sopenharmony_civoid SkCanvas::doSave() {
609cb93a386Sopenharmony_ci    this->willSave();
610cb93a386Sopenharmony_ci
611cb93a386Sopenharmony_ci    SkASSERT(fMCRec->fDeferredSaveCount > 0);
612cb93a386Sopenharmony_ci    fMCRec->fDeferredSaveCount -= 1;
613cb93a386Sopenharmony_ci    this->internalSave();
614cb93a386Sopenharmony_ci}
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_civoid SkCanvas::restore() {
617cb93a386Sopenharmony_ci    if (fMCRec->fDeferredSaveCount > 0) {
618cb93a386Sopenharmony_ci        SkASSERT(fSaveCount > 1);
619cb93a386Sopenharmony_ci        fSaveCount -= 1;
620cb93a386Sopenharmony_ci        fMCRec->fDeferredSaveCount -= 1;
621cb93a386Sopenharmony_ci    } else {
622cb93a386Sopenharmony_ci        // check for underflow
623cb93a386Sopenharmony_ci        if (fMCStack.count() > 1) {
624cb93a386Sopenharmony_ci            this->willRestore();
625cb93a386Sopenharmony_ci            SkASSERT(fSaveCount > 1);
626cb93a386Sopenharmony_ci            fSaveCount -= 1;
627cb93a386Sopenharmony_ci            this->internalRestore();
628cb93a386Sopenharmony_ci            this->didRestore();
629cb93a386Sopenharmony_ci        }
630cb93a386Sopenharmony_ci    }
631cb93a386Sopenharmony_ci}
632cb93a386Sopenharmony_ci
633cb93a386Sopenharmony_civoid SkCanvas::restoreToCount(int count) {
634cb93a386Sopenharmony_ci    // safety check
635cb93a386Sopenharmony_ci    if (count < 1) {
636cb93a386Sopenharmony_ci        count = 1;
637cb93a386Sopenharmony_ci    }
638cb93a386Sopenharmony_ci
639cb93a386Sopenharmony_ci    int n = this->getSaveCount() - count;
640cb93a386Sopenharmony_ci    for (int i = 0; i < n; ++i) {
641cb93a386Sopenharmony_ci        this->restore();
642cb93a386Sopenharmony_ci    }
643cb93a386Sopenharmony_ci}
644cb93a386Sopenharmony_ci
645cb93a386Sopenharmony_civoid SkCanvas::internalSave() {
646cb93a386Sopenharmony_ci    fMCRec = new (fMCStack.push_back()) MCRec(fMCRec);
647cb93a386Sopenharmony_ci
648cb93a386Sopenharmony_ci    this->topDevice()->save();
649cb93a386Sopenharmony_ci}
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ciint SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
652cb93a386Sopenharmony_ci    return this->saveLayer(SaveLayerRec(bounds, paint, 0));
653cb93a386Sopenharmony_ci}
654cb93a386Sopenharmony_ci
655cb93a386Sopenharmony_ciint SkCanvas::saveLayer(const SaveLayerRec& rec) {
656cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
657cb93a386Sopenharmony_ci    if (rec.fPaint && rec.fPaint->nothingToDraw()) {
658cb93a386Sopenharmony_ci        // no need for the layer (or any of the draws until the matching restore()
659cb93a386Sopenharmony_ci        this->save();
660cb93a386Sopenharmony_ci        this->clipRect({0,0,0,0});
661cb93a386Sopenharmony_ci    } else {
662cb93a386Sopenharmony_ci        SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
663cb93a386Sopenharmony_ci        fSaveCount += 1;
664cb93a386Sopenharmony_ci        this->internalSaveLayer(rec, strategy);
665cb93a386Sopenharmony_ci    }
666cb93a386Sopenharmony_ci    return this->getSaveCount() - 1;
667cb93a386Sopenharmony_ci}
668cb93a386Sopenharmony_ci
669cb93a386Sopenharmony_ciint SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
670cb93a386Sopenharmony_ci    if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
671cb93a386Sopenharmony_ci        // Assuming clips never expand, if the request bounds is outside of the current clip
672cb93a386Sopenharmony_ci        // there is no need to copy/restore the area, so just devolve back to a regular save.
673cb93a386Sopenharmony_ci        this->save();
674cb93a386Sopenharmony_ci    } else {
675cb93a386Sopenharmony_ci        bool doTheWork = this->onDoSaveBehind(bounds);
676cb93a386Sopenharmony_ci        fSaveCount += 1;
677cb93a386Sopenharmony_ci        this->internalSave();
678cb93a386Sopenharmony_ci        if (doTheWork) {
679cb93a386Sopenharmony_ci            this->internalSaveBehind(bounds);
680cb93a386Sopenharmony_ci        }
681cb93a386Sopenharmony_ci    }
682cb93a386Sopenharmony_ci    return this->getSaveCount() - 1;
683cb93a386Sopenharmony_ci}
684cb93a386Sopenharmony_ci
685cb93a386Sopenharmony_ci// In our current design/features, we should never have a layer (src) in a different colorspace
686cb93a386Sopenharmony_ci// than its parent (dst), so we assert that here. This is called out from other asserts, in case
687cb93a386Sopenharmony_ci// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
688cb93a386Sopenharmony_ci// colorspace.
689cb93a386Sopenharmony_cistatic void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
690cb93a386Sopenharmony_ci    SkASSERT(src == dst);
691cb93a386Sopenharmony_ci}
692cb93a386Sopenharmony_ci
693cb93a386Sopenharmony_ci// Helper function to compute the center reference point used for scale decomposition under
694cb93a386Sopenharmony_ci// non-linear transformations.
695cb93a386Sopenharmony_cistatic skif::ParameterSpace<SkPoint> compute_decomposition_center(
696cb93a386Sopenharmony_ci        const SkMatrix& dstToLocal,
697cb93a386Sopenharmony_ci        const skif::ParameterSpace<SkRect>* contentBounds,
698cb93a386Sopenharmony_ci        const skif::DeviceSpace<SkIRect>& targetOutput) {
699cb93a386Sopenharmony_ci    // Will use the inverse and center of the device bounds if the content bounds aren't provided.
700cb93a386Sopenharmony_ci    SkRect rect = contentBounds ? SkRect(*contentBounds) : SkRect::Make(SkIRect(targetOutput));
701cb93a386Sopenharmony_ci    SkPoint center = {rect.centerX(), rect.centerY()};
702cb93a386Sopenharmony_ci    if (!contentBounds) {
703cb93a386Sopenharmony_ci        // Theoretically, the inverse transform could put center's homogeneous coord behind W = 0,
704cb93a386Sopenharmony_ci        // but that case is handled automatically in Mapping::decomposeCTM later.
705cb93a386Sopenharmony_ci        dstToLocal.mapPoints(&center, 1);
706cb93a386Sopenharmony_ci    }
707cb93a386Sopenharmony_ci
708cb93a386Sopenharmony_ci    return skif::ParameterSpace<SkPoint>(center);
709cb93a386Sopenharmony_ci}
710cb93a386Sopenharmony_ci
711cb93a386Sopenharmony_ci// Compute suitable transformations and layer bounds for a new layer that will be used as the source
712cb93a386Sopenharmony_ci// input into 'filter'  before being drawn into 'dst' via the returned skif::Mapping.
713cb93a386Sopenharmony_ci// Null filters are permitted and act as the identity. The returned mapping will be compatible with
714cb93a386Sopenharmony_ci// the image filter.
715cb93a386Sopenharmony_ci//
716cb93a386Sopenharmony_ci// Returns an empty rect if the layer wouldn't draw anything after filtering.
717cb93a386Sopenharmony_cistatic std::pair<skif::Mapping, skif::LayerSpace<SkIRect>> get_layer_mapping_and_bounds(
718cb93a386Sopenharmony_ci        const SkImageFilter* filter,
719cb93a386Sopenharmony_ci        const SkMatrix& localToDst,
720cb93a386Sopenharmony_ci        const skif::DeviceSpace<SkIRect>& targetOutput,
721cb93a386Sopenharmony_ci        const skif::ParameterSpace<SkRect>* contentBounds = nullptr,
722cb93a386Sopenharmony_ci        bool mustCoverDst = true,
723cb93a386Sopenharmony_ci        SkScalar scaleFactor = 1.0f) {
724cb93a386Sopenharmony_ci    auto failedMapping = []() {
725cb93a386Sopenharmony_ci        return std::make_pair<skif::Mapping, skif::LayerSpace<SkIRect>>(
726cb93a386Sopenharmony_ci                {}, skif::LayerSpace<SkIRect>::Empty());
727cb93a386Sopenharmony_ci    };
728cb93a386Sopenharmony_ci
729cb93a386Sopenharmony_ci    SkMatrix dstToLocal;
730cb93a386Sopenharmony_ci    if (!localToDst.isFinite() ||
731cb93a386Sopenharmony_ci        !localToDst.invert(&dstToLocal)) {
732cb93a386Sopenharmony_ci        return failedMapping();
733cb93a386Sopenharmony_ci    }
734cb93a386Sopenharmony_ci
735cb93a386Sopenharmony_ci    skif::ParameterSpace<SkPoint> center =
736cb93a386Sopenharmony_ci            compute_decomposition_center(dstToLocal, contentBounds, targetOutput);
737cb93a386Sopenharmony_ci    // *after* possibly getting a representative point from the provided content bounds, it might
738cb93a386Sopenharmony_ci    // be necessary to discard the bounds for subsequent layer calculations.
739cb93a386Sopenharmony_ci    if (mustCoverDst) {
740cb93a386Sopenharmony_ci        contentBounds = nullptr;
741cb93a386Sopenharmony_ci    }
742cb93a386Sopenharmony_ci
743cb93a386Sopenharmony_ci    // Determine initial mapping and a reasonable maximum dimension to prevent layer-to-device
744cb93a386Sopenharmony_ci    // transforms with perspective and skew from triggering excessive buffer allocations.
745cb93a386Sopenharmony_ci    skif::Mapping mapping;
746cb93a386Sopenharmony_ci    if (!mapping.decomposeCTM(localToDst, filter, center)) {
747cb93a386Sopenharmony_ci        return failedMapping();
748cb93a386Sopenharmony_ci    }
749cb93a386Sopenharmony_ci    // Push scale factor into layer matrix and device matrix (net no change, but the layer will have
750cb93a386Sopenharmony_ci    // its resolution adjusted in comparison to the final device).
751cb93a386Sopenharmony_ci    if (scaleFactor != 1.0f &&
752cb93a386Sopenharmony_ci        !mapping.adjustLayerSpace(SkMatrix::Scale(scaleFactor, scaleFactor))) {
753cb93a386Sopenharmony_ci        return failedMapping();
754cb93a386Sopenharmony_ci    }
755cb93a386Sopenharmony_ci
756cb93a386Sopenharmony_ci    // Perspective and skew could exceed this since mapping.deviceToLayer(targetOutput) is
757cb93a386Sopenharmony_ci    // theoretically unbounded under those conditions. Under a 45 degree rotation, a layer needs to
758cb93a386Sopenharmony_ci    // be 2X larger per side of the prior device in order to fully cover it. We use the max of that
759cb93a386Sopenharmony_ci    // and 2048 for a reasonable upper limit (this allows small layers under extreme transforms to
760cb93a386Sopenharmony_ci    // use more relative resolution than a larger layer).
761cb93a386Sopenharmony_ci    static const int kMinDimThreshold = 2048;
762cb93a386Sopenharmony_ci    int maxLayerDim = std::max(Sk64_pin_to_s32(2 * std::max(SkIRect(targetOutput).width64(),
763cb93a386Sopenharmony_ci                                                            SkIRect(targetOutput).height64())),
764cb93a386Sopenharmony_ci                               kMinDimThreshold);
765cb93a386Sopenharmony_ci
766cb93a386Sopenharmony_ci    skif::LayerSpace<SkIRect> layerBounds;
767cb93a386Sopenharmony_ci    if (filter) {
768cb93a386Sopenharmony_ci        layerBounds = as_IFB(filter)->getInputBounds(mapping, targetOutput, contentBounds);
769cb93a386Sopenharmony_ci        // When a filter is involved, the layer size may be larger than the default maxLayerDim due
770cb93a386Sopenharmony_ci        // to required inputs for filters (e.g. a displacement map with a large radius).
771cb93a386Sopenharmony_ci        if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) {
772cb93a386Sopenharmony_ci            skif::Mapping idealMapping(SkMatrix::I(), mapping.layerMatrix());
773cb93a386Sopenharmony_ci            auto idealLayerBounds = as_IFB(filter)->getInputBounds(idealMapping, targetOutput,
774cb93a386Sopenharmony_ci                                                                   contentBounds);
775cb93a386Sopenharmony_ci            maxLayerDim = std::max(std::max(idealLayerBounds.width(), idealLayerBounds.height()),
776cb93a386Sopenharmony_ci                                   maxLayerDim);
777cb93a386Sopenharmony_ci        }
778cb93a386Sopenharmony_ci    } else {
779cb93a386Sopenharmony_ci        layerBounds = mapping.deviceToLayer(targetOutput);
780cb93a386Sopenharmony_ci        if (contentBounds) {
781cb93a386Sopenharmony_ci            // For better or for worse, user bounds currently act as a hard clip on the layer's
782cb93a386Sopenharmony_ci            // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
783cb93a386Sopenharmony_ci            skif::LayerSpace<SkIRect> knownBounds = mapping.paramToLayer(*contentBounds).roundOut();
784cb93a386Sopenharmony_ci            if (!layerBounds.intersect(knownBounds)) {
785cb93a386Sopenharmony_ci                return failedMapping();
786cb93a386Sopenharmony_ci            }
787cb93a386Sopenharmony_ci        }
788cb93a386Sopenharmony_ci    }
789cb93a386Sopenharmony_ci
790cb93a386Sopenharmony_ci    if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) {
791cb93a386Sopenharmony_ci        skif::LayerSpace<SkIRect> newLayerBounds(
792cb93a386Sopenharmony_ci                SkIRect::MakeWH(std::min(layerBounds.width(), maxLayerDim),
793cb93a386Sopenharmony_ci                                std::min(layerBounds.height(), maxLayerDim)));
794cb93a386Sopenharmony_ci        SkMatrix adjust = SkMatrix::MakeRectToRect(SkRect::Make(SkIRect(layerBounds)),
795cb93a386Sopenharmony_ci                                                   SkRect::Make(SkIRect(newLayerBounds)),
796cb93a386Sopenharmony_ci                                                   SkMatrix::kFill_ScaleToFit);
797cb93a386Sopenharmony_ci        if (!mapping.adjustLayerSpace(adjust)) {
798cb93a386Sopenharmony_ci            return failedMapping();
799cb93a386Sopenharmony_ci        } else {
800cb93a386Sopenharmony_ci            layerBounds = newLayerBounds;
801cb93a386Sopenharmony_ci        }
802cb93a386Sopenharmony_ci    }
803cb93a386Sopenharmony_ci
804cb93a386Sopenharmony_ci    return {mapping, layerBounds};
805cb93a386Sopenharmony_ci}
806cb93a386Sopenharmony_ci
807cb93a386Sopenharmony_cistatic SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool f16) {
808cb93a386Sopenharmony_ci    SkColorType ct = f16 ? SkColorType::kRGBA_F16_SkColorType : prev.colorType();
809cb93a386Sopenharmony_ci    if (!f16 &&
810cb93a386Sopenharmony_ci        prev.bytesPerPixel() <= 4 &&
811cb93a386Sopenharmony_ci        prev.colorType() != kRGBA_8888_SkColorType &&
812cb93a386Sopenharmony_ci        prev.colorType() != kBGRA_8888_SkColorType) {
813cb93a386Sopenharmony_ci        // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
814cb93a386Sopenharmony_ci        // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
815cb93a386Sopenharmony_ci        ct = kN32_SkColorType;
816cb93a386Sopenharmony_ci    }
817cb93a386Sopenharmony_ci    return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
818cb93a386Sopenharmony_ci}
819cb93a386Sopenharmony_ci
820cb93a386Sopenharmony_cistatic bool draw_layer_as_sprite(const SkMatrix& matrix, const SkISize& size) {
821cb93a386Sopenharmony_ci    // Assume anti-aliasing and highest valid filter mode (linear) for drawing layers and image
822cb93a386Sopenharmony_ci    // filters. If the layer can be drawn as a sprite, these can be downgraded.
823cb93a386Sopenharmony_ci    SkPaint paint;
824cb93a386Sopenharmony_ci    paint.setAntiAlias(true);
825cb93a386Sopenharmony_ci    SkSamplingOptions sampling{SkFilterMode::kLinear};
826cb93a386Sopenharmony_ci    return SkTreatAsSprite(matrix, size, sampling, paint);
827cb93a386Sopenharmony_ci}
828cb93a386Sopenharmony_ci
829cb93a386Sopenharmony_civoid SkCanvas::internalDrawDeviceWithFilter(SkBaseDevice* src,
830cb93a386Sopenharmony_ci                                            SkBaseDevice* dst,
831cb93a386Sopenharmony_ci                                            const SkImageFilter* filter,
832cb93a386Sopenharmony_ci                                            const SkPaint& paint,
833cb93a386Sopenharmony_ci                                            DeviceCompatibleWithFilter compat,
834cb93a386Sopenharmony_ci                                            SkScalar scaleFactor) {
835cb93a386Sopenharmony_ci    check_drawdevice_colorspaces(dst->imageInfo().colorSpace(),
836cb93a386Sopenharmony_ci                                 src->imageInfo().colorSpace());
837cb93a386Sopenharmony_ci
838cb93a386Sopenharmony_ci    // 'filter' sees the src device's buffer as the implicit input image, and processes the image
839cb93a386Sopenharmony_ci    // in this device space (referred to as the "layer" space). However, the filter
840cb93a386Sopenharmony_ci    // parameters need to respect the current matrix, which is not necessarily the local matrix that
841cb93a386Sopenharmony_ci    // was set on 'src' (e.g. because we've popped src off the stack already).
842cb93a386Sopenharmony_ci    // TODO (michaelludwig): Stay in SkM44 once skif::Mapping supports SkM44 instead of SkMatrix.
843cb93a386Sopenharmony_ci    SkMatrix localToSrc = (src->globalToDevice() * fMCRec->fMatrix).asM33();
844cb93a386Sopenharmony_ci    SkISize srcDims = src->imageInfo().dimensions();
845cb93a386Sopenharmony_ci
846cb93a386Sopenharmony_ci    // Whether or not we need to make a transformed tmp image from 'src', and what that transform is
847cb93a386Sopenharmony_ci    bool needsIntermediateImage = false;
848cb93a386Sopenharmony_ci    SkMatrix srcToIntermediate;
849cb93a386Sopenharmony_ci
850cb93a386Sopenharmony_ci    skif::Mapping mapping;
851cb93a386Sopenharmony_ci    skif::LayerSpace<SkIRect> requiredInput;
852cb93a386Sopenharmony_ci    if (compat == DeviceCompatibleWithFilter::kYes) {
853cb93a386Sopenharmony_ci        // Just use the relative transform from src to dst and the src's whole image, since
854cb93a386Sopenharmony_ci        // internalSaveLayer should have already determined what was necessary.
855cb93a386Sopenharmony_ci        SkASSERT(scaleFactor == 1.0f);
856cb93a386Sopenharmony_ci        mapping = skif::Mapping(src->getRelativeTransform(*dst), localToSrc);
857cb93a386Sopenharmony_ci        requiredInput = skif::LayerSpace<SkIRect>(SkIRect::MakeSize(srcDims));
858cb93a386Sopenharmony_ci        SkASSERT(!requiredInput.isEmpty());
859cb93a386Sopenharmony_ci    } else {
860cb93a386Sopenharmony_ci        // Compute the image filter mapping by decomposing the local->device matrix of dst and
861cb93a386Sopenharmony_ci        // re-determining the required input.
862cb93a386Sopenharmony_ci        std::tie(mapping, requiredInput) = get_layer_mapping_and_bounds(
863cb93a386Sopenharmony_ci                filter, dst->localToDevice(), skif::DeviceSpace<SkIRect>(dst->devClipBounds()),
864cb93a386Sopenharmony_ci                nullptr, true, SkTPin(scaleFactor, 0.f, 1.f));
865cb93a386Sopenharmony_ci        if (requiredInput.isEmpty()) {
866cb93a386Sopenharmony_ci            return;
867cb93a386Sopenharmony_ci        }
868cb93a386Sopenharmony_ci
869cb93a386Sopenharmony_ci        // The above mapping transforms from local to dst's device space, where the layer space
870cb93a386Sopenharmony_ci        // represents the intermediate buffer. Now we need to determine the transform from src to
871cb93a386Sopenharmony_ci        // intermediate to prepare the input to the filter.
872cb93a386Sopenharmony_ci        if (!localToSrc.invert(&srcToIntermediate)) {
873cb93a386Sopenharmony_ci            return;
874cb93a386Sopenharmony_ci        }
875cb93a386Sopenharmony_ci        srcToIntermediate.postConcat(mapping.layerMatrix());
876cb93a386Sopenharmony_ci        if (draw_layer_as_sprite(srcToIntermediate, srcDims)) {
877cb93a386Sopenharmony_ci            // src differs from intermediate by just an integer translation, so it can be applied
878cb93a386Sopenharmony_ci            // automatically when taking a subset of src if we update the mapping.
879cb93a386Sopenharmony_ci            skif::LayerSpace<SkIPoint> srcOrigin({(int) srcToIntermediate.getTranslateX(),
880cb93a386Sopenharmony_ci                                                  (int) srcToIntermediate.getTranslateY()});
881cb93a386Sopenharmony_ci            mapping.applyOrigin(srcOrigin);
882cb93a386Sopenharmony_ci            requiredInput.offset(-srcOrigin);
883cb93a386Sopenharmony_ci        } else {
884cb93a386Sopenharmony_ci            // The contents of 'src' will be drawn to an intermediate buffer using srcToIntermediate
885cb93a386Sopenharmony_ci            // and that buffer will be the input to the image filter.
886cb93a386Sopenharmony_ci            needsIntermediateImage = true;
887cb93a386Sopenharmony_ci        }
888cb93a386Sopenharmony_ci    }
889cb93a386Sopenharmony_ci
890cb93a386Sopenharmony_ci    sk_sp<SkSpecialImage> filterInput;
891cb93a386Sopenharmony_ci    if (!needsIntermediateImage) {
892cb93a386Sopenharmony_ci        // The src device can be snapped directly
893cb93a386Sopenharmony_ci        skif::LayerSpace<SkIRect> srcSubset(SkIRect::MakeSize(srcDims));
894cb93a386Sopenharmony_ci        if (srcSubset.intersect(requiredInput)) {
895cb93a386Sopenharmony_ci            filterInput = src->snapSpecial(SkIRect(srcSubset));
896cb93a386Sopenharmony_ci
897cb93a386Sopenharmony_ci            // TODO: For now image filter input images need to have a (0,0) origin. The required
898cb93a386Sopenharmony_ci            // input's top left has been baked into srcSubset so we use that as the image origin.
899cb93a386Sopenharmony_ci            mapping.applyOrigin(srcSubset.topLeft());
900cb93a386Sopenharmony_ci        }
901cb93a386Sopenharmony_ci    } else {
902cb93a386Sopenharmony_ci        // We need to produce a temporary image that is equivalent to 'src' but transformed to
903cb93a386Sopenharmony_ci        // a coordinate space compatible with the image filter
904cb93a386Sopenharmony_ci
905cb93a386Sopenharmony_ci        // TODO: If the srcToIntermediate is scale+translate, can we use the framebuffer blit
906cb93a386Sopenharmony_ci        // extensions to handle doing the copy and scale at the same time?
907cb93a386Sopenharmony_ci
908cb93a386Sopenharmony_ci        SkASSERT(compat == DeviceCompatibleWithFilter::kUnknown);
909cb93a386Sopenharmony_ci        SkRect srcRect;
910cb93a386Sopenharmony_ci        if (!SkMatrixPriv::InverseMapRect(srcToIntermediate, &srcRect,
911cb93a386Sopenharmony_ci                                          SkRect::Make(SkIRect(requiredInput)))) {
912cb93a386Sopenharmony_ci            return;
913cb93a386Sopenharmony_ci        }
914cb93a386Sopenharmony_ci
915cb93a386Sopenharmony_ci        SkIRect srcSubset = srcRect.roundOut();
916cb93a386Sopenharmony_ci        sk_sp<SkSpecialImage> srcImage;
917cb93a386Sopenharmony_ci        if (srcSubset.intersect(SkIRect::MakeSize(srcDims)) &&
918cb93a386Sopenharmony_ci            (srcImage = src->snapSpecial(srcSubset))) {
919cb93a386Sopenharmony_ci            // Make a new surface and draw 'srcImage' into it with the srcToIntermediate transform
920cb93a386Sopenharmony_ci            // to produce the final input image for the filter
921cb93a386Sopenharmony_ci            SkBaseDevice::CreateInfo info(make_layer_info(src->imageInfo(), requiredInput.width(),
922cb93a386Sopenharmony_ci                                                          requiredInput.height(), false),
923cb93a386Sopenharmony_ci                                          SkPixelGeometry::kUnknown_SkPixelGeometry,
924cb93a386Sopenharmony_ci                                          SkBaseDevice::TileUsage::kNever_TileUsage,
925cb93a386Sopenharmony_ci                                          false, fAllocator.get());
926cb93a386Sopenharmony_ci            sk_sp<SkBaseDevice> intermediateDevice(src->onCreateDevice(info, &paint));
927cb93a386Sopenharmony_ci            if (!intermediateDevice) {
928cb93a386Sopenharmony_ci                return;
929cb93a386Sopenharmony_ci            }
930cb93a386Sopenharmony_ci            intermediateDevice->setOrigin(SkM44(srcToIntermediate),
931cb93a386Sopenharmony_ci                                          requiredInput.left(), requiredInput.top());
932cb93a386Sopenharmony_ci
933cb93a386Sopenharmony_ci            SkMatrix offsetLocalToDevice = intermediateDevice->localToDevice();
934cb93a386Sopenharmony_ci            offsetLocalToDevice.preTranslate(srcSubset.left(), srcSubset.top());
935cb93a386Sopenharmony_ci            // We draw with non-AA bilinear since we cover the destination but definitely don't have
936cb93a386Sopenharmony_ci            // a pixel-aligned transform.
937cb93a386Sopenharmony_ci            intermediateDevice->drawSpecial(srcImage.get(), offsetLocalToDevice,
938cb93a386Sopenharmony_ci                                            SkSamplingOptions{SkFilterMode::kLinear}, {});
939cb93a386Sopenharmony_ci            filterInput = intermediateDevice->snapSpecial();
940cb93a386Sopenharmony_ci
941cb93a386Sopenharmony_ci            // TODO: Like the non-intermediate case, we need to apply the image origin.
942cb93a386Sopenharmony_ci            mapping.applyOrigin(requiredInput.topLeft());
943cb93a386Sopenharmony_ci        }
944cb93a386Sopenharmony_ci    }
945cb93a386Sopenharmony_ci
946cb93a386Sopenharmony_ci    if (filterInput) {
947cb93a386Sopenharmony_ci        const bool use_nn = draw_layer_as_sprite(mapping.deviceMatrix(),
948cb93a386Sopenharmony_ci                                                 filterInput->subset().size());
949cb93a386Sopenharmony_ci        SkSamplingOptions sampling{use_nn ? SkFilterMode::kNearest : SkFilterMode::kLinear};
950cb93a386Sopenharmony_ci        if (filter) {
951cb93a386Sopenharmony_ci            dst->drawFilteredImage(mapping, filterInput.get(), filter, sampling, paint);
952cb93a386Sopenharmony_ci        } else {
953cb93a386Sopenharmony_ci            dst->drawSpecial(filterInput.get(), mapping.deviceMatrix(), sampling, paint);
954cb93a386Sopenharmony_ci        }
955cb93a386Sopenharmony_ci    }
956cb93a386Sopenharmony_ci}
957cb93a386Sopenharmony_ci
958cb93a386Sopenharmony_ci// This is similar to image_to_color_filter used by AutoLayerForImageFilter, but with key changes:
959cb93a386Sopenharmony_ci//  - image_to_color_filter requires the entire image filter DAG to be represented as a color filter
960cb93a386Sopenharmony_ci//    that does not affect transparent black (SkImageFilter::asAColorFilter)
961cb93a386Sopenharmony_ci//  - when that is met, the image filter's CF is composed around any CF that was on the draw's paint
962cb93a386Sopenharmony_ci//    since for a draw, the color filtering happens before any image filtering
963cb93a386Sopenharmony_ci//  - optimize_layer_filter only applies to the last node and does not care about transparent black
964cb93a386Sopenharmony_ci//    since a layer is being made regardless (SkImageFilter::isColorFilterNode)
965cb93a386Sopenharmony_ci//  - any extracted CF is composed inside the restore paint's CF because image filters are evaluated
966cb93a386Sopenharmony_ci//    before the color filter of a restore paint for layers.
967cb93a386Sopenharmony_ci//
968cb93a386Sopenharmony_ci// Assumes that 'filter', and thus its inputs, will remain owned by the caller. Modifies 'paint'
969cb93a386Sopenharmony_ci// to have the updated color filter and returns the image filter to evaluate on restore.
970cb93a386Sopenharmony_ci//
971cb93a386Sopenharmony_ci// FIXME: skbug.com/12083 - we modify 'coversDevice' here because for now, only the color filter
972cb93a386Sopenharmony_ci// produced from an image filter node is checked for affecting transparent black, even though it's
973cb93a386Sopenharmony_ci// better in the long run to have any CF that affects transparent black expand to the clip.
974cb93a386Sopenharmony_cistatic const SkImageFilter* optimize_layer_filter(const SkImageFilter* filter, SkPaint* paint,
975cb93a386Sopenharmony_ci                                                  bool* coversDevice=nullptr) {
976cb93a386Sopenharmony_ci    SkASSERT(paint);
977cb93a386Sopenharmony_ci    SkColorFilter* cf;
978cb93a386Sopenharmony_ci    if (filter && filter->isColorFilterNode(&cf)) {
979cb93a386Sopenharmony_ci        sk_sp<SkColorFilter> inner(cf);
980cb93a386Sopenharmony_ci        if (paint->getAlphaf() < 1.f) {
981cb93a386Sopenharmony_ci            // The paint's alpha is applied after the image filter but before the paint's color
982cb93a386Sopenharmony_ci            // filter. If there is transparency, we have to apply it between the two filters.
983cb93a386Sopenharmony_ci            // FIXME: The Blend CF should allow composing directly at construction.
984cb93a386Sopenharmony_ci            inner = SkColorFilters::Compose(
985cb93a386Sopenharmony_ci                    SkColorFilters::Blend(/* src */ paint->getColor(), SkBlendMode::kDstIn),
986cb93a386Sopenharmony_ci                                          /* dst */ std::move(inner));
987cb93a386Sopenharmony_ci            paint->setAlphaf(1.f);
988cb93a386Sopenharmony_ci        }
989cb93a386Sopenharmony_ci
990cb93a386Sopenharmony_ci        // Check if the once-wrapped color filter affects transparent black *before* we combine
991cb93a386Sopenharmony_ci        // it with any original color filter on the paint.
992cb93a386Sopenharmony_ci        if (coversDevice) {
993cb93a386Sopenharmony_ci            *coversDevice = as_CFB(inner)->affectsTransparentBlack();
994cb93a386Sopenharmony_ci        }
995cb93a386Sopenharmony_ci
996cb93a386Sopenharmony_ci        paint->setColorFilter(SkColorFilters::Compose(paint->refColorFilter(), std::move(inner)));
997cb93a386Sopenharmony_ci        SkASSERT(filter->countInputs() == 1);
998cb93a386Sopenharmony_ci        return filter->getInput(0);
999cb93a386Sopenharmony_ci    } else {
1000cb93a386Sopenharmony_ci        if (coversDevice) {
1001cb93a386Sopenharmony_ci            *coversDevice = false;
1002cb93a386Sopenharmony_ci        }
1003cb93a386Sopenharmony_ci        return filter;
1004cb93a386Sopenharmony_ci    }
1005cb93a386Sopenharmony_ci}
1006cb93a386Sopenharmony_ci
1007cb93a386Sopenharmony_ci// If there is a backdrop filter, or if the restore paint has a color filter that affects
1008cb93a386Sopenharmony_ci// transparent black, then the new layer must be sized such that it covers the entire device
1009cb93a386Sopenharmony_ci// clip bounds of the prior device (otherwise edges of the temporary layer would be visible).
1010cb93a386Sopenharmony_ci// See skbug.com/8783
1011cb93a386Sopenharmony_cistatic bool must_cover_prior_device(const SkImageFilter* backdrop,
1012cb93a386Sopenharmony_ci                                    const SkPaint& restorePaint) {
1013cb93a386Sopenharmony_ci    // FIXME(michaelludwig) - see skbug.com/12083, once clients do not depend on user bounds for
1014cb93a386Sopenharmony_ci    // clipping a layer visually, we can respect the fact that the color filter affects transparent
1015cb93a386Sopenharmony_ci    // black and should cover the device.
1016cb93a386Sopenharmony_ci    return SkToBool(backdrop); // ||
1017cb93a386Sopenharmony_ci           // (restorePaint.getColorFilter() &&
1018cb93a386Sopenharmony_ci           // as_CFB(restorePaint.getColorFilter())->affectsTransparentBlack());
1019cb93a386Sopenharmony_ci}
1020cb93a386Sopenharmony_ci
1021cb93a386Sopenharmony_civoid SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1022cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1023cb93a386Sopenharmony_ci    // Do this before we create the layer. We don't call the public save() since that would invoke a
1024cb93a386Sopenharmony_ci    // possibly overridden virtual.
1025cb93a386Sopenharmony_ci    this->internalSave();
1026cb93a386Sopenharmony_ci
1027cb93a386Sopenharmony_ci    if (this->isClipEmpty()) {
1028cb93a386Sopenharmony_ci        // Early out if the layer wouldn't draw anything
1029cb93a386Sopenharmony_ci        return;
1030cb93a386Sopenharmony_ci    }
1031cb93a386Sopenharmony_ci
1032cb93a386Sopenharmony_ci    // Build up the paint for restoring the layer, taking only the pieces of rec.fPaint that are
1033cb93a386Sopenharmony_ci    // relevant. Filtering is automatically chosen in internalDrawDeviceWithFilter based on the
1034cb93a386Sopenharmony_ci    // device's coordinate space.
1035cb93a386Sopenharmony_ci    SkPaint restorePaint(rec.fPaint ? *rec.fPaint : SkPaint());
1036cb93a386Sopenharmony_ci    restorePaint.setMaskFilter(nullptr);  // mask filters are ignored for saved layers
1037cb93a386Sopenharmony_ci    restorePaint.setImageFilter(nullptr); // the image filter is held separately
1038cb93a386Sopenharmony_ci    // Smooth non-axis-aligned layer edges; this automatically downgrades to non-AA for aligned
1039cb93a386Sopenharmony_ci    // layer restores. This is done to match legacy behavior where the post-applied MatrixTransform
1040cb93a386Sopenharmony_ci    // bilerp also smoothed cropped edges. See skbug.com/11252
1041cb93a386Sopenharmony_ci    restorePaint.setAntiAlias(true);
1042cb93a386Sopenharmony_ci
1043cb93a386Sopenharmony_ci    bool optimizedCFAffectsTransparent;
1044cb93a386Sopenharmony_ci    const SkImageFilter* filter = optimize_layer_filter(
1045cb93a386Sopenharmony_ci            rec.fPaint ? rec.fPaint->getImageFilter() : nullptr, &restorePaint,
1046cb93a386Sopenharmony_ci            &optimizedCFAffectsTransparent);
1047cb93a386Sopenharmony_ci
1048cb93a386Sopenharmony_ci    // Size the new layer relative to the prior device, which may already be aligned for filters.
1049cb93a386Sopenharmony_ci    SkBaseDevice* priorDevice = this->topDevice();
1050cb93a386Sopenharmony_ci    skif::Mapping newLayerMapping;
1051cb93a386Sopenharmony_ci    skif::LayerSpace<SkIRect> layerBounds;
1052cb93a386Sopenharmony_ci    std::tie(newLayerMapping, layerBounds) = get_layer_mapping_and_bounds(
1053cb93a386Sopenharmony_ci            filter, priorDevice->localToDevice(),
1054cb93a386Sopenharmony_ci            skif::DeviceSpace<SkIRect>(priorDevice->devClipBounds()),
1055cb93a386Sopenharmony_ci            skif::ParameterSpace<SkRect>::Optional(rec.fBounds),
1056cb93a386Sopenharmony_ci            must_cover_prior_device(rec.fBackdrop, restorePaint) || optimizedCFAffectsTransparent);
1057cb93a386Sopenharmony_ci
1058cb93a386Sopenharmony_ci    auto abortLayer = [this]() {
1059cb93a386Sopenharmony_ci        // The filtered content would not draw anything, or the new device space has an invalid
1060cb93a386Sopenharmony_ci        // coordinate system, in which case we mark the current top device as empty so that nothing
1061cb93a386Sopenharmony_ci        // draws until the canvas is restored past this saveLayer.
1062cb93a386Sopenharmony_ci        AutoUpdateQRBounds aqr(this);
1063cb93a386Sopenharmony_ci        this->topDevice()->clipRect(SkRect::MakeEmpty(), SkClipOp::kIntersect, /* aa */ false);
1064cb93a386Sopenharmony_ci    };
1065cb93a386Sopenharmony_ci
1066cb93a386Sopenharmony_ci    if (layerBounds.isEmpty()) {
1067cb93a386Sopenharmony_ci        abortLayer();
1068cb93a386Sopenharmony_ci        return;
1069cb93a386Sopenharmony_ci    }
1070cb93a386Sopenharmony_ci
1071cb93a386Sopenharmony_ci    sk_sp<SkBaseDevice> newDevice;
1072cb93a386Sopenharmony_ci    if (strategy == kFullLayer_SaveLayerStrategy) {
1073cb93a386Sopenharmony_ci        SkASSERT(!layerBounds.isEmpty());
1074cb93a386Sopenharmony_ci        SkImageInfo info = make_layer_info(priorDevice->imageInfo(),
1075cb93a386Sopenharmony_ci                                           layerBounds.width(), layerBounds.height(),
1076cb93a386Sopenharmony_ci                                           SkToBool(rec.fSaveLayerFlags & kF16ColorType));
1077cb93a386Sopenharmony_ci        if (rec.fSaveLayerFlags & kF16ColorType) {
1078cb93a386Sopenharmony_ci            info = info.makeColorType(kRGBA_F16_SkColorType);
1079cb93a386Sopenharmony_ci        }
1080cb93a386Sopenharmony_ci        SkASSERT(info.alphaType() != kOpaque_SkAlphaType);
1081cb93a386Sopenharmony_ci
1082cb93a386Sopenharmony_ci        SkPixelGeometry geo = rec.fSaveLayerFlags & kPreserveLCDText_SaveLayerFlag
1083cb93a386Sopenharmony_ci                                      ? fProps.pixelGeometry()
1084cb93a386Sopenharmony_ci                                      : kUnknown_SkPixelGeometry;
1085cb93a386Sopenharmony_ci        const bool trackCoverage = SkToBool(
1086cb93a386Sopenharmony_ci                rec.fSaveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1087cb93a386Sopenharmony_ci        const auto createInfo = SkBaseDevice::CreateInfo(info, geo, SkBaseDevice::kNever_TileUsage,
1088cb93a386Sopenharmony_ci                                                         trackCoverage, fAllocator.get());
1089cb93a386Sopenharmony_ci        // Use the original paint as a hint so that it includes the image filter
1090cb93a386Sopenharmony_ci        newDevice.reset(priorDevice->onCreateDevice(createInfo, rec.fPaint));
1091cb93a386Sopenharmony_ci    }
1092cb93a386Sopenharmony_ci
1093cb93a386Sopenharmony_ci    bool initBackdrop = (rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop;
1094cb93a386Sopenharmony_ci    if (!newDevice) {
1095cb93a386Sopenharmony_ci        // Either we weren't meant to allocate a full layer, or the full layer creation failed.
1096cb93a386Sopenharmony_ci        // Using an explicit NoPixelsDevice lets us reflect what the layer state would have been
1097cb93a386Sopenharmony_ci        // on success (or kFull_LayerStrategy) while squashing draw calls that target something that
1098cb93a386Sopenharmony_ci        // doesn't exist.
1099cb93a386Sopenharmony_ci        newDevice = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeWH(layerBounds.width(),
1100cb93a386Sopenharmony_ci                                                                 layerBounds.height()),
1101cb93a386Sopenharmony_ci                                                 fProps, this->imageInfo().refColorSpace());
1102cb93a386Sopenharmony_ci        initBackdrop = false;
1103cb93a386Sopenharmony_ci    }
1104cb93a386Sopenharmony_ci
1105cb93a386Sopenharmony_ci    // Configure device to match determined mapping for any image filters.
1106cb93a386Sopenharmony_ci    // The setDeviceCoordinateSystem applies the prior device's global transform since
1107cb93a386Sopenharmony_ci    // 'newLayerMapping' only defines the transforms between the two devices and it must be updated
1108cb93a386Sopenharmony_ci    // to the global coordinate system.
1109cb93a386Sopenharmony_ci    newDevice->setMarkerStack(fMarkerStack.get());
1110cb93a386Sopenharmony_ci    if (!newDevice->setDeviceCoordinateSystem(priorDevice->deviceToGlobal() *
1111cb93a386Sopenharmony_ci                                              SkM44(newLayerMapping.deviceMatrix()),
1112cb93a386Sopenharmony_ci                                              SkM44(newLayerMapping.layerMatrix()),
1113cb93a386Sopenharmony_ci                                              layerBounds.left(), layerBounds.top())) {
1114cb93a386Sopenharmony_ci        // If we made it this far and the coordinate system is invalid, we most likely had a valid
1115cb93a386Sopenharmony_ci        // mapping until being combined with the previous device-to-global matrix, at which point
1116cb93a386Sopenharmony_ci        // it overflowed or floating point rounding caused it to no longer be invertible. There's
1117cb93a386Sopenharmony_ci        // not much we can do but clean up the layer and mark the clip as empty. This tends to come
1118cb93a386Sopenharmony_ci        // up in fuzzer-generated inputs, so this policy is not unreasonable and helps avoids UB.
1119cb93a386Sopenharmony_ci        newDevice = nullptr;
1120cb93a386Sopenharmony_ci        abortLayer();
1121cb93a386Sopenharmony_ci        return;
1122cb93a386Sopenharmony_ci    }
1123cb93a386Sopenharmony_ci
1124cb93a386Sopenharmony_ci    if (initBackdrop) {
1125cb93a386Sopenharmony_ci        SkPaint backdropPaint;
1126cb93a386Sopenharmony_ci        const SkImageFilter* backdropFilter = optimize_layer_filter(rec.fBackdrop, &backdropPaint);
1127cb93a386Sopenharmony_ci        // The new device was constructed to be compatible with 'filter', not necessarily
1128cb93a386Sopenharmony_ci        // 'rec.fBackdrop', so allow DrawDeviceWithFilter to transform the prior device contents
1129cb93a386Sopenharmony_ci        // if necessary to evaluate the backdrop filter. If no filters are involved, then the
1130cb93a386Sopenharmony_ci        // devices differ by integer translations and are always compatible.
1131cb93a386Sopenharmony_ci        bool scaleBackdrop = rec.fExperimentalBackdropScale != 1.0f;
1132cb93a386Sopenharmony_ci        auto compat = (filter || backdropFilter || scaleBackdrop)
1133cb93a386Sopenharmony_ci                ? DeviceCompatibleWithFilter::kUnknown : DeviceCompatibleWithFilter::kYes;
1134cb93a386Sopenharmony_ci        this->internalDrawDeviceWithFilter(priorDevice,     // src
1135cb93a386Sopenharmony_ci                                           newDevice.get(), // dst
1136cb93a386Sopenharmony_ci                                           backdropFilter,
1137cb93a386Sopenharmony_ci                                           backdropPaint,
1138cb93a386Sopenharmony_ci                                           compat,
1139cb93a386Sopenharmony_ci                                           rec.fExperimentalBackdropScale);
1140cb93a386Sopenharmony_ci    }
1141cb93a386Sopenharmony_ci
1142cb93a386Sopenharmony_ci    fMCRec->newLayer(std::move(newDevice), sk_ref_sp(filter), restorePaint);
1143cb93a386Sopenharmony_ci    fQuickRejectBounds = this->computeDeviceClipBounds();
1144cb93a386Sopenharmony_ci}
1145cb93a386Sopenharmony_ci
1146cb93a386Sopenharmony_ciint SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1147cb93a386Sopenharmony_ci    if (0xFF == alpha) {
1148cb93a386Sopenharmony_ci        return this->saveLayer(bounds, nullptr);
1149cb93a386Sopenharmony_ci    } else {
1150cb93a386Sopenharmony_ci        SkPaint tmpPaint;
1151cb93a386Sopenharmony_ci        tmpPaint.setAlpha(alpha);
1152cb93a386Sopenharmony_ci        return this->saveLayer(bounds, &tmpPaint);
1153cb93a386Sopenharmony_ci    }
1154cb93a386Sopenharmony_ci}
1155cb93a386Sopenharmony_ci
1156cb93a386Sopenharmony_civoid SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1157cb93a386Sopenharmony_ci    SkBaseDevice* device = this->topDevice();
1158cb93a386Sopenharmony_ci
1159cb93a386Sopenharmony_ci    // Map the local bounds into the top device's coordinate space (this is not
1160cb93a386Sopenharmony_ci    // necessarily the full global CTM transform).
1161cb93a386Sopenharmony_ci    SkIRect devBounds;
1162cb93a386Sopenharmony_ci    if (localBounds) {
1163cb93a386Sopenharmony_ci        SkRect tmp;
1164cb93a386Sopenharmony_ci        device->localToDevice().mapRect(&tmp, *localBounds);
1165cb93a386Sopenharmony_ci        if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
1166cb93a386Sopenharmony_ci            devBounds.setEmpty();
1167cb93a386Sopenharmony_ci        }
1168cb93a386Sopenharmony_ci    } else {
1169cb93a386Sopenharmony_ci        devBounds = device->devClipBounds();
1170cb93a386Sopenharmony_ci    }
1171cb93a386Sopenharmony_ci    if (devBounds.isEmpty()) {
1172cb93a386Sopenharmony_ci        return;
1173cb93a386Sopenharmony_ci    }
1174cb93a386Sopenharmony_ci
1175cb93a386Sopenharmony_ci    // This is getting the special image from the current device, which is then drawn into (both by
1176cb93a386Sopenharmony_ci    // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1177cb93a386Sopenharmony_ci    // own device, we need to explicitly copy the back image contents so that its original content
1178cb93a386Sopenharmony_ci    // is available when we splat it back later during restore.
1179cb93a386Sopenharmony_ci    auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1180cb93a386Sopenharmony_ci    if (!backImage) {
1181cb93a386Sopenharmony_ci        return;
1182cb93a386Sopenharmony_ci    }
1183cb93a386Sopenharmony_ci
1184cb93a386Sopenharmony_ci    // we really need the save, so we can wack the fMCRec
1185cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1186cb93a386Sopenharmony_ci
1187cb93a386Sopenharmony_ci    fMCRec->fBackImage =
1188cb93a386Sopenharmony_ci            std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()});
1189cb93a386Sopenharmony_ci
1190cb93a386Sopenharmony_ci    SkPaint paint;
1191cb93a386Sopenharmony_ci    paint.setBlendMode(SkBlendMode::kClear);
1192cb93a386Sopenharmony_ci    this->drawClippedToSaveBehind(paint);
1193cb93a386Sopenharmony_ci}
1194cb93a386Sopenharmony_ci
1195cb93a386Sopenharmony_civoid SkCanvas::internalRestore() {
1196cb93a386Sopenharmony_ci    SkASSERT(!fMCStack.empty());
1197cb93a386Sopenharmony_ci
1198cb93a386Sopenharmony_ci    // now detach these from fMCRec so we can pop(). Gets freed after its drawn
1199cb93a386Sopenharmony_ci    std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer);
1200cb93a386Sopenharmony_ci    std::unique_ptr<BackImage> backImage = std::move(fMCRec->fBackImage);
1201cb93a386Sopenharmony_ci
1202cb93a386Sopenharmony_ci    fMarkerStack->restore(fMCRec);
1203cb93a386Sopenharmony_ci
1204cb93a386Sopenharmony_ci    // now do the normal restore()
1205cb93a386Sopenharmony_ci    fMCRec->~MCRec();       // balanced in save()
1206cb93a386Sopenharmony_ci    fMCStack.pop_back();
1207cb93a386Sopenharmony_ci    fMCRec = (MCRec*) fMCStack.back();
1208cb93a386Sopenharmony_ci
1209cb93a386Sopenharmony_ci    if (!fMCRec) {
1210cb93a386Sopenharmony_ci        // This was the last record, restored during the destruction of the SkCanvas
1211cb93a386Sopenharmony_ci        return;
1212cb93a386Sopenharmony_ci    }
1213cb93a386Sopenharmony_ci
1214cb93a386Sopenharmony_ci    this->topDevice()->restore(fMCRec->fMatrix);
1215cb93a386Sopenharmony_ci
1216cb93a386Sopenharmony_ci    if (backImage) {
1217cb93a386Sopenharmony_ci        SkPaint paint;
1218cb93a386Sopenharmony_ci        paint.setBlendMode(SkBlendMode::kDstOver);
1219cb93a386Sopenharmony_ci        this->topDevice()->drawSpecial(backImage->fImage.get(),
1220cb93a386Sopenharmony_ci                                       SkMatrix::Translate(backImage->fLoc),
1221cb93a386Sopenharmony_ci                                       SkSamplingOptions(),
1222cb93a386Sopenharmony_ci                                       paint);
1223cb93a386Sopenharmony_ci    }
1224cb93a386Sopenharmony_ci
1225cb93a386Sopenharmony_ci    // Draw the layer's device contents into the now-current older device. We can't call public
1226cb93a386Sopenharmony_ci    // draw functions since we don't want to record them.
1227cb93a386Sopenharmony_ci    if (layer && !layer->fDevice->isNoPixelsDevice() && !layer->fDiscard) {
1228cb93a386Sopenharmony_ci        layer->fDevice->setImmutable();
1229cb93a386Sopenharmony_ci
1230cb93a386Sopenharmony_ci        // Don't go through AutoLayerForImageFilter since device draws are so closely tied to
1231cb93a386Sopenharmony_ci        // internalSaveLayer and internalRestore.
1232cb93a386Sopenharmony_ci        if (this->predrawNotify()) {
1233cb93a386Sopenharmony_ci            SkBaseDevice* dstDev = this->topDevice();
1234cb93a386Sopenharmony_ci            if (layer->fImageFilter) {
1235cb93a386Sopenharmony_ci                this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src
1236cb93a386Sopenharmony_ci                                                   dstDev,               // dst
1237cb93a386Sopenharmony_ci                                                   layer->fImageFilter.get(),
1238cb93a386Sopenharmony_ci                                                   layer->fPaint,
1239cb93a386Sopenharmony_ci                                                   DeviceCompatibleWithFilter::kYes);
1240cb93a386Sopenharmony_ci            } else {
1241cb93a386Sopenharmony_ci                // NOTE: We don't just call internalDrawDeviceWithFilter with a null filter
1242cb93a386Sopenharmony_ci                // because we want to take advantage of overridden drawDevice functions for
1243cb93a386Sopenharmony_ci                // document-based devices.
1244cb93a386Sopenharmony_ci                SkSamplingOptions sampling;
1245cb93a386Sopenharmony_ci                dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint);
1246cb93a386Sopenharmony_ci            }
1247cb93a386Sopenharmony_ci        }
1248cb93a386Sopenharmony_ci    }
1249cb93a386Sopenharmony_ci
1250cb93a386Sopenharmony_ci    // Reset the clip restriction if the restore went past the save point that had added it.
1251cb93a386Sopenharmony_ci    if (this->getSaveCount() < fClipRestrictionSaveCount) {
1252cb93a386Sopenharmony_ci        fClipRestrictionRect.setEmpty();
1253cb93a386Sopenharmony_ci        fClipRestrictionSaveCount = -1;
1254cb93a386Sopenharmony_ci    }
1255cb93a386Sopenharmony_ci    // Update the quick-reject bounds in case the restore changed the top device or the
1256cb93a386Sopenharmony_ci    // removed save record had included modifications to the clip stack.
1257cb93a386Sopenharmony_ci    fQuickRejectBounds = this->computeDeviceClipBounds();
1258cb93a386Sopenharmony_ci    this->validateClip();
1259cb93a386Sopenharmony_ci}
1260cb93a386Sopenharmony_ci
1261cb93a386Sopenharmony_cisk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1262cb93a386Sopenharmony_ci    if (nullptr == props) {
1263cb93a386Sopenharmony_ci        props = &fProps;
1264cb93a386Sopenharmony_ci    }
1265cb93a386Sopenharmony_ci    return this->onNewSurface(info, *props);
1266cb93a386Sopenharmony_ci}
1267cb93a386Sopenharmony_ci
1268cb93a386Sopenharmony_cisk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1269cb93a386Sopenharmony_ci    return this->baseDevice()->makeSurface(info, props);
1270cb93a386Sopenharmony_ci}
1271cb93a386Sopenharmony_ci
1272cb93a386Sopenharmony_ciSkImageInfo SkCanvas::imageInfo() const {
1273cb93a386Sopenharmony_ci    return this->onImageInfo();
1274cb93a386Sopenharmony_ci}
1275cb93a386Sopenharmony_ci
1276cb93a386Sopenharmony_ciSkImageInfo SkCanvas::onImageInfo() const {
1277cb93a386Sopenharmony_ci    return this->baseDevice()->imageInfo();
1278cb93a386Sopenharmony_ci}
1279cb93a386Sopenharmony_ci
1280cb93a386Sopenharmony_cibool SkCanvas::getProps(SkSurfaceProps* props) const {
1281cb93a386Sopenharmony_ci    return this->onGetProps(props);
1282cb93a386Sopenharmony_ci}
1283cb93a386Sopenharmony_ci
1284cb93a386Sopenharmony_cibool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1285cb93a386Sopenharmony_ci    if (props) {
1286cb93a386Sopenharmony_ci        *props = fProps;
1287cb93a386Sopenharmony_ci    }
1288cb93a386Sopenharmony_ci    return true;
1289cb93a386Sopenharmony_ci}
1290cb93a386Sopenharmony_ci
1291cb93a386Sopenharmony_cibool SkCanvas::peekPixels(SkPixmap* pmap) {
1292cb93a386Sopenharmony_ci    return this->onPeekPixels(pmap);
1293cb93a386Sopenharmony_ci}
1294cb93a386Sopenharmony_ci
1295cb93a386Sopenharmony_cibool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1296cb93a386Sopenharmony_ci    return this->baseDevice()->peekPixels(pmap);
1297cb93a386Sopenharmony_ci}
1298cb93a386Sopenharmony_ci
1299cb93a386Sopenharmony_civoid* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1300cb93a386Sopenharmony_ci    SkPixmap pmap;
1301cb93a386Sopenharmony_ci    if (!this->onAccessTopLayerPixels(&pmap)) {
1302cb93a386Sopenharmony_ci        return nullptr;
1303cb93a386Sopenharmony_ci    }
1304cb93a386Sopenharmony_ci    if (info) {
1305cb93a386Sopenharmony_ci        *info = pmap.info();
1306cb93a386Sopenharmony_ci    }
1307cb93a386Sopenharmony_ci    if (rowBytes) {
1308cb93a386Sopenharmony_ci        *rowBytes = pmap.rowBytes();
1309cb93a386Sopenharmony_ci    }
1310cb93a386Sopenharmony_ci    if (origin) {
1311cb93a386Sopenharmony_ci        // If the caller requested the origin, they presumably are expecting the returned pixels to
1312cb93a386Sopenharmony_ci        // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
1313cb93a386Sopenharmony_ci        // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
1314cb93a386Sopenharmony_ci        // instead of an origin, just don't expose the pixels in that case. Note that this means
1315cb93a386Sopenharmony_ci        // that layers with complex coordinate spaces can still report their pixels if the caller
1316cb93a386Sopenharmony_ci        // does not ask for the origin (e.g. just to dump its output to a file, etc).
1317cb93a386Sopenharmony_ci        if (this->topDevice()->isPixelAlignedToGlobal()) {
1318cb93a386Sopenharmony_ci            *origin = this->topDevice()->getOrigin();
1319cb93a386Sopenharmony_ci        } else {
1320cb93a386Sopenharmony_ci            return nullptr;
1321cb93a386Sopenharmony_ci        }
1322cb93a386Sopenharmony_ci    }
1323cb93a386Sopenharmony_ci    return pmap.writable_addr();
1324cb93a386Sopenharmony_ci}
1325cb93a386Sopenharmony_ci
1326cb93a386Sopenharmony_cibool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1327cb93a386Sopenharmony_ci    return this->topDevice()->accessPixels(pmap);
1328cb93a386Sopenharmony_ci}
1329cb93a386Sopenharmony_ci
1330cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////
1331cb93a386Sopenharmony_ci
1332cb93a386Sopenharmony_civoid SkCanvas::translate(SkScalar dx, SkScalar dy) {
1333cb93a386Sopenharmony_ci    if (dx || dy) {
1334cb93a386Sopenharmony_ci        this->checkForDeferredSave();
1335cb93a386Sopenharmony_ci        fMCRec->fMatrix.preTranslate(dx, dy);
1336cb93a386Sopenharmony_ci
1337cb93a386Sopenharmony_ci        this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1338cb93a386Sopenharmony_ci
1339cb93a386Sopenharmony_ci        this->didTranslate(dx,dy);
1340cb93a386Sopenharmony_ci    }
1341cb93a386Sopenharmony_ci}
1342cb93a386Sopenharmony_ci
1343cb93a386Sopenharmony_civoid SkCanvas::scale(SkScalar sx, SkScalar sy) {
1344cb93a386Sopenharmony_ci    if (sx != 1 || sy != 1) {
1345cb93a386Sopenharmony_ci        this->checkForDeferredSave();
1346cb93a386Sopenharmony_ci        fMCRec->fMatrix.preScale(sx, sy);
1347cb93a386Sopenharmony_ci
1348cb93a386Sopenharmony_ci        this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1349cb93a386Sopenharmony_ci
1350cb93a386Sopenharmony_ci        this->didScale(sx, sy);
1351cb93a386Sopenharmony_ci    }
1352cb93a386Sopenharmony_ci}
1353cb93a386Sopenharmony_ci
1354cb93a386Sopenharmony_civoid SkCanvas::rotate(SkScalar degrees) {
1355cb93a386Sopenharmony_ci    SkMatrix m;
1356cb93a386Sopenharmony_ci    m.setRotate(degrees);
1357cb93a386Sopenharmony_ci    this->concat(m);
1358cb93a386Sopenharmony_ci}
1359cb93a386Sopenharmony_ci
1360cb93a386Sopenharmony_civoid SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1361cb93a386Sopenharmony_ci    SkMatrix m;
1362cb93a386Sopenharmony_ci    m.setRotate(degrees, px, py);
1363cb93a386Sopenharmony_ci    this->concat(m);
1364cb93a386Sopenharmony_ci}
1365cb93a386Sopenharmony_ci
1366cb93a386Sopenharmony_civoid SkCanvas::skew(SkScalar sx, SkScalar sy) {
1367cb93a386Sopenharmony_ci    SkMatrix m;
1368cb93a386Sopenharmony_ci    m.setSkew(sx, sy);
1369cb93a386Sopenharmony_ci    this->concat(m);
1370cb93a386Sopenharmony_ci}
1371cb93a386Sopenharmony_ci
1372cb93a386Sopenharmony_civoid SkCanvas::concat(const SkMatrix& matrix) {
1373cb93a386Sopenharmony_ci    if (matrix.isIdentity()) {
1374cb93a386Sopenharmony_ci        return;
1375cb93a386Sopenharmony_ci    }
1376cb93a386Sopenharmony_ci    this->concat(SkM44(matrix));
1377cb93a386Sopenharmony_ci}
1378cb93a386Sopenharmony_ci
1379cb93a386Sopenharmony_civoid SkCanvas::internalConcat44(const SkM44& m) {
1380cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1381cb93a386Sopenharmony_ci
1382cb93a386Sopenharmony_ci    fMCRec->fMatrix.preConcat(m);
1383cb93a386Sopenharmony_ci
1384cb93a386Sopenharmony_ci    this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1385cb93a386Sopenharmony_ci}
1386cb93a386Sopenharmony_ci
1387cb93a386Sopenharmony_civoid SkCanvas::concat(const SkM44& m) {
1388cb93a386Sopenharmony_ci    this->internalConcat44(m);
1389cb93a386Sopenharmony_ci    // notify subclasses
1390cb93a386Sopenharmony_ci    this->didConcat44(m);
1391cb93a386Sopenharmony_ci}
1392cb93a386Sopenharmony_ci
1393cb93a386Sopenharmony_civoid SkCanvas::internalSetMatrix(const SkM44& m) {
1394cb93a386Sopenharmony_ci    fMCRec->fMatrix = m;
1395cb93a386Sopenharmony_ci
1396cb93a386Sopenharmony_ci    this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1397cb93a386Sopenharmony_ci}
1398cb93a386Sopenharmony_ci
1399cb93a386Sopenharmony_civoid SkCanvas::setMatrix(const SkMatrix& matrix) {
1400cb93a386Sopenharmony_ci    this->setMatrix(SkM44(matrix));
1401cb93a386Sopenharmony_ci}
1402cb93a386Sopenharmony_ci
1403cb93a386Sopenharmony_civoid SkCanvas::setMatrix(const SkM44& m) {
1404cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1405cb93a386Sopenharmony_ci    this->internalSetMatrix(m);
1406cb93a386Sopenharmony_ci    this->didSetM44(m);
1407cb93a386Sopenharmony_ci}
1408cb93a386Sopenharmony_ci
1409cb93a386Sopenharmony_civoid SkCanvas::resetMatrix() {
1410cb93a386Sopenharmony_ci    this->setMatrix(SkM44());
1411cb93a386Sopenharmony_ci}
1412cb93a386Sopenharmony_ci
1413cb93a386Sopenharmony_civoid SkCanvas::markCTM(const char* name) {
1414cb93a386Sopenharmony_ci    if (SkCanvasPriv::ValidateMarker(name)) {
1415cb93a386Sopenharmony_ci        fMarkerStack->setMarker(SkOpts::hash_fn(name, strlen(name), 0),
1416cb93a386Sopenharmony_ci                                this->getLocalToDevice(), fMCRec);
1417cb93a386Sopenharmony_ci        this->onMarkCTM(name);
1418cb93a386Sopenharmony_ci    }
1419cb93a386Sopenharmony_ci}
1420cb93a386Sopenharmony_ci
1421cb93a386Sopenharmony_cibool SkCanvas::findMarkedCTM(const char* name, SkM44* mx) const {
1422cb93a386Sopenharmony_ci    return SkCanvasPriv::ValidateMarker(name) &&
1423cb93a386Sopenharmony_ci           fMarkerStack->findMarker(SkOpts::hash_fn(name, strlen(name), 0), mx);
1424cb93a386Sopenharmony_ci}
1425cb93a386Sopenharmony_ci
1426cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
1427cb93a386Sopenharmony_ci
1428cb93a386Sopenharmony_civoid SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1429cb93a386Sopenharmony_ci    if (!rect.isFinite()) {
1430cb93a386Sopenharmony_ci        return;
1431cb93a386Sopenharmony_ci    }
1432cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1433cb93a386Sopenharmony_ci    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1434cb93a386Sopenharmony_ci    this->onClipRect(rect.makeSorted(), op, edgeStyle);
1435cb93a386Sopenharmony_ci}
1436cb93a386Sopenharmony_ci
1437cb93a386Sopenharmony_civoid SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1438cb93a386Sopenharmony_ci    SkASSERT(rect.isSorted());
1439cb93a386Sopenharmony_ci    const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1440cb93a386Sopenharmony_ci
1441cb93a386Sopenharmony_ci    AutoUpdateQRBounds aqr(this);
1442cb93a386Sopenharmony_ci    this->topDevice()->clipRect(rect, op, isAA);
1443cb93a386Sopenharmony_ci}
1444cb93a386Sopenharmony_ci
1445cb93a386Sopenharmony_civoid SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1446cb93a386Sopenharmony_ci    // The device clip restriction is a surface-space rectangular intersection that cannot be
1447cb93a386Sopenharmony_ci    // drawn outside of. The rectangle is remembered so that subsequent resetClip calls still
1448cb93a386Sopenharmony_ci    // respect the restriction. Other than clip resetting, all clip operations restrict the set
1449cb93a386Sopenharmony_ci    // of renderable pixels, so once set, the restriction will be respected until the canvas
1450cb93a386Sopenharmony_ci    // save stack is restored past the point this function was invoked. Unfortunately, the current
1451cb93a386Sopenharmony_ci    // implementation relies on the clip stack of the underyling SkDevices, which leads to some
1452cb93a386Sopenharmony_ci    // awkward behavioral interactions (see skbug.com/12252).
1453cb93a386Sopenharmony_ci    //
1454cb93a386Sopenharmony_ci    // Namely, a canvas restore() could undo the clip restriction's rect, and if
1455cb93a386Sopenharmony_ci    // setDeviceClipRestriction were called at a nested save level, there's no way to undo just the
1456cb93a386Sopenharmony_ci    // prior restriction and re-apply the new one. It also only makes sense to apply to the base
1457cb93a386Sopenharmony_ci    // device; any other device for a saved layer will be clipped back to the base device during its
1458cb93a386Sopenharmony_ci    // matched restore. As such, we:
1459cb93a386Sopenharmony_ci    // - Remember the save count that added the clip restriction and reset the rect to empty when
1460cb93a386Sopenharmony_ci    //   we've restored past that point to keep our state in sync with the device's clip stack.
1461cb93a386Sopenharmony_ci    // - We assert that we're on the base device when this is invoked.
1462cb93a386Sopenharmony_ci    // - We assert that setDeviceClipRestriction() is only called when there was no prior
1463cb93a386Sopenharmony_ci    //   restriction (cannot re-restrict, and prior state must have been reset by restoring the
1464cb93a386Sopenharmony_ci    //   canvas state).
1465cb93a386Sopenharmony_ci    // - Historically, the empty rect would reset the clip restriction but it only could do so
1466cb93a386Sopenharmony_ci    //   partially since the device's clips wasn't adjusted. Resetting is now handled
1467cb93a386Sopenharmony_ci    //   automatically via SkCanvas::restore(), so empty input rects are skipped.
1468cb93a386Sopenharmony_ci    SkASSERT(this->topDevice() == this->baseDevice()); // shouldn't be in a nested layer
1469cb93a386Sopenharmony_ci    // and shouldn't already have a restriction
1470cb93a386Sopenharmony_ci    SkASSERT(fClipRestrictionSaveCount < 0 && fClipRestrictionRect.isEmpty());
1471cb93a386Sopenharmony_ci
1472cb93a386Sopenharmony_ci    if (fClipRestrictionSaveCount < 0 && !rect.isEmpty()) {
1473cb93a386Sopenharmony_ci        fClipRestrictionRect = rect;
1474cb93a386Sopenharmony_ci        fClipRestrictionSaveCount = this->getSaveCount();
1475cb93a386Sopenharmony_ci
1476cb93a386Sopenharmony_ci        // A non-empty clip restriction immediately applies an intersection op (ignoring the ctm).
1477cb93a386Sopenharmony_ci        // so we have to resolve the save.
1478cb93a386Sopenharmony_ci        this->checkForDeferredSave();
1479cb93a386Sopenharmony_ci        AutoUpdateQRBounds aqr(this);
1480cb93a386Sopenharmony_ci        // Use clipRegion() since that operates in canvas-space, whereas clipRect() would apply the
1481cb93a386Sopenharmony_ci        // device's current transform first.
1482cb93a386Sopenharmony_ci        this->topDevice()->clipRegion(SkRegion(rect), SkClipOp::kIntersect);
1483cb93a386Sopenharmony_ci    }
1484cb93a386Sopenharmony_ci}
1485cb93a386Sopenharmony_ci
1486cb93a386Sopenharmony_civoid SkCanvas::internal_private_resetClip() {
1487cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1488cb93a386Sopenharmony_ci    this->onResetClip();
1489cb93a386Sopenharmony_ci}
1490cb93a386Sopenharmony_ci
1491cb93a386Sopenharmony_civoid SkCanvas::onResetClip() {
1492cb93a386Sopenharmony_ci    SkIRect deviceRestriction = this->topDevice()->imageInfo().bounds();
1493cb93a386Sopenharmony_ci    if (fClipRestrictionSaveCount >= 0 && this->topDevice() == this->baseDevice()) {
1494cb93a386Sopenharmony_ci        // Respect the device clip restriction when resetting the clip if we're on the base device.
1495cb93a386Sopenharmony_ci        // If we're not on the base device, then the "reset" applies to the top device's clip stack,
1496cb93a386Sopenharmony_ci        // and the clip restriction will be respected automatically during a restore of the layer.
1497cb93a386Sopenharmony_ci        if (!deviceRestriction.intersect(fClipRestrictionRect)) {
1498cb93a386Sopenharmony_ci            deviceRestriction = SkIRect::MakeEmpty();
1499cb93a386Sopenharmony_ci        }
1500cb93a386Sopenharmony_ci    }
1501cb93a386Sopenharmony_ci
1502cb93a386Sopenharmony_ci    AutoUpdateQRBounds aqr(this);
1503cb93a386Sopenharmony_ci    this->topDevice()->replaceClip(deviceRestriction);
1504cb93a386Sopenharmony_ci}
1505cb93a386Sopenharmony_ci
1506cb93a386Sopenharmony_civoid SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1507cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1508cb93a386Sopenharmony_ci    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1509cb93a386Sopenharmony_ci    if (rrect.isRect()) {
1510cb93a386Sopenharmony_ci        this->onClipRect(rrect.getBounds(), op, edgeStyle);
1511cb93a386Sopenharmony_ci    } else {
1512cb93a386Sopenharmony_ci        this->onClipRRect(rrect, op, edgeStyle);
1513cb93a386Sopenharmony_ci    }
1514cb93a386Sopenharmony_ci}
1515cb93a386Sopenharmony_ci
1516cb93a386Sopenharmony_civoid SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1517cb93a386Sopenharmony_ci    bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1518cb93a386Sopenharmony_ci
1519cb93a386Sopenharmony_ci    AutoUpdateQRBounds aqr(this);
1520cb93a386Sopenharmony_ci    this->topDevice()->clipRRect(rrect, op, isAA);
1521cb93a386Sopenharmony_ci}
1522cb93a386Sopenharmony_ci
1523cb93a386Sopenharmony_civoid SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1524cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1525cb93a386Sopenharmony_ci    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1526cb93a386Sopenharmony_ci
1527cb93a386Sopenharmony_ci    if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) {
1528cb93a386Sopenharmony_ci        SkRect r;
1529cb93a386Sopenharmony_ci        if (path.isRect(&r)) {
1530cb93a386Sopenharmony_ci            this->onClipRect(r, op, edgeStyle);
1531cb93a386Sopenharmony_ci            return;
1532cb93a386Sopenharmony_ci        }
1533cb93a386Sopenharmony_ci        SkRRect rrect;
1534cb93a386Sopenharmony_ci        if (path.isOval(&r)) {
1535cb93a386Sopenharmony_ci            rrect.setOval(r);
1536cb93a386Sopenharmony_ci            this->onClipRRect(rrect, op, edgeStyle);
1537cb93a386Sopenharmony_ci            return;
1538cb93a386Sopenharmony_ci        }
1539cb93a386Sopenharmony_ci        if (path.isRRect(&rrect)) {
1540cb93a386Sopenharmony_ci            this->onClipRRect(rrect, op, edgeStyle);
1541cb93a386Sopenharmony_ci            return;
1542cb93a386Sopenharmony_ci        }
1543cb93a386Sopenharmony_ci    }
1544cb93a386Sopenharmony_ci
1545cb93a386Sopenharmony_ci    this->onClipPath(path, op, edgeStyle);
1546cb93a386Sopenharmony_ci}
1547cb93a386Sopenharmony_ci
1548cb93a386Sopenharmony_civoid SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1549cb93a386Sopenharmony_ci    bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1550cb93a386Sopenharmony_ci
1551cb93a386Sopenharmony_ci    AutoUpdateQRBounds aqr(this);
1552cb93a386Sopenharmony_ci    this->topDevice()->clipPath(path, op, isAA);
1553cb93a386Sopenharmony_ci}
1554cb93a386Sopenharmony_ci
1555cb93a386Sopenharmony_civoid SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) {
1556cb93a386Sopenharmony_ci    if (sh) {
1557cb93a386Sopenharmony_ci        if (sh->isOpaque()) {
1558cb93a386Sopenharmony_ci            if (op == SkClipOp::kIntersect) {
1559cb93a386Sopenharmony_ci                // we don't occlude anything, so skip this call
1560cb93a386Sopenharmony_ci            } else {
1561cb93a386Sopenharmony_ci                SkASSERT(op == SkClipOp::kDifference);
1562cb93a386Sopenharmony_ci                // we occlude everything, so set the clip to empty
1563cb93a386Sopenharmony_ci                this->clipRect({0,0,0,0});
1564cb93a386Sopenharmony_ci            }
1565cb93a386Sopenharmony_ci        } else {
1566cb93a386Sopenharmony_ci            this->checkForDeferredSave();
1567cb93a386Sopenharmony_ci            this->onClipShader(std::move(sh), op);
1568cb93a386Sopenharmony_ci        }
1569cb93a386Sopenharmony_ci    }
1570cb93a386Sopenharmony_ci}
1571cb93a386Sopenharmony_ci
1572cb93a386Sopenharmony_civoid SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) {
1573cb93a386Sopenharmony_ci    AutoUpdateQRBounds aqr(this);
1574cb93a386Sopenharmony_ci    this->topDevice()->clipShader(sh, op);
1575cb93a386Sopenharmony_ci}
1576cb93a386Sopenharmony_ci
1577cb93a386Sopenharmony_civoid SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1578cb93a386Sopenharmony_ci    this->checkForDeferredSave();
1579cb93a386Sopenharmony_ci    this->onClipRegion(rgn, op);
1580cb93a386Sopenharmony_ci}
1581cb93a386Sopenharmony_ci
1582cb93a386Sopenharmony_civoid SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1583cb93a386Sopenharmony_ci    AutoUpdateQRBounds aqr(this);
1584cb93a386Sopenharmony_ci    this->topDevice()->clipRegion(rgn, op);
1585cb93a386Sopenharmony_ci}
1586cb93a386Sopenharmony_ci
1587cb93a386Sopenharmony_civoid SkCanvas::validateClip() const {
1588cb93a386Sopenharmony_ci#ifdef SK_DEBUG
1589cb93a386Sopenharmony_ci    SkRect tmp = this->computeDeviceClipBounds();
1590cb93a386Sopenharmony_ci    if (this->isClipEmpty()) {
1591cb93a386Sopenharmony_ci        SkASSERT(fQuickRejectBounds.isEmpty());
1592cb93a386Sopenharmony_ci    } else {
1593cb93a386Sopenharmony_ci        SkASSERT(tmp == fQuickRejectBounds);
1594cb93a386Sopenharmony_ci    }
1595cb93a386Sopenharmony_ci#endif
1596cb93a386Sopenharmony_ci}
1597cb93a386Sopenharmony_ci
1598cb93a386Sopenharmony_cibool SkCanvas::androidFramework_isClipAA() const {
1599cb93a386Sopenharmony_ci    return this->topDevice()->onClipIsAA();
1600cb93a386Sopenharmony_ci}
1601cb93a386Sopenharmony_ci
1602cb93a386Sopenharmony_civoid SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1603cb93a386Sopenharmony_ci    rgn->setEmpty();
1604cb93a386Sopenharmony_ci    SkBaseDevice* device = this->topDevice();
1605cb93a386Sopenharmony_ci    if (device && device->isPixelAlignedToGlobal()) {
1606cb93a386Sopenharmony_ci        device->onAsRgnClip(rgn);
1607cb93a386Sopenharmony_ci        SkIPoint origin = device->getOrigin();
1608cb93a386Sopenharmony_ci        if (origin.x() | origin.y()) {
1609cb93a386Sopenharmony_ci            rgn->translate(origin.x(), origin.y());
1610cb93a386Sopenharmony_ci        }
1611cb93a386Sopenharmony_ci    }
1612cb93a386Sopenharmony_ci}
1613cb93a386Sopenharmony_ci
1614cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
1615cb93a386Sopenharmony_ci
1616cb93a386Sopenharmony_cibool SkCanvas::isClipEmpty() const {
1617cb93a386Sopenharmony_ci    return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kEmpty;
1618cb93a386Sopenharmony_ci}
1619cb93a386Sopenharmony_ci
1620cb93a386Sopenharmony_cibool SkCanvas::isClipRect() const {
1621cb93a386Sopenharmony_ci    return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kRect;
1622cb93a386Sopenharmony_ci}
1623cb93a386Sopenharmony_ci
1624cb93a386Sopenharmony_cibool SkCanvas::quickReject(const SkRect& src) const {
1625cb93a386Sopenharmony_ci#ifdef SK_DEBUG
1626cb93a386Sopenharmony_ci    // Verify that fQuickRejectBounds are set properly.
1627cb93a386Sopenharmony_ci    this->validateClip();
1628cb93a386Sopenharmony_ci#endif
1629cb93a386Sopenharmony_ci
1630cb93a386Sopenharmony_ci    SkRect devRect = SkMatrixPriv::MapRect(fMCRec->fMatrix, src);
1631cb93a386Sopenharmony_ci    return !devRect.isFinite() || !devRect.intersects(fQuickRejectBounds);
1632cb93a386Sopenharmony_ci}
1633cb93a386Sopenharmony_ci
1634cb93a386Sopenharmony_cibool SkCanvas::quickReject(const SkPath& path) const {
1635cb93a386Sopenharmony_ci    return path.isEmpty() || this->quickReject(path.getBounds());
1636cb93a386Sopenharmony_ci}
1637cb93a386Sopenharmony_ci
1638cb93a386Sopenharmony_cibool SkCanvas::internalQuickReject(const SkRect& bounds, const SkPaint& paint,
1639cb93a386Sopenharmony_ci                                   const SkMatrix* matrix) {
1640cb93a386Sopenharmony_ci    if (!bounds.isFinite() || paint.nothingToDraw()) {
1641cb93a386Sopenharmony_ci        return true;
1642cb93a386Sopenharmony_ci    }
1643cb93a386Sopenharmony_ci
1644cb93a386Sopenharmony_ci    if (paint.canComputeFastBounds()) {
1645cb93a386Sopenharmony_ci        SkRect tmp = matrix ? matrix->mapRect(bounds) : bounds;
1646cb93a386Sopenharmony_ci        return this->quickReject(paint.computeFastBounds(tmp, &tmp));
1647cb93a386Sopenharmony_ci    }
1648cb93a386Sopenharmony_ci
1649cb93a386Sopenharmony_ci    return false;
1650cb93a386Sopenharmony_ci}
1651cb93a386Sopenharmony_ci
1652cb93a386Sopenharmony_ci
1653cb93a386Sopenharmony_ciSkRect SkCanvas::getLocalClipBounds() const {
1654cb93a386Sopenharmony_ci    SkIRect ibounds = this->getDeviceClipBounds();
1655cb93a386Sopenharmony_ci    if (ibounds.isEmpty()) {
1656cb93a386Sopenharmony_ci        return SkRect::MakeEmpty();
1657cb93a386Sopenharmony_ci    }
1658cb93a386Sopenharmony_ci
1659cb93a386Sopenharmony_ci    SkMatrix inverse;
1660cb93a386Sopenharmony_ci    // if we can't invert the CTM, we can't return local clip bounds
1661cb93a386Sopenharmony_ci    if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
1662cb93a386Sopenharmony_ci        return SkRect::MakeEmpty();
1663cb93a386Sopenharmony_ci    }
1664cb93a386Sopenharmony_ci
1665cb93a386Sopenharmony_ci    SkRect bounds;
1666cb93a386Sopenharmony_ci    // adjust it outwards in case we are antialiasing
1667cb93a386Sopenharmony_ci    const int margin = 1;
1668cb93a386Sopenharmony_ci
1669cb93a386Sopenharmony_ci    SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1670cb93a386Sopenharmony_ci    inverse.mapRect(&bounds, r);
1671cb93a386Sopenharmony_ci    return bounds;
1672cb93a386Sopenharmony_ci}
1673cb93a386Sopenharmony_ci
1674cb93a386Sopenharmony_ciSkIRect SkCanvas::getRoundInDeviceClipBounds() const {
1675cb93a386Sopenharmony_ci    return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundIn();
1676cb93a386Sopenharmony_ci}
1677cb93a386Sopenharmony_ci
1678cb93a386Sopenharmony_ciSkIRect SkCanvas::getDeviceClipBounds() const {
1679cb93a386Sopenharmony_ci    return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundOut();
1680cb93a386Sopenharmony_ci}
1681cb93a386Sopenharmony_ci
1682cb93a386Sopenharmony_ciSkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const {
1683cb93a386Sopenharmony_ci    const SkBaseDevice* dev = this->topDevice();
1684cb93a386Sopenharmony_ci    if (dev->onGetClipType() == SkBaseDevice::ClipType::kEmpty) {
1685cb93a386Sopenharmony_ci        return SkRect::MakeEmpty();
1686cb93a386Sopenharmony_ci    } else {
1687cb93a386Sopenharmony_ci        SkRect devClipBounds =
1688cb93a386Sopenharmony_ci                SkMatrixPriv::MapRect(dev->deviceToGlobal(), SkRect::Make(dev->devClipBounds()));
1689cb93a386Sopenharmony_ci        if (outsetForAA) {
1690cb93a386Sopenharmony_ci            // Expand bounds out by 1 in case we are anti-aliasing.  We store the
1691cb93a386Sopenharmony_ci            // bounds as floats to enable a faster quick reject implementation.
1692cb93a386Sopenharmony_ci            devClipBounds.outset(1.f, 1.f);
1693cb93a386Sopenharmony_ci        }
1694cb93a386Sopenharmony_ci        return devClipBounds;
1695cb93a386Sopenharmony_ci    }
1696cb93a386Sopenharmony_ci}
1697cb93a386Sopenharmony_ci
1698cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////
1699cb93a386Sopenharmony_ci
1700cb93a386Sopenharmony_ciSkMatrix SkCanvas::getTotalMatrix() const {
1701cb93a386Sopenharmony_ci    return fMCRec->fMatrix.asM33();
1702cb93a386Sopenharmony_ci}
1703cb93a386Sopenharmony_ci
1704cb93a386Sopenharmony_ciSkM44 SkCanvas::getLocalToDevice() const {
1705cb93a386Sopenharmony_ci    return fMCRec->fMatrix;
1706cb93a386Sopenharmony_ci}
1707cb93a386Sopenharmony_ci
1708cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && SK_SUPPORT_GPU
1709cb93a386Sopenharmony_ci
1710cb93a386Sopenharmony_ciSkIRect SkCanvas::topLayerBounds() const {
1711cb93a386Sopenharmony_ci    return this->topDevice()->getGlobalBounds();
1712cb93a386Sopenharmony_ci}
1713cb93a386Sopenharmony_ci
1714cb93a386Sopenharmony_ciGrBackendRenderTarget SkCanvas::topLayerBackendRenderTarget() const {
1715cb93a386Sopenharmony_ci    auto proxy = SkCanvasPriv::TopDeviceTargetProxy(const_cast<SkCanvas*>(this));
1716cb93a386Sopenharmony_ci    if (!proxy) {
1717cb93a386Sopenharmony_ci        return {};
1718cb93a386Sopenharmony_ci    }
1719cb93a386Sopenharmony_ci    const GrRenderTarget* renderTarget = proxy->peekRenderTarget();
1720cb93a386Sopenharmony_ci    return renderTarget ? renderTarget->getBackendRenderTarget() : GrBackendRenderTarget();
1721cb93a386Sopenharmony_ci}
1722cb93a386Sopenharmony_ci#endif
1723cb93a386Sopenharmony_ci
1724cb93a386Sopenharmony_ciGrRecordingContext* SkCanvas::recordingContext() {
1725cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU
1726cb93a386Sopenharmony_ci    if (auto gpuDevice = this->topDevice()->asGpuDevice()) {
1727cb93a386Sopenharmony_ci        return gpuDevice->recordingContext();
1728cb93a386Sopenharmony_ci    }
1729cb93a386Sopenharmony_ci#endif
1730cb93a386Sopenharmony_ci
1731cb93a386Sopenharmony_ci    return nullptr;
1732cb93a386Sopenharmony_ci}
1733cb93a386Sopenharmony_ci
1734cb93a386Sopenharmony_civoid SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1735cb93a386Sopenharmony_ci                          const SkPaint& paint) {
1736cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1737cb93a386Sopenharmony_ci    if (outer.isEmpty()) {
1738cb93a386Sopenharmony_ci        return;
1739cb93a386Sopenharmony_ci    }
1740cb93a386Sopenharmony_ci    if (inner.isEmpty()) {
1741cb93a386Sopenharmony_ci        this->drawRRect(outer, paint);
1742cb93a386Sopenharmony_ci        return;
1743cb93a386Sopenharmony_ci    }
1744cb93a386Sopenharmony_ci
1745cb93a386Sopenharmony_ci    // We don't have this method (yet), but technically this is what we should
1746cb93a386Sopenharmony_ci    // be able to return ...
1747cb93a386Sopenharmony_ci    // if (!outer.contains(inner))) {
1748cb93a386Sopenharmony_ci    //
1749cb93a386Sopenharmony_ci    // For now at least check for containment of bounds
1750cb93a386Sopenharmony_ci    if (!outer.getBounds().contains(inner.getBounds())) {
1751cb93a386Sopenharmony_ci        return;
1752cb93a386Sopenharmony_ci    }
1753cb93a386Sopenharmony_ci
1754cb93a386Sopenharmony_ci    this->onDrawDRRect(outer, inner, paint);
1755cb93a386Sopenharmony_ci}
1756cb93a386Sopenharmony_ci
1757cb93a386Sopenharmony_civoid SkCanvas::drawPaint(const SkPaint& paint) {
1758cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1759cb93a386Sopenharmony_ci    this->onDrawPaint(paint);
1760cb93a386Sopenharmony_ci}
1761cb93a386Sopenharmony_ci
1762cb93a386Sopenharmony_civoid SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1763cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1764cb93a386Sopenharmony_ci    // To avoid redundant logic in our culling code and various backends, we always sort rects
1765cb93a386Sopenharmony_ci    // before passing them along.
1766cb93a386Sopenharmony_ci    this->onDrawRect(r.makeSorted(), paint);
1767cb93a386Sopenharmony_ci}
1768cb93a386Sopenharmony_ci
1769cb93a386Sopenharmony_civoid SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1770cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1771cb93a386Sopenharmony_ci    this->onDrawBehind(paint);
1772cb93a386Sopenharmony_ci}
1773cb93a386Sopenharmony_ci
1774cb93a386Sopenharmony_civoid SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1775cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1776cb93a386Sopenharmony_ci    if (region.isEmpty()) {
1777cb93a386Sopenharmony_ci        return;
1778cb93a386Sopenharmony_ci    }
1779cb93a386Sopenharmony_ci
1780cb93a386Sopenharmony_ci    if (region.isRect()) {
1781cb93a386Sopenharmony_ci        return this->drawIRect(region.getBounds(), paint);
1782cb93a386Sopenharmony_ci    }
1783cb93a386Sopenharmony_ci
1784cb93a386Sopenharmony_ci    this->onDrawRegion(region, paint);
1785cb93a386Sopenharmony_ci}
1786cb93a386Sopenharmony_ci
1787cb93a386Sopenharmony_civoid SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1788cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1789cb93a386Sopenharmony_ci    // To avoid redundant logic in our culling code and various backends, we always sort rects
1790cb93a386Sopenharmony_ci    // before passing them along.
1791cb93a386Sopenharmony_ci    this->onDrawOval(r.makeSorted(), paint);
1792cb93a386Sopenharmony_ci}
1793cb93a386Sopenharmony_ci
1794cb93a386Sopenharmony_civoid SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1795cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1796cb93a386Sopenharmony_ci    this->onDrawRRect(rrect, paint);
1797cb93a386Sopenharmony_ci}
1798cb93a386Sopenharmony_ci
1799cb93a386Sopenharmony_civoid SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1800cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1801cb93a386Sopenharmony_ci    this->onDrawPoints(mode, count, pts, paint);
1802cb93a386Sopenharmony_ci}
1803cb93a386Sopenharmony_ci
1804cb93a386Sopenharmony_civoid SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1805cb93a386Sopenharmony_ci                            const SkPaint& paint) {
1806cb93a386Sopenharmony_ci    this->drawVertices(vertices.get(), mode, paint);
1807cb93a386Sopenharmony_ci}
1808cb93a386Sopenharmony_ci
1809cb93a386Sopenharmony_civoid SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1810cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1811cb93a386Sopenharmony_ci    RETURN_ON_NULL(vertices);
1812cb93a386Sopenharmony_ci
1813cb93a386Sopenharmony_ci    // We expect fans to be converted to triangles when building or deserializing SkVertices.
1814cb93a386Sopenharmony_ci    SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode);
1815cb93a386Sopenharmony_ci
1816cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1817cb93a386Sopenharmony_ci    // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
1818cb93a386Sopenharmony_ci    if (paint.getShader() && !vertices->priv().hasTexCoords()) {
1819cb93a386Sopenharmony_ci        SkPaint noShaderPaint(paint);
1820cb93a386Sopenharmony_ci        noShaderPaint.setShader(nullptr);
1821cb93a386Sopenharmony_ci        this->onDrawVerticesObject(vertices, mode, noShaderPaint);
1822cb93a386Sopenharmony_ci        return;
1823cb93a386Sopenharmony_ci    }
1824cb93a386Sopenharmony_ci#endif
1825cb93a386Sopenharmony_ci
1826cb93a386Sopenharmony_ci    this->onDrawVerticesObject(vertices, mode, paint);
1827cb93a386Sopenharmony_ci}
1828cb93a386Sopenharmony_ci
1829cb93a386Sopenharmony_civoid SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1830cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1831cb93a386Sopenharmony_ci    this->onDrawPath(path, paint);
1832cb93a386Sopenharmony_ci#ifdef SK_ENABLE_PATH_COMPLEXITY_DFX
1833cb93a386Sopenharmony_ci    SkPathComplexityDfx::ShowPathComplexityDfx(this, path);
1834cb93a386Sopenharmony_ci#endif
1835cb93a386Sopenharmony_ci}
1836cb93a386Sopenharmony_ci
1837cb93a386Sopenharmony_ci// Returns true if the rect can be "filled" : non-empty and finite
1838cb93a386Sopenharmony_cistatic bool fillable(const SkRect& r) {
1839cb93a386Sopenharmony_ci    SkScalar w = r.width();
1840cb93a386Sopenharmony_ci    SkScalar h = r.height();
1841cb93a386Sopenharmony_ci    return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1842cb93a386Sopenharmony_ci}
1843cb93a386Sopenharmony_ci
1844cb93a386Sopenharmony_cistatic SkPaint clean_paint_for_lattice(const SkPaint* paint) {
1845cb93a386Sopenharmony_ci    SkPaint cleaned;
1846cb93a386Sopenharmony_ci    if (paint) {
1847cb93a386Sopenharmony_ci        cleaned = *paint;
1848cb93a386Sopenharmony_ci        cleaned.setMaskFilter(nullptr);
1849cb93a386Sopenharmony_ci        cleaned.setAntiAlias(false);
1850cb93a386Sopenharmony_ci    }
1851cb93a386Sopenharmony_ci    return cleaned;
1852cb93a386Sopenharmony_ci}
1853cb93a386Sopenharmony_ci
1854cb93a386Sopenharmony_civoid SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1855cb93a386Sopenharmony_ci                             SkFilterMode filter, const SkPaint* paint) {
1856cb93a386Sopenharmony_ci    RETURN_ON_NULL(image);
1857cb93a386Sopenharmony_ci
1858cb93a386Sopenharmony_ci    const int xdivs[] = {center.fLeft, center.fRight};
1859cb93a386Sopenharmony_ci    const int ydivs[] = {center.fTop, center.fBottom};
1860cb93a386Sopenharmony_ci
1861cb93a386Sopenharmony_ci    Lattice lat;
1862cb93a386Sopenharmony_ci    lat.fXDivs = xdivs;
1863cb93a386Sopenharmony_ci    lat.fYDivs = ydivs;
1864cb93a386Sopenharmony_ci    lat.fRectTypes = nullptr;
1865cb93a386Sopenharmony_ci    lat.fXCount = lat.fYCount = 2;
1866cb93a386Sopenharmony_ci    lat.fBounds = nullptr;
1867cb93a386Sopenharmony_ci    lat.fColors = nullptr;
1868cb93a386Sopenharmony_ci    this->drawImageLattice(image, lat, dst, filter, paint);
1869cb93a386Sopenharmony_ci}
1870cb93a386Sopenharmony_ci
1871cb93a386Sopenharmony_civoid SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1872cb93a386Sopenharmony_ci                                SkFilterMode filter, const SkPaint* paint) {
1873cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1874cb93a386Sopenharmony_ci    RETURN_ON_NULL(image);
1875cb93a386Sopenharmony_ci    if (dst.isEmpty()) {
1876cb93a386Sopenharmony_ci        return;
1877cb93a386Sopenharmony_ci    }
1878cb93a386Sopenharmony_ci
1879cb93a386Sopenharmony_ci    SkIRect bounds;
1880cb93a386Sopenharmony_ci    Lattice latticePlusBounds = lattice;
1881cb93a386Sopenharmony_ci    if (!latticePlusBounds.fBounds) {
1882cb93a386Sopenharmony_ci        bounds = SkIRect::MakeWH(image->width(), image->height());
1883cb93a386Sopenharmony_ci        latticePlusBounds.fBounds = &bounds;
1884cb93a386Sopenharmony_ci    }
1885cb93a386Sopenharmony_ci
1886cb93a386Sopenharmony_ci    if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1887cb93a386Sopenharmony_ci        SkPaint latticePaint = clean_paint_for_lattice(paint);
1888cb93a386Sopenharmony_ci        this->onDrawImageLattice2(image, latticePlusBounds, dst, filter, &latticePaint);
1889cb93a386Sopenharmony_ci    } else {
1890cb93a386Sopenharmony_ci        this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst,
1891cb93a386Sopenharmony_ci                            SkSamplingOptions(filter), paint, kStrict_SrcRectConstraint);
1892cb93a386Sopenharmony_ci    }
1893cb93a386Sopenharmony_ci}
1894cb93a386Sopenharmony_ci
1895cb93a386Sopenharmony_civoid SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1896cb93a386Sopenharmony_ci                         const SkColor colors[], int count, SkBlendMode mode,
1897cb93a386Sopenharmony_ci                         const SkSamplingOptions& sampling, const SkRect* cull,
1898cb93a386Sopenharmony_ci                         const SkPaint* paint) {
1899cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1900cb93a386Sopenharmony_ci    RETURN_ON_NULL(atlas);
1901cb93a386Sopenharmony_ci    if (count <= 0) {
1902cb93a386Sopenharmony_ci        return;
1903cb93a386Sopenharmony_ci    }
1904cb93a386Sopenharmony_ci    SkASSERT(atlas);
1905cb93a386Sopenharmony_ci    SkASSERT(tex);
1906cb93a386Sopenharmony_ci    this->onDrawAtlas2(atlas, xform, tex, colors, count, mode, sampling, cull, paint);
1907cb93a386Sopenharmony_ci}
1908cb93a386Sopenharmony_ci
1909cb93a386Sopenharmony_civoid SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1910cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1911cb93a386Sopenharmony_ci    if (key) {
1912cb93a386Sopenharmony_ci        this->onDrawAnnotation(rect, key, value);
1913cb93a386Sopenharmony_ci    }
1914cb93a386Sopenharmony_ci}
1915cb93a386Sopenharmony_ci
1916cb93a386Sopenharmony_civoid SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
1917cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1918cb93a386Sopenharmony_ci    this->onDrawShadowRec(path, rec);
1919cb93a386Sopenharmony_ci}
1920cb93a386Sopenharmony_ci
1921cb93a386Sopenharmony_civoid SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1922cb93a386Sopenharmony_ci    // We don't test quickReject because the shadow outsets the path's bounds.
1923cb93a386Sopenharmony_ci    // TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here?
1924cb93a386Sopenharmony_ci    if (!this->predrawNotify()) {
1925cb93a386Sopenharmony_ci        return;
1926cb93a386Sopenharmony_ci    }
1927cb93a386Sopenharmony_ci    this->topDevice()->drawShadow(path, rec);
1928cb93a386Sopenharmony_ci}
1929cb93a386Sopenharmony_ci
1930cb93a386Sopenharmony_civoid SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
1931cb93a386Sopenharmony_ci                                           QuadAAFlags aaFlags, const SkColor4f& color,
1932cb93a386Sopenharmony_ci                                           SkBlendMode mode) {
1933cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1934cb93a386Sopenharmony_ci    // Make sure the rect is sorted before passing it along
1935cb93a386Sopenharmony_ci    this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
1936cb93a386Sopenharmony_ci}
1937cb93a386Sopenharmony_ci
1938cb93a386Sopenharmony_civoid SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
1939cb93a386Sopenharmony_ci                                               const SkPoint dstClips[],
1940cb93a386Sopenharmony_ci                                               const SkMatrix preViewMatrices[],
1941cb93a386Sopenharmony_ci                                               const SkSamplingOptions& sampling,
1942cb93a386Sopenharmony_ci                                               const SkPaint* paint,
1943cb93a386Sopenharmony_ci                                               SrcRectConstraint constraint) {
1944cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
1945cb93a386Sopenharmony_ci    this->onDrawEdgeAAImageSet2(imageSet, cnt, dstClips, preViewMatrices, sampling, paint,
1946cb93a386Sopenharmony_ci                                constraint);
1947cb93a386Sopenharmony_ci}
1948cb93a386Sopenharmony_ci
1949cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
1950cb93a386Sopenharmony_ci//  These are the virtual drawing methods
1951cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
1952cb93a386Sopenharmony_ci
1953cb93a386Sopenharmony_civoid SkCanvas::onDiscard() {
1954cb93a386Sopenharmony_ci    if (fSurfaceBase) {
1955cb93a386Sopenharmony_ci        sk_ignore_unused_variable(fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode));
1956cb93a386Sopenharmony_ci    }
1957cb93a386Sopenharmony_ci}
1958cb93a386Sopenharmony_ci
1959cb93a386Sopenharmony_civoid SkCanvas::onDrawPaint(const SkPaint& paint) {
1960cb93a386Sopenharmony_ci    this->internalDrawPaint(paint);
1961cb93a386Sopenharmony_ci}
1962cb93a386Sopenharmony_ci
1963cb93a386Sopenharmony_civoid SkCanvas::internalDrawPaint(const SkPaint& paint) {
1964cb93a386Sopenharmony_ci    // drawPaint does not call internalQuickReject() because computing its geometry is not free
1965cb93a386Sopenharmony_ci    // (see getLocalClipBounds(), and the two conditions below are sufficient.
1966cb93a386Sopenharmony_ci    if (paint.nothingToDraw() || this->isClipEmpty()) {
1967cb93a386Sopenharmony_ci        return;
1968cb93a386Sopenharmony_ci    }
1969cb93a386Sopenharmony_ci
1970cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, nullptr, CheckForOverwrite::kYes);
1971cb93a386Sopenharmony_ci    if (layer) {
1972cb93a386Sopenharmony_ci        this->topDevice()->drawPaint(layer->paint());
1973cb93a386Sopenharmony_ci    }
1974cb93a386Sopenharmony_ci}
1975cb93a386Sopenharmony_ci
1976cb93a386Sopenharmony_civoid SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1977cb93a386Sopenharmony_ci                            const SkPaint& paint) {
1978cb93a386Sopenharmony_ci    if ((long)count <= 0 || paint.nothingToDraw()) {
1979cb93a386Sopenharmony_ci        return;
1980cb93a386Sopenharmony_ci    }
1981cb93a386Sopenharmony_ci    SkASSERT(pts != nullptr);
1982cb93a386Sopenharmony_ci
1983cb93a386Sopenharmony_ci    SkRect bounds;
1984cb93a386Sopenharmony_ci    // Compute bounds from points (common for drawing a single line)
1985cb93a386Sopenharmony_ci    if (count == 2) {
1986cb93a386Sopenharmony_ci        bounds.set(pts[0], pts[1]);
1987cb93a386Sopenharmony_ci    } else {
1988cb93a386Sopenharmony_ci        bounds.setBounds(pts, SkToInt(count));
1989cb93a386Sopenharmony_ci    }
1990cb93a386Sopenharmony_ci
1991cb93a386Sopenharmony_ci    // Enforce paint style matches implicit behavior of drawPoints
1992cb93a386Sopenharmony_ci    SkPaint strokePaint = paint;
1993cb93a386Sopenharmony_ci    strokePaint.setStyle(SkPaint::kStroke_Style);
1994cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, strokePaint)) {
1995cb93a386Sopenharmony_ci        return;
1996cb93a386Sopenharmony_ci    }
1997cb93a386Sopenharmony_ci
1998cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, strokePaint, &bounds);
1999cb93a386Sopenharmony_ci    if (layer) {
2000cb93a386Sopenharmony_ci        this->topDevice()->drawPoints(mode, count, pts, layer->paint());
2001cb93a386Sopenharmony_ci    }
2002cb93a386Sopenharmony_ci}
2003cb93a386Sopenharmony_ci
2004cb93a386Sopenharmony_civoid SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2005cb93a386Sopenharmony_ci    SkASSERT(r.isSorted());
2006cb93a386Sopenharmony_ci    if (this->internalQuickReject(r, paint)) {
2007cb93a386Sopenharmony_ci        return;
2008cb93a386Sopenharmony_ci    }
2009cb93a386Sopenharmony_ci
2010cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &r, CheckForOverwrite::kYes);
2011cb93a386Sopenharmony_ci    if (layer) {
2012cb93a386Sopenharmony_ci        this->topDevice()->drawRect(r, layer->paint());
2013cb93a386Sopenharmony_ci    }
2014cb93a386Sopenharmony_ci}
2015cb93a386Sopenharmony_ci
2016cb93a386Sopenharmony_civoid SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2017cb93a386Sopenharmony_ci    const SkRect bounds = SkRect::Make(region.getBounds());
2018cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, paint)) {
2019cb93a386Sopenharmony_ci        return;
2020cb93a386Sopenharmony_ci    }
2021cb93a386Sopenharmony_ci
2022cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &bounds);
2023cb93a386Sopenharmony_ci    if (layer) {
2024cb93a386Sopenharmony_ci        this->topDevice()->drawRegion(region, layer->paint());
2025cb93a386Sopenharmony_ci    }
2026cb93a386Sopenharmony_ci}
2027cb93a386Sopenharmony_ci
2028cb93a386Sopenharmony_civoid SkCanvas::onDrawBehind(const SkPaint& paint) {
2029cb93a386Sopenharmony_ci    SkBaseDevice* dev = this->topDevice();
2030cb93a386Sopenharmony_ci    if (!dev) {
2031cb93a386Sopenharmony_ci        return;
2032cb93a386Sopenharmony_ci    }
2033cb93a386Sopenharmony_ci
2034cb93a386Sopenharmony_ci    SkIRect bounds;
2035cb93a386Sopenharmony_ci    SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2036cb93a386Sopenharmony_ci    for (;;) {
2037cb93a386Sopenharmony_ci        const MCRec* rec = (const MCRec*)iter.prev();
2038cb93a386Sopenharmony_ci        if (!rec) {
2039cb93a386Sopenharmony_ci            return; // no backimages, so nothing to draw
2040cb93a386Sopenharmony_ci        }
2041cb93a386Sopenharmony_ci        if (rec->fBackImage) {
2042cb93a386Sopenharmony_ci            // drawBehind should only have been called when the saveBehind record is active;
2043cb93a386Sopenharmony_ci            // if this fails, it means a real saveLayer was made w/o being restored first.
2044cb93a386Sopenharmony_ci            SkASSERT(dev == rec->fDevice);
2045cb93a386Sopenharmony_ci            bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2046cb93a386Sopenharmony_ci                                       rec->fBackImage->fImage->width(),
2047cb93a386Sopenharmony_ci                                       rec->fBackImage->fImage->height());
2048cb93a386Sopenharmony_ci            break;
2049cb93a386Sopenharmony_ci        }
2050cb93a386Sopenharmony_ci    }
2051cb93a386Sopenharmony_ci
2052cb93a386Sopenharmony_ci    // The backimage location (and thus bounds) were defined in the device's space, so mark it
2053cb93a386Sopenharmony_ci    // as a clip. We use a clip instead of just drawing a rect in case the paint has an image
2054cb93a386Sopenharmony_ci    // filter on it (which is applied before any auto-layer so the filter is clipped).
2055cb93a386Sopenharmony_ci    dev->save();
2056cb93a386Sopenharmony_ci    {
2057cb93a386Sopenharmony_ci        // We also have to temporarily whack the device matrix since clipRegion is affected by the
2058cb93a386Sopenharmony_ci        // global-to-device matrix and clipRect is affected by the local-to-device.
2059cb93a386Sopenharmony_ci        SkAutoDeviceTransformRestore adtr(dev, SkMatrix::I());
2060cb93a386Sopenharmony_ci        dev->clipRect(SkRect::Make(bounds), SkClipOp::kIntersect, /* aa */ false);
2061cb93a386Sopenharmony_ci        // ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly.
2062cb93a386Sopenharmony_ci    }
2063cb93a386Sopenharmony_ci
2064cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint);
2065cb93a386Sopenharmony_ci    if (layer) {
2066cb93a386Sopenharmony_ci        this->topDevice()->drawPaint(layer->paint());
2067cb93a386Sopenharmony_ci    }
2068cb93a386Sopenharmony_ci
2069cb93a386Sopenharmony_ci    dev->restore(fMCRec->fMatrix);
2070cb93a386Sopenharmony_ci}
2071cb93a386Sopenharmony_ci
2072cb93a386Sopenharmony_civoid SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2073cb93a386Sopenharmony_ci    SkASSERT(oval.isSorted());
2074cb93a386Sopenharmony_ci    if (this->internalQuickReject(oval, paint)) {
2075cb93a386Sopenharmony_ci        return;
2076cb93a386Sopenharmony_ci    }
2077cb93a386Sopenharmony_ci
2078cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &oval);
2079cb93a386Sopenharmony_ci    if (layer) {
2080cb93a386Sopenharmony_ci        this->topDevice()->drawOval(oval, layer->paint());
2081cb93a386Sopenharmony_ci    }
2082cb93a386Sopenharmony_ci}
2083cb93a386Sopenharmony_ci
2084cb93a386Sopenharmony_civoid SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2085cb93a386Sopenharmony_ci                         SkScalar sweepAngle, bool useCenter,
2086cb93a386Sopenharmony_ci                         const SkPaint& paint) {
2087cb93a386Sopenharmony_ci    SkASSERT(oval.isSorted());
2088cb93a386Sopenharmony_ci    if (this->internalQuickReject(oval, paint)) {
2089cb93a386Sopenharmony_ci        return;
2090cb93a386Sopenharmony_ci    }
2091cb93a386Sopenharmony_ci
2092cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &oval);
2093cb93a386Sopenharmony_ci    if (layer) {
2094cb93a386Sopenharmony_ci        this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer->paint());
2095cb93a386Sopenharmony_ci    }
2096cb93a386Sopenharmony_ci}
2097cb93a386Sopenharmony_ci
2098cb93a386Sopenharmony_civoid SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2099cb93a386Sopenharmony_ci    const SkRect& bounds = rrect.getBounds();
2100cb93a386Sopenharmony_ci
2101cb93a386Sopenharmony_ci    // Delegating to simpler draw operations
2102cb93a386Sopenharmony_ci    if (rrect.isRect()) {
2103cb93a386Sopenharmony_ci        // call the non-virtual version
2104cb93a386Sopenharmony_ci        this->SkCanvas::drawRect(bounds, paint);
2105cb93a386Sopenharmony_ci        return;
2106cb93a386Sopenharmony_ci    } else if (rrect.isOval()) {
2107cb93a386Sopenharmony_ci        // call the non-virtual version
2108cb93a386Sopenharmony_ci        this->SkCanvas::drawOval(bounds, paint);
2109cb93a386Sopenharmony_ci        return;
2110cb93a386Sopenharmony_ci    }
2111cb93a386Sopenharmony_ci
2112cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, paint)) {
2113cb93a386Sopenharmony_ci        return;
2114cb93a386Sopenharmony_ci    }
2115cb93a386Sopenharmony_ci
2116cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &bounds);
2117cb93a386Sopenharmony_ci    if (layer) {
2118cb93a386Sopenharmony_ci        this->topDevice()->drawRRect(rrect, layer->paint());
2119cb93a386Sopenharmony_ci    }
2120cb93a386Sopenharmony_ci}
2121cb93a386Sopenharmony_ci
2122cb93a386Sopenharmony_civoid SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2123cb93a386Sopenharmony_ci    const SkRect& bounds = outer.getBounds();
2124cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, paint)) {
2125cb93a386Sopenharmony_ci        return;
2126cb93a386Sopenharmony_ci    }
2127cb93a386Sopenharmony_ci
2128cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &bounds);
2129cb93a386Sopenharmony_ci    if (layer) {
2130cb93a386Sopenharmony_ci        this->topDevice()->drawDRRect(outer, inner, layer->paint());
2131cb93a386Sopenharmony_ci    }
2132cb93a386Sopenharmony_ci}
2133cb93a386Sopenharmony_ci
2134cb93a386Sopenharmony_civoid SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2135cb93a386Sopenharmony_ci    if (!path.isFinite()) {
2136cb93a386Sopenharmony_ci        return;
2137cb93a386Sopenharmony_ci    }
2138cb93a386Sopenharmony_ci
2139cb93a386Sopenharmony_ci    const SkRect& pathBounds = path.getBounds();
2140cb93a386Sopenharmony_ci    if (!path.isInverseFillType() && this->internalQuickReject(pathBounds, paint)) {
2141cb93a386Sopenharmony_ci        return;
2142cb93a386Sopenharmony_ci    }
2143cb93a386Sopenharmony_ci    if (path.isInverseFillType() && pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2144cb93a386Sopenharmony_ci        this->internalDrawPaint(paint);
2145cb93a386Sopenharmony_ci        return;
2146cb93a386Sopenharmony_ci    }
2147cb93a386Sopenharmony_ci
2148cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &pathBounds);
2149cb93a386Sopenharmony_ci    if (layer) {
2150cb93a386Sopenharmony_ci        this->topDevice()->drawPath(path, layer->paint());
2151cb93a386Sopenharmony_ci    }
2152cb93a386Sopenharmony_ci}
2153cb93a386Sopenharmony_ci
2154cb93a386Sopenharmony_cibool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h,
2155cb93a386Sopenharmony_ci                                     const SkSamplingOptions& sampling, const SkPaint& paint) {
2156cb93a386Sopenharmony_ci    if (!paint.getImageFilter()) {
2157cb93a386Sopenharmony_ci        return false;
2158cb93a386Sopenharmony_ci    }
2159cb93a386Sopenharmony_ci
2160cb93a386Sopenharmony_ci    const SkMatrix& ctm = this->getTotalMatrix();
2161cb93a386Sopenharmony_ci    if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), sampling, paint)) {
2162cb93a386Sopenharmony_ci        return false;
2163cb93a386Sopenharmony_ci    }
2164cb93a386Sopenharmony_ci
2165cb93a386Sopenharmony_ci    // The other paint effects need to be applied before the image filter, but the sprite draw
2166cb93a386Sopenharmony_ci    // applies the filter explicitly first.
2167cb93a386Sopenharmony_ci    if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) {
2168cb93a386Sopenharmony_ci        return false;
2169cb93a386Sopenharmony_ci    }
2170cb93a386Sopenharmony_ci    // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2171cb93a386Sopenharmony_ci    // Once we can filter and the filter will return a result larger than itself, we should be
2172cb93a386Sopenharmony_ci    // able to remove this constraint.
2173cb93a386Sopenharmony_ci    // skbug.com/4526
2174cb93a386Sopenharmony_ci    //
2175cb93a386Sopenharmony_ci    SkPoint pt;
2176cb93a386Sopenharmony_ci    ctm.mapXY(x, y, &pt);
2177cb93a386Sopenharmony_ci    SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2178cb93a386Sopenharmony_ci    // quick bounds have been outset by 1px compared to overall device bounds, so this makes the
2179cb93a386Sopenharmony_ci    // contains check equivalent to between ir and device bounds
2180cb93a386Sopenharmony_ci    ir.outset(1, 1);
2181cb93a386Sopenharmony_ci    return ir.contains(fQuickRejectBounds);
2182cb93a386Sopenharmony_ci}
2183cb93a386Sopenharmony_ci
2184cb93a386Sopenharmony_ci// Clean-up the paint to match the drawing semantics for drawImage et al. (skbug.com/7804).
2185cb93a386Sopenharmony_cistatic SkPaint clean_paint_for_drawImage(const SkPaint* paint) {
2186cb93a386Sopenharmony_ci    SkPaint cleaned;
2187cb93a386Sopenharmony_ci    if (paint) {
2188cb93a386Sopenharmony_ci        cleaned = *paint;
2189cb93a386Sopenharmony_ci        cleaned.setStyle(SkPaint::kFill_Style);
2190cb93a386Sopenharmony_ci        cleaned.setPathEffect(nullptr);
2191cb93a386Sopenharmony_ci    }
2192cb93a386Sopenharmony_ci    return cleaned;
2193cb93a386Sopenharmony_ci}
2194cb93a386Sopenharmony_ci
2195cb93a386Sopenharmony_ci// drawVertices fills triangles and ignores mask filter and path effect,
2196cb93a386Sopenharmony_ci// so canonicalize the paint before checking quick reject.
2197cb93a386Sopenharmony_cistatic SkPaint clean_paint_for_drawVertices(SkPaint paint) {
2198cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kFill_Style);
2199cb93a386Sopenharmony_ci    paint.setMaskFilter(nullptr);
2200cb93a386Sopenharmony_ci    paint.setPathEffect(nullptr);
2201cb93a386Sopenharmony_ci    return paint;
2202cb93a386Sopenharmony_ci}
2203cb93a386Sopenharmony_ci
2204cb93a386Sopenharmony_civoid SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
2205cb93a386Sopenharmony_ci                            const SkSamplingOptions& sampling, const SkPaint* paint) {
2206cb93a386Sopenharmony_ci    SkPaint realPaint = clean_paint_for_drawImage(paint);
2207cb93a386Sopenharmony_ci
2208cb93a386Sopenharmony_ci    SkRect bounds = SkRect::MakeXYWH(x, y, image->width(), image->height());
2209cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, realPaint)) {
2210cb93a386Sopenharmony_ci        return;
2211cb93a386Sopenharmony_ci    }
2212cb93a386Sopenharmony_ci
2213cb93a386Sopenharmony_ci    if (realPaint.getImageFilter() &&
2214cb93a386Sopenharmony_ci        this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) &&
2215cb93a386Sopenharmony_ci        !image_to_color_filter(&realPaint)) {
2216cb93a386Sopenharmony_ci        // Evaluate the image filter directly on the input image and then draw the result, instead
2217cb93a386Sopenharmony_ci        // of first drawing the image to a temporary layer and filtering.
2218cb93a386Sopenharmony_ci        SkBaseDevice* device = this->topDevice();
2219cb93a386Sopenharmony_ci        sk_sp<SkSpecialImage> special;
2220cb93a386Sopenharmony_ci        if ((special = device->makeSpecial(image))) {
2221cb93a386Sopenharmony_ci            sk_sp<SkImageFilter> filter = realPaint.refImageFilter();
2222cb93a386Sopenharmony_ci            realPaint.setImageFilter(nullptr);
2223cb93a386Sopenharmony_ci
2224cb93a386Sopenharmony_ci            // TODO(michaelludwig) - Many filters could probably be evaluated like this even if the
2225cb93a386Sopenharmony_ci            // CTM is not translate-only; the post-transformation of the filtered image by the CTM
2226cb93a386Sopenharmony_ci            // will probably look just as good and not require an extra layer.
2227cb93a386Sopenharmony_ci            // TODO(michaelludwig) - Once image filter implementations can support source images
2228cb93a386Sopenharmony_ci            // with non-(0,0) origins, we can just mark the origin as (x,y) instead of doing a
2229cb93a386Sopenharmony_ci            // pre-concat here.
2230cb93a386Sopenharmony_ci            SkMatrix layerToDevice = device->localToDevice();
2231cb93a386Sopenharmony_ci            layerToDevice.preTranslate(x, y);
2232cb93a386Sopenharmony_ci            skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y));
2233cb93a386Sopenharmony_ci
2234cb93a386Sopenharmony_ci            if (this->predrawNotify()) {
2235cb93a386Sopenharmony_ci                device->drawFilteredImage(mapping, special.get(), filter.get(), sampling,realPaint);
2236cb93a386Sopenharmony_ci            }
2237cb93a386Sopenharmony_ci            return;
2238cb93a386Sopenharmony_ci        } // else fall through to regular drawing path
2239cb93a386Sopenharmony_ci    }
2240cb93a386Sopenharmony_ci
2241cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, realPaint, &bounds);
2242cb93a386Sopenharmony_ci    if (layer) {
2243cb93a386Sopenharmony_ci        this->topDevice()->drawImageRect(image, nullptr, bounds, sampling,
2244cb93a386Sopenharmony_ci                                         layer->paint(), kStrict_SrcRectConstraint);
2245cb93a386Sopenharmony_ci    }
2246cb93a386Sopenharmony_ci}
2247cb93a386Sopenharmony_ci
2248cb93a386Sopenharmony_civoid SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
2249cb93a386Sopenharmony_ci                                const SkSamplingOptions& sampling, const SkPaint* paint,
2250cb93a386Sopenharmony_ci                                SrcRectConstraint constraint) {
2251cb93a386Sopenharmony_ci    SkPaint realPaint = clean_paint_for_drawImage(paint);
2252cb93a386Sopenharmony_ci
2253cb93a386Sopenharmony_ci    if (this->internalQuickReject(dst, realPaint)) {
2254cb93a386Sopenharmony_ci        return;
2255cb93a386Sopenharmony_ci    }
2256cb93a386Sopenharmony_ci
2257cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, realPaint, &dst, CheckForOverwrite::kYes,
2258cb93a386Sopenharmony_ci                                   image->isOpaque() ? kOpaque_ShaderOverrideOpacity
2259cb93a386Sopenharmony_ci                                                     : kNotOpaque_ShaderOverrideOpacity);
2260cb93a386Sopenharmony_ci    if (layer) {
2261cb93a386Sopenharmony_ci        this->topDevice()->drawImageRect(image, &src, dst, sampling, layer->paint(), constraint);
2262cb93a386Sopenharmony_ci    }
2263cb93a386Sopenharmony_ci}
2264cb93a386Sopenharmony_ci
2265cb93a386Sopenharmony_civoid SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2266cb93a386Sopenharmony_ci                                   SkFilterMode filter, const SkPaint* paint) {
2267cb93a386Sopenharmony_ci    SkPaint realPaint = clean_paint_for_drawImage(paint);
2268cb93a386Sopenharmony_ci
2269cb93a386Sopenharmony_ci    if (this->internalQuickReject(dst, realPaint)) {
2270cb93a386Sopenharmony_ci        return;
2271cb93a386Sopenharmony_ci    }
2272cb93a386Sopenharmony_ci
2273cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, realPaint, &dst);
2274cb93a386Sopenharmony_ci    if (layer) {
2275cb93a386Sopenharmony_ci        this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer->paint());
2276cb93a386Sopenharmony_ci    }
2277cb93a386Sopenharmony_ci}
2278cb93a386Sopenharmony_ci
2279cb93a386Sopenharmony_civoid SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y,
2280cb93a386Sopenharmony_ci                         const SkSamplingOptions& sampling, const SkPaint* paint) {
2281cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2282cb93a386Sopenharmony_ci    RETURN_ON_NULL(image);
2283cb93a386Sopenharmony_ci    this->onDrawImage2(image, x, y, sampling, paint);
2284cb93a386Sopenharmony_ci}
2285cb93a386Sopenharmony_ci
2286cb93a386Sopenharmony_civoid SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2287cb93a386Sopenharmony_ci                             const SkSamplingOptions& sampling, const SkPaint* paint,
2288cb93a386Sopenharmony_ci                             SrcRectConstraint constraint) {
2289cb93a386Sopenharmony_ci    RETURN_ON_NULL(image);
2290cb93a386Sopenharmony_ci    if (!fillable(dst) || !fillable(src)) {
2291cb93a386Sopenharmony_ci        return;
2292cb93a386Sopenharmony_ci    }
2293cb93a386Sopenharmony_ci    this->onDrawImageRect2(image, src, dst, sampling, paint, constraint);
2294cb93a386Sopenharmony_ci}
2295cb93a386Sopenharmony_ci
2296cb93a386Sopenharmony_civoid SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst,
2297cb93a386Sopenharmony_ci                             const SkSamplingOptions& sampling, const SkPaint* paint) {
2298cb93a386Sopenharmony_ci    RETURN_ON_NULL(image);
2299cb93a386Sopenharmony_ci    this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, sampling,
2300cb93a386Sopenharmony_ci                        paint, kFast_SrcRectConstraint);
2301cb93a386Sopenharmony_ci}
2302cb93a386Sopenharmony_ci
2303cb93a386Sopenharmony_civoid SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2304cb93a386Sopenharmony_ci                              const SkPaint& paint) {
2305cb93a386Sopenharmony_ci    auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(*blob, {x, y});
2306cb93a386Sopenharmony_ci    this->onDrawGlyphRunList(glyphRunList, paint);
2307cb93a386Sopenharmony_ci}
2308cb93a386Sopenharmony_ci
2309cb93a386Sopenharmony_civoid SkCanvas::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
2310cb93a386Sopenharmony_ci    SkRect bounds = glyphRunList.sourceBounds();
2311cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, paint)) {
2312cb93a386Sopenharmony_ci        return;
2313cb93a386Sopenharmony_ci    }
2314cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, paint, &bounds);
2315cb93a386Sopenharmony_ci    if (layer) {
2316cb93a386Sopenharmony_ci        this->topDevice()->drawGlyphRunList(glyphRunList, layer->paint());
2317cb93a386Sopenharmony_ci    }
2318cb93a386Sopenharmony_ci}
2319cb93a386Sopenharmony_ci
2320cb93a386Sopenharmony_ci// These call the (virtual) onDraw... method
2321cb93a386Sopenharmony_civoid SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2322cb93a386Sopenharmony_ci                              SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2323cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2324cb93a386Sopenharmony_ci    if (byteLength) {
2325cb93a386Sopenharmony_ci        sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2326cb93a386Sopenharmony_ci        const SkGlyphRunList& glyphRunList =
2327cb93a386Sopenharmony_ci            fScratchGlyphRunBuilder->textToGlyphRunList(
2328cb93a386Sopenharmony_ci                    font, paint, text, byteLength, {x, y}, encoding);
2329cb93a386Sopenharmony_ci        if (!glyphRunList.empty()) {
2330cb93a386Sopenharmony_ci            this->onDrawGlyphRunList(glyphRunList, paint);
2331cb93a386Sopenharmony_ci        }
2332cb93a386Sopenharmony_ci    }
2333cb93a386Sopenharmony_ci}
2334cb93a386Sopenharmony_ci
2335cb93a386Sopenharmony_civoid SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions,
2336cb93a386Sopenharmony_ci                          const uint32_t* clusters, int textByteCount, const char* utf8text,
2337cb93a386Sopenharmony_ci                          SkPoint origin, const SkFont& font, const SkPaint& paint) {
2338cb93a386Sopenharmony_ci    if (count <= 0) { return; }
2339cb93a386Sopenharmony_ci
2340cb93a386Sopenharmony_ci    SkGlyphRun glyphRun {
2341cb93a386Sopenharmony_ci            font,
2342cb93a386Sopenharmony_ci            SkMakeSpan(positions, count),
2343cb93a386Sopenharmony_ci            SkMakeSpan(glyphs, count),
2344cb93a386Sopenharmony_ci            SkMakeSpan(utf8text, textByteCount),
2345cb93a386Sopenharmony_ci            SkMakeSpan(clusters, count),
2346cb93a386Sopenharmony_ci            SkSpan<SkVector>()
2347cb93a386Sopenharmony_ci    };
2348cb93a386Sopenharmony_ci    SkGlyphRunList glyphRunList {
2349cb93a386Sopenharmony_ci            glyphRun,
2350cb93a386Sopenharmony_ci            glyphRun.sourceBounds(paint).makeOffset(origin),
2351cb93a386Sopenharmony_ci            origin
2352cb93a386Sopenharmony_ci    };
2353cb93a386Sopenharmony_ci    this->onDrawGlyphRunList(glyphRunList, paint);
2354cb93a386Sopenharmony_ci}
2355cb93a386Sopenharmony_ci
2356cb93a386Sopenharmony_civoid SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[],
2357cb93a386Sopenharmony_ci                          SkPoint origin, const SkFont& font, const SkPaint& paint) {
2358cb93a386Sopenharmony_ci    if (count <= 0) { return; }
2359cb93a386Sopenharmony_ci
2360cb93a386Sopenharmony_ci    SkGlyphRun glyphRun {
2361cb93a386Sopenharmony_ci        font,
2362cb93a386Sopenharmony_ci        SkMakeSpan(positions, count),
2363cb93a386Sopenharmony_ci        SkMakeSpan(glyphs, count),
2364cb93a386Sopenharmony_ci        SkSpan<const char>(),
2365cb93a386Sopenharmony_ci        SkSpan<const uint32_t>(),
2366cb93a386Sopenharmony_ci        SkSpan<SkVector>()
2367cb93a386Sopenharmony_ci    };
2368cb93a386Sopenharmony_ci    SkGlyphRunList glyphRunList {
2369cb93a386Sopenharmony_ci        glyphRun,
2370cb93a386Sopenharmony_ci        glyphRun.sourceBounds(paint).makeOffset(origin),
2371cb93a386Sopenharmony_ci        origin
2372cb93a386Sopenharmony_ci    };
2373cb93a386Sopenharmony_ci    this->onDrawGlyphRunList(glyphRunList, paint);
2374cb93a386Sopenharmony_ci}
2375cb93a386Sopenharmony_ci
2376cb93a386Sopenharmony_civoid SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[],
2377cb93a386Sopenharmony_ci                          SkPoint origin, const SkFont& font, const SkPaint& paint) {
2378cb93a386Sopenharmony_ci    if (count <= 0) { return; }
2379cb93a386Sopenharmony_ci
2380cb93a386Sopenharmony_ci    auto [positions, rotateScales] =
2381cb93a386Sopenharmony_ci            fScratchGlyphRunBuilder->convertRSXForm(SkMakeSpan(xforms, count));
2382cb93a386Sopenharmony_ci
2383cb93a386Sopenharmony_ci    SkGlyphRun glyphRun {
2384cb93a386Sopenharmony_ci            font,
2385cb93a386Sopenharmony_ci            positions,
2386cb93a386Sopenharmony_ci            SkMakeSpan(glyphs, count),
2387cb93a386Sopenharmony_ci            SkSpan<const char>(),
2388cb93a386Sopenharmony_ci            SkSpan<const uint32_t>(),
2389cb93a386Sopenharmony_ci            rotateScales
2390cb93a386Sopenharmony_ci    };
2391cb93a386Sopenharmony_ci    SkGlyphRunList glyphRunList {
2392cb93a386Sopenharmony_ci            glyphRun,
2393cb93a386Sopenharmony_ci            glyphRun.sourceBounds(paint).makeOffset(origin),
2394cb93a386Sopenharmony_ci            origin
2395cb93a386Sopenharmony_ci    };
2396cb93a386Sopenharmony_ci    this->onDrawGlyphRunList(glyphRunList, paint);
2397cb93a386Sopenharmony_ci}
2398cb93a386Sopenharmony_ci
2399cb93a386Sopenharmony_civoid SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2400cb93a386Sopenharmony_ci                            const SkPaint& paint) {
2401cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2402cb93a386Sopenharmony_ci    RETURN_ON_NULL(blob);
2403cb93a386Sopenharmony_ci    RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2404cb93a386Sopenharmony_ci
2405cb93a386Sopenharmony_ci    // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack.
2406cb93a386Sopenharmony_ci    // See chromium:1080481
2407cb93a386Sopenharmony_ci    // TODO: can consider unrolling a few at a time if this limit becomes a problem.
2408cb93a386Sopenharmony_ci    int totalGlyphCount = 0;
2409cb93a386Sopenharmony_ci    constexpr int kMaxGlyphCount = 1 << 21;
2410cb93a386Sopenharmony_ci    SkTextBlob::Iter i(*blob);
2411cb93a386Sopenharmony_ci    SkTextBlob::Iter::Run r;
2412cb93a386Sopenharmony_ci    while (i.next(&r)) {
2413cb93a386Sopenharmony_ci        int glyphsLeft = kMaxGlyphCount - totalGlyphCount;
2414cb93a386Sopenharmony_ci        RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft);
2415cb93a386Sopenharmony_ci        totalGlyphCount += r.fGlyphCount;
2416cb93a386Sopenharmony_ci    }
2417cb93a386Sopenharmony_ci    this->onDrawTextBlob(blob, x, y, paint);
2418cb93a386Sopenharmony_ci}
2419cb93a386Sopenharmony_ci
2420cb93a386Sopenharmony_civoid SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2421cb93a386Sopenharmony_ci                                    const SkPaint& paint) {
2422cb93a386Sopenharmony_ci    SkPaint simplePaint = clean_paint_for_drawVertices(paint);
2423cb93a386Sopenharmony_ci
2424cb93a386Sopenharmony_ci    const SkRect& bounds = vertices->bounds();
2425cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, simplePaint)) {
2426cb93a386Sopenharmony_ci        return;
2427cb93a386Sopenharmony_ci    }
2428cb93a386Sopenharmony_ci
2429cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, simplePaint, &bounds);
2430cb93a386Sopenharmony_ci    if (layer) {
2431cb93a386Sopenharmony_ci        this->topDevice()->drawVertices(vertices, bmode, layer->paint());
2432cb93a386Sopenharmony_ci    }
2433cb93a386Sopenharmony_ci}
2434cb93a386Sopenharmony_ci
2435cb93a386Sopenharmony_civoid SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2436cb93a386Sopenharmony_ci                         const SkPoint texCoords[4], SkBlendMode bmode,
2437cb93a386Sopenharmony_ci                         const SkPaint& paint) {
2438cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2439cb93a386Sopenharmony_ci    if (nullptr == cubics) {
2440cb93a386Sopenharmony_ci        return;
2441cb93a386Sopenharmony_ci    }
2442cb93a386Sopenharmony_ci
2443cb93a386Sopenharmony_ci    this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2444cb93a386Sopenharmony_ci}
2445cb93a386Sopenharmony_ci
2446cb93a386Sopenharmony_civoid SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2447cb93a386Sopenharmony_ci                           const SkPoint texCoords[4], SkBlendMode bmode,
2448cb93a386Sopenharmony_ci                           const SkPaint& paint) {
2449cb93a386Sopenharmony_ci    // drawPatch has the same behavior restrictions as drawVertices
2450cb93a386Sopenharmony_ci    SkPaint simplePaint = clean_paint_for_drawVertices(paint);
2451cb93a386Sopenharmony_ci
2452cb93a386Sopenharmony_ci    // Since a patch is always within the convex hull of the control points, we discard it when its
2453cb93a386Sopenharmony_ci    // bounding rectangle is completely outside the current clip.
2454cb93a386Sopenharmony_ci    SkRect bounds;
2455cb93a386Sopenharmony_ci    bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2456cb93a386Sopenharmony_ci    if (this->internalQuickReject(bounds, simplePaint)) {
2457cb93a386Sopenharmony_ci        return;
2458cb93a386Sopenharmony_ci    }
2459cb93a386Sopenharmony_ci
2460cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, simplePaint, &bounds);
2461cb93a386Sopenharmony_ci    if (layer) {
2462cb93a386Sopenharmony_ci        this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer->paint());
2463cb93a386Sopenharmony_ci    }
2464cb93a386Sopenharmony_ci}
2465cb93a386Sopenharmony_ci
2466cb93a386Sopenharmony_civoid SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2467cb93a386Sopenharmony_ci#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2468cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2469cb93a386Sopenharmony_ci#endif
2470cb93a386Sopenharmony_ci    RETURN_ON_NULL(dr);
2471cb93a386Sopenharmony_ci    if (x || y) {
2472cb93a386Sopenharmony_ci        SkMatrix matrix = SkMatrix::Translate(x, y);
2473cb93a386Sopenharmony_ci        this->onDrawDrawable(dr, &matrix);
2474cb93a386Sopenharmony_ci    } else {
2475cb93a386Sopenharmony_ci        this->onDrawDrawable(dr, nullptr);
2476cb93a386Sopenharmony_ci    }
2477cb93a386Sopenharmony_ci}
2478cb93a386Sopenharmony_ci
2479cb93a386Sopenharmony_civoid SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2480cb93a386Sopenharmony_ci#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2481cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2482cb93a386Sopenharmony_ci#endif
2483cb93a386Sopenharmony_ci    RETURN_ON_NULL(dr);
2484cb93a386Sopenharmony_ci    if (matrix && matrix->isIdentity()) {
2485cb93a386Sopenharmony_ci        matrix = nullptr;
2486cb93a386Sopenharmony_ci    }
2487cb93a386Sopenharmony_ci    this->onDrawDrawable(dr, matrix);
2488cb93a386Sopenharmony_ci}
2489cb93a386Sopenharmony_ci
2490cb93a386Sopenharmony_civoid SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2491cb93a386Sopenharmony_ci    // drawable bounds are no longer reliable (e.g. android displaylist)
2492cb93a386Sopenharmony_ci    // so don't use them for quick-reject
2493cb93a386Sopenharmony_ci    if (this->predrawNotify()) {
2494cb93a386Sopenharmony_ci        this->topDevice()->drawDrawable(dr, matrix, this);
2495cb93a386Sopenharmony_ci    }
2496cb93a386Sopenharmony_ci}
2497cb93a386Sopenharmony_ci
2498cb93a386Sopenharmony_civoid SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2499cb93a386Sopenharmony_ci                            const SkColor colors[], int count, SkBlendMode bmode,
2500cb93a386Sopenharmony_ci                            const SkSamplingOptions& sampling, const SkRect* cull,
2501cb93a386Sopenharmony_ci                            const SkPaint* paint) {
2502cb93a386Sopenharmony_ci    // drawAtlas is a combination of drawVertices and drawImage...
2503cb93a386Sopenharmony_ci    SkPaint realPaint = clean_paint_for_drawVertices(clean_paint_for_drawImage(paint));
2504cb93a386Sopenharmony_ci    realPaint.setShader(atlas->makeShader(sampling));
2505cb93a386Sopenharmony_ci
2506cb93a386Sopenharmony_ci    if (cull && this->internalQuickReject(*cull, realPaint)) {
2507cb93a386Sopenharmony_ci        return;
2508cb93a386Sopenharmony_ci    }
2509cb93a386Sopenharmony_ci
2510cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, realPaint);
2511cb93a386Sopenharmony_ci    if (layer) {
2512cb93a386Sopenharmony_ci        this->topDevice()->drawAtlas(xform, tex, colors, count, bmode, layer->paint());
2513cb93a386Sopenharmony_ci    }
2514cb93a386Sopenharmony_ci}
2515cb93a386Sopenharmony_ci
2516cb93a386Sopenharmony_civoid SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2517cb93a386Sopenharmony_ci    SkASSERT(key);
2518cb93a386Sopenharmony_ci
2519cb93a386Sopenharmony_ci    if (this->predrawNotify()) {
2520cb93a386Sopenharmony_ci        this->topDevice()->drawAnnotation(rect, key, value);
2521cb93a386Sopenharmony_ci    }
2522cb93a386Sopenharmony_ci}
2523cb93a386Sopenharmony_ci
2524cb93a386Sopenharmony_civoid SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2525cb93a386Sopenharmony_ci                                const SkColor4f& color, SkBlendMode mode) {
2526cb93a386Sopenharmony_ci    SkASSERT(r.isSorted());
2527cb93a386Sopenharmony_ci
2528cb93a386Sopenharmony_ci    SkPaint paint{color};
2529cb93a386Sopenharmony_ci    paint.setBlendMode(mode);
2530cb93a386Sopenharmony_ci    if (this->internalQuickReject(r, paint)) {
2531cb93a386Sopenharmony_ci        return;
2532cb93a386Sopenharmony_ci    }
2533cb93a386Sopenharmony_ci
2534cb93a386Sopenharmony_ci    if (this->predrawNotify()) {
2535cb93a386Sopenharmony_ci        this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2536cb93a386Sopenharmony_ci    }
2537cb93a386Sopenharmony_ci}
2538cb93a386Sopenharmony_ci
2539cb93a386Sopenharmony_civoid SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count,
2540cb93a386Sopenharmony_ci                                     const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2541cb93a386Sopenharmony_ci                                     const SkSamplingOptions& sampling, const SkPaint* paint,
2542cb93a386Sopenharmony_ci                                     SrcRectConstraint constraint) {
2543cb93a386Sopenharmony_ci    if (count <= 0) {
2544cb93a386Sopenharmony_ci        // Nothing to draw
2545cb93a386Sopenharmony_ci        return;
2546cb93a386Sopenharmony_ci    }
2547cb93a386Sopenharmony_ci
2548cb93a386Sopenharmony_ci    SkPaint realPaint = clean_paint_for_drawImage(paint);
2549cb93a386Sopenharmony_ci
2550cb93a386Sopenharmony_ci    // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2551cb93a386Sopenharmony_ci    // individual entries and Chromium's occlusion culling already makes it likely that at least one
2552cb93a386Sopenharmony_ci    // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2553cb93a386Sopenharmony_ci    // or we need it for the autolooper (since it greatly improves image filter perf).
2554cb93a386Sopenharmony_ci    bool needsAutoLayer = SkToBool(realPaint.getImageFilter());
2555cb93a386Sopenharmony_ci    bool setBoundsValid = count == 1 || needsAutoLayer;
2556cb93a386Sopenharmony_ci    SkRect setBounds = imageSet[0].fDstRect;
2557cb93a386Sopenharmony_ci    if (imageSet[0].fMatrixIndex >= 0) {
2558cb93a386Sopenharmony_ci        // Account for the per-entry transform that is applied prior to the CTM when drawing
2559cb93a386Sopenharmony_ci        preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2560cb93a386Sopenharmony_ci    }
2561cb93a386Sopenharmony_ci    if (needsAutoLayer) {
2562cb93a386Sopenharmony_ci        for (int i = 1; i < count; ++i) {
2563cb93a386Sopenharmony_ci            SkRect entryBounds = imageSet[i].fDstRect;
2564cb93a386Sopenharmony_ci            if (imageSet[i].fMatrixIndex >= 0) {
2565cb93a386Sopenharmony_ci                preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2566cb93a386Sopenharmony_ci            }
2567cb93a386Sopenharmony_ci            setBounds.joinPossiblyEmptyRect(entryBounds);
2568cb93a386Sopenharmony_ci        }
2569cb93a386Sopenharmony_ci    }
2570cb93a386Sopenharmony_ci
2571cb93a386Sopenharmony_ci    // If we happen to have the draw bounds, though, might as well check quickReject().
2572cb93a386Sopenharmony_ci    if (setBoundsValid && this->internalQuickReject(setBounds, realPaint)) {
2573cb93a386Sopenharmony_ci        return;
2574cb93a386Sopenharmony_ci    }
2575cb93a386Sopenharmony_ci
2576cb93a386Sopenharmony_ci    auto layer = this->aboutToDraw(this, realPaint, setBoundsValid ? &setBounds : nullptr);
2577cb93a386Sopenharmony_ci    if (layer) {
2578cb93a386Sopenharmony_ci        this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling,
2579cb93a386Sopenharmony_ci                                              layer->paint(), constraint);
2580cb93a386Sopenharmony_ci    }
2581cb93a386Sopenharmony_ci}
2582cb93a386Sopenharmony_ci
2583cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
2584cb93a386Sopenharmony_ci// These methods are NOT virtual, and therefore must call back into virtual
2585cb93a386Sopenharmony_ci// methods, rather than actually drawing themselves.
2586cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
2587cb93a386Sopenharmony_ci
2588cb93a386Sopenharmony_civoid SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) {
2589cb93a386Sopenharmony_ci    SkPaint paint;
2590cb93a386Sopenharmony_ci    paint.setColor(c);
2591cb93a386Sopenharmony_ci    paint.setBlendMode(mode);
2592cb93a386Sopenharmony_ci    this->drawPaint(paint);
2593cb93a386Sopenharmony_ci}
2594cb93a386Sopenharmony_ci
2595cb93a386Sopenharmony_civoid SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2596cb93a386Sopenharmony_ci    const SkPoint pt = { x, y };
2597cb93a386Sopenharmony_ci    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2598cb93a386Sopenharmony_ci}
2599cb93a386Sopenharmony_ci
2600cb93a386Sopenharmony_civoid SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2601cb93a386Sopenharmony_ci    SkPoint pts[2];
2602cb93a386Sopenharmony_ci    pts[0].set(x0, y0);
2603cb93a386Sopenharmony_ci    pts[1].set(x1, y1);
2604cb93a386Sopenharmony_ci    this->drawPoints(kLines_PointMode, 2, pts, paint);
2605cb93a386Sopenharmony_ci}
2606cb93a386Sopenharmony_ci
2607cb93a386Sopenharmony_civoid SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2608cb93a386Sopenharmony_ci    if (radius < 0) {
2609cb93a386Sopenharmony_ci        radius = 0;
2610cb93a386Sopenharmony_ci    }
2611cb93a386Sopenharmony_ci
2612cb93a386Sopenharmony_ci    SkRect  r;
2613cb93a386Sopenharmony_ci    r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2614cb93a386Sopenharmony_ci    this->drawOval(r, paint);
2615cb93a386Sopenharmony_ci}
2616cb93a386Sopenharmony_ci
2617cb93a386Sopenharmony_civoid SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2618cb93a386Sopenharmony_ci                             const SkPaint& paint) {
2619cb93a386Sopenharmony_ci    if (rx > 0 && ry > 0) {
2620cb93a386Sopenharmony_ci        SkRRect rrect;
2621cb93a386Sopenharmony_ci        rrect.setRectXY(r, rx, ry);
2622cb93a386Sopenharmony_ci        this->drawRRect(rrect, paint);
2623cb93a386Sopenharmony_ci    } else {
2624cb93a386Sopenharmony_ci        this->drawRect(r, paint);
2625cb93a386Sopenharmony_ci    }
2626cb93a386Sopenharmony_ci}
2627cb93a386Sopenharmony_ci
2628cb93a386Sopenharmony_civoid SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2629cb93a386Sopenharmony_ci                       SkScalar sweepAngle, bool useCenter,
2630cb93a386Sopenharmony_ci                       const SkPaint& paint) {
2631cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2632cb93a386Sopenharmony_ci    if (oval.isEmpty() || !sweepAngle) {
2633cb93a386Sopenharmony_ci        return;
2634cb93a386Sopenharmony_ci    }
2635cb93a386Sopenharmony_ci    this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2636cb93a386Sopenharmony_ci}
2637cb93a386Sopenharmony_ci
2638cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
2639cb93a386Sopenharmony_ci#ifdef SK_DISABLE_SKPICTURE
2640cb93a386Sopenharmony_civoid SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2641cb93a386Sopenharmony_ci
2642cb93a386Sopenharmony_ci
2643cb93a386Sopenharmony_civoid SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2644cb93a386Sopenharmony_ci                             const SkPaint* paint) {}
2645cb93a386Sopenharmony_ci#else
2646cb93a386Sopenharmony_ci
2647cb93a386Sopenharmony_civoid SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2648cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
2649cb93a386Sopenharmony_ci    RETURN_ON_NULL(picture);
2650cb93a386Sopenharmony_ci
2651cb93a386Sopenharmony_ci    if (matrix && matrix->isIdentity()) {
2652cb93a386Sopenharmony_ci        matrix = nullptr;
2653cb93a386Sopenharmony_ci    }
2654cb93a386Sopenharmony_ci    if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2655cb93a386Sopenharmony_ci        SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2656cb93a386Sopenharmony_ci        picture->playback(this);
2657cb93a386Sopenharmony_ci    } else {
2658cb93a386Sopenharmony_ci        this->onDrawPicture(picture, matrix, paint);
2659cb93a386Sopenharmony_ci    }
2660cb93a386Sopenharmony_ci}
2661cb93a386Sopenharmony_ci
2662cb93a386Sopenharmony_civoid SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2663cb93a386Sopenharmony_ci                             const SkPaint* paint) {
2664cb93a386Sopenharmony_ci    if (this->internalQuickReject(picture->cullRect(), paint ? *paint : SkPaint{}, matrix)) {
2665cb93a386Sopenharmony_ci        return;
2666cb93a386Sopenharmony_ci    }
2667cb93a386Sopenharmony_ci
2668cb93a386Sopenharmony_ci    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2669cb93a386Sopenharmony_ci    picture->playback(this);
2670cb93a386Sopenharmony_ci}
2671cb93a386Sopenharmony_ci#endif
2672cb93a386Sopenharmony_ci
2673cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
2674cb93a386Sopenharmony_ci
2675cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry() = default;
2676cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2677cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2678cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2679cb93a386Sopenharmony_ci
2680cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2681cb93a386Sopenharmony_ci                                       const SkRect& dstRect, int matrixIndex, float alpha,
2682cb93a386Sopenharmony_ci                                       unsigned aaFlags, bool hasClip)
2683cb93a386Sopenharmony_ci                : fImage(std::move(image))
2684cb93a386Sopenharmony_ci                , fSrcRect(srcRect)
2685cb93a386Sopenharmony_ci                , fDstRect(dstRect)
2686cb93a386Sopenharmony_ci                , fMatrixIndex(matrixIndex)
2687cb93a386Sopenharmony_ci                , fAlpha(alpha)
2688cb93a386Sopenharmony_ci                , fAAFlags(aaFlags)
2689cb93a386Sopenharmony_ci                , fHasClip(hasClip) {}
2690cb93a386Sopenharmony_ci
2691cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2692cb93a386Sopenharmony_ci                                       const SkRect& dstRect, float alpha, unsigned aaFlags)
2693cb93a386Sopenharmony_ci                : fImage(std::move(image))
2694cb93a386Sopenharmony_ci                , fSrcRect(srcRect)
2695cb93a386Sopenharmony_ci                , fDstRect(dstRect)
2696cb93a386Sopenharmony_ci                , fAlpha(alpha)
2697cb93a386Sopenharmony_ci                , fAAFlags(aaFlags) {}
2698cb93a386Sopenharmony_ci
2699cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
2700cb93a386Sopenharmony_ci
2701cb93a386Sopenharmony_cistd::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2702cb93a386Sopenharmony_ci                                                     size_t rowBytes, const SkSurfaceProps* props) {
2703cb93a386Sopenharmony_ci    if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
2704cb93a386Sopenharmony_ci        return nullptr;
2705cb93a386Sopenharmony_ci    }
2706cb93a386Sopenharmony_ci
2707cb93a386Sopenharmony_ci    SkBitmap bitmap;
2708cb93a386Sopenharmony_ci    if (!bitmap.installPixels(info, pixels, rowBytes)) {
2709cb93a386Sopenharmony_ci        return nullptr;
2710cb93a386Sopenharmony_ci    }
2711cb93a386Sopenharmony_ci
2712cb93a386Sopenharmony_ci    return props ?
2713cb93a386Sopenharmony_ci        std::make_unique<SkCanvas>(bitmap, *props) :
2714cb93a386Sopenharmony_ci        std::make_unique<SkCanvas>(bitmap);
2715cb93a386Sopenharmony_ci}
2716cb93a386Sopenharmony_ci
2717cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
2718cb93a386Sopenharmony_ci
2719cb93a386Sopenharmony_ciSkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2720cb93a386Sopenharmony_ci    : INHERITED(SkIRect::MakeWH(width, height)) {}
2721cb93a386Sopenharmony_ci
2722cb93a386Sopenharmony_ciSkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2723cb93a386Sopenharmony_ci    : INHERITED(bounds) {}
2724cb93a386Sopenharmony_ci
2725cb93a386Sopenharmony_ciSkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
2726cb93a386Sopenharmony_ci    : INHERITED(device) {}
2727cb93a386Sopenharmony_ci
2728cb93a386Sopenharmony_ciSkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2729cb93a386Sopenharmony_ci    (void)this->INHERITED::getSaveLayerStrategy(rec);
2730cb93a386Sopenharmony_ci    return kNoLayer_SaveLayerStrategy;
2731cb93a386Sopenharmony_ci}
2732cb93a386Sopenharmony_ci
2733cb93a386Sopenharmony_cibool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2734cb93a386Sopenharmony_ci    return false;
2735cb93a386Sopenharmony_ci}
2736cb93a386Sopenharmony_ci
2737cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
2738cb93a386Sopenharmony_ci
2739cb93a386Sopenharmony_cistatic_assert((int)SkRegion::kDifference_Op == (int)SkClipOp::kDifference, "");
2740cb93a386Sopenharmony_cistatic_assert((int)SkRegion::kIntersect_Op  == (int)SkClipOp::kIntersect, "");
2741cb93a386Sopenharmony_ci
2742cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
2743cb93a386Sopenharmony_ci
2744cb93a386Sopenharmony_ciSkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2745cb93a386Sopenharmony_ci    const SkBaseDevice* dev = this->topDevice();
2746cb93a386Sopenharmony_ci    if (fAllocator) {
2747cb93a386Sopenharmony_ci        SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2748cb93a386Sopenharmony_ci        SkIRect clip = dev->devClipBounds();
2749cb93a386Sopenharmony_ci        if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
2750cb93a386Sopenharmony_ci            clip.setEmpty();
2751cb93a386Sopenharmony_ci        }
2752cb93a386Sopenharmony_ci
2753cb93a386Sopenharmony_ci        fAllocator->updateHandle(handle, dev->localToDevice(), clip);
2754cb93a386Sopenharmony_ci        return handle;
2755cb93a386Sopenharmony_ci    }
2756cb93a386Sopenharmony_ci    return nullptr;
2757cb93a386Sopenharmony_ci}
2758cb93a386Sopenharmony_ci
2759cb93a386Sopenharmony_cistatic bool install(SkBitmap* bm, const SkImageInfo& info,
2760cb93a386Sopenharmony_ci                    const SkRasterHandleAllocator::Rec& rec) {
2761cb93a386Sopenharmony_ci    return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
2762cb93a386Sopenharmony_ci}
2763cb93a386Sopenharmony_ci
2764cb93a386Sopenharmony_ciSkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2765cb93a386Sopenharmony_ci                                                                     SkBitmap* bm) {
2766cb93a386Sopenharmony_ci    SkRasterHandleAllocator::Rec rec;
2767cb93a386Sopenharmony_ci    if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2768cb93a386Sopenharmony_ci        return nullptr;
2769cb93a386Sopenharmony_ci    }
2770cb93a386Sopenharmony_ci    return rec.fHandle;
2771cb93a386Sopenharmony_ci}
2772cb93a386Sopenharmony_ci
2773cb93a386Sopenharmony_cistd::unique_ptr<SkCanvas>
2774cb93a386Sopenharmony_ciSkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2775cb93a386Sopenharmony_ci                                    const SkImageInfo& info, const Rec* rec) {
2776cb93a386Sopenharmony_ci    if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
2777cb93a386Sopenharmony_ci        return nullptr;
2778cb93a386Sopenharmony_ci    }
2779cb93a386Sopenharmony_ci
2780cb93a386Sopenharmony_ci    SkBitmap bm;
2781cb93a386Sopenharmony_ci    Handle hndl;
2782cb93a386Sopenharmony_ci
2783cb93a386Sopenharmony_ci    if (rec) {
2784cb93a386Sopenharmony_ci        hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2785cb93a386Sopenharmony_ci    } else {
2786cb93a386Sopenharmony_ci        hndl = alloc->allocBitmap(info, &bm);
2787cb93a386Sopenharmony_ci    }
2788cb93a386Sopenharmony_ci    return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2789cb93a386Sopenharmony_ci}
2790cb93a386Sopenharmony_ci
2791cb93a386Sopenharmony_cistd::array<int, 2> SkCanvas::CalcHpsBluredImageDimension(const SkBlurArg& blurArg)
2792cb93a386Sopenharmony_ci{
2793cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU
2794cb93a386Sopenharmony_ci    auto dContext = GrAsDirectContext(this->recordingContext());
2795cb93a386Sopenharmony_ci    if (dContext) {
2796cb93a386Sopenharmony_ci        return dContext->CalcHpsBluredImageDimension(blurArg);
2797cb93a386Sopenharmony_ci    }
2798cb93a386Sopenharmony_ci#endif
2799cb93a386Sopenharmony_ci    return {0, 0};
2800cb93a386Sopenharmony_ci}
2801cb93a386Sopenharmony_ci
2802cb93a386Sopenharmony_cibool SkCanvas::onDrawBlurImage(const SkImage* image, const SkBlurArg& blurArg)
2803cb93a386Sopenharmony_ci{
2804cb93a386Sopenharmony_ci    return this->topDevice()->drawBlurImage(image, blurArg);
2805cb93a386Sopenharmony_ci}
2806cb93a386Sopenharmony_ci
2807cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
2808