Skip to content

cross-run 탭 감지가 inline_tabs를 무시하여 좌측 탭이 우측 정렬로 오판정 (exam_math.hwp p.7 #18) #290

@planet6897

Description

@planet6897

증상

samples/exam_math.hwp 페이지 7의 18번 "수열" 문항 첫 줄에서 "수열 {a_n}이 모든 자연수 n에 대하여" 텍스트가 좌측 열의 우측 끝으로 밀려나 렌더링됨.

  • PDF (정답): 18. 수열 {a_n}이 모든 ... — "18."과 "수열" 사이는 짧은 공백
  • SVG (버그): 18. ······················· 수열 {a_n}이 모든 ... — "수열"이 우측 끝 근처

기타 문항(19, 20번)과 본 문항의 2·3째 줄은 영향 없음.

재현

```bash
cargo build --release
./target/release/rhwp export-svg samples/exam_math.hwp -o output/svg/exam_math/ -p 6
```

출력 `exam_math_007.svg`를 브라우저에서 열면 "수" 글리프가 `translate(290.9, 162.7)`에 배치됨. 정상 위치는 약 `translate(110, 162.7)` 부근.

근본 원인

위치: `src/renderer/layout/paragraph_layout.rs:1213-1226` (cross-run 우측/가운데 탭 감지 블록)

```rust
if has_tabs && run.text.ends_with('\t') {
if let Some(last_tab_pos) = run.text.rfind('\t') {
let text_before_tab = &run.text[..last_tab_pos];
let w_before = estimate_text_width(text_before_tab, &text_style);
let abs_before = text_style.line_x_offset + w_before;
let tw = if tab_width > 0.0 { tab_width } else { 48.0 };
let (tp, tt, _) = find_next_tab_stop( // ← inline_tabs 무시
abs_before, &tab_stops, tw, auto_tab_right, available_width,
);
if tt == 1 || tt == 2 {
pending_right_tab_render = Some((tp, tt)); // ← 잘못된 설정
}
}
}
```

마지막 `\t`의 종류를 판정할 때 `find_next_tab_stop`(TabDef 전용)만 사용하고, 본문 `tab_extended`(inline_tabs)를 참조하지 않음. 모든 TabDef stop이 `abs_before`보다 작으면 `auto_tab_right` 폴스루로 무조건 RIGHT 탭(type=1)으로 판정되어 다음 run이 우측 끝으로 역산 배치됨.

트레이스 증거 (paragraph 0.144)

```
IR: text="18.\t\t\t수열 이 모든 자연수 에 대하여"
tab_def: 12.0mm(L)/13.3mm(L)/18.0mm(L)/18.6mm(L) auto_tab_right=true
tab_extended: [132,,256,...] [671,,256,...] [79,_,256,...] # widths in HU, type=256(=LEFT)

Run "18.\t\t\t" (inline_tabs 경로): x=26.48 → 28.24 → 37.19 → 38.24 ✓ 정상
Cross-run 감지 (TabDef 경로): abs_before=37.19 → tab_stops 모두 < 37.69 → auto_tab_right → (tp=420.11, tt=1)
pending_right_tab_render = Some((420.11, 1))

Next run "수열 이 모든 자연수 " 배치:
next_w = 201.00
x = col_area.x + 420.11 - 201.00 = 71.80 + 219.11 = 290.91 ← SVG "수" 위치와 일치
```

수정 방향

`paragraph_layout.rs:1213-1226`의 cross-run 감지 블록을 다음과 같이 보정:

  1. `composed.tab_extended`가 해당 `\t` 인덱스를 커버하는 경우:
    • `tab_extended[last_tab_idx][2]`를 탭 종류로 해석
    • 0/256 등 → LEFT → `pending_right_tab_render` 설정하지 않음 (무처리)
    • 1 → RIGHT, 2 → CENTER → 기존 경로 (단, 위치는 `ext[0]` 폭 누적으로 계산)
  2. `tab_extended`가 비었거나 부족한 경우에만 기존 `find_next_tab_stop` 폴백 유지.

회귀 방지

  • `tests/` 또는 `output/re/`에 `samples/exam_math.hwp` page 7 item 18 첫 줄 스냅샷 픽스쳐 추가
  • 시각 회귀 테스트: "수열" 글리프 x좌표가 col_area.x + 200 미만이어야 함

관련

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions