Line data Source code
1 : /*
2 : * Copyright © 2016 Igalia S.L.
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 : * Igalia Author(s): Frédéric Wang
25 : */
26 :
27 : #ifndef HB_OT_MATH_TABLE_HH
28 : #define HB_OT_MATH_TABLE_HH
29 :
30 : #include "hb-open-type-private.hh"
31 : #include "hb-ot-layout-common-private.hh"
32 : #include "hb-ot-math.h"
33 :
34 : namespace OT {
35 :
36 :
37 : struct MathValueRecord
38 : {
39 0 : inline hb_position_t get_x_value (hb_font_t *font, const void *base) const
40 0 : { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
41 0 : inline hb_position_t get_y_value (hb_font_t *font, const void *base) const
42 0 : { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
43 :
44 0 : inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
45 : {
46 0 : TRACE_SANITIZE (this);
47 0 : return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
48 : }
49 :
50 : protected:
51 : SHORT value; /* The X or Y value in design units */
52 : OffsetTo<Device> deviceTable; /* Offset to the device table - from the
53 : * beginning of parent table. May be NULL.
54 : * Suggested format for device table is 1. */
55 :
56 : public:
57 : DEFINE_SIZE_STATIC (4);
58 : };
59 :
60 : struct MathConstants
61 : {
62 0 : inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
63 : {
64 0 : TRACE_SANITIZE (this);
65 :
66 0 : unsigned int count = ARRAY_LENGTH (mathValueRecords);
67 0 : for (unsigned int i = 0; i < count; i++)
68 0 : if (!mathValueRecords[i].sanitize (c, this))
69 0 : return_trace (false);
70 :
71 0 : return_trace (true);
72 : }
73 :
74 0 : inline bool sanitize (hb_sanitize_context_t *c) const
75 : {
76 0 : TRACE_SANITIZE (this);
77 0 : return_trace (c->check_struct (this) && sanitize_math_value_records(c));
78 : }
79 :
80 0 : inline hb_position_t get_value (hb_ot_math_constant_t constant,
81 : hb_font_t *font) const
82 : {
83 0 : switch (constant) {
84 :
85 : case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
86 : case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
87 0 : return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
88 :
89 : case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
90 : case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
91 0 : return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
92 :
93 : case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
94 : case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
95 : case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
96 : case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
97 0 : return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this);
98 :
99 : case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
100 : case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
101 : case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
102 : case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
103 : case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
104 : case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
105 : case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
106 : case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
107 : case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
108 : case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
109 : case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
110 : case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
111 : case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
112 : case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
113 : case HB_OT_MATH_CONSTANT_MATH_LEADING:
114 : case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
115 : case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
116 : case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
117 : case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
118 : case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
119 : case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
120 : case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
121 : case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
122 : case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
123 : case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
124 : case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
125 : case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
126 : case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
127 : case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
128 : case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
129 : case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
130 : case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
131 : case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
132 : case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
133 : case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
134 : case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
135 : case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
136 : case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
137 : case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
138 : case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
139 : case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
140 : case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
141 : case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
142 : case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
143 : case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
144 : case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
145 : case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
146 0 : return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this);
147 :
148 : case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
149 0 : return radicalDegreeBottomRaisePercent;
150 :
151 : default:
152 0 : return 0;
153 : }
154 : }
155 :
156 : protected:
157 : SHORT percentScaleDown[2];
158 : USHORT minHeight[2];
159 : MathValueRecord mathValueRecords[51];
160 : SHORT radicalDegreeBottomRaisePercent;
161 :
162 : public:
163 : DEFINE_SIZE_STATIC (214);
164 : };
165 :
166 : struct MathItalicsCorrectionInfo
167 : {
168 0 : inline bool sanitize (hb_sanitize_context_t *c) const
169 : {
170 0 : TRACE_SANITIZE (this);
171 0 : return_trace (c->check_struct (this) &&
172 : coverage.sanitize (c, this) &&
173 : italicsCorrection.sanitize (c, this));
174 : }
175 :
176 0 : inline hb_position_t get_value (hb_codepoint_t glyph,
177 : hb_font_t *font) const
178 : {
179 0 : unsigned int index = (this+coverage).get_coverage (glyph);
180 0 : return italicsCorrection[index].get_x_value (font, this);
181 : }
182 :
183 : protected:
184 : OffsetTo<Coverage> coverage; /* Offset to Coverage table -
185 : * from the beginning of
186 : * MathItalicsCorrectionInfo
187 : * table. */
188 : ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
189 : * defining italics correction
190 : * values for each
191 : * covered glyph. */
192 :
193 : public:
194 : DEFINE_SIZE_ARRAY (4, italicsCorrection);
195 : };
196 :
197 : struct MathTopAccentAttachment
198 : {
199 0 : inline bool sanitize (hb_sanitize_context_t *c) const
200 : {
201 0 : TRACE_SANITIZE (this);
202 0 : return_trace (c->check_struct (this) &&
203 : topAccentCoverage.sanitize (c, this) &&
204 : topAccentAttachment.sanitize (c, this));
205 : }
206 :
207 0 : inline hb_position_t get_value (hb_codepoint_t glyph,
208 : hb_font_t *font) const
209 : {
210 0 : unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
211 0 : if (index == NOT_COVERED)
212 0 : return font->get_glyph_h_advance (glyph) / 2;
213 0 : return topAccentAttachment[index].get_x_value(font, this);
214 : }
215 :
216 : protected:
217 : OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
218 : * from the beginning of
219 : * MathTopAccentAttachment
220 : * table. */
221 : ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
222 : * defining top accent
223 : * attachment points for each
224 : * covered glyph. */
225 :
226 : public:
227 : DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
228 : };
229 :
230 : struct MathKern
231 : {
232 0 : inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
233 : {
234 0 : TRACE_SANITIZE (this);
235 0 : unsigned int count = 2 * heightCount + 1;
236 0 : for (unsigned int i = 0; i < count; i++)
237 0 : if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
238 0 : return_trace (true);
239 : }
240 :
241 0 : inline bool sanitize (hb_sanitize_context_t *c) const
242 : {
243 0 : TRACE_SANITIZE (this);
244 0 : return_trace (c->check_struct (this) &&
245 : c->check_array (mathValueRecords,
246 : mathValueRecords[0].static_size,
247 : 2 * heightCount + 1) &&
248 : sanitize_math_value_records (c));
249 : }
250 :
251 0 : inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
252 : {
253 0 : const MathValueRecord* correctionHeight = mathValueRecords;
254 0 : const MathValueRecord* kernValue = mathValueRecords + heightCount;
255 0 : int sign = font->y_scale < 0 ? -1 : +1;
256 :
257 : /* The description of the MathKern table is a ambiguous, but interpreting
258 : * "between the two heights found at those indexes" for 0 < i < len as
259 : *
260 : * correctionHeight[i-1] < correction_height <= correctionHeight[i]
261 : *
262 : * makes the result consistent with the limit cases and we can just use the
263 : * binary search algorithm of std::upper_bound:
264 : */
265 0 : unsigned int i = 0;
266 0 : unsigned int count = heightCount;
267 0 : while (count > 0)
268 : {
269 0 : unsigned int half = count / 2;
270 0 : hb_position_t height = correctionHeight[i + half].get_y_value(font, this);
271 0 : if (sign * height < sign * correction_height)
272 : {
273 0 : i += half + 1;
274 0 : count -= half + 1;
275 : } else
276 0 : count = half;
277 : }
278 0 : return kernValue[i].get_x_value(font, this);
279 : }
280 :
281 : protected:
282 : USHORT heightCount;
283 : MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
284 : * which the kern value changes.
285 : * Sorted by the height value in
286 : * design units (heightCount entries),
287 : * Followed by:
288 : * Array of kern values corresponding
289 : * to heights. (heightCount+1 entries).
290 : */
291 :
292 : public:
293 : DEFINE_SIZE_ARRAY (2, mathValueRecords);
294 : };
295 :
296 : struct MathKernInfoRecord
297 : {
298 0 : inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
299 : {
300 0 : TRACE_SANITIZE (this);
301 :
302 0 : unsigned int count = ARRAY_LENGTH (mathKern);
303 0 : for (unsigned int i = 0; i < count; i++)
304 0 : if (unlikely (!mathKern[i].sanitize (c, base)))
305 0 : return_trace (false);
306 :
307 0 : return_trace (true);
308 : }
309 :
310 0 : inline hb_position_t get_kerning (hb_ot_math_kern_t kern,
311 : hb_position_t correction_height,
312 : hb_font_t *font,
313 : const void *base) const
314 : {
315 0 : unsigned int idx = kern;
316 0 : if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
317 0 : return (base+mathKern[idx]).get_value (correction_height, font);
318 : }
319 :
320 : protected:
321 : /* Offset to MathKern table for each corner -
322 : * from the beginning of MathKernInfo table. May be NULL. */
323 : OffsetTo<MathKern> mathKern[4];
324 :
325 : public:
326 : DEFINE_SIZE_STATIC (8);
327 : };
328 :
329 : struct MathKernInfo
330 : {
331 0 : inline bool sanitize (hb_sanitize_context_t *c) const
332 : {
333 0 : TRACE_SANITIZE (this);
334 0 : return_trace (c->check_struct (this) &&
335 : mathKernCoverage.sanitize (c, this) &&
336 : mathKernInfoRecords.sanitize (c, this));
337 : }
338 :
339 0 : inline hb_position_t get_kerning (hb_codepoint_t glyph,
340 : hb_ot_math_kern_t kern,
341 : hb_position_t correction_height,
342 : hb_font_t *font) const
343 : {
344 0 : unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
345 0 : return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
346 : }
347 :
348 : protected:
349 : OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table -
350 : * from the beginning of the
351 : * MathKernInfo table. */
352 : ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of
353 : * MathKernInfoRecords,
354 : * per-glyph information for
355 : * mathematical positioning
356 : * of subscripts and
357 : * superscripts. */
358 :
359 : public:
360 : DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
361 : };
362 :
363 : struct MathGlyphInfo
364 : {
365 0 : inline bool sanitize (hb_sanitize_context_t *c) const
366 : {
367 0 : TRACE_SANITIZE (this);
368 0 : return_trace (c->check_struct (this) &&
369 : mathItalicsCorrectionInfo.sanitize (c, this) &&
370 : mathTopAccentAttachment.sanitize (c, this) &&
371 : extendedShapeCoverage.sanitize (c, this) &&
372 : mathKernInfo.sanitize(c, this));
373 : }
374 :
375 : inline hb_position_t
376 0 : get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
377 0 : { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
378 :
379 : inline hb_position_t
380 0 : get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
381 0 : { return (this+mathTopAccentAttachment).get_value (glyph, font); }
382 :
383 0 : inline bool is_extended_shape (hb_codepoint_t glyph) const
384 0 : { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
385 :
386 0 : inline hb_position_t get_kerning (hb_codepoint_t glyph,
387 : hb_ot_math_kern_t kern,
388 : hb_position_t correction_height,
389 : hb_font_t *font) const
390 0 : { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
391 :
392 : protected:
393 : /* Offset to MathItalicsCorrectionInfo table -
394 : * from the beginning of MathGlyphInfo table. */
395 : OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
396 :
397 : /* Offset to MathTopAccentAttachment table -
398 : * from the beginning of MathGlyphInfo table. */
399 : OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
400 :
401 : /* Offset to coverage table for Extended Shape glyphs -
402 : * from the beginning of MathGlyphInfo table. When the left or right glyph of
403 : * a box is an extended shape variant, the (ink) box (and not the default
404 : * position defined by values in MathConstants table) should be used for
405 : * vertical positioning purposes. May be NULL.. */
406 : OffsetTo<Coverage> extendedShapeCoverage;
407 :
408 : /* Offset to MathKernInfo table -
409 : * from the beginning of MathGlyphInfo table. */
410 : OffsetTo<MathKernInfo> mathKernInfo;
411 :
412 : public:
413 : DEFINE_SIZE_STATIC (8);
414 : };
415 :
416 : struct MathGlyphVariantRecord
417 : {
418 : friend struct MathGlyphConstruction;
419 :
420 : inline bool sanitize (hb_sanitize_context_t *c) const
421 : {
422 : TRACE_SANITIZE (this);
423 : return_trace (c->check_struct (this));
424 : }
425 :
426 : protected:
427 : GlyphID variantGlyph; /* Glyph ID for the variant. */
428 : USHORT advanceMeasurement; /* Advance width/height, in design units, of the
429 : * variant, in the direction of requested
430 : * glyph extension. */
431 :
432 : public:
433 : DEFINE_SIZE_STATIC (4);
434 : };
435 :
436 : struct PartFlags : USHORT
437 : {
438 : enum Flags {
439 : Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
440 :
441 : Defined = 0x0001u, /* All defined flags. */
442 : };
443 :
444 : public:
445 : DEFINE_SIZE_STATIC (2);
446 : };
447 :
448 : struct MathGlyphPartRecord
449 : {
450 : inline bool sanitize (hb_sanitize_context_t *c) const
451 : {
452 : TRACE_SANITIZE (this);
453 : return_trace (c->check_struct (this));
454 : }
455 :
456 0 : inline void extract (hb_ot_math_glyph_part_t &out,
457 : int scale,
458 : hb_font_t *font) const
459 : {
460 0 : out.glyph = glyph;
461 :
462 0 : out.start_connector_length = font->em_scale (startConnectorLength, scale);
463 0 : out.end_connector_length = font->em_scale (endConnectorLength, scale);
464 0 : out.full_advance = font->em_scale (fullAdvance, scale);
465 :
466 : ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
467 : (unsigned int) PartFlags::Extender);
468 :
469 0 : out.flags = (hb_ot_math_glyph_part_flags_t)
470 0 : (unsigned int)
471 0 : (partFlags & PartFlags::Defined);
472 0 : }
473 :
474 : protected:
475 : GlyphID glyph; /* Glyph ID for the part. */
476 : USHORT startConnectorLength; /* Advance width/ height of the straight bar
477 : * connector material, in design units, is at
478 : * the beginning of the glyph, in the
479 : * direction of the extension. */
480 : USHORT endConnectorLength; /* Advance width/ height of the straight bar
481 : * connector material, in design units, is at
482 : * the end of the glyph, in the direction of
483 : * the extension. */
484 : USHORT fullAdvance; /* Full advance width/height for this part,
485 : * in the direction of the extension.
486 : * In design units. */
487 : PartFlags partFlags; /* Part qualifiers. */
488 :
489 : public:
490 : DEFINE_SIZE_STATIC (10);
491 : };
492 :
493 : struct MathGlyphAssembly
494 : {
495 0 : inline bool sanitize (hb_sanitize_context_t *c) const
496 : {
497 0 : TRACE_SANITIZE (this);
498 0 : return_trace (c->check_struct (this) &&
499 : italicsCorrection.sanitize(c, this) &&
500 : partRecords.sanitize(c));
501 : }
502 :
503 0 : inline unsigned int get_parts (hb_direction_t direction,
504 : hb_font_t *font,
505 : unsigned int start_offset,
506 : unsigned int *parts_count, /* IN/OUT */
507 : hb_ot_math_glyph_part_t *parts /* OUT */,
508 : hb_position_t *italics_correction /* OUT */) const
509 : {
510 0 : if (parts_count)
511 : {
512 0 : int scale = font->dir_scale (direction);
513 : const MathGlyphPartRecord *arr =
514 0 : partRecords.sub_array (start_offset, parts_count);
515 0 : unsigned int count = *parts_count;
516 0 : for (unsigned int i = 0; i < count; i++)
517 0 : arr[i].extract (parts[i], scale, font);
518 : }
519 :
520 0 : if (italics_correction)
521 0 : *italics_correction = italicsCorrection.get_x_value (font, this);
522 :
523 0 : return partRecords.len;
524 : }
525 :
526 : protected:
527 : MathValueRecord italicsCorrection; /* Italics correction of this
528 : * MathGlyphAssembly. Should not
529 : * depend on the assembly size. */
530 : ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from
531 : * left to right and bottom to
532 : * top. */
533 :
534 : public:
535 : DEFINE_SIZE_ARRAY (6, partRecords);
536 : };
537 :
538 : struct MathGlyphConstruction
539 : {
540 0 : inline bool sanitize (hb_sanitize_context_t *c) const
541 : {
542 0 : TRACE_SANITIZE (this);
543 0 : return_trace (c->check_struct (this) &&
544 : glyphAssembly.sanitize(c, this) &&
545 : mathGlyphVariantRecord.sanitize(c));
546 : }
547 :
548 0 : inline const MathGlyphAssembly &get_assembly (void) const
549 0 : { return this+glyphAssembly; }
550 :
551 0 : inline unsigned int get_variants (hb_direction_t direction,
552 : hb_font_t *font,
553 : unsigned int start_offset,
554 : unsigned int *variants_count, /* IN/OUT */
555 : hb_ot_math_glyph_variant_t *variants /* OUT */) const
556 : {
557 0 : if (variants_count)
558 : {
559 0 : int scale = font->dir_scale (direction);
560 : const MathGlyphVariantRecord *arr =
561 0 : mathGlyphVariantRecord.sub_array (start_offset, variants_count);
562 0 : unsigned int count = *variants_count;
563 0 : for (unsigned int i = 0; i < count; i++)
564 : {
565 0 : variants[i].glyph = arr[i].variantGlyph;
566 0 : variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
567 : }
568 : }
569 0 : return mathGlyphVariantRecord.len;
570 : }
571 :
572 : protected:
573 : /* Offset to MathGlyphAssembly table for this shape - from the beginning of
574 : MathGlyphConstruction table. May be NULL. */
575 : OffsetTo<MathGlyphAssembly> glyphAssembly;
576 :
577 : /* MathGlyphVariantRecords for alternative variants of the glyphs. */
578 : ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
579 :
580 : public:
581 : DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
582 : };
583 :
584 : struct MathVariants
585 : {
586 0 : inline bool sanitize_offsets (hb_sanitize_context_t *c) const
587 : {
588 0 : TRACE_SANITIZE (this);
589 0 : unsigned int count = vertGlyphCount + horizGlyphCount;
590 0 : for (unsigned int i = 0; i < count; i++)
591 0 : if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
592 0 : return_trace (true);
593 : }
594 :
595 0 : inline bool sanitize (hb_sanitize_context_t *c) const
596 : {
597 0 : TRACE_SANITIZE (this);
598 0 : return_trace (c->check_struct (this) &&
599 : vertGlyphCoverage.sanitize (c, this) &&
600 : horizGlyphCoverage.sanitize (c, this) &&
601 : c->check_array (glyphConstruction,
602 : glyphConstruction[0].static_size,
603 : vertGlyphCount + horizGlyphCount) &&
604 : sanitize_offsets (c));
605 : }
606 :
607 0 : inline hb_position_t get_min_connector_overlap (hb_direction_t direction,
608 : hb_font_t *font) const
609 0 : { return font->em_scale_dir (minConnectorOverlap, direction); }
610 :
611 0 : inline unsigned int get_glyph_variants (hb_codepoint_t glyph,
612 : hb_direction_t direction,
613 : hb_font_t *font,
614 : unsigned int start_offset,
615 : unsigned int *variants_count, /* IN/OUT */
616 : hb_ot_math_glyph_variant_t *variants /* OUT */) const
617 0 : { return get_glyph_construction (glyph, direction, font)
618 0 : .get_variants (direction, font, start_offset, variants_count, variants); }
619 :
620 0 : inline unsigned int get_glyph_parts (hb_codepoint_t glyph,
621 : hb_direction_t direction,
622 : hb_font_t *font,
623 : unsigned int start_offset,
624 : unsigned int *parts_count, /* IN/OUT */
625 : hb_ot_math_glyph_part_t *parts /* OUT */,
626 : hb_position_t *italics_correction /* OUT */) const
627 0 : { return get_glyph_construction (glyph, direction, font)
628 0 : .get_assembly ()
629 : .get_parts (direction, font,
630 : start_offset, parts_count, parts,
631 0 : italics_correction); }
632 :
633 : private:
634 : inline const MathGlyphConstruction &
635 0 : get_glyph_construction (hb_codepoint_t glyph,
636 : hb_direction_t direction,
637 : hb_font_t *font) const
638 : {
639 0 : bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
640 0 : unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
641 : const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
642 0 : : horizGlyphCoverage;
643 :
644 0 : unsigned int index = (this+coverage).get_coverage (glyph);
645 0 : if (unlikely (index >= count)) return Null(MathGlyphConstruction);
646 :
647 0 : if (!vertical)
648 0 : index += vertGlyphCount;
649 :
650 0 : return this+glyphConstruction[index];
651 : }
652 :
653 : protected:
654 : USHORT minConnectorOverlap; /* Minimum overlap of connecting
655 : * glyphs during glyph construction,
656 : * in design units. */
657 : OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table -
658 : * from the beginning of MathVariants
659 : * table. */
660 : OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table -
661 : * from the beginning of MathVariants
662 : * table. */
663 : USHORT vertGlyphCount; /* Number of glyphs for which
664 : * information is provided for
665 : * vertically growing variants. */
666 : USHORT horizGlyphCount; /* Number of glyphs for which
667 : * information is provided for
668 : * horizontally growing variants. */
669 :
670 : /* Array of offsets to MathGlyphConstruction tables - from the beginning of
671 : the MathVariants table, for shapes growing in vertical/horizontal
672 : direction. */
673 : OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
674 :
675 : public:
676 : DEFINE_SIZE_ARRAY (10, glyphConstruction);
677 : };
678 :
679 :
680 : /*
681 : * MATH -- The MATH Table
682 : */
683 :
684 : struct MATH
685 : {
686 : static const hb_tag_t tableTag = HB_OT_TAG_MATH;
687 :
688 0 : inline bool sanitize (hb_sanitize_context_t *c) const
689 : {
690 0 : TRACE_SANITIZE (this);
691 0 : return_trace (version.sanitize (c) &&
692 : likely (version.major == 1) &&
693 : mathConstants.sanitize (c, this) &&
694 : mathGlyphInfo.sanitize (c, this) &&
695 : mathVariants.sanitize (c, this));
696 : }
697 :
698 0 : inline hb_position_t get_constant (hb_ot_math_constant_t constant,
699 : hb_font_t *font) const
700 0 : { return (this+mathConstants).get_value (constant, font); }
701 :
702 0 : inline const MathGlyphInfo &get_math_glyph_info (void) const
703 0 : { return this+mathGlyphInfo; }
704 :
705 0 : inline const MathVariants &get_math_variants (void) const
706 0 : { return this+mathVariants; }
707 :
708 : protected:
709 : FixedVersion<>version; /* Version of the MATH table
710 : * initially set to 0x00010000u */
711 : OffsetTo<MathConstants> mathConstants;/* MathConstants table */
712 : OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
713 : OffsetTo<MathVariants> mathVariants; /* MathVariants table */
714 :
715 : public:
716 : DEFINE_SIZE_STATIC (10);
717 : };
718 :
719 : } /* namespace OT */
720 :
721 :
722 : #endif /* HB_OT_MATH_TABLE_HH */
|