Skip to content

fix: CharShape start_pos 를 UTF-16 stream offset 으로 해석 (closes #915)#1047

Closed
HaimLee-4869 wants to merge 1 commit into
edwardkim:develfrom
HaimLee-4869:pr/915-charshape-relative-offset
Closed

fix: CharShape start_pos 를 UTF-16 stream offset 으로 해석 (closes #915)#1047
HaimLee-4869 wants to merge 1 commit into
edwardkim:develfrom
HaimLee-4869:pr/915-charshape-relative-offset

Conversation

@HaimLee-4869

Copy link
Copy Markdown
Contributor

요약

#915 — table-in-tbox.hwp 2페이지 표 셀 "충남중부권지사" 가 휴먼명조 1pt(1.33px)로 렌더되는 결함 수정.

원인

composer 의 split_by_char_shapes 가 CharShape.start_pos 를 visible char index 로 해석한다(#884).
이 해석은 인라인 제어자가 문단 중간에 있어 char_offsets 에 gap 이 생기는 문단에서 start_pos 가
가시문자 수 범위를 넘어 판정되어 char_shape 가 통째 누락된다. 한편 paragraph_layout /
line_breaking 은 start_pos 를 stream offset 으로 해석하고 있어 경로 간 불일치 상태이기도 했다.

#884 는 table-in-tbox.hwp 1페이지 footer "충남중부권지사장" 을 근거로 visible-index 해석을
도입한 것으로 보인다. 해당 footer 를 한컴2024 글자모양 패널로 재측정한 결과는 아래와 같다.

한컴2024 글자모양 패널 실측 대조

위치 한컴 패널 stream offset (본 PR) visible-index (현행)
table-in-tbox p1 footer "충남중부권지사장" HY수평선B 16pt HY수평선B 16pt ✅ 26pt ❌
table-in-tbox p2 "충남중부권지사" 정상 크기 정상 ✅ 휴먼명조 1pt ❌
KTX 목차 "Ⅰ" 휴먼명조 16pt 휴먼명조 16pt(21.3px) ✅ 18.7pt ❌
KTX 목차 "사업 개요" HY헤드라인M 15pt HY헤드라인M 15pt ✅ 18.7pt ❌

(한컴은 pt, SVG font-size 는 px — px = pt × 96/72.)
start_pos 를 UTF-16 stream offset 으로 해석하면 footer 와 #915 양쪽이 모두 한컴과 정합한다.

변경

검증

  • cargo test 전체 49 스위트 / clippy / fmt --check clean
  • svg_snapshot 8/8 / KTX 페이지번호 우측정렬 보존 / native+WASM 빌드

Closes #915

…im#915)

edwardkim#915: table-in-tbox.hwp p2 표 셀 "충남중부권지사" 가 휴먼명조 1pt(1.33px)
로 렌더되는 결함.

원인: composer 의 split_by_char_shapes 가 CharShape.start_pos 를 visible
char index 로 해석한다(edwardkim#884). 이 해석은 인라인 제어자가 문단 중간에 있어
char_offsets 에 gap 이 생기는 문단에서 start_pos 가 가시문자 수 범위를
넘어 판정되어 char_shape 가 통째 누락된다. 한편 paragraph_layout /
line_breaking 은 start_pos 를 stream offset 으로 해석하고 있어, composer
와 경로 간 불일치 상태이기도 했다.

edwardkim#884 는 table-in-tbox.hwp p1 footer "충남중부권지사장" 의 char_shape
적용을 근거로 visible-index 해석을 도입한 것으로 보인다. 해당 footer 를
한컴2024 글자모양 패널로 재측정한 결과 HY수평선B 16pt 였고, start_pos 를
UTF-16 stream offset 으로 해석하면 footer(HY수평선B 16pt)와 edwardkim#915 양쪽이
모두 한컴과 정합한다.

split_by_char_shapes 의 start_pos 매핑을 stream offset 으로 맞춰 composer
를 paragraph_layout / line_breaking 과 일관시켰다 — char_offsets 에서
start_pos 이상인 첫 가시문자가 char_shape 적용 시작점.

검증 (한컴2024 글자모양 패널 대조):
- table-in-tbox p1 footer "충남중부권지사장": HY수평선B 16pt
- table-in-tbox p2 "충남중부권지사": 휴먼명조 1pt → 정상
- KTX 목차 "Ⅰ" 휴먼명조 16pt / "사업 개요" HY헤드라인M 15pt
- cargo test 전체 49 스위트 / clippy / fmt 통과

tests/issue_915_charshape_cell_font_size.rs: edwardkim#915 회귀 가드 신규.
tests/issue_884_charshape_diagnostic.rs: footer 단언을 한컴 실측값(HY수평선B)으로 갱신.
tests/golden_svg/issue-{157,267,617,677}: stream offset 해석 결과로 갱신.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@edwardkim edwardkim self-requested a review May 20, 2026 22:37
@edwardkim edwardkim added the bug Something isn't working label May 20, 2026
@edwardkim edwardkim added this to the v1.0.0 milestone May 20, 2026
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

Copy link
Copy Markdown
Owner

Merged via cherry-pick (commit d84e7f5, author @HaimLee-4869 보존) into devel 8ba28089.

본 환경 검증 통과: cargo test 1319 + 통합 + 회귀 가드 4 (issue_884 2/2 + issue_915 1/1 + issue_874 1/1 + svg_snapshot 8/8) + sweep 53 diff (광범위 stream offset 정합) + WASM 4.89MB + 작업지시자 시각 판정.

PR #913 (closes #884, @planet6897, commit 9f81351) 의 visible char index 해석을 한컴 2024 글자모양 패널 실측 4 케이스 권위로 revert. composer ↔ paragraph_layout/line_breaking path 일관성 복원 + #915 결함 (table-in-tbox p2 1.33px → 16px) 해소.

feedback_visual_judgment_authority 모범 사례 — PR #913 의 '★ 시각 판정 통과' 도 정량적 한컴 패널 실측 권위로 정정 (측정 우위).

closes #915

@edwardkim edwardkim closed this May 20, 2026
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>
edwardkim added a commit that referenced this pull request May 21, 2026
samples/table-in-tbox.hwp 의 글상자 클릭 동작이 한컴 UX 와 정합되도록
정정. 표 UX 패턴 (isTableBorderClick / enterTableObjectSelection / Esc
처리) 을 글상자에 일반화하여 적용.

한컴 UX 정합:
- 글상자 외곽 경계선 (tolerance 5px) → 객체 선택
- 글상자 내부 (텍스트/빈 영역/안 표) → 즉시 텍스트 편집 진입
- 글상자 안 표 셀 → cursor 정상 진입 (글상자 가로채기 제거)
- Esc → 가장 안쪽 컨테이너부터 escape stack (안 표 → 글상자 안 본문
  → 글상자 객체 → 본문 자연 전이)

본질 (7 코드 갭 정확 식별):

Native (Rust) — 4 파일:
- src/document_core/queries/cursor_rect.rs: TextBoxBboxInfo struct +
  collect_runs Rectangle/Ellipse/Path 노드 메타 수집 + hit_test 우선순위
  (hit_cell → clicked_cell → textbox_hit → hit_body) + format_textbox_entry
  + 0.5 inline Shape 분기 글상자 fall-through (break)
- src/document_core/queries/cursor_nav.rs: resolve_table_by_path 가 path
  중간 항목 Shape (글상자) 면 text_box.paragraphs traverse, 5 ShapeObject
  variants (Rectangle/Ellipse/Polygon/Arc/Curve) 지원
- src/document_core/commands/table_ops.rs: get_shape_bbox_native 신규
  (Rectangle/Ellipse/Path 노드 검색, getTableBBox 동등 패턴)
- src/wasm_api.rs: getShapeBBox 공개 API

Studio (TypeScript) — 4 파일:
- rhwp-studio/src/engine/input-handler.ts: isShapeBorderClickByRef
  (sec/ppi/ci 시그니처, getShapeBBox + 5px tolerance) + findShapeByOuterClick
- rhwp-studio/src/engine/input-handler-mouse.ts: 글상자 클릭 흐름 정정
  (외곽 경계선만 객체 선택, 내부 즉시 cursor 진입, picHit shape 분기
  외곽만 객체 선택) + 객체→편집 전환 (객체 선택 + 내부 클릭 → 편집)
- rhwp-studio/src/engine/input-handler-keyboard.ts: Esc 우선순위 정정
  (nestingDepth >= 2 + isTextBox → 표 객체 선택 우선)
- rhwp-studio/src/engine/cursor.ts: enterTableObjectSelection cellPath.length
  >= 2 면 isTextBox 상태에서도 허용 + moveOutOfSelectedTable 글상자 안
  표 → 외부 이동 시 isTextBox 유지 (escape stack 자연 전이)
- rhwp-studio/src/core/wasm-bridge.ts: getShapeBBox 메서드

검증:
- cargo test --release --lib **1319 passed**
- cargo test --release --tests 모든 통합 passed (issue_852/874/915/1008/919)
- cargo test --release --test issue_919_textbox_hit_test **5/5 passed**:
  textbox_inner_text_hit / textbox_inner_empty_hit / textbox_outside_hit /
  get_shape_bbox_returns_correct_dimensions /
  inner_table_cell_in_textbox_has_two_path_entries
- cargo fmt --all --check clean
- TypeScript tsc --noEmit 0 errors
- WASM Docker 빌드 **4.90MB** (PR #1047 4.89MB + getShapeBBox API 추가)
  + rhwp-studio 동기화
- 작업지시자 시각 판정 통과 (2 라운드: 글상자 진입 + Esc escape stack)

작업지시자 시각 판정 권위 (`feedback_visual_judgment_authority`):
- 1차 (글상자 진입) 통과 후 작업지시자 추가 지적 "글상자 내에 위치한
  표의 셀 hitTest까지 성공입니다. 여기서 esc 키를 누르면 표가 선택되어야
  하는데 글상자가 선택됩니다" → Stage 2.5 추가 정정
- 콘솔 에러 `renderTableObjectSelection 실패: controls[2]가 표가 아닙니다`
  진단 → resolve_table_by_path 의 path traverse 일반화 추가 정정

비범위 (후속):
- 머리말/꼬리말 안 글상자 (본 task 본문만)
- 글상자 안 글상자 중첩 재귀 (본 PR 일부 지원: cellPath traversal)
- 도형 (직사각형/원) 의 hit_test 동일 UX (본 task 는 글상자 한정)

closes #919

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