두부 상자 영구 삭제, Noto Color Emoji에 별 삽입
출처: Dev.to
그 빈 □ 상자는 깨진 문자 — 그게 아니라 글리프가 없어서 나타나는 현상입니다. 저는 더 이상 SVG로 두부(토푸)를 패치하지 않고, 물리적으로 두부가 나올 수 없는 폰트를 만들었습니다.
보셨을 겁니다: 기호가 있어야 할 자리에 작은 빈 사각형이 나타나는 경우. 디자이너들은 이를 “두부(tofu)”라고 부릅니다. 텍스트 자체는 정상인데, 해당 코드포인트에 대한 글리프가 폰트에 없어서 브라우저가 사각형을 그려버리는 것이죠.
제가 관리 패널에서 “★ 와일드카드” 배지를 사용했을 때 이 문제가 발생했습니다. 별 대신에 □ 와일드카드가 표시됐죠.
폰트‑패밀리 스택은 문자마다 별도로 해결됩니다. 브라우저는 각 코드포인트에 대해 스택을 차례로 탐색해 해당 글리프를 가진 폰트를 찾습니다. 어느 것도 없으면 — 두부가 나타납니다.
함정은 미묘합니다: 이모지 폰트에는 텍스트용 딩뱃이 들어 있지 않다는 점입니다.
- ★ 은 U+2605 BLACK STAR — 텍스트 심볼입니다.
- ⭐ 은 U+2B50 — 이모지입니다.
제 스택은 Noto Color Emoji(셀프‑호스팅)로 끝났습니다. 그래서 모든 OS에서 동일하게 심볼이 렌더링됩니다. Noto에는 이모지 별은 있지만 텍스트 별은 없으므로, 브라우저는 ★ 를 이모지 폰트로 라우팅했지만 글리프를 찾지 못하고 사각형을 표시했습니다. 20줄짜리 글리프 뷰어로 확인해 보았습니다:
DelaGothicOne-Regular: U+2605 PRESENT
NotoColorEmoji.v2: U+2605 MISSING
문자를 인라인 ★ 로 교체하면 폰트 의존성이 사라지고 어디서든 렌더링됩니다. 하지만 수십 개 사이트에 걸쳐 모든 ★, →, ✓ 를 SVG로 교체하는 것은 현실적이지도 않고, 확장성도 없습니다.
거의 아무도 시도하지 않는 방법이 있습니다: 폰트는 편집이 가능하다는 점을 이용하는 것이죠. Noto에 ★ 가 없으면, 해당 글리프를 가지고 있는 다른 폰트(예: Dela Gothic One)에서 빌려와 fontTools 로 삽입합니다. 유일한 걸림돌은 단위 스케일링입니다. Dela는 1000 units/em, Noto는 1024 units/em이기 때문이죠.
scale = noto['head'].unitsPerEm / dela['head'].unitsPerEm # 1024/1000
pen = TTGlyphPen(None)
DecomposingRecordingPen(dela.getGlyphSet())[star].replay(
TransformPen(pen, (scale, 0, 0, scale, 0, 0))) # 스케일된 윤곽선
glyf.glyphs[name] = pen.glyph()
glyf.glyphOrder.append(name) # 글리프와 순서를 동기화
for t in noto['cmap'].tables:
if t.isUnicode():
t.cmap[0x2605] = name # 이제 U+2605 가 해결됨
noto.save('TrioEmojiStar.woff2')
가장 좋은 점은: 별이 COLR 컬러 레이어 없이 glyf 테이블에 들어가므로 currentColor 로 렌더링됩니다. 즉, 깔끔하고 테마에 맞게 색을 바꿀 수 있는 검은 별이 되며, 1,485개의 실제 이모지는 그대로 컬러를 유지합니다. 하나의 폰트에 모든 이모지와 별을 담아두면, 해당 코드포인트가 물리적으로 두부가 될 수 없게 됩니다.
두부는 절대 미스터리가 아닙니다. 글리프가 없을 뿐이며, 글리프는 언제든 추가할 수 있는 데이터일 뿐이죠.
원문은 trentontompkins.com에 처음 게시되었습니다. 키트(두 폰트 + 글리프 뷰어 + 폰트 포지) 를 다운로드하세요: never-tofu-font-kit.zip.