증분 글꼴 전송

W3C 후보 권고안 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2025/CRD-IFT-20251118/
최신 공개 버전:
https://www.w3.org/TR/IFT/
편집자 초안:
https://w3c.github.io/IFT/Overview.html
이력:
https://www.w3.org/standards/history/IFT/
피드백:
public-webfonts-wg@w3.org 에 제목 줄을 “[IFT] … 메시지 주제 …”로 하여 보내십시오(보관 자료)
GitHub
구현 보고서:
https://wpt.fyi/results/IFT
편집자:
Chris Lilley (W3C)
(Google Inc.)
(Adobe Inc.)

초록

이 명세는 글꼴을 서버에서 클라이언트로 증분 전송하는 방법을 정의한다. 클라이언트는 실제로 필요한 글꼴의 일부만 로드하여 데이터 전송량을 크게 줄인다. 사용자가 여러 페이지를 탐색할 때 사용자 에이전트가 글꼴을 업데이트하는 것과 같이, 동일한 글꼴에 여러 번 증분 추가할 수 있다. 증분 전송은 레이아웃(커닝, 합자 등) 규칙의 손상을 방지함으로써 unicode-range를 개선하며, 라틴 문자와 인도계 문자 또는 아랍 문자 같은 복잡한 문자 체계에 대한 세분화된 증분을 효율적으로 지원할 수 있다.

이 문서의 상태

이 절에서는 발행 당시 이 문서의 상태를 설명한다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이 문서는 웹 글꼴 워킹 그룹권고안 트랙을 사용하여 후보 권고안 초안으로 발행했다.

이 문서는 초안이며 언제든지 다른 문서에 의해 업데이트되거나 대체되거나 폐기될 수 있다. 진행 중인 작업 이외의 것으로 이 문서를 인용하는 것은 적절하지 않다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받는다.

현재 구현 보고서는 없다. 테스트 스위트를 개발 중이다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹이 작성했다. W3C는 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허 공개 지침도 포함되어 있다. 필수 청구항을 포함한다고 판단되는 특허를 실제로 알고 있는 개인은 필수 청구항에 관한 정보를 W3C 특허 정책 제6절에 따라 공개해야 한다.

후보 권고안으로 발행되었다고 해서 W3C와 그 회원이 이를 승인했다는 의미는 아니다. 후보 권고안 초안은 워킹 그룹이 이후 후보 권고안 스냅샷에 포함하려는 이전 후보 권고안의 변경 사항을 통합한다.

1. 서론

이 절은 규범적이지 않다.

증분 글꼴 전송(IFT)은 웹에서 원격 글꼴(또는 "웹 글꼴")의 지연 시간을 개선하기 위한 기술이다. 이 기술이 없으면 브라우저는 해당 글꼴을 사용하여 문자를 렌더링하기 전에 글꼴의 모든 바이트를 다운로드해야 한다. IFT를 사용하면 브라우저가 파일의 일부 바이트만 다운로드할 수 있으므로, 브라우저가 글꼴이 필요하다는 것을 인식한 시점부터 필요한 텍스트를 해당 글꼴로 렌더링할 수 있는 시점까지의 체감 지연 시간이 감소한다. 기존 글꼴 서브셋 방식과 달리 증분 글꼴 전송은 세그먼트 간 레이아웃 규칙의 인코딩을 유지한다(점진적 글꼴 보강: 평가 보고서 § fail-subset).

WebFonts의 성공은 고르게 분포되어 있지 않다. 이 명세를 사용하면 느린 네트워크, 매우 큰 글꼴 또는 복잡한 서브셋 요구 사항 때문에 현재 사용할 수 없는 곳에서도 WebFonts를 사용할 수 있다. 예를 들어 WOFF 2 [WOFF2]를 사용하더라도 CJK 언어용 글꼴은 실용적으로 사용하기에 너무 클 수 있다.

1.1. 기술적 동기: 평가 보고서

이 명세로 이어진 조사는 점진적 글꼴 보강: 평가 보고서 [PFE-report]를 참조한다.

1.2. 개요

증분 글꼴은 증분 기능을 포함하도록 다시 형식화된 일반 OpenType 글꼴이며, 부분적으로 두 개의 추가 테이블을 사용한다. 이러한 새 테이블을 사용하면 패치를 로드하여 글꼴에 적용함으로써 글꼴을 확장할 수 있다(예: 더 많은 코드 포인트를 포함하도록).

IFT 기술에는 네 가지 주요 구성 요소가 있다:

개괄적으로 증분 글꼴은 다음과 같이 사용한다:

  1. 클라이언트는 전체 글꼴 버전의 일부 초기 데이터 서브셋과 글꼴을 확장하는 데 사용할 수 있는 패치 집합을 설명하는 내장 데이터가 포함된 초기 글꼴 파일을 다운로드한다.

  2. 렌더링할 콘텐츠를 기반으로 클라이언트는 추가 문자, 레이아웃 기능 및/또는 변형 공간을 포함하도록 글꼴을 확장하기 위해 패치를 선택하고 다운로드하고 적용한다. 이 단계는 새 콘텐츠가 생길 때마다 반복된다.

1.3. 증분 글꼴 만들기

증분 글꼴을 생성하는 가장 일반적인 방법은 기존 글꼴을 이 명세에 정의된 증분 인코딩을 사용하도록 변환하는 방식일 것으로 예상된다. 개괄적으로 기존 글꼴을 증분 글꼴로 변환하는 과정은 다음과 같다:

  1. 초기 서브셋의 콘텐츠를 선택한다. 이 콘텐츠는 클라이언트가 로드하는 초기 글꼴 파일에 포함되며 일반적으로 항상 필요할 것으로 예상되는 원래 글꼴의 모든 데이터로 구성된다.

  2. 패치 유형을 하나 이상 선택한다. 패치 유형마다 특성이 다르므로 서로 다른 사용 사례에는 서로 다른 패치 유형이 필요할 수 있으며, 경우에 따라 두 유형을 혼합할 수 있다.

  3. 글꼴의 세그먼트화를 선택한다. 개별 세그먼트는 패치를 통해 클라이언트가 기본 서브셋에 추가한다. 적절한 세그먼트화를 선택하는 것은 효율적인 인코딩을 생성하는 데 가장 중요한 부분 중 하나다.

  4. 이러한 선택을 기반으로 패치 집합을 생성한다. 각 패치는 초기 글꼴 파일 또는 이전 패치를 기준으로 특정 세그먼트의 데이터를 추가한다.

  5. 초기 서브셋과 패치 매핑을 포함하는 초기 글꼴 파일을 생성한다. 이 매핑에는 사용 가능한 모든 패치 파일, 패치 파일이 위치한 URL 및 패치가 글꼴에 추가할 데이터에 관한 정보가 나열된다.

참고: 이는 증분 글꼴 생성 과정을 매우 단순화한 설명이며, 인코딩 생성과 인코딩 요구 사항에 대한 자세한 논의는 § 7 인코딩 절에서 확인할 수 있다.

1.4. 성능 고려 사항과 증분 글꼴 전송의 사용

글꼴, 네트워크 및 렌더링되는 콘텐츠의 특성에 따라 증분 전송이 항상 유익한 것은 아닐 수 있다. 이 절에서는 증분 전송을 언제 사용해야 하는지 결정하는 데 도움이 되는 비규범적 지침을 제공한다.

증분 글꼴은 여러 패치의 병렬 로드를 유발하는 경우가 많다. 따라서 성능을 극대화하려면 증분 글꼴을 제공할 때 멀티플렉싱이 가능한 HTTP 서버(예: [rfc9113] 또는 [rfc9114])를 사용하는 것이 권장된다.

글꼴을 증분 방식으로 로드하는 것은 전체 글꼴을 로드하는 것과 근본적인 성능 절충 관계가 있다. 단순화하면 증분 전송에서는 전송되는 바이트 수가 줄어들 수 있지만, 전체 네트워크 요청 수가 증가하거나 요청 처리 지연 시간이 늘어날 수 있다. 일반적으로 더 적은 바이트를 전송하여 얻는 지연 시간 감소가 증분 전송 방법으로 인해 추가되는 지연 시간보다 큰 경우 증분 글꼴 전송이 유익하다.

가장 먼저 고려할 요소는 렌더링되는 콘텐츠의 언어다. 평가 보고서에는 세 가지 언어 범주에 걸쳐 증분 글꼴 전송을 시뮬레이션한 결과가 포함되어 있다 (점진적 글꼴 보강: 평가 보고서 § langtype). 언어 범주별 증분 글꼴 전송의 예상 성능에 관한 논의는 해당 보고서의 결론 점진적 글꼴 보강: 평가 보고서 § conclusions을 참조한다.

다음으로 글꼴 중 어느 정도가 필요할 것으로 예상되는가? 콘텐츠를 렌더링하는 데 글꼴의 대부분이 필요할 것으로 예상된다면 증분 글꼴 전송은 유익하지 않을 가능성이 높다. 그러나 많은 경우 글꼴의 일부만 필요할 것으로 예상된다. 예:

증분 전송의 대안은 글꼴을 서로 다른 서브셋(일반적으로 문자 체계별)으로 나누고 @font-face의 unicode range 기능을 사용하여 필요한 서브셋만 로드하는 것이다. 그러나 서로 다른 서브셋의 문자 간에 레이아웃 규칙이 있는 경우 일부 콘텐츠의 렌더링이 변경될 수 있다 점진적 글꼴 보강: 평가 보고서 § fail-subset. 증분 글꼴 전송은 원래 글꼴과 모든 레이아웃 규칙을 포함할 수 있으므로 이러한 문제가 없다.

1.4.1. 네트워크 요청 수 줄이기

이전 절에서 설명한 것처럼 증분 글꼴 전송의 가장 기본적인 구현은 기존 글꼴 로드와 비교하여 전체 요청 수를 늘리는 경향이 있다. 각 확장에는 일반적으로 최소 한 번의 왕복 시간이 필요하므로 너무 많은 요청이 발생하면 성능에 부정적인 영향을 줄 수 있다. 사용 가능한 패치 유형과 패치 매핑에 제공된 정보의 양에 따라 클라이언트는 현재 필요하지 않지만 향후 필요할 것으로 예상되는 코드 포인트에 대한 패치를 선제적으로 요청할 수 있다. 구현이 이 기능을 지능적으로 사용하면 전체 요청 수를 줄이는 데 도움이 된다. 평가 보고서는 기본 문자 빈도 기반 코드 포인트 예측 방식의 성능을 테스트하여 이를 조사했으며, 전체 성능이 개선됨을 확인했다.

2. 옵트인 메커니즘

웹 페이지는 ''@font-face'' 블록 안에서 CSS 글꼴 기술 키워드(CSS Fonts 4 § 11.1 글꼴 기술)를 사용하여 글꼴의 증분 전송 사용을 선택할 수 있다. incremental 키워드는 참조된 글꼴이 IFT 데이터를 포함하며 증분 글꼴 전송을 지원하는 사용자 에이전트에서만 로드해야 함을 나타내는 데 사용된다.

@font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont-Incremental.otf") tech(incremental);
}
@font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont-Incremental.otf") tech(incremental);
    unicode-range: U+0000-00FF;
}

두 번째 예에서 보인 것처럼 unicode-range는 IFT 글꼴과 함께 사용할 수 있다. 유니코드 범위는 완전히 확장된 글꼴의 지원 범위와 일치하도록 설정해야 한다. 이를 통해 클라이언트는 필요한 코드 포인트를 글꼴이 지원하지 않을 경우 IFT 글꼴을 로드하려는 시도를 피할 수 있다.

대안으로 글꼴 기술을 기반으로 선택할 수 있는 CSS supports 메커니즘을 사용할 수 있다:

@when font-tech(incremental) {
  @font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont-Incremental.otf");
  }
}
@else {
  @font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont.otf");
  }
}

참고: 각 개별 @font-face 블록은 IFT 사용을 선택할 수도 있고 선택하지 않을 수도 있다. 이는 웹 페이지에서 글꼴을 사용하는 방식이 다양하기 때문이다. 작성자는 이 기술을 사용할 글꼴과 사용하지 않을 글꼴을 제어할 수 있다.

참고: IFT 기술 키워드는 다른 글꼴 기술 지정자와 함께 사용하여 글꼴 기능을 선택할 수 있다. 예를 들어 @font-face에는 tech(incremental, color-COLRv1)이 있는 URL과 tech(incremental, color-COLRv0)이 있는 URL을 포함할 수 있다.

2.1. 오프라인 사용

경우에 따라 사용자 에이전트는 오프라인 사용을 위해 웹 페이지를 저장하려 할 수 있다. 저장된 페이지는 네트워크 연결이 없는 동안 표시될 수 있으므로 증분 글꼴이 참조하는 추가 패치를 요청할 수 없다. 콘텐츠가 변경될 경우(예: JavaScript 실행으로 인해) 증분 글꼴을 확장할 수 없으므로 페이지 저장 메커니즘은 글꼴 서브셋 완전히 확장을 호출하여 증분 글꼴을 완전히 확장하고 증분 글꼴 참조를 완전히 확장된 글꼴로 교체해야 한다.

3. 정의

3.1. 글꼴 서브셋

글꼴 서브셋은 다음 항목의 서브셋을 렌더링하는 데 필요한 데이터만 포함하도록 수정된 글꼴 파일 [iso14496-22] 버전이다:

원래 글꼴이 지원하는 항목이다. 올바르게 구성된 글꼴 서브셋을 사용하여 서브셋 코드 포인트, 레이아웃 기능 또는 디자인 변형 공간의 임의 조합으로 텍스트를 렌더링하면 원래 글꼴과 동일하게 렌더링된다. 여기에는 힌팅 명령과 같이 렌더러가 원래 글꼴에서 사용하도록 선택할 수 있는 모든 선택적 타이포그래피 기능을 사용한 렌더링이 포함된다. 디자인 변형 공간은 사용자 축 스케일을 사용하여 지정된다(OpenType 명세 § otvaroverview#coordinate-scales-and-normalization).

글꼴 서브셋 정의글꼴 서브셋이 지원하는 최소 데이터(코드 포인트, 레이아웃 기능, 변형 축 공간)를 설명한다.

참고: 편의를 위해 이 문서의 나머지 부분에서는 [iso14496-22]의 사본인 [open-type] 명세에 링크한다.

3.2. 글꼴 패치

글꼴 패치는 IFT로 인코딩된 글꼴에 적용할 변경 사항을 인코딩하는 파일이다. 패치는 기존 글꼴 서브셋을 확장하고 지원 범위를 넓히는 데 사용된다.

패치 형식글꼴 서브셋을 기준으로 적용할 변경 사항의 지정된 인코딩이다. 해당 형식에 따라 인코딩된 변경 사항 집합이 글꼴 패치다. 각 패치 형식에는 관련 패치 적용 알고리즘이 있으며, 이 알고리즘은 글꼴 서브셋패치 형식으로 인코딩된 글꼴 패치를 입력으로 받아 확장된 글꼴 서브셋을 출력한다.

3.3. 패치 맵

패치 맵OpenType 테이블로서, 글꼴 서브셋 정의에서 증분 글꼴을 확장하는 패치를 호스팅하는 URL로의 매핑 컬렉션을 인코딩한다. 패치 맵 테이블은 패치 맵 항목 목록을 인코딩하며, 각 항목에는 키와 값이 있다. 항목의 키는 항목의 지원 범위, 즉 어떤 서브셋 정의와 일치하는지에 관한 정보를 정의한다. 값은 항목이 일치할 때 적용해야 하는 패치에 관한 정보를 지정한다. 패치 맵 항목 요약:

  • 글꼴 서브셋 정의: 기본 지원 범위를 정의한다.

  • 0개 이상의 하위 패치 맵 항목에 대한 참조:
    이러한 하위 항목은 지원 범위를 확장하는 데 사용된다.

  • 논리곱 또는 논리합일 수 있는 하위 항목 일치 모드.

패치 맵 형식에 관한 자세한 내용은 § 5 글꼴 형식 확장에서 확인할 수 있다.

3.4. 데이터 유형 설명

이 명세의 나머지 부분에 있는 인코딩된 데이터 구조는 OpenType 명세 § otff#data-types에 정의된 데이터 유형을 기준으로 설명한다. OpenType의 나머지 부분과 마찬가지로 모든 필드는 "빅 엔디언" 바이트 순서를 사용한다.

4. 글꼴 서브셋 확장

이 절에서는 클라이언트가 증분 글꼴 서브셋을 확장하여 추가 코드 포인트, 레이아웃 기능 및/또는 디자인 공간을 포함하도록 하는 알고리즘을 정의한다. 이 알고리즘은 다음 단계를 반복하는 반복형 알고리즘이다:

이 과정은 관련 패치가 더 이상 남지 않을 때까지 반복된다. 패치 적용이 글꼴 파일에 내장된 패치 매핑을 변경할 수 있으므로 각 반복에서 현재 글꼴 서브셋 버전의 패치 맵을 다시 구문 분석하여 어떤 패치가 남아 있는지 확인한다. 따라서 각 반복에서 글꼴 서브셋은 사용 가능한 패치에 관한 신뢰할 수 있는 정보의 원천이며 확장 과정의 현재 상태를 완전히 캡슐화한다.

4.1. 패치 무효화

글꼴 서브셋에 내장된 패치 매핑은 각 패치에 대한 무효화 모드를 인코딩한다. 패치의 무효화 모드는 해당 패치를 적용한 후 더 이상 유효하지 않게 되는 다른 패치를 표시한다. 이 무효화 모드는 확장 알고리즘이 호환되는 패치를 결정하는 데 사용되며 선택 순서에 영향을 준다. 패치 적용 중 패치 유효성은 § 5.3 패치 맵 테이블의 호환성 ID로 강제된다. 모든 패치에는 패치를 나열하는 § 5.3 패치 맵 테이블의 호환성 ID와 일치해야 하는 호환성 ID가 인코딩되어 있다.

무효화 모드는 세 가지다:

특정 패치의 무효화 모드는 해당 형식 번호에 인코딩되며, 이는 § 6.1 형식 요약에서 확인할 수 있다.

4.2. 기본 레이아웃 기능

대부분의 텍스트 셰이퍼에는 항상 활성화되므로 증분 방식으로 로드되는 글꼴에 항상 필요한 레이아웃 기능 집합이 있다. 부록 A: 기본 기능 태그에는 작성 당시 일반적인 셰이퍼 구현에서 기본적으로 필요한 것으로 알려진 기능 목록이 수집되어 있다. 확장 알고리즘의 입력으로 글꼴 서브셋 정의를 구성할 때 클라이언트는 일반적으로 부록 A: 기본 기능 태그에 있는 모든 기능을 서브셋 정의에 포함해야 한다. 그러나 경우에 따라 클라이언트는 사용할 특정 셰이퍼가 부록 A: 기본 기능 태그의 일부 기능을 사용하지 않는다는 것을 알 수 있으며, 사용되지 않는 해당 기능을 서브셋 정의에서 제외하도록 선택할 수 있다.

4.3. 증분 글꼴 확장 알고리즘

다음 알고리즘은 클라이언트가 증분 글꼴 서브셋을 확장하여 추가 코드 포인트, 레이아웃 기능 및/또는 디자인 공간을 포함하도록 하는 데 사용된다. 이 알고리즘은 필요할 때 패치를 로드하면서 한 번에 하나씩 패치를 선택하여 글꼴에 적용한다. 네트워크 왕복을 최소화하기 위한 중요한 최적화로서 최종적으로 필요하게 될 모든 패치의 로드를 시작할 수 있도록 허용한다. 이는 두 가지 형태로 이루어진다:

증분 글꼴 서브셋 확장

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. extended font subsetfont subset으로 설정한다.

  2. extended font subset에서 'IFT ' 및 'IFTX'(있는 경우) 매핑 테이블을 로드한다. 두 테이블은 모두 § 5.3 패치 맵 테이블로 형식화되어 있다. § 5.3 패치 맵 테이블의 요구 사항에 따라 유효한지 확인한다. 어느 테이블이든 유효하지 않으면 오류 처리를 호출한다. extended font subset에 'IFT ' 테이블이 없으면 증분 글꼴이 아니며 확장할 수 없으므로 extended font subset을 반환한다.

  3. 'IFT '의 호환성 ID가 'IFTX'의 호환성 ID와 같으면 오류이므로 오류 처리를 호출한다.

  4. 'IFT ' 및 'IFTX'(있는 경우) 테이블 각각에 대해 형식 1 패치 맵 해석 또는 형식 2 패치 맵 해석을 호출하여 테이블을 항목 목록으로 변환한다. 반환된 항목 목록을 하나의 목록 entry list로 연결한다.

  5. entry list의 각 entry에 대해 entrytarget subset definition을 입력으로 하여 항목 교차 확인을 호출한다. false를 반환하면 entryentry list에서 제거한다. 또한 이 알고리즘 실행 중 이전에 로드되고 적용된 패치 URL 문자열을 가진 모든 항목을 entry list에서 제거한다.

  6. entry list가 비어 있으면 확장 작업이 완료된 것이므로 extended font subset을 반환한다.

  7. entry list의 항목을 각 항목의 패치 형식 무효화 모드에 따라 세 목록으로 그룹화한다: full invalidation entry list, partial invalidation entry list, no invalidation entry list.

  8. 다음 절차로 entry 하나를 선택한다:

    • full invalidation entry list가 비어 있지 않으면 포함된 항목 중 정확히 하나를 선택한다. 단일 항목을 선택하려면 § 4.4 무효화 패치 선택의 기준을 따른다.

    • 그렇지 않고 partial invalidation entry list가 비어 있지 않으면 포함된 항목 중 정확히 하나를 선택한다. 단일 항목을 선택하려면 § 4.4 무효화 패치 선택의 기준을 따른다.

    • 그렇지 않으면 패치 맵에서 가장 먼저 나열된 no invalidation entry list의 항목을 선택한다. § 5.3.1 패치 맵 테이블: 형식 1에서는 항목 인덱스가 가장 낮은 항목이다. § 5.3.2 패치 맵 테이블: 형식 2에서는 entries 배열에서 가장 먼저 나타나는 항목이다. IFT와 IFTX 테이블의 항목이 모두 후보라면 IFT의 모든 항목이 IFTX의 항목보다 앞에 있는 것으로 간주한다.

  9. initial font URL을 초기 글꼴 URL로, entry의 첫 번째 패치 URL 문자열을 패치 URL 문자열로 하여 패치 파일 로드를 호출함으로써 patch file의 로드를 시작한다(이전에 시작되지 않은 경우). entry에 다른 URL 문자열이 있으면 동일한 절차로 해당 로드도 시작한다. 이는 이 알고리즘의 향후 반복에서 사용될 수 있다. 또한 클라이언트는 동일한 절차를 사용하여 entry에 의해 무효화되지 않는 entry list의 항목에 대한 로드를 선택적으로 시작할 수 있다. 단일 실행 중 클라이언트가 로드하고 적용할 수 있는 패치의 총수는 다음으로 제한된다:

    이 알고리즘을 한 번 호출하는 동안 로드하고 적용할 수 있다. 어느 수치든 초과되면 오류이므로 오류 처리를 호출한다.

  10. patch file 로드가 완료되면 § 6 글꼴 패치 형식의 적절한 적용 알고리즘(entry의 패치 형식과 일치)을 사용하여 패치 URL 문자열과 entry의 호환성 ID를 사용해 patch fileextended font subset에 적용한다. patch file 로드에서 오류가 발생하면 오류 처리에 따라 처리한다.

  11. 2단계로 이동한다.

참고: 9단계에서 클라이언트는 현재 선택한 항목에 의해 무효화되지 않는 패치의 로드를 병렬로 선택적으로 시작할 수 있다. 이러한 패치는 무효화되지 않으므로 이후 반복에서 거의 항상 필요하며, 병렬로 로드하면 왕복을 제거하여 성능이 크게 향상된다. 이러한 방식으로 로드를 시작할 때 요청 시작 순서는 8단계에 지정된 순서를 따라야 한다.

참고: 남아 있는 교차 항목이 모두 무효화 없음 항목이면 5단계의 교차 확인을 후속 반복에서 반복할 필요가 없다. 이는 무효화 없음 패치를 적용해도 자체 항목을 제거하는 것 외에는 사용 가능한 패치 목록이 변경되지 않기 때문이다. 또한 최적화로 클라이언트는 남아 있는 교차 비무효화 항목의 패치 적용을 단일 일괄 작업으로 수행할 수 있다. 글리프 키 기반 패치의 특성상 여러 패치를 순차적으로 적용한 최종 결과를 한 번의 패스로 구성하기가 간단하다. 이렇게 하면 각 개별 패치마다 새로운 glyf/loca/CFF/CFF2 테이블을 반복해서 다시 합성하는 것을 방지하여 필요한 전체 계산량을 크게 줄일 수 있다.

확장 알고리즘의 실행 예는 부록 B: 확장 알고리즘 실행 예제에서 확인할 수 있다.

항목 교차 확인

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. subset definition의 각 집합(코드 포인트, 기능 태그, 디자인 공간)에 대해 해당 집합이 mapping entry의 서브셋 정의에 있는 대응 집합과 교차하는지 확인한다. 집합은 다음 조건에서 교차한다:

    서브셋 정의 집합이 비어 있음 서브셋 정의 집합이 비어 있지 않음
    매핑 항목 집합이 비어 있음 true true
    매핑 항목 집합이 비어 있지 않음 false 두 집합이 교차하면 true

    디자인 공간 집합의 교차를 확인할 때 교차하는 세그먼트 쌍이 하나 이상 있으면 교차한다(태그가 같고 범위가 교차함).

  2. 1단계에서 확인한 하나 이상의 집합이 교차하지 않으면 intersects에 대해 false를 반환한다.

  3. mapping entry에 하위 항목이 없으면 intersects에 대해 true를 반환한다.

  4. mapping entry에서 참조하는 각 하위 항목에 대해 subset definition을 입력으로 하여 항목 교차 확인을 호출한다. 하위 항목 일치 모드가 논리곱이면 모든 호출이 true를 반환하는 경우에만 intersects에 대해 true를 반환한다. 그렇지 않으면 하나 이상의 호출이 true를 반환하는 경우에만 true를 반환한다.

아래 표는 패치 매핑을 나타내며 다양한 항목에 대한 교차 확인의 예상 결과를 보여 준다. 이 예에서 집합(즉, 코드 포인트, 기능 태그, 디자인 공간, 하위 항목)이 지정되지 않으면 빈 집합으로 간주한다.

인덱스 매핑 항목 서브셋 정의 교차하는가?
0
subset definition {
  code points: {1, 2, 3},
},
match mode: disjunctive,
code points: {2},
true
1
subset definition {
  code points: {4, 5, 6},
},
match mode: disjunctive,
code points: {2},
false
2
subset definition {
  code points: {1, 2, 3},
},
match mode: disjunctive,
code points: {2},
feature tags: {smcp},
true
3
subset definition: {
  code points: {1, 2, 3},
},
match mode: disjunctive,
feature tags: {smcp},
false
4
subset definition: {
  code points: {1, 2, 3},
},
child entry indices: {1},
match mode: disjunctive,
code points: {5},
false
5
subset definition: {
},
child entry indices: {0, 1},
match mode: conjunctive,
code points: {2},
false
6
subset definition: {
},
child entry indices: {0, 1},
match mode: conjunctive,
code points: {2, 6},
true

패치 파일 로드

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. URL 표준 § url-parsing을 사용하여 patch URL stringURL 레코드로 구문 분석한다. initial font URL기본 URL이고 인코딩은 UTF-8이다. 결과를 target URL에 저장한다. URL 구문 분석에 실패하면 오류를 반환한다.

  2. 구현 사용자 에이전트의 가져오기 기능을 사용하여 target URL의 콘텐츠를 가져온다. 웹 브라우저에서는 [FETCH]를 사용해야 한다. [FETCH]를 사용할 때 요청은 다음과 같이 구성한다:

    • method를 GET으로 설정한다.

    • urltarget URL로 설정한다.

    • clientinitial font URL을 가져오는 데 사용한 요청 객체의 클라이언트로 설정한다.

    • initiator type을 "font"로 설정한다.

    • destination을 "font"로 설정한다.

    • referrerinitial font URL로 설정한다.

    • mode를 "cors"로 설정한다.

    processResponseConsumeBody가 이 알고리즘의 3단계인 requestFetch한다.

    [FETCH]가 아닌 구현의 경우 사용 가능한 가져오기 기능을 사용하여 target URL을 요청한다. 동등한 개념이 존재하는 경우 위에 지정된 [FETCH] 기반 설정을 복사한다. 해당 가져오기 결과로 3단계를 진행한다.

  3. processResponseConsumeBody에는 응답과 null, failure 또는 바이트 시퀀스가 전달된다. 바이트 시퀀스를 받으면 해당 바이트를 patch file로 반환한다. null을 받으면 빈 바이트 배열을 patch file로 반환한다. 그렇지 않으면 오류를 반환한다.

참고: 가져오기 설정은 CSS 글꼴 로드에 사용되는 설정 CSS Fonts 4 § 4.8.2 글꼴 가져오기 요구 사항과 일치하도록 하는 것을 목표로 하지만 두 가지 차이가 있다. 첫째, referrer는 초기 글꼴의 URL로 설정되고 둘째, URL 확인은 스타일시트 대신 초기 글꼴을 기본 URL로 사용한다.

오류 처리

글꼴 서브셋 확장 과정이 오류로 실패하면 글꼴 내 일부 데이터가 완전히 로드되지 않을 수 있으며, 그 결과 누락된 데이터에 의존하는 콘텐츠를 렌더링하면 잘못된 렌더링이 발생할 수 있다. 클라이언트는 글꼴을 계속 사용하도록 선택할 수 있지만 § 4.6 글꼴이 렌더링할 수 있는 콘텐츠 결정에 따라 완전히 로드된 코드 포인트, 기능 및 디자인 공간을 렌더링하는 데만 사용해야 한다. 다른 모든 콘텐츠는 일반적인 클라이언트 대체 논리에 따라 다른 글꼴로 대체하여 렌더링해야 한다.

패치 파일 로드 중 오류가 발생한 경우 클라이언트는 글꼴 서브셋 확장을 계속 시도할 수 있다. 증분 글꼴 서브셋 확장의 8단계에서 각 무효화 그룹 내에서 로드에 실패한 패치는 선택에서 제외한다. 무효화 그룹이 비어 있지 않고 해당 그룹에서 선택해야 하지만 실패한 패치만 포함하면 확장이 실패한 것이며 계속할 수 없다.

그 밖의 모든 오류가 발생한 경우 클라이언트는 글꼴 서브셋을 더 확장하려고 시도해서는 안 된다.

4.4. 무효화 패치 선택

증분 글꼴 서브셋 확장 알고리즘을 실행하는 동안 경우에 따라 후보 항목 목록에서 단일 무효화(전체 또는 부분) 패치 항목을 선택해야 한다. 사용되는 선택 기준은 확장을 수행하는 데 필요한 전체 왕복 횟수에 직접적인 영향을 준다. 왕복은 비용이 크므로 성능을 극대화하려면 필요한 총 왕복 횟수를 최소화하는 방식으로 패치를 선택해야 한다.

다음 선택 기준은 왕복 횟수를 최소화하며 클라이언트는 증분 글꼴 서브셋 확장의 8단계에서 단일 부분 또는 전체 무효화 패치를 선택할 때 이 기준을 사용해야 한다:

  1. 하나 이상의 후보 항목에 연결된 패치 파일이 이전에 증분 글꼴 서브셋 확장의 9단계에 의해 로드된 경우, 다음 단계에서는 패치 파일이 이미 로드되었거나 현재 로드 중인 후보 항목만 고려한다. 그렇지 않으면 모든 후보 항목을 고려한다.

  2. 각 후보 항목에 대해 해당 항목의 서브셋 정의와 참조된 하위 항목 그래프를 통해 도달할 수 있는 모든 하위 항목의 서브셋 정의를 합집합하여 전체 서브셋 정의를 계산한다.

  3. 각 후보 항목에 대해 전체 서브셋 정의와 대상 서브셋 정의의 집합 교차를 계산한다.

  4. 2단계의 교차가 다른 어떤 교차의 진부분집합도 아닌 항목을 찾는다.

  5. 동일한 패치 맵에 있고 3단계에서 찾은 항목과 동일한 교차를 갖는 추가 항목을 찾는다. 이 항목 집합(3단계 선택 포함)에서 최종 선택은 패치 맵에 가장 먼저 나열된 항목이다. § 5.3.1 패치 맵 테이블: 형식 1에서는 항목 인덱스가 가장 낮은 항목이다. § 5.3.2 패치 맵 테이블: 형식 2에서는 entries 배열에 가장 먼저 나타나는 항목이다.

참고: 3단계의 기준을 충족하는 항목을 빠르고 효율적으로 찾는 방법은 코드 포인트 집합 교차의 크기, 기능 태그 집합 교차의 크기, 마지막으로 디자인 공간 교차의 크기를 기준으로 항목을 내림차순 정렬하는 것이다. 이 정렬의 첫 번째 항목은 다른 항목의 진부분집합일 수 없다. 진상위집합은 적어도 하나의 항목이 더 커야 하기 때문이다. 이 방식은 클라이언트가 현재 요청하는 데이터를 가장 많이 추가하는 패치를 선택한다는 추가적인 이점도 있다.

4.5. 대상 서브셋 정의

증분 글꼴 서브셋 확장 알고리즘은 클라이언트가 렌더링하려는 콘텐츠를 기반으로 한 대상 서브셋 정의를 입력으로 받는다. 클라이언트는 콘텐츠 전체에 대해 하나의 서브셋 정의를 구성하고 확장 알고리즘을 한 번 실행하도록 선택할 수 있다. 또는 콘텐츠를 더 작은 범위로 나누고 각 범위에 대한 서브셋 정의를 구성한 뒤 각각의 더 작은 서브셋 정의에 대해 확장 알고리즘을 실행할 수 있다. 다음 조건을 충족하는 한 두 방식 모두 최종적으로 전체 콘텐츠를 동일하게 렌더링하는 글꼴을 생성한다:

4.6. 글꼴이 렌더링할 수 있는 콘텐츠 결정

초기 글꼴이든 부분적으로 확장된 글꼴이든 어떤 증분 글꼴이 주어졌을 때 클라이언트는 해당 글꼴이 현재 상태에서 어떤 콘텐츠를 렌더링할 수 있는지 알고자 할 수 있다. 이는 클라이언트가 텍스트의 어느 부분에 대체 글꼴을 사용할지 결정하려는 경우 특히 중요하다.

대체 처리 중 클라이언트는 일반적으로 글꼴의 cmap 테이블을 확인하여 어떤 코드 포인트가 지원되는지 결정한다. 그러나 IFT 글꼴에서는 § 6.3 글리프 키 기반 패치의 작동 방식 때문에 cmap 테이블에 아직 대응하는 글리프 데이터가 로드되지 않은 코드 포인트의 매핑이 포함될 수 있다. 따라서 클라이언트는 코드 포인트 존재 여부를 결정할 때 cmap 테이블에만 의존해서는 안 된다. 대신 다음 절차를 사용하여 증분 글꼴이 어떤 콘텐츠 부분을 렌더링할 수 있는지 확인할 수 있다:

클라이언트는 셰이핑 단위보다 더 세분화된 수준에서 글꼴이 무엇을 렌더링할 수 있는지도 알고자 할 수 있다. 다음 의사 코드는 위 검사를 통과하지 못한 셰이핑 단위를 증분 글꼴을 사용하여 렌더링할 수 있는 범위로 나누는 가능한 방법을 보여 준다:

# shaping_unit 안에서 ift_font가 지원하고 안전하게 렌더링할 수 있는
# [start, end] 포함 범위 목록을 반환한다.
#
# shaping_unit은 각 항목에 코드 포인트, 연결된 레이아웃 기능 목록 및 해당 코드 포인트를
# 렌더링하는 디자인 공간 포인트가 포함된 배열이다.
def supported_spans(shaping_unit, ift_font):
  current_start = current_end = current_subset_def = None
  supported_spans = []

  i = 0
  while i < shaping_unit.length():
    if current_subset_def is None:
      current_subset_def = SubsetDefinition()
      current_start = i

    current_end = i
    current_subset_def.add(shaping_unit.codepoint_at(i),
                           shaping_unit.features_at(i),
                           shaping_unit.design_space_point_at(i))

    if supports_subset_def(ift_font, current_subset_def):
      i += 1
      continue

    if current_end > current_start:
      supported_spans.append(Span(current_start, current_end - 1))
      # 다음 반복에서 현재 코드 포인트를 단독으로 확인할 수 있도록 i를 증가시키지 않는다.
    else:
      i += 1

    current_start = current_end = current_subset_def = None

  return supported_spans


# ift_font가 subset_def에 포함된 콘텐츠의 렌더링을 지원하면 true를 반환한다.
def supports_subset_def(ift_font, subset_def):
  # 다음 두 검사가 모두 true인 경우에만 true를 반환한다:
  # - subset_def의 각 코드 포인트가 ift_font의 cmap 테이블에 의해 '0' 이외의 글리프 id에 매핑된다.
  # - subset_def를 사용하여 ift_font에 "증분 글꼴 서브셋 확장" 알고리즘을 실행하고 6단계에서 중지한 후
  #   항목 목록이 비어 있다.

반환된 범위 중 하나에 포함되지 않는 셰이핑 단위의 텍스트는 증분 글꼴에서 지원되지 않으며 대체 글꼴로 렌더링해야 한다. 각 범위는 독립적으로 셰이핑해야 한다(즉, 각 범위가 새로운 셰이핑 단위가 됨). 이 방법은 셰이핑 단위를 나누므로 다중 코드 포인트 치환과 같은 원래 글꼴의 모든 기능이 제공되지 않을 수 있다. 클라이언트가 증분 글꼴 서브셋 확장 알고리즘을 § 4.5 대상 서브셋 정의에 따라 구성된 서브셋 정의로 올바르게 따르고 있다면 누락된 데이터가 로드되며 이 경우는 관련 패치가 로드되는 동안에만 일시적으로 발생한다. 누락된 패치가 도착하여 적용되면 치환 결과로 영향을 받는 코드 포인트의 렌더링이 변경될 수 있다.

참고: 위의 "supported_spans(...)" 검사는 증분 글꼴 확장을 구동하는 데 사용하기 위한 것이 아니다. 증분 글꼴 서브셋 확장 실행을 위한 대상 서브셋 정의 구성 지침은 § 4.5 대상 서브셋 정의에 제공된다.

4.7. 글꼴 완전히 확장하기

이 절에서는 증분 글꼴을 완전히 확장된 비증분 글꼴로 변환하는 데 사용할 수 있는 알고리즘을 정의한다. 이 과정은 증분 글꼴이 제공하는 사용 가능한 모든 데이터를 로드하고 더 이상 적용할 패치가 없는 하나의 정적 글꼴 파일을 생성한다.

글꼴 서브셋 완전히 확장

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. font subset을 사용하여 증분 글꼴 서브셋 확장을 호출한다. 입력 대상 서브셋 정의는 항목 교차 확인 단계에서 모든 항목과 교차하는 것으로 간주되는 특수한 정의다. 결과 글꼴 서브셋을 expanded font으로 반환한다.

4.8. 확장된 증분 글꼴 캐싱

확장된 증분 글꼴에는 이 절의 절차에 따라 향후 확장 작업을 수행하는 데 필요한 모든 상태가 포함되어 있다. 따라서 클라이언트가 향후 사용을 위해 증분 글꼴을 저장하거나 캐시해야 하는 경우 가장 최근 확장 알고리즘 적용으로 생성된 글꼴 바이너리만 저장하면 충분하다. 초기 글꼴이나 이전 확장에서 생성된 버전을 유지할 필요가 없다.

5. 글꼴 형식 확장

증분 글꼴은 기존 OpenType 형식을 따르지만, 4바이트 태그 'IFT ' 및 'IFTX'로 식별되는 두 개의 새 테이블을 포함한다. 이 새 테이블은 모두 패치 맵이다. 모든 증분 글꼴에는 최소한 'IFT ' 테이블이 포함된다. 'IFTX' 테이블은 선택 사항이다. 두 테이블이 모두 존재하면 글꼴 전체의 매핑은 두 테이블 매핑의 합집합이다. 두 새 테이블은 이 명세에서만 사용되며 OpenType 명세에는 추가되지 않는다.

참고: 매핑을 두 개의 서로 다른 테이블로 분할할 수 있으면 증분 글꼴이 여러 패치 유형을 더 쉽게 사용할 수 있다. 예를 들어 한 유형의 모든 패치는 'IFT ' 테이블에 지정하고 두 번째 유형의 모든 패치는 'IFTX' 테이블에 지정할 수 있다. 해당 패치는 매핑 테이블 중 하나만 업데이트하여 충돌하는 업데이트를 피할 수 있다.

5.1. 증분 글꼴 전송과 글꼴 압축 형식

웹에서 글꼴을 사용할 때 [WOFF] 또는 [WOFF2]와 같은 압축 형식으로 압축하는 것이 일반적이다. 다음 조건을 충족하는 한 이러한 형식을 사용하여 증분 글꼴 전송 인코딩에 사용되는 초기 글꼴 파일을 압축할 수 있다:

  1. 압축 형식을 통해 글꼴을 인코딩한 다음 디코딩하는 과정에서 각 테이블의 바이트가 변경되지 않는다.

  2. 증분 글꼴 전송 확장 알고리즘(§ 4 글꼴 서브셋 확장)은 압축되지 않은 글꼴 파일에서만 작동하므로 압축된 글꼴은 확장하기 전에 디코딩해야 한다.

[WOFF2]의 경우 특별한 주의가 필요하다. 증분 글꼴을 전송을 위해 WOFF2로 인코딩하는 경우:

  1. WOFF2 인코딩에 변환된 glyf 및 loca 테이블(WOFF 2.0 § 5.1 변환된 glyf 테이블 형식)이 포함되는 경우 증분 글꼴에는 glyf 또는 loca 테이블을 수정하는 § 6.2 테이블 키 기반 패치가 포함되어서는 안 된다. WOFF2 형식은 변환된 glyf 및 loca 테이블을 디코딩한 결과의 구체적인 바이트를 보장하지 않는다. § 6.3 글리프 키 기반 패치는 변환된 glyf 및 loca 테이블과 함께 사용할 수 있다.

  2. 'IFT ' 및 'IFTX' 테이블은 WOFF 2.0 § 5 압축 데이터 형식에 정의된 표준 절차에 따라 WOFF2 인코더가 처리하고 brotli로 인코딩할 수 있다.

참고: glyf/loca 변환을 비활성화해도 WOFF2 압축이 WOFF보다 우수하므로 일반적으로 IFT 글꼴은 WOFF2를 사용하여 압축하는 것이 권장된다. 인코딩이 테이블 키 기반 패치를 사용하여 해당 테이블을 업데이트하는 경우 glyf/loca 변환은 비활성화한다.

5.2. CFF 및 CFF2 증분 글꼴

CFF 또는 CFF2 테이블에 저장된 글리프 윤곽선을 포함하는 증분 글꼴에는 다음과 같은 추가 제한이 있다:

이 세 요구 사항을 통해 CFF 및 CFF2 테이블에서 글리프 키 기반 패치 적용 구현을 크게 단순화할 수 있다. CFF/CFF2 테이블에 인코딩된 다른 데이터 요소의 오프셋을 변경하지 않고 글리프 데이터를 삽입할 수 있다. 저장된 CFF/CFF2 오프셋을 사용하면 클라이언트가 CFF/CFF2 테이블의 다른 부분을 구문 분석하지 않고도 CharStrings INDEX를 찾을 수 있다.

참고: 경우에 따라 테이블 키 기반 패치가 CFF 또는 CFF2 테이블을 추가하거나 변경할 수 있다. 이 경우 패치는 새 콘텐츠 또는 변경된 콘텐츠를 반영하도록 charstrings 오프셋도 추가하거나 업데이트해야 한다.

CFF 또는 CFF2 서브루틴화는 증분 글꼴 전송과 호환된다. 그러나 단순한 서브루틴화는 초기 파일 크기를 늘리는 대신 패치 크기를 줄이는 경향이 있다. 또한 WOFF2는 서브루틴화된 글꼴보다 서브루틴화되지 않은 글꼴을 더 효과적으로 압축하는 것으로 자주 나타났다(압축되지 않은 파일이 훨씬 커지는 대가로). 따라서 IFT의 구체적인 요구에 맞게 서브루틴화를 피하거나 적당히 사용하거나 맞춤화하는 것이 권장된다.

5.3. 패치 맵 테이블

패치 맵은 두 형식 중 하나로 인코딩된다:

각 형식은 해당 형식으로 인코딩된 바이트를 해석하여 나타내는 항목 목록을 생성하는 알고리즘을 정의한다. 증분 글꼴 서브셋 확장 알고리즘은 해석 알고리즘을 호출하고 결과 항목 목록에서 작동한다. 인코딩된 바이트는 항상 패치 맵에 관한 신뢰할 수 있는 정보의 원천이다. 서브셋 확장 중 패치를 적용하면 패치 맵의 인코딩된 바이트가 변경되고 그 결과 인코딩된 바이트에서 파생된 항목 목록도 변경된다. 확장 알고리즘은 각 반복 시작 시 인코딩된 바이트를 다시 해석하여 이전 반복에서 이루어진 모든 변경 사항을 반영한다.

5.3.1. 패치 맵 테이블: 형식 1

형식 1 패치 맵 인코딩:

유형 이름 설명
uint8 format 1로 설정하며 형식 1임을 식별한다.
uint24 reserved 사용하지 않으며 0으로 설정한다.
uint8 flags 선택적 필드의 존재를 알리는 플래그. 비트 0(최하위 비트)이 설정되면 cffCharStringsOffset이 존재한다. 비트 1(최하위 비트)이 설정되면 cff2CharStringsOffset이 존재한다.
uint32 compatibilityId[4] 이 글꼴과 호환되는 패치를 식별하는 데 사용되는 고유 ID(§ 4.1 패치 무효화 참조). 인코더가 이 값을 선택한다. 인코더는 IFT 글꼴을 인코딩하는 동안 이전에 사용되지 않은 무작위 값으로 설정해야 한다.
uint16 maxEntryIndex 이 테이블에 인코딩된 가장 큰 항목 인덱스.
uint16 maxGlyphMapEntryIndex 이 테이블에 인코딩된 가장 큰 글리프 맵 항목 인덱스. maxEntryIndex보다 작거나 같아야 한다.
uint24 glyphCount 매핑이 제공되는 글리프 수. 글꼴 파일의 글리프 수와 일치해야 한다.

참고: 글꼴의 글리프 수는 글꼴 파일에 인코딩된다. 작성 당시 이 값은 maxp 테이블에 나열되어 있지만 향후 글꼴 형식 확장은 글리프 수 값을 인코딩하기 위해 다른 테이블을 사용할 수 있다.

Offset32 glyphMapOffset 글리프 맵 하위 테이블에 대한 오프셋. 오프셋은 이 테이블의 시작을 기준으로 한다.
Offset32 featureMapOffset 기능 맵 하위 테이블에 대한 오프셋. 오프셋은 이 테이블의 시작을 기준으로 한다. null(0)일 수 있다.
uint8 appliedEntriesBitMap[(maxEntryIndex + 8)/8] 어떤 항목이 적용되었는지 추적하는 비트 맵. 비트 i가 설정되면 항목 i의 패치가 이 글꼴에 적용되었음을 나타낸다. 비트 0은 appliedEntriesBitMap[0]의 최하위 비트이고 비트 7은 최상위 비트다. 비트 8은 appliedEntriesBitMap[1]의 최하위 비트이며 이후에도 동일하다.
uint16 urlTemplateLength urlTemplate 바이트 배열의 길이.
uint8 urlTemplate[urlTemplateLength] 각 항목과 연결된 URL 문자열을 생성하는 데 사용되는 URL 템플릿을 포함하는 바이트 배열.
uint8 patchFormat urlTemplate로 연결된 패치의 형식을 지정한다. § 6.1 형식 요약 표의 형식 번호 중 하나로 설정해야 한다.
uint32 cffCharStringsOffset flags의 비트 0(최하위)이 설정된 경우에만 존재한다. CFF 테이블의 시작에서 CFF 테이블의 CharStrings INDEX 데이터 구조까지의 오프셋을 제공한다.
uint32 cff2CharStringsOffset flags의 비트 1이 설정된 경우에만 존재한다. CFF2 테이블의 시작에서 CFF2 테이블의 CharStrings INDEX 데이터 구조까지의 오프셋을 제공한다.

참고: glyphCount는 65,535개를 초과하는 글리프를 허용하는 제안된 향후 글꼴 형식 확장과 호환되도록 설계되었다.

글리프 맵 인코딩:

글리프 맵 테이블은 글꼴의 각 글리프 인덱스를 항목 인덱스와 연결한다.

유형 이름 설명
uint16 firstMappedGlyph firstMappedGlyph보다 작은 모든 글리프 인덱스는 암시적으로 항목 인덱스 0에 매핑된다.
uint8/uint16 entryIndex[glyphCount - firstMappedGlyph] 글리프 i의 항목 인덱스는 entryIndex[i - firstMappedGlyph]에 저장된다. 배열 구성원은 maxEntryIndex가 256보다 작으면 uint8이고, 그렇지 않으면 uint16이다.

기능 맵 인코딩:

기능 맵 테이블은 기능 태그와 글리프의 조합을 항목 인덱스와 연결한다.

유형 이름 설명
uint16 featureCount featureRecords의 수.
FeatureRecord featureRecords[featureCount] 특정 기능 태그에 대한 매핑을 제공한다. featureRecordsfeatureTag를 기준으로 오름차순 정렬되며 각 기능 태그는 최대 한 번만 나타난다. 정렬 시 태그 값은 4바이트 빅 엔디언 부호 없는 정수로 해석하고 정수 값으로 정렬한다.
EntryMapRecord entryMapRecords[variable] 각 기능 매핑의 키(항목 인덱스)를 제공한다. entryMapRecords 배열은 featureRecords 배열의 entryMapCount 필드 합계만큼 항목을 포함한다. entryMapRecords[0]은 featureRecords[0]의 첫 번째 항목에 대응하고, entryMapRecords[featureRecord[0].entryMapCount]는 featureRecords[1]의 첫 번째 항목에 대응하며, entryMapRecords[featureRecords[0].entryMapCount + featureRecord[1].entryMapCount]]는 featureRecords[2]의 첫 번째 항목에 대응하는 식이다.

FeatureRecord 인코딩:

유형 이름 설명
Tag featureTag 이 매핑이 적용되는 기능 태그.
uint8/uint16 firstNewEntryIndex maxEntryIndex가 256보다 작으면 uint8, 그렇지 않으면 uint16이다. 이 레코드가 매핑하는 첫 번째 항목 인덱스.
uint8/uint16 entryMapCount maxEntryIndex가 256보다 작으면 uint8, 그렇지 않으면 uint16이다. 이 기능과 연결된 EntryMapRecord의 수.

EntryMapRecord 인코딩:

유형 이름 설명
uint8/uint16 firstEntryIndex maxEntryIndex가 256보다 작으면 uint8, 그렇지 않으면 uint16이다. firstEntryIndex와 lastEntryIndex는 이 매핑으로 생성되는 항목의 서브셋 정의를 구성하는 글리프 맵 항목 집합을 지정한다.
uint8/uint16 lastEntryIndex maxEntryIndex가 256보다 작으면 uint8, 그렇지 않으면 uint16이다.

항목 맵 레코드는 firstEntryIndex보다 크거나 같고 lastEntryIndex보다 작거나 같은 모든 항목 인덱스와 일치한다.

5.3.1.1. 형식 1 해석

이 알고리즘은 형식 1 패치 맵을 패치 맵 항목 목록으로 변환하는 데 사용된다.

형식 1 패치 맵 해석

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. patch map 데이터가 완전하고 잘리지 않았으며, format이 1이고, § 5.3.1 패치 맵 테이블: 형식 1의 요구 사항 ("must"로 표시된 요구 사항)에 따라 유효한지 확인한다. 그렇지 않으면 오류를 반환한다.

  2. entryIndex의 각 고유한 entry index에 대해:

    • entry index가 0이면 초기 글꼴에 이미 있는 글리프를 표시하는 데 사용되는 특수 항목이다. 이 인덱스를 건너뛰고 항목을 만들지 않는다.

    • entry indexmaxGlyphMapEntryIndex보다 크면 이 항목은 유효하지 않으므로 해당 entry index를 건너뛴다.

    • appliedEntriesBitMap에서 entry index의 비트가 1로 설정되어 있으면 해당 entry index를 건너뛴다.

    • entry index에 매핑되는 글리프 인덱스 집합을 수집한다.

    • font subsetcmap 테이블에 있는 코드 포인트-글리프 매핑을 사용하여 글리프 인덱스 집합을 유니코드 코드 포인트 집합으로 변환한다. cmap에서 매핑하지 않는 글리프 인덱스는 무시한다. 여러 코드 포인트가 동일한 글리프 id에 매핑될 수 있다. 글리프와 연결된 모든 코드 포인트를 포함해야 한다.

    • urlTemplateentry index를 입력으로 하여 URL 템플릿 확장을 호출하여 entry index를 URL 문자열로 변환한다. 템플릿 확장에서 오류가 발생하면 오류를 반환한다.

    • 유니코드 코드 포인트 집합이 비어 있으면 해당 entry index를 건너뛴다.

    • 유니코드 코드 포인트 집합만 포함하고 생성된 URL 문자열, patchFormat으로 지정된 패치 형식 및 compatibilityId에 매핑되는 서브셋 정의를 가진 항목entry list에 추가한다.

  3. featureMapOffset이 null이 아니면 featureRecordsentryMapRecords에 있는 각 FeatureRecord 및 연결된 EntryMapRecord에 대해:

  4. entry list를 반환한다.

참고: 인코딩은 [0, maxEntryIndex]의 모든 항목 인덱스에 대한 항목을 포함할 필요는 없지만, 최대의 간결성을 위해 포함하는 것이 권장된다.

5.3.1.2. 형식 1에서 항목 제거

이 알고리즘은 형식 1 패치 맵에서 항목을 제거하는 데 사용된다. 이 제거는 패치 맵의 바이트를 수정하지만 바이트 수는 변경하지 않는다.

형식 1 패치 맵에서 항목 제거

이 알고리즘의 입력은 다음과 같다:

알고리즘:

  1. patch mapformat이 1이고 § 5.3.1 패치 맵 테이블: 형식 1의 요구 사항에 따라 유효한지 확인한다. 그렇지 않으면 오류를 반환한다.

  2. patch mapentryIndex에 있는 각 고유한 entry index에 대해:

    • appliedEntriesBitMap에서 entry index의 비트가 1로 설정되어 있으면 해당 entry index를 건너뛴다.

    • urlTemplateentry index를 입력으로 하여 URL 템플릿 확장을 호출함으로써 entry index를 URL 문자열로 변환한다. 템플릿 확장에서 오류가 발생하면 오류를 반환한다.

    • 생성된 URL 문자열이 patch URL string과 같으면 appliedEntriesBitMap에서 entry index의 비트를 1로 설정한다.

5.3.2. 패치 맵 테이블: 형식 2

형식 2 패치 맵 인코딩:

유형 이름 설명
uint8 format 2로 설정하며 형식 2임을 식별한다.
uint24 reserved 사용하지 않으며 0으로 설정한다.
uint8 flags 선택적 필드의 존재를 알리는 플래그. 비트 0(최하위 비트)이 설정되면 cffCharStringsOffset이 존재한다. 비트 1(최하위 비트)이 설정되면 cff2CharStringsOffset이 존재한다.
uint32 compatibilityId[4] 이 글꼴과 호환되는 패치를 식별하는 데 사용되는 고유 ID(§ 4.1 패치 무효화 참조). 인코더가 이 값을 선택한다. 인코더는 IFT 글꼴을 인코딩하는 동안 이전에 사용되지 않은 무작위 값으로 설정해야 한다.
uint8 defaultPatchFormat urlTemplate로 연결된 패치의 형식을 지정한다(항목에서 재정의하지 않는 경우). § 6.1 형식 요약 표의 형식 번호 중 하나로 설정해야 한다.
uint24 entryCount 이 테이블에 인코딩된 항목 수.
Offset32 entries 매핑 항목 하위 테이블에 대한 오프셋. 오프셋은 이 테이블의 시작을 기준으로 한다.
Offset32 entryIdStringData 모든 항목 ID 문자열을 연결한 데이터 블록에 대한 오프셋. null(0)일 수 있다. 오프셋은 이 테이블의 시작을 기준으로 한다.
uint16 urlTemplateLength urlTemplate 바이트 배열의 길이.
uint8 urlTemplate[urlTemplateLength] 각 항목과 연결된 URL 문자열을 생성하는 데 사용되는 URL 템플릿을 포함하는 바이트 배열.
uint32 cffCharStringsOffset flags의 비트 0(최하위)이 설정된 경우에만 존재한다. CFF 테이블의 시작에서 CFF 테이블의 CharStrings INDEX 데이터 구조까지의 오프셋을 제공한다.
uint32 cff2CharStringsOffset flags의 비트 1이 설정된 경우에만 존재한다. CFF2 테이블의 시작에서 CFF2 테이블의 CharStrings INDEX 데이터 구조까지의 오프셋을 제공한다.

매핑 항목 인코딩:

유형 이름 설명
uint8 entries[variable] entryCount개의 매핑 항목 인코딩 바이트를 포함하는 바이트 배열. 각 항목은 가변 길이이며 길이는 형식 2 패치 맵 항목 해석에 따라 결정된다.

매핑 항목 인코딩:

유형 이름 설명
uint8 formatFlags 비트 필드. 비트 0(최하위 비트)부터 비트 5까지는 선택적 필드의 존재를 나타낸다. 비트 6이 설정되면 이 항목은 무시된다. 비트 7은 향후 사용을 위해 예약되며 0으로 설정한다.
uint8 featureCount featureTags 목록의 기능 태그 수. formatFlags 비트 0이 설정된 경우에만 존재한다.
Tag featureTags[featureCount] 항목의 글꼴 서브셋 정의에 있는 기능 태그 목록. formatFlags 비트 0이 설정된 경우에만 존재한다.
uint16 designSpaceCount 디자인 공간 목록의 요소 수. formatFlags 비트 0이 설정된 경우에만 존재한다.
디자인 공간 세그먼트 designSpaceSegments[designSpaceCount] 항목의 글꼴 서브셋 정의에 있는 디자인 공간 세그먼트 목록. formatFlags 비트 0이 설정된 경우에만 존재한다.
uint8 childEntryMatchModeAndCount 이 필드와 다음 필드는 이전 항목의 교차 여부에 따라 달라지는 이 항목의 교차 확인 조건을 추가하는 데 사용된다. 최상위 비트는 일치 모드를 나타내는 데 사용된다. 비트가 설정되면 조건은 논리곱이고 그렇지 않으면 논리합이다. 나머지 7비트는 부호 없는 정수로 해석되며 childEntryIndices 목록의 항목 인덱스 수를 나타낸다. 이 필드는 formatFlags 비트 1이 설정된 경우에만 존재한다.
uint24 childEntryIndices[0b01111111 & childEntryMatchModeAndCount] 각 값은 이 항목의 교차 여부를 결정하기 위해 교차를 확인할 entries 배열 내 항목의 인덱스다. entries에서 이 매핑 항목보다 앞에 나타난 항목만 참조할 수 있다. formatFlags 비트 1이 설정된 경우에만 존재한다.
int24 entryIdDelta[variable] 이 항목의 URL 문자열 ID를 계산하는 부호 있는 델타 목록. 존재하는 경우 하나 이상의 델타를 가진다. 델타의 최하위 비트가 설정되면 델타가 하나 더 뒤따른다. 최하위 비트가 지워진 델타가 나타날 때까지 반복된다. 각 델타의 항목 id는 마지막으로 계산된 항목 id + 1 + floor(entryIdDelta / 2)다. formatFlags 비트 2가 설정되고 entryIdStringData가 null(0)인 경우에만 존재한다. 존재하지 않고 entryIdStringData가 null(0)이면 이 항목에는 하나의 id가 있으며 델타는 0으로 간주한다.
uint24 entryIdStringLength[variable] 이 항목의 각 id 문자열이 entryIdStringData 데이터 블록에서 차지하는 바이트 수. 길이 값의 최상위 비트가 설정되면 다른 길이 값이 뒤따른다. 최상위 비트가 지워진 길이 값이 나타날 때까지 반복된다. 실제 길이 값은 각 값의 최하위 23비트에 저장된다. formatFlags 비트 2가 설정되고 entryIdStringData가 null(0)이 아닌 경우에만 존재한다. 존재하는 경우 하나 이상의 길이 값을 가진다. 존재하지 않고 entryIdStringData가 null(0)이 아니면 이전 항목의 마지막 id 문자열로 설정된 하나의 id 문자열이 있으며 첫 번째 항목의 경우 빈 문자열로 설정된다.
uint8 patchFormat 이 항목으로 연결된 패치의 형식을 지정한다. § 6.1 형식 요약 표의 ID 번호를 사용한다. defaultPatchFormat을 재정의한다. formatFlags 비트 3이 설정된 경우에만 존재한다.
uint16/uint24 bias 코드 포인트 집합의 모든 코드 포인트 값에 추가되는 바이어스 값. 형식 비트 4가 0이고 비트 5가 1이면 존재하며 uint16이다. 형식 비트 4가 1이고 비트 5가 1이면 존재하며 uint24다. 그렇지 않으면 존재하지 않는다.
uint8 codePoints[variable] 이 매핑의 코드 포인트 집합. 희소 비트 집합으로 인코딩된다. formatFlags 비트 4 및/또는 5가 설정된 경우에만 존재한다. 길이는 § 5.3.2.3 희소 비트 집합의 디코딩 절차를 따라 결정한다.

인코더가 파일 시스템에 저장한 다음 제공할 패치를 생성하는 경우 일반적으로 형식 2 패치 맵의 가장 작은 인코딩을 생성하므로 숫자 항목 ID만 (entryIdDelta를 통해) 사용하는 것이 권장된다. 문자열 ID는 패치를 미리 저장하지 않고 ID 문자열을 사용하여 요청되는 패치에 관한 정보를 인코딩할 수 있는 경우에 유용하다.

디자인 공간 세그먼트 인코딩:

유형 이름 설명
Tag tag 축 태그 값.
Fixed start 세그먼트의 시작(포함). 이 값은 사용자 축 스케일을 사용한다: OpenType 명세 § otvaroverview#coordinate-scales-and-normalization.
Fixed end 세그먼트의 끝(포함). start보다 크거나 같아야 한다. 이 값은 사용자 축 스케일을 사용한다: OpenType 명세 § otvaroverview#coordinate-scales-and-normalization.
5.3.2.1. 형식 2 해석

이 알고리즘은 형식 2 패치 맵패치 맵 항목 목록으로 변환하는 데 사용된다.

형식 2 패치 맵 해석

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. patch mapformat이 2이고 § 5.3.2 패치 맵 테이블: 형식 2의 요구 사항 ("must"로 표시된 요구 사항)에 따라 유효한지 확인한다. 그렇지 않으면 오류를 반환한다.

  2. entryIdStringData 오프셋이 0이면 last entry id를 0으로 초기화한다. 그렇지 않으면 빈 바이트 문자열로 초기화한다. current byte를 0으로, current id string byte를 0으로 설정한다.

  3. entry listprior entry list를 빈 목록으로 초기화한다.

  4. entryCount형식 2 패치 맵 항목 해석을 호출한다. 각 호출에 대해:

    • prior entry list, entries[current byte]에서 patch map 끝까지의 바이트, entryIdStringData가 0이 아닌 경우 entryIdStringData[current id string byte]에서 patch map 끝까지의 바이트, last entry id, defaultPatchFormaturlTemplate을 전달한다.

    • last entry id를 반환된 항목 id로 설정한다.

    • 반환된 소비 바이트 수를 current byte에 더한다.

    • 반환된 소비 id 문자열 바이트 수를 current id string byte에 더한다.

    • 반환된 항목을 prior entry list에 추가한다.

    • 반환된 ignored 값이 false이면 반환된 항목의 호환성 ID를 compatibilityId로 설정하고 항목을 entry list에 추가한다.

  5. entry list를 반환한다.

형식 2 패치 맵 항목 해석

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. 모든 단계에서 entry bytes에서 데이터를 로드할 때마다 읽은 바이트 수만큼 consumed bytes를 증가시킨다.

  2. entry id = last entry id, consumed id string bytes = 0으로 설정한다.

  3. entry의 패치 형식을 default patch format으로 설정한다.

  4. 모든 집합이 비어 있도록 초기화된 단일 글꼴 서브셋 정의entry에 추가한다.

  5. entry bytes에서 formatFlags를 읽는다.

  6. formatFlags 비트 0이 설정되면 기능 태그 및 디자인 공간 목록이 존재한다:

  7. formatFlags 비트 1이 설정되면 복사 인덱스 목록이 존재한다:

    • childEntryMatchModeAndCount의 최상위 비트가 설정되어 있으면 entry의 일치 모드를 논리곱으로 설정하고, 그렇지 않으면 논리합으로 설정한다.

    • childEntryMatchModeAndCountchildEntryIndices로 지정된 하위 항목 인덱스 목록을 entry bytes에서 읽는다.

    • 하위 항목 인덱스는 이전에 로드된 항목을 참조한다. 0은 prior entry list의 첫 번째 매핑 항목, 1은 두 번째 항목이며 이후에도 동일하다. childEntryIndices의 각 값에 대해 일치하는 인덱스를 가진 항목을 prior entry list에서 찾는다. 해당 항목에 대한 참조를 entry에 추가한다. childEntryIndicesprior entry list의 길이보다 크거나 같으면 이 인코딩은 유효하지 않으므로 오류를 반환한다.

  8. formatFlags 비트 2가 설정되면 id 델타 또는 id 문자열 길이가 존재한다:

    • id string bytes가 없으면:

      • 다음 entryIdDelta 값을 읽는다.

      • entry identry id + 1 + floor(delta value / 2)로 설정한다. entry id가 음수이거나 4,294,967,295보다 크면 이 인코딩은 유효하지 않으므로 오류를 반환한다.

      • url templateentry id를 입력으로 하여 URL 템플릿 확장을 호출함으로써 entry id를 URL 문자열로 변환한다. 템플릿 확장에서 오류가 발생하면 오류를 반환한다.

      • 생성된 패치 URL 문자열을 entry에 추가한다.

      • 읽은 델타 값의 최하위 비트가 설정되어 있으면 8단계를 반복한다.

    • 그렇지 않고 id string bytes가 있으면:

      • 다음 entryIdStringLength 값을 읽는다.

      • 최하위 23비트를 부호 없는 정수로 해석하고 id string bytes에서 해당 수만큼 바이트를 읽는다. entry id를 결과로 설정한다. 읽은 바이트 수만큼 consumed id string bytes를 증가시킨다.

      • url templateentry id를 입력으로 하여 URL 템플릿 확장을 호출함으로써 entry id를 URL 문자열로 변환한다. 템플릿 확장에서 오류가 발생하면 오류를 반환한다.

      • 생성된 패치 URL 문자열을 entry에 추가한다.

      • 읽은 길이 값의 최상위 비트가 설정되어 있으면 8단계를 반복한다.

  9. formatFlags 비트 2가 설정되지 않은 경우:

    • id string bytes가 없으면:

      • entry identry id + 1로 설정한다.

      • url templateentry id를 입력으로 하여 URL 템플릿 확장을 호출함으로써 entry id를 URL 문자열로 변환한다. 템플릿 확장에서 오류가 발생하면 오류를 반환한다.

      • 생성된 패치 URL 문자열을 entry에 추가한다.

    • 그렇지 않고 id string bytes가 있으면:

      • url templateentry id를 입력으로 하여 URL 템플릿 확장을 호출함으로써 entry id를 URL 문자열로 변환한다. 템플릿 확장에서 오류가 발생하면 오류를 반환한다.

      • 생성된 패치 URL 문자열을 entry에 추가한다.

  10. formatFlags 비트 3이 설정되면 패치 형식이 존재한다. patchFormat으로 지정된 형식을 entry bytes에서 읽고 entry의 패치 형식을 읽은 값으로 설정한다. patchFormat§ 6.1 형식 요약의 값 중 하나가 아니면 이 인코딩은 유효하지 않으므로 오류를 반환한다.

  11. formatFlags 비트 4와 비트 5 중 하나 또는 둘 모두가 설정되면 코드 포인트 목록이 존재한다:

    • formatFlags 비트 4가 0이고 비트 5가 1이면 entry bytes에서 2바이트(uint16) bias 값을 읽는다.

    • formatFlags 비트 4가 1이고 비트 5가 1이면 entry bytes에서 3바이트(uint24) bias 값을 읽는다.

    • 그렇지 않으면 bias는 0이다.

    • § 5.3.2.3 희소 비트 집합에 따라 bias를 사용하여 entry bytes에서 희소 비트 집합 codePoints를 읽는다. 결과 코드 포인트 집합을 entry의 첫 번째 글꼴 서브셋 정의에 추가한다. 희소 비트 집합 디코딩에 실패하면 이 인코딩은 유효하지 않으므로 오류를 반환한다.

  12. formatFlags 비트 6이 설정되면 ignored를 true로 설정한다. 그렇지 않으면 ignored는 false다.

  13. entry id, entry, consumed bytes, consumed id string bytesignored를 반환한다.

5.3.2.2. 형식 2에서 항목 제거

이 알고리즘은 형식 2 패치 맵에서 항목을 제거하는 데 사용된다. 이 제거는 패치 맵의 바이트를 수정하지만 바이트 수는 변경하지 않는다.

형식 2 패치 맵에서 항목 제거

이 알고리즘의 입력은 다음과 같다:

이 알고리즘은 형식 2 패치 맵 해석의 수정된 버전이다. patch map을 입력으로 하여 형식 2 패치 맵 해석을 호출하되 다음과 같이 변경한다:

5.3.2.3. 희소 비트 집합

희소 비트 집합은 서로 다른 부호 없는 정수 집합을 간결하게 저장하는 데이터 구조다. 이 집합은 각 노드가 일정한 수의 자식을 가지며 구간을 동일한 파티션으로 재귀적으로 나누는 트리로 표현된다. 높이가 H이고 분기 계수가 B인 트리는 [0부터 BH-1]까지의 정수에 대한 집합 포함 여부를 저장할 수 있다. 트리는 전송을 위해 바이트 배열로 인코딩된다.

형식 2 패치 맵의 맥락에서 희소 비트 집합은 유니코드 코드 포인트 집합을 저장하는 데 사용된다. 따라서 희소 비트 집합에 저장된 정수 값은 0부터 0x10FFFF 범위의 유니코드 코드 포인트 값으로 제한된다.

희소 비트 집합 인코딩:

유형 이름 설명
uint8 header 비트 0(최하위)과 1은 분기 계수 인코딩을 통해 트리의 분기 계수 B를 인코딩한다. 비트 2부터 6까지는 H 값을 인코딩하는 5비트 부호 없는 정수다. 비트 7은 0으로 설정하며 향후 사용을 위해 예약된다.
uint8 treeData[variable] 트리의 바이너리 인코딩.

treeData의 정확한 길이는 처음에는 알 수 없으며 디코딩 알고리즘을 실행하여 결정한다. 분기 계수 2 또는 4를 사용할 때 마지막 노드는 바이트의 비트를 일부만 사용할 수 있다. 이 경우 남은 모든 비트는 사용하지 않으며 무시한다.

분기 계수 인코딩:

비트 1 비트 0 분기 계수(B) 최대 높이(H)
0 0 2 31
0 1 4 16
1 0 8 11
1 1 32 7

인코딩된 높이(H)가 위 표에서 인코딩된 분기 계수(B)의 최대 높이보다 큰 희소 비트 집합은 유효하지 않다.

희소 비트 집합 treeData 디코딩

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

FIFO(선입선출) 큐 Q를 사용하는 알고리즘:

  1. treeData에서 첫 번째 바이트를 제거한다. 이는 헤더 바이트다. 희소 비트 집합에 따라 트리 높이 H와 분기 계수 B를 결정한다.

  2. HB에 해당하는 분기 계수 인코딩 표 행의 "최대 높이"보다 크면 인코딩은 유효하지 않으므로 오류를 반환한다.

  3. H가 0이면 빈 집합이며 treeData의 추가 바이트를 소비하지 않는다. 빈 집합을 반환한다.

  4. 튜플 (0, 1)을 Q에 삽입한다.

  5. S를 빈 집합으로 초기화한다.

  6. treeDatatreeData[0]의 최하위 비트가 문자열의 첫 번째 비트이고 treeData[0]의 최상위 비트가 8번째 비트인 비트 문자열로 해석되며 이후에도 동일하다.

  7. 다음 단계에서 S에 추가되는 값이 최대 유니코드 코드 포인트 값 (0x10FFFF)보다 크면 해당 값을 무시하고 S에 추가하지 않는다.

  8. Q가 비어 있으면 S를 반환한다.

  9. Q에서 다음 튜플 t를 추출한다. t의 첫 번째 값은 start이고 두 번째 값은 depth다.

  10. treeData 비트 문자열에서 다음 B비트를 제거한다. 첫 번째로 제거된 비트는 v1, 두 번째는 v2이며 마지막으로 제거된 비트 vB까지 이어진다. 제거 전에 treeData에 남은 비트가 B개보다 적으면 treeData가 잘못된 것이므로 오류를 반환한다.

  11. v1부터 vB까지의 모든 비트가 0이면 [start + bias, start + bias + BH - depth + 1) 구간의 모든 정수를 S에 삽입한다. 5단계로 이동한다.

  12. v1부터 vB까지에서 1인 각 vi에 대해: depthH와 같으면 정수 start + bias + i - 1을 S에 추가한다. 그렇지 않으면 튜플 (start + (i - 1) * BH - depth, depth + 1)을 Q에 삽입한다.

  13. 8단계로 이동한다.

참고: 희소 비트 집합을 인코딩할 때 인코더는 가능한 모든 분기 계수를 사용할 수 있지만, 일반적으로 접하는 대부분의 유니코드 코드 포인트 집합에서 가장 작은 인코딩을 생성하는 것으로 나타났으므로 4를 사용하는 것이 권장된다.

분기 계수가 8인 트리에서 집합 {2, 33, 323}은 다음 비트 문자열로 인코딩할 수 있다:
비트 문자열:
|-- header --|- lvl 0 |---- level 1 ----|------- level 2 -----------|
| B=8 H=3    |   n0   |   n1       n2   |   n3       n4       n5    |
[ 01  11000 0 10000100 10001000 10000000 00100000 01000000 00010000 ]

다음 바이트 문자열이 된다:
[
  0b00001110,
  0b00100001,
  0b00010001,
  0b00000001,
  0b00000100,
  0b00000010,
  0b00001000
]
분기 계수가 2인 트리에서 빈 집합은 다음 비트 문자열로 인코딩된다:
비트 문자열:
|-- header -- |
| B=2 H=0     |
[ 00  00000 0 ]

다음 바이트 문자열이 된다:
[
  0b00000000,
]
집합 {0, 1, 2, ..., 17}은 분기 계수 4를 사용하여 다음과 같이 인코딩할 수 있다:
비트 문자열:
|-- header --| l0 |- lvl 1 -| l2  |
| B=4 H=3    | n0 | n1 | n2 | n3  |
[ 10  11000 0 1100 0000 1000 1100 ]

바이트 문자열:
[
  0b00001101,
  0b00000011,
  0b00110001
]

5.3.3. URL 템플릿

URL 템플릿은 각 패치 맵 항목과 연결된 URL 문자열을 압축하는 데 사용된다. 각 패치 매핑 테이블은 URL 템플릿을 제공하고 공통 템플릿을 각 항목의 ID를 입력으로 사용하여 확장함으로써 각 항목의 URL 문자열을 생성한다. 템플릿 확장의 출력은 [UTF-8]로 인코딩된 문자열이다.

URL 템플릿은 리터럴 값을 삽입하거나 입력 항목 ID를 기반으로 값을 삽입하는 일련의 1바이트 연산 코드로 인코딩된다.

URL 템플릿을 디코딩하고 확장하는 알고리즘은 다음과 같다.

URL 템플릿 확장

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. URL string을 빈 바이트 배열로 초기화한다. 나머지 단계에서는 url template bytes를 큐로 사용한다. 읽기 작업은 큐의 앞쪽(인덱스 0의 바이트부터)에서 바이트를 제거한다.

  2. url template bytes의 다음 바이트를 op code로 읽는다. 남은 바이트가 없으면 확장이 완료된 것이므로 URL string을 반환한다.

  3. op code의 최상위 비트가 설정되지 않은 경우:

    • op code의 최하위 7비트를 부호 없는 정수 number of literals로 해석한다.

    • number of literals가 0이면 오류를 반환한다.

    • url template bytes에서 다음 number of literals개 바이트를 literal bytes로 읽는다. url template bytes에 남은 바이트가 충분하지 않으면 오류를 반환한다.

    • literal bytesUTF-8, ISO 10646의 변환 형식 § section-4에 따른 유효한 UTF-8 인코딩 문자열인지 확인한다. 그렇지 않으면 오류를 반환한다.

    • literal bytesURL string의 끝에 추가한다.

    • 2단계로 이동한다.

  4. op code의 최상위 비트가 설정된 경우:

    • 다음 연산 코드 참조 표에서 op code를 찾는다. "삽입 작업" 열에 지정된 작업을 수행한다. 표에서 op code를 찾을 수 없으면 오류를 반환한다.

    • 2단계로 이동한다.

연산 코드 참조 표

이름 연산 코드 값 삽입 작업
id32 삽입 128 (0b10000000) 다음 확장 변수 표의 id32 변수 값을 URL string에 추가한다.
d1 삽입 129 (0b10000001) 다음 확장 변수 표의 d1 변수 값을 URL string에 추가한다.
d2 삽입 130 (0b10000010) 다음 확장 변수 표의 d2 변수 값을 URL string에 추가한다.
d3 삽입 131 (0b10000011) 다음 확장 변수 표의 d3 변수 값을 URL string에 추가한다.
d4 삽입 132 (0b10000100) 다음 확장 변수 표의 d4 변수 값을 URL string에 추가한다.
id64 삽입 133 (0b10000101) 다음 확장 변수 표의 id64 변수 값을 URL string에 추가한다.

확장 변수

변수
id32 입력 entry ID를 패딩을 생략한 base32hex 문자열 (숫자 0-9, A-V 사용)로 인코딩한 값. entry ID가 부호 없는 정수이면 먼저 빅 엔디언 32비트 부호 없는 정수로 변환해야 하지만, 인코딩하기 전에 0과 같은 모든 선행 바이트를 제거해야 한다. (예를 들어 정수가 256보다 작으면 한 바이트만 인코딩한다.) entry ID가 0이면 0 바이트 하나를 인코딩한다. entry ID가 문자열이면 원시 바이트를 base32hex로 인코딩한다.
d1 id32 변수에 있는 문자열의 마지막 문자. id32 변수가 비어 있으면 값은 문자 _ (U+005F)다.
d2 id32 변수에 있는 문자열의 끝에서 두 번째 문자. id32 변수의 문자가 2개 미만이면 값은 문자 _ (U+005F)다.
d3 id32 변수에 있는 문자열의 끝에서 세 번째 문자. id32 변수의 문자가 3개 미만이면 값은 문자 _ (U+005F)다.
d4 id32 변수에 있는 문자열의 끝에서 네 번째 문자. id32 변수의 문자가 4개 미만이면 값은 문자 _ (U+005F)다.
id64 입력 entry ID를 패딩을 포함한 base64url 문자열 (A-Z, a-z, 0-9, -(빼기) 및 _(밑줄) 사용)로 인코딩한 값. 패딩 문자가 '='이므로 '%3D'로 URL 인코딩해야 한다. entry ID가 부호 없는 정수이면 먼저 빅 엔디언 32비트 부호 없는 정수로 변환해야 하지만, 인코딩하기 전에 0과 같은 모든 선행 바이트를 제거해야 한다. (예를 들어 정수가 256보다 작으면 한 바이트만 인코딩한다.) entry ID가 0이면 0 바이트 하나를 인코딩한다. entry ID가 문자열이면 원시 바이트를 base64url로 인코딩한다.

몇 가지 입력 예와 대응하는 확장 결과. "템플릿 바이트" 열의 값은 C 스타일 바이트 배열로 제공한다.

템플릿 바이트 입력 ID ID 유형 확장 결과
[16, 'h', 't', 't', 'p', 's', ':', '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 128] 123 정수 https://foo.bar/FC
[8, 'f', 'o', 'o', '?', 'b', 'a', 'r', '=', 128] 123 정수 foo?bar=FC
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 128] 0 정수 //foo.bar/00
[5, '/', 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 128] 478 정수 /foo/0/F/07F0
[5, '/', 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 131, 1, '/', 128] 123 정수 /foo/C/F/_/FC
[4, 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 131, 1, '/', 128] ['b', 'a', 'z'] 문자열 foo/K/N/G/C9GNK
[4, 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 131, 1, '/', 128] ['z'] 문자열 foo/8/F/_/F8
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] 14,000,000 정수 //foo.bar/1Z-A
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] 0 정수 //foo.bar/AA%3D%3D
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] 17,000,000 정수 //foo.bar/AQNmQA%3D%3D
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] [0xc3, 0xa0, 0x62, 0x63] 문자열 //foo.bar/w6BiYw%3D%3D

다음 예에서는 확장이 실패하고 오류를 반환할 것으로 예상된다:

템플릿 바이트 입력 ID ID 유형 실패 이유
[4, 'f', 'o', 'o', '/', 150] 123 정수 연산 코드 150은 유효하지 않음
[4, 'f', 'o', 'o', '/', 0, 128] 123 정수 연산 코드 0은 유효하지 않음
[10, 'f', 'o', 'o', '/', 128] 123 정수 리터럴 복사 연산 코드 10에 필요한 바이트가 템플릿에 충분하지 않음.
[4, 'f', 'o', 'o', 0x85, 128] 123 정수 리터럴 바이트가 유효한 UTF-8이 아님.

6. 글꼴 패치 형식

증분 글꼴 전송에서는 패치를 적용하여 글꼴 서브셋을 확장한다. 이 명세는 각각 고유한 확장 시나리오 집합에 적합한 두 가지 패치 형식을 정의한다. 하나의 인코딩은 둘 이상의 패치 형식을 사용할 수 있다.

6.1. 형식 요약

이 명세는 다음 패치 형식을 정의한다:

각 알고리즘에 대한 자세한 설명은 다음 절에서 확인할 수 있다.

다음 형식 번호는 § 5.3 패치 맵 테이블에서 패치 형식과 무효화 모드를 식별하는 데 사용된다:

형식 번호 이름 무효화
1 § 6.2 테이블 키 기반 전체 무효화
2 § 6.2 테이블 키 기반 부분 무효화
3 § 6.3 글리프 키 기반 무효화 없음

6.2. 테이블 키 기반

테이블 키 기반 패치에는 입력 글꼴 파일의 개별 글꼴 테이블에 적용되는 패치 집합이 포함된다. 각 테이블 패치는 입력 글꼴 파일의 대응 테이블을 공유 LZ77 사전으로 사용하여 brotli 압축으로 인코딩된다. 테이블 키 기반으로 인코딩된 패치는 짧은 헤더와 하나 이상의 brotli 인코딩 패치로 구성된다. 테이블 패치 외에도 패치는 글꼴 서브셋의 테이블을 교체하거나(기존 테이블 데이터는 사용하지 않음) 제거할 수 있다.

테이블 키 기반 패치 인코딩:

유형 이름 설명
Tag format 형식을 테이블 키 기반으로 식별하며 'iftk'로 설정해야 한다.
uint32 reserved 향후 사용을 위해 예약되며 0으로 설정한다.
uint32 compatibilityId[4] 이 패치를 적용할 수 있는 글꼴 서브셋의 id. § 4.1 패치 무효화를 참조한다.
uint16 patchesCount patches 배열의 항목 수.
Offset32 patches[patchesCount+1] 각 항목은 이 테이블의 시작에서 TablePatch까지의 오프셋이다. 오프셋은 오름차순으로 정렬해야 한다.

patches 배열에서 연속된 두 오프셋의 차이는 해당 TablePatch의 크기를 나타낸다.

TablePatch 인코딩:

유형 이름 설명
Tag tag 이 패치가 적용되는 글꼴 테이블을 식별하는 태그.
uint8 flags 비트 필드. 비트 0(최하위 비트)이 설정되면 이 패치가 기존 테이블을 교체한다. 비트 1이 설정되면 이 테이블을 제거한다.
uint32 maxUncompressedLength brotliStream의 최대 압축 해제 길이.
uint8 brotliStream[variable] Brotli 인코딩 바이트 스트림.

6.2.1. 테이블 키 기반 패치 적용

패치 적용 알고리즘은 테이블 키 기반 패치를 적용하여 글꼴 서브셋을 추가 코드 포인트, 기능 및/또는 디자인 변형 공간을 포함하도록 확장하는 데 사용된다.

테이블 키 기반 패치 적용

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. extended font subset을 테이블이 없는 빈 글꼴로 초기화한다.

  2. patch§ 6.2 테이블 키 기반의 요구 사항 ("must"로 표시된 요구 사항)에 따라 유효하고 모든 TablePatchpatch 안에 포함되어 있는지 확인한다. 그렇지 않으면 오류를 반환한다.

  3. patchcompatibilityId 필드가 compatibility id와 같은지 확인한다. 일치하지 않거나 base font subset에 'IFT ' 또는 'IFTX' 테이블이 없으면 패치 적용이 실패한 것이므로 오류를 반환한다.

  4. 다음 단계에서 extended font subset에 테이블을 추가한다는 것은 OpenType 명세의 요구 사항에 따라 테이블 데이터를 글꼴에 추가하고 테이블 디렉터리에 새 항목을 삽입하는 것을 의미한다. 해당 항목에는 테이블 데이터의 체크섬이 포함된다. 기존 테이블을 수정하지 않고 복사하는 경우 클라이언트는 원본 글꼴의 항목에서 체크섬을 다시 사용할 수 있다. 그렇지 않으면 새 체크섬을 계산해야 한다.

  5. patches의 인덱스 i인 각 항목에 대해:

  6. 5단계에서 처리한 항목에서 찾을 수 없는 태그를 가진 base font subset의 각 테이블에 대해 해당 테이블의 사본을 extended font subset에 추가한다.

6.3. 글리프 키 기반

글리프 키 기반 패치에는 각각 글리프 인덱스와 글꼴 테이블에 연결된 데이터 청크 집합이 포함된다. 인코딩된 데이터는 참조된 테이블의 해당 글리프 인덱스에 대한 기존 데이터를 모두 교체한다. 글리프 키 기반 패치는 glyf/loca, gvar, CFFCFF2 테이블의 데이터를 인코딩할 수 있다.

글리프 키 기반 패치 인코딩:

유형 이름 설명
Tag format 형식을 글리프 키 기반으로 식별하며 'ifgk'로 설정해야 한다.
uint32 reserved 향후 사용을 위해 예약되며 0으로 설정한다.
uint8 flags 비트 필드. 비트 0(최하위 비트)이 설정되면 glyphIds는 uint24를 사용하고, 그렇지 않으면 uint16을 사용한다.
uint32 compatibilityId[4] 이 패치를 적용할 수 있는 글꼴 서브셋의 호환성 id. § 4.1 패치 무효화를 참조한다.
uint32 maxUncompressedLength brotliStream의 최대 압축 해제 길이.
uint8 brotliStream[variable] Brotli로 인코딩된 GlyphPatches 테이블.

GlyphPatches 인코딩:

유형 이름 설명
uint32 glyphCount 패치에 인코딩된 글리프 수.
uint8 tableCount 패치에 데이터가 있는 테이블 수.
uint16/uint24 glyphIds[glyphCount] 패치에 포함된 글리프 인덱스 배열. flags의 비트 0(최하위 비트)이 설정되면 요소는 uint24이고 그렇지 않으면 uint16이다. 오름차순으로 정렬되어야 하며 중복 값을 포함해서는 안 된다.
Tag tables[tableCount] 패치에 포함된 테이블 (태그 기준) 배열. 오름차순으로 정렬되어야 하며 중복 값을 포함해서는 안 된다. 정렬 시 태그 값은 4바이트 빅 엔디언 부호 없는 정수로 해석하고 정수 값으로 정렬한다.
Offset32 glyphDataOffsets[glyphCount * tableCount + 1] 각 테이블의 글리프 데이터에 대한 오프셋 배열. 처음 glyphCount개의 오프셋은 tables[0]에 대응하고, 다음 glyphCount개의 오프셋(있는 경우)은 tables[1]에 대응하며 이후에도 동일하다. 모든 오프셋은 GlyphPatches 테이블의 시작을 기준으로 한다. 오프셋은 오름차순으로 정렬해야 한다.
uint8 glyphData[variable] 오프셋으로 선택되는 실제 글리프 데이터.

glyphDataOffsets 배열에서 연속된 두 오프셋의 차이는 해당 글리프 데이터의 크기를 나타낸다.

6.3.1. 글리프 키 기반 패치 적용

패치 적용 알고리즘은 글리프 키 기반 패치를 적용하여 글꼴 서브셋을 추가 코드 포인트, 기능 및/또는 디자인 변형 공간을 포함하도록 확장하는 데 사용된다.

글리프 키 기반 패치 적용

이 알고리즘의 입력은 다음과 같다:

이 알고리즘의 출력은 다음과 같다:

알고리즘:

  1. patch§ 6.3 글리프 키 기반의 요구 사항 ("must"로 표시된 요구 사항)에 따라 유효한지 확인한다. 그렇지 않으면 오류를 반환한다.

  2. patchcompatibilityId 필드가 compatibility id와 같은지 확인한다. 일치하지 않거나 base font subset에 'IFT ' 또는 'IFTX' 테이블이 없으면 패치 적용이 실패한 것이므로 오류를 반환한다.

  3. Brotli 압축 데이터 형식 § 10 디코딩 알고리즘에 따라 brotliStream의 brotli 인코딩 데이터를 디코딩한다. 디코딩된 데이터는 GlyphPatches 테이블이다. 디코딩된 데이터가 maxUncompressedLength보다 크면 오류를 반환한다.

  4. tables에 나열된 인덱스 i인 각 글꼴 테이블에 대해:

    • base font subset의 대응 테이블을 사용하여 새 테이블을 합성한다. 각 글리프의 데이터는 존재하는 경우 glyphData의 해당 글리프 인덱스에 대응하는 데이터로 교체하고, 그렇지 않으면 base font subset의 대응 테이블에서 해당 글리프 인덱스의 데이터를 복사한다.

    • 글리프 인덱스의 패치 글리프 데이터는 글리프 인덱스와 같은 glyphIds[j]를 찾아 위치를 결정한다. 연결된 글리프 데이터의 오프셋은 glyphDataOffsets[i * glyphCount + j]다. 연결된 글리프 데이터의 길이는 glyphDataOffsets[i * glyphCount + j + 1]에서 glyphDataOffsets[i * glyphCount + j]를 뺀 값이다.

    • 새 테이블을 합성하는 구체적인 과정은 지정된 테이블 형식에 따라 달라진다. 글리프와 연결되지 않은 모든 데이터는 base font subset의 테이블에서 복사해야 한다. glyf, gvar, CFF 또는 CFF2 유형의 테이블을 지원한다. 그 밖의 유형의 테이블 항목은 모두 무시해야 한다. glyf를 업데이트할 때 loca 테이블도 업데이트해야 한다. 이 단계의 결과로 글꼴의 다른 테이블을 수정할 수 없다. 특히 이는 패치가 maxp에 지정된 numGlyphs를 초과하는 인덱스의 글리프를 추가할 수 없음을 의미한다.

      CFF, CFF2gvar에는 글리프별 데이터에 대한 가변 크기 오프셋이 있다. 새 테이블을 합성할 때 필요한 경우 오프셋 크기를 늘릴 수 있다. glyf/loca의 오프셋 크기는 head 테이블에 지정되므로 변경할 수 없다. 합성 중 가능한 경우 오프셋 크기를 늘린 후에도 생성된 오프셋이 가능한 최대 오프셋 값을 초과하면 패치 적용이 실패한 것이다. 오류를 반환한다.

    • base font subset에 일치하는 테이블이 없으면 오류를 반환한다.

    • 합성된 테이블을 extended font subset에 삽입한다.

  5. compatibility id와 동일한 compatibilityId를 가진 § 5.3 패치 맵 테이블을 찾는다. 형식 1 패치 맵이면 패치 맵 테이블과 patch URL string을 입력으로 하여 형식 1 패치 맵에서 항목 제거를 호출한다. 그렇지 않고 형식 2 패치 맵이면 패치 맵 테이블과 patch URL string을 입력으로 하여 형식 2 패치 맵에서 항목 제거를 호출한다. 수정된 패치 맵 테이블을 extended font subset에 복사한다.

  6. 4단계 또는 5단계에서 처리한 항목에서 찾을 수 없는 태그를 가진 base font subset의 각 테이블에 대해 해당 테이블의 사본을 extended font subset에 추가한다.

  7. 이전 단계에서 글꼴 테이블의 콘텐츠가 수정된 경우 각 수정된 테이블에 대해 글꼴 테이블 디렉터리의 체크섬을 테이블의 새 콘텐츠와 일치하도록 업데이트한다.

7. 인코딩

인코더는 증분 글꼴과 연결된 패치 집합을 생성하는 도구다. "인코딩"은 특정한 경우의 결과에 영향을 주기 위해 인코더가 요구하거나 허용하는 모든 매개변수를 포함하여 인코더를 사용하는 과정을 의미한다. 준수 인코더가 생성한 증분 글꼴과 연결된 패치는:

  1. § 5 글꼴 형식 확장§ 6 글꼴 패치 형식의 모든 요구 사항을 충족해야 한다.

  2. 일관성이 있어야 한다. 즉, 가능한 모든 글꼴 서브셋 정의에 대해 해당 서브셋 정의와 증분 글꼴을 사용하여 증분 글꼴 서브셋 확장을 호출한 결과는 증분 글꼴 서브셋 확장 8단계에서 선택한 구체적인 패치 선택 순서와 관계없이 항상 같아야 한다.

  3. 패치 무효화 기준을 준수해야 한다. IFT 인코딩의 일부인 모든 패치는 호환되는 글꼴 서브셋에 적용될 때 연결된 패치 맵 항목이 선언한 무효화 모드의 § 4.1 패치 무효화 기준을 준수하는 패치 맵 호환성 ID만 변경해야 한다.

  4. 인코더가 기존 글꼴을 증분 글꼴로 변환하는 데 사용되는 경우 연결된 완전히 확장된 글꼴은 기존 글꼴과 동등해야 한다. 동등한 완전 확장 글꼴은 기존 글꼴과 동일한 테이블 (증분 IFT/IFTX 테이블 제외)을 모두 가져야 하며 각 테이블은 기존 글꼴의 대응 테이블과 기능적으로 동등해야 한다. 참고: 완전히 확장된 글꼴이 기존 글꼴과 정확히 바이너리 수준에서 일치하지 않을 수 있다.

  5. 확장 과정 전체에서 완전히 확장된 글꼴의 기능을 유지해야 한다. 즉, 증분 글꼴에서 파생된 완전히 확장된 글꼴과 임의의 콘텐츠가 주어졌을 때, 증분 글꼴 및 해당 콘텐츠를 포함하는 최소 서브셋 정의를 사용하여 증분 글꼴 서브셋 확장을 호출해 생성된 글꼴 서브셋은 해당 콘텐츠에 대해 완전히 확장된 글꼴과 동일하게 렌더링해야 한다.

인코더를 사용하여 기존 글꼴 파일을 증분 글꼴로 변환하고 클라이언트가 이 문서의 다른 절에 따라 구현된 경우 IFT 명세의 의도는 클라이언트에서 글꼴의 모양과 동작이 전체 파일을 클라이언트에 전송한 것과 동일하도록 하는 것이다. IFT 명세의 주요 목표는 IFT 형식과 프로토콜이 WOFF2에 필적하는 글꼴 전송의 중립적인 매체로 사용될 수 있도록 하는 것이다. 인코더가 위의 모든 요구 사항(1~5)을 충족하는 원본 글꼴에서 인코딩을 생성하면 해당 인코딩은 원래 글꼴의 모든 기능을 유지한다. 위의 요구 사항 4는 원래 글꼴의 모든 기능에 도달할 수 있도록 보장한다. 이는 IFT 글꼴의 부분 버전이 부분 글꼴을 파생하는 데 사용된 서브셋 정의의 서브셋인 콘텐츠에 대해 전체 버전(여기서는 원래 글꼴)과 동등한 기능을 가져야 한다고 요구하는 요구 사항 5와 함께 작동한다.

이는 글꼴 제작사 또는 글꼴의 다른 권리 소유자가 IFT를 사용한 해당 글꼴의 인코딩 및 전송이 글꼴의 동작과 제작자의 의도를 변경하지 않는다는 확신을 갖고자 하는 경우 중요할 수 있다. 라이선스 또는 계약에는 IFT 준수에 관한 요구 사항이 포함될 수 있으며, 콘텐츠 중립성 때문에 글꼴을 WOFF2 형식으로 다시 인코딩하는 것이 사실상 허용되는 상황에서는 해당 글꼴의 IFT 인코딩도 허용될 수 있다.

그러나 인코딩 준수에 관한 이러한 요구 사항은 원본 글꼴의 모든 기능을 유지하지 않는 인코딩의 가능성과 실용적 사용을 배제하거나 사용 중단시키기 위한 것이 아니다. 최소 요구 사항(위의 1, 2, 3)을 충족하는 모든 인코딩은 유효하며 적절한 용도가 있을 수 있다. 경우에 따라 인코딩된 글꼴이 원래 글꼴 파일에 포함된 일부 기능/데이터의 지원을 모든 패치 파일에서 생략하도록 하는 것이 바람직할 수 있다. 다른 경우에는 글꼴 제작 원본 파일에서 IFT 형식으로 직접 인코딩할 수 있다. 인코더가 위의 요구 사항 4를 충족하지 않도록 선택하는 경우에도 확장 과정 전체에서 글꼴의 일관된 동작을 보장하는 요구 사항 5를 충족하는 것이 강력히 권장된다.

7.1. 인코딩 고려 사항

이 절은 규범적이지 않다.

인코딩 과정의 세부 사항은 인코더마다 다를 수 있으며 이 문서의 범위를 벗어난다. 그러나 이 절에서는 인코더 구현이 고려할 수 있는 지침을 제공하며, 기존 글꼴 파일의 증분 버전을 생성할 때 해당 글꼴의 모양과 동작을 재현하는 데 중요할 수 있다. 이 절의 지침은 이 명세를 개발하는 동안 인코더 구현을 구축한 경험을 기반으로 한다. 작성 당시 § 7 인코딩의 요구 사항 1~4를 충족하여 인코딩되는 원래 글꼴의 모든 기능/동작을 유지하는 고성능 인코딩을 생성하는 방법에 관한 최선의 이해를 나타낸다.

§ 6.2 테이블 키 기반 패치에 관하여

§ 6.2 테이블 키 기반 패치는 일부 글꼴 테이블의 콘텐츠를 변경하고 다른 테이블은 변경하지 않을 수 있다. 패치되는 각 테이블은 일반적으로 특정 테이블 콘텐츠를 기준으로 해야 하지만 다른 테이블은 다른 콘텐츠를 가질 수 있다. 따라서 § 6.2 테이블 키 기반 패치가 글리프 데이터를 포함하는 테이블을 변경하지 않는 한 § 6.3 글리프 키 기반 패치와 호환될 수 있으며 부분 무효화만 수행할 수 있다 (즉, 다른 § 6.2 테이블 키 기반 패치는 무효화하지만 § 6.3 글리프 키 기반 패치는 무효화하지 않음). 또한 두 § 6.2 테이블 키 기반 패치 집합은 동일한 테이블을 수정하지 않으면 서로 독립적일 수 있다. 예를 들어 글리프 테이블을 제외한 모든 콘텐츠에 § 6.2 테이블 키 기반 패치를 사용하고 해당 테이블에는 § 6.3 글리프 키 기반 패치 대신 또 다른 § 6.2 테이블 키 기반 패치 집합을 사용할 수 있다. 이 두 집합은 이론적으로 각각 부분 무효화일 수 있으며 서로 의존적이지만 다른 집합과는 독립적이다.

§ 6.2 테이블 키 기반 패치를 적용하면 일반적으로 해당 패치가 나열된 IFT 또는 IFTX 테이블이 변경되어 글꼴을 더 확장하기 위한 새 패치 집합이 추가된다. 이는 전체 § 6.2 테이블 키 기반 패치 집합이 세그먼트화의 각 글꼴 서브셋을 노드로, 각 패치를 간선으로 하는 그래프를 형성한다는 의미다. 또한 이러한 유형의 패치는 일반적으로 직렬로 다운로드하고 적용되므로 지연 시간과 관련된 이 패치 유형의 성능에 영향을 준다.

§ 6.3 글리프 키 기반 패치에 관하여

§ 6.3 글리프 키 기반 패치는 다른 패치 유형과 상당히 다르다. 첫째, § 6.3 글리프 키 기반 패치는 글리프 윤곽선 데이터를 포함하는 테이블만 수정할 수 있으므로 증분 글꼴§ 6.3 글리프 키 기반만 사용하는 경우 다른 모든 글꼴 테이블 데이터를 초기 글꼴 파일에 포함해야 한다. 둘째, § 6.3 글리프 키 기반 패치는 무효화하지 않으므로 독립적으로 다운로드하고 적용할 수 있다. 이러한 독립성 덕분에 여러 패치를 병렬로 다운로드할 수 있어 무효화 패치 유형과 비교하여 필요한 왕복 횟수를 크게 줄일 수 있다.

인코딩에 사용할 패치 형식 선택

모든 인코딩은 사용할 패치 유형을 하나 이상 선택해야 한다. § 6.2 테이블 키 기반 패치는 글꼴의 모든 유형의 데이터를 패치할 수 있지만 이 유형은 최소한 부분 무효화이므로 필요한 전체 패치 수는 세그먼트 수에 따라 선형이 아니라 지수적으로 증가한다. § 6.3 글리프 키 기반 패치는 윤곽선 및 변형 델타 데이터 업데이트로 제한되지만 필요한 수는 세그먼트 수에 따라 선형으로 증가한다.

패치 수 외에도 인코더는 일반적인 콘텐츠의 패치를 가져오는 데 필요한 네트워크 왕복 횟수를 고려해야 한다. 무효화 패치 유형은 패치 요청을 직렬로 수행해야 한다. 이는 콘텐츠에 여러 세그먼트가 필요한 경우 여러 번의 네트워크 왕복이 필요할 수 있음을 의미한다. 반면 글리프 키 기반 패치는 무효화하지 않으므로 패치를 병렬로 가져올 수 있어 한 번의 왕복만 필요하다.

두 유형의 극단적인 경우를 보면 § 6.2 테이블 키 기반 패치는 상당한 비윤곽선 데이터를 가지며 소수의 패치만 필요한 글꼴에 가장 적합하다. § 6.3 글리프 키 기반 패치는 데이터의 대부분이 글리프 윤곽선으로 구성된 글꼴에 가장 적합하며 많은 기존 CJK 글꼴이 이에 해당한다.

두 극단의 중간에 있는 글꼴 또는 글리프 데이터의 세분화된 세그먼트화가 필요하지만 다른 테이블의 데이터 세그먼트화도 필요한 경우 § 6.2 테이블 키 기반§ 6.3 글리프 키 기반 패치 유형을 다음과 같이 혼합하는 것이 바람직할 수 있다:

  1. 모든 테이블 키 기반 패치 항목을 한 매핑 테이블에 유지하고 모든 글리프 키 기반 항목을 다른 매핑 테이블에 유지한다.

  2. 글리프 키 기반 패치가 변경하는 테이블(윤곽선, 변형 델타 및 글리프 키 기반 패치 매핑 테이블)을 제외한 모든 테이블을 테이블 키 기반 패치로 업데이트한다. 이러한 패치는 패치 수를 합리적으로 유지하기 위해 소수의 큰 세그먼트를 사용해야 한다.

  3. 글리프 키 기반 패치는 업데이트되는 구체적인 글리프 ID를 참조하므로 테이블 키 기반 패치는 원래 글꼴에서 사용된 글리프-글리프 ID 할당을 변경해서는 안 된다. 그렇지 않으면 글리프 키 기반 패치에 나열된 글리프 ID가 잘못될 수 있다. 글꼴 서브셋 도구에서는 이를 "글리프 ID 유지"라는 옵션으로 제공하는 경우가 많다.

  4. 마지막으로 글리프 키 기반 패치를 사용하여 나머지 테이블을 업데이트한다. 여기서는 너무 많은 패치를 요구하지 않고 훨씬 작은 세분화된 세그먼트를 사용할 수 있다.

많은 글꼴이 두 극단 사이에 위치하므로 혼합 패치 유형 인코딩은 일반적으로 사용되는 접근 방식이 될 것으로 예상된다.

무효화 패치로 왕복 횟수 줄이기

무효화 패치 유형 중 하나를 사용하는 세그먼트화에서 필요한 왕복 횟수를 줄이는 한 가지 방법은 단일 세그먼트용 패치 외에도 여러 세그먼트를 한 번에 추가하는 패치를 제공하는 것이다. 예를 들어 A, B, C, D라는 4개 세그먼트가 있는 글꼴을 생각해 보자. 패치 테이블에는 A, B, C, D, A + B, A + C, A + D, B + C, B + D 및 C + D를 추가하는 패치를 나열할 수 있다. 그러면 두 세그먼트를 한 번의 왕복으로 추가할 수 있다. 이 접근 방식의 단점은 필요한 고유 패치 수가 더 증가한다는 것이다.

인코딩된 패치 매핑의 항목 순서

§ 4.4 무효화 패치 선택에서 클라이언트는 로드하고 적용할 패치를 선택할 때 동률을 해소하기 위해 패치 맵의 항목 순서를 사용한다. 클라이언트는 전체 전송 크기를 줄이는 것을 목표로 하므로 여러 항목의 교차 크기가 같을 때 전체 전송 크기가 가장 작은 패치를 선택하는 것이 일반적으로 클라이언트에 유리하다. 따라서 인코더는 패치 맵의 항목을 바이트 크기가 작은 순서에서 큰 순서로 배치해야 한다. 그러면 클라이언트가 § 4.4 무효화 패치 선택을 따를 때 더 작은 패치를 선호하여 성능을 극대화한다.

패치 수 관리

많은 세그먼트와 함께 § 6.2 테이블 키 기반 패치를 사용하면 매우 많은 패치가 필요할 수 있으며 두 가지 부정적인 영향을 줄 수 있다. 첫째, 미리 생성된 모든 패치에 필요한 저장 공간이 바람직하지 않을 정도로 커질 수 있다. 둘째, 패치 수가 많을수록 일반적으로 CDN 캐시 성능이 낮아진다. 더 많은 패치는 주어진 서브셋에서 다른 서브셋으로 가는 경로 수가 더 많음을 의미하며 사용자가 접근하는 콘텐츠에 따라 서로 다른 사용자가 서로 다른 경로를 사용하기 때문이다. 미리 생성된 전체 패치 수를 줄이는 데 사용할 수 있는 몇 가지 기법이 있다:

  1. 패치 그래프의 최대 깊이를 사용한다. 이 제한에 도달하면 글꼴을 패치하여 전체 원래 글꼴의 나머지 부분을 모두 추가한다. 일정 수의 세그먼트가 추가된 후 남은 전체 글꼴을 로드하게 된다. 그래프 깊이를 제한하면 낮은 깊이에서 패치가 조합적으로 폭증하는 것을 줄일 수 있다.

  2. 또는 낮은 깊이에서 인코더가 여러 세그먼트를 단일 패치로 결합하기 시작하여 각 수준의 분기 수를 줄일 수 있다.

세그먼트화 선택

인코더가 내려야 하는 가장 중요하고 복잡한 결정 중 하나는 인코딩된 글꼴의 데이터를 어떻게 세그먼트화할지다. 위 논의는 세그먼트 수에 초점을 맞췄지만 증분 글꼴의 성능은 세그먼트 내 데이터 그룹화에 훨씬 더 크게 의존한다. 효율을 극대화하려면 인코더는 일반적으로 함께 사용되는 데이터 (예: 코드 포인트)를 동일한 세그먼트에 그룹화해야 한다. 그러면 클라이언트가 글꼴을 확장할 때 불필요한 데이터 로드량이 줄어든다. 인코더는 세그먼트 크기도 결정해야 한다. 작은 세그먼트는 더 많은 패치를 생성하여 더 많은 네트워크 요청을 요구하는 오버헤드가 발생하지만, 큰 세그먼트와 비교하면 일반적으로 각 세그먼트의 불필요한 데이터가 줄어든다. 코드 포인트를 세그먼트화할 때 코드 포인트 사용 빈도 데이터가 세그먼트화 지침에 도움이 될 수 있다.

일부 코드 포인트는 명확한 세그먼트화를 가질 수 있으며 어떤 코드 포인트를 함께 그룹화할지 거의 의문의 여지가 없을 수 있다. 예를 들어 라틴 알파벳의 대문자와 소문자는 자연스러운 그룹을 이룬다. 다른 경우는 더 복잡할 수 있다. 예를 들어 중국어, 일본어, 한국어는 일부 코드 포인트를 공유하지만 일본어에서 빈도가 높은 코드 포인트가 중국어에서는 빈도가 낮을 수 있다. 경우에 따라 하나의 언어에 맞게 인코딩을 최적화할 수 있다. 또 다른 접근 방식은 절충 인코딩을 생성하는 것이다. 예를 들어 세그먼트화할 때 일본어, 중국어, 한국어에서 모두 빈도가 높은 코드 포인트를 한 세그먼트에 넣고, 일본어와 중국어에서만 빈도가 높은 코드 포인트를 다른 세그먼트에 넣는 식이다. 그런 다음 한 언어에서만 빈도가 높은 코드 포인트는 일반적인 방식으로 처리할 수 있다. 이는 세그먼트 크기를 덜 균일하게 만들지만 한 언어의 고빈도 패치를 로드할 때 저빈도 글리프까지 가져오는 것을 방지한다.

기본 레이아웃 기능 포함

부록 A: 기본 기능 태그에는 기본적으로 일반적으로 사용되는 레이아웃 기능 목록이 수집되어 있다. 이 목록의 기능은 일반적으로 셰이퍼가 항상 사용하므로 최상의 성능을 위해 인코더는 글꼴 인코딩에서 이러한 기능을 선택 사항으로 만들지 않아야 한다.

기능적 동등성 유지

§ 7 인코딩에서 설명한 것처럼 인코더는 원래 글꼴의 기능을 유지해야 한다. 글꼴은 복잡하고 코드 포인트 간 상호 작용을 포함하는 경우가 많으므로 글꼴의 부분 복사본으로 기능적 동등성을 유지하기가 까다로울 수 있다. 다음 두 하위 절에서는 서로 다른 패치 유형을 사용하여 기능적 동등성을 유지하는 방법을 설명한다.

테이블 키 기반 패치

§ 6.2 테이블 키 기반 패치를 준비할 때 기능적 동등성을 달성하는 한 가지 방법은 기존 글꼴 서브셋 구현을 활용하여 원래 글꼴의 기능을 유지하는 글꼴 서브셋을 생성하는 것이다. 그런 다음 이러한 서브셋에서 IFT 패치를 파생할 수 있다.

글꼴 서브셋 도구는 원하는 글꼴 서브셋 정의를 기반으로 입력 글꼴에서 글꼴 서브셋을 생성한다. 글꼴을 안정적으로 서브셋화하는 방식은 잘 알려져 있으며 여러 오픈 소스 구현이 있다 (완전한 형식적 설명은 이 문서의 범위를 벗어남). 일반적으로 도달 가능성 분석을 포함하며, 테이블의 데이터를 글꼴 서브셋 정의와 비교하여 서브셋 정의가 포함하는 가능한 콘텐츠에서 어떤 부분에 도달할 수 있는지 확인한다. 도달 가능한 데이터는 생성된 글꼴 서브셋에 유지되고 도달할 수 없는 데이터는 제거될 수 있다.

다음 의사 코드 예에서는 글꼴 서브셋 도구를 사용하여 테이블 키 기반 패치만 사용하는 IFT 인코딩 글꼴을 생성한다:

# 글꼴(full_font)을 base_subset_def에서 시작하고 subset_definitions 중 하나를
# 증분 방식으로 추가할 수 있는 증분 글꼴로 인코딩한다. IFT로 인코딩된 글꼴과
# 연결된 패치 집합을 반환한다.
encode_as_ift(full_font, base_subset_def, subset_definitions):
  base_font = subset(full_font, base_subset_def)
  base_font, patches  = encode_node(full_font, base_font, base_subset_def, subset_definitions)
  return base_font, patches

# base_font을 업데이트하여 subset_definitions 중 하나에 도달하는 모든 IFT 패치 매핑을
# 추가하고 연결된 패치를 생성한다.
encode_node(full_font, base_font, cur_def, subset_definitions):
  patches = []
  next_fonts = []
  
  for each subset_def in subset_definitions not fully covered by cur_def:
    next_def = subset_def union cur_def
    next_font = subset(full_font, next_def)
    let patch_url be a new unique url

    add a mapping from, (subset_def - cur_def) to patch_url, into base_font
    next_font, patches += encode_node(full_font, next_font, next_def, subset_definitions)

    next_fonts += (next_font, next_def, patch_url)

  for each (next_font, next_def, patch_url) in next_fonts:
    patch = table_keyed_patch_diff(base_font, next_font)
    patches += (patch, patch_url)
  
  return base_font, patches

이 예제 구현에서 입력 기본 서브셋 정의와 서브셋 정의 목록의 합집합이 입력 전체 글꼴을 완전히 포함하고 사용된 서브셋 도구 구현이 모든 기능을 올바르게 유지하면 위 구현은 중립 인코딩이 되기 위한 § 7 인코딩의 요구 사항을 충족해야 한다. 이 기본 인코더 구현은 설명을 위한 것이며 가능한 모든 인코더 구현을 대표하기 위한 것이 아니다. 특히 글리프 키 기반 패치를 사용하거나 그 사용 방법을 보여 주지 않는다. 대부분의 인코더는 더 복잡할 가능성이 높으며 남은 절에서 설명하는 추가 요소를 고려해야 한다.

§ 6.3 글리프 키 기반 패치

코드 포인트와 기능 태그로 매개변수화되지만 서로 독립적으로 적용할 수 있다는 점 때문에 § 6.3 글리프 키 기반 패치에는 추가 요구 사항이 있으며 서브셋 도구 구현을 사용하여 직접 파생할 수 없다. 그러나 이러한 구현은 이 유형의 패치를 생성할 때 기능적 동등성을 유지하기 위해 인코더가 무엇을 해야 하는지 명확히 하는 데 도움이 된다. 주어진 글꼴 서브셋 정의에 상대적인 글꼴 서브셋 생성 결과를 생각해 보자. 해당 글꼴 서브셋 정의글리프 폐쇄를 서브셋에 포함된 전체 글리프 집합으로 정의할 수 있다. 서브셋 도구는 설명된 코드 포인트와 레이아웃 기능의 임의 조합을 렌더링하는 데 이 글리프 집합이 필요하다고 결정한다.

이 정의를 사용하면 전체 § 6.3 글리프 키 기반 패치 집합에 대한 글리프 폐쇄 요구 사항은 다음과 같다:

서브셋 도구가 정확하게 작업한다고 가정하면 글리프 폐쇄 요구 사항은 동등한 동작 요구 사항의 결과다. 서브셋 도구가 서브셋에 글리프 *i*를 포함하지만 § 6.3 글리프 키 기반 패치를 생성하는 인코더가 해당 정의에 대응하는 패치 집합에서 글리프 *i*를 생략하는 글꼴 서브셋 정의가 있다고 가정하자. 서브셋 도구가 옳다면 해당 글리프는 정의의 코드 포인트 및 기능 조합을 렌더링할 때 동등한 동작을 유지하기 위해 존재해야 한다. 이는 증분 글꼴이 해당 조합을 렌더링할 때 동등하게 동작하지 않음을 의미한다.

따라서 글리프 키 기반 패치를 사용하는 인코딩을 생성할 때 인코더는 글리프 폐쇄 요구 사항을 충족하는 방식으로 모든 패치 사이에 글리프를 분배하는 방법을 결정해야 한다. 이는 주로 세그먼트에 할당된 코드 포인트를 살펴보고 어떤 다른 글리프가 대응 패치에 포함되어야 하는지 결정하는 문제다. 예를 들어 코드 포인트에 의해 세그먼트에 포함된 글리프를 글리프 변형으로 치환할 수 있는 경우가 있다. 경우에 따라 여러 세그먼트가 로드된 경우에만 글리프가 필요할 수 있으며 이 경우 해당 글리프를 그 세그먼트 중 하나에 대응하는 패치에 추가할 수 있다 (합자 또는 미리 조합된 악센트 문자에서 발생할 수 있음). 마지막으로 세그먼트 초기 분석 후 동일한 글리프가 둘 이상의 세그먼트 패치를 로드할 때 필요할 수 있다. 이 상황을 처리하는 주요 전략은 다섯 가지다:

  1. 둘 이상의 세그먼트를 결합하여 하나의 패치에 포함할 수 있다. 이는 공통 글리프의 중복을 방지하지만 세그먼트 크기를 늘린다.

  2. 공통 글리프를 자체 패치에 배치한 다음 해당 공통 패치가 필요한 세그먼트와 함께 로드되도록 매핑 항목을 설정할 수 있다. 예를 들어 'c'가 세그먼트 'a'와 'b'에 필요한 공통 세그먼트라면 형식 2 매핑 테이블을 통해 다음 매핑 항목을 가질 수 있다:

    • 서브셋 정의 a → 세그먼트 a

    • 서브셋 정의 b → 세그먼트 b

    • 서브셋 정의 a와 서브셋 정의 b의 합집합 → 세그먼트 c

  3. 유니코드 변형 선택자와 같은 경우에는 많은 다른 코드 포인트와 함께 사용될 때 글리프 치환을 유발하는 수정자 코드 포인트가 있다. 대체 글리프 수가 많기 때문에 수정자 코드 포인트와 적절한 기본 코드 포인트가 모두 존재할 때만 로드되는 자체 패치에 유지하는 것이 바람직하다. 이는 형식 2 패치 맵childEntryIndices를 통한 다중 항목 일치를 사용하여 구현할 수 있다. 설정 방법의 예는 예제 2: 하위 항목이 있는 글리프 키 기반 패치를 참조한다.

  4. 또는 글리프 데이터를 여러 패치에 중복하는 대가로 해당 세그먼트에 대응하는 패치 중 둘 이상에 글리프를 포함할 수 있다.

  5. 마지막으로 공통 글리프를 초기 글꼴로 이동할 수 있다. 이는 세그먼트 크기를 늘리고 글리프 데이터를 중복하는 것을 방지하지만 초기 글꼴의 크기를 늘린다. 또한 글리프 데이터가 필요하지 않을 때도 항상 로드된다는 의미다. 이는 많은 세그먼트에서 필요하거나 세그먼트화를 복잡하게 만드는 글리프에 유용할 수 있다.

초기 글꼴에 데이터 미리 로드

경우에 따라 초기 파일에 패치를 적용하는 오버헤드를 피하는 것이 바람직할 수 있다. 예를 들어 회사 홈페이지에 로드되는 글꼴이 이미 해당 페이지의 콘텐츠를 렌더링할 수 있도록 하는 것이 바람직할 수 있다. 이러한 파일의 주요 이점은 렌더링 지연 감소다. 콘텐츠를 한 번의 왕복 후 렌더링할 수 있다.

다운로드되는 글꼴 파일에 데이터를 포함하는 두 가지 접근 방식이 있다. 하나는 증분 글꼴 전체를 단순히 인코딩하여 데이터가 초기 파일에 있도록 하는 것이다. 이러한 데이터는 글꼴의 모든 패치 적용 버전에서 항상 사용할 수 있다. 이는 동일한 데이터가 여러 세그먼트에서 필요할 경우 유용할 수 있다.

다른 접근 방식은 이미 패치가 적용된 글꼴을 다운로드하는 것이다. 즉, "기본" 파일에 데이터가 거의 없거나 전혀 없는 글꼴을 인코딩한 다음 서버 측에서 해당 파일에 패치를 적용하여 다운로드되는 파일에 해당 패치의 데이터가 이미 포함되도록 할 수 있다.

미리 로드된 글꼴 버전이 하나만 필요한 경우 두 전략의 결과는 대략 동등하지만 첫 번째 방식이 더 단순하고 경우에 따라 더 구체적이다. 그러나 둘 이상의 미리 로드된 글꼴이 필요한 경우 사전 패치 방식이 더 나은 경우가 많다. 첫 번째 접근 방식을 사용하면 미리 로드된 각 파일마다 하나씩 여러 인코딩을 생성해야 한다. 두 번째 접근 방식을 사용하면 모든 미리 로드된 파일이 동일한 전체 패치 그래프를 공유하므로 패치를 저장하는 데 필요한 전체 공간이 줄고 모든 미리 로드된 파일이 동일한 집합에서 후속 패치를 선택하여 CDN 캐시 효율이 향상된다.

테이블 순서

초기 글꼴 파일(woff2로 인코딩되었는지 여부와 관계없이)에서 실제 테이블 바이트의 파일 내 순서를 사용자 지정할 수 있다. 인코더는 매핑 테이블(IFT 및 IFTX)과 매핑 테이블을 디코딩하는 데 필요한 추가 테이블(cmap)을 가능한 한 파일 앞부분에 배치하는 것을 고려해야 한다. 그러면 최적화된 클라이언트 구현이 모든 글꼴 데이터를 받기 전에 패치 매핑에 접근하여 필요한 패치 요청을 더 일찍 시작할 수 있다.

마찬가지로 테이블 키 기반 패치는 패치되는 각 테이블에 별도의 brotli 스트림을 가지며 형식은 이러한 스트림을 패치 파일의 임의 순서로 배치할 수 있게 한다. 따라서 같은 이유로 인코더는 매핑 테이블 업데이트와 매핑 테이블을 디코딩하는 데 필요한 추가 테이블을 가능한 한 패치 파일 앞부분에 배치하는 것을 고려해야 한다.

입력 ID 인코딩 선택

이 명세는 패치 ID를 URL 템플릿에 삽입하기 위한 두 가지 인코딩을 지원한다. 첫 번째는 일반적으로 파일 시스템에 저장될 미리 생성된 패치에 적합한 base32hex다. Base32hex 인코딩은 0-9와 A-V만 사용하며, 이는 일반적으로 사용되는 모든 파일 시스템의 파일 이름에 안전한 문자이고 대소문자 구분이 없어서 발생하는 충돌 위험도 없다. 문자열은 패딩 없이 삽입되므로 이 형식은 안정적으로 디코딩할 수 없으며 동적으로 생성되는 패치에는 적합하지 않을 수 있다. 다른 인코딩은 URL 또는 대소문자를 구분하는 파일 시스템에 삽입하기 적합한 base64 변형인 base64url이다. 이 인코딩을 사용할 때 id는 값을 안정적으로 디코딩할 수 있도록 패딩과 함께 삽입된다.

개별 문자 선택자 d1부터 d4는 base32hex로 인코딩된 id에만 상대적이다. 일반적으로 id 인코딩의 마지막 문자를 기준으로 관련 파일을 하나 이상의 하위 디렉터리 수준에 분산하여 단일 파일 시스템 디렉터리에 저장되는 파일 수를 줄이는 데 사용된다. 정수 id를 사용할 때는 숫자 사이에 고르게 분포하는 경향이 있지만 문자열 id에서는 고르지 않게 분포하거나 일정할 수도 있다. 문자열 id와 함께 d1부터 d4를 사용하려는 인코더는 id 문자열의 끝부분이 달라지도록 주의해야 한다. d1부터 d4와 base64url로 인코딩된 id를 혼합하는 것은 유효하다.

8. 개인정보 보호 고려 사항

8.1. 문자 집합을 통한 콘텐츠 추론

IFT는 웹 글꼴을 호스팅하는 서버에 브라우저가 해당 글꼴로 렌더링하려는 문자 집합에 관한 정보를 노출한다(자세한 내용은 § 4 글꼴 서브셋 확장 참조).

매우 큰 문자 집합을 사용하는 일부 언어(중국어와 일본어가 예)에서는 전체 전송 바이트가 크게 줄어들어 모바일 네트워크를 포함한 환경에서도 처음으로 웹 글꼴을 사용할 수 있게 된다. 그러나 이러한 언어에서는 악의적인 글꼴 서버가 개별 요청을 분석하여 읽고 있는 콘텐츠 유형에 관한 정보를 얻을 가능성이 있다. 요청되는 문자가 매우 특이하지 않은 한 이 공격이 얼마나 실현 가능한지 또는 악용에 필요한 계산 복잡도는 명확하지 않다.

더 구체적으로 IFT 글꼴은 유니코드 코드 포인트 그룹 집합을 포함하며 렌더링되는 콘텐츠와 교차하는 그룹에 대해 요청한다. 이는 그룹의 코드 포인트 중 하나 이상이 필요했다는 정보를 호스팅 서버에 제공하지만 그룹 내에서 어떤 구체적인 코드 포인트가 필요했는지는 포함하지 않는다. 이는 기존 CSS Fonts 4 § 4.5 문자 범위: unicode-range 설명자와 기능적으로 매우 유사하며 동일한 개인정보 보호 영향을 가진다. unicode-range의 개인정보 보호 영향에 관한 논의는 CSS Fonts 4 명세에서 확인할 수 있다:

콘텐츠 및/또는 사이트 작성자가 IFT 글꼴을 사용하도록 선택하면 위에서 설명한 것처럼 IFT 글꼴을 확장하는 동안 렌더링되는 콘텐츠에 관한 일정량의 정보가 전송되므로 해당 글꼴을 인코딩한 주체와 글꼴을 로드한 서비스를 어느 정도 신뢰하게 된다. (아래에서 설명하는 것처럼 인코딩에 더 많은 주의를 기울일수록 서비스에 대한 신뢰는 줄어들므로 둘 사이에는 균형이 있다.) 따라서 개인정보 보호에 민감한 경우 콘텐츠에 관한 정보가 제3자에게 전송되는 것을 방지하도록 IFT 글꼴을 자체 호스팅하는 것이 권장된다. 또한 이러한 경우 다른 출처에서 글꼴을 로드하지 못하도록 콘텐츠 보안 정책 설정을 구성하는 것이 권장된다.

8.2. IFT 글꼴 인코딩과 개인정보 보호

IFT 글꼴을 인코딩하는 방식은 패치 파일 전송을 통해 콘텐츠에 관한 정보를 얼마나 많이 추론할 수 있는지에 큰 영향을 준다. 이 절에서는 IFT 글꼴 인코딩 시 내린 선택의 개인정보 보호 영향을 평가하는 방법에 관한 일반 지침을 제공한다.

IFT 글꼴은 연결된 활성화 조건을 가진 패치 집합으로 나뉜다. 패치를 요청하면 콘텐츠에 해당 패치의 활성화 조건과 교차하는 항목이 포함되어 있음을 전달한다. 따라서 글꼴의 활성화 조건 구조가 인코딩의 개인정보 보호 특성을 평가하는 데 가장 중요한 측면이다.

글꼴이 지원하는 각 고유 코드 포인트, 기능 및 디자인 공간 구성은 존재 여부라는 잠재적 신호를 제공한다. 활성화 조건은 논리합 또는 논리곱일 수 있다. 논리합 조건은 조건의 개별 항목 중 하나 이상이 존재했다는 사실만 전달하므로 불확실성을 도입한다. 반면 논리곱 패치는 각 개별 항목이 동시에 존재해야 하므로 불확실성을 추가하지 않는다.

코드 포인트 또는 기능의 일반적인 발생 빈도는 해당 항목의 존재가 전달하는 정보의 양에 영향을 준다. 발생 빈도가 높은 항목은 빈도가 낮은 항목보다 적은 정보를 전달한다. 낮은 빈도의 코드 포인트가 존재하면 가능한 콘텐츠 집합이 훨씬 더 좁아진다. 개괄적으로 이는 빈도가 낮은 항목을 포함하는 조건에는 더 크고 덜 세분화된 조건을 사용해야 함을 의미한다.

이 명세를 개발하는 동안 수행한 시뮬레이션에서는 논리합 조건의 최소 그룹 크기가 4~7개 항목일 때 양호한 수준의 모호성을 제공함을 확인했다. 인코딩에서 최소 그룹 크기를 사용하는 것은 성능 측면에서도 좋은 방법이다. 지나치게 세분화된 패치는 과도한 오버헤드를 유발하여 성능을 저하시킨다. 저빈도 항목은 드물게 필요하므로 해당 항목을 포함하는 패치에 최소 그룹 크기를 적용해도 전체 성능에는 영향이 적다. 전체 성능은 고빈도 항목이 좌우하는 경향이 있다.

인코더는 생성된 인코딩의 각 조건을 평가하고 유효 그룹 크기를 결정해야 한다. 유효 그룹 크기는 개별 항목(코드 포인트, 레이아웃 태그, 디자인 공간) 중에서 해당 조건을 트리거하는 데 기여하는 가장 작은 논리합 하위 조건이다. 개인정보 보호에 민감한 사용 사례를 위한 인코딩에서는 인코더가 모든 조건의 최소 그룹 크기가 적어도 4~7이 되도록 보장해야 한다. 예를 들어 다음 경우를 생각해 보자:

인코더는 사용 사례마다 필요한 수준이 다르므로 생성되는 인코딩의 개인정보 보호 수준에 대한 구성 제어를 제공해야 한다. 예를 들어 https를 통해 자체 호스팅하도록 인코딩된 글꼴은 일반적인 제3자 글꼴 서비스에 호스팅될 IFT 글꼴과 비교하여 개인정보 보호 문제를 유발하지 않는다. 개인정보 보호에 덜 민감한 경우를 위한 인코딩에서는 권장 최소 그룹 크기를 위반하는 최적화를 선택할 수 있다. 예를 들어 유효 그룹 크기가 1인 선택적 레이아웃 기능의 데이터를 추가하는 조건을 둘 수 있다.

인코더가 특정 인코딩의 개인정보 보호 정도를 유연하게 제공하는 경우 문서 및/또는 사용자 인터페이스에서 이 절의 정보를 충분히 전달하여 인코딩을 만드는 사용자가 적절한 선택을 할 수 있도록 하는 것이 권장된다. 마찬가지로 IFT 글꼴을 호스팅하는 사이트는 자체 글꼴을 인코딩하거나 제3자로부터 이미 인코딩된 글꼴을 얻을 때 개인정보 보호를 고려하는 것이 권장된다.

8.3. 출처별 제한으로 핑거프린팅 방지

[css-fonts-4]에서 요구하는 것처럼:

"웹 글꼴은 @font-face 규칙과 연결되거나 FontFaceSet을 소유하는 문서 외의 다른 문서에서 접근할 수 없어야 한다. 기기의 다른 애플리케이션은 웹 글꼴에 접근할 수 없어야 한다." - CSS Fonts 4 § 10.2 웹 글꼴

IFT 글꼴은 CSS에서 일반 글꼴과 동일하게 처리되므로(§ 2 옵트인 메커니즘) 이러한 요구 사항이 적용되며 출처 간 정보 유출을 방지한다.

글꼴 팔레트 값에도 유사한 요구 사항이 적용된다:

"작성자가 정의한 글꼴 색상 팔레트는 이를 참조하는 문서에서만 사용할 수 있어야 한다. 이를 참조하는 문서 외부에서 작성자 정의 색상 팔레트를 사용하면 한 페이지의 콘텐츠가 다른 페이지에 영향을 줄 수 있으므로 보안 유출이 되며 공격자가 공격 경로로 사용할 수 있다." - CSS Fonts 4 § 9.2 사용자 정의 글꼴 색상 팔레트: @font-palette-values 규칙

9. 보안 고려 사항

한 가지 보안 문제는 IFT 글꼴이 잠재적으로 패치에 대한 많은 네트워크 요청을 생성할 수 있다는 것이다. 이는 클라이언트 또는 패치를 호스팅하는 서비스에 문제를 일으킬 수 있다. IFT 명세에는 과도한 요청 수를 제한하기 위한 몇 가지 완화 조치가 포함되어 있다:

  1. § 4 글꼴 서브셋 확장: 동일한 URL을 여러 번 다시 요청하는 것을 금지하고 확장 과정 중 발행할 수 있는 전체 요청 수를 제한한다.

  2. 패치 파일 로드: 웹 브라우저 구현에서 [FETCH] 사용을 지정하고 초기 글꼴 로드의 CORS 설정과 일치시킨다. 그 결과 호스팅 서비스가 적절한 접근 제어 헤더를 통해 옵트인하지 않는 한 패치 파일에 대한 교차 출처 요청은 허용되지 않는다.

10. 변경 사항

2025년 7월 31일 후보 권고안 스냅샷 이후(커밋 기록 참조):

2025년 7월 15일 작업 초안 이후(커밋 기록 참조):

2025년 2월 20일 작업 초안 이후(커밋 기록 참조):

2024년 7월 9일 작업 초안 이후(커밋 기록 참조):

부록 A: 기본 기능 태그

이 부록은 규범적이지 않다. 대부분의 셰이퍼 구현에서 기본적으로 사용되는 것으로 간주되는 레이아웃 기능 목록을 제공한다. 이 목록은 다음 자료에서 구성했다:

셰이퍼에서 기본적으로 사용하는 레이아웃 기능

태그 이름
abvf 기준선 위 형태
abvm 기준선 위 마크 위치 지정
abvs 기준선 위 치환
akhn Akhand
blwf 기준선 아래 형태
blwm 기준선 아래 마크 위치 지정
blws 기준선 아래 치환
calt 문맥 대체
ccmp 글리프 조합 / 분해
cfar Ro 뒤의 결합 형태
chws 문맥 반각 간격
cjct 결합 형태
clig 문맥 합자
cswh 문맥 스와시
curs 필기체 위치 지정
dist 거리
dnom 분모
dtls 점 없는 형태
fin2 종결 형태 #2
fin3 종결 형태 #3
fina 종결 형태
flac 평탄화된 악센트 형태
frac 분수
half 반 형태
haln Halant 형태
init 초기 형태
isol 독립 형태
jalt 정렬 대체
kern 커닝
liga 표준 합자
ljmo 초성 자모 형태
locl 지역화된 형태
ltra 왼쪽에서 오른쪽 대체
ltrm 왼쪽에서 오른쪽 반전 형태
mark 마크 위치 지정
med2 중간 형태 #2
medi 중간 형태
mkmk 마크 간 위치 지정
mset 치환을 통한 마크 위치 지정
nukt Nukta 형태
numr 분자
pref 기준선 앞 형태
pres 기준선 앞 치환
pstf 기준선 뒤 형태
psts 기준선 뒤 치환
rand 무작위화
rclt 필수 문맥 대체
rkrf Rakar 형태
rlig 필수 합자
rphf Reph 형태
rtla 오른쪽에서 왼쪽 대체
rtlm 오른쪽에서 왼쪽 반전 형태
rvrn 필수 변형 대체
ssty 수학 스크립트 스타일 대체
stch 늘이기 글리프 분해
tjmo 종성 자모 형태
valt 대체 세로 메트릭
vatu Vattu 변형
vchw 세로 문맥 반각 간격
vert 세로 쓰기
vjmo 중성 자모 형태
vkrn 세로 커닝
vpal 비례 대체 세로 메트릭
vrt2 세로 대체 및 회전
vrtr 회전용 세로 대체

부록 B: 확장 알고리즘 실행 예제

이 부록은 규범적이지 않다. 일반적인 IFT 글꼴이 § 4.3 증분 글꼴 확장 알고리즘에 의해 처리되는 방법의 예를 제공한다.

예제 1: 테이블 및 글리프 키 기반 패치

이 예에서 IFT 글꼴은 § 6.2 테이블 키 기반§ 6.3 글리프 키 기반 패치를 혼합하여 포함한다.

초기 글꼴: 다음 IFT 및 IFTX 패치 매핑을 포함한다. 참고: 서브셋 정의에서 기능 및 디자인 공간 집합이 지정되지 않으면 빈 집합으로 기본 설정된다.

테이블 = "IFT " 호환성 ID = 0x0000_0000_0000_0001
서브셋 정의 URL 형식 번호
code points: { 'a', 'b', ..., 'z' }
//foo.bar/01.tk 2, 테이블 키 기반 - 부분 무효화
code points: { 'A', 'B', ..., 'Z' }
//foo.bar/02.tk 2, 테이블 키 기반 - 부분 무효화
code points: { '0', '1', ..., '9' }
//foo.bar/03.tk 2, 테이블 키 기반 - 부분 무효화
code points: { 'a', 'b', ..., 'z',
               'A', 'B', ..., 'Z' }
//foo.bar/04.tk 2, 테이블 키 기반 - 부분 무효화
code points: { 'a', 'b', ..., 'z',
               'A', 'B', ..., 'Z',
               '0', '1', ..., '9' }
//foo.bar/05.tk 2, 테이블 키 기반 - 부분 무효화

테이블 = "IFTX" 호환성 ID = 0x0000_0000_0000_0002
서브셋 정의 URL 형식 번호
code points: { 'a', 'b', ..., 'm' }
//foo.bar/01.gk 3, 글리프 키 기반
code points: { 'n', 'o', ..., 'z' }
//foo.bar/02.gk 3, 글리프 키 기반
code points: { 'A', 'B', ..., 'M' }
//foo.bar/03.gk 3, 글리프 키 기반
code points: { 'N', 'O', ..., 'Z' }
//foo.bar/04.gk 3, 글리프 키 기반
code points: { '0', '1', ..., '9' }
//foo.bar/05.gk 3, 글리프 키 기반

최적화된 확장 예제

참고: 이 예제 실행은 대상 서브셋 정의를 위해 글꼴을 확장하는 데 필요한 왕복 횟수를 줄이는 것을 목표로 하는 최적화된 클라이언트에서 구현되는 방식으로 설명한다. 이 최적화된 실행은 확장 알고리즘을 완전히 준수하지만 일부 URL(글리프 키 기반 URL)을 확장 알고리즘에 지정된 시점보다 일찍 로드한다. 이러한 패치는 앞선 테이블 키 기반 패치에 의해 무효화되지 않으므로 허용된다.

입력:

반복 1:

반복 2:

반복 3:

반복 4:

예제 2: 하위 항목이 있는 글리프 키 기반 패치

이 예에서 IFT 글꼴은 § 6.3 글리프 키 기반 패치 집합을 포함하며, UVS 치환을 올바르게 처리하기 위해 하위 항목을 사용한다. 각 기본 글리프 집합에는 변형 선택자를 통해 치환되는 대체 글리프 집합이 있다. 이들은 별도의 패치에 유지된다. 대체 글리프 패치는 하위 항목을 통해 기본 글리프와 변형 선택자가 동시에 존재할 때만 로드되도록 구성된다.

초기 글꼴: 다음 IFT 패치 매핑을 포함한다. 참고: 서브셋 정의에서 코드 포인트, 기능, 디자인 공간 또는 하위 항목 집합이 지정되지 않으면 빈 집합으로 기본 설정된다.

테이블 = "IFT " 호환성 ID = 0x0000_0000_0000_0001
서브셋 정의 URL 형식 번호 무시됨? 참고
code points:
  { 'a', 'b', ..., 'm' }
//foo.bar/01.gk 3, 글리프 키 기반 아니요
code points:
  { 'n', 'o', ..., 'z' }
//foo.bar/02.gk 3, 글리프 키 기반 아니요
code points: { VS1 }
N/A 3, 글리프 키 기반
child entries: [0, 2],
match mode: conjunctive
//foo.bar/03.gk 3, 글리프 키 기반 아니요 VS1에 의해 활성화되는 {'a', ..., 'm'}의 대체 글리프를 포함
child entries: [1, 2],
match mode: conjunctive
//foo.bar/04.gk 3, 글리프 키 기반 아니요 VS1에 의해 활성화되는 {'n', ..., 'z'}의 대체 글리프를 포함

확장 예제 1

입력:

반복 1:

반복 2:

확장 예제 2

입력:

반복 1:

반복 2:

반복 3:

적합성

문서 규칙

적합성 요구 사항은 설명적 주장과 RFC 2119 용어를 조합하여 표현한다. 이 문서의 규범적 부분에서 사용하는 핵심어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” 및 “OPTIONAL”은 RFC 2119에 설명된 대로 해석해야 한다. 그러나 가독성을 위해 이 명세에서는 이러한 단어를 모두 대문자로 표기하지 않는다.

명시적으로 비규범적이라고 표시된 절, 예제 및 참고를 제외한 이 명세의 모든 텍스트는 규범적이다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 시작하거나 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분한다:

이는 정보 제공용 예제의 한 예다.

정보 제공용 참고는 “참고”라는 말로 시작하며 다음과 같이 class="note"를 사용하여 규범적 텍스트와 구분한다:

참고, 이는 정보 제공용 참고다.

적합 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구 사항 (예: "선행 공백 문자를 모두 제거한다" 또는 "false를 반환하고 이 단계를 중단한다")은 알고리즘을 도입할 때 사용한 핵심어 ("must", "should", "may" 등)의 의미에 따라 해석해야 한다.

알고리즘 또는 구체적인 단계로 표현된 적합성 요구 사항은 최종 결과가 동등하기만 하면 어떤 방식으로든 구현할 수 있다. 특히 이 명세에 정의된 알고리즘은 이해하기 쉽도록 작성되었으며 성능을 목적으로 하지 않는다. 구현자는 최적화하는 것이 권장된다.

색인

이 명세에서 정의하는 용어

참조로 정의된 용어

참고 문헌

규범적 참고 문헌

[CSS-FONTS-4]
Chris Lilley. CSS 글꼴 모듈 레벨 4. 2024년 2월 1일. WD. URL: https://www.w3.org/TR/css-fonts-4/
[FETCH]
Anne van Kesteren. Fetch 표준. 현행 표준. URL: https://fetch.spec.whatwg.org/
[I18N-GLOSSARY]
Richard Ishida; Addison Phillips. 국제화 용어집. 2024년 10월 17일. NOTE. URL: https://www.w3.org/TR/i18n-glossary/
[ISO14496-22]
정보 기술 — 시청각 객체의 코딩 — 제22부: 개방형 글꼴 형식. 개발 중. URL: https://www.iso.org/standard/87621.html
[OPEN-TYPE]
OpenType 명세. 2024년 5월. Note. URL: https://learn.microsoft.com/en-us/typography/opentype/spec
[PFE-report]
Chris Lilley. 점진적 글꼴 보강: 평가 보고서. 2020년 10월 15일. Note. URL: https://www.w3.org/TR/PFE-evaluation/
[RFC2119]
S. Bradner. 요구 수준을 나타내기 위해 RFC에서 사용하는 핵심어. 1997년 3월. 현재 최선의 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC4648]
S. Josefsson. Base16, Base32 및 Base64 데이터 인코딩. 2006년 10월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc4648
[RFC7932]
J. Alakuijala; Z. Szabadka. Brotli 압축 데이터 형식. 2016년 7월. 정보 제공. URL: https://www.rfc-editor.org/rfc/rfc7932
[Shared-Brotli]
J. Alakuijala; 외. 공유 Brotli 압축 데이터 형식. 2025년 2월. 인터넷 초안. URL: https://datatracker.ietf.org/doc/html/draft-vandevenne-shared-brotli-format-15
[UNICODE]
유니코드 표준. URL: https://www.unicode.org/versions/latest/
[UTF-8]
F. Yergeau. UTF-8, ISO 10646의 변환 형식. 2003년 11월. 인터넷 표준. URL: https://www.rfc-editor.org/rfc/rfc3629
[WHATWG-URL]
Anne van Kesteren. URL 표준. 현행 표준. URL: https://url.spec.whatwg.org/
[WOFF2]
Vladimir Levantovsky. WOFF 파일 형식 2.0. 2024년 8월 8일. REC. URL: https://www.w3.org/TR/WOFF2/

비규범적 참고 문헌

[CSS-CONDITIONAL-5]
Chris Lilley; 외. CSS 조건부 규칙 모듈 레벨 5. 2025년 10월 30일. WD. URL: https://www.w3.org/TR/css-conditional-5/
[ENABLING-TYPOGRAPHY]
John Hudson. 타이포그래피 활성화: OpenType 레이아웃의 일반 모델을 향하여. 2014년 4월 15일. Note. URL: https://www.tiro.com/articles/enabling-typography
[RFC9113]
M. Thomson, 편집자; C. Benfield, 편집자. HTTP/2. 2022년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc9113.html
[RFC9114]
M. Bishop, 편집자. HTTP/3. 2022년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc9114.html
[WOFF]
Jonathan Kew; Tal Leming; Erik van Blokland. WOFF 파일 형식 1.0. 2012년 12월 13일. REC. URL: https://www.w3.org/TR/WOFF/