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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 7 additions and 26 deletions

View File

@ -432,10 +432,6 @@ impl TableRowLayout for Vector {
TextLabel::new("Stroke Transform").narrow(true).widget_instance(),
TextLabel::new(format_transform_matrix(&stroke.transform)).narrow(true).widget_instance(),
]);
table_rows.push(vec![
TextLabel::new("Stroke Non-Scaling").narrow(true).widget_instance(),
TextLabel::new((if stroke.non_scaling { "Yes" } else { "No" }).to_string()).narrow(true).widget_instance(),
]);
table_rows.push(vec![
TextLabel::new("Stroke Paint Order").narrow(true).widget_instance(),
TextLabel::new(stroke.paint_order.to_string()).narrow(true).widget_instance(),

View File

@ -515,7 +515,6 @@ fn apply_usvg_stroke(stroke: &usvg::Stroke, modify_inputs: &mut ModifyInputsCont
align: StrokeAlign::Center,
paint_order: PaintOrder::StrokeAbove,
transform,
non_scaling: false,
})
}
}

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(),
}
}

View File

@ -1,16 +1,14 @@
use core_types::table::Table;
use core_types::transform::Footprint;
use core_types::transform::{Footprint, Transform};
use core_types::{CloneVarArgs, ExtractAll, ExtractVarArgs};
use core_types::{Color, Context, Ctx, ExtractFootprint, OwnedContextImpl, WasmNotSend};
use graph_craft::document::value::RenderOutput;
pub use graph_craft::document::value::RenderOutputType;
pub use graph_craft::wasm_application_io::*;
use graphene_application_io::{ApplicationIo, ExportFormat, ImageTexture, RenderConfig};
use graphic_types::Artboard;
use graphic_types::Graphic;
use graphic_types::Vector;
use graphic_types::raster_types::Image;
use graphic_types::raster_types::{CPU, Raster};
use graphic_types::{Artboard, Graphic, Vector};
use rendering::{Render, RenderOutputType as RenderOutputTypeRequest, RenderParams, RenderSvgSegmentList, SvgRender, format_transform_matrix};
use rendering::{RenderMetadata, SvgSegment};
use std::collections::HashMap;
@ -110,6 +108,7 @@ async fn create_context<'a: 'n>(
render_output_type,
footprint: Footprint::default(),
scale: render_config.scale,
viewport_zoom: footprint.decompose_scale().x,
..Default::default()
};

View File

@ -211,7 +211,6 @@ where
join_miter_limit: miter_limit,
align,
transform: DAffine2::IDENTITY,
non_scaling: false,
paint_order,
};