• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "modules/sksg/include/SkSGRenderNode.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkImageFilter.h"
12 #include "include/core/SkPaint.h"
13 #include "modules/sksg/src/SkSGNodePriv.h"
14 
15 namespace sksg {
16 
17 namespace {
18 
19 enum Flags : uint8_t {
20     kInvisible_Flag = 1 << 0,
21 };
22 
23 } // namespace
24 
RenderNode(uint32_t inval_traits)25 RenderNode::RenderNode(uint32_t inval_traits) : INHERITED(inval_traits) {}
26 
isVisible() const27 bool RenderNode::isVisible() const {
28     return !(fNodeFlags & kInvisible_Flag);
29 }
30 
setVisible(bool v)31 void RenderNode::setVisible(bool v) {
32     if (v == this->isVisible()) {
33         return;
34     }
35 
36     this->invalidate();
37     fNodeFlags = v ? (fNodeFlags & ~kInvisible_Flag)
38                    : (fNodeFlags | kInvisible_Flag);
39 }
40 
render(SkCanvas * canvas,const RenderContext * ctx) const41 void RenderNode::render(SkCanvas* canvas, const RenderContext* ctx) const {
42     SkASSERT(!this->hasInval());
43     if (this->isVisible() && !this->bounds().isEmpty()) {
44         this->onRender(canvas, ctx);
45     }
46     SkASSERT(!this->hasInval());
47 }
48 
nodeAt(const SkPoint & p) const49 const RenderNode* RenderNode::nodeAt(const SkPoint& p) const {
50     return this->bounds().contains(p.x(), p.y()) ? this->onNodeAt(p) : nullptr;
51 }
52 
ScaleAlpha(SkAlpha alpha,float opacity)53 static SkAlpha ScaleAlpha(SkAlpha alpha, float opacity) {
54    return SkToU8(sk_float_round2int(alpha * opacity));
55 }
56 
ComputeDiffInverse(const SkMatrix & base,const SkMatrix & ctm)57 static SkMatrix ComputeDiffInverse(const SkMatrix& base, const SkMatrix& ctm) {
58     // Mask filters / shaders are declared to operate under a specific transform, but due to the
59     // deferral mechanism, other transformations might have been pushed to the state.
60     // We want to undo these transforms:
61     //
62     //   baseCTM x T = ctm
63     //
64     //   =>  T = Inv(baseCTM) x ctm
65     //
66     //   =>  Inv(T) = Inv(Inv(baseCTM) x ctm)
67     //
68     //   =>  Inv(T) = Inv(ctm) x baseCTM
69 
70     SkMatrix m;
71     if (base != ctm && ctm.invert(&m)) {
72         m.preConcat(base);
73     } else {
74         m = SkMatrix::I();
75     }
76 
77     return m;
78 }
79 
requiresIsolation() const80 bool RenderNode::RenderContext::requiresIsolation() const {
81     // Note: fShader is never applied on isolation layers.
82     return ScaleAlpha(SK_AlphaOPAQUE, fOpacity) != SK_AlphaOPAQUE
83         || fColorFilter
84         || fMaskFilter
85         || fBlendMode != SkBlendMode::kSrcOver;
86 }
87 
modulatePaint(const SkMatrix & ctm,SkPaint * paint) const88 void RenderNode::RenderContext::modulatePaint(const SkMatrix& ctm, SkPaint* paint) const {
89     paint->setAlpha(ScaleAlpha(paint->getAlpha(), fOpacity));
90     paint->setColorFilter(SkColorFilters::Compose(fColorFilter, paint->refColorFilter()));
91     if (fShader) {
92         paint->setShader(fShader->makeWithLocalMatrix(ComputeDiffInverse(fShaderCTM, ctm)));
93     }
94     if (fMaskFilter) {
95         paint->setMaskFilter(fMaskFilter->makeWithMatrix(ComputeDiffInverse(fMaskCTM, ctm)));
96     }
97     paint->setBlendMode(fBlendMode);
98 }
99 
ScopedRenderContext(SkCanvas * canvas,const RenderContext * ctx)100 RenderNode::ScopedRenderContext::ScopedRenderContext(SkCanvas* canvas, const RenderContext* ctx)
101     : fCanvas(canvas)
102     , fCtx(ctx ? *ctx : RenderContext())
103     , fRestoreCount(canvas->getSaveCount()) {}
104 
~ScopedRenderContext()105 RenderNode::ScopedRenderContext::~ScopedRenderContext() {
106     if (fRestoreCount >= 0) {
107         fCanvas->restoreToCount(fRestoreCount);
108     }
109 }
110 
111 RenderNode::ScopedRenderContext&&
modulateOpacity(float opacity)112 RenderNode::ScopedRenderContext::modulateOpacity(float opacity) {
113     SkASSERT(opacity >= 0 && opacity <= 1);
114     fCtx.fOpacity *= opacity;
115     return std::move(*this);
116 }
117 
118 RenderNode::ScopedRenderContext&&
modulateColorFilter(sk_sp<SkColorFilter> cf)119 RenderNode::ScopedRenderContext::modulateColorFilter(sk_sp<SkColorFilter> cf) {
120     fCtx.fColorFilter = SkColorFilters::Compose(std::move(fCtx.fColorFilter), std::move(cf));
121     return std::move(*this);
122 }
123 
124 RenderNode::ScopedRenderContext&&
modulateShader(sk_sp<SkShader> sh,const SkMatrix & shader_ctm)125 RenderNode::ScopedRenderContext::modulateShader(sk_sp<SkShader> sh, const SkMatrix& shader_ctm) {
126     // Topmost shader takes precedence.
127     if (!fCtx.fShader) {
128         fCtx.fShader = std::move(sh);
129         fCtx.fShaderCTM = shader_ctm;
130     }
131 
132     return std::move(*this);
133 }
134 
135 RenderNode::ScopedRenderContext&&
modulateMaskFilter(sk_sp<SkMaskFilter> mf,const SkMatrix & ctm)136 RenderNode::ScopedRenderContext::modulateMaskFilter(sk_sp<SkMaskFilter> mf, const SkMatrix& ctm) {
137     if (fCtx.fMaskFilter) {
138         // As we compose mask filters, use the relative transform T for the inner mask:
139         //
140         //   maskCTM x T = ctm
141         //
142         //   => T = Inv(maskCTM) x ctm
143         //
144         SkMatrix invMaskCTM;
145         if (mf && fCtx.fMaskCTM.invert(&invMaskCTM)) {
146             const auto relative_transform = SkMatrix::Concat(invMaskCTM, ctm);
147             fCtx.fMaskFilter = SkMaskFilter::MakeCompose(std::move(fCtx.fMaskFilter),
148                                                          mf->makeWithMatrix(relative_transform));
149         }
150     } else {
151         fCtx.fMaskFilter = std::move(mf);
152         fCtx.fMaskCTM    = ctm;
153     }
154 
155     return std::move(*this);
156 }
157 
158 RenderNode::ScopedRenderContext&&
modulateBlendMode(SkBlendMode mode)159 RenderNode::ScopedRenderContext::modulateBlendMode(SkBlendMode mode) {
160     fCtx.fBlendMode = mode;
161     return std::move(*this);
162 }
163 
164 RenderNode::ScopedRenderContext&&
setIsolation(const SkRect & bounds,const SkMatrix & ctm,bool isolation)165 RenderNode::ScopedRenderContext::setIsolation(const SkRect& bounds, const SkMatrix& ctm,
166                                               bool isolation) {
167     if (isolation && fCtx.requiresIsolation()) {
168         SkPaint layer_paint;
169         fCtx.modulatePaint(ctm, &layer_paint);
170         fCanvas->saveLayer(bounds, &layer_paint);
171 
172         // Reset only the props applied via isolation layers.
173         fCtx.fColorFilter = nullptr;
174         fCtx.fMaskFilter  = nullptr;
175         fCtx.fOpacity     = 1;
176         fCtx.fBlendMode   = SkBlendMode::kSrcOver;
177     }
178 
179     return std::move(*this);
180 }
181 
182 RenderNode::ScopedRenderContext&&
setFilterIsolation(const SkRect & bounds,const SkMatrix & ctm,sk_sp<SkImageFilter> filter)183 RenderNode::ScopedRenderContext::setFilterIsolation(const SkRect& bounds, const SkMatrix& ctm,
184                                                     sk_sp<SkImageFilter> filter) {
185     SkPaint layer_paint;
186     fCtx.modulatePaint(ctm, &layer_paint);
187 
188     SkASSERT(!layer_paint.getImageFilter());
189     layer_paint.setImageFilter(std::move(filter));
190     fCanvas->saveLayer(bounds, &layer_paint);
191     fCtx = RenderContext();
192 
193     return std::move(*this);
194 }
195 
CustomRenderNode(std::vector<sk_sp<RenderNode>> && children)196 CustomRenderNode::CustomRenderNode(std::vector<sk_sp<RenderNode>>&& children)
197     : INHERITED(kOverrideDamage_Trait)  // We cannot make any assumptions - override conservatively.
198     , fChildren(std::move(children)) {
199     for (const auto& child : fChildren) {
200         this->observeInval(child);
201     }
202 }
203 
~CustomRenderNode()204 CustomRenderNode::~CustomRenderNode() {
205     for (const auto& child : fChildren) {
206         this->unobserveInval(child);
207     }
208 }
209 
hasChildrenInval() const210 bool CustomRenderNode::hasChildrenInval() const {
211     for (const auto& child : fChildren) {
212         if (NodePriv::HasInval(child)) {
213             return true;
214         }
215     }
216 
217     return false;
218 }
219 
220 } // namespace sksg
221