Skip to content

fix: CharShape start_pos 를 visible char index 로 해석 (closes #884)#913

Closed
planet6897 wants to merge 2 commits into
edwardkim:develfrom
planet6897:pr-task884
Closed

fix: CharShape start_pos 를 visible char index 로 해석 (closes #884)#913
planet6897 wants to merge 2 commits into
edwardkim:develfrom
planet6897:pr-task884

Conversation

@planet6897

Copy link
Copy Markdown
Contributor

요약

HWP 5.0 PARA_CHAR_SHAPE.start_pos 의 해석을 u16 stream 위치 (해석 A) → visible character index (해석 B) 로 변경. inline picture 등 다단위 컨트롤이 있는 paragraph 에서 char_shape 적용 영역이 어긋나는 결함 정정.

객관 데이터 (raw dump 검증)

samples/table-in-tbox.hwpShape.TextBox > Table > cell[0] paragraph 분석:

text:           " 충남중부권지사장" (9 visible chars, 1 leading space + 8 Korean)
char_offsets:   [8, 9, 10, 11, 12, 13, 14, 15, 16]  ← inline picture u16=0..7 점유
char_shapes:
  start_pos=0 id=14 → HY헤드라인M 26pt bold
  start_pos=9 id=20 → HY수평선B 16pt bold
해석 동작 결과
A (이전) start_pos=9 → char_offsets[1]=9 → visible1 부터 id=20 "충남중부권지사장" → HY수평선B 21.33pt 잘못
B (현재) start_pos=9 ≥ text.chars().count()=9 → 미적용 전체 id=14 → HY헤드라인M 26pt PDF 정합

변경

  • src/renderer/composer.rs
    • compose_runs_for_line: cs.start_pos 를 visible char index 로 직접 비교 (이전 char_offsets.iter().position(|&off| off >= cs.start_pos) 제거)
    • find_active_char_shape_visible(char_shapes, visible_idx) 신규
    • 기존 find_active_char_shape(utf16_pos) 는 wrapper 로 전환 (호환성 유지)

검증

cargo test --release
# 1257 unit + integration tests GREEN
  • tests/issue_884_charshape_diagnostic.rs 신규 (RED 가드 + raw 데이터 dump)
  • svg_snapshot 8/8 GREEN
  • WASM build 영향 없음

골든 갱신 (해석 A 의 결함 manifest 가 정정된 결과)

이슈 본문 Task #696 B-2-Z 실험이 "회귀 4건" 으로 분류한 케이스는 사실 해석 A 의 결함 manifest 였음 (한 paragraph 안에서 inline 컨트롤 다음 텍스트에 char_shape 가 잘못 적용된 결과).

골든 변경
issue-157/page-1.svg 1 line position
issue-267/ktx-toc-page.svg "Ⅰ" 글자 font 통일 (제목 일관성 ↑)
issue-617/exam-kor-page5.svg 본문 font 분기 정합
issue-677/bokhakwonseo-page1.svg 괄호 font 정합

관련

🤖 Generated with Claude Code

table-in-tbox.hwp 의 Shape.TextBox > Table > cell[0] paragraph
(" 충남중부권지사장") raw 데이터로 해석 A/B 객관 비교:

- text: 9 visible chars, 1 leading space + 7 Korean
- char_offsets: [8, 9, 10, ..., 16]  (inline picture 8 u16 점유)
- char_shapes:
    start_pos=0 id=14 → HY헤드라인M 26pt bold
    start_pos=9 id=20 → HY수평선B 16pt bold

해석 A (현재): start_pos=9 → char_offsets[1]=9 → visible[1]("충") 부터
  id=20 적용. SVG 출력: 충남중부권지사장 모두 HY수평선B (잘못).

해석 B (정답): start_pos=9 → visible idx 9 → text 길이 9 보다 ≥ → 미적용.
  전체 id=14 (HY헤드라인M) 유지. PDF 정합 (이슈 본문 기준).

RED 가드: 현재 결함 (HY수평선B) 상태에서 GREEN.
fix 후: HY헤드라인M 으로 전환 시 assert 반전 필요.

회귀 영향 (해석 B 적용 시): svg_snapshot 4 골든 변경
- issue_157 (line position +64)
- issue_267 (Ⅰ 글자 font 통일)
- issue_617 (인터넷 카페 font 분기)
- issue_677 (괄호 font 변경)

PDF 정합 검증 필요 — fix 진행 여부 결정.

Refs: edwardkim#884, Task edwardkim#696 B-2-Z 실험
paragraph 의 PARA_CHAR_SHAPE.start_pos 를 u16 stream 위치 (A) 가 아닌
visible character index (B) 로 해석한다. inline picture 등 다단위
컨트롤이 있는 paragraph 에서 char_shape 적용 영역 어긋남 결함 정정.

검증 (table-in-tbox.hwp Shape.TextBox > Table > cell[0] " 충남중부권지사장"):
  text 9 visible chars, char_offsets [8, 9, .., 16]
  char_shapes: (start_pos=0 id=14 HY헤드라인M 26pt),
               (start_pos=9 id=20 HY수평선B 16pt)
  해석 A (이전): id=20 → visible[1]("충") 부터 적용 (잘못)
  해석 B (현재): start_pos=9 ≥ text length 9 → 미적용,
                전체 id=14 유지 (HY헤드라인M, PDF 정합)

변경:
- src/renderer/composer.rs: compose_runs_for_line 의 cs.start_pos →
  visible idx 직접 비교. find_active_char_shape → wrapper 로 변환,
  find_active_char_shape_visible 신규 도입.

영향 골든 갱신:
- tests/golden_svg/issue-157/page-1.svg (line position +64px)
- tests/golden_svg/issue-267/ktx-toc-page.svg (Ⅰ 글자 font 통일)
- tests/golden_svg/issue-617/exam-kor-page5.svg (인터넷 카페 font)
- tests/golden_svg/issue-677/bokhakwonseo-page1.svg (괄호 font)

회귀: 1257 unit + integration tests GREEN.

이슈 본문 Task edwardkim#696 B-2-Z 실험의 "회귀 4건" 은 해석 A 의 결함 manifest 였음
— 해석 B 가 모든 케이스에서 의도된 동작.

closes edwardkim#884
@edwardkim edwardkim self-requested a review May 15, 2026 09:16
@edwardkim edwardkim added the bug Something isn't working label May 15, 2026
@edwardkim edwardkim added this to the v1.0.0 milestone May 15, 2026
edwardkim pushed a commit that referenced this pull request May 15, 2026
PR #913 (@planet6897) cherry-pick. mydocs 제외.

composer.rs compose_runs_for_line: start_pos를 u16 stream 위치가 아닌
visible character index로 직접 비교. inline picture 등 다단위 컨트롤이
있는 paragraph에서 char_shape 적용 영역 어긋남 해소.

골든 SVG 4건 갱신 (해석 A 결함 manifest → 해석 B 정합).

검증:
- cargo test --release --lib: 1258 passed
- issue_884_charshape_diagnostic: 2 passed
- 웹 에디터 시각 판정 ★ 통과

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@edwardkim

Copy link
Copy Markdown
Owner

검토 + cherry-pick 머지 완료. 감사합니다.

처리 결과

재검증

검증 결과
cargo test --release --lib 1258 passed
issue_884_charshape_diagnostic 2 passed
웹 에디터 시각 판정 ★ 통과 (page 1)

Task #696 B-2-Z 실험의 "회귀 4건"이 사실 해석 A의 결함이었다는 분석이 정확합니다. 수고하셨습니다.

시각 판정 중 발견된 기존 결함 (별도 이슈)

@edwardkim edwardkim closed this May 15, 2026
oksure added a commit to oksure/rhwp that referenced this pull request May 17, 2026
…fallback

Issue edwardkim#884 (PR edwardkim#913) 회귀 방지 테스트와 Issue edwardkim#915 수정을 동시 충족하는
hybrid 로직:
  - start_pos < total_chars → visible char index (해석 B, 한컴 정합)
  - start_pos == total_chars → 범위 끝 sentinel (적용 대상 없음)
  - start_pos > total_chars → char_offsets binary search (stream fallback)

Case 1 (TextBox셀): start_pos=9, total=9 → sentinel → skip (HY헤드라인M 유지)
Case 2 (외부표셀): start_pos=28, total=27 → binary search → visible 20 (정상)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@planet6897 planet6897 deleted the pr-task884 branch May 19, 2026 00:37
edwardkim added a commit that referenced this pull request May 20, 2026
…ffset 해석 통일 — PR #913 revert

@HaimLee-4869 5번째 기여. CharShape.start_pos 해석을 UTF-16 stream
offset (해석 A) 로 통일 — PR #913 (closes #884, @planet6897, commit
9f81351) 의 visible char index (해석 B) 해석을 한컴 2024 글자모양
패널 실측 4 케이스 권위로 명시적 revert.

본질:
- src/renderer/composer.rs split_by_char_shapes 의 start_pos lookup
  을 char_offsets.iter().position(|&off| off >= cs.start_pos) 로
  변경 — char_offsets[i] 가 가시문자 i 의 stream offset 이므로
  start_pos 이상인 첫 가시문자가 char_shape 적용 시작점.
- fallback active-shape 조회: find_active_char_shape_visible →
  find_active_char_shape (line_stream_start = char_offsets[text_start]).
- 결과: composer ↔ paragraph_layout.rs / line_breaking.rs 의 4
  경로가 모두 해석 A 로 일관.

한컴 2024 글자모양 패널 실측 4 케이스 (해석 A 정답):
| 위치 | 한컴 패널 | 해석 A (본 PR) | 해석 B (PR #913) |
|------|----------|----------------|------------------|
| table-in-tbox p1 footer "충남중부권지사장" | HY수평선B 16pt | ✅ | 26pt ❌ |
| table-in-tbox p2 "충남중부권지사" | 정상 | ✅ | 휴먼명조 1pt ❌ #915 |
| KTX 목차 "Ⅰ" | 휴먼명조 16pt | ✅ | 18.7pt ❌ |
| KTX 목차 "사업 개요" | HY헤드라인M 15pt | ✅ | 18.7pt ❌ |

PR #913 의 오진 원인:
- footer "충남중부권지사장" 의 "26pt" 판정이 HY수평선B 굵은 글꼴 +
  로고 옆 배치로 인한 육안 착시 — 한컴 패널 실측은 16pt.
- composer 만 해석 B 로 바꿔서 paragraph_layout/line_breaking 와
  불일치 상태 (path 불일치).
- 인라인 제어자가 문단 *중간* 에 있는 문단에서 start_pos 가
  char_offsets gap 만큼 부풀려져 char_shape 통째 누락 → #915
  (table-in-tbox p2 "충남중부권지사" 1.33px).

회귀 가드 (4 가드 영구화):
- tests/issue_884_charshape_diagnostic.rs 갱신 — 단언 반전 (footer
  "충" HY수평선B 검증, 한컴 실측 기반).
- tests/issue_915_charshape_cell_font_size.rs 신규 — 한글 음절
  < 5px 부재 휴리스틱 (정상 ≥5px, 결함 ≈1.33px).
- tests/issue_874_ktx_toc_page_number_right_align.rs (PR #1026)
  양립 — KTX 페이지번호 정합 유지.
- tests/svg_snapshot.rs 8/8 (issue-157/267/617/677 골든 4 갱신,
  table_text/form_002/aift/render_deterministic 보존).

검증 (본 환경):
- cargo test --release --lib **1319 passed**
- cargo test --release --tests 모든 통합 passed (0 FAILED)
- cargo test --release --test issue_884_charshape_diagnostic **2/2 passed**
- cargo test --release --test issue_915_charshape_cell_font_size **1/1 passed**
- cargo test --release --test issue_874_ktx_toc_page_number_right_align **1/1 passed**
- cargo test --release --test svg_snapshot **8/8 passed**
- cargo fmt --all --check clean
- sweep 8 fixtures (277 SVGs): 53 diff (광범위 stream offset 정합,
  table-in-tbox/KTX/hwp3-sample16/exam_kor/exam_math/aift) / 페이지
  수 회귀 부재 / biz_plan 무영향
- **table-in-tbox p2 정량 입증**: font-size="1.3333" → font-size="16"
- WASM Docker 빌드 4.89MB + rhwp-studio 동기화
- 작업지시자 시각 판정 통과 (한컴 2024 패널 실측 4 케이스 권위)

`feedback_visual_judgment_authority` 모범 사례 — PR #913 의 "★ 시각
판정 통과" 도 정량적 한컴 패널 실측 권위로 정정 가능 (측정 우위).
`reference_authoritative_hancom` — Windows 한컴 편집기 글자모양
패널이 1차 권위.

`feedback_pr_supersede_chain` — PR #913 (오진 정합) → PR #1047 (실측
정정) 의 supersede 패턴. PR #913 머지 commit `9f81351a` 의 4 경로
중 composer 만 해석 B 였음 → path 일관성 복원.

closes #915

Co-Authored-By: HaimLee-4869 <j_haim4869@naver.com>
edwardkim added a commit that referenced this pull request May 20, 2026
… revert)

PR #1047 (closes #915) 머지 후속 처리:
- mydocs/pr/archives/pr_1047_review.md (검토 문서 archives 이동)
- mydocs/orders/20260521.md (PR #1047 entry 추가)
- rhwp-studio/public/{rhwp.d.ts,rhwp.js,rhwp_bg.wasm} (WASM 4.89MB 동기화)

@HaimLee-4869 5번째 기여 — PR #913 revert (한컴 2024 글자모양 패널
실측 4 케이스 권위로 visible char index → UTF-16 stream offset 해석
통일). composer ↔ paragraph_layout/line_breaking 4 경로 일관성 복원.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants