fix(ui): bookmark_position keeps a sliver page when nothing else shows; the rail test checks the rail's real edges (#5636)

A page showing under a pixel at the window's top is ignored in favour of the next page, but still
chosen when no other page shows. The rail test no longer tolerates 2 pt of overflow: it compares the
page and zoom fields with the rail's own edges.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
RiceDeeandClaude Sonnet 5.5 committed 2026-11-01 18:37:23 +11:00
1 parent cab29b4f19
commit 461200e74a
2 files changed
+13 -7

No files matched your search

+10 -6
View File
@@ -33,12 +33,16 @@ impl DocView {
// nearest one below.
let top = self.viewport_screen.top();
// A page showing less than a pixel is rounding, not what the reader is looking at: a jump
// to the next page leaves the previous one's bottom edge within a pixel of the top.
let showing = || self.screen_xforms.iter().filter(|(_, xf)| xf.rect.bottom() > top + 1.0);
let (page, xf) = showing()
.filter(|(_, xf)| xf.rect.top() <= top)
.min_by_key(|(p, _)| *p)
.or_else(|| showing().min_by(|a, b| a.1.rect.top().total_cmp(&b.1.rect.top()).then(a.0.cmp(&b.0))))?;
// to the next page leaves the previous one's bottom edge within a pixel of the top. Such a
// sliver still counts when nothing else shows (the last page at the very end).
let pick = |slack: f32| {
let showing = || self.screen_xforms.iter().filter(move |(_, xf)| xf.rect.bottom() > top + slack);
showing()
.filter(|(_, xf)| xf.rect.top() <= top)
.min_by_key(|(p, _)| *p)
.or_else(|| showing().min_by(|a, b| a.1.rect.top().total_cmp(&b.1.rect.top()).then(a.0.cmp(&b.0))))
};
let (page, xf) = pick(1.0).or_else(|| pick(0.0))?;
let p = info.pages.get(*page)?;
// Above the page (in the gap before it) is the page's own top. The window's vertical is
// the view's y, or its x when the view is turned a quarter.
+3 -1
View File
@@ -1433,11 +1433,13 @@ fn typing_in_one_tab_never_reaches_another_tabs_added_text() {
fn rail_page_and_zoom_fields_match_and_fit_the_rail() {
let mut h = harness();
h.run_steps(3);
// The rail is 49 pt wide at the window's right edge (1400 pt wide), inside a 1 pt border.
let (rail_left, rail_right) = (1400.0 - 49.0 + 1.0, 1400.0 - 1.0);
let rail = h.get_by_label("Bookmarks").rect();
let (page, zoom) = (h.get_by_label("Current page").rect(), h.get_by_label("Zoom").rect());
assert_eq!((page.width(), page.height()), (zoom.width(), zoom.height()), "{page:?} vs {zoom:?}");
for r in [page, zoom] {
assert!(r.left() >= rail.left() - 2.0 && r.right() <= rail.right() + 2.0, "{r:?} is cut off by the rail ({rail:?})");
assert!(r.left() >= rail_left && r.right() <= rail_right, "{r:?} is cut off by the rail ({rail_left}..{rail_right})");
assert!((r.center().x - rail.center().x).abs() < 1.0, "{r:?} is off the rail's centre ({rail:?})");
}
}