fix: 단일-run RIGHT + leader 인라인 탭 cell right inner 정렬 (Task #874 후속)#1021
fix: 단일-run RIGHT + leader 인라인 탭 cell right inner 정렬 (Task #874 후속)#1021HaimLee-4869 wants to merge 1 commit into
Conversation
후속) Task edwardkim#874 (cross-run RIGHT+leader 의 text_start_offset 미포함 정렬 보정) 의 후속 영역으로, 단일-run 케이스 — \t 가 한 run 안에 있고 그 뒤에 content 가 같은 run 으로 이어지는 케이스 (예: 목차 한 줄 "Ⅰ. 사업개요\t...3") — 의 cell right inner 미달 정렬을 보정한다. 본질: - 인라인 (2, _) RIGHT + leader 분기의 단일-run path 는 body_right_legacy (= available_width - line_x_offset) 사용 → text_start_offset 미포함 으로 cell right inner (= text_start_offset + available_width) 까지 미달. - 또한 seg_w 가 leading space 를 skip → digit right edge 가 cell right inner 보다 좌측으로 정렬 미달. - Task edwardkim#874 가 도입한 cross-run path (override_to_right + body_right_text_rel + right_tab_block_width_override) 는 단일-run 케이스를 cover 하지 않음 (그 경로는 다음 run 으로 carry-over 된 후만 활성). Fix (text_measurement.rs): - 두 measurer (EmbeddedTextMeasurer + WasmTextMeasurer) 의 (2, _) RIGHT + leader 분기를 분리: * if fill_low != 0 안에서 has_content_after 검사 * \t 뒤 content 가 있는 단일-run → cell_right_run_rel (= text_start_offset + available_width - line_x_offset) 정렬 + seg_w_full (i+1 부터, leading space 포함) 측정 * \t 뒤 trailing space / 끝만 있으면 (cross-run 직전) → 원본 path 유지 (body_right_legacy - seg_w). 다음 run 의 pending_right_tab 분기가 처리. ★ native + WASM 두 path 정책: rhwp 의 텍스트 측정/배치는 native CLI 의 EmbeddedTextMeasurer 와 rhwp-studio Canvas 의 WasmTextMeasurer 두 구현으로 병존하므로 (rhwp-studio Canvas 시각 정합을 위해) 양쪽 동시 fix 가 필수. 회귀 영향: - cross-run RIGHT+leader path (Task edwardkim#874) 영향 0 — 경로 분기 보존 - RIGHT (no leader) 분기 영향 0 — (2, _) 별도 분기 보존 - LEFT/CENTER/DECIMAL 분기 영향 0 검증 환경: - Linux + cargo + wasm-pack (Docker 미사용, 로컬 네이티브) - 한컴오피스 2024 한글 + Windows + 한컴 폰트 설치 (시각 정합 비교) 회귀 검증: - cargo check --lib: OK (10.20s) - cargo check --target wasm32-unknown-unknown --lib: OK (23.33s) - cargo test --lib: 1307 passed, 0 failed, 2 ignored (57.39s) - cargo clippy --lib -- -D warnings: 0건 - cargo test --test svg_snapshot: 8 passed (UPDATE_GOLDEN=1 갱신) - wasm-pack build --target web --dev: OK (15s) Golden 갱신 (한 가지 패턴): - tests/golden_svg/issue-267/ktx-toc-page.svg - 14 lines 변경, 모두 text element 의 x 속성 (좌표) 만 — y/글자/폰트/색상 변경 0 - 페이지번호 4개 (8 / 16 / 20 / 24) 의 x 좌표가 10px 좌측 이동 - Leader 점선 끝 (x2) 영역 보존 → 점선-페이지번호 gap 15px → 5px 정합 - 다른 6개 golden (form-002, issue-147, issue-157, issue-617, issue-677, table-text) 영향 0 본가 PDF baseline 정합: - pdf/KTX-2022.pdf 페이지 2 (한글 2022 편집기 출력) 시각 비교 결과: * 페이지번호 우측 끝이 모두 cell right inner 에 정렬 (RIGHT 정합) * Leader 점선이 페이지번호 직전까지 도달 (점선-숫자 gap ~1-3px) * 단일/두자리 페이지번호 우측 끝이 동일 x — RIGHT 정합 - 새 SVG (fix 후) 영역 영역 정합 방향 일치, 기존 SVG (fix 전) 는 overshoot. 시각 검증: - 사용자 시각 검증 OK (KTX.hwp + 본가 두 대상 파일 영역 4장 캡쳐) - 본가 PDF baseline 정합 확인 (Claude 영역 PDF 페이지 2 시각 비교) 관련: - Task edwardkim#874 (cross-run RIGHT+leader text_start_offset) - Issue edwardkim#977 (Skia replay 경로 outline number x 영역) — 본 PR 영역 밖, 좌측 정합 영역. 본 PR 은 우측 정합 (cell right inner) 영역. - PR edwardkim#980 (closed) — text_measurement.rs::compute_char_positions 의 native vs WASM 휴리스틱 통일 시도, 영역 별도. Co-Authored-By: Claude <noreply@anthropic.com>
|
@HaimLee-4869 님의 rhwp-collab 프로젝트를 보고 왔습니다. CRDT/OT 같은 분산 협업을 위해 CQRS 패턴으로 설계한 걸 정확하게 파악하고 작업하신 것에 칭찬을 드리고 싶습니다. crdt.js 구현에서 Lamport + Site ID Tombstone 방식을 선택한 점이 인상적이었습니다. |
…ht inner 정렬 @HaimLee-4869 (두 번째 기여) — KTX 목차 페이지번호(3/4/6/7/8/14/16/17/ 20/21/23/24/25/27 등) 우측 끝이 cell right inner 미달 + leader 점선-숫자 gap ~10px 초과 회귀 해소. text_measurement.rs 두 measurer(Embedded TextMeasurer + WasmTextMeasurer)에 (2, _) RIGHT+leader 단일-run + content 분기 추가 — cell_right_run_rel(=text_start_offset + available_width - line_x_offset) 정렬 + seg_w_full(leading space 포함). Task #874 cross-run path(pending_right_tab carry-over)와 보완 관계, scope 좁힘(has_content_after 검사, max(x) 보존). 옵션 A: 본질 커밋 cfb71fa cherry-pick (작성자 @HaimLee-4869 보존, KTX golden 4 블록 충돌 → source patch + UPDATE_GOLDEN 일괄 갱신 전략). 처리 중 PR #1020 회귀 CI 실패 발견 → hotfix 2회 push (issue_826 단언 정정 + fmt) 동반. 사고로 PR #1021 source 가 두 번째 hotfix(3ed8297)에 흡수 → 본 PR commit(7f879ab)은 KTX golden 정합으로 축소되었으나 원 의도(source + golden) 모두 devel 반영. 본 환경 검증: cargo test 1307 + svg_snapshot 8 + issue_826 4 + clippy -D + fmt 0 + WASM 4.83MB. sweep 9 fixture(KTX/table-vpos-01/sample16-hwp5/exam_kor/math/aift/biz_plan/복학원서/ mel-001) 전부 diff=0 입증. 작업지시자 "svg 골든을 교체해야 합니다" + 정량 입증으로 시각 판정 대체. native + WASM 양쪽 동시 fix (PR #900 패턴, feedback_image_renderer_paths_ separate 본질 정합). 첫 PR #1020 직후 두 번째 기여 — PR 본문 매우 충실 (Symptom 표 + Before/After 캡처 + Root cause + Fix + Wiki 정합 + 회귀 검증 + 관련 영역 분리).
|
옵션 A로 devel에 반영했습니다 (본질 커밋 cfb71fa cherry-pick, 작성자 메타데이터 보존). 검증:
본 PR 처리 중 직전 PR #1020의 회귀 CI 실패( native + WASM 두 measurer 동시 fix(PR #900 패턴) + Task #874 cross-run path와 보완 관계 설계가 견고합니다. 두 번째 기여도 PR 본문이 매우 충실(Symptom 표 + Before/After 캡처 + Root cause + Fix + Wiki 정합 + 회귀 검증 + 관련 영역 분리)했습니다. @HaimLee-4869 님 첫 PR #1020에 이어 견고한 후속 PR 감사합니다. |
@edwardkim 님 직접 머지해 주시고 rhwp-collab 프로젝트까지 살펴봐 주셔서 정말 감사합니다! 본가 Wiki와 Investigation PR 가이드가 PR 작성에 큰 도움이 되었습니다. rhwp-collab 은 교내 캡스톤 프로젝트 진행하면서 rhwp 본가를 열심히 공부한 결과물입니다. CQRS + Lamport timestamp + Site ID Tombstone 선택을 알아봐 주셔서 정말 기쁩니다. issue_826 hotfix 도 처리해 주셔서 감사합니다. 나머지 PR 들도 차근차근 진행하겠습니다. OVERLAP 10~12 후속 (#1023) 과 정공법 후보들도 캡스톤 마감 (2026-06-15) 후 여유 있을 때 살펴보고 싶습니다! 감사합니다. |
|
PR #1026 (좁은 구두점 polished by @HaimLee-4869, 세 번째 기여) 는 머지하지 않음. 본 PR H2 분기 순서 변경이 PR #1021 (단일-run RIGHT + leader) 의 KTX 목차 cell right inner 정합을 회귀 — 페이지번호 x="689.76" → "699.76" (+10px). 컨트리뷰터에게 PR #1021 KTX 동작 보존 + 회귀 가드 fixture 추가 요청. PR OPEN 유지. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… 4 hunk 복원 PR #1003 (closes #990) 의 cherry-pick `--theirs` 충돌 해소가 PR #1011 (closes #1006) 의 PageBorderBasis 통합 contract 를 PR #987 시절 attr 비트 해석으로 무심코 revert. HWP3 native (attr=0) 만 paper_based=false 로 판정되어 외곽선이 body-edge 로 좁아진 시각 회귀 발생. Bisect 단언 (border_top y): - 850cfb5 (PR #1011): 17.88 (paper-edge, 기준선) - 71aedda (PR #1015): 17.88 - 84246b2 (PR #1018): 17.88 - 27c05d5 (PR #1020): 17.88 - b5d3834 (PR #1021): 17.88 - c2024ec (PR #1003): 55.64 ← 회귀 도입 - 65c8e69 (devel HEAD): 55.64 Fix: src/renderer/layout.rs 4 hunk 복원 - 변경 A: page_number_baseline_y() — (attr & 0x01) → matches!(basis, PaperBased) - 변경 B: build_page_borders() — 동일 + 주석 + 디버그 로그 (bit1/bit2/footer_inside) - 변경 C: footer_inside clip 복원 — 페이지 번호 외곽선 바깥 위치 (PR #1011) - 변경 D: `(bx, mut by, bw, mut bh)` — footer clip 의 by/bh 수정 위함 Parser 측 PR #1011 변경 (basis=PaperBased 주입) 은 PR #1003 cherry-pick 시 보존됨. fix 는 renderer (layout.rs) 한정 단일 파일. 검증 (Stage 2 별도 보고): - 3 포맷 paper_based=true 단언 (RHWP_DEBUG_PAGE_BORDER) - HWP3 sample16 border_top y=17.88 복원 - HWP5/HWPX 변환본 무변동 (17.88 유지) - cargo test --release --lib 1307 passed - cargo clippy --release --lib -- -D warnings clean - cargo fmt --check clean Refs #1029 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…류 + native/WASM 동기화 @HaimLee-4869 4번째 기여 (1차 옵션 B 보류 후 KTX 회귀 가드 + rebase 후 재제출). 휴먼명조/HY중고딕/HY신명조/HY견명조 폰트의 좁은 구두점 (U+2018 ', U+2019 ', U+2027 ‧) 폭이 한컴 대비 ~4px 과대 문제 fix. 폰트 메트릭 DB fullwidth 잘못 기록 + WASM path 동기화 누락이 본질. 본질 (3 hunks, 모두 src/renderer/layout/text_measurement.rs): - H1. is_narrow_punctuation 확장 — DB 미수록 폴백 path 정정 (U+2018, U+2019, U+2027 추가). - H2. measure_char_width_embedded narrow override — DB fullwidth 정정 (em/2 = 0.5em → 0.3em, glyph_w >= em_size 조건으로 정상 DB 값 영향 0). - H3. wasm_internals::measure_char_width_hwp narrow 분기 추가 — WASM path 동기화 (native EmbeddedTextMeasurer 와 일관). ★ native + WASM 두 path 정책 (본가 PR #900 패턴 정합, PR #1021 영역 확정): rhwp 의 문자 폭 측정은 native CLI (EmbeddedTextMeasurer) 와 rhwp-studio Canvas (WasmTextMeasurer 영역 wasm_internals::measure_char_width_hwp) 두 구현으로 병존. char/layout fix 는 두 path 동시 점검 필수. 재제출 변경 (PR 본문 "C8+C9 소스 로직 변경 없음"): - 최신 devel rebase (bbd38e8, PR #1033 머지 후 base) - **KTX 회귀 가드 신규** tests/issue_874_ktx_toc_page_number_right_align.rs (98 lines) — render_page_svg_native SVG 의 페이지번호 digit max_x < 695.0 단언. 정상 ≤690.8 / 회귀 시 ≈699.76. PR #1021 정합 영구화. - golden 갱신 (issue-157 굴림체 + issue-617 HY신명조). issue-267 KTX golden 보존 (1차 검토 시 변경됐던 영역, 본 재제출에서 정정). 검증 (본 환경): - cargo test --release --lib 1319 passed + 통합 모두 passed - cargo test --release --test issue_874_ktx_toc_page_number_right_align **1 passed** (페이지번호 정합 정량 입증) - cargo test --release --test svg_snapshot **8/8 passed** (issue_267_ktx_toc_page 포함) — KTX golden 무회귀 - cargo fmt --all --check clean - sweep 7 fixtures (550 SVGs): 32 diff = 모두 본 PR 본질 (KTX 9 휴먼명조 / hwp3-sample16-hwp5 1 + exam_kor 17 + aift 5 HY신명조 narrow 정합) / 페이지 수 회귀 부재 / 함초롬바탕 / Pretendard / 맑은 고딕 무영향 - KTX page 002 (목차) 페이지번호 좌표 BEFORE = AFTER (1차 회귀 부재) - WASM Docker 빌드 4.89MB + rhwp-studio 동기화 - 작업지시자 시각 판정 통과 (KTX 페이지번호 정합 유지 + 휴먼명조 narrow 정합 한컴 정답지 정합) 1차 검토 회귀 원인 재정정: - 1차 보고서 (mydocs/pr/archives/pr_1026_report.md) 의 "H2 분기 순서 변경" 추정이 잘못된 분석으로 판명. 진짜 원인은 1차 cherry-pick + UPDATE_GOLDEN 일괄 갱신 (issue-267 KTX golden 도 함께 변경) 또는 통째-파일 교체로 PR #1021 코드 유실 (KTX 회귀 가드 코드 본문 명시). - 본 PR 재제출에서 KTX 회귀 가드 (issue_874) 영구화 + issue-267 golden 보존으로 1차 결함 정정. 회귀 영향 (의도적 분리): - 함초롬바탕 / Pretendard / 맑은 고딕: DB narrow 정확 기록, 영향 0 - U+00B7 ('·' Middle Dot): 본가 Task #257 + #630 영역 이미 처리. Task #630 "DB 전각 측정 유지 결정" trade-off 충돌 없음 - 다른 punctuation (콤마, 마침표, 콜론 등): 분기 조건 영향 0 별도 PR 권장 영역 (PR 본문 명시): - U+00B7 본문 영역 시각 NG: Task #630 context-aware 처리 후속 - U+2014 / U+2016 등 다른 General Punctuation block - HY family fallback 메트릭 보정 (별도 트랙) Refs PR #1021 Co-Authored-By: HaimLee-4869 <j_haim4869@naver.com>
…osed) PR #1026 (재제출, Refs PR #1021) 머지 후속 처리: - mydocs/pr/archives/pr_1026_review_v2.md (재검토 문서 archives 이동) - mydocs/orders/20260521.md (2026-05-21 PR #1026 entry) - rhwp-studio/public/{rhwp.d.ts,rhwp.js,rhwp_bg.wasm} (WASM 4.89MB 동기화) @HaimLee-4869 1차 보류 PR 재제출 모범 사례 — KTX 회귀 가드 영구화로 1차 검토 결함 정정 + native/WASM 두 path 동기화. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
목차 페이지의 단일-run RIGHT+leader 인라인 탭에서 페이지번호가 cell right inner 까지 미달하는 정렬 문제를 보정. Task #874 (cross-run 영역) 후속 영역.
Symptom
KTX.hwp 목차 페이지에서 페이지번호 (3, 4, 6, 7, 8, 14, 16, 17, 20, 21, 23, 24, 25, 27 등) 의 우측 끝이 cell right inner 까지 미달하고, leader 점선과 페이지번호 사이 gap 이 한컴 정답지 보다 약 10px 더 큼.
Before / After — 본가 sample (KTX.hwp 목차)
추가 검증 영역 — 사용자 작업 영역 (도청 공문 목차)
Root cause
인라인
(2, _)RIGHT + leader 분기의 단일-run path 는body_right_legacy(=available_width - line_x_offset) 사용 →text_start_offset미포함 으로 cell right inner (=text_start_offset + available_width) 까지 미달. 또한seg_w가 leading space 를 skip → digit right edge 가 cell right inner 보다 좌측으로 정렬 미달.Task #874 가 도입한 cross-run path (
override_to_right+body_right_text_rel+right_tab_block_width_override) 는 단일-run 케이스를 cover 하지 않음 (그 경로는 다음 run 으로 carry-over 된 후만 활성).Fix
text_measurement.rs의 두 measurer (EmbeddedTextMeasurer+WasmTextMeasurer) 의(2, _)RIGHT + leader 분기를 분리:if fill_low != 0안에서has_content_after검사\t뒤 content 가 있는 단일-run →cell_right_run_rel(=text_start_offset + available_width - line_x_offset) 정렬 +seg_w_full(i+1 부터, leading space 포함) 측정\t뒤 trailing space / 끝만 있으면 (cross-run 직전) → 원본 path 유지 (body_right_legacy - seg_w). 다음 run 의pending_right_tab분기가 처리.★ native + WASM 두 path 정책 (본가 PR #900 패턴 정합)
rhwp 의 텍스트 측정/배치는 native CLI 의
EmbeddedTextMeasurer와 rhwp-studio Canvas 의WasmTextMeasurer두 구현으로 병존하므로 (rhwp-studio Canvas 시각 정합을 위해) 양쪽 동시 fix 가 필수. 본 PR 도 양쪽 동시 적용.본가 Wiki 정합
본 fix 영역은 본가 Wiki HWP Tab Leader Rendering 명세 영역과 본질 정합 — 외부 기여자 분석 영역 후속:
text_start_offset + available_widthfill_low != 0(leader 활성) 분기 영역pdf/KTX-2022.pdfp.2) 정합 확인 ✓검증 환경
pdf/KTX-2022.pdf페이지 2, 한글 2022 편집기 출력)회귀 검증
cargo check --libcargo check --target wasm32-unknown-unknown --libcargo test --libcargo clippy --lib -- -D warningscargo test --test svg_snapshotwasm-pack build --target web --devGolden 갱신 (한 가지 패턴)
tests/golden_svg/issue-267/ktx-toc-page.svgtextelement 의x속성 (좌표) 만 — y/글자/폰트/색상 변경 0x2) 영역 보존 → 점선-페이지번호 gap 15px → 5px 정합회귀 영향 (의도적 분리)
(2, _)별도 분기 보존관련 영역 (별도 영역)
text_start_offset도입. 본 PR 은 단일-run 후속 영역으로 정합.text_replay.rs의bbox.x영역으로 본 PR 의compute_char_positions영역과 분리.text_measurement.rs::compute_char_positions의 native vs WASM 휴리스틱 통일 시도. 영역 별도 — 본 PR 영역과 무관.