|
|
Donner SVG Editor & Engine
SVG-native editor and embeddable SVG2 + CSS3 engine in C++20, with GPU (WebGPU) and compact CPU renderers, built for correctness, security, and performance.
|
Donner is intended as a hobby project with the latest C++ spec, so it is likely that toolchains that support it won't be pre-installed.
CMake builds on Linux: pkg-config and development libraries for Fontconfig and Freetype. For Debian/Ubuntu:
The recommended way to use Bazel is to install Bazelisk, which will automatically download Bazel as required. To install:
Verify that you can build with
All other dependencies will be downloaded on-demand.
The first build downloads LLVM and other external dependencies, and builds all dependencies from source. With the default tiny-skia backend, clean build times are reasonable. After dependencies are downloaded, clean build times are:
To run the tests, run:
To include experimental code as well, run:
See the latest Build report.
To generate a build report locally:
To regenerate the checked-in build report at docs/build_report.md:
When saving to docs/build_report.md the script automatically switches to --link-mode=docs. In that mode:
To build the Doxygen site with the bundled reports:
tools/build_docs.sh runs doxygen Doxyfile, copies docs/reports/binary-size/ into the generated HTML output, and extracts docs/reports/coverage.zip into reports/coverage/ so the deployed docs site has both reports live.
To collect coverage without generating the local HTML report:
In quiet mode the long phases write detailed output to coverage-report/*.log and print a progress line about every 60 seconds. Set DONNER_COVERAGE_PROGRESS_INTERVAL_SECONDS to shorten that interval for local debugging.
tools/coverage.sh runs Bazel coverage, filters excluded LCOV records, validates that the filtered report is non-empty, and then prints the same line buckets Codecov uses for the project percentage. The important distinction is that Codecov does not use raw LCOV line coverage as its project percentage:
That means local raw LCOV line coverage can be several points higher than Codecov when many conditionals have only one branch covered. Use tools/lcov_metrics.py or the summary printed by tools/coverage.sh when comparing against Codecov's project target:
For exact comparisons against a processed Codecov commit, use Codecov's commit API JSON as the reference file/line universe. This accounts for Codecov's upload-time normalization of LCOV records, including lines that appear in DA records locally but are not counted in the processed report:
Bazel is the primary build system, but CMake support is also available through a Bazel-to-CMake converter. This is for users who want to integrate Donner into their CMake-based projects.
To run tests, they must be enabled during the CMake configuration step:
This fetches dependencies via FetchContent and builds the libraries. Unit tests are not built by default and can be enabled with the DONNER_BUILD_TESTS option.
The standalone CMake consumer example under examples/cmake_consumer/ is a getting-started project for linking the exported donner target from another CMake project. See Adding to Your CMake Project for the external-consumer setup.
| Option | Default | Description |
|---|---|---|
| DONNER_RENDERER_BACKEND | "tiny_skia" | Renderer backend selection; the supported default is "tiny_skia" |
| DONNER_TEXT | ON | Enable text rendering (<text>, <tspan>) |
| DONNER_TEXT_WOFF2 | ON | Enable WOFF2 web font loading |
| DONNER_FILTERS | ON | Enable SVG filter effects |
| DONNER_BUILD_TESTS | OFF | Build unit tests (adds googletest dependency) |
| Config / Flag | Description |
|---|---|
| --config=geode | Use the Geode GPU backend (WebGPU/Dawn + Slug; the editor's default renderer); also enables --//donner/svg/renderer/geode:enable_geode=true |
| --config=text-full | Enable HarfBuzz text shaping + WOFF2 (advanced text layout) |
| --config=asan-fuzzer | Build fuzzers with AddressSanitizer |
| --config=latest_llvm | Use the latest LLVM toolchain (required for coverage) |
| --config=lld | Force the lld linker; workaround for dev boxes whose default linker can't link the suite (see FAQ below) |
The GitHub-hosted CI lanes (the hosted Linux/macOS fallback builds, the linker-canary, the hosted Coverage build, the nightly full-tree build, and the sanitizer lanes) can share a BuildBuddy remote cache. It is off by default and never affects local builds or the self-hosted runners.
How it works. The .github/actions/buildbuddy-cache composite action runs early in each hosted lane. When the BUILDBUDDY_API_KEY repository secret is present it writes a .buildbuddy.bazelrc fragment (loaded by a try-import in .bazelrc) that points Bazel at grpcs://remote.buildbuddy.io. When the secret is absent the action writes nothing and the try-import is a silent no-op, so every lane builds exactly as it would without the cache.
Pull-request runs are read-only: they may read cache hits but never upload (--remote_upload_local_results=false), so a PR can never poison the cache. Only trusted main pushes and scheduled runs upload results.
Activation. Add a repository secret named BUILDBUDDY_API_KEY (Settings -> Secrets and variables -> Actions) holding a BuildBuddy API key. No code change or redeploy is needed; the next hosted run picks it up automatically.
Deactivation. Delete the BUILDBUDDY_API_KEY secret. On their next run the lanes revert to cache-less builds with no other change.
That indicates that xcode is not installed, the bad error message is a known bazel issue: https://github.com/bazelbuild/bazel/issues/23111
Validate that xcode is installed with:
If it is not installed, install it from the App Store. Once this is complete clean bazel state and retry:
This means Bazel's autoconfigured toolchain picked a linker on your machine that can't handle Bazel's --start-lib/--end-lib archive groups: ld.gold resolves them in a single pass and can drop objects emitted before their consumers, and some distros ship an ld.bfd that doesn't support --start-lib at all. lld handles both cases. Install lld (e.g. sudo apt-get install lld on Debian/Ubuntu) and build with:
This is a local dev-box workaround, not the default, so it doesn't force an lld dependency onto CI images that already link fine. See #665.
Donner builds everything from source. The tiny-skia backend stays relatively fast because it has no large external rendering dependency. Incremental builds are fast due to Bazel's caching.
The full native editor lives at //donner/editor:editor and uses Geode/WebGPU by default without requiring --config=geode:
The browser editor build also uses Geode/WebGPU by default and is toolchain-gated behind --config=editor-wasm:
Use -- --https for LAN access with the generated local certificate. Then open the served index.html in a browser. See docs/design_docs/0020-editor.md for the editor design and milestone plan.