Skip to content

Latest commit

 

History

History
243 lines (178 loc) · 6.91 KB

File metadata and controls

243 lines (178 loc) · 6.91 KB

SVG Support

v-gui includes a complete SVG rendering pipeline for vector graphics. SVGs are parsed, tessellated into triangles, cached, and rendered efficiently via the GPU.

Basic Usage

// From file
gui.svg(file_name: 'icon.svg', width: 24, height: 24)

// Inline SVG data
gui.svg(svg_data: '<svg viewBox="0 0 24 24">...</svg>', width: 24, height: 24)

// With color override (for monochrome icons)
gui.svg(file_name: 'icon.svg', width: 24, height: 24, color: gui.theme().text_color)

Supported SVG Features

Elements

Element Support
<path> Full (all commands: M, L, H, V, C, S, Q, T, A, Z)
<rect> Full (including rx/ry for rounded corners)
<circle> Full
<ellipse> Full
<line> Full
<polygon> Full
<polyline> Full
<g> Full (nested groups with style inheritance)
<clipPath> Full (binary stencil clipping via <defs>)

Transforms

All SVG transform functions are supported:

<g transform="translate(10, 20)">...</g>
<g transform="rotate(45)">...</g>
<g transform="rotate(45, 100, 100)">...</g>  <!-- rotate around point -->
<g transform="scale(2)">...</g>
<g transform="scale(2, 0.5)">...</g>
<g transform="skewX(30)">...</g>
<g transform="skewY(30)">...</g>
<g transform="matrix(a, b, c, d, e, f)">...</g>

<!-- Multiple transforms are composed -->
<g transform="translate(50, 50) rotate(45) scale(2)">...</g>

Fills and Strokes

<!-- Fill colors -->
<path fill="#ff0000" ... />
<path fill="rgb(255, 0, 0)" ... />
<path fill="red" ... />
<path fill="none" ... />

<!-- Strokes -->
<path stroke="#000" stroke-width="2" ... />
<path stroke-linecap="round" ... />   <!-- butt, round, square -->
<path stroke-linejoin="bevel" ... />  <!-- miter, round, bevel -->

Style Inheritance

Styles cascade from parent groups to children:

<g fill="blue" stroke="black" stroke-width="2">
    <rect ... />          <!-- inherits blue fill, black stroke -->
    <circle fill="red" /> <!-- red fill, inherits black stroke -->
</g>

Clip Paths

Clip paths use stencil-based clipping to restrict rendering to a defined shape:

<defs>
    <clipPath id="myClip">
        <circle cx="50" cy="50" r="40"/>
    </clipPath>
</defs>
<rect width="100" height="100" fill="blue" clip-path="url(#myClip)"/>

The clip-path attribute works on individual shapes and <g> groups. Group clip paths are inherited by children.

Architecture

Parsing

SVGs are parsed into VectorPath structures containing:

  • Path segments (move, line, quadratic/cubic bezier, arc, close)
  • Fill color
  • Stroke properties (color, width, cap, join)
  • Transform matrix

Tessellation

Paths are converted to triangles for GPU rendering:

  1. Curve flattening: Bezier curves subdivided to polylines based on tolerance
  2. Transform application: Affine transforms applied to all coordinates
  3. Fill tessellation: Ear clipping algorithm with hole support
  4. Stroke tessellation: Polylines expanded to quads with proper joins and caps

Caching

Tessellated SVGs are cached by source and size:

// Automatic caching - same SVG at same size reuses tessellation
gui.svg(file_name: 'icon.svg', width: 24, height: 24)  // tessellates
gui.svg(file_name: 'icon.svg', width: 24, height: 24)  // cache hit

// Different size = new cache entry
gui.svg(file_name: 'icon.svg', width: 48, height: 48)  // tessellates at new scale

Manual cache control:

// Clear specific SVG from cache
window.remove_svg_from_cache('icon.svg')

// Clear all cached SVGs
window.clear_svg_cache()

Examples

Simple Icon

gui.row(
    content: [
        gui.svg(file_name: 'save.svg', width: 16, height: 16),
        gui.text(text: 'Save'),
    ]
)

Icon with Theme Color

gui.svg(
    file_name: 'settings.svg',
    width: 24,
    height: 24,
    color: gui.theme().text_color,  // overrides SVG fill colors
)

Complex SVG (Ghostscript Tiger)

// See examples/tiger.v for complete example
gui.svg(file_name: 'tiger.svg', width: 450, height: 450)

The classic Ghostscript Tiger (240 paths with transforms, groups, and strokes) renders correctly, demonstrating full SVG compatibility.

Limitations

Security Limits

To prevent denial-of-service attacks, the following limits are enforced:

  • Elements: 100,000 max (most icons have <10; complex SVGs like tiger.svg: ~240)
  • Path segments: 100,000 max per path (typical paths: <50)
  • Group nesting: 32 levels max (prevents stack overflow)
  • ViewBox dimensions: 10,000 max (prevents extreme allocations)
  • Coordinates: ±1,000,000 max (prevents integer overflow)
  • Attribute length: 1MB max (prevents excessive string allocations)

SVGs exceeding these limits will be partially rendered or rejected. For production use, optimize SVG files to stay well within limits.

Cache Behavior

SVGs are cached for performance:

  • Capacity: 100 entries (unique source + size combinations)
  • Eviction: LRU (least recently accessed)
  • Key: hash(source):width×10:height×10 (0.1px precision)
  • Memory: Each entry stores tessellated triangles (~1-10MB for complex SVGs)
  • Limit: SVGs generating >10MB triangles bypass cache (still render)

Cache invalidation: Call window.clear_svg_cache() or window.remove_svg_from_cache(source) after modifying files.

Cache efficiency: SVGs at different sizes are cached separately. Round sizes to 0.1px to maximize reuse (e.g., 24.0, 32.0, 48.0).

Performance Tuning

Optimize SVG files:

  • Remove editor metadata (<metadata>, <sodipodi> tags)
  • Merge paths where possible (reduces element count)
  • Simplify transforms (inline when possible)
  • Use integers for coordinates (faster parsing)

When to pre-render: For SVGs with >100 paths or heavy use of filters/masks (not supported), consider rasterizing to PNG at target sizes.

Rendering performance:

  • First load: ~1-5ms parse + tessellate (depends on complexity)
  • Cached: ~0.01ms (hash lookup + GPU upload)
  • Frame time: <0.1ms per SVG (GPU batched)

Not Supported

  • Gradients, patterns, filters
  • <use> (symbol reuse)
  • <mask> (luminance alpha masking)
  • <linearGradient> and <radialGradient>
  • CSS styling (<style> blocks, class attributes)
  • opacity attribute
  • Text (<text>, <tspan>)
  • Filters (<filter>)

For icons and illustrations, these limitations rarely matter. For complex SVGs with gradients or text, consider converting to supported features or using bitmap images.

Performance Tips

  1. Use appropriate sizes: Tessellation quality scales with display size. Don't render a 1000x1000 SVG at 24x24.

  2. Reuse SVGs: The cache is keyed by source+size. Identical SVG widgets share tessellation.

  3. Simplify paths: Fewer path segments = faster tessellation. Tools like SVGO can optimize.

  4. Color override for icons: Using color: parameter is faster than parsing colors from SVG.