mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add Graphic::None and store paint choices as plain color, gradient, and no-paint values
This commit is contained in:
committed by
Dennis Kobert
parent
9dd1e2bdf9
commit
8e233d3229
@@ -69,7 +69,7 @@ struct LegacyTable<T> {
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_to_optional_color<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Option<no_std_types::color::Color>, D::Error> {
|
||||
pub fn migrate_to_color<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<no_std_types::color::Color, D::Error> {
|
||||
use no_std_types::color::Color;
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -81,8 +81,8 @@ pub fn migrate_to_optional_color<'de, D: serde::Deserializer<'de>>(deserializer:
|
||||
}
|
||||
|
||||
Ok(match ColorFormat::deserialize(deserializer)? {
|
||||
ColorFormat::OptionalColor(color) => color,
|
||||
ColorFormat::List(list) => list.element.into_iter().next(),
|
||||
ColorFormat::OptionalColor(color) => color.unwrap_or(Color::TRANSPARENT),
|
||||
ColorFormat::List(list) => list.element.into_iter().next().unwrap_or(Color::TRANSPARENT),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use vector_types::Vector;
|
||||
/// [`map_groups_to_resident`] re-parks it into a serving arena.
|
||||
pub fn map_groups_to_owned<'out>(graphic: &Graphic<'_>) -> Graphic<'out> {
|
||||
match graphic {
|
||||
Graphic::None => Graphic::None,
|
||||
Graphic::Group(group) => Graphic::Group(group.copy_out()),
|
||||
Graphic::Graphic(children) => {
|
||||
let mut out = List::new();
|
||||
@@ -78,6 +79,7 @@ unsafe fn deep_repark_graphic(value: &(dyn std::any::Any + Send + Sync), dst: *m
|
||||
/// what this level newly produced. `None` reports arena exhaustion.
|
||||
pub fn map_groups_to_persistent<'p>(graphic: &Graphic<'_>, promotion: &core_types::record::Promotion<'p>) -> Option<Graphic<'p>> {
|
||||
match graphic {
|
||||
Graphic::None => Some(Graphic::None),
|
||||
Graphic::Group(group) => group.to_persistent(promotion).map(Graphic::Group),
|
||||
Graphic::Graphic(children) => {
|
||||
let mut out = List::new();
|
||||
@@ -196,7 +198,7 @@ fn graphic_retained_heap(graphic: &Graphic<'_>) -> usize {
|
||||
Graphic::Text(text) => text.len(),
|
||||
Graphic::Gradient(gradient) => gradient.len() * size_of::<(f64, Color)>(),
|
||||
Graphic::Graphic(children) => (0..children.len()).filter_map(|index| children.element(index)).map(graphic_retained_heap).sum(),
|
||||
Graphic::Group(_) | Graphic::RasterGPU(_) | Graphic::Color(_) => 0,
|
||||
Graphic::None | Graphic::Group(_) | Graphic::RasterGPU(_) | Graphic::Color(_) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ pub(crate) fn run_to_legacy_list<T: Clone + Send + Sync + dyn_any::StaticTypeSiz
|
||||
/// The graphic with every `Group` converted to its legacy form.
|
||||
pub fn map_groups_to_legacy<'out>(graphic: &Graphic<'_>) -> Graphic<'out> {
|
||||
match graphic {
|
||||
Graphic::None => Graphic::None,
|
||||
Graphic::Group(group) => group_to_legacy_graphic(group),
|
||||
Graphic::Graphic(children) => {
|
||||
let mut out = List::new();
|
||||
|
||||
@@ -31,8 +31,11 @@ pub use vector_types::Vector;
|
||||
/// A leaf holds its element directly; its attributes ride the containing
|
||||
/// lane. Multi-element content is a [`core_types::record::Group`] run, or
|
||||
/// transitionally the legacy `Graphic` list.
|
||||
#[derive(Clone, Debug, CacheHash, PartialEq, DynAny)]
|
||||
#[derive(Clone, Debug, Default, CacheHash, PartialEq, DynAny)]
|
||||
pub enum Graphic<'e> {
|
||||
/// The absence of graphical content, like CSS's `none` keyword: painting it produces nothing.
|
||||
#[default]
|
||||
None,
|
||||
Graphic(List<Graphic<'e>>),
|
||||
Vector(Vector),
|
||||
RasterCPU(Raster<CPU>),
|
||||
@@ -43,12 +46,6 @@ pub enum Graphic<'e> {
|
||||
Group(core_types::record::Group<'e>),
|
||||
}
|
||||
|
||||
impl Default for Graphic<'_> {
|
||||
fn default() -> Self {
|
||||
Self::Graphic(List::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// A typed legacy list as a legacy graphic list: each item de-tables to a
|
||||
/// leaf element, keeping its attributes on the containing lane.
|
||||
pub(in crate::graphic) fn detable_items<'e, T: Clone + Send + Sync + 'static>(list: List<T>, leaf: fn(T) -> Graphic<'e>) -> List<Graphic<'e>> {
|
||||
@@ -382,6 +379,7 @@ impl<'e> Graphic<'e> {
|
||||
}
|
||||
|
||||
match self {
|
||||
Graphic::None => true,
|
||||
Graphic::Graphic(list) => all_clipped(list),
|
||||
Graphic::Group(group) => group_all_clipped(group),
|
||||
_ => false,
|
||||
@@ -397,6 +395,7 @@ impl<'e> Graphic<'e> {
|
||||
|
||||
pub fn is_opaque(&self) -> bool {
|
||||
match self {
|
||||
Graphic::None => false,
|
||||
Graphic::Graphic(list) => !list.is_empty() && list.iter_element_values().all(Graphic::is_opaque),
|
||||
// A bare leaf carries no paint attribute, which rides its lane, so
|
||||
// nothing here claims opacity.
|
||||
@@ -410,6 +409,7 @@ impl<'e> Graphic<'e> {
|
||||
|
||||
pub fn is_fully_transparent(&self) -> bool {
|
||||
match self {
|
||||
Graphic::None => true,
|
||||
Graphic::Graphic(list) => list.iter_element_values().all(Graphic::is_fully_transparent),
|
||||
// A bare leaf carries no paint attribute, so only an unstroked
|
||||
// vector is invisible on its own.
|
||||
@@ -430,6 +430,7 @@ impl<'e> Graphic<'e> {
|
||||
/// Whether the graphic holds no content: a leaf always holds its element.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
Graphic::None => true,
|
||||
Graphic::Graphic(list) => list.is_empty(),
|
||||
Graphic::Group(group) => group_is_empty(group),
|
||||
_ => false,
|
||||
@@ -440,6 +441,7 @@ impl<'e> Graphic<'e> {
|
||||
impl BoundingBox for Graphic<'_> {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||
match self {
|
||||
Graphic::None => RenderBoundingBox::None,
|
||||
Graphic::Vector(vector) => BoundingBox::bounding_box(vector, transform, include_stroke),
|
||||
Graphic::RasterCPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
@@ -453,6 +455,7 @@ impl BoundingBox for Graphic<'_> {
|
||||
|
||||
fn thumbnail_bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||
match self {
|
||||
Graphic::None => RenderBoundingBox::None,
|
||||
Graphic::Vector(vector) => vector.thumbnail_bounding_box(transform, include_stroke),
|
||||
Graphic::RasterCPU(raster) => raster.thumbnail_bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(raster) => raster.thumbnail_bounding_box(transform, include_stroke),
|
||||
@@ -484,6 +487,7 @@ impl<'e> ListConvert<Graphic<'e>> for Raster<GPU> {
|
||||
impl RenderComplexity for Graphic<'_> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
match self {
|
||||
Self::None => 0,
|
||||
Self::Graphic(list) => list.render_complexity(),
|
||||
Self::Vector(list) => list.render_complexity(),
|
||||
Self::RasterCPU(list) => list.render_complexity(),
|
||||
|
||||
@@ -256,6 +256,7 @@ impl RenderExt for List<Graphic<'_>> {
|
||||
let gradient_id = render_gradient_paint(&core_types::lane::LeafLane::new(self, 0, gradient), svg_defs, item_transform, element_transform);
|
||||
format!(r##" {paint_attr}="url(#{gradient_id})""##)
|
||||
}
|
||||
Some(Graphic::None) => format!(r#" {paint_attr}="none""#),
|
||||
Some(Graphic::Vector(_)) | Some(Graphic::RasterCPU(_)) | Some(Graphic::RasterGPU(_)) | Some(Graphic::Graphic(_)) | Some(Graphic::Text(_)) | Some(Graphic::Group(_)) => {
|
||||
let bounds = if target == PaintTarget::Stroke {
|
||||
// To prevent a wraparound artefact occurring when the tile boundary and the stroke region are perfectly aligned, the local coordinate is expanded slightly.
|
||||
|
||||
@@ -552,6 +552,7 @@ pub trait Render: BoundingBox + RenderComplexity {
|
||||
impl Render for Graphic<'_> {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||
match self {
|
||||
Graphic::None => (),
|
||||
Graphic::Graphic(list) => list.render_svg(render, render_params),
|
||||
Graphic::Vector(vector) => render_vector_svg(&Single(vector), render, render_params),
|
||||
Graphic::RasterCPU(raster) => render_raster_cpu_svg(&Single(raster), render, render_params),
|
||||
@@ -565,6 +566,7 @@ impl Render for Graphic<'_> {
|
||||
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||
match self {
|
||||
Graphic::None => (),
|
||||
Graphic::Graphic(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||
Graphic::Vector(vector) => render_vector_vello(&Single(vector), scene, transform, context, render_params),
|
||||
Graphic::RasterCPU(raster) => render_raster_cpu_vello(&Single(raster), scene, transform, render_params),
|
||||
@@ -590,6 +592,7 @@ impl Render for Graphic<'_> {
|
||||
|
||||
fn contains_artboard(&self) -> bool {
|
||||
match self {
|
||||
Graphic::None => false,
|
||||
Graphic::Graphic(list) => list.contains_artboard(),
|
||||
_ => false,
|
||||
}
|
||||
@@ -597,6 +600,7 @@ impl Render for Graphic<'_> {
|
||||
|
||||
fn new_ids_from_hash(&mut self, reference: Option<NodeId>) {
|
||||
match self {
|
||||
Graphic::None => (),
|
||||
Graphic::Graphic(list) => list.new_ids_from_hash(reference),
|
||||
Graphic::Vector(vector) => vector.vector_new_ids_from_hash(reference.map(|id| id.0).unwrap_or_default()),
|
||||
_ => (),
|
||||
@@ -660,6 +664,7 @@ fn collect_element_metadata<'a>(
|
||||
}
|
||||
|
||||
match element {
|
||||
Graphic::None => {}
|
||||
Graphic::Graphic(list) => collect_graphic_metadata_with(list, reach.nested(), metadata, footprint, element_id),
|
||||
Graphic::Vector(vector) if reach.applies() => collect_vector_metadata(&PaintOverlay::new(&Single(vector), reach.paint), metadata, footprint, element_id),
|
||||
Graphic::Vector(vector) => collect_vector_metadata(&Single(vector), metadata, footprint, element_id),
|
||||
@@ -703,6 +708,7 @@ fn collect_group_row_metadata(group: &Group, metadata: &mut RenderMetadata, elem
|
||||
|
||||
fn add_element_upstream_click_targets<'a>(element: &'a Graphic, reach: PaintReach<'a>, click_targets: &mut Vec<ClickTarget>) {
|
||||
match element {
|
||||
Graphic::None => (),
|
||||
Graphic::Graphic(list) => add_graphic_upstream_click_targets_with(list, reach.nested(), click_targets),
|
||||
Graphic::Vector(vector) if reach.applies() => add_vector_upstream_click_targets(&PaintOverlay::new(&Single(vector), reach.paint), click_targets),
|
||||
Graphic::Vector(vector) => add_vector_upstream_click_targets(&Single(vector), click_targets),
|
||||
@@ -715,6 +721,7 @@ fn add_element_upstream_click_targets<'a>(element: &'a Graphic, reach: PaintReac
|
||||
|
||||
fn add_element_upstream_outline_targets<'a>(element: &'a Graphic, reach: PaintReach<'a>, outlines: &mut Vec<ClickTarget>) {
|
||||
match element {
|
||||
Graphic::None => (),
|
||||
Graphic::Graphic(list) => add_graphic_upstream_outline_targets_with(list, reach.nested(), outlines),
|
||||
Graphic::Vector(vector) if reach.applies() => add_vector_upstream_outline_targets(&PaintOverlay::new(&Single(vector), reach.paint), outlines),
|
||||
Graphic::Vector(vector) => add_vector_upstream_outline_targets(&Single(vector), outlines),
|
||||
@@ -1563,6 +1570,7 @@ fn render_vector_vello<S: LaneSource<Element = Vector>>(source: &S, scene: &mut
|
||||
for paint_index in 0..fill_graphic.len() {
|
||||
let Some(paint) = fill_graphic.element(paint_index) else { continue };
|
||||
match paint {
|
||||
Graphic::None => continue,
|
||||
Graphic::Color(color) => {
|
||||
let fill = peniko::Brush::Solid(SRGBA8::from(*color).to_peniko_color());
|
||||
scene.fill(fill_rule, kurbo::Affine::new(element_transform.to_cols_array()), &fill, None, path);
|
||||
@@ -1643,6 +1651,7 @@ fn render_vector_vello<S: LaneSource<Element = Vector>>(source: &S, scene: &mut
|
||||
};
|
||||
|
||||
match stroke_graphic {
|
||||
Graphic::None => continue,
|
||||
Graphic::Color(color) => {
|
||||
let brush = peniko::Brush::Solid(SRGBA8::from(*color).to_peniko_color());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user