Make the Outline render mode draw with consistent stroke thickness at any viewport zoom (#3848)

* Remove dead code for now-retired SVG implementation

* Implement viewport zoom compensation for thickness
This commit is contained in:
Keavon Chambers
2026-03-02 20:13:05 -08:00
committed by GitHub
parent a8b5203d6c
commit 7cc3097acd
7 changed files with 7 additions and 26 deletions

View File

@@ -148,10 +148,6 @@ impl RenderExt for Stroke {
if let Some(stroke_join_miter_limit) = stroke_join_miter_limit {
let _ = write!(&mut attributes, r#" stroke-miterlimit="{stroke_join_miter_limit}""#);
}
// Add vector-effect attribute to make strokes non-scaling
if self.non_scaling {
let _ = write!(&mut attributes, r#" vector-effect="non-scaling-stroke""#);
}
if paint_order.is_some() {
let _ = write!(&mut attributes, r#" style="paint-order: stroke;" "#);
}

View File

@@ -180,6 +180,8 @@ pub struct RenderParams {
pub aligned_strokes: bool,
pub override_paint_order: bool,
pub artboard_background: Option<Color>,
/// Viewport zoom level (document-space scale). Used to compute constant viewport-pixel stroke widths in Outline mode.
pub viewport_zoom: f64,
}
impl Hash for RenderParams {
@@ -197,6 +199,7 @@ impl Hash for RenderParams {
self.aligned_strokes.hash(state);
self.override_paint_order.hash(state);
self.artboard_background.hash(state);
self.viewport_zoom.to_bits().hash(state);
}
}
@@ -1109,7 +1112,7 @@ impl Render for Table<Vector> {
match render_params.render_mode {
RenderMode::Outline => {
let outline_stroke = kurbo::Stroke {
width: LAYER_OUTLINE_STROKE_WEIGHT,
width: LAYER_OUTLINE_STROKE_WEIGHT / if render_params.viewport_zoom > 0. { render_params.viewport_zoom } else { 1. },
miter_limit: 4.,
join: Join::Miter,
start_cap: Cap::Butt,

View File

@@ -309,8 +309,6 @@ pub struct Stroke {
#[serde(default = "daffine2_identity")]
pub transform: DAffine2,
#[serde(default)]
pub non_scaling: bool,
#[serde(default)]
pub paint_order: PaintOrder,
}
@@ -328,7 +326,6 @@ impl std::hash::Hash for Stroke {
self.join_miter_limit.to_bits().hash(state);
self.align.hash(state);
self.transform.to_cols_array().iter().for_each(|x| x.to_bits().hash(state));
self.non_scaling.hash(state);
self.paint_order.hash(state);
}
}
@@ -345,7 +342,6 @@ impl Stroke {
join_miter_limit: 4.,
align: StrokeAlign::Center,
transform: DAffine2::IDENTITY,
non_scaling: false,
paint_order: PaintOrder::StrokeAbove,
}
}
@@ -364,7 +360,6 @@ impl Stroke {
time * self.transform.matrix2 + (1. - time) * other.transform.matrix2,
self.transform.translation * time + other.transform.translation * (1. - time),
),
non_scaling: if time < 0.5 { self.non_scaling } else { other.non_scaling },
paint_order: if time < 0.5 { self.paint_order } else { other.paint_order },
}
}
@@ -462,11 +457,6 @@ impl Stroke {
self
}
pub fn with_non_scaling(mut self, non_scaling: bool) -> Self {
self.non_scaling = non_scaling;
self
}
pub fn has_renderable_stroke(&self) -> bool {
self.weight > 0. && self.color.is_some_and(|color| color.a() != 0.)
}
@@ -485,7 +475,6 @@ impl Default for Stroke {
join_miter_limit: 4.,
align: StrokeAlign::Center,
transform: DAffine2::IDENTITY,
non_scaling: false,
paint_order: PaintOrder::default(),
}
}