mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-07 15:55:00 +00:00
Merge 8f60a45241
into ce605acf3a
This commit is contained in:
commit
088f3cf8c5
6 changed files with 104 additions and 8 deletions
|
@ -27,7 +27,7 @@ use graphene_std::vector::misc::GridType;
|
|||
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
|
||||
use graphene_std::vector::misc::{CentroidType, PointSpacingType};
|
||||
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
|
||||
use graphene_std::vector::style::{GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphene_std::vector::style::{GradientType, PaintOrder, ShapeRenderingModes, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphene_std::{GraphicGroupTable, NodeInputDecleration};
|
||||
|
||||
pub(crate) fn string_properties(text: &str) -> Vec<LayoutGroup> {
|
||||
|
@ -230,6 +230,7 @@ pub(crate) fn property_from_type(
|
|||
Some(x) if x == TypeId::of::<BooleanOperation>() => enum_choice::<BooleanOperation>().for_socket(default_info).property_row(),
|
||||
Some(x) if x == TypeId::of::<CentroidType>() => enum_choice::<CentroidType>().for_socket(default_info).property_row(),
|
||||
Some(x) if x == TypeId::of::<LuminanceCalculation>() => enum_choice::<LuminanceCalculation>().for_socket(default_info).property_row(),
|
||||
Some(x) if x == TypeId::of::<ShapeRenderingModes>() => enum_choice::<ShapeRenderingModes>().for_socket(default_info).property_row(),
|
||||
// =====
|
||||
// OTHER
|
||||
// =====
|
||||
|
|
|
@ -468,17 +468,42 @@ impl Default for Stroke {
|
|||
}
|
||||
}
|
||||
|
||||
/// The shape-rendering attribute provides hints to the renderer about what tradeoffs to make when rendering shapes like paths, circles, or rectangles.
|
||||
/// See https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/shape-rendering
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
|
||||
#[widget(Dropdown)]
|
||||
pub enum ShapeRenderingModes {
|
||||
#[default]
|
||||
Auto,
|
||||
OptimizeSpeed,
|
||||
CrispEdges,
|
||||
GeometricPrecision,
|
||||
}
|
||||
|
||||
impl ShapeRenderingModes {
|
||||
pub fn svg_name(&self) -> &'static str {
|
||||
match self {
|
||||
ShapeRenderingModes::Auto => "auto",
|
||||
ShapeRenderingModes::OptimizeSpeed => "optimizeSpeed",
|
||||
ShapeRenderingModes::CrispEdges => "crispEdges",
|
||||
ShapeRenderingModes::GeometricPrecision => "geometricPrecision",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, DynAny, specta::Type)]
|
||||
pub struct PathStyle {
|
||||
pub stroke: Option<Stroke>,
|
||||
pub fill: Fill,
|
||||
pub shape_rendering: ShapeRenderingModes,
|
||||
}
|
||||
|
||||
impl std::hash::Hash for PathStyle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.stroke.hash(state);
|
||||
self.fill.hash(state);
|
||||
self.shape_rendering.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,13 +516,15 @@ impl std::fmt::Display for PathStyle {
|
|||
None => "None".to_string(),
|
||||
};
|
||||
|
||||
write!(f, "Fill: {fill}\nStroke: {stroke}")
|
||||
let shape_rendering = &self.shape_rendering;
|
||||
|
||||
write!(f, "Fill: {fill}\nStroke: {stroke}\nShape-Rendering: {shape_rendering}")
|
||||
}
|
||||
}
|
||||
|
||||
impl PathStyle {
|
||||
pub const fn new(stroke: Option<Stroke>, fill: Fill) -> Self {
|
||||
Self { stroke, fill }
|
||||
pub const fn new(stroke: Option<Stroke>, fill: Fill, shape_rendering: ShapeRenderingModes) -> Self {
|
||||
Self { stroke, fill, shape_rendering }
|
||||
}
|
||||
|
||||
pub fn lerp(&self, other: &Self, time: f64) -> Self {
|
||||
|
@ -521,6 +548,7 @@ impl PathStyle {
|
|||
}
|
||||
(None, None) => None,
|
||||
},
|
||||
shape_rendering: self.shape_rendering,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,6 +626,11 @@ impl PathStyle {
|
|||
self.stroke = Some(stroke);
|
||||
}
|
||||
|
||||
/// Replace the path's [ShapeRenderingModes] with a provided one.
|
||||
pub fn set_shape_rendering(&mut self, shape_rendering: ShapeRenderingModes) {
|
||||
self.shape_rendering = shape_rendering;
|
||||
}
|
||||
|
||||
/// Set the path's fill to None.
|
||||
///
|
||||
/// # Example
|
||||
|
|
|
@ -97,7 +97,7 @@ pub struct VectorData {
|
|||
impl Default for VectorData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
style: PathStyle::new(Some(Stroke::new(Some(Color::BLACK), 0.)), super::style::Fill::None),
|
||||
style: PathStyle::new(Some(Stroke::new(Some(Color::BLACK), 0.)), super::style::Fill::None, super::style::ShapeRenderingModes::Auto),
|
||||
colinear_manipulators: Vec::new(),
|
||||
point_domain: PointDomain::new(),
|
||||
segment_domain: SegmentDomain::new(),
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::algorithms::bezpath_algorithms::{self, position_on_bezpath, sample_po
|
|||
use super::algorithms::offset_subpath::offset_subpath;
|
||||
use super::algorithms::spline::{solve_spline_first_handle_closed, solve_spline_first_handle_open};
|
||||
use super::misc::{CentroidType, point_to_dvec2};
|
||||
use super::style::{Fill, Gradient, GradientStops, Stroke};
|
||||
use super::style::{Fill, Gradient, GradientStops, ShapeRenderingModes, Stroke};
|
||||
use super::{PointId, SegmentDomain, SegmentId, StrokeId, VectorData, VectorDataExt, VectorDataTable};
|
||||
use crate::bounds::BoundingBox;
|
||||
use crate::instances::{Instance, InstanceMut, Instances};
|
||||
|
@ -214,6 +214,35 @@ where
|
|||
vector_data
|
||||
}
|
||||
|
||||
/// Set the shape-render SVG property for all input vectors. Determines anti-aliasing, but output varies by renderer.
|
||||
/// Not implimented in Vello
|
||||
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector))]
|
||||
async fn shape_render_mode<V>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
VectorDataTable,
|
||||
VectorDataTable,
|
||||
VectorDataTable,
|
||||
VectorDataTable,
|
||||
GraphicGroupTable,
|
||||
GraphicGroupTable,
|
||||
GraphicGroupTable,
|
||||
GraphicGroupTable
|
||||
)]
|
||||
/// The vector elements, or group of vector elements, to apply the shape render mode to.
|
||||
mut vector_data: V,
|
||||
render_mode: ShapeRenderingModes,
|
||||
) -> V
|
||||
where
|
||||
V: VectorDataTableIterMut + 'n + Send,
|
||||
{
|
||||
for vector in vector_data.vector_iter_mut() {
|
||||
vector.instance.style.set_shape_rendering(render_mode);
|
||||
}
|
||||
|
||||
vector_data
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Instancing"), path(graphene_core::vector))]
|
||||
async fn repeat<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
|
|
|
@ -248,6 +248,7 @@ tagged_value! {
|
|||
ReferencePoint(graphene_core::transform::ReferencePoint),
|
||||
CentroidType(graphene_core::vector::misc::CentroidType),
|
||||
BooleanOperation(graphene_path_bool::BooleanOperation),
|
||||
ShapeRenderingModes(graphene_core::vector::style::ShapeRenderingModes),
|
||||
}
|
||||
|
||||
impl TaggedValue {
|
||||
|
|
|
@ -3,7 +3,7 @@ use glam::{DAffine2, DVec2};
|
|||
use graphene_core::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||
use graphene_core::gradient::{Gradient, GradientType};
|
||||
use graphene_core::uuid::generate_uuid;
|
||||
use graphene_core::vector::style::{Fill, PaintOrder, PathStyle, Stroke, StrokeAlign, StrokeCap, StrokeJoin, ViewMode};
|
||||
use graphene_core::vector::style::{Fill, PaintOrder, PathStyle, ShapeRenderingModes, Stroke, StrokeAlign, StrokeCap, StrokeJoin, ViewMode};
|
||||
use std::fmt::Write;
|
||||
|
||||
pub trait RenderExt {
|
||||
|
@ -200,6 +200,26 @@ impl RenderExt for Stroke {
|
|||
}
|
||||
}
|
||||
|
||||
impl RenderExt for ShapeRenderingModes {
|
||||
type Output = String;
|
||||
|
||||
/// Provide the SVG attributes for the stroke.
|
||||
fn render(
|
||||
&self,
|
||||
_svg_defs: &mut String,
|
||||
_element_transform: DAffine2,
|
||||
_stroke_transform: DAffine2,
|
||||
_bounds: [DVec2; 2],
|
||||
_transformed_bounds: [DVec2; 2],
|
||||
_aligned_strokes: bool,
|
||||
_override_paint_order: bool,
|
||||
_render_params: &RenderParams,
|
||||
) -> Self::Output {
|
||||
let svg_name = self.svg_name();
|
||||
format!(" shape-rendering=\"{svg_name}\"")
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderExt for PathStyle {
|
||||
type Output = String;
|
||||
|
||||
|
@ -271,7 +291,19 @@ impl RenderExt for PathStyle {
|
|||
)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
format!("{fill_attribute}{stroke_attribute}")
|
||||
|
||||
let shape_rendering_attribute = self.shape_rendering.render(
|
||||
svg_defs,
|
||||
element_transform,
|
||||
stroke_transform,
|
||||
bounds,
|
||||
transformed_bounds,
|
||||
aligned_strokes,
|
||||
override_paint_order,
|
||||
render_params,
|
||||
);
|
||||
|
||||
format!("{fill_attribute}{stroke_attribute}{shape_rendering_attribute}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue