|
| 1 | +# SVG Support |
| 2 | + |
| 3 | +v-gui includes a complete SVG rendering pipeline for vector graphics. SVGs are parsed, tessellated |
| 4 | +into triangles, cached, and rendered efficiently via the GPU. |
| 5 | + |
| 6 | +## Basic Usage |
| 7 | + |
| 8 | +```v ignore |
| 9 | +// From file |
| 10 | +gui.svg(file_name: 'icon.svg', width: 24, height: 24) |
| 11 | +
|
| 12 | +// Inline SVG data |
| 13 | +gui.svg(svg_data: '<svg viewBox="0 0 24 24">...</svg>', width: 24, height: 24) |
| 14 | +
|
| 15 | +// With color override (for monochrome icons) |
| 16 | +gui.svg(file_name: 'icon.svg', width: 24, height: 24, color: gui.theme().text_color) |
| 17 | +``` |
| 18 | + |
| 19 | +## Supported SVG Features |
| 20 | + |
| 21 | +### Elements |
| 22 | + |
| 23 | +| Element | Support | |
| 24 | +|---------|---------| |
| 25 | +| `<path>` | Full (all commands: M, L, H, V, C, S, Q, T, A, Z) | |
| 26 | +| `<rect>` | Full (including rx/ry for rounded corners) | |
| 27 | +| `<circle>` | Full | |
| 28 | +| `<ellipse>` | Full | |
| 29 | +| `<line>` | Full | |
| 30 | +| `<polygon>` | Full | |
| 31 | +| `<polyline>` | Full | |
| 32 | +| `<g>` | Full (nested groups with style inheritance) | |
| 33 | + |
| 34 | +### Transforms |
| 35 | + |
| 36 | +All SVG transform functions are supported: |
| 37 | + |
| 38 | +```xml |
| 39 | +<g transform="translate(10, 20)">...</g> |
| 40 | +<g transform="rotate(45)">...</g> |
| 41 | +<g transform="rotate(45, 100, 100)">...</g> <!-- rotate around point --> |
| 42 | +<g transform="scale(2)">...</g> |
| 43 | +<g transform="scale(2, 0.5)">...</g> |
| 44 | +<g transform="skewX(30)">...</g> |
| 45 | +<g transform="skewY(30)">...</g> |
| 46 | +<g transform="matrix(a, b, c, d, e, f)">...</g> |
| 47 | + |
| 48 | +<!-- Multiple transforms are composed --> |
| 49 | +<g transform="translate(50, 50) rotate(45) scale(2)">...</g> |
| 50 | +``` |
| 51 | + |
| 52 | +### Fills and Strokes |
| 53 | + |
| 54 | +```xml |
| 55 | +<!-- Fill colors --> |
| 56 | +<path fill="#ff0000" ... /> |
| 57 | +<path fill="rgb(255, 0, 0)" ... /> |
| 58 | +<path fill="red" ... /> |
| 59 | +<path fill="none" ... /> |
| 60 | + |
| 61 | +<!-- Strokes --> |
| 62 | +<path stroke="#000" stroke-width="2" ... /> |
| 63 | +<path stroke-linecap="round" ... /> <!-- butt, round, square --> |
| 64 | +<path stroke-linejoin="bevel" ... /> <!-- miter, round, bevel --> |
| 65 | +``` |
| 66 | + |
| 67 | +### Style Inheritance |
| 68 | + |
| 69 | +Styles cascade from parent groups to children: |
| 70 | + |
| 71 | +```xml |
| 72 | +<g fill="blue" stroke="black" stroke-width="2"> |
| 73 | + <rect ... /> <!-- inherits blue fill, black stroke --> |
| 74 | + <circle fill="red" /> <!-- red fill, inherits black stroke --> |
| 75 | +</g> |
| 76 | +``` |
| 77 | + |
| 78 | +## Architecture |
| 79 | + |
| 80 | +### Parsing |
| 81 | + |
| 82 | +SVGs are parsed into `VectorPath` structures containing: |
| 83 | +- Path segments (move, line, quadratic/cubic bezier, arc, close) |
| 84 | +- Fill color |
| 85 | +- Stroke properties (color, width, cap, join) |
| 86 | +- Transform matrix |
| 87 | + |
| 88 | +### Tessellation |
| 89 | + |
| 90 | +Paths are converted to triangles for GPU rendering: |
| 91 | + |
| 92 | +1. **Curve flattening**: Bezier curves subdivided to polylines based on tolerance |
| 93 | +2. **Transform application**: Affine transforms applied to all coordinates |
| 94 | +3. **Fill tessellation**: Ear clipping algorithm with hole support |
| 95 | +4. **Stroke tessellation**: Polylines expanded to quads with proper joins and caps |
| 96 | + |
| 97 | +### Caching |
| 98 | + |
| 99 | +Tessellated SVGs are cached by source and size: |
| 100 | + |
| 101 | +```v ignore |
| 102 | +// Automatic caching - same SVG at same size reuses tessellation |
| 103 | +gui.svg(file_name: 'icon.svg', width: 24, height: 24) // tessellates |
| 104 | +gui.svg(file_name: 'icon.svg', width: 24, height: 24) // cache hit |
| 105 | +
|
| 106 | +// Different size = new cache entry |
| 107 | +gui.svg(file_name: 'icon.svg', width: 48, height: 48) // tessellates at new scale |
| 108 | +``` |
| 109 | + |
| 110 | +Manual cache control: |
| 111 | + |
| 112 | +```v ignore |
| 113 | +// Clear specific SVG from cache |
| 114 | +window.remove_svg_from_cache('icon.svg') |
| 115 | +
|
| 116 | +// Clear all cached SVGs |
| 117 | +window.clear_svg_cache() |
| 118 | +``` |
| 119 | + |
| 120 | +## Examples |
| 121 | + |
| 122 | +### Simple Icon |
| 123 | + |
| 124 | +```v ignore |
| 125 | +gui.row( |
| 126 | + content: [ |
| 127 | + gui.svg(file_name: 'save.svg', width: 16, height: 16), |
| 128 | + gui.text(text: 'Save'), |
| 129 | + ] |
| 130 | +) |
| 131 | +``` |
| 132 | + |
| 133 | +### Icon with Theme Color |
| 134 | + |
| 135 | +```v ignore |
| 136 | +gui.svg( |
| 137 | + file_name: 'settings.svg', |
| 138 | + width: 24, |
| 139 | + height: 24, |
| 140 | + color: gui.theme().text_color, // overrides SVG fill colors |
| 141 | +) |
| 142 | +``` |
| 143 | + |
| 144 | +### Complex SVG (Ghostscript Tiger) |
| 145 | + |
| 146 | +```v ignore |
| 147 | +// See examples/tiger.v for complete example |
| 148 | +gui.svg(file_name: 'tiger.svg', width: 450, height: 450) |
| 149 | +``` |
| 150 | + |
| 151 | +The classic Ghostscript Tiger (240 paths with transforms, groups, and strokes) renders correctly, |
| 152 | +demonstrating full SVG compatibility. |
| 153 | + |
| 154 | +## Limitations |
| 155 | + |
| 156 | +Currently not supported: |
| 157 | +- `<defs>` and `<use>` (symbol reuse) |
| 158 | +- `<clipPath>` and `<mask>` |
| 159 | +- `<linearGradient>` and `<radialGradient>` |
| 160 | +- CSS styling (`<style>` blocks, `class` attributes) |
| 161 | +- `opacity` attribute |
| 162 | +- Text (`<text>`, `<tspan>`) |
| 163 | +- Filters (`<filter>`) |
| 164 | + |
| 165 | +For icons and illustrations, these limitations rarely matter. For complex SVGs with gradients or |
| 166 | +text, consider converting to supported features or using bitmap images. |
| 167 | + |
| 168 | +## Performance Tips |
| 169 | + |
| 170 | +1. **Use appropriate sizes**: Tessellation quality scales with display size. Don't render a |
| 171 | + 1000x1000 SVG at 24x24. |
| 172 | + |
| 173 | +2. **Reuse SVGs**: The cache is keyed by source+size. Identical SVG widgets share tessellation. |
| 174 | + |
| 175 | +3. **Simplify paths**: Fewer path segments = faster tessellation. Tools like SVGO can optimize. |
| 176 | + |
| 177 | +4. **Color override for icons**: Using `color:` parameter is faster than parsing colors from SVG. |
0 commit comments