| /* | |
| * Copyright 2026 Rive | |
| */ | |
| #ifndef _RIVE_SVG_FACTORY_HPP_ | |
| #define _RIVE_SVG_FACTORY_HPP_ | |
| #include "rive/factory.hpp" | |
| #include "rive/math/raw_path.hpp" | |
| #include "rive/renderer.hpp" | |
| #include "rive/shapes/paint/color.hpp" | |
| #include <sstream> | |
| #include <string> | |
| #include <vector> | |
| namespace rive | |
| { | |
| // -- Render objects stored by SVGFactory, read by SVGRenderer -- | |
| class SVGRenderPath : public RenderPath | |
| { | |
| public: | |
| SVGRenderPath() = default; | |
| SVGRenderPath(RawPath& rawPath, FillRule fillRule); | |
| void rewind() override; | |
| void fillRule(FillRule value) override; | |
| void addRenderPath(const RenderPath* path, const Mat2D& transform) override; | |
| void moveTo(float x, float y) override; | |
| void lineTo(float x, float y) override; | |
| void cubicTo(float ox, float oy, float ix, float iy, float x, float y) | |
| override; | |
| void close() override; | |
| void addRawPath(const RawPath& path) override; | |
| std::string toSvgD(int floatPrecision) const; | |
| FillRule getFillRule() const { return m_fillRule; } | |
| private: | |
| RawPath m_rawPath; | |
| FillRule m_fillRule = FillRule::nonZero; | |
| }; | |
| class SVGRenderShader : public RenderShader | |
| { | |
| public: | |
| virtual ~SVGRenderShader() = default; | |
| virtual void emitDefs(std::ostream& out, const std::string& id) const = 0; | |
| }; | |
| class SVGLinearGradientShader : public SVGRenderShader | |
| { | |
| public: | |
| SVGLinearGradientShader(float sx, | |
| float sy, | |
| float ex, | |
| float ey, | |
| const ColorInt colors[], | |
| const float stops[], | |
| size_t count); | |
| void emitDefs(std::ostream& out, const std::string& id) const override; | |
| private: | |
| float m_sx, m_sy, m_ex, m_ey; | |
| std::vector<ColorInt> m_colors; | |
| std::vector<float> m_stops; | |
| }; | |
| class SVGRadialGradientShader : public SVGRenderShader | |
| { | |
| public: | |
| SVGRadialGradientShader(float cx, | |
| float cy, | |
| float radius, | |
| const ColorInt colors[], | |
| const float stops[], | |
| size_t count); | |
| void emitDefs(std::ostream& out, const std::string& id) const override; | |
| private: | |
| float m_cx, m_cy, m_radius; | |
| std::vector<ColorInt> m_colors; | |
| std::vector<float> m_stops; | |
| }; | |
| class SVGRenderPaint : public RenderPaint | |
| { | |
| public: | |
| void style(RenderPaintStyle value) override; | |
| void color(ColorInt value) override; | |
| void thickness(float value) override; | |
| void join(StrokeJoin value) override; | |
| void cap(StrokeCap value) override; | |
| void blendMode(BlendMode value) override; | |
| void shader(rcp<RenderShader> sh) override; | |
| void invalidateStroke() override {} | |
| void feather(float value) override {} | |
| bool isStroke() const { return m_isStroke; } | |
| ColorInt getColor() const { return m_color; } | |
| float getThickness() const { return m_thickness; } | |
| StrokeJoin getJoin() const { return m_join; } | |
| StrokeCap getCap() const { return m_cap; } | |
| BlendMode getBlendMode() const { return m_blendMode; } | |
| SVGRenderShader* getSvgShader() const; | |
| private: | |
| bool m_isStroke = false; | |
| ColorInt m_color = 0xFF000000; | |
| float m_thickness = 1.0f; | |
| StrokeJoin m_join = StrokeJoin::miter; | |
| StrokeCap m_cap = StrokeCap::butt; | |
| BlendMode m_blendMode = BlendMode::srcOver; | |
| rcp<RenderShader> m_shader; | |
| }; | |
| class SVGRenderImage : public RenderImage | |
| { | |
| public: | |
| SVGRenderImage(Span<const uint8_t> encodedBytes, | |
| uint32_t width, | |
| uint32_t height); | |
| std::string toDataURI() const; | |
| private: | |
| std::vector<uint8_t> m_encodedBytes; | |
| }; | |
| class SVGRenderBuffer : public RenderBuffer | |
| { | |
| public: | |
| SVGRenderBuffer(RenderBufferType type, | |
| RenderBufferFlags flags, | |
| size_t sizeInBytes); | |
| protected: | |
| void* onMap() override; | |
| void onUnmap() override; | |
| private: | |
| std::vector<uint8_t> m_bytes; | |
| }; | |
| // -- Factory -- | |
| class SVGFactory : public Factory | |
| { | |
| public: | |
| // Reads the pixel dimensions of an encoded image. SVG embeds the encoded | |
| // bytes verbatim as a data URI, so the pixels themselves are never needed. | |
| // Returns false when the format isn't recognized. | |
| using DecodeImageSize = bool (*)(Span<const uint8_t> encodedBytes, | |
| uint32_t* width, | |
| uint32_t* height); | |
| // Injected so this factory depends on no particular image decoder. | |
| // Without one, decodeImage() fails and images drop out of the output. | |
| explicit SVGFactory(DecodeImageSize decodeImageSize = nullptr) : | |
| m_decodeImageSize(decodeImageSize) | |
| {} | |
| rcp<RenderBuffer> makeRenderBuffer(RenderBufferType type, | |
| RenderBufferFlags flags, | |
| size_t sizeInBytes) override; | |
| rcp<RenderShader> makeLinearGradient(float sx, | |
| float sy, | |
| float ex, | |
| float ey, | |
| const ColorInt colors[], | |
| const float stops[], | |
| size_t count) override; | |
| rcp<RenderShader> makeRadialGradient(float cx, | |
| float cy, | |
| float radius, | |
| const ColorInt colors[], | |
| const float stops[], | |
| size_t count) override; | |
| rcp<RenderPath> makeRenderPath(RawPath& rawPath, | |
| FillRule fillRule) override; | |
| rcp<RenderPath> makeEmptyRenderPath() override; | |
| rcp<RenderPaint> makeRenderPaint() override; | |
| rcp<RenderImage> decodeImage(Span<const uint8_t> data) override; | |
| private: | |
| DecodeImageSize m_decodeImageSize; | |
| }; | |
| } // namespace rive | |
| #endif |