GraphiteEditor / GraphiteEditor/Graphite

Paints as graphics

Open
#2,779 2 comments 0 reactions 1 assignee Claimed by @Keavon View on GitHub
Architecture Graphics
Dominant language
Rust
Stars
27.2k
Forks
1.3k
Avg merge
20h 5m
Merged PRs (30d)
57

Description

A **paint** is something that's graphical, which can be given to a Fill or Stroke node to be applied to the appearance of a vector path or stroke area.

For Graphite, we should use a model where a paint can be any graphical data:
1. As a layer, it shows up with finite or infinite bounds in the render like normal. It may be clipped to a layer beneath it via a clipping mask.
2. As a fill paint, it shows up only within the fill area of a vector path.
3. As a stroke paint, it shows up only within the stroke area of a vector path.

Right now, we support any graphical **element** in case 1 (part of the render), but only the `FillChoice` enum which can be `None`/a solid `Color`/the `Gradient` struct for case 2 (vector fills), and only a `Color` for case 3 (vector strokes). This change calls for making the **Fill** and **Stroke** nodes accept any graphical data (i.e., anything that can be type-coerced into a graphical element) as opposed to their current parameters.

Then for colors and gradients, both of these types need to be added to the graphical element enum, allowing layers of color or gradient data to display infinitely in all directions. This solves the requested feature for choosing a background color of an infinite canvas, by simply making it be the bottom layer.

For patterns, we will have a sort of pattern tiling node which uses the footprint to render the infinite data. This can be implemented after the colors and gradients from the previous paragraph with insights gleaned from that process.

An alternative to adding these to the `Graphic` enum is that we could have a type coercion node that generates a vector rectangle with the footprint bounds, and fills it with the color, gradient, or pattern stroke. So feeding a color into a layer, a fill paint, or a stroke paint, would just type coerce it into a filled rectangle vector element of the appropriate size to cover the rendered area. This helps avoid needing to keep extending the `Graphic` enum and adding more rendering implementations to it.

We do need to update the renderer code to produce SVG output syntax for fill and stroke paints. For ordinary graphical data, this could work by using a `` (without the infinite tiling unless the user has created an infinite pattern with the data) or clip/mask. For color, this needs to become a standard fill color, and for gradient, likewise.

Paint transforms need to also be preserved, so a scaled/skewed paint can be drawn with that stretch applied, just like we do for a skewed gradient right now using `Gradient::transform`.

More detailed discussion: https://discord.com/channels/731730685944922173/1175577028209168474/1388368187803959391

Links:
- https://www.w3.org/TR/SVG2/pservers.html
- https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/pattern
- https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill
- https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke
- https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorials/SVG_from_scratch/Fills_and_strokes

```rs
pub enum Graphic {
// EXISTING
Graphic(Table),
Vector(Table),
RasterCPU(Table>),
RasterGPU(Table>),
// NEW ADDITIONS
Color(Table),
Gradient(Table),
Typography(Table),
Filter(Table),
Tiling(Table), // Has an attribute for SvgPatternViewBox
Background(Table), // This may be changed or removed from the design
// SvgPolyfill(Graphic, OriginalType), // This may be changed or removed from the design
}

enum SvgFilter {
GaussianBlur { source: Graphic, radius: DVec2, wrap: EdgeWrap },
// ...
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.