Add support for choosing the rendered variant of EPUB resources - #898
Merged
Merged
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Four moderate issues remain involving position data, anchor navigation, and Divina profile detection.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds selectable EPUB resource variants, allowing HTML or bitmap fallbacks to be rendered while preserving authored spine order.
Changes:
- Adds
.default,.html, and.imagevariant preferences. - Updates fallback parsing, locator handling, spread behavior, and bitmap layout.
- Adds tests, fixtures, and changelog documentation.
File summaries
| File | Summary |
|---|---|
Tests/StreamerTests/Parser/EPUB/OPFParserTests.swift |
Tests fallback parsing and Divina inference. |
Tests/StreamerTests/Fixtures/OPF/fallback-html-image-partial.opf |
Adds a partial fallback fixture. |
Tests/NavigatorTests/EPUB/EPUBViewportAndLocationCalculatorTests.swift |
Tests rendered locator metadata. |
Tests/NavigatorTests/EPUB/EPUBSpreadTests.swift |
Tests bitmap spread behavior. |
Tests/NavigatorTests/EPUB/EPUBReadingOrderTests.swift |
Tests variant selection and locator resolution. |
Sources/Streamer/Parser/EPUB/OPFParser.swift |
Preserves spine links and records fallbacks. Moderate (3 votes): Divina profile detection does not recognize bitmap alternates. |
Sources/Navigator/EPUB/EPUBViewportAndLocationCalculator.swift |
Reports rendered resource hrefs and media types. |
Sources/Navigator/EPUB/EPUBSpreadView.swift |
Resolves selected resources by variant. |
Sources/Navigator/EPUB/EPUBResourceVariant.swift |
Defines supported resource variants. |
Sources/Navigator/EPUB/EPUBReflowableSpreadView.swift |
Supports variant-aware locator navigation. |
Sources/Navigator/EPUB/EPUBReadingOrder.swift |
Selects rendered variants. Moderate (1 vote): Positions are not normalized for fixed bitmap variants. Moderate (1 vote): Query/fragment handling can prevent anchor navigation. |
Sources/Navigator/EPUB/EPUBNavigatorViewModel.swift |
Applies variant configuration. Moderate (1 vote): Position data can remain inconsistent with selected bitmap variants. |
Sources/Navigator/EPUB/EPUBNavigatorViewController.swift |
Integrates variant-aware navigation. |
CHANGELOG.md |
Documents the new behavior. |
Review details
Suppressed comments (3)
Sources/Navigator/EPUB/EPUBNavigatorViewModel.swift:123
EPUBReadingOrderchanges the media type and layout seen by the navigator, butpositionsByReadingOrderis still loaded from the publication's original spine links. For an XHTML spine item with a bitmap fallback, the positions service creates multiple reflowable positions for XHTML; selecting.imagethen renders one fixed page whilepositionCountand locator calculation still use those positions, producing incorrect position andtotalProgressionvalues. Rebuild or disable positions for the rendered order when the preferred variant changes, and cover it with a location test.
self.readingOrder = EPUBReadingOrder(
readingOrder: readingOrder,
preferredVariant: config.preferredResourceVariant
Sources/Navigator/EPUB/EPUBReadingOrder.swift:86
- Setting the rendered copy to
.fixeddoes not update the position list.positionsByReadingOrderis produced byEPUBPositionsServicefrompublication.manifest.readingOrder, where these HTML spine links are still reflowable, so a bitmap fallback can retain several HTML positions. The fixed spread then reports/preloads those positions and calculates total progression as if the bitmap were reflowable; normalize the positions for the selected rendered variants (one position for each bitmap) before using them.
if link.mediaType?.isBitmap == true {
link.properties.epubLayout = .fixed
Sources/Navigator/EPUB/EPUBReadingOrder.swift:63
index(of:)intentionally matches a rendered link after stripping query/fragment, but this guard compares the URLs including those components. A locator for the rendered resource such asp1.xhtml#idis therefore treated as an alternate, its fragment is cleared below, and anchor navigation fails. Compare query/fragment-stripped URLs (or track whether the match was the rendered link) before clearing locations.
guard !href.isEquivalentTo(locator.href) else {
return (index, locator)
}
- Files reviewed: 14/14 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Added
Navigator
EPUBNavigatorViewController.Configuration.preferredResourceVariantto choose which variant of each resource is rendered among itsalternates, such as the XHTML page or its bitmap fallback.EPUBNavigatorDelegate.navigator(_:contentInsetFor:)to customize the content insets of a spread according to itsEPUBLayout, for example to add margins only around the reflowable resources of a mixed-layout publication. It takes precedence overnavigatorContentInset(_:).Changed
Navigator
page-spread-left). It was previously displayed on the left or right half of the viewport, depending on the reading progression.Streamer
alternates.EPUBNavigatorViewController.Configuration.preferredResourceVariant = .imagein the EPUB navigator configuration to render the bitmaps like before.