Donner
C++20 SVG rendering library
Loading...
Searching...
No Matches
Introduction

Donner is an under-development modern C++20 SVG rendering library which provides full access to the SVG DOM, enabling browser-level functionality without the browser.

Donner splash image

Currently, Donner includes:

  • SVG2 core functionality, such as shapes, fills, strokes, and gradients.
  • CSS3 parsing and cascading support, with a hand-rolled library.
  • A game-engine-inspired EnTT ECS-backed document tree.
  • A SVG DOM-style API to traverse, inspect, and modify documents in memory.
  • A two-phase renderer, which builds and caches a rendering tree for efficient frame-based rendering.

Donner currently renders with Skia as core functionality is being implemented. While Skia is powerful, it adds a lot of code size so alternative approaches may be considered in the future.

Donner focuses on security and performance, which is validated with code coverage and fuzz testing.

Try it out: Render an SVG to PNG

bazel run --run_under="cd $PWD &&" //examples:svg_to_png -- donner_splash.svg

Open in GitHub Codespaces

How it works: svg_to_png.cc

API Demo

//! [svg_string]
// This is the base SVG we are loading, a simple path containing a line
<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>
)");
//! [svg_string]
//! [svg_parse]
// Call ParseSVG to load the SVG file
ParseResult<donner::svg::SVGDocument> maybeResult =
//! [svg_parse]
//! [error_handling]
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
}
//! [error_handling]
//! [get_path]
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.has_value(), "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.
//! [get_path]
if (std::optional<donner::svg::PathSpline> spline = path.computedSpline()) {
std::cout << "Path: " << *spline << "\n";
std::cout << "Length: " << spline->pathLength() << " userspace units\n";
} else {
std::cout << "Path is empty\n";
}

Detailed docs: svg_tree_interaction.cc

Documentation

Project Goals

  • Have minimal dependencies, so it can be integrated into existing applications, assuming a modern compiler.
  • Expose the SVG DOM, so that applications can manipulate SVGs dynamically.
  • Implement the SVG 2 Specification.

Status

Building

Donner is built using Bazel, and builds are tested on Linux and macOS.

See more details in the Building Donner instructions.

Previous Next
Getting started