Export document navigation from the box tree: LinkRuns, DocumentIDs, Headings - #139
Merged
Merged
Conversation
…Headings
go-pdfkit/html2pdf re-implemented, unexported, what it needed to write PDF
link annotations, named destinations and an outline: per-line clickable
runs of each <a href>, the position of each id'd element, and the h1..h6
outline. None of that is about PDF — it is what a laid-out document looks
like to anything that navigates it (an outline panel, an EPUB export, a
scroll-to-hash in a browser shell) — and html2pdf had also copied the
engine's own anchorFor and itemRect to get at it. So it moves here.
nav.go adds, over a laid-out *layout.Box tree, in document CSS px:
LinkRuns(root, base, ids) []LinkRun one rectangle per anchor per line,
URI (absolute http(s)) or Fragment
(an id in ids); an atom-less anchor
gets its outermost box, once
DocumentIDs(root) map[string]Anchor every id and legacy <a name> with a
position, first occurrence wins
Headings(root) []Heading h1..h6 in order, atoms' texts joined
by single spaces, untitled skipped
LinksFromBox is left as it is (one bounding box per anchor, in image
pixels, for hit-testing a click) and its tests pass unchanged; its
itemRect now rounds out the shared float primitive itemBox instead of
carrying a second copy of the same conditions. anchorFor stays unexported
and is shared by both readings of the tree.
Tests are html2pdf's, ported to the engine's fixtures (dom.Parse,
css.Cascade, layout.LayoutDocument with real fonts): a wrapped anchor
splits per line; a dangling "#nowhere" is dropped; the document's own URL
plus a fragment is a Fragment; a relative href resolves against base;
javascript:/mailto:/tel:/data:/empty hrefs yield nothing; an atom-less
anchor gets its block's rectangle once and a text anchor is not doubled;
ids for a block, an inline and <a name>; headings with levels and an
icon-only heading skipped; resolveAnchor's edge cases.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
Why
go-pdfkit/html2pdf re-implemented, unexported, what it needed to write PDF link annotations, named destinations and an outline: per-line clickable runs of each
<a href>, the position of each id'd element, and the h1..h6 outline. None of that is about PDF — it is what a laid-out document looks like to anything that navigates it (an outline panel, an EPUB export, a scroll-to-hash in a browser shell) — and html2pdf had also copied the engine's ownanchorForanditemRectto get at it. So it moves here, and html2pdf can delete its copies.What
nav.goadds, over a laid-out*layout.Boxtree, in document CSS px:LinkRuns: one rectangle per anchor per line (a wrapped link's clickable area follows the text),URIfor an absolute http(s) target orFragmentfor an id inids; javascript:/mailto:/tel:/data:/empty hrefs and fragments nobody anchors yield nothing. An anchor that laid out no atom at all (a link around an empty CSS-sized block — Hacker News's vote arrows) gets the rectangle of the outermost box under it, once.DocumentIDs: every id and legacy<a name>with a position — a block's box top-left, an inline's first atom — document order, first occurrence wins.Headings: h1..h6 in document order, title = atoms' texts joined by single spaces, untitled skipped.LinksFromBoxis left as it is (one bounding box per anchor in image pixels, for hit-testing a click) and its tests pass unchanged; itsitemRectnow rounds out the shared float primitiveitemBoxinstead of carrying a second copy of the same conditions.anchorForstays unexported and is shared by both.Tests
html2pdf's, ported to the engine's fixtures (
dom.Parse,css.Cascade,layout.LayoutDocumentwith real fonts): a wrapped anchor splits per line; a dangling#nowhereis dropped; the document's own URL plus a fragment is aFragment; a relative href resolves against base; javascript:/mailto:/tel:/data:/empty hrefs yield nothing; an atom-less anchor gets its block's rectangle once and a text anchor is not doubled; ids for a block, an inline and<a name>; headings with levels and an icon-only heading skipped;resolveAnchor's edge cases.CGO_ENABLED=0 go vet ./... && go test -short ./...green locally.🤖 Generated with Claude Code