xref: /aosp_15_r20/external/skia/modules/sksg/include/SkSGRenderNode.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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 SkSGRenderNode_DEFINED
9 #define SkSGRenderNode_DEFINED
10 
11 #include "include/core/SkBlender.h"
12 #include "include/core/SkColorFilter.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkShader.h"
16 #include "modules/sksg/include/SkSGNode.h"
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <utility>
21 #include <vector>
22 
23 class SkCanvas;
24 class SkImageFilter;
25 class SkPaint;
26 struct SkPoint;
27 struct SkRect;
28 
29 namespace sksg {
30 
31 /**
32  * Base class for nodes which can render to a canvas.
33  */
34 class RenderNode : public Node {
35 protected:
36     struct RenderContext;
37 
38 public:
39     // Render the node and its descendants to the canvas.
40     void render(SkCanvas*, const RenderContext* = nullptr) const;
41 
42     // Perform a front-to-back hit-test, and return the RenderNode located at |point|.
43     // Normally, hit-testing stops at leaf Draw nodes.
44     const RenderNode* nodeAt(const SkPoint& point) const;
45 
46     // Controls the visibility of the render node.  Invisible nodes are not rendered,
47     // but they still participate in revalidation.
48     bool isVisible() const;
49     void setVisible(bool);
50 
51 protected:
52     explicit RenderNode(uint32_t inval_traits = 0);
53 
54     virtual void onRender(SkCanvas*, const RenderContext*) const = 0;
55     virtual const RenderNode* onNodeAt(const SkPoint& p)   const = 0;
56 
57     // Paint property overrides.
58     // These are deferred until we can determine whether they can be applied to the individual
59     // draw paints, or whether they require content isolation (applied to a layer).
60     struct RenderContext {
61         sk_sp<SkColorFilter> fColorFilter;
62         sk_sp<SkShader>      fShader;
63         sk_sp<SkShader>      fMaskShader;
64         sk_sp<SkBlender>     fBlender;
65         SkMatrix             fShaderCTM = SkMatrix::I(),
66                              fMaskCTM   = SkMatrix::I();
67         float                fOpacity   = 1;
68 
69         // Returns true if the paint overrides require a layer when applied to non-atomic draws.
70         bool requiresIsolation() const;
71 
72         void modulatePaint(const SkMatrix& ctm, SkPaint*, bool is_layer_paint = false) const;
73     };
74 
75     class ScopedRenderContext final {
76     public:
77         ScopedRenderContext(SkCanvas*, const RenderContext*);
78         ~ScopedRenderContext();
79 
ScopedRenderContext(ScopedRenderContext && that)80         ScopedRenderContext(ScopedRenderContext&& that) { *this = std::move(that); }
81 
82         ScopedRenderContext& operator=(ScopedRenderContext&& that) {
83             fCanvas       = that.fCanvas;
84             fCtx          = std::move(that.fCtx);
85             fMaskShader   = std::move(that.fMaskShader);
86             fRestoreCount = that.fRestoreCount;
87 
88             // scope ownership is being transferred
89             that.fRestoreCount = -1;
90 
91             return *this;
92         }
93 
94         operator const RenderContext*  () const { return &fCtx; }
95         const RenderContext* operator->() const { return &fCtx; }
96 
97         // Add (cumulative) paint overrides to a render node sub-DAG.
98         ScopedRenderContext&& modulateOpacity(float opacity);
99         ScopedRenderContext&& modulateColorFilter(sk_sp<SkColorFilter>);
100         ScopedRenderContext&& modulateShader(sk_sp<SkShader>, const SkMatrix& shader_ctm);
101         ScopedRenderContext&& modulateMaskShader(sk_sp<SkShader>, const SkMatrix& ms_ctm);
102         ScopedRenderContext&& modulateBlender(sk_sp<SkBlender>);
103 
104         // Force content isolation for a node sub-DAG by applying the RenderContext
105         // overrides via a layer.
106         ScopedRenderContext&& setIsolation(const SkRect& bounds, const SkMatrix& ctm,
107                                            bool do_isolate);
108 
109         // Similarly, force content isolation by applying the RenderContext overrides and
110         // an image filter via a single layer.
111         ScopedRenderContext&& setFilterIsolation(const SkRect& bounds, const SkMatrix& ctm,
112                                                  sk_sp<SkImageFilter>);
113 
114     private:
115         // stack-only
116         void* operator new(size_t)        = delete;
117         void* operator new(size_t, void*) = delete;
118 
119         // Scopes cannot be copied.
120         ScopedRenderContext(const ScopedRenderContext&)            = delete;
121         ScopedRenderContext& operator=(const ScopedRenderContext&) = delete;
122 
123         SkCanvas*       fCanvas;
124         RenderContext   fCtx;
125         sk_sp<SkShader> fMaskShader; // to be applied at isolation layer restore time
126         int             fRestoreCount;
127     };
128 
129 private:
130     friend class ImageFilterEffect;
131 
132     using INHERITED = Node;
133 };
134 
135 /**
136  * Clients outside SkSG looking to implement custom render nodes,
137  * should derive from this class instead of RenderNode.  It handles
138  * various book-keeping, and provides a controlled extension point.
139  */
140 class CustomRenderNode : public RenderNode {
141 protected:
142     explicit CustomRenderNode(std::vector<sk_sp<RenderNode>>&& children);
143     ~CustomRenderNode() override;
144 
children()145     const std::vector<sk_sp<RenderNode>>& children() const { return fChildren; }
146 
147     bool hasChildrenInval() const;
148 
149 private:
150     std::vector<sk_sp<RenderNode>> fChildren;
151 
152     using INHERITED = RenderNode;
153 };
154 
155 } // namespace sksg
156 
157 #endif // SkSGRenderNode_DEFINED
158