mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Rename the Graphic enum wrapper variants with a "List" suffix (#4434)
* Make the Artboard and Gradient newtype fields public to match the other list newtypes * Rename the Graphic enum's self-named Graphic::Graphic variant to Graphic::GraphicList * Rename the Graphic::Vector variant to Graphic::VectorList * Rename the Graphic::RasterCPU variant to Graphic::RasterCPUList * Rename the Graphic::RasterGPU variant to Graphic::RasterGPUList * Rename the Graphic::Color variant to Graphic::ColorList * Rename the Graphic::Gradient variant to Graphic::GradientList * Rename the Graphic::Text variant to Graphic::TextList * Restore the SVG group tag comment that the variant rename sweep clobbered
This commit is contained in:
@@ -578,13 +578,13 @@ impl TableItemLayout for Graphic {
|
|||||||
fn identifier(&self) -> String {
|
fn identifier(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::None => "None".to_string(),
|
Self::None => "None".to_string(),
|
||||||
Self::Graphic(list) => list.identifier(),
|
Self::GraphicList(list) => list.identifier(),
|
||||||
Self::Vector(list) => list.identifier(),
|
Self::VectorList(list) => list.identifier(),
|
||||||
Self::RasterCPU(list) => list.identifier(),
|
Self::RasterCPUList(list) => list.identifier(),
|
||||||
Self::RasterGPU(list) => list.identifier(),
|
Self::RasterGPUList(list) => list.identifier(),
|
||||||
Self::Color(list) => list.identifier(),
|
Self::ColorList(list) => list.identifier(),
|
||||||
Self::Gradient(list) => list.identifier(),
|
Self::GradientList(list) => list.identifier(),
|
||||||
Self::Text(list) => list.identifier(),
|
Self::TextList(list) => list.identifier(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Don't put a breadcrumb for Graphic
|
// Don't put a breadcrumb for Graphic
|
||||||
@@ -594,13 +594,13 @@ impl TableItemLayout for Graphic {
|
|||||||
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
fn value_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||||
match self {
|
match self {
|
||||||
Self::None => label("None"),
|
Self::None => label("None"),
|
||||||
Self::Graphic(list) => list.layout_with_breadcrumb(data),
|
Self::GraphicList(list) => list.layout_with_breadcrumb(data),
|
||||||
Self::Vector(list) => list.layout_with_breadcrumb(data),
|
Self::VectorList(list) => list.layout_with_breadcrumb(data),
|
||||||
Self::RasterCPU(list) => list.layout_with_breadcrumb(data),
|
Self::RasterCPUList(list) => list.layout_with_breadcrumb(data),
|
||||||
Self::RasterGPU(list) => list.layout_with_breadcrumb(data),
|
Self::RasterGPUList(list) => list.layout_with_breadcrumb(data),
|
||||||
Self::Color(list) => list.layout_with_breadcrumb(data),
|
Self::ColorList(list) => list.layout_with_breadcrumb(data),
|
||||||
Self::Gradient(list) => list.layout_with_breadcrumb(data),
|
Self::GradientList(list) => list.layout_with_breadcrumb(data),
|
||||||
Self::Text(list) => list.layout_with_breadcrumb(data),
|
Self::TextList(list) => list.layout_with_breadcrumb(data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ impl NodeRuntime {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Graphic list: thumbnail (text-aware bounds, since the `BoundingBox` trait can't lay out `Graphic::Text` content)
|
// Graphic list: thumbnail (text-aware bounds, since the `BoundingBox` trait can't lay out `Graphic::TextList` content)
|
||||||
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, List<Graphic>>>() {
|
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, List<Graphic>>>() {
|
||||||
if update_thumbnails {
|
if update_thumbnails {
|
||||||
let bounds = graphene_std::renderer::graphic_list_bounding_box(&io.output, DAffine2::IDENTITY);
|
let bounds = graphene_std::renderer::graphic_list_bounding_box(&io.output, DAffine2::IDENTITY);
|
||||||
|
|||||||
@@ -282,12 +282,12 @@ mod tests {
|
|||||||
use vector_types::vector::style::{StrokeAlign, StrokeCap, StrokeJoin};
|
use vector_types::vector::style::{StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
|
|
||||||
fn solid_paint(color: Color) -> List<Graphic> {
|
fn solid_paint(color: Color) -> List<Graphic> {
|
||||||
List::new_from_element(Graphic::Color(List::new_from_element(color)))
|
List::new_from_element(Graphic::ColorList(List::new_from_element(color)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_color(appearance: &Appearance, index: usize) -> Option<Color> {
|
fn paint_color(appearance: &Appearance, index: usize) -> Option<Color> {
|
||||||
let paint = appearance.paint_at(index)?;
|
let paint = appearance.paint_at(index)?;
|
||||||
let Some(Graphic::Color(colors)) = paint.element(0) else { return None };
|
let Some(Graphic::ColorList(colors)) = paint.element(0) else { return None };
|
||||||
colors.element(0).copied()
|
colors.element(0).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use glam::DAffine2;
|
|||||||
/// enclosing `List<Artboard>`, not as fields here. This keeps `Artboard` a pure type-system boundary
|
/// enclosing `List<Artboard>`, not as fields here. This keeps `Artboard` a pure type-system boundary
|
||||||
/// that prevents arbitrary `List<List<...<Graphic>>>` nesting.
|
/// that prevents arbitrary `List<List<...<Graphic>>>` nesting.
|
||||||
#[derive(Clone, Debug, Default, CacheHash, PartialEq, DynAny)]
|
#[derive(Clone, Debug, Default, CacheHash, PartialEq, DynAny)]
|
||||||
pub struct Artboard(List<Graphic>);
|
pub struct Artboard(pub List<Graphic>);
|
||||||
|
|
||||||
impl Artboard {
|
impl Artboard {
|
||||||
pub fn new(content: List<Graphic>) -> Self {
|
pub fn new(content: List<Graphic>) -> Self {
|
||||||
|
|||||||
@@ -19,31 +19,31 @@ pub enum Graphic {
|
|||||||
/// The absence of graphical content, like CSS's `none` keyword: painting it produces nothing.
|
/// The absence of graphical content, like CSS's `none` keyword: painting it produces nothing.
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
Graphic(List<Graphic>),
|
GraphicList(List<Graphic>),
|
||||||
Vector(List<Vector>),
|
VectorList(List<Vector>),
|
||||||
RasterCPU(List<Raster<CPU>>),
|
RasterCPUList(List<Raster<CPU>>),
|
||||||
RasterGPU(List<Raster<GPU>>),
|
RasterGPUList(List<Raster<GPU>>),
|
||||||
Color(List<Color>),
|
ColorList(List<Color>),
|
||||||
Gradient(List<Gradient>),
|
GradientList(List<Gradient>),
|
||||||
Text(List<String>),
|
TextList(List<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Graphic
|
// GraphicList
|
||||||
impl From<List<Graphic>> for Graphic {
|
impl From<List<Graphic>> for Graphic {
|
||||||
fn from(graphic: List<Graphic>) -> Self {
|
fn from(graphic: List<Graphic>) -> Self {
|
||||||
Graphic::Graphic(graphic)
|
Graphic::GraphicList(graphic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vector
|
// Vector
|
||||||
impl From<Vector> for Graphic {
|
impl From<Vector> for Graphic {
|
||||||
fn from(vector: Vector) -> Self {
|
fn from(vector: Vector) -> Self {
|
||||||
Graphic::Vector(List::new_from_element(vector))
|
Graphic::VectorList(List::new_from_element(vector))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<List<Vector>> for Graphic {
|
impl From<List<Vector>> for Graphic {
|
||||||
fn from(vector: List<Vector>) -> Self {
|
fn from(vector: List<Vector>) -> Self {
|
||||||
Graphic::Vector(vector)
|
Graphic::VectorList(vector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,12 +52,12 @@ impl From<List<Vector>> for Graphic {
|
|||||||
// Raster<CPU>
|
// Raster<CPU>
|
||||||
impl From<Raster<CPU>> for Graphic {
|
impl From<Raster<CPU>> for Graphic {
|
||||||
fn from(raster: Raster<CPU>) -> Self {
|
fn from(raster: Raster<CPU>) -> Self {
|
||||||
Graphic::RasterCPU(List::new_from_element(raster))
|
Graphic::RasterCPUList(List::new_from_element(raster))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<List<Raster<CPU>>> for Graphic {
|
impl From<List<Raster<CPU>>> for Graphic {
|
||||||
fn from(raster: List<Raster<CPU>>) -> Self {
|
fn from(raster: List<Raster<CPU>>) -> Self {
|
||||||
Graphic::RasterCPU(raster)
|
Graphic::RasterCPUList(raster)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Note: List conversions handled by blanket impl in gcore
|
// Note: List conversions handled by blanket impl in gcore
|
||||||
@@ -65,12 +65,12 @@ impl From<List<Raster<CPU>>> for Graphic {
|
|||||||
// Raster<GPU>
|
// Raster<GPU>
|
||||||
impl From<Raster<GPU>> for Graphic {
|
impl From<Raster<GPU>> for Graphic {
|
||||||
fn from(raster: Raster<GPU>) -> Self {
|
fn from(raster: Raster<GPU>) -> Self {
|
||||||
Graphic::RasterGPU(List::new_from_element(raster))
|
Graphic::RasterGPUList(List::new_from_element(raster))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<List<Raster<GPU>>> for Graphic {
|
impl From<List<Raster<GPU>>> for Graphic {
|
||||||
fn from(raster: List<Raster<GPU>>) -> Self {
|
fn from(raster: List<Raster<GPU>>) -> Self {
|
||||||
Graphic::RasterGPU(raster)
|
Graphic::RasterGPUList(raster)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Note: List conversions handled by blanket impl in gcore
|
// Note: List conversions handled by blanket impl in gcore
|
||||||
@@ -78,12 +78,12 @@ impl From<List<Raster<GPU>>> for Graphic {
|
|||||||
// Color
|
// Color
|
||||||
impl From<Color> for Graphic {
|
impl From<Color> for Graphic {
|
||||||
fn from(color: Color) -> Self {
|
fn from(color: Color) -> Self {
|
||||||
Graphic::Color(List::new_from_element(color))
|
Graphic::ColorList(List::new_from_element(color))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<List<Color>> for Graphic {
|
impl From<List<Color>> for Graphic {
|
||||||
fn from(color: List<Color>) -> Self {
|
fn from(color: List<Color>) -> Self {
|
||||||
Graphic::Color(color)
|
Graphic::ColorList(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Note: List conversions handled by blanket impl in gcore
|
// Note: List conversions handled by blanket impl in gcore
|
||||||
@@ -92,24 +92,24 @@ impl From<List<Color>> for Graphic {
|
|||||||
// Gradient
|
// Gradient
|
||||||
impl From<Gradient> for Graphic {
|
impl From<Gradient> for Graphic {
|
||||||
fn from(gradient: Gradient) -> Self {
|
fn from(gradient: Gradient) -> Self {
|
||||||
Graphic::Gradient(List::new_from_element(gradient))
|
Graphic::GradientList(List::new_from_element(gradient))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<List<Gradient>> for Graphic {
|
impl From<List<Gradient>> for Graphic {
|
||||||
fn from(gradient: List<Gradient>) -> Self {
|
fn from(gradient: List<Gradient>) -> Self {
|
||||||
Graphic::Gradient(gradient)
|
Graphic::GradientList(gradient)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String
|
// String
|
||||||
impl From<String> for Graphic {
|
impl From<String> for Graphic {
|
||||||
fn from(text: String) -> Self {
|
fn from(text: String) -> Self {
|
||||||
Graphic::Text(List::new_from_element(text))
|
Graphic::TextList(List::new_from_element(text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<List<String>> for Graphic {
|
impl From<List<String>> for Graphic {
|
||||||
fn from(text: List<String>) -> Self {
|
fn from(text: List<String>) -> Self {
|
||||||
Graphic::Text(text)
|
Graphic::TextList(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ impl From<List<String>> for Graphic {
|
|||||||
/// collapses no structure and rebuilding or snapshotting the result would be busywork.
|
/// collapses no structure and rebuilding or snapshotting the result would be busywork.
|
||||||
pub fn is_lone_anonymous_leaf(content: &List<Graphic>) -> bool {
|
pub fn is_lone_anonymous_leaf(content: &List<Graphic>) -> bool {
|
||||||
content.len() == 1
|
content.len() == 1
|
||||||
&& !matches!(content.element(0), Some(Graphic::Graphic(_)))
|
&& !matches!(content.element(0), Some(Graphic::GraphicList(_)))
|
||||||
&& content.attribute::<DAffine2>(ATTR_TRANSFORM, 0).is_none()
|
&& content.attribute::<DAffine2>(ATTR_TRANSFORM, 0).is_none()
|
||||||
&& content.attribute::<f64>(ATTR_OPACITY, 0).is_none()
|
&& content.attribute::<f64>(ATTR_OPACITY, 0).is_none()
|
||||||
&& content.attribute::<f64>(ATTR_OPACITY_FILL, 0).is_none()
|
&& content.attribute::<f64>(ATTR_OPACITY_FILL, 0).is_none()
|
||||||
@@ -126,7 +126,7 @@ pub fn is_lone_anonymous_leaf(content: &List<Graphic>) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Deeply flattens a `List<Graphic>`, collecting only elements matching a specific variant (extracted by `extract_variant`)
|
/// Deeply flattens a `List<Graphic>`, collecting only elements matching a specific variant (extracted by `extract_variant`)
|
||||||
/// and discarding all other non-matching content. Recursion through `Graphic::Graphic` sub-`List`s composes transforms and opacity.
|
/// and discarding all other non-matching content. Recursion through `Graphic::GraphicList` sub-`List`s composes transforms and opacity.
|
||||||
fn flatten_graphic_list<T>(content: List<Graphic>, extract_variant: fn(Graphic) -> Option<List<T>>) -> List<T> {
|
fn flatten_graphic_list<T>(content: List<Graphic>, extract_variant: fn(Graphic) -> Option<List<T>>) -> List<T> {
|
||||||
// Its list is already the flat answer, so hand it back rather than rebuilding it item by item
|
// Its list is already the flat answer, so hand it back rather than rebuilding it item by item
|
||||||
if is_lone_anonymous_leaf(&content) {
|
if is_lone_anonymous_leaf(&content) {
|
||||||
@@ -154,7 +154,7 @@ fn flatten_graphic_list<T>(content: List<Graphic>, extract_variant: fn(Graphic)
|
|||||||
match current_graphic_item.into_element() {
|
match current_graphic_item.into_element() {
|
||||||
// Compose the parent's transform/opacity/fill onto each child, but only for attributes the parent carries.
|
// Compose the parent's transform/opacity/fill onto each child, but only for attributes the parent carries.
|
||||||
// A child lacking one is padded with the composition identity (`1.` for opacity/fill, identity for transform), so composing through it is a no-op.
|
// A child lacking one is padded with the composition identity (`1.` for opacity/fill, identity for transform), so composing through it is a no-op.
|
||||||
Graphic::Graphic(mut sub_list) => {
|
Graphic::GraphicList(mut sub_list) => {
|
||||||
// A group's first child has no preceding sibling, so its clipping flag is inert until splicing
|
// A group's first child has no preceding sibling, so its clipping flag is inert until splicing
|
||||||
// hands it the group's own predecessor. Clear it (keeping the column) to stay clip-neutral.
|
// hands it the group's own predecessor. Clear it (keeping the column) to stay clip-neutral.
|
||||||
if sub_list.attribute::<bool>(ATTR_CLIPPING_MASK, 0).is_some() {
|
if sub_list.attribute::<bool>(ATTR_CLIPPING_MASK, 0).is_some() {
|
||||||
@@ -244,13 +244,13 @@ pub fn bake_paint_transforms(attributes: &mut ItemAttributeValues, transform: DA
|
|||||||
fn bake_graphic_transform(graphic: &mut Graphic, transform: DAffine2) {
|
fn bake_graphic_transform(graphic: &mut Graphic, transform: DAffine2) {
|
||||||
match graphic {
|
match graphic {
|
||||||
Graphic::None => {}
|
Graphic::None => {}
|
||||||
Graphic::Graphic(list) => bake_list_transform(list, transform),
|
Graphic::GraphicList(list) => bake_list_transform(list, transform),
|
||||||
Graphic::Vector(list) => bake_list_transform(list, transform),
|
Graphic::VectorList(list) => bake_list_transform(list, transform),
|
||||||
Graphic::RasterCPU(list) => bake_list_transform(list, transform),
|
Graphic::RasterCPUList(list) => bake_list_transform(list, transform),
|
||||||
Graphic::RasterGPU(list) => bake_list_transform(list, transform),
|
Graphic::RasterGPUList(list) => bake_list_transform(list, transform),
|
||||||
Graphic::Gradient(list) => bake_list_transform(list, transform),
|
Graphic::GradientList(list) => bake_list_transform(list, transform),
|
||||||
Graphic::Text(list) => bake_list_transform(list, transform),
|
Graphic::TextList(list) => bake_list_transform(list, transform),
|
||||||
Graphic::Color(_) => {}
|
Graphic::ColorList(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,31 +273,31 @@ pub trait TryFromGraphic: Clone + Sized {
|
|||||||
|
|
||||||
impl TryFromGraphic for Vector {
|
impl TryFromGraphic for Vector {
|
||||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||||
if let Graphic::Vector(t) = graphic { Some(t) } else { None }
|
if let Graphic::VectorList(t) = graphic { Some(t) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFromGraphic for Raster<CPU> {
|
impl TryFromGraphic for Raster<CPU> {
|
||||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||||
if let Graphic::RasterCPU(t) = graphic { Some(t) } else { None }
|
if let Graphic::RasterCPUList(t) = graphic { Some(t) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFromGraphic for Color {
|
impl TryFromGraphic for Color {
|
||||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||||
if let Graphic::Color(t) = graphic { Some(t) } else { None }
|
if let Graphic::ColorList(t) = graphic { Some(t) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFromGraphic for Gradient {
|
impl TryFromGraphic for Gradient {
|
||||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||||
if let Graphic::Gradient(t) = graphic { Some(t) } else { None }
|
if let Graphic::GradientList(t) = graphic { Some(t) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFromGraphic for String {
|
impl TryFromGraphic for String {
|
||||||
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
fn try_from_graphic(graphic: Graphic) -> Option<List<Self>> {
|
||||||
if let Graphic::Text(t) = graphic { Some(t) } else { None }
|
if let Graphic::TextList(t) = graphic { Some(t) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,37 +324,37 @@ impl IntoGraphicList for List<Vector> {
|
|||||||
fn into_graphic_list(self) -> List<Graphic> {
|
fn into_graphic_list(self) -> List<Graphic> {
|
||||||
// A synthetic container, not a real group layer, so it carries no `editor:layer_path` that would
|
// A synthetic container, not a real group layer, so it carries no `editor:layer_path` that would
|
||||||
// overwrite the inner items' own stamps when flattened back out
|
// overwrite the inner items' own stamps when flattened back out
|
||||||
List::new_from_element(Graphic::Vector(self))
|
List::new_from_element(Graphic::VectorList(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoGraphicList for List<Raster<CPU>> {
|
impl IntoGraphicList for List<Raster<CPU>> {
|
||||||
fn into_graphic_list(self) -> List<Graphic> {
|
fn into_graphic_list(self) -> List<Graphic> {
|
||||||
List::new_from_element(Graphic::RasterCPU(self))
|
List::new_from_element(Graphic::RasterCPUList(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoGraphicList for List<Raster<GPU>> {
|
impl IntoGraphicList for List<Raster<GPU>> {
|
||||||
fn into_graphic_list(self) -> List<Graphic> {
|
fn into_graphic_list(self) -> List<Graphic> {
|
||||||
List::new_from_element(Graphic::RasterGPU(self))
|
List::new_from_element(Graphic::RasterGPUList(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoGraphicList for List<Color> {
|
impl IntoGraphicList for List<Color> {
|
||||||
fn into_graphic_list(self) -> List<Graphic> {
|
fn into_graphic_list(self) -> List<Graphic> {
|
||||||
List::new_from_element(Graphic::Color(self))
|
List::new_from_element(Graphic::ColorList(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoGraphicList for List<Gradient> {
|
impl IntoGraphicList for List<Gradient> {
|
||||||
fn into_graphic_list(self) -> List<Graphic> {
|
fn into_graphic_list(self) -> List<Graphic> {
|
||||||
List::new_from_element(Graphic::Gradient(self))
|
List::new_from_element(Graphic::GradientList(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoGraphicList for List<String> {
|
impl IntoGraphicList for List<String> {
|
||||||
fn into_graphic_list(self) -> List<Graphic> {
|
fn into_graphic_list(self) -> List<Graphic> {
|
||||||
List::new_from_element(Graphic::Text(self))
|
List::new_from_element(Graphic::TextList(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,50 +374,50 @@ impl From<Item<DAffine2>> for Graphic {
|
|||||||
// DVec2
|
// DVec2
|
||||||
impl From<Item<DVec2>> for Graphic {
|
impl From<Item<DVec2>> for Graphic {
|
||||||
fn from(position: Item<DVec2>) -> Self {
|
fn from(position: Item<DVec2>) -> Self {
|
||||||
Graphic::Vector(List::new_from_element(Vector::from_anchor_position(position.into_element())))
|
Graphic::VectorList(List::new_from_element(Vector::from_anchor_position(position.into_element())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Note: List conversions handled by blanket impl in gcore
|
// Note: List conversions handled by blanket impl in gcore
|
||||||
|
|
||||||
impl Graphic {
|
impl Graphic {
|
||||||
pub fn as_graphic(&self) -> Option<&List<Graphic>> {
|
pub fn as_graphic_list(&self) -> Option<&List<Graphic>> {
|
||||||
match self {
|
match self {
|
||||||
Graphic::Graphic(graphic) => Some(graphic),
|
Graphic::GraphicList(graphic_list) => Some(graphic_list),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_graphic_mut(&mut self) -> Option<&mut List<Graphic>> {
|
pub fn as_graphic_list_mut(&mut self) -> Option<&mut List<Graphic>> {
|
||||||
match self {
|
match self {
|
||||||
Graphic::Graphic(graphic) => Some(graphic),
|
Graphic::GraphicList(graphic_list) => Some(graphic_list),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_vector(&self) -> Option<&List<Vector>> {
|
pub fn as_vector_list(&self) -> Option<&List<Vector>> {
|
||||||
match self {
|
match self {
|
||||||
Graphic::Vector(vector) => Some(vector),
|
Graphic::VectorList(vector) => Some(vector),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_vector_mut(&mut self) -> Option<&mut List<Vector>> {
|
pub fn as_vector_list_mut(&mut self) -> Option<&mut List<Vector>> {
|
||||||
match self {
|
match self {
|
||||||
Graphic::Vector(vector) => Some(vector),
|
Graphic::VectorList(vector) => Some(vector),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_raster(&self) -> Option<&List<Raster<CPU>>> {
|
pub fn as_raster_cpu_list(&self) -> Option<&List<Raster<CPU>>> {
|
||||||
match self {
|
match self {
|
||||||
Graphic::RasterCPU(raster) => Some(raster),
|
Graphic::RasterCPUList(raster) => Some(raster),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_raster_mut(&mut self) -> Option<&mut List<Raster<CPU>>> {
|
pub fn as_raster_cpu_list_mut(&mut self) -> Option<&mut List<Raster<CPU>>> {
|
||||||
match self {
|
match self {
|
||||||
Graphic::RasterCPU(raster) => Some(raster),
|
Graphic::RasterCPUList(raster) => Some(raster),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,19 +429,19 @@ impl Graphic {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => true,
|
Graphic::None => true,
|
||||||
Graphic::Vector(list) => all_clipped(list),
|
Graphic::VectorList(list) => all_clipped(list),
|
||||||
Graphic::Graphic(list) => all_clipped(list),
|
Graphic::GraphicList(list) => all_clipped(list),
|
||||||
Graphic::RasterCPU(list) => all_clipped(list),
|
Graphic::RasterCPUList(list) => all_clipped(list),
|
||||||
Graphic::RasterGPU(list) => all_clipped(list),
|
Graphic::RasterGPUList(list) => all_clipped(list),
|
||||||
Graphic::Color(list) => all_clipped(list),
|
Graphic::ColorList(list) => all_clipped(list),
|
||||||
Graphic::Gradient(list) => all_clipped(list),
|
Graphic::GradientList(list) => all_clipped(list),
|
||||||
Graphic::Text(list) => all_clipped(list),
|
Graphic::TextList(list) => all_clipped(list),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_reduce_to_clip_path(&self) -> bool {
|
pub fn can_reduce_to_clip_path(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Graphic::Vector(vector) => (0..vector.len()).all(|index| {
|
Graphic::VectorList(vector) => (0..vector.len()).all(|index| {
|
||||||
let opacity: f64 = vector.attribute_cloned_or(ATTR_OPACITY, index, 1.);
|
let opacity: f64 = vector.attribute_cloned_or(ATTR_OPACITY, index, 1.);
|
||||||
let appearance = vector.attribute::<Appearance>(ATTR_APPEARANCE, index);
|
let appearance = vector.attribute::<Appearance>(ATTR_APPEARANCE, index);
|
||||||
|
|
||||||
@@ -468,8 +468,8 @@ impl Graphic {
|
|||||||
pub fn is_opaque(&self) -> bool {
|
pub fn is_opaque(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => false,
|
Graphic::None => false,
|
||||||
Graphic::Graphic(list) => !list.is_empty() && list.iter_element_values().all(Graphic::is_opaque),
|
Graphic::GraphicList(list) => !list.is_empty() && list.iter_element_values().all(Graphic::is_opaque),
|
||||||
Graphic::Vector(list) => {
|
Graphic::VectorList(list) => {
|
||||||
!list.is_empty()
|
!list.is_empty()
|
||||||
&& (0..list.len()).all(|i| {
|
&& (0..list.len()).all(|i| {
|
||||||
let opacity: f64 = list.attribute_cloned_or(ATTR_OPACITY, i, 1.);
|
let opacity: f64 = list.attribute_cloned_or(ATTR_OPACITY, i, 1.);
|
||||||
@@ -493,17 +493,17 @@ impl Graphic {
|
|||||||
opacity >= 1. - f64::EPSILON && fill_opaque && strokes_opaque_or_invisible
|
opacity >= 1. - f64::EPSILON && fill_opaque && strokes_opaque_or_invisible
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Graphic::Color(list) => list.element(0).is_some_and(|color| color.is_opaque()),
|
Graphic::ColorList(list) => list.element(0).is_some_and(|color| color.is_opaque()),
|
||||||
Graphic::Gradient(list) => list.element(0).is_some_and(|stops| stops.iter().all(|stop| stop.color.is_opaque())),
|
Graphic::GradientList(list) => list.element(0).is_some_and(|stops| stops.iter().all(|stop| stop.color.is_opaque())),
|
||||||
Graphic::RasterCPU(_) | Graphic::RasterGPU(_) | Graphic::Text(_) => false,
|
Graphic::RasterCPUList(_) | Graphic::RasterGPUList(_) | Graphic::TextList(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_fully_transparent(&self) -> bool {
|
pub fn is_fully_transparent(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => true,
|
Graphic::None => true,
|
||||||
Graphic::Graphic(list) => list.iter_element_values().all(Graphic::is_fully_transparent),
|
Graphic::GraphicList(list) => list.iter_element_values().all(Graphic::is_fully_transparent),
|
||||||
Graphic::Vector(list) => (0..list.len()).all(|i| {
|
Graphic::VectorList(list) => (0..list.len()).all(|i| {
|
||||||
let opacity: f64 = list.attribute_cloned_or(ATTR_OPACITY, i, 1.);
|
let opacity: f64 = list.attribute_cloned_or(ATTR_OPACITY, i, 1.);
|
||||||
if opacity <= f64::EPSILON {
|
if opacity <= f64::EPSILON {
|
||||||
return true;
|
return true;
|
||||||
@@ -528,29 +528,29 @@ impl Graphic {
|
|||||||
|
|
||||||
fills_invisible && strokes_invisible
|
fills_invisible && strokes_invisible
|
||||||
}),
|
}),
|
||||||
Graphic::Color(list) => list.iter_element_values().all(|color| color.a() == 0.),
|
Graphic::ColorList(list) => list.iter_element_values().all(|color| color.a() == 0.),
|
||||||
Graphic::Gradient(list) => list.iter_element_values().all(|stops| stops.iter().all(|stop| stop.color.a() == 0.)),
|
Graphic::GradientList(list) => list.iter_element_values().all(|stops| stops.iter().all(|stop| stop.color.a() == 0.)),
|
||||||
Graphic::RasterCPU(_) | Graphic::RasterGPU(_) | Graphic::Text(_) => false,
|
Graphic::RasterCPUList(_) | Graphic::RasterGPUList(_) | Graphic::TextList(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if this paint opaquely covers the entire fill region.
|
/// True if this paint opaquely covers the entire fill region.
|
||||||
/// Vector, Raster, and a nested Graphic may leave gaps, so they return false.
|
/// Vector, Raster, and a nested Graphic may leave gaps, so they return false.
|
||||||
pub fn covers_opaquely(&self) -> bool {
|
pub fn covers_opaquely(&self) -> bool {
|
||||||
matches!(self, Graphic::Color(_) | Graphic::Gradient(_)) && self.is_opaque()
|
matches!(self, Graphic::ColorList(_) | Graphic::GradientList(_)) && self.is_opaque()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this graphic contains no content.
|
/// Returns true if this graphic contains no content.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => true,
|
Graphic::None => true,
|
||||||
Graphic::Graphic(list) => list.is_empty(),
|
Graphic::GraphicList(list) => list.is_empty(),
|
||||||
Graphic::Vector(list) => list.is_empty(),
|
Graphic::VectorList(list) => list.is_empty(),
|
||||||
Graphic::Color(list) => list.is_empty(),
|
Graphic::ColorList(list) => list.is_empty(),
|
||||||
Graphic::Gradient(list) => list.is_empty(),
|
Graphic::GradientList(list) => list.is_empty(),
|
||||||
Graphic::RasterCPU(list) => list.is_empty(),
|
Graphic::RasterCPUList(list) => list.is_empty(),
|
||||||
Graphic::RasterGPU(list) => list.is_empty(),
|
Graphic::RasterGPUList(list) => list.is_empty(),
|
||||||
Graphic::Text(list) => list.is_empty(),
|
Graphic::TextList(list) => list.is_empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,26 +595,26 @@ impl BoundingBox for Graphic {
|
|||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => RenderBoundingBox::None,
|
Graphic::None => RenderBoundingBox::None,
|
||||||
Graphic::Vector(list) => vector_list_bounding_box(list, transform, include_stroke),
|
Graphic::VectorList(list) => vector_list_bounding_box(list, transform, include_stroke),
|
||||||
Graphic::RasterCPU(list) => list.bounding_box(transform, include_stroke),
|
Graphic::RasterCPUList(list) => list.bounding_box(transform, include_stroke),
|
||||||
Graphic::RasterGPU(list) => list.bounding_box(transform, include_stroke),
|
Graphic::RasterGPUList(list) => list.bounding_box(transform, include_stroke),
|
||||||
Graphic::Graphic(list) => list.bounding_box(transform, include_stroke),
|
Graphic::GraphicList(list) => list.bounding_box(transform, include_stroke),
|
||||||
Graphic::Color(list) => list.bounding_box(transform, include_stroke),
|
Graphic::ColorList(list) => list.bounding_box(transform, include_stroke),
|
||||||
Graphic::Gradient(list) => list.bounding_box(transform, include_stroke),
|
Graphic::GradientList(list) => list.bounding_box(transform, include_stroke),
|
||||||
Graphic::Text(list) => list.bounding_box(transform, include_stroke),
|
Graphic::TextList(list) => list.bounding_box(transform, include_stroke),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thumbnail_bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
fn thumbnail_bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => RenderBoundingBox::None,
|
Graphic::None => RenderBoundingBox::None,
|
||||||
Graphic::Vector(vector) => vector_list_bounding_box(vector, transform, include_stroke),
|
Graphic::VectorList(vector) => vector_list_bounding_box(vector, transform, include_stroke),
|
||||||
Graphic::RasterCPU(raster) => raster.thumbnail_bounding_box(transform, include_stroke),
|
Graphic::RasterCPUList(raster) => raster.thumbnail_bounding_box(transform, include_stroke),
|
||||||
Graphic::RasterGPU(raster) => raster.thumbnail_bounding_box(transform, include_stroke),
|
Graphic::RasterGPUList(raster) => raster.thumbnail_bounding_box(transform, include_stroke),
|
||||||
Graphic::Graphic(graphic) => graphic.thumbnail_bounding_box(transform, include_stroke),
|
Graphic::GraphicList(list) => list.thumbnail_bounding_box(transform, include_stroke),
|
||||||
Graphic::Color(color) => color.thumbnail_bounding_box(transform, include_stroke),
|
Graphic::ColorList(color) => color.thumbnail_bounding_box(transform, include_stroke),
|
||||||
Graphic::Gradient(gradient) => gradient.thumbnail_bounding_box(transform, include_stroke),
|
Graphic::GradientList(gradient) => gradient.thumbnail_bounding_box(transform, include_stroke),
|
||||||
Graphic::Text(list) => list.thumbnail_bounding_box(transform, include_stroke),
|
Graphic::TextList(list) => list.thumbnail_bounding_box(transform, include_stroke),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -623,13 +623,13 @@ impl RenderComplexity for Graphic {
|
|||||||
fn render_complexity(&self) -> usize {
|
fn render_complexity(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::None => 0,
|
Self::None => 0,
|
||||||
Self::Graphic(list) => list.render_complexity(),
|
Self::GraphicList(list) => list.render_complexity(),
|
||||||
Self::Vector(list) => list.render_complexity(),
|
Self::VectorList(list) => list.render_complexity(),
|
||||||
Self::RasterCPU(list) => list.render_complexity(),
|
Self::RasterCPUList(list) => list.render_complexity(),
|
||||||
Self::RasterGPU(list) => list.render_complexity(),
|
Self::RasterGPUList(list) => list.render_complexity(),
|
||||||
Self::Color(list) => list.render_complexity(),
|
Self::ColorList(list) => list.render_complexity(),
|
||||||
Self::Gradient(list) => list.render_complexity(),
|
Self::GradientList(list) => list.render_complexity(),
|
||||||
Self::Text(list) => list.render_complexity(),
|
Self::TextList(list) => list.render_complexity(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -712,7 +712,7 @@ mod tests {
|
|||||||
use core_types::uuid::NodeId;
|
use core_types::uuid::NodeId;
|
||||||
|
|
||||||
fn vector_graphic() -> Graphic {
|
fn vector_graphic() -> Graphic {
|
||||||
Graphic::Vector(List::new_from_element(Vector::default()))
|
Graphic::VectorList(List::new_from_element(Vector::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vector_list_stamped_with_layers(layers: [u64; 2]) -> List<Vector> {
|
fn vector_list_stamped_with_layers(layers: [u64; 2]) -> List<Vector> {
|
||||||
@@ -773,7 +773,7 @@ mod tests {
|
|||||||
let flattened: List<Vector> = graphics.into_flattened_list();
|
let flattened: List<Vector> = graphics.into_flattened_list();
|
||||||
assert_eq!(flattened.attribute_cloned_or_default::<f64>(ATTR_OPACITY, 0), 0.5);
|
assert_eq!(flattened.attribute_cloned_or_default::<f64>(ATTR_OPACITY, 0), 0.5);
|
||||||
|
|
||||||
let mut group = List::new_from_element(Graphic::Graphic(List::new_from_element(vector_graphic())));
|
let mut group = List::new_from_element(Graphic::GraphicList(GraphicList(List::new_from_element(vector_graphic()))));
|
||||||
group.set_attribute(ATTR_OPACITY, 0, 0.5_f64);
|
group.set_attribute(ATTR_OPACITY, 0, 0.5_f64);
|
||||||
let flattened: List<Vector> = group.into_flattened_list();
|
let flattened: List<Vector> = group.into_flattened_list();
|
||||||
assert_eq!(flattened.attribute_cloned_or_default::<f64>(ATTR_OPACITY, 0), 0.5);
|
assert_eq!(flattened.attribute_cloned_or_default::<f64>(ATTR_OPACITY, 0), 0.5);
|
||||||
@@ -784,7 +784,7 @@ mod tests {
|
|||||||
fn flatten_cascades_into_padded_empty_appearance_rows() {
|
fn flatten_cascades_into_padded_empty_appearance_rows() {
|
||||||
use core_types::Color;
|
use core_types::Color;
|
||||||
|
|
||||||
let solid = |color: Color| List::new_from_element(Graphic::Color(List::new_from_element(color)));
|
let solid = |color: Color| List::new_from_element(Graphic::ColorList(List::new_from_element(color)));
|
||||||
|
|
||||||
// Declaring an appearance on row 0 forces the column, padding row 1 with the empty appearance
|
// Declaring an appearance on row 0 forces the column, padding row 1 with the empty appearance
|
||||||
let mut inner = List::new();
|
let mut inner = List::new();
|
||||||
@@ -792,13 +792,13 @@ mod tests {
|
|||||||
inner.push(Item::new_from_element(Vector::default()));
|
inner.push(Item::new_from_element(Vector::default()));
|
||||||
inner.set_attribute(ATTR_APPEARANCE, 0, Appearance::new_single(Coverage::new_fill(), solid(Color::BLACK)));
|
inner.set_attribute(ATTR_APPEARANCE, 0, Appearance::new_single(Coverage::new_fill(), solid(Color::BLACK)));
|
||||||
|
|
||||||
let mut outer = List::new_from_element(Graphic::Vector(inner));
|
let mut outer = List::new_from_element(Graphic::VectorList(inner));
|
||||||
outer.set_attribute(ATTR_APPEARANCE, 0, Appearance::new_single(Coverage::new_fill(), solid(Color::WHITE)));
|
outer.set_attribute(ATTR_APPEARANCE, 0, Appearance::new_single(Coverage::new_fill(), solid(Color::WHITE)));
|
||||||
|
|
||||||
let flattened: List<Vector> = outer.into_flattened_list();
|
let flattened: List<Vector> = outer.into_flattened_list();
|
||||||
let color_of = |index: usize| {
|
let color_of = |index: usize| {
|
||||||
let appearance = flattened.attribute::<Appearance>(ATTR_APPEARANCE, index)?;
|
let appearance = flattened.attribute::<Appearance>(ATTR_APPEARANCE, index)?;
|
||||||
let Some(Graphic::Color(colors)) = appearance.paint_at(0)?.element(0) else { return None };
|
let Some(Graphic::ColorList(colors)) = appearance.paint_at(0)?.element(0) else { return None };
|
||||||
colors.element(0).copied()
|
colors.element(0).copied()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -816,13 +816,13 @@ mod graphic_is_opaque_tests {
|
|||||||
|
|
||||||
fn color_graphic(alpha: f64) -> Graphic {
|
fn color_graphic(alpha: f64) -> Graphic {
|
||||||
let color = Color::from_rgbaf32(1., 0., 0., alpha as f32).unwrap();
|
let color = Color::from_rgbaf32(1., 0., 0., alpha as f32).unwrap();
|
||||||
Graphic::Color(List::new_from_element(color))
|
Graphic::ColorList(List::new_from_element(color))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradient_graphic(gradient: Gradient) -> Graphic {
|
fn gradient_graphic(gradient: Gradient) -> Graphic {
|
||||||
let mut gradient_list = List::new_from_element(gradient);
|
let mut gradient_list = List::new_from_element(gradient);
|
||||||
gradient_list.set_attribute(ATTR_GRADIENT_SPREAD, 0, GradientSpread::Pad);
|
gradient_list.set_attribute(ATTR_GRADIENT_SPREAD, 0, GradientSpread::Pad);
|
||||||
Graphic::Gradient(gradient_list)
|
Graphic::GradientList(gradient_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -839,7 +839,7 @@ mod graphic_is_opaque_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vector_is_not_opaque() {
|
fn vector_is_not_opaque() {
|
||||||
let g = Graphic::Vector(List::default());
|
let g = Graphic::VectorList(List::default());
|
||||||
assert!(!g.is_opaque());
|
assert!(!g.is_opaque());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -242,13 +242,13 @@ impl RenderExt for List<Graphic> {
|
|||||||
let paint_attr = target.paint_attr();
|
let paint_attr = target.paint_attr();
|
||||||
|
|
||||||
match fill_graphic {
|
match fill_graphic {
|
||||||
Some(Graphic::Color(color_list)) => color_list.render(svg_defs, item_transform, element_transform, stroke_transform, bounds, render_params, target),
|
Some(Graphic::ColorList(color_list)) => color_list.render(svg_defs, item_transform, element_transform, stroke_transform, bounds, render_params, target),
|
||||||
Some(Graphic::Gradient(gradient_list)) => {
|
Some(Graphic::GradientList(gradient_list)) => {
|
||||||
let gradient_id = gradient_list.render(svg_defs, item_transform, element_transform, stroke_transform, bounds, render_params, target);
|
let gradient_id = gradient_list.render(svg_defs, item_transform, element_transform, stroke_transform, bounds, render_params, target);
|
||||||
format!(r##" {paint_attr}="url(#{gradient_id})""##)
|
format!(r##" {paint_attr}="url(#{gradient_id})""##)
|
||||||
}
|
}
|
||||||
Some(Graphic::None) => format!(r#" {paint_attr}="none""#),
|
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::VectorList(_)) | Some(Graphic::RasterCPUList(_)) | Some(Graphic::RasterGPUList(_)) | Some(Graphic::GraphicList(_)) | Some(Graphic::TextList(_)) => {
|
||||||
let bounds = if target == PaintTarget::Stroke {
|
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.
|
// To prevent a wraparound artefact occurring when the tile boundary and the stroke region are perfectly aligned, the local coordinate is expanded slightly.
|
||||||
let inverse = |len: f64| if len > 0. { 1. / len } else { 0. };
|
let inverse = |len: f64| if len > 0. { 1. / len } else { 0. };
|
||||||
|
|||||||
@@ -655,26 +655,26 @@ impl Render for Graphic {
|
|||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => (),
|
Graphic::None => (),
|
||||||
Graphic::Graphic(list) => list.render_svg(render, render_params),
|
Graphic::GraphicList(list) => list.render_svg(render, render_params),
|
||||||
Graphic::Vector(list) => list.render_svg(render, render_params),
|
Graphic::VectorList(list) => list.render_svg(render, render_params),
|
||||||
Graphic::RasterCPU(list) => list.render_svg(render, render_params),
|
Graphic::RasterCPUList(list) => list.render_svg(render, render_params),
|
||||||
Graphic::RasterGPU(_) => (),
|
Graphic::RasterGPUList(_) => (),
|
||||||
Graphic::Color(list) => list.render_svg(render, render_params),
|
Graphic::ColorList(list) => list.render_svg(render, render_params),
|
||||||
Graphic::Gradient(list) => list.render_svg(render, render_params),
|
Graphic::GradientList(list) => list.render_svg(render, render_params),
|
||||||
Graphic::Text(list) => list.render_svg(render, render_params),
|
Graphic::TextList(list) => list.render_svg(render, render_params),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => (),
|
Graphic::None => (),
|
||||||
Graphic::Graphic(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::GraphicList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
Graphic::Vector(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::VectorList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
Graphic::RasterCPU(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::RasterCPUList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
Graphic::RasterGPU(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::RasterGPUList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
Graphic::Color(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::ColorList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
Graphic::Gradient(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::GradientList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
Graphic::Text(list) => list.render_to_vello(scene, transform, context, render_params),
|
Graphic::TextList(list) => list.render_to_vello(scene, transform, context, render_params),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,10 +682,10 @@ impl Render for Graphic {
|
|||||||
if let Some(element_id) = element_id {
|
if let Some(element_id) = element_id {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => {}
|
Graphic::None => {}
|
||||||
Graphic::Graphic(_) => {
|
Graphic::GraphicList(_) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
}
|
}
|
||||||
Graphic::Vector(list) => {
|
Graphic::VectorList(list) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
// TODO: Find a way to handle more than the first item
|
// TODO: Find a way to handle more than the first item
|
||||||
if !list.is_empty() {
|
if !list.is_empty() {
|
||||||
@@ -697,7 +697,7 @@ impl Render for Graphic {
|
|||||||
metadata.local_transforms.insert(element_id, transform);
|
metadata.local_transforms.insert(element_id, transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Graphic::RasterCPU(list) => {
|
Graphic::RasterCPUList(list) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
|
|
||||||
// TODO: Find a way to handle more than the first item
|
// TODO: Find a way to handle more than the first item
|
||||||
@@ -705,7 +705,7 @@ impl Render for Graphic {
|
|||||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Graphic::RasterGPU(list) => {
|
Graphic::RasterGPUList(list) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
|
|
||||||
// TODO: Find a way to handle more than the first item
|
// TODO: Find a way to handle more than the first item
|
||||||
@@ -713,7 +713,7 @@ impl Render for Graphic {
|
|||||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Graphic::Color(list) => {
|
Graphic::ColorList(list) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
|
|
||||||
// TODO: Find a way to handle more than the first item
|
// TODO: Find a way to handle more than the first item
|
||||||
@@ -721,7 +721,7 @@ impl Render for Graphic {
|
|||||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Graphic::Gradient(list) => {
|
Graphic::GradientList(list) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
|
|
||||||
// TODO: Find a way to handle more than the first item
|
// TODO: Find a way to handle more than the first item
|
||||||
@@ -729,7 +729,7 @@ impl Render for Graphic {
|
|||||||
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
metadata.local_transforms.insert(element_id, list.attribute_cloned_or_default(ATTR_TRANSFORM, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Graphic::Text(list) => {
|
Graphic::TextList(list) => {
|
||||||
metadata.upstream_footprints.insert(element_id, footprint);
|
metadata.upstream_footprints.insert(element_id, footprint);
|
||||||
|
|
||||||
// TODO: Find a way to handle more than the first item
|
// TODO: Find a way to handle more than the first item
|
||||||
@@ -742,65 +742,65 @@ impl Render for Graphic {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => (),
|
Graphic::None => (),
|
||||||
Graphic::Graphic(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::GraphicList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
Graphic::Vector(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::VectorList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
Graphic::RasterCPU(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::RasterCPUList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
Graphic::RasterGPU(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::RasterGPUList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
Graphic::Color(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::ColorList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
Graphic::Gradient(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::GradientList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
Graphic::Text(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
Graphic::TextList(list) => list.collect_metadata(metadata, footprint, element_id, inherited_appearance),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>, inherited_appearance: Option<&Appearance>) {
|
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>, inherited_appearance: Option<&Appearance>) {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => (),
|
Graphic::None => (),
|
||||||
Graphic::Graphic(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::GraphicList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
Graphic::Vector(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::VectorList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
Graphic::RasterCPU(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::RasterCPUList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
Graphic::RasterGPU(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::RasterGPUList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
Graphic::Color(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::ColorList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
Graphic::Gradient(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::GradientList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
Graphic::Text(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
Graphic::TextList(list) => list.add_upstream_click_targets(click_targets, inherited_appearance),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_upstream_outline_targets(&self, outlines: &mut Vec<ClickTarget>, inherited_appearance: Option<&Appearance>) {
|
fn add_upstream_outline_targets(&self, outlines: &mut Vec<ClickTarget>, inherited_appearance: Option<&Appearance>) {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => (),
|
Graphic::None => (),
|
||||||
Graphic::Graphic(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::GraphicList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
Graphic::Vector(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::VectorList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
Graphic::RasterCPU(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::RasterCPUList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
Graphic::RasterGPU(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::RasterGPUList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
Graphic::Color(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::ColorList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
Graphic::Gradient(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::GradientList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
Graphic::Text(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
Graphic::TextList(list) => list.add_upstream_outline_targets(outlines, inherited_appearance),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_artboard(&self) -> bool {
|
fn contains_artboard(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => false,
|
Graphic::None => false,
|
||||||
Graphic::Graphic(list) => list.contains_artboard(),
|
Graphic::GraphicList(list) => list.contains_artboard(),
|
||||||
Graphic::Vector(list) => list.contains_artboard(),
|
Graphic::VectorList(list) => list.contains_artboard(),
|
||||||
Graphic::RasterCPU(list) => list.contains_artboard(),
|
Graphic::RasterCPUList(list) => list.contains_artboard(),
|
||||||
Graphic::RasterGPU(list) => list.contains_artboard(),
|
Graphic::RasterGPUList(list) => list.contains_artboard(),
|
||||||
Graphic::Color(list) => list.contains_artboard(),
|
Graphic::ColorList(list) => list.contains_artboard(),
|
||||||
Graphic::Gradient(list) => list.contains_artboard(),
|
Graphic::GradientList(list) => list.contains_artboard(),
|
||||||
Graphic::Text(list) => list.contains_artboard(),
|
Graphic::TextList(list) => list.contains_artboard(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_ids_from_hash(&mut self, reference: Option<NodeId>) {
|
fn new_ids_from_hash(&mut self, reference: Option<NodeId>) {
|
||||||
match self {
|
match self {
|
||||||
Graphic::None => (),
|
Graphic::None => (),
|
||||||
Graphic::Graphic(list) => list.new_ids_from_hash(reference),
|
Graphic::GraphicList(list) => list.new_ids_from_hash(reference),
|
||||||
Graphic::Vector(list) => list.new_ids_from_hash(reference),
|
Graphic::VectorList(list) => list.new_ids_from_hash(reference),
|
||||||
Graphic::RasterCPU(_) => (),
|
Graphic::RasterCPUList(_) => (),
|
||||||
Graphic::RasterGPU(_) => (),
|
Graphic::RasterGPUList(_) => (),
|
||||||
Graphic::Color(_) => (),
|
Graphic::ColorList(_) => (),
|
||||||
Graphic::Gradient(_) => (),
|
Graphic::GradientList(_) => (),
|
||||||
Graphic::Text(_) => (),
|
Graphic::TextList(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1279,7 +1279,7 @@ fn render_vector_item_svg(list: &List<Vector>, index: usize, vector: &Vector, re
|
|||||||
// The mask must draw at full alpha so the SVG `<mask>`/`<clipPath>` fully zeroes the path interior.
|
// The mask must draw at full alpha so the SVG `<mask>`/`<clipPath>` fully zeroes the path interior.
|
||||||
// The wrapping SVG group (above) handles the user-set opacity.
|
// The wrapping SVG group (above) handles the user-set opacity.
|
||||||
let mut mask_item = Item::new_from_element(cloned_vector).with_attribute(ATTR_TRANSFORM, item_transform);
|
let mut mask_item = Item::new_from_element(cloned_vector).with_attribute(ATTR_TRANSFORM, item_transform);
|
||||||
let black_fill = List::new_from_element(Graphic::Color(List::new_from_element(Color::BLACK)));
|
let black_fill = List::new_from_element(Graphic::ColorList(List::new_from_element(Color::BLACK)));
|
||||||
mask_item.set_attribute(ATTR_APPEARANCE, Appearance::new_single(Coverage::new_fill(), black_fill));
|
mask_item.set_attribute(ATTR_APPEARANCE, Appearance::new_single(Coverage::new_fill(), black_fill));
|
||||||
let vector_item = List::new_from_item(mask_item);
|
let vector_item = List::new_from_item(mask_item);
|
||||||
|
|
||||||
@@ -1361,7 +1361,7 @@ fn render_vector_item_svg(list: &List<Vector>, index: usize, vector: &Vector, re
|
|||||||
// Gradient should align with the fill path bbox so that a shared gradient lines up across fill and stroke.
|
// Gradient should align with the fill path bbox so that a shared gradient lines up across fill and stroke.
|
||||||
// Only clipping-based paints need the stroke-inclusive bbox.
|
// Only clipping-based paints need the stroke-inclusive bbox.
|
||||||
let paint_bounds = match list.element(0) {
|
let paint_bounds = match list.element(0) {
|
||||||
Some(Graphic::Color(_)) | Some(Graphic::Gradient(_)) => bounds_matrix,
|
Some(Graphic::ColorList(_)) | Some(Graphic::GradientList(_)) => bounds_matrix,
|
||||||
_ => stroke_bounds_matrix,
|
_ => stroke_bounds_matrix,
|
||||||
};
|
};
|
||||||
list.render(defs, item_transform, element_transform, applied_stroke_transform, paint_bounds, &render_params, PaintTarget::Stroke)
|
list.render(defs, item_transform, element_transform, applied_stroke_transform, paint_bounds, &render_params, PaintTarget::Stroke)
|
||||||
@@ -1429,7 +1429,7 @@ impl Render for List<Vector> {
|
|||||||
let mut masked_by = None;
|
let mut masked_by = None;
|
||||||
|
|
||||||
if next_clips && clip_mask_state.is_none() {
|
if next_clips && clip_mask_state.is_none() {
|
||||||
let masker = Graphic::Vector(List::new_from_item(Item::from_parts(vector.clone(), self.clone_item_attributes(index))));
|
let masker = Graphic::VectorList(List::new_from_item(Item::from_parts(vector.clone(), self.clone_item_attributes(index))));
|
||||||
let mask_type = if masker.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask };
|
let mask_type = if masker.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask };
|
||||||
let uuid = generate_uuid();
|
let uuid = generate_uuid();
|
||||||
|
|
||||||
@@ -1586,13 +1586,13 @@ impl Render for List<Vector> {
|
|||||||
let Some(paint) = fill_graphic.element(paint_index) else { continue };
|
let Some(paint) = fill_graphic.element(paint_index) else { continue };
|
||||||
match paint {
|
match paint {
|
||||||
Graphic::None => continue,
|
Graphic::None => continue,
|
||||||
Graphic::Color(list) => {
|
Graphic::ColorList(list) => {
|
||||||
let Some(color) = list.element(0) else { continue };
|
let Some(color) = list.element(0) else { continue };
|
||||||
|
|
||||||
let fill = peniko::Brush::Solid(SRGBA8::from(*color).to_peniko_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);
|
scene.fill(fill_rule, kurbo::Affine::new(element_transform.to_cols_array()), &fill, None, path);
|
||||||
}
|
}
|
||||||
Graphic::Gradient(list) => {
|
Graphic::GradientList(list) => {
|
||||||
let Some((brush, gradient_to_device)) = create_peniko_gradient_brush(list, &multiplied_transform) else {
|
let Some((brush, gradient_to_device)) = create_peniko_gradient_brush(list, &multiplied_transform) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -1605,7 +1605,7 @@ impl Render for List<Vector> {
|
|||||||
let brush_transform = kurbo::Affine::new((inverse_element_transform * gradient_to_device).to_cols_array());
|
let brush_transform = kurbo::Affine::new((inverse_element_transform * gradient_to_device).to_cols_array());
|
||||||
scene.fill(fill_rule, kurbo::Affine::new(element_transform.to_cols_array()), &brush, Some(brush_transform), path);
|
scene.fill(fill_rule, kurbo::Affine::new(element_transform.to_cols_array()), &brush, Some(brush_transform), path);
|
||||||
}
|
}
|
||||||
Graphic::Vector(_) | Graphic::RasterCPU(_) | Graphic::RasterGPU(_) | Graphic::Graphic(_) | Graphic::Text(_) => {
|
Graphic::VectorList(_) | Graphic::RasterCPUList(_) | Graphic::RasterGPUList(_) | Graphic::GraphicList(_) | Graphic::TextList(_) => {
|
||||||
scene.push_clip_layer(fill_rule, kurbo::Affine::new(element_transform.to_cols_array()), path);
|
scene.push_clip_layer(fill_rule, kurbo::Affine::new(element_transform.to_cols_array()), path);
|
||||||
paint.render_to_vello(scene, multiplied_transform, context, &paint_render_params);
|
paint.render_to_vello(scene, multiplied_transform, context, &paint_render_params);
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
@@ -1669,13 +1669,13 @@ impl Render for List<Vector> {
|
|||||||
|
|
||||||
match stroke_graphic {
|
match stroke_graphic {
|
||||||
Graphic::None => continue,
|
Graphic::None => continue,
|
||||||
Graphic::Color(list) => {
|
Graphic::ColorList(list) => {
|
||||||
let Some(color) = list.element(0) else { continue };
|
let Some(color) = list.element(0) else { continue };
|
||||||
let brush = peniko::Brush::Solid(SRGBA8::from(*color).to_peniko_color());
|
let brush = peniko::Brush::Solid(SRGBA8::from(*color).to_peniko_color());
|
||||||
|
|
||||||
scene.stroke(&stroke, kurbo::Affine::new(element_transform.to_cols_array()), &brush, None, &path);
|
scene.stroke(&stroke, kurbo::Affine::new(element_transform.to_cols_array()), &brush, None, &path);
|
||||||
}
|
}
|
||||||
Graphic::Gradient(list) => {
|
Graphic::GradientList(list) => {
|
||||||
let Some((brush, gradient_to_device)) = create_peniko_gradient_brush(list, &multiplied_transform) else {
|
let Some((brush, gradient_to_device)) = create_peniko_gradient_brush(list, &multiplied_transform) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -1688,7 +1688,7 @@ impl Render for List<Vector> {
|
|||||||
|
|
||||||
scene.stroke(&stroke, kurbo::Affine::new(element_transform.to_cols_array()), &brush, Some(brush_transform), &path);
|
scene.stroke(&stroke, kurbo::Affine::new(element_transform.to_cols_array()), &brush, Some(brush_transform), &path);
|
||||||
}
|
}
|
||||||
Graphic::Vector(_) | Graphic::RasterCPU(_) | Graphic::RasterGPU(_) | Graphic::Graphic(_) | Graphic::Text(_) => {
|
Graphic::VectorList(_) | Graphic::RasterCPUList(_) | Graphic::RasterGPUList(_) | Graphic::GraphicList(_) | Graphic::TextList(_) => {
|
||||||
let stroked = peniko::kurbo::stroke(path.iter(), &stroke, &StrokeOpts::default(), 0.01);
|
let stroked = peniko::kurbo::stroke(path.iter(), &stroke, &StrokeOpts::default(), 0.01);
|
||||||
|
|
||||||
scene.push_clip_layer(peniko::Fill::NonZero, kurbo::Affine::new(element_transform.to_cols_array()), &stroked);
|
scene.push_clip_layer(peniko::Fill::NonZero, kurbo::Affine::new(element_transform.to_cols_array()), &stroked);
|
||||||
@@ -1713,7 +1713,7 @@ impl Render for List<Vector> {
|
|||||||
// The mask must draw at full alpha so `SrcOut` fully zeroes the path interior.
|
// The mask must draw at full alpha so `SrcOut` fully zeroes the path interior.
|
||||||
// The outer opacity/blend layer (above) handles the user-set opacity.
|
// The outer opacity/blend layer (above) handles the user-set opacity.
|
||||||
let mut mask_item = Item::new_from_element(cloned_element).with_attribute(ATTR_TRANSFORM, item_transform);
|
let mut mask_item = Item::new_from_element(cloned_element).with_attribute(ATTR_TRANSFORM, item_transform);
|
||||||
let black_fill = List::new_from_element(Graphic::Color(List::new_from_element(Color::BLACK)));
|
let black_fill = List::new_from_element(Graphic::ColorList(List::new_from_element(Color::BLACK)));
|
||||||
mask_item.set_attribute(ATTR_APPEARANCE, Appearance::new_single(Coverage::new_fill(), black_fill));
|
mask_item.set_attribute(ATTR_APPEARANCE, Appearance::new_single(Coverage::new_fill(), black_fill));
|
||||||
let vector_list = List::new_from_item(mask_item);
|
let vector_list = List::new_from_item(mask_item);
|
||||||
|
|
||||||
@@ -2680,7 +2680,7 @@ pub fn text_list_bounding_box(list: &List<String>, outer_transform: DAffine2) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `List<Graphic>::thumbnail_bounding_box`, but lays out `Graphic::Text` items, which the `BoundingBox` trait reports as `None`.
|
/// Like `List<Graphic>::thumbnail_bounding_box`, but lays out `Graphic::TextList` items, which the `BoundingBox` trait reports as `None`.
|
||||||
/// Used for layer thumbnails so text layers (whose content is a `List<Graphic>` wrapping the text) frame their content.
|
/// Used for layer thumbnails so text layers (whose content is a `List<Graphic>` wrapping the text) frame their content.
|
||||||
pub fn graphic_list_bounding_box(list: &List<Graphic>, transform: DAffine2) -> RenderBoundingBox {
|
pub fn graphic_list_bounding_box(list: &List<Graphic>, transform: DAffine2) -> RenderBoundingBox {
|
||||||
let mut combined: Option<[DVec2; 2]> = None;
|
let mut combined: Option<[DVec2; 2]> = None;
|
||||||
@@ -2690,8 +2690,8 @@ pub fn graphic_list_bounding_box(list: &List<Graphic>, transform: DAffine2) -> R
|
|||||||
let item_transform = transform * list.attribute_cloned_or_default::<DAffine2>(ATTR_TRANSFORM, index);
|
let item_transform = transform * list.attribute_cloned_or_default::<DAffine2>(ATTR_TRANSFORM, index);
|
||||||
let Some(graphic) = list.element(index) else { continue };
|
let Some(graphic) = list.element(index) else { continue };
|
||||||
let bounds = match graphic {
|
let bounds = match graphic {
|
||||||
Graphic::Text(text_list) => text_list_bounding_box(text_list, item_transform),
|
Graphic::TextList(text_list) => text_list_bounding_box(text_list, item_transform),
|
||||||
Graphic::Graphic(sub_list) => graphic_list_bounding_box(sub_list, item_transform),
|
Graphic::GraphicList(sub_list) => graphic_list_bounding_box(sub_list, item_transform),
|
||||||
other => other.thumbnail_bounding_box(item_transform, true),
|
other => other.thumbnail_bounding_box(item_transform, true),
|
||||||
};
|
};
|
||||||
match bounds {
|
match bounds {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub enum GradientForm {
|
|||||||
/// attributes place each stop along the 0 to 1 range. Stops lacking the `position` attribute distribute evenly,
|
/// attributes place each stop along the 0 to 1 range. Stops lacking the `position` attribute distribute evenly,
|
||||||
/// and stops lacking the `midpoint` attribute interpolate linearly (`0.5`).
|
/// and stops lacking the `midpoint` attribute interpolate linearly (`0.5`).
|
||||||
#[derive(Default, Debug, Clone, PartialEq, graphene_hash::CacheHash, DynAny)]
|
#[derive(Default, Debug, Clone, PartialEq, graphene_hash::CacheHash, DynAny)]
|
||||||
pub struct Gradient(List<Color>);
|
pub struct Gradient(pub List<Color>);
|
||||||
|
|
||||||
/// A gradient's per-stop parallel arrays, generic over color format: `GradientStops<Color>` nests inside the
|
/// A gradient's per-stop parallel arrays, generic over color format: `GradientStops<Color>` nests inside the
|
||||||
/// [`GradientRamp`] exchange struct, while `GradientStops<SRGBA8>` is the JS-boundary shape used by the color picker UI.
|
/// [`GradientRamp`] exchange struct, while `GradientStops<SRGBA8>` is the JS-boundary shape used by the color picker UI.
|
||||||
|
|||||||
@@ -983,7 +983,7 @@ pub async fn flatten_graphic(_: impl Ctx, content: List<Graphic>, fully_flatten:
|
|||||||
|
|
||||||
match current_element {
|
match current_element {
|
||||||
// If we're allowed to recurse, flatten any graphics we encounter
|
// If we're allowed to recurse, flatten any graphics we encounter
|
||||||
Graphic::Graphic(mut current_element) if recurse => {
|
Graphic::GraphicList(mut current_element) if recurse => {
|
||||||
// Apply the parent graphic's transform to all child elements
|
// Apply the parent graphic's transform to all child elements
|
||||||
for graphic_transform in current_element.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
for graphic_transform in current_element.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
||||||
*graphic_transform = current_transform * *graphic_transform;
|
*graphic_transform = current_transform * *graphic_transform;
|
||||||
@@ -991,7 +991,7 @@ pub async fn flatten_graphic(_: impl Ctx, content: List<Graphic>, fully_flatten:
|
|||||||
|
|
||||||
flatten_list(output_graphic_list, current_element, fully_flatten, recursion_depth + 1);
|
flatten_list(output_graphic_list, current_element, fully_flatten, recursion_depth + 1);
|
||||||
}
|
}
|
||||||
// Push any leaf elements we encounter: either `Graphic::Graphic(...)` values beyond the recursion depth, or non-`Graphic::Graphic` variants (e.g. `Graphic::Vector`, `Graphic::Raster*`, `Graphic::Color`, `Graphic::Gradient`, `Graphic::Text`)
|
// Push any leaf element: a group beyond the recursion depth, or any non-group variant
|
||||||
_ => {
|
_ => {
|
||||||
let attributes = current_graphic_list.clone_item_attributes(index);
|
let attributes = current_graphic_list.clone_item_attributes(index);
|
||||||
output_graphic_list.push(Item::from_parts(current_element, attributes));
|
output_graphic_list.push(Item::from_parts(current_element, attributes));
|
||||||
|
|||||||
@@ -224,9 +224,9 @@ fn flatten_vector(graphic_list: &List<Graphic>) -> List<Vector> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match graphic.clone() {
|
match graphic.clone() {
|
||||||
Graphic::Vector(vector) => vector.into_iter().map(compose_parent).collect::<Vec<_>>(),
|
Graphic::VectorList(vector) => vector.into_iter().map(compose_parent).collect::<Vec<_>>(),
|
||||||
Graphic::Text(text) => text_nodes::shape_text_list(&text, false).into_iter().map(compose_parent).collect::<Vec<_>>(),
|
Graphic::TextList(text) => text_nodes::shape_text_list(&text, false).into_iter().map(compose_parent).collect::<Vec<_>>(),
|
||||||
Graphic::Graphic(mut graphic) => {
|
Graphic::GraphicList(mut graphic) => {
|
||||||
if parent_has_transform {
|
if parent_has_transform {
|
||||||
for transform in graphic.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
for transform in graphic.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM) {
|
||||||
*transform = parent_transform * *transform;
|
*transform = parent_transform * *transform;
|
||||||
@@ -261,7 +261,7 @@ fn flatten_vector(graphic_list: &List<Graphic>) -> List<Vector> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Rasters, colors, and gradients bound no region, so they contribute no operand
|
// Rasters, colors, and gradients bound no region, so they contribute no operand
|
||||||
Graphic::None | Graphic::RasterCPU(_) | Graphic::RasterGPU(_) | Graphic::Color(_) | Graphic::Gradient(_) => Vec::new(),
|
Graphic::None | Graphic::RasterCPUList(_) | Graphic::RasterGPUList(_) | Graphic::ColorList(_) | Graphic::GradientList(_) => Vec::new(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ mod test {
|
|||||||
Item::new_from_element(count),
|
Item::new_from_element(count),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
|
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::VectorList(repeated))).await);
|
||||||
let vector = vector_list.element(0).unwrap();
|
let vector = vector_list.element(0).unwrap();
|
||||||
assert_eq!(vector.region_manipulator_groups().count(), 3);
|
assert_eq!(vector.region_manipulator_groups().count(), 3);
|
||||||
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
||||||
@@ -340,7 +340,7 @@ mod test {
|
|||||||
Item::new_from_element(1),
|
Item::new_from_element(1),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
|
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::VectorList(repeated))).await);
|
||||||
let vector = vector_list.element(0).unwrap();
|
let vector = vector_list.element(0).unwrap();
|
||||||
assert_eq!(vector.region_manipulator_groups().count(), 1);
|
assert_eq!(vector.region_manipulator_groups().count(), 1);
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ mod test {
|
|||||||
Item::new_from_element(count),
|
Item::new_from_element(count),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
|
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::VectorList(repeated))).await);
|
||||||
let vector = vector_list.element(0).unwrap();
|
let vector = vector_list.element(0).unwrap();
|
||||||
assert_eq!(vector.region_manipulator_groups().count(), 8);
|
assert_eq!(vector.region_manipulator_groups().count(), 8);
|
||||||
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
||||||
@@ -381,7 +381,7 @@ mod test {
|
|||||||
Item::new_from_element(8),
|
Item::new_from_element(8),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
|
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::VectorList(repeated))).await);
|
||||||
let vector = vector_list.element(0).unwrap();
|
let vector = vector_list.element(0).unwrap();
|
||||||
assert_eq!(vector.region_manipulator_groups().count(), 8);
|
assert_eq!(vector.region_manipulator_groups().count(), 8);
|
||||||
|
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ trait VectorListIterMut {
|
|||||||
impl VectorListIterMut for List<Graphic> {
|
impl VectorListIterMut for List<Graphic> {
|
||||||
fn for_each_vector_list_mut(&mut self, mut f: impl FnMut(&mut List<Vector>)) {
|
fn for_each_vector_list_mut(&mut self, mut f: impl FnMut(&mut List<Vector>)) {
|
||||||
for graphic in self.iter_element_values_mut() {
|
for graphic in self.iter_element_values_mut() {
|
||||||
if let Some(vector_list) = graphic.as_vector_mut() {
|
if let Some(vector_list) = graphic.as_vector_list_mut() {
|
||||||
f(vector_list);
|
f(vector_list);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vector_count(&self) -> usize {
|
fn vector_count(&self) -> usize {
|
||||||
self.iter_element_values().filter_map(|element| element.as_vector()).map(|list| list.len()).sum()
|
self.iter_element_values().filter_map(|element| element.as_vector_list()).map(|list| list.len()).sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ impl VectorItemMut for Item<Vector> {
|
|||||||
|
|
||||||
impl VectorItemMut for Item<Graphic> {
|
impl VectorItemMut for Item<Graphic> {
|
||||||
fn for_each_vector_mut(&mut self, mut f: impl FnMut(&mut Vector, DAffine2)) {
|
fn for_each_vector_mut(&mut self, mut f: impl FnMut(&mut Vector, DAffine2)) {
|
||||||
let Some(vector_list) = self.element_mut().as_vector_mut() else { return };
|
let Some(vector_list) = self.element_mut().as_vector_list_mut() else { return };
|
||||||
let (elements, transforms) = vector_list.element_and_attribute_slices_mut::<DAffine2>(ATTR_TRANSFORM);
|
let (elements, transforms) = vector_list.element_and_attribute_slices_mut::<DAffine2>(ATTR_TRANSFORM);
|
||||||
for (vector, transform) in elements.iter_mut().zip(transforms.iter()) {
|
for (vector, transform) in elements.iter_mut().zip(transforms.iter()) {
|
||||||
f(vector, *transform);
|
f(vector, *transform);
|
||||||
@@ -115,8 +115,8 @@ impl MapVectorItems for Graphic {
|
|||||||
fn map_nested(graphic: &mut Graphic, f: &mut impl FnMut(Item<Vector>) -> Item<Vector>) {
|
fn map_nested(graphic: &mut Graphic, f: &mut impl FnMut(Item<Vector>) -> Item<Vector>) {
|
||||||
match graphic {
|
match graphic {
|
||||||
// Collecting from zero items would drop the attribute columns, so an empty list is left alone
|
// Collecting from zero items would drop the attribute columns, so an empty list is left alone
|
||||||
Graphic::Vector(list) if !list.is_empty() => *list = std::mem::take(list).into_iter().map(&mut *f).collect(),
|
Graphic::VectorList(list) if !list.is_empty() => *list = std::mem::take(list).into_iter().map(&mut *f).collect(),
|
||||||
Graphic::Graphic(list) => list.iter_element_values_mut().for_each(|nested| map_nested(nested, f)),
|
Graphic::GraphicList(list) => list.iter_element_values_mut().for_each(|nested| map_nested(nested, f)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,8 +130,8 @@ impl MapVectorItems for Graphic {
|
|||||||
fn vector_elements_mut(content: &mut Item<Graphic>) -> Vec<&mut Vector> {
|
fn vector_elements_mut(content: &mut Item<Graphic>) -> Vec<&mut Vector> {
|
||||||
fn collect<'a>(graphic: &'a mut Graphic, elements: &mut Vec<&'a mut Vector>) {
|
fn collect<'a>(graphic: &'a mut Graphic, elements: &mut Vec<&'a mut Vector>) {
|
||||||
match graphic {
|
match graphic {
|
||||||
Graphic::Vector(list) => elements.extend(list.iter_element_values_mut()),
|
Graphic::VectorList(list) => elements.extend(list.iter_element_values_mut()),
|
||||||
Graphic::Graphic(list) => list.iter_element_values_mut().for_each(|nested| collect(nested, elements)),
|
Graphic::GraphicList(list) => list.iter_element_values_mut().for_each(|nested| collect(nested, elements)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,14 +159,14 @@ impl ExpandVectorItems for Graphic {
|
|||||||
fn expand_nested(graphic: &mut Graphic, f: &mut impl FnMut(Item<Vector>) -> List<Vector>) {
|
fn expand_nested(graphic: &mut Graphic, f: &mut impl FnMut(Item<Vector>) -> List<Vector>) {
|
||||||
match graphic {
|
match graphic {
|
||||||
// Collecting from zero items would drop the attribute columns, so an empty list is left alone
|
// Collecting from zero items would drop the attribute columns, so an empty list is left alone
|
||||||
Graphic::Vector(list) if !list.is_empty() => {
|
Graphic::VectorList(list) if !list.is_empty() => {
|
||||||
let mut expanded = List::with_capacity(list.len());
|
let mut expanded = List::with_capacity(list.len());
|
||||||
for item in std::mem::take(list) {
|
for item in std::mem::take(list) {
|
||||||
expanded.extend(f(item));
|
expanded.extend(f(item));
|
||||||
}
|
}
|
||||||
*list = expanded;
|
*list = expanded;
|
||||||
}
|
}
|
||||||
Graphic::Graphic(list) => list.iter_element_values_mut().for_each(|nested| expand_nested(nested, f)),
|
Graphic::GraphicList(list) => list.iter_element_values_mut().for_each(|nested| expand_nested(nested, f)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ where
|
|||||||
|
|
||||||
// Stamp the gradient styling inputs onto any gradient paint missing them, whether the paint arrived as a picker value or a wire
|
// Stamp the gradient styling inputs onto any gradient paint missing them, whether the paint arrived as a picker value or a wire
|
||||||
for graphic in fill.iter_element_values_mut() {
|
for graphic in fill.iter_element_values_mut() {
|
||||||
let Graphic::Gradient(gradient) = graphic else { continue };
|
let Graphic::GradientList(gradient) = graphic else { continue };
|
||||||
|
|
||||||
if gradient.iter_attribute_values::<GradientForm>(ATTR_GRADIENT_FORM).is_none() {
|
if gradient.iter_attribute_values::<GradientForm>(ATTR_GRADIENT_FORM).is_none() {
|
||||||
for value in gradient.iter_attribute_values_mut_or_default::<GradientForm>(ATTR_GRADIENT_FORM) {
|
for value in gradient.iter_attribute_values_mut_or_default::<GradientForm>(ATTR_GRADIENT_FORM) {
|
||||||
@@ -1510,8 +1510,8 @@ impl SolidifyStroke for Graphic {
|
|||||||
fn solidify_strokes(content: Item<Graphic>) -> List<Graphic> {
|
fn solidify_strokes(content: Item<Graphic>) -> List<Graphic> {
|
||||||
fn solidify_nested(graphic: &mut Graphic) {
|
fn solidify_nested(graphic: &mut Graphic) {
|
||||||
match graphic {
|
match graphic {
|
||||||
Graphic::Vector(list) if !list.is_empty() => *list = solidify_stroke_list_with_snapshot(std::mem::take(list)),
|
Graphic::VectorList(list) if !list.is_empty() => *list = solidify_stroke_list_with_snapshot(std::mem::take(list)),
|
||||||
Graphic::Graphic(list) => list.iter_element_values_mut().for_each(solidify_nested),
|
Graphic::GraphicList(list) => list.iter_element_values_mut().for_each(solidify_nested),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2594,25 +2594,25 @@ async fn morph<I: IntoGraphicList>(
|
|||||||
} else {
|
} else {
|
||||||
gradient_list.push(Item::new_from_element(stops));
|
gradient_list.push(Item::new_from_element(stops));
|
||||||
}
|
}
|
||||||
Graphic::Gradient(gradient_list)
|
Graphic::GradientList(gradient_list)
|
||||||
};
|
};
|
||||||
|
|
||||||
let graphic = match (a.element(0), b.element(0)) {
|
let graphic = match (a.element(0), b.element(0)) {
|
||||||
(Some(Graphic::Color(color_list_a)), Some(Graphic::Color(color_list_b))) => color_list_a
|
(Some(Graphic::ColorList(color_list_a)), Some(Graphic::ColorList(color_list_b))) => color_list_a
|
||||||
.element(0)
|
.element(0)
|
||||||
.zip(color_list_b.element(0))
|
.zip(color_list_b.element(0))
|
||||||
.map(|(color_a, color_b)| Graphic::from(color_a.lerp(color_b, time as f32))),
|
.map(|(color_a, color_b)| Graphic::from(color_a.lerp(color_b, time as f32))),
|
||||||
(Some(Graphic::Color(color_list_a)), Some(Graphic::Gradient(gradient_list_b))) => color_list_a.element(0).zip(gradient_list_b.element(0)).map(|(color_a, stops_b)| {
|
(Some(Graphic::ColorList(color_list_a)), Some(Graphic::GradientList(gradient_list_b))) => color_list_a.element(0).zip(gradient_list_b.element(0)).map(|(color_a, stops_b)| {
|
||||||
let solid_to_gradient = stops_b.map_colors(|_| *color_a);
|
let solid_to_gradient = stops_b.map_colors(|_| *color_a);
|
||||||
let stops = solid_to_gradient.lerp(stops_b, time);
|
let stops = solid_to_gradient.lerp(stops_b, time);
|
||||||
gradient_with_stops(gradient_list_b.clone(), stops)
|
gradient_with_stops(gradient_list_b.clone(), stops)
|
||||||
}),
|
}),
|
||||||
(Some(Graphic::Gradient(gradient_list_a)), Some(Graphic::Color(color_list_b))) => gradient_list_a.element(0).zip(color_list_b.element(0)).map(|(stops_a, color_b)| {
|
(Some(Graphic::GradientList(gradient_list_a)), Some(Graphic::ColorList(color_list_b))) => gradient_list_a.element(0).zip(color_list_b.element(0)).map(|(stops_a, color_b)| {
|
||||||
let gradient_to_solid = stops_a.map_colors(|_| *color_b);
|
let gradient_to_solid = stops_a.map_colors(|_| *color_b);
|
||||||
let stops = stops_a.lerp(&gradient_to_solid, time);
|
let stops = stops_a.lerp(&gradient_to_solid, time);
|
||||||
gradient_with_stops(gradient_list_a.clone(), stops)
|
gradient_with_stops(gradient_list_a.clone(), stops)
|
||||||
}),
|
}),
|
||||||
(Some(Graphic::Gradient(gradient_list_a)), Some(Graphic::Gradient(gradient_list_b))) => gradient_list_a.element(0).zip(gradient_list_b.element(0)).map(|(stops_a, stops_b)| {
|
(Some(Graphic::GradientList(gradient_list_a)), Some(Graphic::GradientList(gradient_list_b))) => gradient_list_a.element(0).zip(gradient_list_b.element(0)).map(|(stops_a, stops_b)| {
|
||||||
let stops = stops_a.lerp(stops_b, time);
|
let stops = stops_a.lerp(stops_b, time);
|
||||||
let metadata_source = if time < 0.5 { gradient_list_a } else { gradient_list_b };
|
let metadata_source = if time < 0.5 { gradient_list_a } else { gradient_list_b };
|
||||||
|
|
||||||
@@ -3759,7 +3759,7 @@ mod test {
|
|||||||
Item::new_from_element(0),
|
Item::new_from_element(0),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let combined = List::new_from_item(super::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(copy_to_points))).await);
|
let combined = List::new_from_item(super::combine_paths(Footprint::default(), List::new_from_element(Graphic::VectorList(copy_to_points))).await);
|
||||||
let combined_copy_to_points = combined.element(0).unwrap();
|
let combined_copy_to_points = combined.element(0).unwrap();
|
||||||
|
|
||||||
assert_eq!(combined_copy_to_points.region_manipulator_groups().count(), expected_points.len());
|
assert_eq!(combined_copy_to_points.region_manipulator_groups().count(), expected_points.len());
|
||||||
@@ -3912,7 +3912,7 @@ mod test {
|
|||||||
let fill = appearance.first_paint_of(Cover::Fill).expect("Morph should keep the fill paint at the midpoint");
|
let fill = appearance.first_paint_of(Cover::Fill).expect("Morph should keep the fill paint at the midpoint");
|
||||||
|
|
||||||
// Interpolated color between red and blue should have >0 value on both R and B
|
// Interpolated color between red and blue should have >0 value on both R and B
|
||||||
let Some(Graphic::Color(colors)) = fill.element(0) else {
|
let Some(Graphic::ColorList(colors)) = fill.element(0) else {
|
||||||
panic!("Expected a solid color fill, got {:?}", fill.element(0));
|
panic!("Expected a solid color fill, got {:?}", fill.element(0));
|
||||||
};
|
};
|
||||||
let color = *colors.element(0).expect("Color present");
|
let color = *colors.element(0).expect("Color present");
|
||||||
@@ -3929,7 +3929,7 @@ mod test {
|
|||||||
|
|
||||||
let paint_color = |appearance: &Appearance, cover| {
|
let paint_color = |appearance: &Appearance, cover| {
|
||||||
let paint = appearance.first_paint_of(cover).expect("Morph should keep both paints at the midpoint");
|
let paint = appearance.first_paint_of(cover).expect("Morph should keep both paints at the midpoint");
|
||||||
let Some(Graphic::Color(colors)) = paint.element(0) else {
|
let Some(Graphic::ColorList(colors)) = paint.element(0) else {
|
||||||
panic!("Expected a solid color paint, got {:?}", paint.element(0));
|
panic!("Expected a solid color paint, got {:?}", paint.element(0));
|
||||||
};
|
};
|
||||||
*colors.element(0).expect("Color present")
|
*colors.element(0).expect("Color present")
|
||||||
|
|||||||
Reference in New Issue
Block a user