Skip to content

fix(text_measurement): U+00B7 폭 폰트 metric 정합 — 비례폰트 .notdef 위장값 가드#1059

Closed
HaimLee-4869 wants to merge 1 commit into
edwardkim:develfrom
HaimLee-4869:pr/u00b7-notdef-guard
Closed

fix(text_measurement): U+00B7 폭 폰트 metric 정합 — 비례폰트 .notdef 위장값 가드#1059
HaimLee-4869 wants to merge 1 commit into
edwardkim:develfrom
HaimLee-4869:pr/u00b7-notdef-guard

Conversation

@HaimLee-4869

Copy link
Copy Markdown
Contributor

배경 / 원인

· (U+00B7 MIDDLE DOT, 가운뎃점)은 한글 문서에서 매우 흔하다 (예: 시·군,
4급 이상·배우자).

휴먼명조·HY신명조·한양 계열 등 다수의 비례폰트는 자체 · 글리프를 갖지
않는다. 이때 폰트 cmap이 U+00B7을 .notdef(glyph 0)로 매핑하고 .notdef
advance는 통상 em_size(전각)이므로, 폰트 메트릭 DB에 해당 폰트의 U+00B7
폭이 전각(1.0em)으로 위장 기록된다.

한컴은 이 경우 · 글리프를 가진 대체 폰트(바탕 등, ≈0.33em)로 점을 렌더한다.
따라서 rhwp가 위장된 전각 폭을 그대로 쓰면 가운뎃점 좌우 공백이 한컴 대비
비정상으로 벌어진다.

증상 (한컴2024 vs rhwp)

시·군, 4급 이상·배우자 등에서 가운뎃점 좌우 공백이 벌어진다 (좌: 한컴2024, 우: rhwp).

before

점고치기 전

after

점고치기 후

변경 내용

measure_char_width_embedded에 가드를 추가한다.

  • c == U+00B7 && glyph_w >= em_size(전각) && 비례폰트 → 0.3em으로 정정
  • 고정폭(monospace) 폰트(돋움체·바탕체 등)는 모든 글리프가 em_size이고
    ·도 진짜 전각이므로 제외 — 신규 헬퍼 is_monospace_metric(Basic Latin
    글자폭이 모두 동일한지)로 판별

가드는 native·WASM 공유 함수에 위치하여 양 렌더 경로에 동시 적용된다.

영향 범위

폰트 메트릭 DB 595종 중 70종이 해당한다 (비례폰트 + U+00B7 위장 전각):
HY 계열 36종(HY신명조·HY명조·HYGothic 류·HY견고딕·HY궁서·HY헤드라인 등),
휴먼 계열 13종, MD 5종, YJ 9종, 안상수 4종, 펜흘림 1종.
monospace 4종(BatangChe/DotumChe/GulimChe/GungsuhChe)은 가드가 제외한다.

본 저장소 samples/의 HWPX 50종 중 30종이 위 비례폰트를 사용한다.

근거 — 한컴 변환 PDF 좌표 측정

· 앞·뒤 글자의 x좌표로 측정한 advance (em 비율):

대상 폰트 한컴 PDF rhwp (전) rhwp (후)
본문 시·군 휴먼명조 (비례) 0.34em 1.02em 0.32em
본문 이상·배우자 휴먼명조 (비례) 0.34em 1.00em 0.30em
목차 기술·제품 돋움체 (고정폭) 1.01em 1.00em 1.00em

pdf/aift-2022.pdf 목차의 ·는 돋움체(고정폭)라 전각이며 정정 후에도 보존된다.

검증

  • cargo test --lib: 1324 passed
  • cargo test --test svg_snapshot: 8/8 — issue_147_aift_page3(돋움체 목차
    전각) 불변
  • cargo clippy -- -D warnings: clean / cargo fmt --check: clean
  • 회귀 테스트 test_b7_notdef_artifact_narrow_in_proportional_font 추가
  • native·WASM 양 경로 동시 적용 (공유 함수)

sweep 영향 예고

비례폰트 + U+00B7 조합이 등장하는 페이지의 가운뎃점이 narrow로 바뀐다.
이는 의도된 한컴 정합 정정이며, golden 8종은 불변임을 확인했다.

Issue #630 과의 관계

Issue #630(돋움체 목차 · 전각 측정)은 본 변경과 무관하며 그대로 옳다 —
돋움체는 고정폭이라 가드가 발동하지 않아 전각이 보존된다. 본 PR은 #630이
다루지 않은 비례폰트의 위장 전각만을 정정한다. 좁은 구두점
(U+2018/U+2019/U+2027) 폭 분류를 다룬 PR #1026과도 독립적이다 — 본 변경은
U+00B7 전용이다.

비례폰트(휴먼명조·HY신명조·한양 시리즈 등)는 `·`(U+00B7 가운뎃점)
글리프를 갖지 않아, cmap 이 .notdef(glyph 0)로 매핑되며 advance 가
em_size(전각)로 기록된다. 한컴은 이 경우 `·` 글리프를 가진 대체 폰트
(바탕 등 ≈0.33em)로 렌더하므로, 전각 advance 는 한컴 대비 과대하여
가운뎃점 좌우 공백이 비정상으로 벌어진다 (예: "시·군", "이상·배우자").

measure_char_width_embedded 에 가드 추가:
  c == U+00B7 && glyph_w >= em_size && 비례폰트  →  0.3em 으로 정정.
고정폭(monospace) 폰트(돋움체·바탕체 등)는 모든 글리프가 em_size 이고
`·` 도 진짜 전각이므로 제외 — is_monospace_metric 으로 판별한다.

근거 (한컴 PDF 좌표 측정):
- 휴먼명조 본문 `·` = 0.33em (한컴은 바탕 대체 렌더) ↔ rhwp 1.0em (정정 대상)
- 돋움체 목차 `·` = 1.0em (고정폭, 진짜 전각) ↔ rhwp 1.0em (정합 유지)

범위: 폰트 metric DB 595종 중 70종이 해당 (HY·휴먼·한양·MD·YJ·안상수
계열). monospace 4종(체 변형)은 가드가 정확히 제외한다.

가드는 native·WASM 공유 함수에 위치하여 양 경로에 동시 적용된다.
Issue edwardkim#630(돋움체 `·` 전각 측정)은 본 변경과 무관하며 그대로 옳다 —
돋움체는 고정폭이라 가드가 발동하지 않는다.

회귀 테스트 test_b7_notdef_artifact_narrow_in_proportional_font 추가.
svg_snapshot 8 골든 불변 — issue_147_aift_page3(돋움체 목차 전각) 보존.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@edwardkim edwardkim self-requested a review May 21, 2026 23:14
@edwardkim edwardkim added the enhancement New feature or request label May 21, 2026
@edwardkim edwardkim added this to the v1.0.0 milestone May 21, 2026
@edwardkim

Copy link
Copy Markdown
Owner

검토 완료 — merge 수용. devel 에 반영합니다.

검증 결과

본 PR 은 CI no checks reported (첫 fork PR 권한 정책) 라서 본 환경 직접 검증으로 대체했습니다. CI 통과 PR 들과 동등 수준 확보:

처리

평가

.notdef (glyph 0) 의 advance 가 em_size 로 위장 기록되는 메커니즘을 정확히 식별하고, 3 조건 동시 만족 (c == U+00B7 + glyph_w >= em_size + !is_monospace_metric) 으로 좁힘 가드를 설계한 점이 모범적입니다. is_monospace_metric 헬퍼의 표본 부족 가드 (count >= 16) 도 한글 전용 폰트 오판 방지에 정합니다.

feedback_hancom_compat_specific_over_general 권위 사례 — Issue #630 (돋움체 고정폭 전각) 정합을 별도 가드 보존으로 비회귀 보장. feedback_image_renderer_paths_separate 정합 — native·WASM 공유 함수 (measure_char_width_embedded) 가드 위치로 양 경로 동시 적용. PR #1026 패턴 일관.

한컴 PDF 좌표 정량 측정 (시·군 0.34em ↔ rhwp 전 1.02em ↔ rhwp 후 0.32em) 으로 정합 근거를 결정적으로 제시한 점도 인상적입니다.

기여 감사합니다.

@edwardkim

Copy link
Copy Markdown
Owner

devel 반영 완료 (cherry-pick). PR close 합니다.

@edwardkim edwardkim closed this May 21, 2026
edwardkim pushed a commit that referenced this pull request May 22, 2026
…t check 복구)

Task #1058 Stage 16 (adaa0b0) 에서 추가된 신규 파일이 rustfmt 정합
미통과 — devel CI #970 (sha=749048c9) Format check 실패. cargo fmt
적용으로 정정. 본 환경 cargo fmt --check 전체 exit 0 검증.

본 정정은 PR #1057 처리 진행 전 devel CI 회복 위한 단독 commit.
다른 처리분 (PR #1054/#1059 누적 + 예정 PR #1057) 은 별도 누적 push
계획 (작업지시자 결정 "본 PR 처리분 누적 후 push").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim pushed a commit that referenced this pull request May 22, 2026
U+00B7 폭 폰트 metric 정합 — 비례폰트 .notdef 위장값 가드 (HaimLee-4869).
cmap .notdef → em_size 위장 메커니즘 정확 식별 + 3 조건 좁힘 가드
(U+00B7 + 전각 위장 + 비례폰트) + monospace 보존 (Issue #630 정합).
CI no checks reported (첫 fork PR 권한 정책) → 본 환경 직접 검증으로
대체. 시각 판정 면제 (PR #1044/#1054 패턴 — 정량 게이트 4 조건 충족).

본 환경 검증: cargo test --lib 1324 passed + 신규/기존 회귀 가드 +
svg_snapshot 8/8 통과. #1055 회귀와 무관 확인 (sample16-hwp5 에
U+00B7 0 건).

feedback_hancom_compat_specific_over_general 권위 사례.
feedback_image_renderer_paths_separate 정합 (native·WASM 공유 함수
가드).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim pushed a commit that referenced this pull request May 22, 2026
3 PR 본질 + 3 archives 통합 — author 보존 cherry-pick:
- PR #1054 (closes #1049, Jaeook Ryu): VPOS_CORR lazy_base trailing-ls
  bridge 정합. #1046 가설 반증 후 진짜 원인 (이중 차감) 정확 식별.
- PR #1059 (HaimLee-4869): U+00B7 폭 폰트 metric 정합 — 비례폰트
  .notdef 위장값 가드. native·WASM 공유 함수 가드.
- PR #1057 (Refs #536, seorii): CanvasKit direct replay contract harden
  (P17). 4 path 동시 정합 + Copilot 6/6 반영.

본 환경 cargo test --release --lib 1324 passed, 0 failed. CI 전부 pass.
시각 판정 면제 (모두 정량 게이트 충족) — 메모리 룰 후보 권위 사례
누적 (PR #1039#1044#1054#1059#1057 5 사례).

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants