1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
# 004 — 글자: 양방향, 합성, 셰이핑을 빌드할 때 컴파일한 표로
2026-09-28. Pure 외부 피드백 002의 셋째 항목. [002](002-symbol-format.md)는 FreeType을 실행 중에서 빼고 글꼴을
빌드할 때 곡선 레코드로 바꿨다. 그 대가로 Vega는 코드 포인트 하나를 글리프 하나로 그렸다. 합자, 커닝, 아랍 문자의 위치별
형태, 결합 부호의 자리, 오른쪽에서 왼쪽으로 쓰는 글(양방향)이 없었다.
착수 기준:
- 바꿀 결정: 셰이핑을 실행 중에 OpenType 표(GSUB, GPOS)를 해석해서 할지(HarfBuzz의 방식), 빌드할 때 글꼴의 행동을
단순한 표로 컴파일해 두고 실행 중에는 검증한 표를 제자리에서 읽기만 할지. 심볼과 같은 원칙이면 뒤쪽이다.
- 남은 질문: 컴파일한 표만으로 HarfBuzz와 같은 글리프와 자리가 나오는가? 어느 문자 체계까지인가? 양방향과 합성은 유니코드의
적합성 시험을 모두 통과하는가?
- 최소 확인: 유니코드 15.1의 `BidiTest.txt`(49만 줄)와 `BidiCharacterTest.txt`(9.6만 줄), `NormalizationTest.txt`를 모두
통과한다. 셰이핑은 라틴(커닝, 합자), 아랍(위치별 형태, lam-alef, 결합 부호), 히브리(결합 부호) 문장에서 HarfBuzz 10.2와
글리프와 자리가 같다.
- 중단 기준: 적합성 시험에 틀린 줄이 하나라도 있으면 그 단계를 쓰지 않는다. 셰이핑이 HarfBuzz와 다른 문장은 원인을 찾을
때까지 그 문자 체계를 받지 않는다(빌드 도구가 거부한다).
## 단계
1. 유니코드 성질 표: UCD에서 생성한 두 단계 표(코드 포인트 → 값). [text/unicode.py](../../text/unicode.py)가
[text/unicode-data.c](../../text/unicode-data.c)를 만든다.
2. 양방향(UAX #9): 문단 수준, 명시적 수준과 격리(X1–X10), 약한 형(W1–W7), 괄호 쌍(N0), 중립(N1–N2), 암시적 수준(I1–I2),
줄(L1)과 보이는 순서(L2).
3. 정규화: 한글 음절과 정준 합성(NFC).
4. 셰이핑: 빌드 도구가 글꼴마다 HarfBuzz로 커닝 쌍, 합자, 위치별 형태, 결합 부호의 자리를 뽑아 심볼 파일에 넣는다. 실행 중에는
그 표를 찾아 쓴다.
5. 비례폭 글줄: 셰이핑한 글리프를 제 advance로 늘어놓아 그린다.
6. 접근성.
## 양방향
[text/bidi.c](../../text/bidi.c)는 UAX #9를 규칙 이름 그대로 짠다. 문단 수준(P2–P3), 명시적 수준과 방향 상태 스택(깊이
125, 넘친 격리·내장·유효 격리의 계수, X1–X8), 제거(X9)와 격리 실행 열(X10: 격리 시작자로 끝나는 실행은 짝 PDI로 시작하는
실행으로 이어지고, sos와 eos는 명시적 수준으로 정한다), 약한 형(W1–W7), 괄호 쌍(N0: 깊이 63의 스택, U+2329·232A와
U+3008·3009의 정준 동치, 바뀐 괄호 뒤의 결합 부호), 중립(N1–N2), 암시적 수준(I1–I2), 그리고 한 줄로서의 L1과 보이는
순서(L2)다. 성질은 UCD에서 만든 표다(양방향 클래스는 두 단계 표 37 KiB, 괄호 128개, 거울 글자 428개).
유니코드 15.1의 적합성 시험을 모두 통과한다. `BidiTest.txt`의 770,241 경우(클래스 열마다 비트 집합이 가리키는 문단 방향)와
`BidiCharacterTest.txt`의 91,707 경우(코드 포인트, 괄호 포함)에서 수준과 보이는 순서가 하나도 틀리지 않는다. Pi 5에서 전체가
0.74초다. 처음 짠 것은 148 경우가 틀렸다. 앞선 격리 실행 열의 암시적 수준(I1–I2)이 바꾼 수준으로 다음 열의 sos를 정했기
때문이다(sos와 eos는 명시적 수준으로 정해야 한다).
## 정규화
[text/normalize.c](../../text/normalize.c)는 NFD와 NFC다. 코드 포인트를 끝까지 분해하고(표에 다 풀어 둔 정준 분해 2,061개,
한글 음절은 산술로), 결합 등급으로 부호를 안정 정렬한 뒤, 마지막 기저 문자와 막히지 않은 문자를 합친다(원시 합성 941쌍,
합성 제외 목록 반영, 한글 L+V와 LV+T는 산술로). 코드 포인트 하나는 많아야 넷으로 풀린다(UCD 전체를 확인했다).
`NormalizationTest.txt`의 19,074줄(줄마다 NFC와 NFD 16가지 대조)과, 그 1부에 없는 코드 포인트 1,095,035개가 제 자신의
NFC이자 NFD라는 것을 모두 지킨다. 적합성 시험 셋을 합쳐 Pi 5에서 0.9초다.
|