1. 소개
이 절은 비규범적입니다.
점진적 글꼴 전송(IFT)은 웹에서 원격 글꼴(또는 "웹 글꼴")의 지연 시간을 개선하는 기술입니다. 이 기술이 없으면 브라우저는 해당 글꼴을 사용하여 문자를 렌더링하기 전에 글꼴의 모든 바이트를 다운로드해야 합니다. IFT를 사용하면 브라우저가 파일의 일부 바이트만 다운로드할 수 있으므로 브라우저가 글꼴이 필요하다는 사실을 인식한 시점부터 해당 글꼴로 필요한 텍스트를 렌더링할 수 있는 시점까지 사용자가 체감하는 지연 시간이 줄어듭니다. 기존 글꼴 하위 집합 생성 방식과 달리 점진적 글꼴 전송은 세그먼트 간의 레이아웃 규칙 인코딩을 유지합니다(점진적 글꼴 보강: 평가 보고서 § fail-subset).
웹 글꼴의 성공적인 활용은 고르게 분포되어 있지 않습니다. 이 명세를 사용하면 느린 네트워크, 매우 큰 글꼴 또는 복잡한 하위 집합 생성 요구 사항으로 인해 현재 사용이 어려운 환경에서도 웹 글꼴을 사용할 수 있습니다. 예를 들어 WOFF 2 [WOFF2]를 사용하더라도 CJK 언어용 글꼴은 실용적으로 사용하기에 너무 클 수 있습니다.
1.1. 기술적 동기: 평가 보고서
이 명세의 개발로 이어진 조사에 대해서는 점진적 글꼴 보강: 평가 보고서 [PFE-report]를 참조하십시오.
1.2. 개요
점진적 글꼴은 점진적 기능을 포함하도록 형식을 변경한 일반적인 OpenType 글꼴이며, 이러한 기능은 부분적으로 두 개의 추가 테이블을 통해 구현됩니다. 이러한 새 테이블을 사용하면 패치를 불러와 적용하여 글꼴을 확장할 수 있습니다(예: 더 많은 코드 포인트 지원).
IFT 기술은 네 가지 주요 구성 요소로 이루어집니다.
-
§ 4 글꼴 하위 집합 확장: 클라이언트가 패치를 선택하고 적용하는 데 사용하는 알고리즘을 제공합니다.
-
§ 5 글꼴 형식 확장: 글꼴에 적용할 수 있는 패치 목록을 포함하는 새 테이블을 정의합니다.
-
§ 6 글꼴 패치 형식: 사용할 수 있는 두 가지 유형의 패치를 정의합니다. 하나는 "범용" 바이너리 패치이고 다른 하나는 글리프 데이터를 저장하는 글꼴 형식에 특화된 패치입니다.
-
§ 7 인코딩: 점진적 글꼴을 구성하는 글꼴과 관련 패치를 생성합니다.
개략적으로 점진적 글꼴은 다음과 같이 사용됩니다.
-
클라이언트는 전체 글꼴 버전에서 추출한 초기 데이터 하위 집합과 글꼴을 확장하는 데 사용할 수 있는 패치 집합을 설명하는 내장 데이터가 포함된 초기 글꼴 파일을 다운로드합니다.
-
렌더링할 콘텐츠에 따라 클라이언트는 패치를 선택하고 다운로드하여 적용함으로써 추가 문자, 레이아웃 기능 및/또는 변형 공간을 지원하도록 글꼴을 확장합니다. 이 단계는 새로운 콘텐츠가 있을 때마다 반복됩니다.
1.3. 점진적 글꼴 생성
점진적 글꼴을 생성하는 가장 일반적인 방법은 기존 글꼴을 변환하여 이 명세에서 정의한 점진적 인코딩을 사용하도록 만드는 방식일 것으로 예상됩니다. 개략적으로 기존 글꼴을 점진적 글꼴로 변환하는 과정은 다음과 같습니다.
-
초기 하위 집합의 콘텐츠를 선택합니다. 이 콘텐츠는 클라이언트가 불러오는 초기 글꼴 파일에 포함되며 일반적으로 항상 필요할 것으로 예상되는 원본 글꼴의 데이터로 구성됩니다.
-
패치 유형을 하나 이상 선택합니다. 패치 유형마다 특성이 다르므로 사용 사례에 따라 서로 다른 패치 유형이 필요할 수 있으며, 경우에 따라 두 유형을 함께 사용할 수도 있습니다.
-
글꼴의 분할 방식을 선택합니다. 클라이언트는 패치를 사용하여 개별 세그먼트를 기본 하위 집합에 추가합니다. 적절한 분할 방식을 선택하는 것은 효율적인 인코딩을 생성하는 데 가장 중요한 부분 중 하나입니다.
-
이러한 선택을 바탕으로 패치 집합을 생성합니다. 각 패치는 초기 글꼴 파일 또는 이전 패치를 기준으로 특정 세그먼트의 데이터를 추가합니다.
-
초기 하위 집합과 패치 매핑을 포함하는 초기 글꼴 파일을 생성합니다. 이 매핑에는 사용 가능한 모든 패치 파일, 해당 파일이 위치한 URL, 그리고 패치가 글꼴에 추가할 데이터에 관한 정보가 나열됩니다.
참고: 이는 점진적 글꼴 생성 과정을 매우 단순화하여 설명한 것입니다. 인코딩 생성에 관한 자세한 논의와 인코딩 요구 사항은 § 7 인코딩 절에서 확인할 수 있습니다.
1.4. 성능 고려 사항과 점진적 글꼴 전송의 활용
점진적 전송을 사용하는 것이 항상 유익한 것은 아니며, 글꼴의 특성, 네트워크 및 렌더링할 콘텐츠에 따라 달라집니다. 이 절에서는 점진적 전송을 언제 활용해야 하는지 판단하는 데 도움이 되는 비규범적 지침을 제공합니다.
점진적 글꼴에서는 여러 패치를 병렬로 불러오는 일이 일반적입니다. 따라서 성능을 극대화하려면 점진적 글꼴을 제공할 때 다중화를 지원하는 HTTP 서버(예: [rfc9113] 또는 [rfc9114])를 사용하는 것이 권장됩니다.
글꼴을 점진적으로 불러오는 방식에는 전체 글꼴을 불러오는 방식과 비교하여 근본적인 성능 절충 관계가 있습니다. 간단히 말해 점진적 전송은 전송되는 바이트 수를 줄일 수 있지만, 전체 네트워크 요청 수가 증가하거나 요청 처리 지연 시간이 늘어날 수 있습니다. 일반적으로 전송 바이트 수 감소로 인한 지연 시간 단축 효과가 점진적 전송 방식으로 발생하는 추가 지연 시간보다 클 때 점진적 글꼴 전송이 유익합니다.
첫 번째로 고려해야 할 요소는 렌더링할 콘텐츠의 언어입니다. 평가 보고서에는 세 가지 언어 범주에 걸쳐 점진적 글꼴 전송을 시뮬레이션한 결과가 포함되어 있습니다(점진적 글꼴 보강: 평가 보고서 § langtype). 언어 범주별 점진적 글꼴 전송의 예상 성능에 관한 논의는 보고서의 결론인 점진적 글꼴 보강: 평가 보고서 § conclusions를 참조하십시오.
다음으로 글꼴의 어느 정도가 필요할 것으로 예상되는지 고려해야 합니다. 콘텐츠를 렌더링하는 데 글꼴의 대부분이 필요할 것으로 예상된다면 점진적 글꼴 전송은 유익하지 않을 가능성이 높습니다. 그러나 많은 경우 글꼴의 일부만 필요할 것으로 예상됩니다. 예를 들면 다음과 같습니다.
-
글꼴이 여러 언어를 지원하지만 사용자가 해당 언어 중 일부 언어의 콘텐츠만 렌더링할 것으로 예상되는 경우입니다.
-
렌더링할 콘텐츠가 글꼴에 포함된 전체 문자 중 일부만 사용하는 경우입니다. 이는 중국어, 일본어, 한국어, 이모지 및 아이콘 글꼴에서 흔히 발생합니다.
-
소량의 텍스트만 렌더링하는 경우입니다. 예를 들어 제목에만 사용되는 글꼴이 이에 해당합니다.
점진적 전송의 대안은 글꼴을 별도의 하위 집합으로 나누고(일반적으로 문자 체계별로) @font-face의 유니코드 범위 기능을 사용하여 필요한 하위 집합만 불러오는 것입니다. 그러나 서로 다른 하위 집합의 문자 사이에 레이아웃 규칙이 있는 경우 일부 콘텐츠의 렌더링이 변경될 수 있습니다(점진적 글꼴 보강: 평가 보고서 § 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 지원 기능을 사용하는 것입니다.
@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에는 두 개의 URL을 포함할 수 있으며, 하나에는
tech(incremental, color-COLRv1)을, 다른 하나에는
tech(incremental, color-COLRv0)을 사용할 수 있습니다.
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로의 매핑 모음을 인코딩합니다. 이러한 패치는 점진적 글꼴을 확장합니다. 패치 맵 테이블은 패치 맵 항목 목록을 인코딩하며, 각 항목에는 키와 값이 있습니다. 항목의 키는 해당 항목의 적용 범위를 정의하며, 이는 어떤 하위 집합 정의가 해당 항목과 일치하는지에 관한 정보입니다. 값은 항목이 일치할 때 적용해야 하는 패치에 관한 정보를 지정합니다. 패치 맵 항목의 요약은 다음과 같습니다.
| 키 | 값 |
|---|---|
|
패치 맵 형식에 관한 자세한 내용은 § 5 글꼴 형식 확장에서 확인할 수 있습니다.
3.4. 데이터 유형 설명
이 명세의 나머지 부분에서 인코딩된 데이터 구조는 OpenType 명세 § otff#data-types에 정의된 데이터 유형을 사용하여 설명합니다. OpenType의 다른 부분과 마찬가지로 모든 필드는 "빅 엔디언" 바이트 순서를 사용합니다.
4. 글꼴 하위 집합 확장
이 절에서는 클라이언트가 점진적 글꼴 하위 집합을 확장하여 추가 코드 포인트, 레이아웃 기능 및/또는 디자인 공간을 지원하도록 하는 알고리즘을 정의합니다. 이 알고리즘은 다음 작업을 반복합니다.
-
글꼴 하위 집합의 패치 매핑을 사용 가능한 패치 목록으로 파싱합니다.
-
사용 가능한 패치 중 렌더링할 콘텐츠와 일치하는 패치가 있는지 확인합니다.
-
사용 가능한 패치 하나를 선택하여 불러온 다음 적용합니다.
이 과정은 관련된 패치가 더 이상 남지 않을 때까지 반복됩니다. 패치를 적용하면 글꼴 파일에 내장된 패치 매핑이 변경될 수 있으므로, 매 반복마다 현재 버전의 글꼴 하위 집합에 있는 패치 맵을 다시 파싱하여 남아 있는 패치를 확인합니다. 따라서 매 반복마다 글꼴 하위 집합은 사용 가능한 패치를 판단하는 신뢰할 수 있는 정보원이 되며, 확장 과정의 현재 상태를 완전히 포함합니다.
4.1. 패치 무효화
글꼴 하위 집합에 내장된 패치 매핑은 각 패치의 무효화 모드를 인코딩합니다. 패치의 무효화 모드는 해당 패치를 적용한 후 어떤 다른 패치가 더 이상 유효하지 않게 되는지 표시합니다. 이 무효화 모드는 확장 알고리즘에서 호환되는 패치를 결정하는 데 사용되며 선택 순서에도 영향을 줍니다. 패치 적용 중 패치의 유효성은 § 5.3 패치 맵 테이블의 호환성 ID를 통해 검증됩니다. 모든 패치에는 내부에 인코딩된 호환성 ID가 있으며, 이 ID는 해당 패치를 나열하는 § 5.3 패치 맵 테이블의 호환성 ID와 일치해야 합니다.
무효화 모드에는 세 가지가 있습니다.
-
완전 무효화: 이 패치를 적용하면 현재 글꼴 하위 집합에 나열된 다른 모든 패치가 무효화됩니다. 'IFT '와 'IFTX'의 § 5.3 패치 맵 테이블 모두에서 호환성 ID가 변경됩니다.
-
부분 무효화: 이 패치를 적용하면 동일한 § 5.3 패치 맵 테이블에 있는 다른 모든 패치가 무효화됩니다. 이 패치를 포함하는 § 5.3 패치 맵 테이블의 호환성 ID만 변경됩니다.
-
무효화 없음: 이 패치를 적용해도 다른 패치는 무효화되지 않습니다. 'IFT '와 'IFTX'의 § 5.3 패치 맵 테이블에 있는 호환성 ID는 변경되지 않습니다.
특정 패치의 무효화 모드는 해당 패치의 형식 번호에 인코딩되며, 이는 § 6.1 형식 요약에서 확인할 수 있습니다.
4.2. 기본 레이아웃 기능
대부분의 텍스트 셰이퍼에는 항상 활성화되는 레이아웃 기능 집합이 있으며, 따라서 이러한 기능은 점진적으로 불러오는 글꼴에 항상 필요합니다. 부록 A: 기본 기능 태그에는 작성 시점에 일반적인 셰이퍼 구현에서 기본적으로 필요하다고 알려진 기능 목록이 수록되어 있습니다. 확장 알고리즘에 입력할 글꼴 하위 집합 정의를 구성할 때 클라이언트는 일반적으로 부록 A: 기본 기능 태그에 나열된 모든 기능을 하위 집합 정의에 포함해야 합니다. 그러나 경우에 따라 클라이언트는 사용할 특정 셰이퍼가 부록 A: 기본 기능 태그의 일부 기능을 사용하지 않는다는 사실을 알고 있을 수 있으며, 사용하지 않는 기능을 하위 집합 정의에서 제외하도록 선택할 수 있습니다.
4.3. 점진적 글꼴 확장 알고리즘
다음 알고리즘은 클라이언트가 점진적 글꼴 하위 집합을 확장하여 추가 코드 포인트, 레이아웃 기능 및/또는 디자인 공간을 지원하도록 하는 데 사용됩니다. 이 알고리즘은 필요할 때 패치를 불러오면서 한 번에 하나씩 점진적으로 선택하고 글꼴에 적용합니다. 네트워크 왕복 횟수를 최소화하기 위한 중요한 최적화로, 결과적으로 필요한 모든 패치의 불러오기를 미리 시작할 수 있습니다. 이러한 패치는 두 가지 형태로 나타납니다.
-
첫째, 패치 매핑 항목에는 둘 이상의 URL 문자열이 나열될 수 있으며, 첫 번째 이후의 각 URL 문자열도 향후 반복에서 필요하므로 불러와야 합니다.
-
둘째, § 4.1 패치 무효화를 사용하여 어떤 패치의 불러오기를 시작할 수 있는지 결정합니다. 대상 하위 집합 정의와 일치하고 § 4.1 패치 무효화에 따라 다음에 적용할 패치에 의해 무효화되지 않는 모든 패치는 향후 반복에서 필요할 것으로 예상할 수 있습니다.
점진적 글꼴 하위 집합 확장하기
이 알고리즘의 입력은 다음과 같습니다.
-
initial font URL: font subset이 파생된 초기 점진적 글꼴의 위치를 식별하는 URL입니다.
-
target subset definition: 클라이언트가 font subset을 확장하여 지원하도록 하려는 글꼴 하위 집합 정의입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
extended font subset: font subset의 확장된 버전입니다. 점진적 글꼴일 수도 있고 아닐 수도 있습니다.
알고리즘은 다음과 같습니다.
-
extended font subset을 font subset으로 설정합니다.
-
extended font subset에서 'IFT ' 및 'IFTX'(존재하는 경우) 매핑 테이블을 불러옵니다. 두 테이블은 모두 § 5.3 패치 맵 테이블 형식으로 구성되어 있습니다. § 5.3 패치 맵 테이블의 요구 사항에 따라 유효한지 확인합니다. 어느 테이블이든 유효하지 않으면 오류 처리하기를 호출합니다. extended font subset에 'IFT ' 테이블이 없으면 해당 글꼴은 점진적 글꼴이 아니므로 확장할 수 없습니다. extended font subset을 반환합니다.
-
'IFT '의 호환성 ID가 'IFTX'의 호환성 ID와 같으면 오류이므로 오류 처리하기를 호출합니다.
-
'IFT ' 및 'IFTX'(존재하는 경우) 테이블 각각에 대해 패치 맵 해석하기를 호출하여 테이블을 항목 목록으로 변환합니다. 반환된 항목 목록들을 하나의 목록인 entry list로 연결합니다.
-
entry list의 각 entry에 대해 entry와 target subset definition을 입력으로 하여 항목 교집합 확인하기를 호출합니다. false를 반환하면 entry를 entry list에서 제거합니다. 또한 이 알고리즘의 실행 중 이전에 불러와서 적용한 패치 URL 문자열을 가진 모든 항목도 entry list에서 제거합니다.
-
entry list가 비어 있으면 확장 작업이 완료된 것이므로 extended font subset을 반환합니다.
-
entry list의 항목들을 각 항목의 패치 형식의 무효화 모드에 따라 세 목록으로 분류합니다. full invalidation entry list, partial invalidation entry list, 그리고 no invalidation entry list입니다.
-
다음 절차에 따라 하나의 entry를 선택합니다.
-
full invalidation entry list가 비어 있지 않으면 포함된 항목 중 정확히 하나를 선택합니다. 단일 항목을 선택할 때는 § 4.4 무효화 패치 선택의 기준을 따릅니다.
-
그렇지 않고 partial invalidation entry list가 비어 있지 않으면 포함된 항목 중 정확히 하나를 선택합니다. 단일 항목을 선택할 때는 § 4.4 무효화 패치 선택의 기준을 따릅니다.
-
그렇지 않으면 no invalidation entry list에서 패치 맵에 가장 먼저 나열된 항목( entries 배열에서 가장 먼저 나타나는 항목)을 선택합니다. IFT와 IFTX 테이블의 항목이 모두 후보인 경우 IFT의 모든 항목이 IFTX의 항목보다 앞에 있는 것으로 간주합니다.
-
-
initial font URL을 초기 글꼴 URL로, entry의 첫 번째 패치 URL 문자열을 패치 URL 문자열로 하여 패치 파일 불러오기를 호출해 patch file의 불러오기를 시작합니다(이전에 시작하지 않은 경우). entry에 다른 URL 문자열이 있으면 동일한 절차를 사용하여 해당 문자열에 대한 불러오기도 시작합니다. 이들은 알고리즘의 향후 반복에서 사용될 수 있습니다. 또한 클라이언트는 entry에 의해 무효화되지 않을 entry list의 항목에 대해서도 동일한 절차를 사용하여 선택적으로 불러오기를 시작할 수 있습니다. 이 알고리즘을 한 번 실행하는 동안 클라이언트가 불러와 적용할 수 있는 패치의 총 개수는 다음과 같이 제한됩니다.
이 알고리즘을 한 번 호출하는 동안 불러와 적용할 수 있는 패치 수에 대한 제한입니다. 어느 한쪽의 개수를 초과하면 오류이므로 오류 처리하기를 호출합니다.
-
patch file의 불러오기가 완료되면 § 6 글꼴 패치 형식에서 entry의 패치 형식과 일치하는 적절한 적용 알고리즘을 사용하여 entry의 패치 URL 문자열과 호환성 ID를 전달하고 patch file을 extended font subset에 적용합니다. patch file을 불러오는 중 오류가 발생했다면 오류 처리하기에 따라 처리합니다.
-
2단계로 돌아갑니다.
참고: 9단계에서 클라이언트는 현재 선택한 항목에 의해 무효화되지 않는 패치를 병렬로 불러오기 시작하도록 선택할 수 있습니다. 이러한 패치는 무효화되지 않으므로 이후 반복에서 거의 항상 필요하며, 병렬로 불러오면 네트워크 왕복을 없애 성능을 크게 개선할 수 있습니다. 이 방식으로 불러오기를 시작할 때는 요청을 시작하는 순서가 8단계에 지정된 순서를 따라야 합니다.
참고: 교집합이 있는 항목 중 남아 있는 항목이 모두 무효화하지 않는 항목이라면 5단계의 교집합 검사를 이후 반복에서 다시 수행할 필요가 없습니다(무효화하지 않는 패치를 적용해도 해당 패치 자신의 항목이 제거되는 것 외에는 사용 가능한 패치 목록이 변경되지 않기 때문입니다). 또한 최적화를 위해 클라이언트는 교집합이 있는 나머지 비무효화 항목들의 패치를 하나의 일괄 작업으로 적용할 수 있습니다. 글리프 키 기반 패치의 특성상 여러 패치를 순차적으로 적용한 최종 결과를 한 번의 처리로 생성하는 것은 비교적 간단합니다. 이 방식을 사용하면 개별 패치마다 새로운 glyf/loca/CFF/CFF2 테이블을 반복적으로 재구성하지 않아도 되므로 전체 계산량을 크게 줄일 수 있습니다.
항목 교집합 확인하기
이 알고리즘의 입력은 다음과 같습니다.
-
mapping entry: 패치 맵 항목입니다.
-
subset definition: 글꼴 하위 집합 정의입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
intersects: subset definition이 mapping entry와 교차하면 true이고, 그렇지 않으면 false입니다.
알고리즘은 다음과 같습니다.
-
subset definition의 각 집합(코드 포인트, 기능 태그, 디자인 공간)에 대해 해당 집합이 mapping entry의 하위 집합 정의에 있는 대응하는 집합과 교차하는지 확인합니다. 집합은 다음 조건에서 교차합니다.
하위 집합 정의의 집합이 비어 있음 하위 집합 정의의 집합이 비어 있지 않음 매핑 항목의 집합이 비어 있음 true true 매핑 항목의 집합이 비어 있지 않음 false 두 집합이 교차하면 true 디자인 공간 집합의 교집합을 확인할 때는 교차하는 세그먼트 쌍이 하나 이상 있으면 교차하는 것으로 간주합니다 (태그가 같고 범위가 교차해야 합니다).
-
1단계에서 확인한 집합 중 하나 이상이 교차하지 않으면 intersects에 대해 false를 반환합니다.
-
mapping entry에 하위 항목이 없으면 intersects에 대해 true를 반환합니다.
-
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 |
패치 파일 불러오기
이 알고리즘의 입력은 다음과 같습니다.
-
patch URL string: 불러올 패치 파일을 식별하는 URL 문자열([UTF-8]로 인코딩됨)입니다. 상대 URL일 수도 있습니다.
-
initial font URL: font subset이 파생된 초기 점진적 글꼴의 위치를 식별하는 URL입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
patch file: patch URL string으로 식별되는 콘텐츠(바이트)입니다.
알고리즘은 다음과 같습니다.
-
URL 표준 § url-parsing을 사용하여 patch URL string을 URL 레코드로 파싱합니다. initial font URL은 기준 URL이고 인코딩은 UTF-8입니다. 결과를 target URL에 저장합니다. URL 파싱에 실패하면 오류를 반환합니다.
-
구현하는 사용자 에이전트의 가져오기 기능을 사용하여 target URL의 콘텐츠를 가져옵니다. 웹 브라우저에서는 [FETCH]를 사용해야 합니다. [FETCH]를 사용할 때 요청은 다음과 같이 구성합니다.
-
method를 GET으로 설정합니다.
-
url을 target URL로 설정합니다.
-
client를 initial font URL을 가져오는 데 사용한 요청 객체의 클라이언트로 설정합니다.
-
initiator type을 "font"로 설정합니다.
-
destination을 "font"로 설정합니다.
-
referrer를 initial font URL로 설정합니다.
-
mode를 "cors"로 설정합니다.
Fetch를 사용하여 요청을 가져옵니다. 이때 processResponseConsumeBody는 이 알고리즘의 3단계입니다.
[FETCH]를 사용하지 않는 구현에서는 사용 가능한 가져오기 기능을 사용하여 target URL에 대한 요청을 수행합니다. 동등한 개념이 존재하는 경우 위에서 지정한 [FETCH] 기반 설정을 복사합니다. 해당 가져오기 결과를 가지고 3단계로 진행합니다.
-
-
processResponseConsumeBody에는 응답과 null, 실패 또는 바이트 시퀀스가 전달됩니다. 바이트 시퀀스를 받으면 해당 바이트를 patch file로 반환합니다. null을 받으면 빈 바이트 배열을 patch file로 반환합니다. 그 외의 경우에는 오류를 반환합니다.
참고: 가져오기 설정은 CSS 글꼴 불러오기에 사용되는 설정(CSS Fonts 4 § 4.8.2 글꼴 가져오기 요구 사항)과 일치하도록 설계되었지만 몇 가지 차이가 있습니다. 첫째, referrer는 초기 글꼴의 URL로 설정됩니다. 둘째, URL 해석에서는 스타일시트 대신 초기 글꼴을 기준으로 사용합니다.
오류 처리하기
글꼴 하위 집합 확장 과정에서 오류가 발생했다면 글꼴 내 일부 데이터가 완전히 불러와지지 않았을 수 있으며, 그 결과 누락된 데이터에 의존하는 콘텐츠를 렌더링하면 잘못된 결과가 나타날 수 있습니다. 클라이언트는 해당 글꼴을 계속 사용하도록 선택할 수 있지만, § 4.6 글꼴이 렌더링할 수 있는 콘텐츠 결정에 따라 완전히 불러온 코드 포인트, 기능 및 디자인 공간을 렌더링할 때만 사용해야 합니다. 다른 모든 콘텐츠의 렌더링에는 일반적인 클라이언트 대체 글꼴 처리 논리에 따라 다른 글꼴을 사용해야 합니다.
패치 파일 불러오기 중 오류가 발생했다면 클라이언트는 글꼴 하위 집합 확장을 계속 시도할 수 있습니다. 점진적 글꼴 하위 집합 확장하기의 8단계에서는 각 무효화 그룹 안에서 불러오기에 실패한 패치를 선택 대상에서 제외합니다. 무효화 그룹이 비어 있지 않고 해당 그룹에서 패치를 선택해야 하지만 실패한 패치만 포함되어 있다면 확장이 실패한 것이므로 더 이상 계속할 수 없습니다.
그 밖의 모든 오류가 발생한 경우 클라이언트는 글꼴 하위 집합을 더 이상 확장하려고 시도해서는 안 됩니다.
4.4. 무효화 패치 선택
점진적 글꼴 하위 집합 확장하기 알고리즘을 실행하는 동안 후보 항목 목록에서 단일 무효화(완전 또는 부분) 패치 항목을 선택해야 하는 경우가 있습니다. 사용되는 선택 기준은 확장을 수행하는 데 필요한 총 왕복 횟수에 직접적인 영향을 미칩니다. 왕복에는 상당한 비용이 발생하므로 성능을 극대화하려면 필요한 총 왕복 횟수를 최소화하는 방식으로 패치를 선택해야 합니다.
다음 선택 기준은 왕복 횟수를 최소화하며, 클라이언트는 점진적 글꼴 하위 집합 확장하기의 8단계에서 단일 부분 또는 완전 무효화 패치를 선택할 때 이 기준을 사용해야 합니다.:
-
하나 이상의 후보 항목에 연결된 패치 파일이 이전에 점진적 글꼴 하위 집합 확장하기의 9단계에서 불러와졌다면, 다음 단계에서는 패치 파일이 이미 불러와졌거나 현재 불러오는 중인 후보 항목만 고려합니다. 그렇지 않으면 모든 후보 항목을 고려합니다.
-
각 후보 항목에 대해 해당 항목의 하위 집합 정의와 참조된 하위 항목의 그래프를 통해 도달할 수 있는 모든 하위 항목의 하위 집합 정의를 합집합으로 결합하여 전체 하위 집합 정의를 계산합니다.
-
각 후보 항목에 대해 전체 하위 집합 정의와 대상 하위 집합 정의의 교집합을 계산합니다.
-
2단계에서 계산한 교집합이 다른 어떤 교집합의 진부분집합도 아닌 항목을 찾습니다.
-
동일한 패치 맵에 있고 3단계에서 찾은 항목과 교집합이 같은 추가 항목을 찾습니다. 이 항목들의 집합에서 (3단계에서 선택한 항목 포함) 최종적으로 패치 맵에 가장 먼저 나열된 항목( entries 배열에 가장 먼저 나타나는 항목)을 선택합니다.
참고: 3단계의 기준을 충족하는 항목을 빠르고 효율적으로 찾는 방법은 먼저 코드 포인트 집합의 교집합 크기, 다음으로 기능 태그 집합의 교집합 크기, 마지막으로 디자인 공간 교집합 크기를 기준으로 항목을 내림차순 정렬하는 것입니다. 이렇게 정렬하면 첫 번째 항목은 다른 항목의 진부분집합이 아님이 보장됩니다. 진상위집합이라면 적어도 하나의 항목이 더 있어야 하기 때문입니다. 이 방법에는 클라이언트가 현재 요청하는 데이터를 가장 많이 추가하는 패치를 선택한다는 추가적인 이점도 있습니다.
4.5. 대상 하위 집합 정의
점진적 글꼴 하위 집합 확장하기 알고리즘은 클라이언트가 렌더링하려는 콘텐츠를 기반으로 한 대상 하위 집합 정의를 입력으로 받습니다. 클라이언트는 전체 콘텐츠에 대한 단일 하위 집합 정의를 구성하고 확장 알고리즘을 한 번 실행할 수 있습니다. 또는 콘텐츠를 더 작은 구간으로 나누고 각 구간에 대한 하위 집합 정의를 구성한 다음 각각의 작은 하위 집합 정의에 대해 확장 알고리즘을 실행할 수도 있습니다. 다음 조건을 충족하면 두 방법 모두 궁극적으로 전체 콘텐츠를 동일하게 렌더링하는 글꼴을 생성합니다.
-
하위 집합 정의를 생성하는 각 텍스트 구간은 하나 이상의 완전한 셰이핑 단위로만 구성되어야 합니다.
-
여기서 셰이핑 단위는 클라이언트가 셰이핑 과정에서 하나의 단위로 함께 처리하는 텍스트 구간입니다.
4.6. 글꼴이 렌더링할 수 있는 콘텐츠 결정
초기 글꼴이든 부분적으로 확장된 글꼴이든 점진적 글꼴이 주어지면 클라이언트는 해당 글꼴이 현재 상태에서 어떤 콘텐츠를 렌더링할 수 있는지 알고자 할 수 있습니다. 이는 클라이언트가 텍스트의 어느 부분에 대체 글꼴을 사용해야 하는지 판단할 때 특히 중요합니다.
대체 글꼴 처리 과정에서 클라이언트는 일반적으로 글꼴의 cmap 테이블을 확인하여 지원되는 코드 포인트를 결정합니다. 그러나 IFT 글꼴에서는 § 6.3 글리프 키 기반 패치의 작동 방식 때문에 cmap 테이블에 아직 해당 글리프 데이터가 불러와지지 않은 코드 포인트의 매핑이 포함될 수 있습니다. 따라서 클라이언트는 코드 포인트의 존재 여부를 판단할 때 cmap 테이블에만 의존해서는 안 됩니다. 대신 다음 절차를 사용하여 점진적 글꼴이 콘텐츠의 어느 부분을 렌더링할 수 있는지 확인할 수 있습니다.
-
콘텐츠를 텍스트 셰이핑 과정에서 처리할 셰이핑 단위로 나눕니다(§ 4.5 대상 하위 집합 정의 참조).
-
각 셰이핑 단위에 대해 두 가지 검사를 수행합니다.
-
첫째, 셰이핑 단위의 코드 포인트 중 하나라도 해당하는 cmap 항목이 없거나 해당 항목이 글리프 0에 매핑된다면 점진적 글꼴은 해당 셰이핑 단위의 렌더링을 완전히 지원하지 않습니다.
-
둘째, 해당 글꼴 하위 집합 정의를 계산하고 점진적 글꼴 하위 집합 확장하기 알고리즘을 실행하되 6단계에서 중단합니다. 항목 목록이 비어 있지 않으면 점진적 글꼴은 해당 셰이핑 단위의 렌더링을 완전히 지원하지 않습니다.
-
-
두 검사를 모두 통과한 셰이핑 단위는 해당 글꼴로 전체를 렌더링할 수 있습니다.
클라이언트는 셰이핑 단위보다 더 세밀한 수준에서 글꼴이 렌더링할 수 있는 내용을 알고자 할 수도 있습니다. 다음 의사 코드는 위 검사를 통과하지 못한 셰이핑 단위를 점진적 글꼴로 렌더링할 수 있는 구간으로 나누는 한 가지 방법을 보여줍니다.
# 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에 "Extend an Incremental Font Subset" 알고리즘을 실행하고 6단계에서 중단했을 때 # 항목 목록이 비어 있습니다.
반환된 구간 중 어느 것에도 포함되지 않는 셰이핑 단위의 텍스트는 점진적 글꼴에서 지원되지 않으므로 대체 글꼴로 렌더링해야 합니다. 각 구간은 독립적으로 셰이핑해야 합니다(즉, 각 구간이 새로운 셰이핑 단위가 됩니다). 이 방법은 셰이핑 단위를 나누기 때문에 여러 코드 포인트의 치환과 같은 원본 글꼴의 일부 기능을 사용할 수 없을 수 있습니다. 클라이언트가 점진적 글꼴 하위 집합 확장하기 알고리즘을 § 4.5 대상 하위 집합 정의에 따라 구성된 하위 집합 정의로 올바르게 수행하고 있다면 누락된 데이터가 불러와지므로 이 상황은 관련 패치를 불러오는 동안 일시적으로만 발생합니다. 누락된 패치가 도착하여 적용되면 치환으로 인해 영향을 받는 코드 포인트의 렌더링이 변경될 수 있습니다.
참고: 위의 "supported_spans(...)" 검사는 점진적 글꼴 확장을 수행하는 데 사용하기 위한 것이 아닙니다. 점진적 글꼴 하위 집합 확장하기를 실행할 때 대상 하위 집합 정의를 구성하는 지침은 § 4.5 대상 하위 집합 정의에 나와 있습니다.
4.7. 글꼴 완전히 확장하기
이 절에서는 점진적 글꼴을 완전히 확장된 비점진적 글꼴로 변환하는 데 사용할 수 있는 알고리즘을 정의합니다. 이 과정은 점진적 글꼴에서 제공하는 사용 가능한 모든 데이터를 불러와 더 이상 적용할 패치가 없는 단일 정적 글꼴 파일을 생성합니다.
글꼴 하위 집합 완전히 확장하기
이 알고리즘의 입력은 다음과 같습니다.
이 알고리즘의 출력은 다음과 같습니다.
-
expanded font: 점진적 글꼴이 아닌 [open-type] 글꼴입니다.
알고리즘은 다음과 같습니다.
-
font subset을 사용하여 점진적 글꼴 하위 집합 확장하기를 호출합니다. 입력 대상 하위 집합 정의는 항목 교집합 확인하기 단계에서 모든 항목과 교차하는 것으로 간주되는 특수한 정의입니다. 결과 글꼴 하위 집합을 expanded font로 반환합니다.
4.8. 확장된 점진적 글꼴 캐싱
확장된 점진적 글꼴에는 이 절의 절차에 따라 향후 확장 작업을 수행하는 데 필요한 모든 상태가 포함되어 있습니다. 따라서 클라이언트가 나중에 사용하기 위해 점진적 글꼴을 저장하거나 캐싱해야 하는 경우, 확장 알고리즘을 가장 최근에 적용하여 생성한 글꼴 바이너리만 저장하면 충분합니다. 초기 글꼴이나 이전 확장으로 생성된 버전을 보관할 필요는 없습니다.
5. 글꼴 형식 확장
점진적 글꼴은 기존 OpenType 형식을 따르지만, 4바이트 태그 'IFT '와 'IFTX'로 식별되는 두 개의 새로운 테이블을 포함합니다. 이 두 테이블은 모두 패치 맵입니다. 모든 점진적 글꼴에는 최소한 'IFT ' 테이블이 포함됩니다. 'IFTX' 테이블은 선택 사항입니다. 두 테이블이 모두 존재하면 글꼴 전체의 매핑은 두 테이블 매핑의 합집합이 됩니다. 이 두 새 테이블은 이 명세에서만 사용되며 Open-Type 명세에는 추가되지 않습니다.
참고: 매핑을 서로 다른 두 테이블로 나눌 수 있도록 하면 점진적 글꼴에서 여러 패치 유형을 더 쉽게 사용할 수 있습니다. 예를 들어 한 유형의 모든 패치를 'IFT ' 테이블에 지정하고 다른 유형의 모든 패치를 'IFTX' 테이블에 지정할 수 있습니다. 이러한 패치는 매핑 테이블 중 하나만 갱신하여 충돌하는 갱신을 방지할 수 있습니다.
5.1. 점진적 글꼴 전송과 글꼴 압축 형식
웹에서 글꼴을 사용할 때 [WOFF] 또는 [WOFF2]와 같은 압축 형식으로 글꼴을 압축하는 것이 일반적입니다. 다음 조건을 충족한다면 이러한 형식을 사용하여 점진적 글꼴 전송 인코딩의 초기 글꼴 파일을 압축할 수 있습니다.
-
압축 형식으로 글꼴을 인코딩한 다음 디코딩하는 과정에서 각 테이블의 바이트가 변경되지 않아야 합니다.
-
점진적 글꼴 전송 확장 알고리즘(§ 4 글꼴 하위 집합 확장)은 압축되지 않은 글꼴 파일에서 직접 작동하므로, 확장을 시도하기 전에 압축된 글꼴을 디코딩해야 합니다.
[WOFF2]에는 특별한 주의가 필요합니다. 점진적 글꼴을 전송하기 위해 WOFF2로 인코딩하는 경우 다음 사항을 고려해야 합니다.
-
WOFF2 인코딩에 변환된 glyf 및 loca 테이블(WOFF 2.0 § 5.1 변환된 glyf 테이블 형식)이 포함된다면 점진적 글꼴에는 glyf 또는 loca 테이블을 수정하는 § 6.2 테이블 키 기반 패치를 포함하지 않아야 합니다. WOFF2 형식은 변환된 glyf 및 loca 테이블을 디코딩한 결과의 정확한 바이트를 보장하지 않습니다. § 6.3 글리프 키 기반 패치는 변환된 glyf 및 loca 테이블과 함께 사용할 수 있습니다.
-
'IFT ' 및 'IFTX' 테이블은 WOFF 2.0 § 5 압축 데이터 형식에 정의된 표준 절차에 따라 WOFF2 인코더에서 처리하고 Brotli로 인코딩할 수 있습니다.
참고: glyf/loca 변환을 비활성화하더라도 WOFF2 압축은 WOFF보다 우수하므로 일반적으로 IFT 글꼴을 WOFF2로 압축하는 것이 권장됩니다. 인코딩이 테이블 키 기반 패치를 사용하여 해당 테이블을 갱신하는 경우에는 glyf/loca 변환을 비활성화하는 것이 권장됩니다.
5.2. CFF 및 CFF2 점진적 글꼴
CFF 또는 CFF2 테이블에 저장된 글리프 윤곽선을 포함하는 점진적 글꼴에는 다음과 같은 추가 제한이 적용됩니다.
-
점진적 글꼴의 CFF 및 CFF2 테이블에서는 CharStrings INDEX 데이터 구조가 테이블의 마지막 요소여야 합니다 (그 뒤에는 4바이트 워드 경계까지 0 패딩만 올 수 있습니다).
-
점진적 글꼴의 CFF 및 CFF2 테이블에는 CharStrings INDEX 데이터 구조와 겹치는 다른 데이터 요소가 있어서는 안 됩니다.
-
'IFT ' 패치 맵 테이블에는 CFF 및/또는 CFF2 테이블의 CharStrings INDEX 데이터 시작 위치에 대한 오프셋 (cffCharStringsOffset 또는 cff2CharStringsOffset)이 포함되어야 합니다.
이 세 가지 요구 사항을 통해 CFF 및 CFF2 테이블에 글리프 키 기반 패치를 적용하는 구현을 크게 단순화할 수 있습니다. CFF/CFF2 테이블에 인코딩된 다른 데이터 요소의 오프셋을 변경하지 않고도 글리프 데이터를 삽입할 수 있기 때문입니다. 저장된 CFF/CFF2 오프셋을 사용하면 클라이언트가 CFF/CFF2 테이블의 다른 부분을 파싱하지 않고도 CharStrings INDEX를 찾을 수 있습니다.
참고: 경우에 따라 CFF 또는 CFF2 테이블이 테이블 키 기반 패치에 의해 추가되거나 변경될 수 있습니다. 이러한 경우 패치는 새로 추가되거나 변경된 콘텐츠를 반영하도록 charstrings 오프셋도 추가하거나 갱신해야 합니다.
CFF 또는 CFF2의 서브루틴화는 점진적 글꼴 전송과 호환됩니다. 그러나 단순한 서브루틴화는 일반적으로 초기 파일 크기를 늘리는 대신 패치 크기를 줄이는 경향이 있습니다. 또한 WOFF2는 서브루틴화되지 않은 글꼴을 서브루틴화된 동등한 글꼴보다 더 효율적으로 압축하는 경우가 많습니다(대신 압축되지 않은 파일의 크기는 훨씬 커집니다). 따라서 서브루틴화를 피하거나 적절한 수준으로 사용하거나 IFT의 특정 요구 사항에 맞게 조정하는 것이 권장됩니다.
5.3. 패치 맵 테이블
이 절에서는 패치 맵의 인코딩을 설명하고, 이 형식으로 인코딩된 바이트를 해석하여 해당 바이트가 나타내는 항목 목록을 생성하는 알고리즘을 정의합니다. 점진적 글꼴 하위 집합 확장하기 알고리즘은 해석 알고리즘을 호출하고 그 결과로 생성된 항목 목록을 처리합니다. 인코딩된 바이트는 항상 패치 맵의 신뢰할 수 있는 정보원입니다. 하위 집합을 확장하는 동안 패치를 적용하면 패치 맵의 인코딩된 바이트가 변경되며, 그 결과 인코딩된 바이트에서 파생된 항목 목록도 변경됩니다. 확장 알고리즘은 이전 반복에서 이루어진 변경 사항을 반영하기 위해 매 반복이 시작될 때 인코딩된 바이트를 다시 해석합니다.
패치 맵 테이블 인코딩:
| 유형 | 이름 | 설명 |
|---|---|---|
| uint8 | format | 2로 설정하며, 이 테이블의 형식을 식별합니다. 참고: 이전 버전의 명세에는 형식 1이 있었지만 제거되었습니다. 호환성을 유지하고 향후 확장 지점을 제공하기 위해 format 필드는 이전 값인 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개의 매핑 항목이 인코딩된 바이트를 포함하는 바이트 배열입니다. 각 항목의 길이는 가변적이며, 패치 맵 항목 해석하기에 따라 결정됩니다. |
매핑 항목 인코딩:
| 유형 | 이름 | 설명 |
|---|---|---|
| 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.3 희소 비트 집합의 디코딩 절차에 따라 결정됩니다. |
인코더가 파일 시스템에 저장한 후 제공할 패치를 생성하는 경우에는 일반적으로 숫자형 항목 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.1. 패치 맵 해석하기
이 알고리즘은 패치 맵을 패치 맵 항목 목록으로 변환하는 데 사용됩니다.
패치 맵 해석하기
이 알고리즘의 입력은 다음과 같습니다.
-
patch map: 패치 맵 테이블입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
entry list: 패치 맵 항목 목록입니다.
알고리즘은 다음과 같습니다.
-
patch map의 format이 2이고 § 5.3 패치 맵 테이블의 요구 사항("must"로 표시된 요구 사항)에 따라 유효한지 확인합니다. 그렇지 않으면 오류를 반환합니다.
-
entryIdStringData 오프셋이 0이면 last entry id를 0으로 초기화합니다. 그렇지 않으면 빈 바이트 문자열로 초기화합니다. current byte를 0으로, current id string byte를 0으로 설정합니다.
-
entry list와 prior entry list를 빈 목록으로 초기화합니다.
-
패치 맵 항목 해석하기를 entryCount번 호출합니다. 각 호출에서 다음을 수행합니다.
-
prior entry list, patch map의 entries[current byte]부터 patch map 끝까지의 바이트, entryIdStringData가 0이 아닌 경우 patch map의 entryIdStringData[current id string byte]부터 patch map 끝까지의 바이트, last entry id, defaultPatchFormat 및 urlTemplate을 전달합니다.
-
last entry id를 반환된 항목 ID로 설정합니다.
-
반환된 소비 바이트 수를 current byte에 더합니다.
-
반환된 소비 ID 문자열 바이트 수를 current id string byte에 더합니다.
-
반환된 항목을 prior entry list에 추가합니다.
-
반환된 ignored 값이 false이면 반환된 항목의 호환성 ID를 compatibilityId로 설정하고 해당 항목을 entry list에 추가합니다.
-
-
entry list를 반환합니다.
패치 맵 항목 해석하기
이 알고리즘의 입력은 다음과 같습니다.
-
prior entry list: 현재 항목보다 앞에 있는 항목의 목록입니다.
-
entry bytes: 인코딩된 매핑 항목을 포함하는 바이트 배열입니다.
-
id string bytes(선택 사항): 항목 ID 문자열을 포함하는 바이트 배열입니다.
-
last entry id: 마지막으로 생성된 항목 ID입니다.
-
default patch format: 형식이 지정되지 않은 경우 사용할 기본 패치 형식입니다.
-
url template: 패치를 찾는 데 사용되는 URL 템플릿입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
entry id: 이 항목에서 마지막으로 생성된 숫자형 또는 문자열 ID입니다.
-
entry: 단일 항목입니다.
-
consumed bytes: 항목을 인코딩하는 데 사용된 바이트 수입니다.
-
consumed id string bytes: 항목 ID 문자열을 인코딩하는 데 사용된 바이트 수입니다.
-
ignored: true이면 이 항목을 무시해야 합니다.
알고리즘은 다음과 같습니다.
-
모든 단계에서 entry bytes로부터 데이터를 불러올 때마다 consumed bytes를 읽은 바이트 수만큼 증가시킵니다.
-
entry id = last entry id, consumed id string bytes = 0으로 설정합니다.
-
entry의 패치 형식을 default patch format으로 설정합니다.
-
모든 집합을 빈 상태로 초기화한 단일 글꼴 하위 집합 정의를 entry에 추가합니다.
-
entry bytes에서 formatFlags를 읽습니다.
-
formatFlags의 비트 0이 설정되어 있으면 기능 태그와 디자인 공간 목록이 존재합니다.
-
entry bytes에서 featureCount와 featureTags로 지정된 기능 태그 목록을 읽고, 불러온 태그를 entry의 첫 번째 글꼴 하위 집합 정의에 추가합니다.
-
entry bytes에서 designSpaceCount와 designSpaceSegments로 지정된 디자인 공간 세그먼트 목록을 읽고, 해당 세그먼트를 entry의 첫 번째 글꼴 하위 집합 정의에 추가합니다. 각 세그먼트는 tag로 식별되는 축에서 start부터 end까지 양 끝을 포함하는 구간을 정의합니다. 세그먼트의 start가 end보다 크면 인코딩이 유효하지 않으므로 오류를 반환합니다.
-
-
formatFlags의 비트 1이 설정되어 있으면 복사 인덱스 목록이 존재합니다.
-
childEntryMatchModeAndCount의 최상위 비트가 설정되어 있으면 entry의 일치 모드를 논리곱으로 설정하고, 그렇지 않으면 논리합으로 설정합니다.
-
entry bytes에서 childEntryMatchModeAndCount와 childEntryIndices로 지정된 하위 항목 인덱스 목록을 읽습니다.
-
하위 항목 인덱스는 이전에 불러온 항목을 참조합니다. 0은 prior entry list의 첫 번째 매핑 항목, 1은 두 번째 항목을 나타내며 이후도 마찬가지입니다. childEntryIndices의 각 값에 대해 prior entry list에서 일치하는 인덱스의 항목을 찾습니다. 해당 항목에 대한 참조를 entry에 추가합니다. childEntryIndices 값이 prior entry list의 길이보다 크거나 같으면 인코딩이 유효하지 않으므로 오류를 반환합니다.
-
-
formatFlags의 비트 2가 설정되어 있으면 ID 차이값 또는 ID 문자열 길이가 존재합니다.
-
id string bytes가 존재하지 않으면 다음을 수행합니다.
-
다음 entryIdDelta 값을 읽습니다.
-
entry id를
entry id + 1 + floor(delta value / 2)로 설정합니다. entry id가 음수이거나 4,294,967,295보다 크면 인코딩이 유효하지 않으므로 오류를 반환합니다. -
url template과 entry id를 입력으로 하여 URL 템플릿 확장하기를 호출하여 entry id를 URL 문자열로 변환합니다. 템플릿 확장에서 오류가 발생하면 오류를 반환합니다.
-
생성된 패치 URL 문자열을 entry에 추가합니다.
-
읽은 차이값의 최하위 비트가 설정되어 있으면 8단계를 반복합니다.
-
-
그렇지 않고 id string bytes가 존재하면 다음을 수행합니다.
-
다음 entryIdStringLength 값을 읽습니다.
-
최하위 23비트를 부호 없는 정수로 해석하고 그 수만큼 id string bytes에서 바이트를 읽습니다. entry id를 그 결과로 설정합니다. consumed id string bytes를 읽은 바이트 수만큼 증가시킵니다.
-
url template과 entry id를 입력으로 하여 URL 템플릿 확장하기를 호출하여 entry id를 URL 문자열로 변환합니다. 템플릿 확장에서 오류가 발생하면 오류를 반환합니다.
-
생성된 패치 URL 문자열을 entry에 추가합니다.
-
읽은 길이 값의 최상위 비트가 설정되어 있으면 8단계를 반복합니다.
-
-
-
formatFlags의 비트 2가 설정되지 않은 경우:
-
id string bytes가 존재하지 않으면 다음을 수행합니다.
-
entry id를 entry id + 1로 설정합니다.
-
url template과 entry id를 입력으로 하여 URL 템플릿 확장하기를 호출하여 entry id를 URL 문자열로 변환합니다. 템플릿 확장에서 오류가 발생하면 오류를 반환합니다.
-
생성된 패치 URL 문자열을 entry에 추가합니다.
-
-
그렇지 않고 id string bytes가 존재하면 다음을 수행합니다.
-
url template과 entry id를 입력으로 하여 URL 템플릿 확장하기를 호출하여 entry id를 URL 문자열로 변환합니다. 템플릿 확장에서 오류가 발생하면 오류를 반환합니다.
-
생성된 패치 URL 문자열을 entry에 추가합니다.
-
-
-
formatFlags의 비트 3이 설정되어 있으면 패치 형식이 존재합니다. entry bytes에서 patchFormat으로 지정된 형식을 읽고 entry의 패치 형식을 읽은 값으로 설정합니다. patchFormat이 § 6.1 형식 요약의 값 중 하나가 아니면 인코딩이 유효하지 않으므로 오류를 반환합니다.
-
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.3 희소 비트 집합에 따라 entry bytes에서 bias를 적용하여 희소 비트 집합 codePoints를 읽습니다. 결과 코드 포인트 집합을 entry의 첫 번째 글꼴 하위 집합 정의에 추가합니다. 희소 비트 집합 디코딩에 실패하면 인코딩이 유효하지 않으므로 오류를 반환합니다.
-
-
formatFlags의 비트 6이 설정되어 있으면 ignored를 true로 설정합니다. 그렇지 않으면 ignored는 false입니다.
-
entry id, entry, consumed bytes, consumed id string bytes 및 ignored를 반환합니다.
5.3.2. 패치 맵에서 항목 제거하기
이 알고리즘은 패치 맵에서 항목을 제거하는 데 사용됩니다. 이 제거 작업은 패치 맵의 바이트를 변경하지만 바이트 수는 변경하지 않습니다.
패치 맵에서 항목 제거하기
이 알고리즘의 입력은 다음과 같습니다.
-
patch map: 패치 맵 테이블입니다. 이 절차에 의해 수정될 수 있습니다.
-
patch URL string: 제거할 항목을 식별하는 패치의 URL 문자열입니다.
이 알고리즘은 패치 맵 해석하기의 수정된 버전입니다. patch map을 입력으로 사용하여 패치 맵 해석하기를 호출하되 다음 사항을 변경합니다.
-
패치 맵 항목 해석하기의 8단계와 9단계에서 첫 번째 차이값/길이 값에 대해서만 생성된 URL 문자열을 patch URL string과 비교합니다. 두 값이 같으면 formatFlags의 비트 6을 1로 설정합니다. 이 시점에서 해석 과정을 중단합니다.
-
패치 맵 해석하기의 반환값은 사용하지 않습니다.
5.3.3. 희소 비트 집합
희소 비트 집합은 서로 다른 부호 없는 정수의 집합을 간결하게 저장하는 데이터 구조입니다. 이 집합은 각 노드가 고정된 수의 자식을 가지며 구간을 동일한 부분으로 재귀적으로 분할하는 트리로 표현됩니다. 높이가 H이고 분기 계수가 B인 트리는 [0부터 BH-1]까지의 정수에 대한 집합 포함 여부를 저장할 수 있습니다(양 끝 포함). 이 트리는 전송을 위해 바이트 배열로 인코딩됩니다.
패치 맵 테이블에서 희소 비트 집합은 유니코드 코드 포인트 집합을 저장하는 데 사용됩니다. 따라서 희소 비트 집합에 저장되는 정수 값은 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 디코딩하기
이 알고리즘의 입력은 다음과 같습니다.
-
treeData: 디코딩할 바이트 배열입니다.
-
bias: 디코딩된 각 집합 구성원에 더할 부호 없는 정수 값입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
S: 부호 없는 정수의 집합입니다.
FIFO(선입선출) 큐 Q를 사용하는 알고리즘은 다음과 같습니다.
-
treeData에서 첫 번째 바이트를 제거합니다. 이것이 헤더 바이트입니다. 희소 비트 집합에 따라 트리 높이 H와 분기 계수 B를 결정합니다.
-
H가 분기 계수 인코딩 표에서 B에 해당하는 행의 "최대 높이"보다 크면 인코딩이 유효하지 않으므로 오류를 반환합니다.
-
H가 0이면 이는 빈 집합이며 treeData의 추가 바이트를 소비하지 않습니다. 빈 집합을 반환합니다.
-
튜플 (0, 1)을 Q에 삽입합니다.
-
S를 빈 집합으로 초기화합니다.
-
treeData는 비트 문자열로 해석합니다. 여기서 treeData[0]의 최하위 비트가 문자열의 첫 번째 비트이고, treeData[0]의 최상위 비트가 여덟 번째 비트이며 이후도 마찬가지입니다.
-
다음 단계에서 S에 추가하려는 값이 유니코드 코드 포인트의 최대값(0x10FFFF)보다 크면 해당 값을 무시하고 S에 추가하지 않습니다.
-
Q가 비어 있으면 S를 반환합니다.
-
Q에서 다음 튜플 t를 꺼냅니다. t의 첫 번째 값은 start이고 두 번째 값은 depth입니다.
-
treeData 비트 문자열에서 다음 B개의 비트를 제거합니다. 처음 제거한 비트는 v1, 두 번째는 v2이며 마지막으로 제거한 비트인 vB까지 이어집니다. 제거하기 전에 treeData에 남은 비트가 B개보다 적으면 treeData의 형식이 잘못된 것이므로 오류를 반환합니다.
-
v1부터 vB까지의 모든 비트가 0이면, 다음 구간의 모든 정수를 [start + bias, start + bias + BH - depth + 1) S에 삽입합니다. 5단계로 이동합니다.
-
v1부터 vB까지에서 1인 각 vi에 대해 다음을 수행합니다. depth가 H와 같으면 정수 start + bias + i - 1을 S에 추가합니다. 그렇지 않으면 튜플 (start + (i - 1) * BH - depth, depth + 1)을 Q에 삽입합니다.
-
8단계로 이동합니다.
참고: 희소 비트 집합을 인코딩할 때 인코더는 가능한 모든 분기 계수를 사용할 수 있지만, 일반적으로 사용되는 대부분의 유니코드 코드 포인트 집합에서 가장 작은 인코딩을 제공하는 것으로 확인되었으므로 분기 계수 4를 사용하는 것이 권장됩니다.
bit string: |-- 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 ]
bit string: |-- header -- | | B=2 H=0 | [ 00 00000 0 ] 이 비트 문자열은 다음 바이트 문자열로 변환됩니다. [ 0b00000000, ]
bit string: |-- header --| l0 |- lvl 1 -| l2 | | B=4 H=3 | n0 | n1 | n2 | n3 | [ 10 11000 0 1100 0000 1000 1100 ] byte string: [ 0b00001101, 0b00000011, 0b00110001 ]
5.3.4. URL 템플릿
URL 템플릿은 각 패치 맵 항목에 연결된 URL 문자열을 압축하는 데 사용됩니다. 각 패치 매핑 테이블은 URL 템플릿을 제공하며, 각 항목의 ID를 입력으로 사용하여 공통 템플릿을 확장함으로써 각 항목의 URL 문자열을 생성합니다. 템플릿 확장의 출력은 [UTF-8]로 인코딩된 문자열입니다.
URL 템플릿은 리터럴 값을 삽입하거나 입력 항목 ID를 기반으로 값을 삽입하는 일련의 1바이트 연산 코드로 인코딩됩니다.
URL 템플릿을 디코딩하고 확장하는 알고리즘은 다음과 같습니다.
URL 템플릿 확장하기
이 알고리즘의 입력은 다음과 같습니다.
-
url template bytes: URL 템플릿을 포함하는 바이트 배열입니다.
-
entry ID: 항목의 ID입니다. 부호 없는 정수 또는 바이트 배열일 수 있습니다.
이 알고리즘의 출력은 다음과 같습니다.
-
URL string: URL 문자열을 나타내는 바이트 배열입니다. [UTF-8]로 인코딩됩니다.
알고리즘은 다음과 같습니다.
-
URL string을 빈 바이트 배열로 초기화합니다. url template bytes는 나머지 단계에서 큐로 사용됩니다. 읽기 작업은 큐의 앞쪽(인덱스 0의 바이트부터 시작)에서 바이트를 제거합니다.
-
url template bytes의 다음 바이트를 읽어 op code에 저장합니다. 남은 바이트가 없으면 확장이 완료된 것이므로 URL string을 반환합니다.
-
op code의 최상위 비트가 설정되지 않았으면 다음을 수행합니다.
-
op code의 최하위 7비트를 부호 없는 정수인 number of literals로 해석합니다.
-
number of literals가 0이면 오류를 반환합니다.
-
url template bytes에서 다음 number of literals개의 바이트를 읽어 literal bytes에 저장합니다. url template bytes에 충분한 바이트가 남아 있지 않으면 오류를 반환합니다.
-
UTF-8, ISO 10646의 변환 형식 § section-4에 따라 literal bytes가 유효한 UTF-8 인코딩 문자열인지 확인합니다. 유효하지 않으면 오류를 반환합니다.
-
literal bytes를 URL string의 끝에 추가합니다.
-
2단계로 이동합니다.
-
-
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보다 작으면 1바이트만 인코딩됩니다.) 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보다 작으면 1바이트만 인코딩됩니다.) 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. 형식 요약
이 명세에서는 다음 패치 형식을 정의합니다.
-
§ 6.2 테이블 키 기반: 글꼴 하위 집합의 테이블을 기준으로 사용하는 Brotli 인코딩 바이너리 차이 데이터의 모음입니다.
-
§ 6.3 글리프 키 기반: 각각 글리프 ID 및 테이블과 연결된 불투명 바이너리 데이터 블록의 모음입니다.
각 알고리즘에 대한 자세한 설명은 다음 절에서 확인할 수 있습니다.
다음 형식 번호는 § 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. 테이블 키 기반 패치 적용하기
이 패치 적용 알고리즘은 테이블 키 기반 패치를 적용하여 글꼴 하위 집합을 추가 코드 포인트, 기능 및/또는 디자인 변형 공간을 지원하도록 확장하는 데 사용됩니다.
테이블 키 기반 패치 적용하기
이 알고리즘의 입력은 다음과 같습니다.
-
base font subset: 확장할 글꼴 하위 집합입니다.
-
patch: base font subset에 적용할 테이블 키 기반 패치입니다.
-
compatibility id: 이 패치를 나열한 base font subset의 'IFT ' 또는 'IFTX' 테이블에 있는 ID 번호입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
extended font subset: patch에 의해 확장된 글꼴 하위 집합입니다.
알고리즘은 다음과 같습니다.
-
extended font subset을 테이블이 없는 빈 글꼴로 초기화합니다.
-
patch가 § 6.2 테이블 키 기반의 요구 사항("must"로 표시된 요구 사항)에 따라 유효하고 모든 TablePatch가 patch 안에 포함되어 있는지 확인합니다. 그렇지 않으면 오류를 반환합니다.
-
patch의 compatibilityId 필드가 compatibility id와 같은지 확인합니다. 일치하지 않거나 base font subset에 'IFT ' 또는 'IFTX' 테이블이 하나도 없으면 패치 적용이 실패한 것이므로 오류를 반환합니다.
-
다음 단계에서 extended font subset에 테이블을 추가한다는 것은 글꼴에 테이블 데이터를 추가하고 OpenType 명세의 요구 사항에 따라 테이블 디렉터리에 새 항목을 삽입하는 것을 의미합니다. 이 항목에는 테이블 데이터의 체크섬이 포함됩니다. 기존 테이블을 수정하지 않고 복사하는 경우 클라이언트는 원본 글꼴의 항목에 있는 체크섬을 재사용할 수 있습니다. 그렇지 않으면 새 체크섬을 계산해야 합니다.
-
patches의 인덱스 i에 해당하는 각 항목에 대해 다음을 수행합니다.
-
인덱스 i에 연결된 TablePatch를 찾습니다. 객체는 오프셋 patches[i]에서 시작하고(포함), 오프셋 patches[i+1]에서 끝납니다(제외). 두 오프셋 모두 patch의 시작을 기준으로 합니다.
-
patches에서 이전에 적용한 항목의 tag가 현재 항목과 같으면 현재 항목을 무시하고 다음 항목으로 진행합니다. 항목은 patches 배열에 나열된 순서대로 처리됩니다.
-
flags의 비트 1이 설정되어 있으면 tag로 식별되는 테이블을 extended font subset에 복사하거나 추가하지 않습니다. 다음 항목으로 진행합니다.
-
flags의 비트 0(최하위 비트)이 설정되어 있으면 brotliStream을 Brotli 압축 데이터 형식 § 10 디코딩 알고리즘에 따라 디코딩합니다. 공유 사전은 사용하지 않습니다. 디코딩된 데이터가 maxUncompressedLength보다 크면 오류를 반환합니다. brotliStream에 디코딩 과정에서 사용되지 않은 데이터가 있으면 오류를 반환합니다. 테이블을 extended font subset에 추가합니다. 이 테이블은 tag로 식별되며, 내용은 디코딩된 brotliStream으로 설정합니다. 다음 항목으로 진행합니다.
-
그렇지 않으면 brotliStream을 Brotli 압축 데이터 형식 § 10 디코딩 알고리즘에 따라 디코딩합니다. 이때 base font subset에서 tag로 식별되는 테이블을 공유 LZ77 사전으로 사용합니다. 해당 테이블이 없으면 오류를 반환합니다. 디코딩된 데이터가 maxUncompressedLength보다 크면 오류를 반환합니다. brotliStream에 디코딩 과정에서 사용되지 않은 데이터가 있으면 오류를 반환합니다. 테이블을 extended font subset에 추가합니다. 이 테이블은 tag로 식별되며, 내용은 디코딩된 brotliStream으로 설정합니다.
-
-
base font subset의 각 테이블 중 5단계에서 처리한 어떤 항목에서도 찾을 수 없는 태그를 가진 테이블은 복사하여 extended font subset에 추가합니다.
6.3. 글리프 키 기반
글리프 키 기반 패치는 각각 글리프 인덱스 및 글꼴 테이블과 연결된 데이터 청크 모음을 포함합니다. 인코딩된 데이터는 참조된 테이블에서 해당 글리프 인덱스의 기존 데이터를 대체합니다. 글리프 키 기반 패치는 glyf/loca, gvar, CFF 및 CFF2 테이블의 데이터를 인코딩할 수 있습니다.
글리프 키 기반 패치 인코딩:
| 유형 | 이름 | 설명 |
|---|---|---|
| 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. 글리프 키 기반 패치 적용하기
이 패치 적용 알고리즘은 글리프 키 기반 패치를 적용하여 글꼴 하위 집합을 추가 코드 포인트, 기능 및/또는 디자인 변형 공간을 지원하도록 확장하는 데 사용됩니다.
글리프 키 기반 패치 적용하기
이 알고리즘의 입력은 다음과 같습니다.
-
base font subset: 확장할 글꼴 하위 집합입니다.
-
patch: base font subset에 적용할 글리프 키 기반 패치입니다.
-
patch URL string: 패치 데이터가 위치한 URL 문자열입니다.
-
compatibility id: 이 패치를 나열한 base font subset의 'IFT ' 또는 'IFTX' 테이블에 있는 호환성 ID입니다.
이 알고리즘의 출력은 다음과 같습니다.
-
extended font subset: patch에 의해 확장된 글꼴 하위 집합입니다.
알고리즘은 다음과 같습니다.
-
patch가 § 6.3 글리프 키 기반의 요구 사항("must"로 표시된 요구 사항)에 따라 유효한지 확인합니다. 그렇지 않으면 오류를 반환합니다.
-
patch의 compatibilityId 필드가 compatibility id와 같은지 확인합니다. 일치하지 않거나 base font subset에 'IFT ' 또는 'IFTX' 테이블이 하나도 없으면 패치 적용이 실패한 것이므로 오류를 반환합니다.
-
brotliStream의 Brotli 인코딩 데이터를 Brotli 압축 데이터 형식 § 10 디코딩 알고리즘에 따라 디코딩합니다. 디코딩된 데이터는 GlyphPatches 테이블입니다. 디코딩된 데이터가 maxUncompressedLength보다 크면 오류를 반환합니다.
-
글꼴 테이블 중 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, CFF2 및 gvar는 글리프별 데이터에 대한 가변 크기 오프셋을 사용합니다. 새 테이블을 합성할 때 필요한 경우 오프셋 크기를 늘릴 수 있습니다. glyf/loca의 오프셋 크기는 head 테이블에 지정되어 있으므로 변경할 수 없습니다. 합성 과정에서 오프셋 크기를 늘릴 수 있는 만큼 늘린 후에도 최대 가능한 오프셋 값을 초과하는 오프셋이 생성되면 패치 적용이 실패한 것입니다. 오류를 반환합니다.
-
base font subset에 일치하는 테이블이 없으면 오류를 반환합니다.
-
합성된 테이블을 extended font subset에 삽입합니다.
-
-
compatibility id와 동일한 compatibilityId를 가진 § 5.3 패치 맵 테이블을 찾습니다. 패치 맵 테이블과 patch URL string을 입력으로 하여 패치 맵에서 항목 제거하기를 호출합니다. 수정된 패치 맵 테이블을 extended font subset에 복사합니다.
-
base font subset의 각 테이블 중 4단계 또는 5단계에서 처리한 어떤 항목에서도 찾을 수 없는 태그를 가진 테이블은 복사하여 extended font subset에 추가합니다.
-
이전 단계에서 글꼴 테이블의 내용이 수정되었다면, 수정된 각 테이블에 대해 글꼴 테이블 디렉터리의 체크섬을 테이블의 새 내용과 일치하도록 갱신합니다.
7. 인코딩
인코더는 점진적 글꼴과 관련 패치 집합을 생성하는 도구입니다. "인코딩"은 특정 경우의 결과에 영향을 미치기 위해 인코더가 요구하거나 허용하는 매개변수를 포함하여 인코더를 사용하는 과정을 의미합니다. 적합한 인코더가 생성한 점진적 글꼴과 관련 패치는 다음 조건을 충족합니다.
-
§ 5 글꼴 형식 확장 및 § 6 글꼴 패치 형식의 모든 요구 사항을 충족해야 합니다.
-
일관성이 있어야 합니다. 즉, 가능한 모든 글꼴 하위 집합 정의에 대해 해당 하위 집합 정의와 점진적 글꼴을 사용하여 점진적 글꼴 하위 집합 확장하기를 호출한 결과는 점진적 글꼴 하위 집합 확장하기의 8단계에서 선택한 특정 패치 선택 순서와 관계없이 항상 동일해야 합니다.
-
패치 무효화 기준을 준수해야 합니다. IFT 인코딩에 포함된 모든 패치는 호환되는 글꼴 하위 집합에 적용될 때 패치 맵의 호환성 ID에 대해서만 변경을 수행해야 하며, 그 변경은 연결된 패치 맵 항목이 선언한 무효화 모드에 대한 § 4.1 패치 무효화 기준을 준수해야 합니다.
-
인코더를 사용하여 기존 글꼴을 점진적 글꼴로 변환할 때, 연결된 완전히 확장된 글꼴은 기존 글꼴과 동등해야 합니다. 동등한 완전히 확장된 글꼴은 기존 글꼴과 동일한 모든 테이블을 포함해야 하며(점진적 IFT/IFTX 테이블은 제외), 각 테이블은 기존 글꼴의 해당 테이블과 기능적으로 동등해야 합니다. 참고: 완전히 확장된 글꼴이 항상 기존 글꼴과 바이너리 수준에서 정확히 일치하는 것은 아닙니다.
-
확장 과정 전반에 걸쳐 완전히 확장된 글꼴의 기능을 유지해야 합니다. 즉, 점진적 글꼴에서 파생된 완전히 확장된 글꼴과 임의의 콘텐츠가 주어졌을 때, 점진적 글꼴 및 해당 콘텐츠를 포함하는 최소 하위 집합 정의를 사용하여 점진적 글꼴 하위 집합 확장하기를 호출하여 생성된 글꼴 하위 집합은 해당 콘텐츠에 대해 완전히 확장된 글꼴과 동일하게 렌더링되어야 합니다.
인코더를 사용하여 기존 글꼴 파일을 점진적 글꼴로 변환하고 클라이언트가 이 문서의 다른 절에 따라 구현된 경우, IFT 명세의 의도는 클라이언트에서 글꼴의 모양과 동작이 전체 글꼴 파일을 클라이언트에 전송했을 때와 동일하도록 하는 것입니다. IFT 명세의 주요 목표는 IFT 형식과 프로토콜이 WOFF2에 필적하는 글꼴 전송용 중립적인 매개체로 기능하도록 하는 것입니다. 인코더가 위의 모든 요구 사항(1부터 5까지)을 충족하는 원본 글꼴의 인코딩을 생성한다면, 해당 인코딩은 원본 글꼴의 모든 기능을 유지합니다. 위의 요구 사항 4는 원본 글꼴의 모든 기능에 접근할 수 있도록 보장합니다. 이는 요구 사항 5와 함께 작동하며, 요구 사항 5는 IFT 글꼴의 부분 버전이 해당 부분 글꼴을 생성하는 데 사용된 하위 집합 정의에 포함되는 콘텐츠에 대해 전체 버전(여기서는 원본 글꼴)과 동등한 기능을 갖도록 요구합니다.
이는 글꼴 제작사나 기타 권리자가 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 글리프 키 기반 패치 유형을 다음과 같이 혼합하는 것이 바람직할 수 있습니다.
-
모든 테이블 키 기반 패치 항목을 하나의 매핑 테이블에 보관하고 모든 글리프 키 기반 항목을 다른 매핑 테이블에 보관합니다.
-
테이블 키 기반 패치를 사용하여 글리프 키 기반 패치가 수정하는 테이블을 제외한 모든 테이블을 갱신합니다(윤곽선, 변형 델타 및 글리프 키 기반 패치 매핑 테이블). 이러한 패치는 패치 수를 적절하게 유지하기 위해 소수의 큰 세그먼트를 사용해야 합니다.
-
글리프 키 기반 패치는 갱신할 특정 글리프 ID를 참조하므로 테이블 키 기반 패치는 원본 글꼴에서 사용된 글리프와 글리프 ID 간의 할당 관계를 변경해서는 안 됩니다. 그렇지 않으면 글리프 키 기반 패치에 나열된 글리프 ID가 잘못될 수 있습니다. 글꼴 하위 집합 생성 도구에서는 흔히 "retain glyph IDs"라는 옵션으로 제공됩니다.
-
마지막으로 글리프 키 기반 패치를 사용하여 나머지 테이블을 갱신합니다. 여기서는 패치 수가 지나치게 증가하지 않으면서 훨씬 작고 세밀한 세그먼트를 사용할 수 있습니다.
많은 글꼴이 두 극단 사이에 위치하므로 혼합 패치 유형 인코딩은 일반적으로 사용되는 접근 방식이 될 것으로 예상됩니다.
무효화 패치를 사용한 왕복 횟수 줄이기
무효화 패치 유형을 사용하는 분할 방식에서 필요한 왕복 횟수를 줄이는 방법 중 하나는 여러 세그먼트를 한 번에 추가하는 패치를 제공하는 것입니다(개별 세그먼트용 패치에 추가하여). 예를 들어 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 캐시 성능이 저하됩니다. 패치 수가 많다는 것은 특정 하위 집합에서 다른 하위 집합으로 이동하는 경로가 더 많다는 뜻이며, 사용자는 접근하는 콘텐츠에 따라 서로 다른 경로를 사용하기 때문입니다. 미리 생성해야 하는 패치의 총 개수를 줄이는 데 사용할 수 있는 몇 가지 기법은 다음과 같습니다.
-
패치 그래프에 최대 깊이를 설정합니다. 이 한계에 도달하면 원본 전체 글꼴의 나머지 모든 부분을 추가하도록 글꼴에 패치를 적용합니다. 이렇게 하면 일정 수의 세그먼트가 추가된 후 나머지 글꼴 전체가 불러와집니다. 그래프의 깊이를 제한하면 더 깊은 수준에서 발생하는 패치의 조합적 폭증을 줄일 수 있습니다.
-
또는 더 깊은 수준에서 인코더가 여러 세그먼트를 하나의 패치로 결합하기 시작하여 각 수준의 분기 수를 줄일 수 있습니다.
분할 방식 선택
인코더가 내려야 하는 가장 중요하고 복잡한 결정 중 하나는 인코딩된 글꼴의 데이터를 어떻게 분할할지 결정하는 것입니다. 위의 논의에서는 세그먼트 수에 초점을 맞추었지만 점진적 글꼴의 성능은 세그먼트 내 데이터의 그룹화 방식에 훨씬 더 크게 좌우됩니다. 효율성을 극대화하려면 인코더는 함께 자주 사용되는 데이터(예: 코드 포인트)를 동일한 세그먼트로 묶어야 합니다. 이렇게 하면 글꼴을 확장할 때 클라이언트가 불필요한 데이터를 불러오는 양이 줄어듭니다. 인코더는 세그먼트의 크기도 결정해야 합니다. 작은 세그먼트는 패치 수를 늘리고 더 많은 네트워크 요청을 필요로 하므로 오버헤드가 증가하지만, 일반적으로 큰 세그먼트보다 각 세그먼트에 포함되는 불필요한 데이터가 적습니다. 코드 포인트를 분할할 때는 코드 포인트 사용 빈도에 관한 데이터가 분할 방식을 결정하는 데 도움이 될 수 있습니다.
일부 코드 포인트는 자연스럽게 분할할 수 있거나 적어도 어떤 코드 포인트를 함께 묶어야 할지 비교적 명확할 수 있습니다. 예를 들어 라틴 알파벳의 대문자와 소문자는 자연스러운 그룹을 형성합니다. 다른 경우는 더 복잡할 수 있습니다. 예를 들어 중국어, 일본어, 한국어는 일부 코드 포인트를 공유하지만 일본어에서 사용 빈도가 높은 코드 포인트가 중국어에서는 사용 빈도가 낮을 수 있습니다. 경우에 따라 하나의 언어에 맞춰 인코딩을 최적화할 수 있습니다. 또 다른 방법은 절충된 인코딩을 생성하는 것입니다. 예를 들어 분할할 때 인코더는 일본어, 중국어, 한국어에서 모두 자주 사용되는 코드 포인트를 하나의 세그먼트에 넣고, 일본어와 중국어에서만 자주 사용되는 코드 포인트를 다른 세그먼트에 넣는 식으로 처리할 수 있습니다. 그런 다음 한 언어에서만 자주 사용되는 코드 포인트는 일반적인 방식으로 처리할 수 있습니다. 이렇게 하면 세그먼트 크기가 덜 균일해지지만, 어느 한 언어의 고빈도 패치를 불러올 때 저빈도 글리프가 함께 불러와지는 것을 방지할 수 있습니다.
기본 레이아웃 기능 포함
부록 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 글리프 키 기반 패치 집합에 대한 글리프 폐포 요구 사항은 다음과 같습니다.
-
패치 맵 테이블을 통해 글꼴 하위 집합 정의에 대해 불러온 패치에 포함된 글리프 집합은 해당 글꼴 하위 집합 정의의 글리프 폐포에 포함된 글리프 집합의 상위집합이어야 합니다.
하위 집합 생성 도구가 정확하게 작동한다고 가정하면 글리프 폐포 요구 사항은 동등한 동작에 대한 요구 사항에서 비롯됩니다. 어떤 글꼴 하위 집합 정의에 대해 하위 집합 생성 도구는 글리프 *i*를 하위 집합에 포함하지만, § 6.3 글리프 키 기반 패치를 생성하는 인코더는 해당 정의에 대응하는 패치 집합에서 글리프 *i*를 생략한다고 가정해 보겠습니다. 하위 집합 생성 도구의 판단이 옳다면, 해당 글리프는 정의에 포함된 코드 포인트와 기능의 어떤 조합을 렌더링할 때 동등한 동작을 유지하기 위해 존재해야 합니다. 이는 그 조합을 렌더링할 때 점진적 글꼴이 동등하게 동작하지 않음을 의미합니다.
따라서 글리프 키 기반 패치를 사용하는 인코딩을 생성할 때 인코더는 글리프 폐포 요구 사항을 충족하는 방식으로 모든 패치에 글리프를 어떻게 분배할지 결정해야 합니다. 이는 주로 세그먼트에 할당된 코드 포인트를 살펴보고 해당 세그먼트에 대응하는 패치에 어떤 다른 글리프를 포함해야 하는지 결정하는 문제입니다. 예를 들어 코드 포인트에 의해 세그먼트에 포함된 글리프가 변형 글리프로 치환될 수 있는 경우가 있습니다. 일부 글리프는 여러 세그먼트를 불러왔을 때만 필요할 수 있으며, 이 경우 해당 글리프는 그 세그먼트 중 어느 하나에 대응하는 패치에 추가할 수 있습니다. (합자 또는 미리 조합된 악센트 문자에서 이러한 일이 발생할 수 있습니다.) 마지막으로 세그먼트의 초기 분석 후 동일한 글리프가 둘 이상의 세그먼트에 대한 패치를 불러올 때 필요할 수 있습니다. 이러한 상황을 처리하는 다섯 가지 주요 전략은 다음과 같습니다.
-
둘 이상의 세그먼트를 결합하여 하나의 패치에 포함할 수 있습니다. 이렇게 하면 공통 글리프의 중복을 방지할 수 있지만 세그먼트의 크기가 증가합니다.
-
공통 글리프를 별도의 패치에 배치하고 해당 글리프가 필요한 세그먼트를 불러올 때 공통 패치도 함께 불러오도록 매핑 항목을 설정할 수 있습니다. 예를 들어 'c'가 세그먼트 'a'와 'b'에 필요한 공통 세그먼트라면 다음과 같은 매핑 항목을 사용할 수 있습니다.
-
하위 집합 정의 a → 세그먼트 a
-
하위 집합 정의 b → 세그먼트 b
-
하위 집합 정의 a와 하위 집합 정의 b의 합집합 → 세그먼트 c
-
-
유니코드 변형 선택자처럼, 다른 많은 코드 포인트와 함께 사용될 때 글리프 치환을 유발하는 수정자 코드 포인트가 존재하는 경우가 있습니다. 대체 글리프의 수가 많으므로 수정자 코드 포인트와 적절한 기본 코드 포인트가 모두 존재할 때만 불러오는 별도 패치에 대체 글리프를 보관하는 것이 바람직합니다. 이는 childEntryIndices를 통한 다중 항목 일치를 사용하여 구현할 수 있습니다. 설정 방법의 예시는 예시 2: 하위 항목이 있는 글리프 키 기반 패치를 참조하십시오.
-
또는 글리프 데이터를 여러 패치에 중복하여 포함하는 대가로, 해당 세그먼트에 대응하는 둘 이상의 패치에 동일한 글리프를 포함할 수 있습니다.
-
마지막으로 공통 글리프를 초기 글꼴로 옮길 수 있습니다. 이렇게 하면 세그먼트 크기가 증가하거나 글리프 데이터가 중복되는 것을 방지할 수 있지만 초기 글꼴의 크기가 증가합니다. 또한 해당 글리프의 데이터는 필요하지 않은 경우에도 항상 불러와집니다. 이는 여러 세그먼트에서 필요하거나 분할을 복잡하게 만드는 글리프에 유용할 수 있습니다.
초기 글꼴에 데이터 미리 불러오기
경우에 따라 초기 파일에 패치를 적용하는 데 따른 오버헤드를 피하는 것이 바람직할 수 있습니다. 예를 들어 회사 홈페이지에서 불러오는 글꼴이 해당 페이지의 콘텐츠를 이미 렌더링할 수 있도록 하는 것이 바람직할 수 있습니다. 이러한 파일의 주요 이점은 렌더링 지연 시간이 줄어든다는 것입니다. 한 번의 왕복 후에 콘텐츠를 렌더링할 수 있습니다.
다운로드되는 글꼴 파일에 데이터를 포함하는 방법에는 두 가지가 있습니다. 하나는 점진적 글꼴 전체를 인코딩하여 초기 파일에 해당 데이터가 포함되도록 하는 것입니다. 이러한 데이터는 패치가 적용된 모든 글꼴 버전에서 항상 사용할 수 있습니다. 이는 같은 데이터가 여러 서로 다른 세그먼트에서 필요할 수 있는 경우에 유용합니다.
다른 방법은 이미 패치가 적용된 글꼴을 다운로드하는 것입니다. 즉, "기본" 파일에는 데이터가 거의 없거나 전혀 없는 글꼴을 인코딩한 다음 서버 측에서 해당 파일에 패치를 적용하여, 다운로드되는 파일에 이미 해당 패치에 포함된 데이터가 들어 있도록 할 수 있습니다.
글꼴의 미리 불러온 버전이 하나만 필요하다면 두 전략의 결과는 대체로 비슷하지만, 첫 번째 방법이 더 간단하고 경우에 따라 더 구체적입니다. 그러나 미리 불러온 글꼴이 둘 이상 필요한 경우에는 사전 패치 적용 방식이 더 나은 경우가 많습니다. 첫 번째 방법을 사용하면 미리 불러온 파일마다 별도의 인코딩을 생성해야 합니다. 반면 두 번째 방법을 사용하면 미리 불러온 모든 파일이 동일한 전체 패치 그래프를 공유하므로 패치를 저장하는 데 필요한 총 공간이 줄어들고 CDN 캐시 효율성도 향상됩니다. 모든 미리 불러온 파일이 동일한 집합에서 후속 패치를 선택하기 때문입니다.
테이블 순서
초기 글꼴 파일에서는(WOFF2로 인코딩되었는지와 관계없이) 파일 내 실제 테이블 바이트의 순서를 사용자 지정할 수 있습니다. 인코더는 매핑 테이블(IFT 및 IFTX)과 매핑 테이블을 디코딩하는 데 필요한 추가 테이블(cmap)을 파일의 가능한 한 앞쪽에 배치하는 것을 고려해야 합니다. 이렇게 하면 최적화된 클라이언트 구현이 모든 글꼴 데이터를 수신하기 전에 패치 매핑에 접근하여 필요한 패치에 대한 요청을 더 일찍 시작할 수 있습니다.
마찬가지로 테이블 키 기반 패치는 패치가 적용되는 각 테이블에 대해 별도의 Brotli 스트림을 가지며, 형식에서는 이러한 스트림을 패치 파일 내의 어떤 순서로든 배치할 수 있습니다. 따라서 동일한 이유로 인코더는 매핑 테이블의 갱신 데이터와 매핑 테이블을 디코딩하는 데 필요한 추가 테이블을 패치 파일의 가능한 한 앞쪽에 배치하는 것을 고려해야 합니다.
입력 ID 인코딩 선택
이 명세는 URL 템플릿에 패치 ID를 포함하기 위한 두 가지 인코딩을 지원합니다. 첫 번째는 base32hex이며, 일반적으로 파일 시스템에 저장되는 미리 생성된 패치에 적합합니다. Base32hex 인코딩은 0-9와 A-V 문자만 사용하므로, 일반적으로 사용되는 모든 파일 시스템에서 파일 이름으로 안전하게 사용할 수 있으며 대소문자를 구분하지 않아 발생하는 충돌 위험이 없습니다. 이 형식은 패딩 없이 문자열을 삽입하므로 안정적으로 디코딩할 수 없어, 동적으로 생성되는 패치에는 적합하지 않을 수 있습니다. 다른 인코딩은 base64url로, URL이나 대소문자를 구분하는 파일 시스템에 포함하기에 적합한 base64 인코딩의 변형입니다. 이 인코딩을 사용하면 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 명세에서 확인할 수 있습니다.
-
CSS Fonts 4 § 15.1 이 기능은 웹사이트나 다른 당사자에게 어떤 정보를 노출할 수 있으며, 그러한 노출은 어떤 목적으로 필요한가요?. 개인정보 보호에 특히 민감한 환경에서는 사용자 에이전트가 문서의 모든 웹 글꼴을 다운로드할 것을 권장합니다. IFT 글꼴의 경우 § 4.7 글꼴 완전히 확장하기를 사용하면 존재하는 구체적인 콘텐츠에 관한 정보를 제공하지 않고 사용 가능한 IFT 글꼴 전체를 가져올 수 있습니다. 또는 개인정보 보호에 민감한 환경에서 사용자 에이전트는 현재 콘텐츠에 필요하지 않은 추가 패치를 무작위로 선택하여 실제로 필요한 패치를 알아보기 어렵게 만들 수 있습니다.
-
CSS Fonts 4 § 15.8 이 명세는 출처에 어떤 데이터를 노출하나요? 동일하거나 다른 환경에서 다른 기능을 통해 노출되는 데이터와 동일한 데이터도 문서화해 주세요.
콘텐츠 및/또는 사이트 작성자가 IFT 글꼴을 사용하기로 선택하면, 해당 글꼴을 인코딩한 주체와 글꼴을 불러오는 서비스 모두를 어느 정도 신뢰해야 합니다. 앞에서 설명한 것처럼 IFT 글꼴을 확장하는 동안 렌더링되는 콘텐츠에 관한 일부 정보가 전송되기 때문입니다. (두 요소 사이에는 균형 관계가 있습니다. 아래에서 설명하듯이 인코딩에 더 많은 주의를 기울였다면 서비스에 요구되는 신뢰 수준은 낮아집니다.) 따라서 개인정보 보호에 민감한 경우 IFT 글꼴을 직접 호스팅하는 것이 권장됩니다. 이렇게 하면 콘텐츠에 관한 어떠한 정보도 제3자에게 전송되지 않습니다. 또한 이러한 경우에는 다른 출처에서 글꼴을 불러오지 못하도록 콘텐츠 보안 정책을 구성하는 것이 권장됩니다.
8.2. IFT 글꼴 인코딩과 개인정보 보호
IFT 글꼴의 인코딩 방식은 패치 파일 전송을 통해 콘텐츠에 관한 정보를 얼마나 많이 추론할 수 있는지에 큰 영향을 미칩니다. 이 절에서는 IFT 글꼴을 인코딩할 때 내리는 선택이 개인정보 보호에 미치는 영향을 평가하는 방법에 관한 일반적인 지침을 제공합니다.
IFT 글꼴은 각각 활성화 조건이 연결된 패치들의 모음으로 나뉩니다. 패치에 대한 요청이 이루어지면 콘텐츠에 해당 패치의 활성화 조건과 교차하는 요소가 존재한다는 정보가 전달됩니다. 따라서 글꼴의 활성화 조건 구조는 인코딩의 개인정보 보호 특성을 평가할 때 가장 중요한 요소입니다.
글꼴이 지원하는 각 고유 코드 포인트, 기능 및 디자인 공간 구성은 해당 요소의 존재 여부라는 잠재적 신호를 제공합니다. 활성화 조건은 논리합 또는 논리곱일 수 있습니다. 논리합 조건은 활성화되더라도 조건에 포함된 개별 항목 중 적어도 하나가 존재한다는 사실만 전달하므로 불확실성을 만들어 냅니다. 반면 논리곱 패치는 각 개별 항목이 동시에 존재해야 하므로 불확실성을 추가하지 않습니다.
코드 포인트나 기능의 일반적인 출현 빈도는 그 존재가 얼마나 많은 정보를 전달하는지에 영향을 미칩니다. 출현 빈도가 높은 항목은 낮은 빈도의 항목보다 적은 정보를 전달합니다. 출현 빈도가 낮은 코드 포인트가 존재한다는 사실은 가능한 콘텐츠의 범위를 훨씬 더 좁힙니다. 따라서 개략적으로 말하면 출현 빈도가 낮은 항목을 포함하는 조건에는 더 크고 세분화 수준이 낮은 조건을 사용해야 합니다.
이 명세를 개발하는 동안 수행한 시뮬레이션에서는 최소 그룹 크기(논리합 조건의 경우)를 4~7개 항목으로 설정하면 적절한 수준의 모호성을 확보할 수 있는 것으로 나타났습니다. 인코딩에 최소 그룹 크기를 사용하는 것은 성능 측면에서도 바람직합니다. 지나치게 세분화된 패치는 과도한 오버헤드를 발생시켜 성능을 저하시키기 때문입니다. 출현 빈도가 낮은 항목은 자주 필요하지 않으므로 해당 항목을 포함하는 패치에 최소 그룹 크기를 적용하더라도 전체 성능에 미치는 영향은 작습니다. 전체 성능은 주로 출현 빈도가 높은 항목에 의해 결정되는 경향이 있습니다.
인코더는 생성된 인코딩의 각 조건을 평가하고 유효 그룹 크기를 결정해야 합니다. 유효 그룹 크기는 조건의 활성화에 기여하는 개별 항목(코드 포인트, 레이아웃 태그, 디자인 공간)에 대한 논리합 하위 조건 중 가장 작은 크기입니다. 개인정보 보호에 민감한 용도를 대상으로 하는 인코딩에서는 인코더가 모든 조건의 최소 그룹 크기를 적어도 4~7개로 유지해야 합니다. 예를 들어 다음 경우를 살펴보겠습니다.
-
A or B or C or D: 유효 그룹 크기가 4이며 최소 요구 사항을 충족합니다. -
A and B and C AND D: 유효 그룹 크기가 1이며 최소 요구 사항을 충족하지 않습니다. -
(A or B or C or D) AND (E or F): (D or E) 하위 조건으로 인해 유효 그룹 크기가 2입니다. 따라서 최소 요구 사항을 충족하지 않습니다.
인코더는 생성되는 인코딩의 개인정보 보호 수준을 설정하는 제어 기능을 제공해야 합니다. 사용 사례마다 필요한 수준이 다르기 때문입니다. 예를 들어 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 명세에는 과도한 요청 수를 제한하기 위한 몇 가지 완화 조치가 포함되어 있습니다.
-
§ 4 글꼴 하위 집합 확장: 동일한 URL을 여러 번 다시 요청하는 것을 금지하고, 확장 과정에서 보낼 수 있는 총 요청 수에 제한을 둡니다.
-
패치 파일 불러오기: 웹 브라우저 구현에서 [FETCH]를 사용하도록 지정하며, 초기 글꼴 불러오기에 사용된 CORS 설정과 일치시킵니다. 따라서 호스팅 서비스가 적절한 접근 제어 헤더를 통해 명시적으로 허용하지 않는 한 패치 파일에 대한 교차 출처 요청은 금지됩니다.
10. 변경 사항
2025년 11월 18일 W3C 후보 권고안 초안 이후의 변경 사항 (커밋 기록 참조):
- 기본 기능 레지스트리를 갱신하여 halt 및 vhal을 포함했습니다.
- URL 템플릿 확장 알고리즘에 'conform' 마크업을 추가했습니다.
- 명세에서 패치 맵 형식 1을 제거했습니다.
- 패치 맵이 format = 2를 사용하는 이유에 관한 참고 사항을 추가했습니다.
- 오타와 문법 오류를 수정했습니다.
2025년 7월 31일 후보 권고안 스냅샷 이후의 변경 사항 (커밋 기록 참조):
- 테스트 가능한 규범적 알고리즘에 마크업을 추가했습니다.
- 마크업과 스타일을 사용하여 클라이언트 및 인코더의 적합성 명세를 구분했습니다.
- 테스트 가능한 단언에 스타일을 추가했습니다.
- 비규범적 참고 사항과 도입부의 정의에서 의도치 않게 사용된 적합성 표현(should, must)을 제거했습니다.
- 테스트 가능한 모든 (must) 단언에 마크업을 추가했습니다.
- 부록 B(예시)를 비규범적으로 표시했습니다.
2025년 7월 15일 작업 초안 이후의 변경 사항 (커밋 기록 참조):
- 참고 문헌에서 사용하지 않는 항목을 제거했습니다.
- "셰이핑 단위"라는 용어를 정의하고 내보냈습니다.
2025년 2월 20일 작업 초안 이후의 변경 사항(커밋 기록 참조):
- 인코더에 대한 지침을 제공하도록 개인정보 보호 절을 확장했습니다.
- 완전한 절대 URL 및 호스트 이름 기준 상대 URL 확장의 예시를 추가했습니다.
- 'url template bytes'에서 바이트를 읽는 방법을 명확히 했습니다.
- 추가 오류 조건을 도입했습니다. 연산 코드 0(리터럴 0개 삽입)을 무효로 처리합니다. 리터럴 삽입 작업에 필요한 바이트가 충분하지 않으면 실패하도록 하고, 실패하는 예시를 추가했습니다.
- URL 확장 예시에서 바이트 배열에 C 구문을 사용하도록 갱신했습니다. 상대 URL과 쿼리 매개변수가 있는 URL을 포함한 다양한 예시를 추가했습니다.
- TAG 검토에 따라 RFC6570 URI 템플릿을 제거하고 연산 코드로 인코딩된 템플릿으로 대체했습니다.
- fetch 호출과 processResponseConsumeBody 콜백 사용을 추가했습니다.
- fetch 요청 구성에 관한 구체적인 정보를 추가했습니다.
- 검토 의견에 따라 항목 선택에 관한 문구를 더 명확하게 수정했습니다.
- 무효화하지 않는 패치의 선택 및 가져오기 순서를 지정했습니다.
- URL 파싱에 실패할 때 수행할 작업을 지정했습니다.
- 여러 패치가 존재할 때 글리프 키 기반 패치 적용을 최적화하는 방법에 관한 참고 사항을 추가했습니다.
- 형식 2 해석에서 지정되지 않은 항목 차이값/길이의 처리가 누락되어 있었습니다. 해당 경우 URL을 생성하는 추가 단계를 도입했습니다.
- WOFF2 관련 설명을 명확히 했습니다.
- 글꼴 압축 절에 WOFF2를 권장하는 참고 사항을 추가했습니다.
- 현재 공유 Brotli 15 명세에 맞게 갱신했습니다.
- 선택적 charstring 오프셋의 존재 여부를 나타내는 플래그 비트를 추가했습니다.
- CFF 테이블과 charstrings 오프셋을 추가하는 패치에 관한 참고 사항을 추가했습니다.
- CFF 또는 CFF2 테이블이 있는 글꼴에 대해 CharStrings 오프셋을 포함하는 필드를 패치 맵에 추가했습니다.
- URI 템플릿 확장에서 정의되지 않은 변수 이름을 허용하지 않도록 했습니다.
- 지원되지 않는 표현식 수준에서 오류를 발생시키는 명세의 문구를 수정했습니다.
- URL 템플릿을 레벨 1 치환으로만 제한했습니다.
- RFC3986 URI에서 WHATWG URL로 변경했습니다.
- "prefetch list"라는 용어를 정의하고 사용했습니다.
- 무효화 패치 선택에서 미리 불러온 항목의 우선순위를 높여 왕복 횟수를 최소화했습니다.
- 글꼴 확장 알고리즘이 URL 미리 불러오기 목록을 사용하도록 갱신했습니다.
- 형식 2 해석 및 항목 제거 알고리즘이 항목당 여러 URL을 처리하도록 갱신했습니다.
- 형식 2 인코딩을 재구성하여 항목당 여러 URL을 선택적으로 지원하도록 했습니다.
- 글리프 키 기반 패치 적용의 오프셋 크기에 관한 지침을 추가했습니다.
- CFF 및 CFF2 점진적 글꼴에 특화된 요구 사항을 포함하는 절을 추가했습니다.
- 기능 레지스트리 부록을 최신 버전으로 갱신했습니다.
2024년 7월 9일 작업 초안 이후의 변경 사항(커밋 기록 참조):
- 하위 항목을 사용하는 확장 예시를 부록 B에 추가했습니다.
- 형식 2 해석에서 이전 항목을 출력용 필터링 목록과 별도로 유지하도록 했습니다.
- 매핑 항목에서 참조하는 항목을 하위 항목이라고 부르도록 했습니다.
- 참조된 항목의 교차 여부를 기준으로 복사 인덱스 메커니즘을 재구성했습니다.
- 구현 작업을 바탕으로 형식 1 및 형식 2 패치 맵 인코딩을 수정했습니다(예: 설명 명확화, 오류 처리, 누락 사항 수정).
- 점진적 글꼴 캐싱에 관한 절을 추가했습니다.
- 기본 레이아웃 기능에 관한 지침을 추가했습니다.
- 순수 Brotli 패치 형식을 제거하여 남은 패치 형식은 테이블 키 기반과 글리프 키 기반이 되었습니다.
- IFT 글꼴이 렌더링할 수 있는 콘텐츠를 확인하는 절차를 추가했습니다.
- 확장 알고리즘에 명시적인 사전 가져오기를 추가했습니다.
- 확장 알고리즘의 실행 예시가 포함된 부록 B를 추가했습니다.
부록 A: 기본 기능 태그
이 부록은 비규범적입니다. 대부분의 셰이퍼 구현에서 기본적으로 사용되는 것으로 간주되는 레이아웃 기능의 목록을 제공합니다. 이 목록은 다음 자료를 바탕으로 작성되었습니다.
-
[enabling-typography]에서 "기본적으로 활성화"로 나열된 기능
-
HarfBuzz 하위 집합 생성 도구의 기본 집합에 포함된 기능
셰이퍼에서 기본적으로 사용되는 레이아웃 기능
| 태그 | 이름 |
|---|---|
| abvf | 기본 글리프 위쪽 형태 |
| abvm | 기본 글리프 위쪽 마크 위치 지정 |
| abvs | 기본 글리프 위쪽 치환 |
| akhn | 아칸드 |
| blwf | 기본 글리프 아래쪽 형태 |
| blwm | 기본 글리프 아래쪽 마크 위치 지정 |
| blws | 기본 글리프 아래쪽 치환 |
| calt | 문맥별 대체 글리프 |
| ccmp | 글리프 합성 / 분해 |
| cfar | Ro 뒤의 결합 형태 |
| chws | 문맥별 반각 간격 |
| cjct | 결합 형태 |
| clig | 문맥별 합자 |
| cswh | 문맥별 스와시 |
| curs | 필기체 위치 지정 |
| dist | 거리 |
| dnom | 분모 |
| dtls | 점 없는 형태 |
| fin2 | 끝 형태 #2 |
| fin3 | 끝 형태 #3 |
| fina | 끝 형태 |
| flac | 평탄화된 악센트 형태 |
| frac | 분수 |
| half | 반 형태 |
| haln | 할란트 형태 |
| init | 첫 형태 |
| isol | 독립 형태 |
| jalt | 양끝 맞춤용 대체 글리프 |
| kern | 커닝 |
| liga | 표준 합자 |
| ljmo | 초성 자모 형태 |
| locl | 지역화된 형태 |
| ltra | 왼쪽에서 오른쪽 방향의 대체 글리프 |
| ltrm | 왼쪽에서 오른쪽 방향의 미러링 형태 |
| mark | 마크 위치 지정 |
| med2 | 중간 형태 #2 |
| medi | 중간 형태 |
| mkmk | 마크 간 위치 지정 |
| mset | 치환을 통한 마크 위치 지정 |
| nukt | 누크타 형태 |
| numr | 분자 |
| pref | 기본 글리프 앞쪽 형태 |
| pres | 기본 글리프 앞쪽 치환 |
| pstf | 기본 글리프 뒤쪽 형태 |
| psts | 기본 글리프 뒤쪽 치환 |
| rand | 무작위화 |
| rclt | 필수 문맥별 대체 글리프 |
| rkrf | 라카르 형태 |
| rlig | 필수 합자 |
| rphf | 레프 형태 |
| rtla | 오른쪽에서 왼쪽 방향의 대체 글리프 |
| rtlm | 오른쪽에서 왼쪽 방향의 미러링 형태 |
| rvrn | 필수 변형 대체 글리프 |
| ssty | 수학 첨자 스타일 대체 글리프 |
| stch | 글리프 늘이기 분해 |
| tjmo | 종성 자모 형태 |
| valt | 대체 세로 메트릭 |
| vatu | 바투 변형 |
| 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)의 불러오기를 확장 알고리즘에 지정된 것보다 먼저 시작합니다. 이는 해당 패치가 앞서 적용되는 테이블 키 기반 패치에 의해 무효화되지 않으므로 허용됩니다.
입력:
-
위에서 정의한 IFT 및 IFTX 테이블을 포함하는 초기 글꼴입니다.
-
대상 하위 집합 정의: 코드 포인트 = {'f', 'P'}
반복 1:
-
1~6단계 - 초기 글꼴의 모든 항목에 항목 교집합 확인하기 검사를 적용하면 다음 패치 항목들이 교차합니다.
-
//foo.bar/01.tk
-
//foo.bar/02.tk
-
//foo.bar/04.tk
-
//foo.bar/05.tk
-
//foo.bar/01.gk
-
//foo.bar/04.gk
-
-
8단계 - 이 집합에서 하나의 항목을 선택해야 합니다. 완전 무효화 항목이 없으므로 부분 무효화 항목(//foo.bar/*.tk) 하나를 선택해야 합니다. § 4.4 무효화 패치 선택에 따라 후보 항목과 대상 하위 집합 정의의 교집합은 다음과 같습니다.
-
//foo.bar/01.tk - {'f'}
-
//foo.bar/02.tk - {'P'}
-
//foo.bar/04.tk - {'f', 'P'}
-
//foo.bar/05.tk - {'f', 'P'}
//foo.bar/01.tk와 //foo.bar/02.tk의 교집합은 모두 //foo.bar/04.tk 및 //foo.bar/05.tk의 진부분집합이므로 선택 기준을 충족하지 않습니다. 따라서 //foo.bar/04.tk 또는 //foo.bar/05.tk가 남습니다. //foo.bar/04.tk가 패치 맵에 먼저 나열되어 있으므로 이를 선택합니다.
-
-
9단계 - 선택된 패치 //foo.bar/04.tk를 가져옵니다. 또한 최적화를 위해 두 글리프 키 기반 패치 //foo.bar/01.gk 및 //foo.bar/04.gk에 대한 가져오기도 동시에 시작합니다. 테이블 키 기반 패치 //foo.bar/04.tk는 부분 무효화를 수행하므로 두 글리프 키 기반 패치는 //foo.bar/04.tk 적용 후에도 유효하게 유지됩니다. 따라서 클라이언트는 이 두 글리프 키 기반 패치가 향후 반복에서 필요할 것으로 예상하고 이 시점에서 불러오기를 시작할 수 있습니다.
-
10단계 - 가져온 패치 //foo.bar/04.tk를 초기 글꼴에 적용합니다. 이 패치는 glyf 및 loca를 제외한 모든 테이블을 갱신하여 코드 포인트 'a'부터 'Z'까지 지원하도록 합니다. 또한 "IFT " 테이블의 매핑은 다음과 같이 갱신됩니다.
테이블 = "IFT " 호환성 ID = 0x0000_0000_0000_0006 하위 집합 정의 URL 형식 번호 code points: { '0', '1', ..., '9' }//foo.bar/08.tk 2, 테이블 키 기반 - 부분 무효화 다음 변경 사항에 유의하십시오.
-
'a', ... 'z' 및 'A', ..., 'Z'에 대한 데이터가 있는 모든 항목이 제거되었습니다. 나머지 코드 포인트 '0', ..., '9'에 대한 항목 하나만 남습니다.
-
글꼴 바이너리가 변경되었으므로 이전에 나열된 테이블 키 기반 패치는 더 이상 유효하지 않습니다. 따라서 호환성 ID가 변경되었고 나머지 '0', ..., '9' 항목의 URL도 변경되었습니다. 새 URL의 패치인 //foo.bar/08.tk는 갱신된 글꼴과 호환됩니다.
-
반복 2:
-
2~6단계 - 이전 반복에서 갱신된 글꼴의 모든 항목에 항목 교집합 확인하기 검사를 적용하면 다음 패치 항목들이 교차합니다.
-
//foo.bar/01.gk
-
//foo.bar/04.gk
-
-
8단계 - 이 집합에서 하나의 항목을 선택해야 합니다. 무효화하지 않는 패치만 남았으므로 클라이언트는 어느 것이든 자유롭게 선택할 수 있습니다. 여기서는 첫 번째 항목인 //foo.bar/01.gk를 선택합니다.
-
9단계 - //foo.bar/01.gk에 대한 가져오기는 반복 1에서 이미 시작되었습니다.
-
10단계 - 가져온 패치 //foo.bar/01.gk를 현재 글꼴 하위 집합에 적용합니다. 이 패치는 코드 포인트 'a'부터 'm'까지의 글리프 데이터를 glyf 및 loca 테이블에 추가합니다. 또한 "IFTX" 테이블의 매핑을 갱신하여 //foo.bar/01.gk 항목을 제거합니다. 호환성 ID와 다른 항목의 URL은 변경되지 않습니다.
반복 3:
-
2~6단계 - 이전 반복에서 갱신된 글꼴의 모든 항목에 항목 교집합 확인하기 검사를 적용하면 다음 패치 항목이 교차합니다.
-
//foo.bar/04.gk
-
-
8단계 - 항목 하나만 남았으므로 이를 선택합니다.
-
9단계 - //foo.bar/04.gk에 대한 가져오기는 반복 1에서 이미 시작되었습니다.
-
10단계 - 가져온 패치 //foo.bar/04.gk를 현재 글꼴 하위 집합에 적용합니다. 이 패치는 코드 포인트 'N'부터 'Z'까지의 글리프 데이터를 glyf 및 loca 테이블에 추가합니다. 또한 "IFTX" 테이블의 매핑을 갱신하여 //foo.bar/04.gk 항목을 제거합니다. 호환성 ID와 다른 항목의 URL은 변경되지 않습니다.
반복 4:
-
2~6단계 - 더 이상 교차하는 항목이 없으므로 알고리즘을 종료합니다. 글꼴 하위 집합을 반환하며, 이제 대상 하위 집합 정의에 포함된 모든 콘텐츠를 렌더링할 준비가 되었습니다.
예시 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
입력:
-
위에서 정의한 IFT 테이블을 포함하는 초기 글꼴입니다.
-
대상 하위 집합 정의: 코드 포인트 = {'f'}
반복 1:
-
1~6단계 - 초기 글꼴의 모든 항목에 항목 교집합 확인하기 검사를 적용하면 다음 패치 항목이 교차합니다.
-
//foo.bar/01.gk
-
-
8~10단계 - 패치가 //foo.bar/01.gk 하나뿐이므로 이를 선택하고 불러와 적용합니다.
반복 2:
-
2~6단계 - 더 이상 교차하는 항목이 없으므로 알고리즘을 종료합니다. 글꼴 하위 집합을 반환하며, 이제 대상 하위 집합 정의에 포함된 모든 콘텐츠를 렌더링할 준비가 되었습니다.
확장 예시 2
입력:
-
위에서 정의한 IFT 테이블을 포함하는 초기 글꼴입니다.
-
대상 하위 집합 정의: 코드 포인트 = {'f', VS1}
반복 1:
-
1~6단계 - 초기 글꼴의 모든 항목에 항목 교집합 확인하기 검사를 적용하면 다음 패치 항목들이 교차합니다.
-
//foo.bar/01.gk
-
//foo.bar/03.gk
-
-
8단계 - 하나의 항목을 선택해야 하며, 이 경우 클라이언트 구현은 어느 것이든 자유롭게 선택할 수 있습니다. //foo.bar/01.gk를 선택합니다.
-
9단계 - 교차하는 두 항목 모두 무효화하지 않으므로 동시에 불러올 수 있습니다.
-
10단계 - //foo.bar/01.gk를 글꼴에 적용합니다. 매핑 테이블을 갱신하여 //foo.bar/01.gk 항목이 무시되도록 표시합니다.
반복 2:
-
1~6단계 - 현재 글꼴의 모든 항목에 항목 교집합 확인하기 검사를 적용하면 다음 패치 항목이 교차합니다.
-
//foo.bar/03.gk
-
-
8~10단계 - 패치가 //foo.bar/03.gk 하나뿐이므로 이를 선택하여 적용합니다 (이전 반복에서 이미 불러왔습니다).
반복 3:
-
2~6단계 - 더 이상 교차하는 항목이 없으므로 알고리즘을 종료합니다. 글꼴 하위 집합을 반환하며, 이제 대상 하위 집합 정의에 포함된 모든 콘텐츠를 렌더링할 준비가 되었습니다.