Part of #394: Actual Size shows print size whatever the display scaling

Display Print Size at 100% Zoom divided an assumed 96 pixels per inch by
the display's scale factor, so on a scaled display (150%, Retina) a
document inch came out a fraction of an inch. Nothing measures the
screen's real density, so an inch is now 96 screen points, the reference
density display scaling is set against, at any scale factor. The unused
screen_ppi and pixels_per_point fields go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-10 14:01:16 +07:00
parent a7faeb4299
commit 77e2a30c6d
4 changed files with 13 additions and 53 deletions

View File

@ -138,7 +138,7 @@ pub fn fit(app: &mut VectorcraftApp, how: &str) {
};
let Some(target) = target else { return };
let zoom = if how == "view.actualSize" {
actual_size_zoom(app.session.prefs.display_print_size, app.screen_ppi, app.pixels_per_point)
actual_size_zoom(app.session.prefs.display_print_size)
} else {
let zx = (rect.width() as f64 - 60.0) / target.width().max(1.0);
let zy = (rect.height() as f64 - 60.0) / target.height().max(1.0);
@ -151,7 +151,6 @@ pub fn fit(app: &mut VectorcraftApp, how: &str) {
}
pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
app.pixels_per_point = f64::from(ui.ctx().pixels_per_point());
let t = Tokens::get(ui.ctx());
let full = ui.available_rect_before_wrap();
// A document that opened, closed or became active since Home was chosen replaces it.
@ -749,25 +748,12 @@ pub(crate) fn animated_zoom(p: &vectorcraft_engine::Prefs) -> bool {
p.animated_zoom && p.gpu_performance
}
/// Zoom for View → Actual Size (`view.actualSize`).
///
/// With Preferences › General › Display Print Size at 100% Zoom off, one document point is one
/// screen point (zoom 1). With it on, one document inch (72 pt) fills one physical inch on the
/// screen: `screen_ppi / (72 × pixels_per_point)`, clamped to the zoom range.
///
/// `screen_ppi` is the assumed monitor density (CSS reference 96 by default; tests may inject a
/// measured value). `pixels_per_point` is egui's scale factor.
///
/// Public behaviour matches Adobe's preference of the same name
/// (<https://helpx.adobe.com/illustrator/using/setting-preferences.html> and the CC 2019 notes on
/// Actual Size / Display Print Size).
pub(crate) fn actual_size_zoom(display_print_size: bool, screen_ppi: f64, pixels_per_point: f64) -> f64 {
if !display_print_size {
return 1.0;
}
let ppp = if pixels_per_point.is_finite() && pixels_per_point > 0.0 { pixels_per_point } else { 1.0 };
let ppi = if screen_ppi.is_finite() && screen_ppi > 0.0 { screen_ppi } else { 96.0 };
(ppi / (72.0 * ppp)).clamp(0.0313, 640.0)
/// Zoom for View → Actual Size (`view.actualSize`). With Preferences › General › Display Print
/// Size at 100% Zoom off, one document point is one screen point. On, one document inch (72 pt)
/// fills an inch of the screen as the system counts it: 96 screen points, the reference density
/// that display scaling is set against (a CSS inch), whatever the scale factor.
pub(crate) fn actual_size_zoom(display_print_size: bool) -> f64 {
if display_print_size { 96.0 / 72.0 } else { 1.0 }
}
/// Zoom view `vm` of the canvas `rect` to `zoom` (clamped to the zoom range), keeping the document
@ -2980,36 +2966,19 @@ mod tests {
}
}
/// General › Display Print Size at 100% Zoom (#394): off, Actual Size is 1 document point per
/// screen point; on, one document inch fills one physical inch (`screen_ppi / (72 × ppp)`).
#[test]
fn actual_size_zoom_follows_display_print_size() {
assert_eq!(actual_size_zoom(false, 96.0, 1.0), 1.0);
assert_eq!(actual_size_zoom(false, 220.0, 2.0), 1.0);
assert!((actual_size_zoom(true, 96.0, 1.0) - 96.0 / 72.0).abs() < 1e-12);
assert!((actual_size_zoom(true, 220.0, 2.0) - 220.0 / (72.0 * 2.0)).abs() < 1e-12);
assert_eq!(actual_size_zoom(true, f64::NAN, 0.0), actual_size_zoom(true, 96.0, 1.0));
}
/// `view.actualSize` reads Preferences › Display Print Size at 100% Zoom and the host's screen
/// density (#394).
/// General › Display Print Size at 100% Zoom (#394): `view.actualSize` is one document point per
/// screen point with it off, and 96 screen points per document inch with it on.
#[test]
fn view_actual_size_follows_display_print_size() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 200, "height": 100})).unwrap();
app.canvas_rect = Some(egui::Rect::from_min_size(Pos2::ZERO, vec2(460.0, 260.0)));
app.screen_ppi = 96.0;
app.pixels_per_point = 1.0;
app.run("view.setZoom", json!({"zoom": 250})).unwrap();
app.run("view.actualSize", json!({})).unwrap();
assert!((app.view().unwrap().zoom - 1.0).abs() < 1e-12, "default pref keeps 100% = 1:1");
assert!((app.view().unwrap().zoom - 1.0).abs() < 1e-12, "off by default: 100% is 1:1");
app.session.execute("prefs.set", &json!({"key": "displayPrintSize", "value": true})).unwrap();
app.run("view.actualSize", json!({})).unwrap();
assert!((app.view().unwrap().zoom - 96.0 / 72.0).abs() < 1e-12, "print size uses screen PPI");
app.pixels_per_point = 2.0;
app.screen_ppi = 220.0;
app.run("view.actualSize", json!({})).unwrap();
assert!((app.view().unwrap().zoom - 220.0 / 144.0).abs() < 1e-12);
assert!((app.view().unwrap().zoom - 96.0 / 72.0).abs() < 1e-12, "an inch is 96 screen points");
}
/// Performance › Animated Zoom (#394): the Zoom tool dragged sideways zooms about where it was

View File

@ -336,13 +336,6 @@ pub struct VectorcraftApp {
last_time: f64,
/// Canvas rect of the last frame (screen points), for control-channel coordinate mapping.
pub canvas_rect: Option<egui::Rect>,
/// Physical pixels per inch assumed for View → Actual Size when Preferences › Display Print
/// Size at 100% Zoom is on. Defaults to the CSS reference density (96). Tests (and a future
/// safe host probe) may set a measured value.
pub screen_ppi: f64,
/// Last canvas `pixels_per_point` (egui's scale factor). Paired with [`Self::screen_ppi`] for
/// Actual Size under Display Print Size.
pub pixels_per_point: f64,
/// Hover position in document coordinates.
pub hover_doc: Option<vectorcraft_geom::Point>,
/// System clipboard: SVG to publish next frame, the last SVG we published (so pasting it back
@ -444,8 +437,6 @@ impl VectorcraftApp {
frame: 0,
last_time: 0.0,
canvas_rect: None,
screen_ppi: 96.0,
pixels_per_point: 1.0,
hover_doc: None,
custom_titlebar: false,
graphics_adapter: None,

View File

@ -209,7 +209,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
"view.actualSize",
"Actual Size",
"Cmd+1",
"{} 100%: with Display Print Size at 100% Zoom off, one document point per screen point; on, one document inch fills one physical inch on the screen (screen PPI / (72 × pixels_per_point))",
"{} 100%: with Display Print Size at 100% Zoom off, one document point per screen point; on, one document inch fills 96 screen points (an inch at the system's reference density, whatever the display scaling)",
),
("view.setZoom", "Set Zoom", "", "{zoom: percent, center?: [x,y]}"),
(

View File

@ -1433,7 +1433,7 @@ control channel's `ui.drag` scrubs), `showHomeScreen` (on by default: the Home s
off, an empty window, and the Home button or `app.home` still shows the screen), `autoCollapseIconPanels` (off by
default: on, a click away from a panel popped out of the icon column puts it away) and `displayPrintSize` (off by
default: View › Actual Size / `view.actualSize` is one document point per screen point; on, one document inch fills
one physical inch using the CSS reference density of 96 ppi).
96 screen points, an inch at the system's reference density whatever the display scaling).
The Smart Guides preferences (Preferences › Smart Guides) apply to `pointer_gesture` with Smart Guides on (the
default view) and to the mouse; they change what the tools show and how far a target pulls, and only Construction