Skip to content

Latest commit

 

History

1,694 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Donner SVG Editor & Engine

Build Status License: ISC DeepWiki CodeFactor
Code coverage % Product lines of code Test lines of code Comments %

A native SVG editor, built on its own SVG2 + CSS3 engine, written from scratch in C++20.

Donner is an SVG-native editor: a fast, native tool for creating and editing SVG, backed by an engine built for browser-grade correctness, security, and performance. The same engine that powers the editor embeds cleanly into your application, from a full GPU-rendered canvas down to a size-optimized software renderer.

Donner splash image

Try it out online!

Why Donner

  • An SVG-native editor. Selection and transform tools with oriented bounding boxes, a pen tool, rich text editing with real font support, and layers. Every icon and cursor is an SVG rendered by Donner itself; the document you edit is the SVG, always.
  • High SVG spec conformance. Conformance is tracked continuously against the resvg test suite with visual regression in CI.
  • Fully featured. SVG2 rendering with CSS3 styling, text with a full font stack (FreeType, HarfBuzz, WOFF2) or a compact built-in stack, filters, and the first slice of SMIL animation with time-sampled rendering.
  • High performance. Geode, a GPU renderer built on WebGPU, drives the editor canvas; a tiny_skia-based CPU backend serves the size-optimized embeddable build.
  • Secure. Built for untrusted content: 24 fuzzers run continuously, and the engine's design lineage includes shipping untrusted SVG and glTF rendering inside privileged apps.
  • Embeddable. A C++20 Bazel module with an exception-free, RTTI-free API surface; the tiny variant is tuned for binary size.

The editor

The editor ships with the engine and is under active development. Open a file, edit visually or in the built-in XML view with two-way sync, and export clean SVG.

Supported SVG elements and features

Donner targets the SVG 2 static rendering subset. The tables below are an honest snapshot of what the engine actually parses and renders today, derived from the code and from the conformance run in donner/svg/renderer/tests/resvg_test_suite.cc, which pixel-compares Donner against the upstream resvg test suite goldens on every push. That test and the SVG 2 conformance program in design 0057 are the measurement backbone; this section is the interim human-readable summary until the conformance suite publishes a generated gap report.

Legend: Yes = parsed and rendered; Partial = supported with the noted gaps; Parsed only = retained on the DOM but not drawn (by design); Experimental = implemented but off by default; No = not recognized (parses to an unknown element).

Elements

Category Elements Support
Structural <svg> <g> <defs> <symbol> <use> <style> <switch> Yes
Hyperlink <a> Yes. Renders as a transparent group (its children draw in place); the link target (href / xlink:href) is retained on the DOM.
Shapes <circle> <ellipse> <line> <path> <polygon> <polyline> <rect> Yes
Raster image <image> Partial. Embedded (data URI) images render; external-URL and cross-file references are not loaded.
Text <text> <tspan> <textPath> Partial. See Text features below. Text requires a text-enabled build; the size-optimized build can omit it.
Paint servers and markers <linearGradient> <radialGradient> <stop> <pattern> <marker> Yes. Linear and radial gradients (all spread methods, radial focal point) and patterns are supported; conic/sweep gradients are not.
Masking and clipping <mask> <clipPath> Partial. Core masking and clipping, mask-type, and vector text children in clip paths work; bitmap text silhouettes, some nested clip-path intersections, and a few mask-unit edge cases are not yet handled.
Filters <filter> and the full <fe*> primitive suite Partial. All 17 filter primitives have DOM wrappers and renderer support. The CSS filter: function-list category is active with 26 of 43 files comparing on both backends; 17 explicitly skipped mismatches await normative classification. enable-background / BackgroundImage and some feImage subregion cases also remain. See the filter element reference.
Descriptive <title> <desc> <metadata> Parsed only (retained, never drawn, per spec).
Animation (SMIL) <animate> <animateTransform> <set> Experimental, off by default. An animation system exists and renders time-sampled frames, but these elements parse to their animation types only when experimental parsing is enabled; otherwise they are treated as unknown.

Elements outside this list (for example <foreignObject>, <tref>, SVG 1.1 <font> / <glyph>, <cursor>, <view>, <script>) are not recognized and parse to an unknown element. See unsupported SVG 1.x features for the SVG 1.1 details.

Presentation attributes and CSS properties

Support Properties
Honored fill / fill-rule / fill-opacity, stroke and all stroke-*, opacity, color, display, visibility, overflow, transform / transform-origin, clip-path / clip-rule, mask / mask-type, filter, color-interpolation-filters, image-rendering (including distinct pixelated, crisp-edges, smooth, quality, and legacy-alias policies for <image> and <feImage>), marker-start / -mid / -end, mix-blend-mode (all 16 modes), isolation, paint-order, and the text properties (font-*, text-anchor, text-decoration, baseline family, letter-spacing, word-spacing, writing-mode).
Partial vector-effect (non-scaling-stroke is exact for uniform scale and rotation, while non-uniform transforms use a scalar approximation and the other at-risk SVG 2 values parse as typed values but render with none behavior); pointer-events (including auto) is used by hit-testing, with text, image, and clip-path edge cases still incomplete; cursor supports every CSS Basic UI keyword, ordered authored url() candidates with optional hotspots, inheritance, and DonnerController::cursorAt. CSS image-set(), declaration-base URL resolution, resource loading, and platform cursor mapping remain.
Recognized but not implemented The rendering hints color-rendering, shape-rendering, text-rendering, and color-interpolation are retained as raw properties but do not yet have typed cascade or runtime behavior.
Not implemented direction / unicode-bidi (bidirectional text), text-orientation, and font-size-adjust. SVG 1.1-only features such as <tref>, glyph-orientation-horizontal, and CSS2 clip: rect(...) are intentionally unsupported; see unsupported SVG 1.x features.

Text features

Text layout supports fills and strokes (including gradient and pattern paints), per-glyph positioning, text-anchor, textPath along a path, and a full font stack (FreeType, HarfBuzz, WOFF2) or a compact built-in stack. Known gaps, tracked against the resvg suite: bidirectional text and direction / unicode-bidi, textLength / lengthAdjust, several SVG 2 <textPath> features (side, method=stretch, spacing=auto, the path attribute), full SVG 2 text-decoration (independent line, style, and color), and some vertical-rl / vertical-lr and text-orientation cases. <tref> is intentionally unsupported because SVG 2 removed it.

Renderers

Donner ships two backends behind one renderer interface. The tiny_skia CPU backend is the default and the most complete; the Geode WebGPU backend drives the editor canvas and is at broad parity, with a few narrower gaps (some 0 N dash caps and nested path-clip intersection) where the CPU backend currently passes conformance cases the GPU backend does not. Both backends honor paint-order for shapes, markers, text, and tspans, and share the same DOM, layout, paint resolution, markers, and filter graph.

CLI Tool: donner-svg

Donner also ships an end-user CLI for rendering and previewing SVG files.

# Render to PNG
bazel run //donner/svg/tool:donner-svg -- donner_splash.svg --output output.png

# Show a terminal preview
bazel run //donner/svg/tool:donner-svg -- donner_splash.svg --preview

# Interactive terminal mode with mouse selection
bazel run //donner/svg/tool:donner-svg -- donner_splash.svg --interactive

Tool docs: donner-svg CLI tool

Simplified Example: Saving an SVG to PNG

bazel run //examples:svg_to_png -- donner_splash.svg

How it works: svg_to_png.cc

API Demo

// This is the base SVG we are loading, a simple path containing a line
const std::string_view svgContents(R"(
  <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 10 10">
    <path d="M 1 1 L 4 5" stroke="blue" />
  </svg>
)");

// Call ParseSVG to load the SVG file
donner::ParseWarningSink disabled = donner::ParseWarningSink::Disabled();
donner::ParseResult<donner::svg::SVGDocument> maybeResult =
    donner::svg::parser::SVGParser::ParseSVG(svgContents, disabled);

if (maybeResult.hasError()) {
  std::cerr << "Parse Error " << maybeResult.error() << "\n";  // Includes line:column and reason
  std::abort();
  // - or - handle the error per your project's conventions
}

donner::svg::SVGDocument document = std::move(maybeResult.result());

// querySelector supports standard CSS selectors, anything that's valid when defining a CSS rule
// works here too, for example querySelector("svg > path[fill='blue']") is also valid and will
// match the same element.
std::optional<donner::svg::SVGElement> maybePath = document.querySelector("path");
UTILS_RELEASE_ASSERT_MSG(maybePath, "Failed to find path element");

// The result of querySelector is a generic SVGElement, but we know it's a path, so we can cast
// it. If the cast fails, an assertion will be triggered.
donner::svg::SVGPathElement path = maybePath->cast<donner::svg::SVGPathElement>();

if (std::optional<donner::Path> computedPath = path.computedPath()) {
  std::cout << "Path: " << *computedPath << "\n";
  std::cout << "Length: " << computedPath->pathLength() << " userspace units\n";
} else {
  std::cout << "Path is empty\n";
}

Detailed docs: svg_tree_interaction.cc

API Demo 2: Rendering a SVG to PNG

using namespace donner;
using namespace donner::svg;
using namespace donner::svg::parser;

std::ifstream file("test.svg");
if (!file) {
  std::cerr << "Could not open file\n";
  std::abort();
}

std::string fileData;
file.seekg(0, std::ios::end);
const std::streamsize fileLength = file.tellg();
file.seekg(0);

fileData.resize(fileLength);  
file.read(fileData.data(), fileLength);

ParseWarningSink warnings;
ParseResult<SVGDocument> maybeDocument = SVGParser::ParseSVG(fileData, warnings);
if (maybeDocument.hasError()) {
  std::cerr << "Parse Error: " << maybeDocument.error() << "\n";
  std::abort();
}

Renderer renderer;
renderer.draw(maybeDocument.result());

const bool success = renderer.save("output.png");

Detailed docs: svg_to_png.cc

Documentation

Status

CMake Support

CMake support is available for integrating Donner into CMake-based projects. The CMake build fetches dependencies and builds the library. Both the tiny_skia (CPU) and Geode (WebGPU) backends are selectable via DONNER_RENDERER_BACKEND (default tiny_skia).

See the CMake Documentation for more details.

Other Libraries

  • C++ | LunaSVG: A lightweight library with an embedded renderer, suitable for embedded applications
  • C++ | ThorVG: A production vector graphics engine with software, OpenGL/ES, and WebGPU backends and Lottie support; targets SVG Tiny 1.2 rather than full SVG, so it is not as fully featured an SVG renderer as Donner or resvg
  • C | NanoSVG: A minimal single-header SVG parser and rasterizer, widely embedded where footprint matters; supports a small subset of SVG
  • Rust | librsvg: Provides a simple way to render SVGs one-shot, does not provide a DOM or animation
  • Rust | resvg: Library that focuses on correctness, safety, and portability for static SVGs
  • Rust | Vello: A GPU compute-centric 2D renderer from the Linebender ecosystem; renders SVG through companion crates rather than natively
  • Java | Apache Batik: A full dynamic SVG implementation with DOM, scripting, and declarative animation; the closest reference for browser-style dynamic SVG outside a browser engine

About

A native SVG editor, built on its own SVG2 + CSS3 engine, written from scratch in C++20.

Topics

Resources

Security policy

Stars

30 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages