forked from akai/readest
Bump foliate-js with two fixed-layout (EPUB and PDF) two-page spread fixes: - Spine seam: overlap the two pages by one device pixel to hide the 1px white seam that appeared at the spine at a fractional devicePixelRatio (e.g. Windows 150% display scale). - Zoomed-out blank page: keep non-PDF pages in block flow below 100% zoom; the PDF-only zoom-out centering was pushing the un-scaled iframe out of view and blanking the page. Adds a unit test for the computeSpreadSpineOverlap helper. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
// Regression test for readest/readest issue #4857.
|
||||
//
|
||||
// In a fixed-layout (EPUB or PDF) two-page spread at a fractional device pixel
|
||||
// ratio (Windows display scale 150% -> devicePixelRatio 1.5), a one-pixel white
|
||||
// seam appeared down the middle of the spread at the spine.
|
||||
//
|
||||
// Root cause: the two page iframes are independent compositor layers, each
|
||||
// scaled by a (usually non-integer) factor. At a fractional devicePixelRatio the
|
||||
// spine between them lands on a fractional device pixel, so each layer's edge
|
||||
// there is anti-aliased against transparency and the reader background bleeds
|
||||
// through as a thin white seam. (Filling the page canvas to its box, #4587, does
|
||||
// not help: the soft edge comes from scaling the layer, not from the content
|
||||
// stopping short of its box.)
|
||||
//
|
||||
// The fix overlaps the (top-most) right page onto the left by exactly one device
|
||||
// pixel, so each soft edge sits over the neighbour's opaque content instead of
|
||||
// the background. The shift is visual-only (translateX), leaving the centred
|
||||
// spread layout untouched. `computeSpreadSpineOverlap` returns that translateX
|
||||
// (in CSS px) for the right page, or 0 for layouts with no touching spine.
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { computeSpreadSpineOverlap } from 'foliate-js/fixed-layout.js';
|
||||
|
||||
describe('computeSpreadSpineOverlap (#4857)', () => {
|
||||
it('overlaps the right page by exactly one device pixel on a real two-page spread', () => {
|
||||
// Windows 150% scale: one device pixel is 1 / 1.5 CSS px.
|
||||
expect(computeSpreadSpineOverlap({ devicePixelRatio: 1.5 })).toBeCloseTo(-1 / 1.5, 10);
|
||||
// Retina / mobile: one device pixel is 0.5 CSS px.
|
||||
expect(computeSpreadSpineOverlap({ devicePixelRatio: 2 })).toBeCloseTo(-0.5, 10);
|
||||
// No scaling: one device pixel is one CSS px.
|
||||
expect(computeSpreadSpineOverlap({ devicePixelRatio: 1 })).toBeCloseTo(-1, 10);
|
||||
});
|
||||
|
||||
it('defaults a missing/zero devicePixelRatio to 1 device pixel', () => {
|
||||
expect(computeSpreadSpineOverlap({})).toBeCloseTo(-1, 10);
|
||||
expect(computeSpreadSpineOverlap({ devicePixelRatio: 0 })).toBeCloseTo(-1, 10);
|
||||
});
|
||||
|
||||
it('does not overlap layouts that have no touching spine', () => {
|
||||
// A single centred page (cover / odd page).
|
||||
expect(computeSpreadSpineOverlap({ center: true, devicePixelRatio: 1.5 })).toBe(0);
|
||||
// Portrait device: only one page of the spread is shown.
|
||||
expect(computeSpreadSpineOverlap({ portrait: true, devicePixelRatio: 1.5 })).toBe(0);
|
||||
// A spread slot padded with a blank page shows a single real page.
|
||||
expect(computeSpreadSpineOverlap({ leftBlank: true, devicePixelRatio: 1.5 })).toBe(0);
|
||||
expect(computeSpreadSpineOverlap({ rightBlank: true, devicePixelRatio: 1.5 })).toBe(0);
|
||||
});
|
||||
|
||||
it('still overlaps a two-page spread when zoomed below 100%', () => {
|
||||
// Zoom is intentionally not an input: the pages stay adjacent at every zoom,
|
||||
// so a sub-100% spread gets the same overlap as a 100% one.
|
||||
expect(computeSpreadSpineOverlap({ devicePixelRatio: 2 })).toBeCloseTo(-0.5, 10);
|
||||
});
|
||||
});
|
||||
+1
-1
Submodule packages/foliate-js updated: 0fa407c4c6...0f85707129
Reference in New Issue
Block a user