DEFINE_SIZE_STATIC (214);
};
+struct MathItalicsCorrectionInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ italicsCorrection.sanitize (c, this));
+ }
+
+ inline bool get_value (hb_font_t *font, hb_codepoint_t glyph,
+ hb_position_t &value) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph);
+ if (likely (index == NOT_COVERED)) return false;
+ if (unlikely (index >= italicsCorrection.len)) return false;
+ value = italicsCorrection[index].get_x_value(font, this);
+ return true;
+ }
+
+protected:
+ OffsetTo<Coverage> coverage; /* Offset to Coverage table -
+ from the beginning of
+ MathItalicsCorrectionInfo
+ table. */
+ ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
+ defining italics correction
+ values for each
+ covered glyph. */
+
+public:
+ DEFINE_SIZE_ARRAY (2 + 2, italicsCorrection);
+};
+
+struct MathTopAccentAttachment
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ topAccentCoverage.sanitize (c, this) &&
+ topAccentAttachment.sanitize (c, this));
+ }
+
+ inline bool get_value (hb_font_t *font, hb_codepoint_t glyph,
+ hb_position_t &value) const
+ {
+ unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
+ if (likely (index == NOT_COVERED)) return false;
+ if (unlikely (index >= topAccentAttachment.len)) return false;
+ value = topAccentAttachment[index].get_x_value(font, this);
+ return true;
+ }
+
+protected:
+ OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
+ from the beginning of
+ MathTopAccentAttachment
+ table. */
+ ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
+ defining top accent
+ attachment points for each
+ covered glyph. */
+
+public:
+ DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
+};
+
+struct MathKern
+{
+ inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ unsigned int count = 2 * heightCount + 1;
+ for (unsigned int i = 0; i < count; i++)
+ if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (mathValueRecords,
+ mathValueRecords[0].static_size,
+ 2 * heightCount + 1) &&
+ sanitize_math_value_records (c));
+ }
+
+ inline hb_position_t get_value (hb_font_t *font,
+ hb_position_t &correction_height) const
+ {
+ const MathValueRecord* correctionHeight = mathValueRecords;
+ const MathValueRecord* kernValue = mathValueRecords + heightCount;
+ // The description of the MathKern table is a ambiguous, but interpreting
+ // "between the two heights found at those indexes" for 0 < i < len as
+ //
+ // correctionHeight[i-1] < correction_height <= correctionHeight[i]
+ //
+ // makes the result consistent with the limit cases and we can just use the
+ // binary search algorithm of std::upper_bound:
+ unsigned int count = heightCount;
+ unsigned int i = 0;
+ while (count > 0) {
+ unsigned int half = count / 2;
+ hb_position_t height =
+ correctionHeight[i + half].get_y_value(font, this);
+ if (height < correction_height) {
+ i += half + 1;
+ count -= half + 1;
+ } else
+ count = half;
+ }
+ return kernValue[i].get_x_value(font, this);
+ }
+
+protected:
+ USHORT heightCount;
+ MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
+ which the kern value changes.
+ Sorted by the height value in
+ design units. */
+ /* Array of kern values corresponding
+ to heights. */
+
+public:
+ DEFINE_SIZE_ARRAY (2, mathValueRecords);
+};
+
+struct MathKernInfoRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathKern[HB_OT_MATH_KERN_TOP_RIGHT].sanitize (c, base) &&
+ mathKern[HB_OT_MATH_KERN_TOP_LEFT].sanitize (c, base) &&
+ mathKern[HB_OT_MATH_KERN_BOTTOM_RIGHT].sanitize (c, base) &&
+ mathKern[HB_OT_MATH_KERN_BOTTOM_LEFT].sanitize (c, base));
+ }
+
+ inline bool has_math_kern (hb_ot_math_kern_t kern) const {
+ return mathKern[kern] != 0;
+ }
+ inline const MathKern &get_math_kern (hb_ot_math_kern_t kern,
+ const void *base) const {
+ return base+mathKern[kern];
+ }
+
+protected:
+ /* Offset to MathKern table for each corner -
+ from the beginning of MathKernInfo table. May be NULL. */
+ OffsetTo<MathKern> mathKern[HB_OT_MATH_KERN_BOTTOM_LEFT -
+ HB_OT_MATH_KERN_TOP_RIGHT + 1];
+
+public:
+ DEFINE_SIZE_STATIC (2 * (HB_OT_MATH_KERN_BOTTOM_LEFT -
+ HB_OT_MATH_KERN_TOP_RIGHT + 1));
+};
+
+struct MathKernInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathKernCoverage.sanitize (c, this) &&
+ mathKernInfoRecords.sanitize (c, this));
+ }
+
+ inline bool
+ get_math_kern_info_record (hb_codepoint_t glyph,
+ const MathKernInfoRecord *&record) const
+ {
+ unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
+ if (likely (index == NOT_COVERED)) return false;
+ if (unlikely (index >= mathKernInfoRecords.len)) return false;
+ record = &mathKernInfoRecords[index];
+ return true;
+ }
+
+protected:
+ OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table -
+ from the beginning of the
+ MathKernInfo table. */
+ ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of
+ MathKernInfoRecords,
+ per-glyph information for
+ mathematical positioning
+ of subscripts and
+ superscripts. */
+
+public:
+ DEFINE_SIZE_ARRAY (2 + 2, mathKernInfoRecords);
+};
+
+struct MathGlyphInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathItalicsCorrectionInfo.sanitize (c, this) &&
+ mathTopAccentAttachment.sanitize (c, this) &&
+ extendedShapeCoverage.sanitize (c, this) &&
+ mathKernInfo.sanitize(c, this));
+ }
+
+ inline bool has_math_italics_correction_info (void) const {
+ return mathItalicsCorrectionInfo != 0;
+ }
+ inline const MathItalicsCorrectionInfo&
+ get_math_italics_correction_info (void) const {
+ return this+mathItalicsCorrectionInfo;
+ }
+
+ inline bool has_math_top_accent_attachment (void) const {
+ return mathTopAccentAttachment != 0;
+ }
+ inline const MathTopAccentAttachment&
+ get_math_top_accent_attachment (void) const {
+ return this+mathTopAccentAttachment;
+ }
+
+ inline bool is_extended_shape (hb_codepoint_t glyph) const
+ {
+ if (likely (extendedShapeCoverage == 0)) return false;
+ unsigned int index = (this+extendedShapeCoverage).get_coverage (glyph);
+ if (likely (index == NOT_COVERED)) return false;
+ return true;
+ }
+
+ inline bool has_math_kern_info (void) const { return mathKernInfo != 0; }
+ inline const MathKernInfo &get_math_kern_info (void) const {
+ return this+mathKernInfo;
+ }
+
+protected:
+ /* Offset to MathItalicsCorrectionInfo table -
+ from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
+
+ /* Offset to MathTopAccentAttachment table -
+ from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
+
+ /* Offset to coverage table for Extended Shape glyphs -
+ from the beginning of MathGlyphInfo table. When the left or right glyph of
+ a box is an extended shape variant, the (ink) box (and not the default
+ position defined by values in MathConstants table) should be used for
+ vertical positioning purposes. May be NULL.. */
+ OffsetTo<Coverage> extendedShapeCoverage;
+
+ /* Offset to MathKernInfo table -
+ from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathKernInfo> mathKernInfo;
+
+public:
+ DEFINE_SIZE_STATIC (4 * 2);
+};
+
/*
* MATH -- The MATH Table
*/
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
- mathConstants.sanitize (c, this));
+ mathConstants.sanitize (c, this) &&
+ mathGlyphInfo.sanitize (c, this));
}
inline bool has_math_constants (void) const { return mathConstants != 0; }
return this+mathConstants;
}
+ inline bool has_math_glyph_info (void) const { return mathGlyphInfo != 0; }
+ inline const MathGlyphInfo &get_math_glyph_info (void) const {
+ return this+mathGlyphInfo;
+ }
protected:
FixedVersion<>version; /* Version of the MATH table
* initially set to 0x00010000u */
OffsetTo<MathConstants> mathConstants; /* MathConstants table */
+ OffsetTo<MathGlyphInfo> mathGlyphInfo; /* MathGlyphInfo table */
public:
- DEFINE_SIZE_STATIC (6);
+ DEFINE_SIZE_STATIC (8);
};
} /* mathspace OT */
return math.has_math_constants() ?
math.get_math_constants().get_value(font, constant) : 0;
}
+
+/**
+ * hb_ot_layout_get_math_italic_correction:
+ *
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the italic correction of the glyph or 0
+ *
+ * Since: ????
+ **/
+HB_EXTERN hb_position_t
+hb_ot_layout_get_math_italic_correction (hb_font_t *font,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (font->face);
+ if (math.has_math_glyph_info()) {
+ const OT::MathGlyphInfo &glyphInfo = math.get_math_glyph_info();
+ if (glyphInfo.has_math_italics_correction_info()) {
+ hb_position_t value;
+ if (glyphInfo.get_math_italics_correction_info().get_value(font, glyph,
+ value))
+ return value;
+ }
+ }
+ return 0;
+}
+
+/**
+ * hb_ot_layout_get_math_top_accent_attachment:
+ *
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the top accent attachment of the glyph or 0
+ *
+ * Since: ????
+ **/
+HB_EXTERN hb_position_t
+hb_ot_layout_get_math_top_accent_attachment (hb_font_t *font,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (font->face);
+ if (math.has_math_glyph_info()) {
+ const OT::MathGlyphInfo &glyphInfo = math.get_math_glyph_info();
+ if (glyphInfo.has_math_top_accent_attachment()) {
+ hb_position_t value;
+ if (glyphInfo.get_math_top_accent_attachment().get_value(font, glyph,
+ value))
+ return value;
+ }
+ }
+ return 0;
+}
+
+/**
+ * hb_ot_layout_is_math_extended_shape:
+ *
+ * @font: a #hb_font_t to test
+ * @glyph: a glyph index to test
+ *
+ * Return value: #TRUE if the glyph is an extended shape and #FALSE otherwise
+ *
+ * Since: ????
+ **/
+HB_EXTERN hb_bool_t
+hb_ot_layout_is_math_extended_shape (hb_face_t *face,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (face);
+ return math.has_math_glyph_info() &&
+ math.get_math_glyph_info().is_extended_shape(glyph);
+}
+
+/**
+ * hb_ot_layout_get_math_kerning:
+ *
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ * @kern: the #hb_ot_math_kern_t from which to retrieve the value
+ * @correction_height: the correction height to use to determine the kerning.
+ *
+ * This function tries to retrieve the MathKern table for the specified font,
+ * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
+ * MathKern table to find one value that is greater or equal to specified
+ * correction_height. If one is found the corresponding value from the list of
+ * kerns is returned and otherwise the last kern value is returned.
+ *
+ * Return value: requested kerning or 0
+ *
+ * Since: ????
+ **/
+HB_EXTERN hb_position_t
+hb_ot_layout_get_math_kerning (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height)
+{
+ const OT::MATH &math = _get_math (font->face);
+ if (math.has_math_glyph_info()) {
+ const OT::MathGlyphInfo &glyphInfo = math.get_math_glyph_info();
+ if (glyphInfo.has_math_kern_info()) {
+ const OT::MathKernInfo &kernInfo = glyphInfo.get_math_kern_info();
+ const OT::MathKernInfoRecord *kernInfoRecord;
+ if (kernInfo.get_math_kern_info_record(glyph, kernInfoRecord) &&
+ kernInfoRecord->has_math_kern(kern)) {
+ return kernInfoRecord->
+ get_math_kern(kern, &kernInfo).get_value(font, correction_height);
+ }
+ }
+ }
+
+ return 0;
+}
hb_ot_layout_get_math_constant (hb_font_t *font,
hb_ot_math_constant_t constant);
+HB_EXTERN hb_position_t
+hb_ot_layout_get_math_italic_correction (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_layout_get_math_top_accent_attachment (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_is_math_extended_shape (hb_face_t *face,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_layout_get_math_kerning (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height);
+
HB_END_DECLS
HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT = 55
} hb_ot_math_constant_t;
+typedef enum {
+ HB_OT_MATH_KERN_TOP_RIGHT = 0,
+ HB_OT_MATH_KERN_TOP_LEFT = 1,
+ HB_OT_MATH_KERN_BOTTOM_RIGHT = 2,
+ HB_OT_MATH_KERN_BOTTOM_LEFT = 3
+} hb_ot_math_kern_t;
+
HB_END_DECLS
#endif /* HB_OT_MATH_H */
cleanupFreeType();
}
+static void
+test_get_math_italic_correction (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 0); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 0); // MathGlyphInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 0); // MathItalicsCorrectionInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 0); // Glyph without italic correction.
+ g_assert(hb_font_get_glyph_from_name (hb_font, "A", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 197);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "B", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 150);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "C", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_italic_correction (hb_font, glyph), ==, 452);
+ closeFont();
+
+ cleanupFreeType();
+
+}
+
+static void
+test_get_math_top_accent_attachment (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 0); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 0); // MathGlyphInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 0); // MathTopAccentAttachment empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 0); // Glyph without top accent attachment.
+ g_assert(hb_font_get_glyph_from_name (hb_font, "D", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 374);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "E", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 346);
+ g_assert(hb_font_get_glyph_from_name (hb_font, "F", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_top_accent_attachment (hb_font, glyph), ==, 318);
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_is_math_extended_shape (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert(!hb_ot_layout_is_math_extended_shape (hb_face, glyph)); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial1.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert(!hb_ot_layout_is_math_extended_shape (hb_face, glyph)); // MathGlyphInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "G", -1, &glyph));
+ g_assert(!hb_ot_layout_is_math_extended_shape (hb_face, glyph));
+ g_assert(hb_font_get_glyph_from_name (hb_font, "H", -1, &glyph));
+ g_assert(hb_ot_layout_is_math_extended_shape (hb_face, glyph));
+ closeFont();
+
+ cleanupFreeType();
+}
+
+static void
+test_get_math_kerning (void)
+{
+ hb_codepoint_t glyph;
+ initFreeType();
+
+ openFont("fonts/MathTestFontEmpty.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0), ==, 0); // MathGlyphInfo not available
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0), ==, 0); // MathGlyphInfo not available
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial2.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0), ==, 0); // MathKernInfo empty
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0), ==, 0); // MathKernInfo empty
+ closeFont();
+
+ openFont("fonts/MathTestFontPartial3.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "space", -1, &glyph));
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 0), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 0), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0), ==, 0); // MathKernInfoRecords empty
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 0), ==, 0); // MathKernInfoRecords empty
+ closeFont();
+
+ openFont("fonts/MathTestFontFull.otf");
+ g_assert(hb_font_get_glyph_from_name (hb_font, "I", -1, &glyph));
+
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 7), ==, 31); // lower than min heigth
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 14), ==, 31); // equal to min height
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 20), ==, 52);
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 23), ==, 52);
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 31), ==, 73);
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 32), ==, 73);
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 86), ==, 199); // equal to max height
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 91), ==, 220); // larger than max height
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 96), ==, 220); // larger than max height
+
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_RIGHT, 39), ==, 94); // top right
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_TOP_LEFT, 39), ==, 55); // top left
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_RIGHT, 39), ==, 22); // bottom right
+ g_assert_cmpint(hb_ot_layout_get_math_kerning (hb_font, glyph, HB_OT_MATH_KERN_BOTTOM_LEFT, 39), ==, 50); // bottom left
+
+ closeFont();
+
+ cleanupFreeType();
+}
+
+
int
main (int argc, char **argv)
{
hb_test_add (test_has_math_data);
hb_test_add (test_get_math_constant);
+ hb_test_add (test_get_math_italic_correction);
+ hb_test_add (test_get_math_top_accent_attachment);
+ hb_test_add (test_is_math_extended_shape);
+ hb_test_add (test_get_math_kerning);
return hb_test_run();
}