Skip to content

thorvg 0.3.0

Choose a tag to compare

@goyox86 goyox86 released this 13 Jun 18:08
· 27 commits to main since this release

A large API-hardening and ergonomics release. The headline themes are
type-safety (enums and parameter structs replacing primitives), a
shared color module, sealed traits, lifetime-correct borrowed views,
and a sweep of memory-safety fixes around FFI ownership.

Changed (breaking)

  • Colors are now typed. Text::set_color / set_outline take
    Rgb; Shape fill/stroke and gradient ColorStop take Rgba.
    Raw u8 channel arguments are gone. Rgb/Rgba live in a shared
    color module, which now also hosts ColorSpace.
  • EngineOption is a plain enum (None / Default / SmartRender)
    matching the C++ engine's exact-equality semantics, instead of a
    bitflags newtype.
  • Shape paint order is a PaintOrder enum (FillThenStroke /
    StrokeThenFill) instead of a bool.
  • Shape primitives take parameter structsRect and Circle
    (with builders and Default) replace long positional argument lists.
  • Scene effects take parameter structsGaussianBlur,
    DropShadow, Tint, and Tritone (builders + Default); blur
    direction and border are now enums rather than ints. Effect methods
    were renamed for consistency.
  • Factory methods return Result across paint/scene/picture/text/
    animation/saver/accessor/gradient, instead of panicking or returning
    bare handles on allocation failure.
  • set_mask / set_clip consume the paint by value, modelling the
    ownership transfer to the C engine (prevents double-free / leaks).
  • Canvas::push and Scene::push renamed to add for C API parity.
  • Picture::load_data takes a typed MimeType enum instead of a
    string.
  • Font-loading API moved from Text to Thorvg (it is engine-global
    state, not per-text).
  • Thorvg::init signature is gated on the threads feature.
  • Paint and Canvas are now sealed traits — they cannot be
    implemented downstream.
  • from_raw conversions are exhaustive for PaintType and
    MaskMethod, and Shape enums (FillRule, StrokeCap, StrokeJoin)
    are exhaustive.

Added

  • Typed Path / PathCommand / Segment model; Shape::path returns
    it and Shape::append_path closes the round-trip. Segments now
    implements size_hint.
  • Text::text getter (C parity).
  • Shape::set_stroke_radial_gradient (C parity).
  • Chainable Matrix transform combinators.
  • Point::new plus rounded-out ergonomics and enum-variant docs.
  • GlCanvas / WgCanvas GPU target builders for API parity (the
    vendored build still strips the GPU engine).
  • Safe, closure-based Picture::set_asset_resolver; BorrowedAccessor
    and BorrowedPaint are passed into for_each visitors.
  • impl From<NulError> for Error, so CString construction works with
    ?.
  • Gradient kinds are enumerated in PaintType.

Fixed

  • Memory leaks in Paint::set_clip / set_mask and a leaked gradient
    handle in Shape (now exposed as a BorrowedGradient view). Leaks are
    memory-safe; the related double-free is listed under Security below.
  • Paint's mask getter called the wrong C API; replaced with the correct
    one.
  • Animation::picture and Picture::get_paint now return stable borrows
    (&Picture / BorrowedPaint) instead of a rebuilt wrapper / raw
    handle — clearer ownership. (Neither was unsound in prior releases.)
  • Hardened the newly safe, closure-based Picture::set_asset_resolver
    (new in this release, see Added) so its trampoline pointer stays stable
    across moves of the picture.

Security

Several FFI-ownership and bounds bugs that were unsound — reachable
from safe code without unsafe
— are fixed in this release. All of
them affect published versions ≤ 0.2.0 (the APIs date back to the
initial release) and are fixed in 0.3.0; users should upgrade.
0.1.0 and 0.1.1 were already yanked.

  • Use-after-free in Saver::save_animation.
  • Dangling input buffersPicture::load_data / Picture::load_raw
    and Text::load_font_data did not tie the borrowed slice's lifetime to
    the consuming object, so the engine could read freed memory after the
    slice was dropped. The buffer lifetime is now enforced by the type
    system.
  • Out-of-bounds read in Picture::load_raw — the pixel-buffer length
    was not validated against the declared width × height; now
    bounds-checked.
  • Out-of-bounds write in SwCanvas::set_target — the target buffer
    size computation could overflow and accept an undersized buffer; now
    overflow-checked.
  • Double-free via Paint::set_clip / set_mask — these took the
    clipper/mask by reference while the engine took ownership, so the Rust
    wrapper and the engine could both free it. They now consume the paint
    by value.
  • Undefined behaviour on panic across FFI — a panic in a user closure
    passed to Accessor::for_each unwound through an extern "C"
    trampoline (UB). Such closures are now wrapped in catch_unwind under
    std; the no_std panic policy is documented.

Removed

  • The unused, unsafe Accessor::set raw-FFI escape hatch.

Deprecated

  • Gradient::get_transform — renamed to transform for consistency
    with Paint::transform.