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 "SkSGRenderNode.h"
9 
10 #include "SkCanvas.h"
11 #include "SkImageFilter.h"
12 #include "SkPaint.h"
13 
14 namespace sksg {
15 
RenderNode(uint32_t inval_traits)16 RenderNode::RenderNode(uint32_t inval_traits) : INHERITED(inval_traits) {}
17 
render(SkCanvas * canvas,const RenderContext * ctx) const18 void RenderNode::render(SkCanvas* canvas, const RenderContext* ctx) const {
19     SkASSERT(!this->hasInval());
20     if (!this->bounds().isEmpty()) {
21         this->onRender(canvas, ctx);
22     }
23 }
24 
nodeAt(const SkPoint & p) const25 const RenderNode* RenderNode::nodeAt(const SkPoint& p) const {
26     return this->bounds().contains(p.x(), p.y()) ? this->onNodeAt(p) : nullptr;
27 }
28 
modulatePaint(SkPaint * paint) const29 bool RenderNode::RenderContext::modulatePaint(SkPaint* paint) const {
30     const auto initial_alpha = paint->getAlpha(),
31                        alpha = SkToU8(sk_float_round2int(initial_alpha * fOpacity));
32 
33     if (alpha != initial_alpha || fColorFilter || fBlendMode != paint->getBlendMode()) {
34         paint->setAlpha(alpha);
35         paint->setColorFilter(SkColorFilter::MakeComposeFilter(fColorFilter,
36                                                                paint->refColorFilter()));
37         paint->setBlendMode(fBlendMode);
38         return true;
39     }
40 
41     return false;
42 }
43 
ScopedRenderContext(SkCanvas * canvas,const RenderContext * ctx)44 RenderNode::ScopedRenderContext::ScopedRenderContext(SkCanvas* canvas, const RenderContext* ctx)
45     : fCanvas(canvas)
46     , fCtx(ctx ? *ctx : RenderContext())
47     , fRestoreCount(canvas->getSaveCount()) {}
48 
~ScopedRenderContext()49 RenderNode::ScopedRenderContext::~ScopedRenderContext() {
50     if (fRestoreCount >= 0) {
51         fCanvas->restoreToCount(fRestoreCount);
52     }
53 }
54 
55 RenderNode::ScopedRenderContext&&
modulateOpacity(float opacity)56 RenderNode::ScopedRenderContext::modulateOpacity(float opacity) {
57     SkASSERT(opacity >= 0 && opacity <= 1);
58     fCtx.fOpacity *= opacity;
59     return std::move(*this);
60 }
61 
62 RenderNode::ScopedRenderContext&&
modulateColorFilter(sk_sp<SkColorFilter> cf)63 RenderNode::ScopedRenderContext::modulateColorFilter(sk_sp<SkColorFilter> cf) {
64     fCtx.fColorFilter = SkColorFilter::MakeComposeFilter(std::move(fCtx.fColorFilter),
65                                                          std::move(cf));
66     return std::move(*this);
67 }
68 
69 RenderNode::ScopedRenderContext&&
modulateBlendMode(SkBlendMode mode)70 RenderNode::ScopedRenderContext::modulateBlendMode(SkBlendMode mode) {
71     fCtx.fBlendMode = mode;
72     return std::move(*this);
73 }
74 
75 RenderNode::ScopedRenderContext&&
setIsolation(const SkRect & bounds,bool isolation)76 RenderNode::ScopedRenderContext::setIsolation(const SkRect& bounds, bool isolation) {
77     if (isolation) {
78         SkPaint layer_paint;
79         if (fCtx.modulatePaint(&layer_paint)) {
80             fCanvas->saveLayer(bounds, &layer_paint);
81             fCtx = RenderContext();
82         }
83     }
84     return std::move(*this);
85 }
86 
87 RenderNode::ScopedRenderContext&&
setFilterIsolation(const SkRect & bounds,sk_sp<SkImageFilter> filter)88 RenderNode::ScopedRenderContext::setFilterIsolation(const SkRect& bounds,
89                                                     sk_sp<SkImageFilter> filter) {
90     SkPaint layer_paint;
91     fCtx.modulatePaint(&layer_paint);
92 
93     SkASSERT(!layer_paint.getImageFilter());
94     layer_paint.setImageFilter(std::move(filter));
95     fCanvas->saveLayer(bounds, &layer_paint);
96     fCtx = RenderContext();
97 
98     return std::move(*this);
99 }
100 
101 } // namespace sksg
102