Task #290: cross-run 탭 감지가 inline_tabs 무시하여 좌측 탭이 우측 정렬로 오판정#292
Merged
Conversation
- 수행계획서 `task_m100_290.md`, 구현계획서 `task_m100_290_impl.md` - Stage 1 완료 보고서 `task_m100_290_stage1.md` - exam_math.hwp p.7 edwardkim#18 "수열" 문제: cross-run 탭 감지가 `composed.tab_extended` 를 무시하여 LEFT inline 탭이 `auto_tab_right` 폴스루로 RIGHT 탭으로 오판, 다음 run 이 우측 끝으로 역산 배치됨 - 근본 위치: `src/renderer/layout/paragraph_layout.rs:1213-1226` (render 측) + `:854-868` (est 측) - `ext[2]` 포맷 실증: hi byte = 탭 종류 enum+1 (1=LEFT, 2=RIGHT, 3=CENTER, 4=DECIMAL), lo byte = fill - inline_tab_cursor 도입 위치 결정, 옵션 A (TabDef 기반 위치) 유지 - 오늘할일 `20260424.md` 에 edwardkim#290 신규 등록 항목 추가
… + 단위 테스트 5건
- 신규 헬퍼 `resolve_last_tab_pending` (`paragraph_layout.rs`):
inline_tabs 가 `last_inline_idx` 를 커버하면 `ext[2] >> 8` 고바이트로 탭 종류 판정.
0/1(LEFT) → None (본 수정 핵심), 2/3(RIGHT/CENTER) → TabDef 기반 기존 경로.
- est 측 (`:840`) + render 측 (`:1198`) 의 cross-run 탭 감지 블록 2곳을 헬퍼 호출로 교체.
각 루프에 `inline_tab_cursor_*` 변수 도입, char_overlap continue 및 루프 말미에서
`run.text.chars().filter(|c| *c == '\t').count()` 만큼 증가.
- 단위 테스트 5건 (`task290_*`): LEFT→None, RIGHT→Some, CENTER→Some, 폴백 2건.
모두 pass. 전체 cargo test --lib 955 pass (기존 14 fail 은 선존재 cfb_writer).
- 스폿 검증: exam_math p.7 item 18 "수" 위치 290.9 → 109.8 (정상),
hwp-3.0-HWPML 저작권 RIGHT 케이스 회귀 없음 ("1" 우측 정렬 유지).
- 통합 테스트 `tests/tab_cross_run.rs` 신규: exam_math.hwp p.7 렌더 후
item 18 "수" 글리프 x < 200 px 검증. 1/1 pass.
- git worktree 로 baseline 생성 → 주요 샘플 전체 페이지 SVG diff:
* exam_math.hwp: 1/20 변경 (p.7 only, 의도된 item 18 수정)
* biz_plan.hwp: 0/6, exam_eng.hwp: 0/11, exam_kor.hwp: 0/25
* hwp-3.0-HWPML.hwp: 0/122 (RIGHT inline tab 회귀 없음)
* 총 184페이지 중 1페이지만 변경 (의도 100%)
- p.7 diff 14줄 모두 item 18 첫 줄 14글자 -181.11px 좌측 이동
- 시각 비교 PNG 3면 (before/after/pdf) 저장:
mydocs/working/task_m100_290_stage3/p7_{before,after,pdf}.png
→ AFTER 가 PDF 와 동일하게 "18. 수열 {a_n}이 모든 ..." 좌측 정렬
- 최종 결과 보고서 `task_m100_290_report.md`: 배경/원인/수정/검증/후속과제/교훈 5축 정리. - 오늘할일 `20260424.md`: "4. Task edwardkim#290" 섹션 신설 + 이슈 활동 표 종료로 이동. - 트러블슈팅 `tab_tac_overlap_142_159.md`: "후속 사건: edwardkim#290" 섹션 추가. edwardkim#142 교훈 ("같은 데이터 다른 경로 계산 시 동기화") 의 범위가 estimate_text_width vs compute_char_positions 에서 "run 내부 탭 처리 vs cross-run 탭 감지" 로 확장됨을 기록. - Stage 4 보고서 `task_m100_290_stage4.md`: 4단계 종료 + 검증 지표 총괄.
# Conflicts: # mydocs/orders/20260424.md
edwardkim
approved these changes
Apr 24, 2026
edwardkim
left a comment
Owner
There was a problem hiding this comment.
Approved. 🎉
@planet6897 님, 훌륭한 조사·수정입니다.
평가 포인트
- 임시 트레이스 RHWP_TRACE290 — 'pending_right_tab=Some((420.11,1)) → x_after=290.91' 전 경로를 숫자로 연결
- ext[2] 포맷 실증 — RIGHT 샘플 (hwp-3.0-HWPML 저작권\t1) 확보로 high/low 바이트 구조 검증
- #142 교훈 재적용 — 'resolve_last_tab_pending' 헬퍼 중앙화. 트러블슈팅 문서 확장 기록
- git worktree baseline diff — 184 페이지 byte-level 자동 검증 (1/184 의도 100%)
- 범위 의식적 제어 — inline_tabs RIGHT/CENTER 렌더 버그 발견해도 후속 이슈로 분리
메인테이너 검증
| 항목 | 결과 |
|---|---|
| cargo test --lib (merge 시뮬레이션) | ✅ 988 / 0 / 1 ignored |
| cargo test --test tab_cross_run | ✅ 1 / 0 (신규) |
| cargo test --test svg_snapshot | ✅ 6 / 0 |
| cargo clippy / wasm32 | ✅ clean |
| CI (원본) | ✅ SUCCESS |
처리 절차
- orders 문서 충돌 (Task #290 vs #288 섹션) 메인테이너 직접 해결
- planet6897/local/task290 에 push (bc6c46d..206e265)
- 재승인 후 admin merge
후속 관찰 (별도 이슈 등록 예정)
브라우저 WASM Canvas 경로(WasmTextMeasurer::estimate_text_width / compute_char_positions)에는 본 PR 수정이 도달하지 않음. SVG 경로는 paragraph_layout.rs 에서 고쳤지만 Canvas 경로는 text_measurement.rs 의 find_next_tab_stop 만 사용하여 동일한 'LEFT inline tab → auto_tab_right 폴스루 오판' 증상이 브라우저에서 재현. 별도 이슈로 등록해 핀셋 처리 예정.
본 PR 의 SVG 경로 수정은 의도대로 완결적 — admin merge 진행합니다.
edwardkim
added a commit
that referenced
this pull request
Apr 24, 2026
edwardkim
added a commit
that referenced
this pull request
Apr 24, 2026
…#290) - 작성자: @planet6897 (Task #290, PR #292) - Merge commit: 085beb0 (admin merge, orders 충돌 직접 해결) - 이슈 #290 CLOSED 처리 절차: - PR 브랜치에 origin/devel 머지 → orders 섹션 재배치 (#290 "## 6", #288 "## 7") - planet6897/local/task290 에 push (maintainerCanModify 허용) - 재승인 + admin merge 검증: - cargo test --lib: 988 passed / 0 failed / 1 ignored (+5 신규 task290) - cargo test --test tab_cross_run: 1 passed (신규) - svg_snapshot: 6 passed, clippy + wasm32 check: clean - CI (원본): 전부 SUCCESS - CLI SVG: p.7 #18 "수" glyph x=109.80 정상 후속 이슈 등록: - #296 (WASM Canvas 경로 inline_tabs 무시) — 본 PR의 Canvas 버전, 메인테이너 핀셋 처리 예정 별도 추적 중: - #291 (KTX.hwp 2단 TAC 표 회귀) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 24, 2026
PR #292 (#290) 머지 후 브라우저 검증에서 exam_math.hwp p.7 #18 "수열" 문항이 여전히 우측으로 밀림 확인. 원인: WasmTextMeasurer 에 inline_tabs 분기 부재로 TabDef 만 참조 → auto_tab_right 폴스루 → RIGHT 오판. 변경: - src/renderer/layout/text_measurement.rs (+69 -2): - 헬퍼 inline_tab_type(ext) = (ext[2] >> 8) & 0xFF 신규 (pub(super)) - WasmTextMeasurer::estimate_text_width 에 inline_tabs 분기 신규 (+23) - WasmTextMeasurer::compute_char_positions 에 동일 분기 신규 (+27) - match arm: 2 => RIGHT, 3 => CENTER, _ => LEFT/DECIMAL (PR #292 실증 포맷) - 네이티브 EmbeddedTextMeasurer 는 건드리지 않음 — 기존 golden 2건 (issue-147, issue-267) 이 우연한 LEFT 폴백에 의존 중이라 범위 축소. 한컴 PDF 대조 후 별도 이슈로 처리 예정. - src/renderer/layout/tests.rs (+32): task296_inline_tab_type_{left,right,center,decimal} 4건 범위 축소 결정: Stage 2 중간에 네이티브 측정기도 수정했을 때 svg_snapshot 2건 FAIL 발생. 기존 golden 이 "우연한 LEFT 폴백" 동작에 의존 중임을 확인 → 무리하게 golden 을 갱신하는 대신 WASM 만 수정하고 네이티브 측은 별도 이슈로 분리. inline_tab_type 을 pub(super) 로 공개해두어 후속 이슈에서 재사용 가능. 검증: - cargo test --lib: 992 passed / 0 failed / 1 ignored (988 → 992, +4 신규) - cargo test --test svg_snapshot: 6 passed (기존 golden 유지) - cargo test --test tab_cross_run: 1 passed (#290 회귀 없음) - cargo clippy / wasm32 check: clean - WASM Docker 빌드 + rhwp-studio 브라우저 시각 검증: 작업지시자 판정 성공 산출물: - mydocs/plans/task_m100_296{,_impl}.md - mydocs/working/task_m100_296_stage{1,2,3,4}.md - mydocs/report/task_m100_296_report.md - mydocs/troubleshootings/tab_tac_overlap_142_159.md ("#296 섹션" 추가) - mydocs/orders/20260424.md (Task #296 섹션 + 종료 리스트 갱신) 후속 이슈 후보: 네이티브 EmbeddedTextMeasurer 의 tab_type = ext[2] 버그 (한컴 PDF 대조로 올바른 동작 확정 후 inline_tab_type 재사용하여 수정) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim
added a commit
that referenced
this pull request
Apr 24, 2026
#297) - 작성자: @planet6897 (Task #297, PR #300, 오늘 6번째 기여) - Merge commit: 0e3fb02 (admin merge, orders 3구간 충돌 직접 해결) - 이슈 #297 CLOSED 처리 절차: - PR 브랜치에 origin/devel 머지 → orders 섹션 3구간 해결 (#295 "## 7", #296 "## 8", #297 "## 9") - planet6897/task297 에 push - 재승인 + admin merge 변경 (1파일): - src/renderer/layout/table_layout.rs +5 -2: - VertRelTo::Page => (col_area.y, col_area.height) [쪽 본문 영역] - VertRelTo::Paper => (0, page_h_approx) [용지 전체, 유지] - HWP 스펙 Page=쪽 본문, Paper=용지 전체 반영 성과: - pi=22 "* 확인 사항" 박스 y: 1371.5 → 1224.07 (PDF 1226.5 ±2 일치) - 145 샘플 중 본문 Page 표 13건 + 바탕쪽 5건 회귀 스캔 완료 (의도 범위 외 무회귀) 검증: - cargo test --lib: 992 passed - svg_snapshot: 6 passed (golden 유지) - 실제 SVG y 좌표 확인: 1224.07px (PDF 일치) #295 → #297 연결 모범 사례: PR #298 리뷰 중 사전 존재 버그로 분리 → 1시간 만에 PR #300 해결. 초기 가설(바탕쪽 Paper) 폐기 → pdftotext 실측으로 근본 원인(enum 미구분) 발견 → 1줄 수정. ===== 오늘 9번째 PR 머지 ===== #284 #285 #266 #273 #277 #278 #289 #292 #298 #300 + 메인테이너 핀셋 #296 Co-Authored-By: Claude Opus 4.7 (1M context) <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.
요약
samples/exam_math.hwp페이지 7 의 18번 "수열" 문항 첫 줄이 좌측 단의 우측 끝으로 밀려 렌더되던 버그를 해결 (closes cross-run 탭 감지가 inline_tabs를 무시하여 좌측 탭이 우측 정렬로 오판정 (exam_math.hwp p.7 #18) #290).src/renderer/layout/paragraph_layout.rs의 cross-run 우측/가운데 탭 감지 블록 (est 측:854-868+ render 측:1213-1226) 이 마지막\t의 종류를 판정할 때find_next_tab_stop(TabDef 전용) 만 호출하여 본문tab_extended(inline_tabs) 를 무시했음. LEFT inline 탭이auto_tab_right폴스루로 RIGHT 오판되어 다음 run 이 우측 끝으로 역산 배치됨.resolve_last_tab_pending으로 inline_tabs 우선 참조 + TabDef 폴백 경로 통합. est/render 양쪽 루프에inline_tab_cursor_*도입.배경과 원인
작업지시자 제보:
samples/exam_math.hwpp.7 #18 문항 첫 줄이 PDF 와 다르게 보임.PDF (정답):
18. 수열 {a_n}이 모든 자연수 n에 대하여SVG (버그):
18.···························수열 {a_n}이 모든 자연수 n에 대하여IR 관찰 (paragraph 0.144)
트레이스로 확정한 메커니즘 (임시
RHWP_TRACE290)"18.\t\t\t"의 3 개\t는 inline 경로에서 LEFT 로 x=38.24 까지 진행 (정상).abs_before=37.19> 모든 stops →auto_tab_right폴스루 → type=1 (RIGHT) 반환.pending_right_tab_render = Some((420.11, 1))설정."수열 이 모든 자연수 "배치 시x = col_area.x + 420.11 - next_w(201.00) = 290.91로 역산 → 우측 끝 근처 배치.ext[2] 포맷 실증 (Stage 1)
RIGHT 샘플 (
samples/hwp-3.0-HWPML.hwp저작권\t1) 확보 + 트레이스 비교:0x01000x0203→ ext[2] 는 high/low byte 합성 값. high=탭 종류 enum+1 (1=LEFT, 2=RIGHT, 3=CENTER, 4=DECIMAL), low=fill_type.
수정 내용
1. 신규 헬퍼
resolve_last_tab_pending2. cross-run 블록 2 곳 교체 +
inline_tab_cursor_*:840):inline_tab_cursor_est: usize = 0도입, 기존 블록을 헬퍼 호출로 교체.:1198):inline_tab_cursor_render: usize = 0도입, 동일 교체.continue직전에cursor += run.text.chars().filter(|c| *c == '\t').count()증가.composed.tab_extended는 parser 에서0x0009(TAB) 마다 1 개씩 push 되므로\t카운트와 정확히 일치.3. 테스트 신규
src/renderer/layout/tests.rs): LEFT→None / RIGHT→Some / CENTER→Some / inline 없음 폴백 2 건.tests/tab_cross_run.rs): exam_math.hwp p.7 렌더 후 item 18 "수" glyphx < 200검증.변경 전/후 (SVG transform)
item 18 첫 줄의 14 글자 모두 일관되게 -181.11 px 좌측 이동:
검증
cargo test --lib task290(신규 5)cargo test --test tab_cross_run(신규 1)cargo test --test svg_snapshotcargo test --lib전체cfb_writer/wasm_api, 무관)cargo clippy --lib -- -D warnings회귀 검증 (git worktree baseline diff)
저작권\t1회귀 없음)시각 비교 (3 면 PNG)
mydocs/working/task_m100_290_stage3/p7_{before,after,pdf}.png— AFTER = PDF 일치.범위 외 후속 과제
text_measurement.rs:217, 320):ext[2]를 전체 u16 으로 해석 → 실제 HWP 값 (최소 256) 과 매칭 안 됨 → inline RIGHT/CENTER 경로 영원히 도달 불가. 저작권\t1 케이스가 "그럭저럭 보이는" 이유는 RIGHT 탭이 LEFT 처리되어 우연히 우측 정렬과 유사해서. 별도 이슈 후보./2.0스케일 (style_resolver.rs:640): 수식 레이아웃 보정: 한컴 기준값 측정 및 상수 조정 #142, 원문자(①~⑤) 폭 추정 오류 및 탭+TAC 위치 계산 불일치 #159 에서 "한컴 격자 비교로 확정" 되었으나 본 수정과 별개 경계 케이스 잠재. 본 타스크에서는 변경하지 않음.교훈
estimate_text_width/compute_char_positions가 아니라 run 내부 탭 처리 vs cross-run 탭 감지 의 불일치로 재발. 런내부는 inline_tabs 를 봤지만 cross-run 감지는 TabDef 만 봤음. 헬퍼 중앙화 (
resolve_last_tab_pending) 로 경계 통일.RHWP_TRACE290로 양쪽 호출의 입력/출력을 동시 관측 → 추측 없이pending_right_tab = Some((420.11, 1))→x_after=290.91로 이어지는 전 경로를 숫자로 연결.산출물
코드
src/renderer/layout/paragraph_layout.rs— 헬퍼 추가 + cross-run 블록 2 곳 교체 + cursor 2 개 도입 (+86 / -24 줄)src/renderer/layout/tests.rs— 단위 테스트 5 건 (+83 줄)tests/tab_cross_run.rs— 통합 테스트 1 건 (신규)문서
mydocs/plans/task_m100_290{,_impl}.md— 수행/구현 계획서mydocs/working/task_m100_290_stage{1,2,3,4}.md— 단계별 완료 보고서mydocs/working/task_m100_290_stage3/p7_{before,after,pdf}.png— 3 면 시각 비교mydocs/report/task_m100_290_report.md— 최종 보고서mydocs/troubleshootings/tab_tac_overlap_142_159.md— cross-run 탭 감지가 inline_tabs를 무시하여 좌측 탭이 우측 정렬로 오판정 (exam_math.hwp p.7 #18) #290 섹션 추가 (수식 레이아웃 보정: 한컴 기준값 측정 및 상수 조정 #142 교훈 확장)mydocs/orders/20260424.md— 완료 항목 추가커밋