1 | /* |
2 | * Copyright © 2007,2008,2009 Red Hat, Inc. |
3 | * Copyright © 2012 Google, Inc. |
4 | * |
5 | * This is part of HarfBuzz, a text shaping library. |
6 | * |
7 | * Permission is hereby granted, without written agreement and without |
8 | * license or royalty fees, to use, copy, modify, and distribute this |
9 | * software and its documentation for any purpose, provided that the |
10 | * above copyright notice and the following two paragraphs appear in |
11 | * all copies of this software. |
12 | * |
13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | * DAMAGE. |
18 | * |
19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | * |
25 | * Red Hat Author(s): Behdad Esfahbod |
26 | * Google Author(s): Behdad Esfahbod |
27 | */ |
28 | |
29 | #ifndef HB_OPEN_FILE_PRIVATE_HH |
30 | #define HB_OPEN_FILE_PRIVATE_HH |
31 | |
32 | #include "hb-open-type-private.hh" |
33 | |
34 | |
35 | namespace OT { |
36 | |
37 | |
38 | /* |
39 | * |
40 | * The OpenType Font File |
41 | * |
42 | */ |
43 | |
44 | |
45 | /* |
46 | * Organization of an OpenType Font |
47 | */ |
48 | |
49 | struct OpenTypeFontFile; |
50 | struct OffsetTable; |
51 | struct TTCHeader; |
52 | |
53 | |
54 | typedef struct TableRecord |
55 | { |
56 | int cmp (Tag t) const |
57 | { return t.cmp (a: tag); } |
58 | |
59 | inline bool sanitize (hb_sanitize_context_t *c) const |
60 | { |
61 | TRACE_SANITIZE (this); |
62 | return_trace (c->check_struct (this)); |
63 | } |
64 | |
65 | Tag tag; /* 4-byte identifier. */ |
66 | CheckSum checkSum; /* CheckSum for this table. */ |
67 | UINT32 offset; /* Offset from beginning of TrueType font |
68 | * file. */ |
69 | UINT32 length; /* Length of this table. */ |
70 | public: |
71 | DEFINE_SIZE_STATIC (16); |
72 | } OpenTypeTable; |
73 | |
74 | typedef struct OffsetTable |
75 | { |
76 | friend struct OpenTypeFontFile; |
77 | |
78 | inline unsigned int get_table_count (void) const |
79 | { return tables.len; } |
80 | inline const TableRecord& get_table (unsigned int i) const |
81 | { |
82 | return tables[i]; |
83 | } |
84 | inline unsigned int get_table_tags (unsigned int start_offset, |
85 | unsigned int *table_count, /* IN/OUT */ |
86 | hb_tag_t *table_tags /* OUT */) const |
87 | { |
88 | if (table_count) |
89 | { |
90 | if (start_offset >= tables.len) |
91 | *table_count = 0; |
92 | else |
93 | *table_count = MIN<unsigned int> (a: *table_count, b: tables.len - start_offset); |
94 | |
95 | const TableRecord *sub_tables = tables.array + start_offset; |
96 | unsigned int count = *table_count; |
97 | for (unsigned int i = 0; i < count; i++) |
98 | table_tags[i] = sub_tables[i].tag; |
99 | } |
100 | return tables.len; |
101 | } |
102 | inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const |
103 | { |
104 | Tag t; |
105 | t.set (tag); |
106 | /* Linear-search for small tables to work around fonts with unsorted |
107 | * table list. */ |
108 | int i = tables.len < 64 ? tables.lsearch (x: t) : tables.bsearch (x: t); |
109 | if (table_index) |
110 | *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i; |
111 | return i != -1; |
112 | } |
113 | inline const TableRecord& get_table_by_tag (hb_tag_t tag) const |
114 | { |
115 | unsigned int table_index; |
116 | find_table_index (tag, table_index: &table_index); |
117 | return get_table (i: table_index); |
118 | } |
119 | |
120 | public: |
121 | inline bool sanitize (hb_sanitize_context_t *c) const |
122 | { |
123 | TRACE_SANITIZE (this); |
124 | return_trace (c->check_struct (this) && tables.sanitize (c)); |
125 | } |
126 | |
127 | protected: |
128 | Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ |
129 | BinSearchArrayOf<TableRecord> |
130 | tables; |
131 | public: |
132 | DEFINE_SIZE_ARRAY (12, tables); |
133 | } OpenTypeFontFace; |
134 | |
135 | |
136 | /* |
137 | * TrueType Collections |
138 | */ |
139 | |
140 | struct |
141 | { |
142 | friend struct TTCHeader; |
143 | |
144 | inline unsigned int (void) const { return table.len; } |
145 | inline const OpenTypeFontFace& (unsigned int i) const { return this+table[i]; } |
146 | |
147 | inline bool (hb_sanitize_context_t *c) const |
148 | { |
149 | TRACE_SANITIZE (this); |
150 | return_trace (table.sanitize (c, this)); |
151 | } |
152 | |
153 | protected: |
154 | Tag ; /* TrueType Collection ID string: 'ttcf' */ |
155 | FixedVersion<>; /* Version of the TTC Header (1.0), |
156 | * 0x00010000u */ |
157 | ArrayOf<LOffsetTo<OffsetTable>, UINT32> |
158 | ; /* Array of offsets to the OffsetTable for each font |
159 | * from the beginning of the file */ |
160 | public: |
161 | DEFINE_SIZE_ARRAY (12, table); |
162 | }; |
163 | |
164 | struct |
165 | { |
166 | friend struct OpenTypeFontFile; |
167 | |
168 | private: |
169 | |
170 | inline unsigned int (void) const |
171 | { |
172 | switch (u.header.version.major) { |
173 | case 2: /* version 2 is compatible with version 1 */ |
174 | case 1: return u.version1.get_face_count (); |
175 | default:return 0; |
176 | } |
177 | } |
178 | inline const OpenTypeFontFace& (unsigned int i) const |
179 | { |
180 | switch (u.header.version.major) { |
181 | case 2: /* version 2 is compatible with version 1 */ |
182 | case 1: return u.version1.get_face (i); |
183 | default:return Null(OpenTypeFontFace); |
184 | } |
185 | } |
186 | |
187 | inline bool (hb_sanitize_context_t *c) const |
188 | { |
189 | TRACE_SANITIZE (this); |
190 | if (unlikely (!u.header.version.sanitize (c))) return_trace (false); |
191 | switch (u.header.version.major) { |
192 | case 2: /* version 2 is compatible with version 1 */ |
193 | case 1: return_trace (u.version1.sanitize (c)); |
194 | default:return_trace (true); |
195 | } |
196 | } |
197 | |
198 | protected: |
199 | union { |
200 | struct { |
201 | Tag ; /* TrueType Collection ID string: 'ttcf' */ |
202 | FixedVersion<>; /* Version of the TTC Header (1.0 or 2.0), |
203 | * 0x00010000u or 0x00020000u */ |
204 | } ; |
205 | TTCHeaderVersion1 ; |
206 | } ; |
207 | }; |
208 | |
209 | |
210 | /* |
211 | * OpenType Font File |
212 | */ |
213 | |
214 | struct OpenTypeFontFile |
215 | { |
216 | static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */ |
217 | |
218 | static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */ |
219 | static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */ |
220 | static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f'); /* TrueType Collection */ |
221 | static const hb_tag_t TrueTag = HB_TAG ('t','r','u','e'); /* Obsolete Apple TrueType */ |
222 | static const hb_tag_t Typ1Tag = HB_TAG ('t','y','p','1'); /* Obsolete Apple Type1 font in SFNT container */ |
223 | |
224 | inline hb_tag_t get_tag (void) const { return u.tag; } |
225 | |
226 | inline unsigned int get_face_count (void) const |
227 | { |
228 | switch (u.tag) { |
229 | case CFFTag: /* All the non-collection tags */ |
230 | case TrueTag: |
231 | case Typ1Tag: |
232 | case TrueTypeTag: return 1; |
233 | case TTCTag: return u.ttcHeader.get_face_count (); |
234 | default: return 0; |
235 | } |
236 | } |
237 | inline const OpenTypeFontFace& get_face (unsigned int i) const |
238 | { |
239 | switch (u.tag) { |
240 | /* Note: for non-collection SFNT data we ignore index. This is because |
241 | * Apple dfont container is a container of SFNT's. So each SFNT is a |
242 | * non-TTC, but the index is more than zero. */ |
243 | case CFFTag: /* All the non-collection tags */ |
244 | case TrueTag: |
245 | case Typ1Tag: |
246 | case TrueTypeTag: return u.fontFace; |
247 | case TTCTag: return u.ttcHeader.get_face (i); |
248 | default: return Null(OpenTypeFontFace); |
249 | } |
250 | } |
251 | |
252 | inline bool sanitize (hb_sanitize_context_t *c) const |
253 | { |
254 | TRACE_SANITIZE (this); |
255 | if (unlikely (!u.tag.sanitize (c))) return_trace (false); |
256 | switch (u.tag) { |
257 | case CFFTag: /* All the non-collection tags */ |
258 | case TrueTag: |
259 | case Typ1Tag: |
260 | case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); |
261 | case TTCTag: return_trace (u.ttcHeader.sanitize (c)); |
262 | default: return_trace (true); |
263 | } |
264 | } |
265 | |
266 | protected: |
267 | union { |
268 | Tag tag; /* 4-byte identifier. */ |
269 | OpenTypeFontFace fontFace; |
270 | TTCHeader ; |
271 | } u; |
272 | public: |
273 | DEFINE_SIZE_UNION (4, tag); |
274 | }; |
275 | |
276 | |
277 | } /* namespace OT */ |
278 | |
279 | |
280 | #endif /* HB_OPEN_FILE_PRIVATE_HH */ |
281 | |