xref: /aosp_15_r20/external/skia/src/core/SkCanvasPriv.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkCanvasPriv_DEFINED
9 #define SkCanvasPriv_DEFINED
10 
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkScalar.h"
15 #include "include/core/SkTileMode.h"
16 #include "include/private/base/SkDebug.h"
17 #include "include/private/base/SkNoncopyable.h"
18 
19 #include <cstddef>
20 
21 class SkDevice;
22 class SkImageFilter;
23 class SkMatrix;
24 class SkReadBuffer;
25 struct SkRect;
26 class SkWriteBuffer;
27 
28 class SkAutoCanvasMatrixPaint : SkNoncopyable {
29 public:
30     SkAutoCanvasMatrixPaint(SkCanvas*, const SkMatrix*, const SkPaint*, const SkRect& bounds);
31     ~SkAutoCanvasMatrixPaint();
32 
33 private:
34     SkCanvas*   fCanvas;
35     int         fSaveCount;
36 };
37 
38 class SkCanvasPriv {
39 public:
40     // The lattice has pointers directly into the readbuffer
41     static bool ReadLattice(SkReadBuffer&, SkCanvas::Lattice*);
42 
43     static void WriteLattice(SkWriteBuffer&, const SkCanvas::Lattice&);
44 
45     // return the byte-size of the lattice, even if the buffer is null
46     // storage must be 4-byte aligned
47     static size_t WriteLattice(void* storage, const SkCanvas::Lattice&);
48 
SaveBehind(SkCanvas * canvas,const SkRect * subset)49     static int SaveBehind(SkCanvas* canvas, const SkRect* subset) {
50         return canvas->only_axis_aligned_saveBehind(subset);
51     }
DrawBehind(SkCanvas * canvas,const SkPaint & paint)52     static void DrawBehind(SkCanvas* canvas, const SkPaint& paint) {
53         canvas->drawClippedToSaveBehind(paint);
54     }
55 
56     // Exposed for testing on non-Android framework builds
ResetClip(SkCanvas * canvas)57     static void ResetClip(SkCanvas* canvas) {
58         canvas->internal_private_resetClip();
59     }
60 
TopDevice(const SkCanvas * canvas)61     static SkDevice* TopDevice(const SkCanvas* canvas) {
62         return canvas->topDevice();
63     }
64 
65     // The experimental_DrawEdgeAAImageSet API accepts separate dstClips and preViewMatrices arrays,
66     // where entries refer into them, but no explicit size is provided. Given a set of entries,
67     // computes the minimum length for these arrays that would provide index access errors.
68     static void GetDstClipAndMatrixCounts(const SkCanvas::ImageSetEntry set[], int count,
69                                           int* totalDstClipCount, int* totalMatrixCount);
70 
71     static SkCanvas::SaveLayerRec ScaledBackdropLayer(const SkRect* bounds,
72                                                       const SkPaint* paint,
73                                                       const SkImageFilter* backdrop,
74                                                       SkScalar backdropScale,
75                                                       SkTileMode backdropTileMode,
76                                                       SkCanvas::SaveLayerFlags saveLayerFlags,
77                                                       SkCanvas::FilterSpan filters = {}) {
78         return SkCanvas::SaveLayerRec(bounds, paint, backdrop, nullptr, backdropScale,
79                                       backdropTileMode, saveLayerFlags, filters);
80     }
81 
82     static SkCanvas::SaveLayerRec ScaledBackdropLayer(const SkRect* bounds,
83                                                       const SkPaint* paint,
84                                                       const SkImageFilter* backdrop,
85                                                       SkScalar backdropScale,
86                                                       SkCanvas::SaveLayerFlags saveLayerFlags,
87                                                       SkCanvas::FilterSpan filters = {}) {
88         return ScaledBackdropLayer(bounds, paint, backdrop, backdropScale, SkTileMode::kClamp,
89                                    saveLayerFlags, filters);
90     }
91 
GetBackdropScaleFactor(const SkCanvas::SaveLayerRec & rec)92     static SkScalar GetBackdropScaleFactor(const SkCanvas::SaveLayerRec& rec) {
93         return rec.fExperimentalBackdropScale;
94     }
95 
SetBackdropScaleFactor(SkCanvas::SaveLayerRec * rec,SkScalar scale)96     static void SetBackdropScaleFactor(SkCanvas::SaveLayerRec* rec, SkScalar scale) {
97         rec->fExperimentalBackdropScale = scale;
98     }
99 
100     // Attempts to convert an image filter to its equivalent color filter, which if possible,
101     // modifies the paint to compose the image filter's color filter into the paint's color filter
102     // slot.
103     // Returns true if the paint has been modified.
104     // Requires the paint to have an image filter and the copy-on-write be initialized.
105     static bool ImageToColorFilter(SkPaint*);
106 };
107 
108 /**
109  *  This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
110  *  against the playback cost of recursing into the subpicture to get at its actual ops.
111  *
112  *  For now we pick a conservatively small value, though measurement (and other heuristics like
113  *  the type of ops contained) may justify changing this value.
114  */
115 constexpr int kMaxPictureOpsToUnrollInsteadOfRef = 1;
116 
117 /**
118  *  We implement ImageFilters and MaskFilters for a given draw by creating a layer, then applying
119  *  the filter to the pixels of that layer (its backing surface/image), and then we call restore()
120  *  to blend that layer to the main canvas.
121  *
122  *  If the paint has neither an image filter nor a mask filter, there will be no layer and paint()
123  *  returns the original without modification.
124  *
125  * NOTE: This works by assuming all sources of color and shading are represented by the SkPaint.
126  * Operations like drawImageRect must convert to an equivalent drawRect call if there's a mask
127  * filter, or otherwise ensure there are no mask filters (e.g. drawAtlas).
128  */
129 class AutoLayerForImageFilter {
130 public:
131     // `rawBounds` is the original bounds of the primitive about to be drawn, unmodified by the
132     // paint. It's used to determine the size of the offscreen layer for filters.
133     // If null, the clip will be used instead.
134     //
135     // If `skipMaskFilterLayer` is true, any SkMaskFilter on `paint` will be left as-is and is
136     // assumed to be handled by the SkDevice that handles the draw.
137     //
138     // Draw functions should use layer->paint() instead of the passed-in paint.
139     AutoLayerForImageFilter(SkCanvas* canvas,
140                             const SkPaint& paint,
141                             const SkRect* rawBounds,
142                             bool skipMaskFilterLayer);
143 
144     AutoLayerForImageFilter(const AutoLayerForImageFilter&) = delete;
145     AutoLayerForImageFilter& operator=(const AutoLayerForImageFilter&) = delete;
146     AutoLayerForImageFilter(AutoLayerForImageFilter&&);
147     AutoLayerForImageFilter& operator=(AutoLayerForImageFilter&&);
148 
149     ~AutoLayerForImageFilter();
150 
paint()151     const SkPaint& paint() const { return fPaint; }
152 
153     // This is public so that a canvas can attempt to specially handle mask filters, specifically
154     // for blurs, and then if the attempt fails fall back on a regular draw with the same autolayer.
155     void addMaskFilterLayer(const SkRect* drawBounds);
156 
157 private:
158     void addImageFilterLayer(const SkRect* drawBounds);
159 
160     void addLayer(const SkPaint& restorePaint, const SkRect* drawBounds, bool coverageOnly);
161 
162     SkPaint         fPaint;
163     SkCanvas*       fCanvas;
164     int             fTempLayersForFilters;
165 
166     SkDEBUGCODE(int fSaveCount;)
167 };
168 
169 #endif
170