Skip to content

feat(engines): follow 한글's stored line layout where it can be used - #839

Merged
KnifeLemon merged 1 commit into
builtin-enginesfrom
engine/stored-lines
Oct 30, 2026
Merged

KnifeLemon merged 1 commit into
builtin-enginesfrom
engine/stored-lines

Conversation

@KnifeLemon

Copy link
Copy Markdown
Owner

What does this change?

Implements the Project 4 item "Layout engine: honor stored HWP/HWPX line layout (fidelity mode)".

Stacked on #834 (paragraph layout). The base is engine/paragraph-layout for a readable diff; it moves to builtin-engines once #834 is merged.

Why

An HWPX that 한글 saved stores each paragraph's lines (hp:linesegarray: start, height, baseline, position, width). 한글 itself draws from them when it opens the file; it does not break the lines again. I checked this with 한글 through automation:

Reader: 한글 positions → model positions

  • Counting rules: 한글's text positions follow the control-character table of Hancom's HWP 5.0 format document.
    • Eight positions for every inline or extended control: tab, field begin/end, section and column definitions, tables, objects, equations, notes, header/footer, numbers, bookmarks, title marks.
    • One position for a line break, non-breaking space, fixed-width space or hyphen.
  • Conversion: the paragraph builder counts both ways while it reads, and converts the stored starts into positions in the layout's text (HLineLayout.Starts).
  • No positions kept: for a paragraph that a table splits, and for a start that falls inside an object.

Layout

  • When stored lines are used: the lines are not marked as estimated by Filee, and every font of the paragraph is installed under its name or another of its names.
  • What the lines take from the stored layout:
    • their starts, with a list number put in front;
    • their stored height and baseline;
    • their place beside an object (horzpos / horzsize).
  • A stored line wider than its line now is squeezed between its characters.
  • Otherwise the paragraph is broken again, and ParagraphBox.StoredLinesIgnored says why.
  • ParagraphLayouter(storedLines: false) and FileeRenderer.ToPdf(storedLines: false) turn it off, for tests and a future preview setting.

Measured on the HWPX files attached to Filee's issues (#49, #51, #65; not in the repository)

  • Conversion: 768 of the 769 paragraphs with stored lines convert. The converted starts fall on spaces and syllable boundaries.
  • Against 한글's own PDF (exported by 한글 automation), 행정정보동의서 (single column):
    • line agreement goes from 46.4% to 82.1%;
    • every line of body text is the same as 한글's;
    • the rest is the table area and the page break after it.
  • The other three documents are dominated by tables, two-column pages and equations, which later items lay out. Their document-level numbers mean little until then.

Tests

  • DocumentModelTests: positions convert across a tab, a footnote, a line break and an equation. A start inside an equation keeps no positions, and neither does a paragraph split by a table.
  • ParagraphLayoutTests:
    • lines start where they were stored, with the stored height and baseline;
    • a stored line that no longer fits is squeezed;
    • a list number shifts the stored starts;
    • a line beside an object keeps its place;
    • stored lines are ignored when estimated, when a font is missing or when they don't map;
    • the off switch works.
  • Engines suite locally: 2308 passed, 0 failed.

🤖 Generated with Claude Code

The HWPX reader converts 한글's text positions (eight per control, one per line break and special space, as Hancom's
HWP 5.0 document defines them) into positions in the layout's text. Paragraphs whose stored lines weren't estimated by
Filee and whose fonts are all installed start their lines where 한글 started them, with the stored height and
baseline, beside objects where 한글 put them, and squeeze a stored line that no longer fits between its characters as
한글 does. Otherwise the paragraph is broken again and ParagraphBox.StoredLinesIgnored says why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KnifeLemon KnifeLemon added the built-in engines Filee: built-in engines (Project 4), on the builtin-engines branch, not released yet label Oct 30, 2026
@github-actions github-actions Bot added the feature New features label Oct 30, 2026
@KnifeLemon
KnifeLemon changed the base branch from engine/paragraph-layout to builtin-engines October 30, 2026 15:12
@KnifeLemon
KnifeLemon merged commit e4b15bb into builtin-engines Oct 30, 2026
18 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

built-in engines Filee: built-in engines (Project 4), on the builtin-engines branch, not released yet feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant