1 | /* |
2 | * Copyright © 2016 Google, Inc. |
3 | * |
4 | * This is part of HarfBuzz, a text shaping library. |
5 | * |
6 | * Permission is hereby granted, without written agreement and without |
7 | * license or royalty fees, to use, copy, modify, and distribute this |
8 | * software and its documentation for any purpose, provided that the |
9 | * above copyright notice and the following two paragraphs appear in |
10 | * all copies of this software. |
11 | * |
12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | * DAMAGE. |
17 | * |
18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | * |
24 | * Google Author(s): Seigo Nonaka |
25 | */ |
26 | |
27 | #ifndef HB_OT_CBDT_TABLE_HH |
28 | #define HB_OT_CBDT_TABLE_HH |
29 | |
30 | #include "hb-open-type-private.hh" |
31 | |
32 | namespace OT { |
33 | |
34 | struct SmallGlyphMetrics |
35 | { |
36 | inline bool sanitize (hb_sanitize_context_t *c) const |
37 | { |
38 | TRACE_SANITIZE (this); |
39 | return_trace (c->check_struct (this)); |
40 | } |
41 | |
42 | inline void get_extents (hb_glyph_extents_t *extents) const |
43 | { |
44 | extents->x_bearing = bearingX; |
45 | extents->y_bearing = bearingY; |
46 | extents->width = width; |
47 | extents->height = -height; |
48 | } |
49 | |
50 | UINT8 height; |
51 | UINT8 width; |
52 | INT8 bearingX; |
53 | INT8 bearingY; |
54 | UINT8 advance; |
55 | |
56 | DEFINE_SIZE_STATIC(5); |
57 | }; |
58 | |
59 | struct BigGlyphMetrics : SmallGlyphMetrics |
60 | { |
61 | INT8 vertBearingX; |
62 | INT8 vertBearingY; |
63 | UINT8 vertAdvance; |
64 | |
65 | DEFINE_SIZE_STATIC(8); |
66 | }; |
67 | |
68 | struct SBitLineMetrics |
69 | { |
70 | inline bool sanitize (hb_sanitize_context_t *c) const |
71 | { |
72 | TRACE_SANITIZE (this); |
73 | return_trace (c->check_struct (this)); |
74 | } |
75 | |
76 | INT8 ascender; |
77 | INT8 decender; |
78 | UINT8 widthMax; |
79 | INT8 caretSlopeNumerator; |
80 | INT8 caretSlopeDenominator; |
81 | INT8 caretOffset; |
82 | INT8 minOriginSB; |
83 | INT8 minAdvanceSB; |
84 | INT8 maxBeforeBL; |
85 | INT8 minAfterBL; |
86 | INT8 padding1; |
87 | INT8 padding2; |
88 | |
89 | DEFINE_SIZE_STATIC(12); |
90 | }; |
91 | |
92 | |
93 | /* |
94 | * Index Subtables. |
95 | */ |
96 | |
97 | struct |
98 | { |
99 | inline bool (hb_sanitize_context_t *c) const |
100 | { |
101 | TRACE_SANITIZE (this); |
102 | return_trace (c->check_struct (this)); |
103 | } |
104 | |
105 | UINT16 ; |
106 | UINT16 ; |
107 | UINT32 ; |
108 | |
109 | DEFINE_SIZE_STATIC(8); |
110 | }; |
111 | |
112 | template <typename OffsetType> |
113 | struct IndexSubtableFormat1Or3 |
114 | { |
115 | inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const |
116 | { |
117 | TRACE_SANITIZE (this); |
118 | return_trace (c->check_struct (this) && |
119 | c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1)); |
120 | } |
121 | |
122 | bool get_image_data (unsigned int idx, |
123 | unsigned int *offset, |
124 | unsigned int *length) const |
125 | { |
126 | if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx])) |
127 | return false; |
128 | |
129 | *offset = header.imageDataOffset + offsetArrayZ[idx]; |
130 | *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx]; |
131 | return true; |
132 | } |
133 | |
134 | IndexSubtableHeader ; |
135 | Offset<OffsetType> offsetArrayZ[VAR]; |
136 | |
137 | DEFINE_SIZE_ARRAY(8, offsetArrayZ); |
138 | }; |
139 | |
140 | struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<UINT32> {}; |
141 | struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<UINT16> {}; |
142 | |
143 | struct IndexSubtable |
144 | { |
145 | inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const |
146 | { |
147 | TRACE_SANITIZE (this); |
148 | if (!u.header.sanitize (c)) return_trace (false); |
149 | switch (u.header.indexFormat) { |
150 | case 1: return_trace (u.format1.sanitize (c, glyph_count)); |
151 | case 3: return_trace (u.format3.sanitize (c, glyph_count)); |
152 | default:return_trace (true); |
153 | } |
154 | } |
155 | |
156 | inline bool get_extents (hb_glyph_extents_t *extents) const |
157 | { |
158 | switch (u.header.indexFormat) { |
159 | case 2: case 5: /* TODO */ |
160 | case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */ |
161 | default:return (false); |
162 | } |
163 | } |
164 | |
165 | bool get_image_data (unsigned int idx, |
166 | unsigned int *offset, |
167 | unsigned int *length, |
168 | unsigned int *format) const |
169 | { |
170 | *format = u.header.imageFormat; |
171 | switch (u.header.indexFormat) { |
172 | case 1: return u.format1.get_image_data (idx, offset, length); |
173 | case 3: return u.format3.get_image_data (idx, offset, length); |
174 | default: return false; |
175 | } |
176 | } |
177 | |
178 | protected: |
179 | union { |
180 | IndexSubtableHeader ; |
181 | IndexSubtableFormat1 format1; |
182 | IndexSubtableFormat3 format3; |
183 | /* TODO: Format 2, 4, 5. */ |
184 | } u; |
185 | public: |
186 | DEFINE_SIZE_UNION (8, header); |
187 | }; |
188 | |
189 | struct IndexSubtableRecord |
190 | { |
191 | inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
192 | { |
193 | TRACE_SANITIZE (this); |
194 | return_trace (c->check_struct (this) && |
195 | firstGlyphIndex <= lastGlyphIndex && |
196 | offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1)); |
197 | } |
198 | |
199 | inline bool get_extents (hb_glyph_extents_t *extents) const |
200 | { |
201 | return (this+offsetToSubtable).get_extents (extents); |
202 | } |
203 | |
204 | bool get_image_data (unsigned int gid, |
205 | unsigned int *offset, |
206 | unsigned int *length, |
207 | unsigned int *format) const |
208 | { |
209 | if (gid < firstGlyphIndex || gid > lastGlyphIndex) |
210 | { |
211 | return false; |
212 | } |
213 | return (this+offsetToSubtable).get_image_data (idx: gid - firstGlyphIndex, |
214 | offset, length, format); |
215 | } |
216 | |
217 | UINT16 firstGlyphIndex; |
218 | UINT16 lastGlyphIndex; |
219 | LOffsetTo<IndexSubtable> offsetToSubtable; |
220 | |
221 | DEFINE_SIZE_STATIC(8); |
222 | }; |
223 | |
224 | struct IndexSubtableArray |
225 | { |
226 | inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const |
227 | { |
228 | TRACE_SANITIZE (this); |
229 | if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count))) |
230 | return_trace (false); |
231 | for (unsigned int i = 0; i < count; i++) |
232 | if (unlikely (!indexSubtablesZ[i].sanitize (c, this))) |
233 | return_trace (false); |
234 | return_trace (true); |
235 | } |
236 | |
237 | public: |
238 | const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const |
239 | { |
240 | for (unsigned int i = 0; i < numTables; ++i) |
241 | { |
242 | unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex; |
243 | unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex; |
244 | if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) { |
245 | return &indexSubtablesZ[i]; |
246 | } |
247 | } |
248 | return nullptr; |
249 | } |
250 | |
251 | protected: |
252 | IndexSubtableRecord indexSubtablesZ[VAR]; |
253 | |
254 | public: |
255 | DEFINE_SIZE_ARRAY(0, indexSubtablesZ); |
256 | }; |
257 | |
258 | struct BitmapSizeTable |
259 | { |
260 | friend struct CBLC; |
261 | |
262 | inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
263 | { |
264 | TRACE_SANITIZE (this); |
265 | return_trace (c->check_struct (this) && |
266 | indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) && |
267 | c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) && |
268 | horizontal.sanitize (c) && |
269 | vertical.sanitize (c)); |
270 | } |
271 | |
272 | const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const |
273 | { |
274 | return (base+indexSubtableArrayOffset).find_table (glyph, numTables: numberOfIndexSubtables); |
275 | } |
276 | |
277 | protected: |
278 | LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset; |
279 | UINT32 indexTablesSize; |
280 | UINT32 numberOfIndexSubtables; |
281 | UINT32 colorRef; |
282 | SBitLineMetrics horizontal; |
283 | SBitLineMetrics vertical; |
284 | UINT16 startGlyphIndex; |
285 | UINT16 endGlyphIndex; |
286 | UINT8 ppemX; |
287 | UINT8 ppemY; |
288 | UINT8 bitDepth; |
289 | INT8 flags; |
290 | |
291 | public: |
292 | DEFINE_SIZE_STATIC(48); |
293 | }; |
294 | |
295 | |
296 | /* |
297 | * Glyph Bitmap Data Formats. |
298 | */ |
299 | |
300 | struct GlyphBitmapDataFormat17 |
301 | { |
302 | SmallGlyphMetrics glyphMetrics; |
303 | UINT32 dataLen; |
304 | UINT8 dataZ[VAR]; |
305 | |
306 | DEFINE_SIZE_ARRAY(9, dataZ); |
307 | }; |
308 | |
309 | |
310 | /* |
311 | * CBLC -- Color Bitmap Location Table |
312 | */ |
313 | |
314 | #define HB_OT_TAG_CBLC HB_TAG('C','B','L','C') |
315 | |
316 | struct CBLC |
317 | { |
318 | friend struct CBDT; |
319 | |
320 | static const hb_tag_t tableTag = HB_OT_TAG_CBLC; |
321 | |
322 | inline bool sanitize (hb_sanitize_context_t *c) const |
323 | { |
324 | TRACE_SANITIZE (this); |
325 | return_trace (c->check_struct (this) && |
326 | likely (version.major == 2 || version.major == 3) && |
327 | sizeTables.sanitize (c, this)); |
328 | } |
329 | |
330 | protected: |
331 | const IndexSubtableRecord *find_table (hb_codepoint_t glyph, |
332 | unsigned int *x_ppem, unsigned int *y_ppem) const |
333 | { |
334 | /* TODO: Make it possible to select strike. */ |
335 | |
336 | unsigned int count = sizeTables.len; |
337 | for (uint32_t i = 0; i < count; ++i) |
338 | { |
339 | unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex; |
340 | unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex; |
341 | if (startGlyphIndex <= glyph && glyph <= endGlyphIndex) |
342 | { |
343 | *x_ppem = sizeTables[i].ppemX; |
344 | *y_ppem = sizeTables[i].ppemY; |
345 | return sizeTables[i].find_table (glyph, base: this); |
346 | } |
347 | } |
348 | |
349 | return nullptr; |
350 | } |
351 | |
352 | protected: |
353 | FixedVersion<> version; |
354 | LArrayOf<BitmapSizeTable> sizeTables; |
355 | |
356 | public: |
357 | DEFINE_SIZE_ARRAY(8, sizeTables); |
358 | }; |
359 | |
360 | /* |
361 | * CBDT -- Color Bitmap Data Table |
362 | */ |
363 | #define HB_OT_TAG_CBDT HB_TAG('C','B','D','T') |
364 | |
365 | struct CBDT |
366 | { |
367 | static const hb_tag_t tableTag = HB_OT_TAG_CBDT; |
368 | |
369 | inline bool sanitize (hb_sanitize_context_t *c) const |
370 | { |
371 | TRACE_SANITIZE (this); |
372 | return_trace (c->check_struct (this) && |
373 | likely (version.major == 2 || version.major == 3)); |
374 | } |
375 | |
376 | struct accelerator_t |
377 | { |
378 | inline void init (hb_face_t *face) |
379 | { |
380 | upem = face->get_upem(); |
381 | |
382 | cblc_blob = Sanitizer<CBLC>::sanitize (blob: face->reference_table (HB_OT_TAG_CBLC)); |
383 | cbdt_blob = Sanitizer<CBDT>::sanitize (blob: face->reference_table (HB_OT_TAG_CBDT)); |
384 | cbdt_len = hb_blob_get_length (blob: cbdt_blob); |
385 | |
386 | if (hb_blob_get_length (blob: cblc_blob) == 0) { |
387 | cblc = nullptr; |
388 | cbdt = nullptr; |
389 | return; /* Not a bitmap font. */ |
390 | } |
391 | cblc = Sanitizer<CBLC>::lock_instance (blob: cblc_blob); |
392 | cbdt = Sanitizer<CBDT>::lock_instance (blob: cbdt_blob); |
393 | |
394 | } |
395 | |
396 | inline void fini (void) |
397 | { |
398 | hb_blob_destroy (blob: this->cblc_blob); |
399 | hb_blob_destroy (blob: this->cbdt_blob); |
400 | } |
401 | |
402 | inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const |
403 | { |
404 | unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */ |
405 | |
406 | if (!cblc) |
407 | return false; // Not a color bitmap font. |
408 | |
409 | const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, x_ppem: &x_ppem, y_ppem: &y_ppem); |
410 | if (!subtable_record || !x_ppem || !y_ppem) |
411 | return false; |
412 | |
413 | if (subtable_record->get_extents (extents)) |
414 | return true; |
415 | |
416 | unsigned int image_offset = 0, image_length = 0, image_format = 0; |
417 | if (!subtable_record->get_image_data (gid: glyph, offset: &image_offset, length: &image_length, format: &image_format)) |
418 | return false; |
419 | |
420 | { |
421 | if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) |
422 | return false; |
423 | |
424 | switch (image_format) |
425 | { |
426 | case 17: { |
427 | if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) |
428 | return false; |
429 | |
430 | const GlyphBitmapDataFormat17& glyphFormat17 = |
431 | StructAtOffset<GlyphBitmapDataFormat17> (P: this->cbdt, offset: image_offset); |
432 | glyphFormat17.glyphMetrics.get_extents (extents); |
433 | } |
434 | break; |
435 | default: |
436 | // TODO: Support other image formats. |
437 | return false; |
438 | } |
439 | } |
440 | |
441 | /* Convert to the font units. */ |
442 | extents->x_bearing *= upem / (float) x_ppem; |
443 | extents->y_bearing *= upem / (float) y_ppem; |
444 | extents->width *= upem / (float) x_ppem; |
445 | extents->height *= upem / (float) y_ppem; |
446 | |
447 | return true; |
448 | } |
449 | |
450 | private: |
451 | hb_blob_t *cblc_blob; |
452 | hb_blob_t *cbdt_blob; |
453 | const CBLC *cblc; |
454 | const CBDT *cbdt; |
455 | |
456 | unsigned int cbdt_len; |
457 | unsigned int upem; |
458 | }; |
459 | |
460 | |
461 | protected: |
462 | FixedVersion<>version; |
463 | UINT8 dataZ[VAR]; |
464 | |
465 | public: |
466 | DEFINE_SIZE_ARRAY(4, dataZ); |
467 | }; |
468 | |
469 | } /* namespace OT */ |
470 | |
471 | #endif /* HB_OT_CBDT_TABLE_HH */ |
472 | |