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