mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Distinguish an absent column from a defaulted one on the lane source
This commit is contained in:
@@ -6,9 +6,13 @@ use crate::attribute::Attribute;
|
||||
/// One marker's column on a source, resolved once so lane reads skip the key
|
||||
/// lookup.
|
||||
pub trait LaneColumn<'a, A: Attribute> {
|
||||
/// The lane's value, or the marker's census default where the column is
|
||||
/// absent.
|
||||
fn get(&self, lane: usize) -> A::Value<'a>;
|
||||
/// The lane's value, `None` where the source carries no such column.
|
||||
fn try_get(&self, lane: usize) -> Option<A::Value<'a>>;
|
||||
|
||||
/// The lane's value, falling back to the marker's census default.
|
||||
fn get(&self, lane: usize) -> A::Value<'a> {
|
||||
self.try_get(lane).unwrap_or_else(A::default)
|
||||
}
|
||||
}
|
||||
|
||||
/// A source of lanes carrying an element and census attributes.
|
||||
@@ -27,6 +31,11 @@ pub trait LaneSource {
|
||||
fn attr<A: Attribute>(&self, lane: usize) -> A::Value<'_> {
|
||||
self.column::<A>().get(lane)
|
||||
}
|
||||
|
||||
/// Distinguishes an absent column from one holding the census default.
|
||||
fn try_attr<A: Attribute>(&self, lane: usize) -> Option<A::Value<'_>> {
|
||||
self.column::<A>().try_get(lane)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1180,8 +1180,8 @@ pub struct ListColumn<'a, A: crate::attribute::Attribute> {
|
||||
}
|
||||
|
||||
impl<'a, A: crate::attribute::Attribute> crate::lane::LaneColumn<'a, A> for ListColumn<'a, A> {
|
||||
fn get(&self, lane: usize) -> A::Value<'a> {
|
||||
self.stored.and_then(|column| column.get_any(lane)).and_then(A::from_stored).unwrap_or_else(A::default)
|
||||
fn try_get(&self, lane: usize) -> Option<A::Value<'a>> {
|
||||
self.stored.and_then(|column| column.get_any(lane)).and_then(A::from_stored)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1888,13 +1888,10 @@ pub struct RunColumn<'a, A: crate::attribute::Attribute> {
|
||||
}
|
||||
|
||||
impl<'a, A: crate::attribute::Attribute> crate::lane::LaneColumn<'a, A> for RunColumn<'a, A> {
|
||||
fn get(&self, lane: usize) -> A::Value<'a> {
|
||||
match self.offset {
|
||||
// SAFETY: the offset comes from the item's own layout, whose field at
|
||||
// this name holds this marker's value type by census registration.
|
||||
Some(offset) => unsafe { self.item.lanes().get(lane).rec().ptr().add(offset).cast::<A::Value<'a>>().read() },
|
||||
None => A::default(),
|
||||
}
|
||||
fn try_get(&self, lane: usize) -> Option<A::Value<'a>> {
|
||||
// SAFETY: the offset comes from the item's own layout, whose field at
|
||||
// this name holds this marker's value type by census registration.
|
||||
self.offset.map(|offset| unsafe { self.item.lanes().get(lane).rec().ptr().add(offset).cast::<A::Value<'a>>().read() })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ use crate::render_ext::{PaintTarget, RenderExt};
|
||||
use crate::to_peniko::{BlendModeExt, ToPenikoColor};
|
||||
use core_types::CacheHash;
|
||||
use core_types::attribute::{
|
||||
Background as BackgroundAttr, BlendMode as BlendModeAttr, Clip, ClippingMask, Dimensions, EditorLayerPath, FontSize, LetterSpacing, LetterTilt, LineHeight, Location, MaxHeight, MaxWidth, Opacity,
|
||||
OpacityFill, Transform,
|
||||
Background as BackgroundAttr, BlendMode as BlendModeAttr, Clip, ClippingMask, Dimensions, EditorLayerPath, EditorTextFrame, FontSize, LetterSpacing, LetterTilt, LineHeight, Location, MaxHeight,
|
||||
MaxWidth, Opacity, OpacityFill, Transform,
|
||||
};
|
||||
use core_types::blending::BlendMode;
|
||||
use core_types::bounds::BoundingBox;
|
||||
@@ -16,7 +16,7 @@ use core_types::math::quad::Quad;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::transform::Footprint;
|
||||
use core_types::uuid::{NodeId, generate_uuid};
|
||||
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_TEXT_FRAME, ATTR_TRANSFORM};
|
||||
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use graphene_hash::CacheHashWrapper;
|
||||
@@ -43,7 +43,8 @@ use std::ops::Deref;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
use text_nodes::markers::{Font, TextAlign};
|
||||
use vector_types::gradient::GradientSpreadMethod;
|
||||
use vector_types::{ATTR_EDITOR_CLICK_TARGET, ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD};
|
||||
use vector_types::markers::EditorClickTarget;
|
||||
use vector_types::{ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD};
|
||||
use vello::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@@ -1588,7 +1589,7 @@ impl Render for List<Vector> {
|
||||
}
|
||||
|
||||
// Use click-target override if the item provides one (e.g. 'Text' node's per-glyph bboxes)
|
||||
let click_target_vector = self.attribute::<Vector>(ATTR_EDITOR_CLICK_TARGET, index).unwrap_or(source);
|
||||
let click_target_vector = self.attr::<EditorClickTarget>(index).unwrap_or(source);
|
||||
|
||||
let item_relative_transform = item_zero_inverse * transform;
|
||||
|
||||
@@ -1617,7 +1618,7 @@ impl Render for List<Vector> {
|
||||
}
|
||||
|
||||
// Surface `editor:text_frame` for the Text tool's drag cage
|
||||
if let Some(&frame) = self.attribute::<DAffine2>(ATTR_EDITOR_TEXT_FRAME, index) {
|
||||
if let Some(frame) = self.try_attr::<EditorTextFrame>(index) {
|
||||
metadata.text_frames.entry(element_id).or_insert(frame);
|
||||
}
|
||||
}
|
||||
@@ -1647,7 +1648,7 @@ impl Render for List<Vector> {
|
||||
let transform: DAffine2 = self.attr::<Transform>(index);
|
||||
|
||||
// Use click-target override geometry if the item provides one (e.g. 'Text' node's per-glyph bounding boxes)
|
||||
let vector = self.attribute::<Vector>(ATTR_EDITOR_CLICK_TARGET, index).unwrap_or(source);
|
||||
let vector = self.attr::<EditorClickTarget>(index).unwrap_or(source);
|
||||
|
||||
extend_targets_from_vector(click_targets, self, index, vector, transform);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ impl PathBuilder {
|
||||
for (entry, widened) in entries.iter().zip(layer_bboxes.iter()) {
|
||||
let glyph_local = [widened[0] - entry.1, widened[1] - entry.1];
|
||||
let rect = Subpath::new_rectangle(glyph_local[0], glyph_local[1]);
|
||||
self.vector_list.set_attribute(ATTR_EDITOR_CLICK_TARGET, entry.0, Vector::from_subpaths([rect], false));
|
||||
self.vector_list.set_attribute(ATTR_EDITOR_CLICK_TARGET, entry.0, Some(Vector::from_subpaths([rect], false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ impl PathBuilder {
|
||||
widen_horizontal_gaps(&mut bboxes, &self.merged_click_target_baselines);
|
||||
|
||||
let widened_subpaths: Vec<_> = bboxes.iter().map(|[min, max]| Subpath::new_rectangle(*min, *max)).collect();
|
||||
self.vector_list.set_attribute(ATTR_EDITOR_CLICK_TARGET, 0, Vector::from_subpaths(widened_subpaths, false));
|
||||
self.vector_list.set_attribute(ATTR_EDITOR_CLICK_TARGET, 0, Some(Vector::from_subpaths(widened_subpaths, false)));
|
||||
}
|
||||
|
||||
// Fill in text frame for items that don't have one yet (single-item mode, where item 0 = identity)
|
||||
|
||||
Reference in New Issue
Block a user