From e68dedd10d5a29bedf8e541d8f976c6388c761f6 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Tue, 31 Mar 2026 21:04:02 +0800 Subject: [PATCH] fix(layout): fix primary view detection on fractional DPR devices, closes #3681 (#3701) --- .../document/paginator-multiview.test.ts | 31 ++++++++++++++++++- packages/foliate-js | 2 +- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/readest-app/src/__tests__/document/paginator-multiview.test.ts b/apps/readest-app/src/__tests__/document/paginator-multiview.test.ts index b0b1ffff..bbff5a15 100644 --- a/apps/readest-app/src/__tests__/document/paginator-multiview.test.ts +++ b/apps/readest-app/src/__tests__/document/paginator-multiview.test.ts @@ -235,10 +235,12 @@ describe('Paginator multi-view architecture', () => { { index: 5, offset: 150, size: 200 }, ]; const detectPrimary = (visibleStart: number) => { + let offset = 0; for (const view of views) { - if (visibleStart < view.offset + view.size) { + if (visibleStart < offset + view.size - 1) { return view.index; } + offset += view.size; } return views[views.length - 1]?.index; }; @@ -249,6 +251,33 @@ describe('Paginator multi-view architecture', () => { expect(detectPrimary(150)).toBe(5); // at boundary → third view expect(detectPrimary(300)).toBe(5); // in third view }); + + it('should handle floating-point precision at view boundaries (Android DPR)', () => { + // On Android with non-integer DPR, container scrollLeft and accumulated + // getBoundingClientRect() sizes diverge by tiny amounts (~0.0001px). + // Real trace: visibleStart=1570.9090576171875, accumulated offset+viewSize=1570.9091796875 + // Fix: 1px tolerance so sub-pixel drift doesn't pick the wrong view. + const viewSize = 785.45458984375; + const detectPrimary = (visibleStart: number) => { + let offset = 0; + const views = [ + { index: 1, size: viewSize }, + { index: 2, size: viewSize }, + { index: 3, size: viewSize }, + ]; + for (const view of views) { + if (visibleStart < offset + view.size - 1) { + return view.index; + } + offset += view.size; + } + return views[views.length - 1]?.index; + }; + // visibleStart from scrollLeft: 2 * viewSize computed differently than sum of rects + const visibleStart = 1570.9090576171875; // container.scrollLeft + // With tolerance, this should detect index 3 (not 2) + expect(detectPrimary(visibleStart)).toBe(3); + }); }); describe('Adjacent index with fromIndex parameter', () => { diff --git a/packages/foliate-js b/packages/foliate-js index 837c98fa..c5c09a97 160000 --- a/packages/foliate-js +++ b/packages/foliate-js @@ -1 +1 @@ -Subproject commit 837c98fae0c39d1cc1cc892408910c2135f8ad0b +Subproject commit c5c09a9762505e2caf83729c988181d92be3ce70