Skip to content

Task #643: 페이지 분할 드리프트 정정 (5축 정합) — closes #643#644

Closed
planet6897 wants to merge 5 commits into
edwardkim:develfrom
planet6897:task643-pagination-drift-fix
Closed

Task #643: 페이지 분할 드리프트 정정 (5축 정합) — closes #643#644
planet6897 wants to merge 5 commits into
edwardkim:develfrom
planet6897:task643-pagination-drift-fix

Conversation

@planet6897
Copy link
Copy Markdown
Contributor

본질

`samples/2022년 국립국어원 업무계획.hwp` 의 두 케이스로 발견된 누적 드리프트 모델 을 5축으로 분해하여 좁은 정정.

케이스 1 (page 6)

pi=80 (' 및 점자 해당 분야 전문인력 확보 어려움') 마지막 줄이 페이지 6 → 7 로 부당 분리.

케이스 2 (page 3)

pi=39 ('국어사전 정보보완심의회 운영을 통한 국어사전 정보 수정 및 보완') 가 페이지 3 → 4 로 부당 분리.

Root Cause (5축 누적 드리프트)

위치 증상
1 `pagination/engine.rs:846-852` fit 루프 마지막 줄의 트레일링 line_spacing 까지 누적 → 잔여 공간 산정 왜곡
2 `typeset.rs:876` 안전마진 축 1 의 band-aid 였으나 본 케이스 fit 결정 차단
3 `layout.rs:1521` VPOS_CORR backward 1.0px 만 허용 → 누적 layout drift 회복 불가
4 `layout.rs:1504` VPOS_CORR end_y sb_N 미차감 → layout 의 sb_N 추가와 합쳐져 line 0 위치 시프트
5 `typeset.rs:566` Task #404 vpos_end para_h_px 누적으로 vpos_end 산정 → 트레일링 ls 포함하여 ~10 HU 과대 → vpos_overflow 오판정

핵심 통찰

  • HWP: `vpos_(N+1) - vpos_N = lh_total + ls_total + sa_N + sb_(N+1)`
  • Layout: y_advance per pi = `sb_N + lh_total + ls_total`
  • → `sb_N ≠ sb_(N+1)` (예: 빈 문단 sb=0 인접) 시 차이 누적

수정

1. pagination fit 산식 (Stage 2)

fit 루프의 마지막 줄은 lh-only 적용 (트레일링 ls 제외).

2. LAYOUT_DRIFT_SAFETY_PX 축소 (Stage 3)

10 → 4px. 축 1 정정 후 보수적 마진 축소 가능.

3. VPOS_CORR 백워드 허용폭 확장 (Stage 3)

1.0 → 8.0px. 문단 사이 trailing line_spacing 영역 내에서 안전 백워드 보정.

4. VPOS_CORR end_y sb 차감 (Stage 3)

vpos_end 에서 curr_sb 사전 차감 → layout 의 sb 추가와 정합.

5. Task #404 vpos_end 산식 정정 (후속)

`para.line_segs.last()` 의 `vpos + line_height` 직접 사용 (트레일링 ls 자연 제외).

검증

회귀 테스트 (1221 / 1221 통과)

  • `tests/issue_643.rs` (신규): 본 케이스 (RED → GREEN) ✅
  • `task554_no_regression_2022_kuglip`: 페이지 수 40 → 35 (의도된 정정, HWP/PDF 정합)
  • `issue_147_aift_page3` golden SVG: 본문 y 좌표 -6.67px 시프트 정정 — UPDATE_GOLDEN
  • `test_544_passage_box_coords_match_pdf_p4`: 통과 (layout trailing_ls 정책 변경 없음)

PDF 정합 검증

  • `samples/2022년 국립국어원 업무계획.pdf` 와 비교
  • body page 1 (PDF "- 1 -") 마지막 항목 = pi=39 ✓
  • body page 7 (PDF "- 7 -") 마지막 항목 = pi=80 fits ✓

페이지 수 변화

`2022년 국립국어원 업무계획.hwp`: 40 → 35 페이지 (HWP/PDF 원본 정합 회복).

잔존 사항

LAYOUT_OVERFLOW 진단 메시지 ~9px 잔존 (paragraph y_out 기준, visible content fits). `record_overflow` 는 진단 기록만 수행, 렌더링 액션 없음. 추후 LAYOUT_OVERFLOW 임계 정책 통합 시 재검토 권장.

산출물

  • 코드: `src/renderer/pagination/engine.rs`, `src/renderer/typeset.rs`, `src/renderer/layout.rs`
  • 테스트: `tests/issue_643.rs` (신규), `tests/issue_554.rs` (갱신), `tests/golden_svg/issue-147/aift-page3.svg` (갱신)
  • 문서: `mydocs/plans/task_m100_643.md`, `task_m100_643_impl.md`, `mydocs/report/task_m100_643_report.md`
  • 커밋 4개

Test plan

  • cargo test --release (1221/1221 통과)
  • Native build (cargo build --release)
  • WASM build (docker compose run --rm wasm)
  • 본 케이스 시각 판정 (rhwp-studio dev server 에서 페이지 3, 6 확인)
  • 광범위 fixture sweep (메인테이너 환경)

closes #643

planet6897 and others added 5 commits May 8, 2026 12:07
본 케이스: samples/2022년 국립국어원 업무계획.hwp 6페이지 마지막 줄
(' 및 점자 해당 분야 전문인력 확보 어려움') 이 다음 페이지로 부당
분리되던 회귀를 정정. HWP 원본 정합 회복.

Root cause 4축:
1. pagination/engine.rs: fit 산식이 마지막 줄의 트레일링 line_spacing
   을 누적 → 잔여 공간 산정 왜곡 (+12-13 HU/문단)
2. typeset.rs: LAYOUT_DRIFT_SAFETY_PX=10px band-aid 가 fit 정정 후 과함
3. layout.rs VPOS_CORR: 백워드 보정 차단 (1.0px) 으로 누적 layout
   drift 회복 불가능
4. layout.rs VPOS_CORR end_y: sb_N 미차감 → layout 의 sb_N 추가와
   합쳐져 line 0 위치가 sb_N 만큼 아래로 시프트

수정:
- pagination/engine.rs:846-867: fit 루프 + part_line_height 산식
  마지막 줄 lh-only 적용 (트레일링 ls 제외)
- typeset.rs:876: LAYOUT_DRIFT_SAFETY_PX 10 → 4 축소
- layout.rs:1504-1521: VPOS_CORR 백워드 허용 1.0 → 8.0px,
  end_y 산식에서 curr_sb 차감

회귀 검증:
- 1221 테스트 통과 (회귀 0)
- task554_no_regression_2022_kuglip: 페이지 수 40 → 38 (의도된 정정,
  본 케이스 fits + 후속 압축으로 HWP 원본 정합)
- issue_147_aift_page3 golden SVG: 본문 y 좌표 -6.67px 시프트 정정
  (pi 누적 sb 드리프트 해소) — UPDATE_GOLDEN

잔존 사항:
- LAYOUT_OVERFLOW 진단 메시지 9.7px 남음 (paragraph y_out 기준,
  실제 visible content line bottom = 1025.7 ≤ body 1028.0 fits).
  진단 메시지는 record_overflow 로 기록만, 액션 없음.
4축 드리프트 누적 모델 분해 + 좁은 정정으로 HWP 원본 정합 회복.
1221 테스트 통과 (회귀 0). 페이지 수 40→38 (의도된 정정).
잔존 LAYOUT_OVERFLOW 진단 메시지 (trailing ls 영역) 는 후속 이슈 권장.
본 케이스: samples/2022년 국립국어원 업무계획.hwp 페이지 3 (body page 1)
마지막 항목 pi=39 ('국어사전 정보보완심의회 운영을 통한 국어사전 정보 수정
및 보완') 가 부당하게 다음 페이지로 분리되던 회귀를 정정.

Root cause:
typeset.rs:566 의 Task edwardkim#404 heading-orphan 가드가 para_h_px 누적 (트레일링
line_spacing 포함) 으로 vpos_end 산정 → ~10 HU 과대 → vpos_overflow 오판정.
HWP 시멘틱은 페이지 끝에서 lh 만 fit 검사 (트레일링 ls 미적용).

수정:
- typeset.rs:566 vpos_end 산식: para.line_segs.last() 의 vpos+lh 직접 사용
  (트레일링 ls 자연 제외).

회귀 검증:
- 1221 테스트 통과 (회귀 0)
- task554_no_regression_2022_kuglip: 페이지 수 38 → 35 (의도된 정정)
- tests/issue_643.rs: 페이지 번호 의존성 제거 (페이지 변동에 강건)

본 케이스 PDF 정합 (body page 1 마지막 항목 pi=39) 회복.
stream/devel 위로 rebase 한 결과, Task edwardkim#643 의 페이지 분할 드리프트
정정으로 인한 좌표 시프트가 두 테스트와 충돌:

1. tests/issue_598_footnote_marker_nav.rs:60
   - samples/footnote-01.hwp 두 번째 본문 각주 마커 y 좌표
   - bbox y: 694.3 → 660.9 (-33.4px)
   - 테스트 hit_test y: 698.0 → 670.0 (새 bbox 내 중앙)

2. tests/golden_svg/issue-147/aift-page3.svg
   - aift.hwp page 3 본문 y -6.67px 시프트 정정 결과 갱신
   - UPDATE_GOLDEN=1 으로 재생성 (post-Task edwardkim#630 + post-Task edwardkim#643)

cargo test --release: 1221+ 테스트 전부 통과 (회귀 0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@planet6897
Copy link
Copy Markdown
Contributor Author

연관 PR (samples/2022년 국립국어원 업무계획.hwp)

본 PR 은 samples/2022년 국립국어원 업무계획.hwp 의 페이지 분할 결함 정정 시리즈 중 첫 번째.

순서 PR Issue 본질 결함 위치
1 #644 (본 PR) #643 페이지 분할 드리프트 5축 정합 6 페이지 마지막 줄 (40→35 페이지로 정정)
2 #714 #712 u32 음수 vert_offset 게이트 31 페이지 상단 12x5 표 침범
3 #715 #713 인트라-로우 분할 orphan(<25px) 가드 31 페이지 하단 row 8 sliver 분할

권장 merge 순서: #644#714#715. 각 PR 은 베이스가 stream/devel 이며 상호 conflict 0 (merge-tree 점검 완료).

통합 검증: stream/devel + 3 PR 통합 빌드에서 cargo test --release 1252 passed, 0 failed.

edwardkim added a commit that referenced this pull request May 8, 2026
closes #643

5 commits 단계별 보존 (옵션 B):
- 016b417 Stage 0/1: 수행/구현 계획서 + RED 테스트
- 247203e Stage 2-4: 4축 정정 (pagination fit / SAFETY_PX / VPOS_CORR)
- 338fe56 Stage 5: 최종 보고서
- 2345d39 후속: Task #404 vpos_end 트레일링 ls 제외 (축 5)
- c1129da 후속: rebase + golden SVG 정합

본 환경 검증:
- 1221 테스트 ALL PASS (failed 0건)
- task554 sweep 12/12 ✅
- 페이지 수 정합: 40 → 35 (HWP/PDF 정합 회복)

PR: #644
컨트리뷰터: @planet6897 (12번째 사이클)
edwardkim added a commit that referenced this pull request May 8, 2026
PR #644 (Task #643): 페이지 분할 드리프트 정정 (5축 정합) — closes #643
- merge commit: 42bb794 (옵션 B — 5 commits 단계별 보존)
- 결정적 검증 1221 테스트 ALL PASS
- 페이지 수 정합 회복: 2022년 국립국어원 업무계획.hwp 40 → 35
- WASM 빌드 + 작업지시자 시각 검증 통과

별건 결함 분리:
- Issue #716 신규 — samples/20250130-hongbo.hwp page 1 LAYOUT_OVERFLOW_DRAW
- devel 과 PR-merged devel 의 page 1 SVG md5 동일 → PR #644 도입 회귀 아님
- Task #332 Stage 4b 잔존 영역 (Stage 5 미수행)

산출물:
- mydocs/pr/archives/pr_644_review.md
- mydocs/pr/archives/pr_644_report.md
- mydocs/orders/20260508.md 갱신
@edwardkim
Copy link
Copy Markdown
Owner

@planet6897 님 12번째 사이클 PR 감사합니다.

본 환경 검증 결과:

결정적 검증 (1221 테스트): ALL PASS

  • tests/issue_643.rs (신규) ✅ — pi=80 page 6 line 1 정착
  • task554 광범위 sweep 12/12 ✅
  • tests/svg_snapshot.rs 7/7 ✅ (issue_147 골든 갱신 적용)
  • tests/issue_598_footnote_marker_nav.rs 4/4 ✅

페이지 수 정합 회복: 2022년 국립국어원 업무계획.hwp 40 → 35 페이지 (HWP/PDF 원본 정합).

5축 분해의 본질: sb_N ≠ sb_(N+1) 누적 드리프트 진단 정확. HWP 의 vpos_(N+1) - vpos_N = lh_total + ls_total + sa_N + sb_(N+1) 인코딩과 본 프로젝트 layout 의 sb_N + lh_total + ls_total y_advance 산식의 정합 정정.

처리: 옵션 B — 5 commits 단계별 보존 머지 + WASM 빌드 + 메인테이너 시각 판정 게이트 통과.

  • merge commit: 42bb7946
  • devel push: 1185eb98..21c118cf

별건 결함 분리: 메인테이너 시각 검증 영역에서 samples/20250130-hongbo.hwp page 1 마지막 줄 LAYOUT_OVERFLOW_DRAW (line=2 y=1048.2 overflow=20.1px) 발견. 본 PR 머지 전후의 page 1 SVG md5 동일 (ab0de6c2e9ecc015402e7acfa091fa02) → 본 PR 도입 회귀 아닌 devel 기존 결함 (Task #332 Stage 4b 잔존 영역, Stage 5 미수행). #716 별도 등록.

처리 보고서: mydocs/pr/archives/pr_644_report.md

closes #643

@edwardkim edwardkim closed this May 8, 2026
edwardkim added a commit that referenced this pull request May 9, 2026
본질: HwpUnit=u32 영역의 signed 캐스트 누락 결함.

`vertical_offset` 음수 (예: -1796 HU) 의 unsigned 비트표현 = 0xFFFFF8FC =
4294965500u32. `> 0` 게이트가 unsigned 양수로 통과 → 후속 `as i32` 캐스트
에서 음수 적용 → 표가 위로 점프, 직전 인라인 표 영역 침범.

비-Partial 경로 (table_layout.rs:1069+) 에는 `raw_y.max(y_start)` 클램프
영역으로 음수 무력화. Partial 경로 (table_partial.rs:59-78) 에는 클램프
부재 영역 → 결함 노출.

영향 샘플: samples/2022년 국립국어원 업무계획.hwp 영역의 12x5 일정 표 영역
(작업지시자 안내 영역의 페이지 31, 본 환경 영역 35 페이지 영역의 동적 페이지
탐색):
- pi=585: 1x3 인라인 TAC 제목 표 ("붙임 / / 과제별 추진일정")
- pi=586: 12x5 일정 표 (vert=문단 -1796 HU 음수)
- 결함: pi=586 외곽 상단이 pi=585 안쪽으로 ~15.94 px 침범
- 정정 후: 침범 0 px (PDF 권위 정합)

정정 (signed 비교 14 라인):
- src/renderer/layout/table_partial.rs:59-78 (Partial 경로, 본질):
    let vert_off_signed = table.common.vertical_offset as i32;
    && vert_off_signed > 0
- src/renderer/layout.rs:2687+ (비-Partial 경로 게이트 동기):
    && (t.common.vertical_offset as i32) > 0

영향 좁힘 (feedback_hancom_compat_specific_over_general):
- is_continuation=true 분할 표 연결 페이지 영역 무영향
- vertical_offset >= 0 영역 (signed 양수/0) 무영향
- 비-TopAndBottom wrap / TAC 표 영역 무관

회귀 가드 (tests/issue_712.rs +88 LOC, 신규):
- 동적 페이지 탐색 영역 — 페이지네이션 변동 영역 견고 (PR #644 / PR #711
  머지 영역 자동 적응)
- pi=586 외곽 상단 ≥ pi=585 외곽 하단 (0.5 px 허용 오차)

검증:
- cargo test --release: lib 1173 + 통합 ALL GREEN, failed 0
- cargo test --release --test issue_712: 1 PASS (회귀 가드)
- cargo test --release --test svg_snapshot: 8/8 (form-002 PR #706 영역 보존)
- cargo test --release test_705: 6/6 (PR #711 영역 보존)
- cargo test --release test_634: 8/8 (가드 갱신 후 보존)
- cargo clippy --release: 신규 경고 0
- 광범위 sweep 7 fixture / 170 페이지 / 회귀 0

Closes #712

Co-Authored-By: Jaeook Ryu <jaeook.ryu@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants