/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkSGRenderNode_DEFINED #define SkSGRenderNode_DEFINED #include "SkSGNode.h" #include "SkBlendMode.h" #include "SkColorFilter.h" class SkCanvas; class SkImageFilter; class SkPaint; namespace sksg { /** * Base class for nodes which can render to a canvas. */ class RenderNode : public Node { protected: struct RenderContext; public: // Render the node and its descendants to the canvas. void render(SkCanvas*, const RenderContext* = nullptr) const; // Perform a front-to-back hit-test, and return the RenderNode located at |point|. // Normally, hit-testing stops at leaf Draw nodes. const RenderNode* nodeAt(const SkPoint& point) const; protected: explicit RenderNode(uint32_t inval_traits = 0); virtual void onRender(SkCanvas*, const RenderContext*) const = 0; virtual const RenderNode* onNodeAt(const SkPoint& p) const = 0; // Paint property overrides. // These are deferred until we can determine whether they can be applied to the individual // draw paints, or whether they require content isolation (applied to a layer). struct RenderContext { sk_sp<SkColorFilter> fColorFilter; float fOpacity = 1; SkBlendMode fBlendMode = SkBlendMode::kSrcOver; // Returns true if the paint was modified. bool modulatePaint(SkPaint*) const; }; class ScopedRenderContext final { public: ScopedRenderContext(SkCanvas*, const RenderContext*); ~ScopedRenderContext(); ScopedRenderContext(ScopedRenderContext&& that) { *this = std::move(that); } ScopedRenderContext& operator=(ScopedRenderContext&& that) { fCanvas = that.fCanvas; fCtx = std::move(that.fCtx); fRestoreCount = that.fRestoreCount; // scope ownership is being transferred that.fRestoreCount = -1; return *this; } operator const RenderContext* () const { return &fCtx; } // Add (cumulative) paint overrides to a render node sub-DAG. ScopedRenderContext&& modulateOpacity(float opacity); ScopedRenderContext&& modulateColorFilter(sk_sp<SkColorFilter>); ScopedRenderContext&& modulateBlendMode(SkBlendMode); // Force content isolation for a node sub-DAG by applying the RenderContext // overrides via a layer. ScopedRenderContext&& setIsolation(const SkRect& bounds, bool do_isolate); // Similarly, force content isolation by applying the RenderContext overrides and // an image filter via a single layer. ScopedRenderContext&& setFilterIsolation(const SkRect& bounds, sk_sp<SkImageFilter>); private: // stack-only void* operator new(size_t) = delete; void* operator new(size_t, void*) = delete; // Scopes cannot be copied. ScopedRenderContext(const ScopedRenderContext&) = delete; ScopedRenderContext& operator=(const ScopedRenderContext&) = delete; SkCanvas* fCanvas; RenderContext fCtx; int fRestoreCount; }; private: friend class ImageFilterEffect; typedef Node INHERITED; }; } // namespace sksg #endif // SkSGRenderNode_DEFINED