Skip to content

fix(typeset): 앵커 문단도 자기 쪽·종이 기준 자리차지 밴드 아래에서 시작한다 (#8186) - #8130

Closed
planet6897 wants to merge 2 commits into
edwardkim:develfrom
planet6897:fix/stored-reset-field-group-controls
Closed

planet6897 wants to merge 2 commits into
edwardkim:develfrom
planet6897:fix/stored-reset-field-group-controls

Conversation

@planet6897

@planet6897 planet6897 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

요약

쪽·종이 기준 위아래 배치(TopAndBottom) 그림·도형을 가진 문단의 첫 줄도 그 밴드 아래에서 시작하게 한다. #7696 이후 rhwp 는 개체를 내보낸 뒤에야 밴드를 등록했다. 그래서 앵커 문단은 밴드 위에 남고 뒤 문단만 밀렸다. 그 결과 본문 전체가 정본보다 줄 하나 위에 그려졌고, 저장 쪽 경계와 다른 줄에서 문단이 나뉘었다.

Closes #8186

이전 head(3d2187812)에 함께 있던 저장 쪽 경계 판정 수정(#8124, 7d9a1db86)은 이 PR 에서 뺐다. 아래 「분리한 판정 수정」 참고.

규칙과 근거

한/글은 위아래 배치 개체의 밴드 안에서 시작하는 줄을 밴드 아래로 보낸다. 그 개체를 가진 문단 자신의 줄도 마찬가지다.

독립 근거는 한/글 2020 이 HWP 로 저장한 입력이다. 구역 첫 빈 문단 pi=0 은 사각형 A 를 가지는데, 그 저장 vpos 가 30915 HU 로 A 하단(30912.5 HU, 단 상대)과 같다. Print PDF 에서도 pi=1 글줄 위끝이 527.2px 로 A 하단 + 줄 한 칸에 있다.

원인

  • register_page_anchored_topbottom_band 는 PageItem::Shape 를 방출한 뒤에만 불린다. 그래서 앵커 문단의 fit 은 자기 밴드를 보지 못한다.
  • 단의 첫 문단이라 쪽 vpos 기준(vpos_snap_current_height)이 그 문단의 vpos(30915)로 잡혔다. 한/글은 이 문단을 밴드 아래에 저장했으므로 이 기준은 틀렸다.
  • 그 결과 pi=1 은 밴드 하단(412.2px)으로 밀리지만, 저장 사다리는 21.3px 를 가리킨다. 흐름은 pi=0 의 줄 한 칸(21.3px)을 잃는다. 문단 P 는 1쪽에 줄 3까지 들어가 줄 3에서 나뉘었다(정본은 줄 2).

수정 (state/transition.rs, paragraph.rs)

경로 수정 전 수정 후
앵커 문단의 fit (prepare_fit_budget) 자기 밴드를 모름 문단 소유 쪽·종이 기준 밴드를 미리 등록하고 같은 밴드 판정(apply_visible_float_exclusions_absorbing)을 적용한다
밴드 아래에서 첫 줄이 단에 안 들어감 — 미리 등록하지 않는다. #7696 의 «줄만 다음 쪽, 개체는 남김» 쪽 소속을 바꾸지 않는다
개체 방출 후 등록 등록 같은 밴드는 중복 등록하지 않는다
단 첫 문단이 밴드에 밀림 쪽 기준 = 그 문단 vpos 민 거리만큼 기준을 되돌린다(vpos_page_base, vpos_stored_column_origin)
배치 page_band_flow_starts 소비 그대로. 조판이 확정한 시작을 같은 키로 소비한다

수정 전후 (code head 9c8499c3b, evidence head c96177867, base devel d9fd85ed5)

입력 해시(sha256 앞 16자):

파일 해시
samples/stored_reset_float/field_float_reset.hwp 9dfe5e3fcdb1041d
samples/stored_reset_float/field_float_reset_plain.hwp 5eefa29cbad1ba0d
pdf/stored_reset_float/field_float_reset-2020.pdf 2c7f2f14f3a60d96
pdf/stored_reset_float/field_float_reset_plain-2020.pdf a0f4e1806669482b

판정값은 scripts/visual_sweep.py 2px 이웃 관용 내용 실루엣 raw(%)이며, 전 쪽을 측정했다. fresh WASM 은 호스트 scripts/wasm-pack-locked.sh 최적화 빌드 118e7a36021f…(Studio public 동기화 SHA 일치)이다.

입력 쪽 base Native head Native head WASM P 분할 base → head
field_float_reset.hwp p1 97.49 99.94 99.95 줄 3 → 줄 2
p2 97.14 99.99 99.98
field_float_reset_plain.hwp (대조군) p1 97.49 99.94 99.95 줄 3 → 줄 2
p2 65.16 99.80 99.79

base 의 gate 는 대조군에서 re_review_required, head 는 Native·WASM 네 경우 모두 passed 다. 쪽수는 모두 2쪽으로 한/글과 같다. 직접 판독: head 는 Native·WASM 모두 1쪽이 «낱말25» 로 끝나고 2쪽이 «낱말26» 으로 시작해 정본과 같다.

TSV 원본: field native-base · field native-new · field wasm-new · plain native-base · plain native-new · plain wasm-new

대조군 p2 — base (devel): 2쪽이 «낱말39» 에서 시작

plain p2 base review

대조군 p2 — head Native / overlay / fresh WASM

plain p2 head review
plain p2 head overlay
plain p2 wasm review

필드 입력 p1·p2 — head Native / overlay / fresh WASM

field p1 head review
field p1 head overlay
field p2 head review
field p2 wasm review

나머지 쪽·경로(base 와 WASM overlay 포함)는 mydocs/report/stored_reset_field_float/ 에 있다.

테스트

tests/cases/stored_reset_field_float_suffix.rs — devel 소스(d9fd85ed5)에서 둘 다 FAIL, head 에서 둘 다 PASS 를 실행으로 확인했다.

테스트 검사 항목 devel head
section_first_paragraph_starts_below_its_own_paper_band 두 입력에서 1쪽 사각형은 A 하나, pi=1 첫 글줄 = A 하단 + pi=0 저장 줄 한 칸(±1px, 해당 쪽 Native/WASM raw ≥99.94), 본문 글줄은 A 밴드에 들어가지 않음 FAIL — pi=1 이 A 하단 506.7 에 붙음 PASS
paragraph_after_section_paper_band_splits_at_stored_line 쪽수, P 줄 범위의 쪽 소속, 뒤 문단 2쪽, 쪽별 글자 소유(…낱말25 / 낱말26…), 사각형 2쪽 FAIL — 두 입력 모두 P 줄 3 분할 PASS

영향 범위와 검증 (head 9c8499c3b, base d9fd85ed5)

검사 결과
samples 1,319건 dump-pages A/B 바뀐 문서는 두 fixture 와 143E433F503322BD33(.hwp/.hwpx). 143E433F 는 SVG 가 바이트 단위로 같고, 조판만 pi=0 을 3.8px 내려 저장 vpos(283 HU)와 맞췄다(이전 head 측정과 같음)
10k 코퍼스 표본 2,000건 A/B 이전 head(밴드 수정 전후)에서 0건. 이번 head 에서는 재실행하지 않았다
nextest (release-test 전체) 11365/11365 통과
Native Skia 3종 lib 3859 통과, issue_2225_missing_picture_placeholder·render_p37_direct_pdf_export 통과
lint fmt, clippy(native·wasm32·workspace all-targets), workspace build, suite manifest --check, unit tier --check 통과
fresh WASM 호스트 최적화 빌드, 위 Visual Sweep 에 사용

분리한 판정 수정 (#8124)

이전 head 는 저장 쪽 경계 판정(stored_body_reset_fragment_matches_current_flow)에서 필드·책갈피와 경계 뒤 용지 기준 글 앞/뒤 개체가 경계를 막지 않게 하는 수정(7d9a1db86)도 담았다. 밴드 보정 뒤로는 이 fixture 가 그 수정을 검출하지 못한다(밴드가 바르면 흐름만으로 같은 줄에서 나뉜다). 확인한 내용:

  • 같은 생성기로 FILL 12–30, 밴드 위치 A_Y 8100–10200 의 변형 34건을 한/글 2020 으로 재저장해 A/B 했다. 판정 수정 유무에 따른 차이는 0건이다.
  • 실물에서는 여전히 갈린다. 10k 「비정규직 목표관리 로드맵」 2구역 pi=6 을 판정 수정이 있으면 저장 경계 줄 3에서 나누고(300쪽), 없으면 통째로 실어 본문 바닥을 7px 넘긴다(299쪽). 그러나 정본이 302쪽이라 쪽수 조건 때문에 fixture 로 쓸 수 없다.

그래서 판정 수정은 검출 근거를 갖출 때까지 #8124 에 남긴다(별도 브랜치 fix/8124-stored-reset-field-controls 에 보존).

한계

🤖 Generated with Claude Code

@edwardkim edwardkim added bug Something isn't working layout 문서 레이아웃/페이지네이션: 표·그림 배치, float/anchor, 줄·행 높이, 겹침·클리핑 rendering SVG/Canvas/PDF 등 렌더 출력과 시각 표시: 그리기, 표시 누락, bbox, paint 정합성 labels Oct 21, 2026 — with ChatGPT Codex Connector
@edwardkim edwardkim added this to the v1.0.0 milestone Oct 21, 2026 — with ChatGPT Codex Connector
@planet6897 planet6897 changed the title fix(typeset): 필드 표시와 경계 뒤 조각의 용지 기준 글 앞/뒤 개체는 문단 안 저장 쪽 경계를 막지 않는다 (#8124) fix(typeset): 앵커 문단도 자기 쪽·종이 기준 밴드 아래에서 시작하고, 필드·뒤 조각 글 앞/뒤 개체는 저장 쪽 경계를 막지 않는다 (#8124) Oct 23, 2026
@planet6897
planet6897 force-pushed the fix/stored-reset-field-group-controls branch from 4e539bb to 3d21878 Compare October 23, 2026 22:08
planet6897 and others added 2 commits October 24, 2026 07:59
한/글은 쪽·종이 기준 위아래 배치 개체를 가진 문단의 첫 줄도 그 밴드를 피해 밴드 아래에
놓는다(stored_reset_float 입력: 구역 첫 빈 문단 vpos 30915 = 사각형 하단). edwardkim#7696 은 개체를
방출한 뒤에 밴드를 등록해 앵커 문단은 밴드 위에 남고 뒤 문단만 밀었다. 쪽 vpos 기준도 그
문단 vpos 로 잡혀 본문 전체가 정본보다 줄 하나(21.3px) 위에 그려졌고, 저장 줄과 흐름의 축이
어긋나 P 를 줄 3에서 나눴다(정본 줄 2).

- 밴드는 흐름과 무관한 절대 위치이므로 문단 fit 전에 그 문단 소유 밴드를 등록한다. 밴드
  아래에서 첫 줄이 단에 들어갈 때만 등록해, 못 들어가는 경우의 쪽 소속(edwardkim#7696 spill)은 그대로다.
- 단 첫 문단이 밴드에 밀리면 그 문단 vpos 로 잡은 쪽 기준을 민 거리만큼 되돌린다.

입력: 한/글 2020 이 열어 HWP 로 저장한 합성 입력 두 개(gen_field_float_reset.py, FILL=20, 구역
첫 빈 문단의 용지 기준 자리차지 사각형)와 Print PDF. 대조군 _plain 은 필드·글 앞 개체가 없다.

회귀 tests/cases/stored_reset_field_float_suffix.rs (devel d9fd85e 에서 둘 다 FAIL, 수정 후 PASS):
- section_first_paragraph_starts_below_its_own_paper_band: pi=1 이 A 하단 + pi=0 저장 줄 한 칸
- paragraph_after_section_paper_band_splits_at_stored_line: P 가 정본처럼 줄 2에서 나뉜다

이 입력은 필드·경계 뒤 개체가 저장 경계 수용을 막는 판정(edwardkim#8124)을 검출하지 않는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
base devel d9fd85e 와 code head 9c8499c 의 Native·fresh WASM review/overlay 와 전 쪽
silhouette TSV 를 두 fixture 에 대해 다시 산출했다. 판정 수정을 뺀 새 code head 로 교체한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@planet6897
planet6897 force-pushed the fix/stored-reset-field-group-controls branch from 3d21878 to c961778 Compare October 23, 2026 23:46
@planet6897 planet6897 changed the title fix(typeset): 앵커 문단도 자기 쪽·종이 기준 밴드 아래에서 시작하고, 필드·뒤 조각 글 앞/뒤 개체는 저장 쪽 경계를 막지 않는다 (#8124) fix(typeset): 앵커 문단도 자기 쪽·종이 기준 자리차지 밴드 아래에서 시작한다 (#8186) Oct 23, 2026
@jangster77
jangster77 self-requested a review October 24, 2026 07:24
@planet6897

Copy link
Copy Markdown
Contributor Author

devel 에 이미 반영되어 닫습니다

@jangster77 검토 요청을 드렸던 PR 인데, #8191 이후 최신 devel 이 같은 결함을 다른 방식으로 이미 고쳐 닫습니다.

회귀 검사 — 이 PR 의 코드 없이 upstream/devel 9418ed0c7 에 이 PR 의 검사·표본만 얹어 실행하면 둘 다 통과합니다.

회귀 검사 devel 9418ed0c7
stored_reset_field_float_suffix::section_first_paragraph_starts_below_its_own_paper_band 통과
stored_reset_field_float_suffix::paragraph_after_section_paper_band_splits_at_stored_line 통과

Visual Sweep (raw 실루엣, --compat 2022, Native / fresh WASM, devel 9418ed0c7 새 빌드)

입력 · 쪽 이 PR 의 base 이 PR head devel 9418ed0c7
field_float_reset.hwp p1 97.49 99.94 / 99.95 100.00 / 100.00
field_float_reset.hwp p2 97.14 99.99 / 99.98 100.00 / 100.00
field_float_reset_plain.hwp p1 97.49 99.94 / 99.95 100.00 / 100.00
field_float_reset_plain.hwp p2 65.16 99.80 / 99.79 100.00 / 100.00

쪽수는 두 입력 모두 2 = 한/글 2020 Print 2 입니다.

devel 은 이 PR 의 «앵커 문단이 자기 밴드를 미리 등록» 대신, 빈 문단의 저장 vpos 가 자기 쪽·종이 기준 밴드 하단과 같으면 그 자리를 원점으로 받는 방식(float_placement 의 밴드 증거)으로 같은 결과를 냅니다. 같은 결함에 두 번째 메커니즘을 얹지 않도록 이 PR 은 닫습니다. 검사·표본·Print PDF 는 브랜치 fix/stored-reset-field-group-controls 에 남아 있습니다.

#8186 은 이 PR 로 닫히지 않으므로 이슈에서 따로 정리하겠습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working layout 문서 레이아웃/페이지네이션: 표·그림 배치, float/anchor, 줄·행 높이, 겹침·클리핑 rendering SVG/Canvas/PDF 등 렌더 출력과 시각 표시: 그리기, 표시 누락, bbox, paint 정합성

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants