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