MATH Table: Add API to check availability of math data.
diff --git a/src/Makefile.sources b/src/Makefile.sources index ac80683..cd30b12 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources
@@ -75,6 +75,7 @@ hb-ot-layout-gsubgpos-private.hh \ hb-ot-layout-gsub-table.hh \ hb-ot-layout-jstf-table.hh \ + hb-ot-layout-math-table.hh \ hb-ot-layout-private.hh \ hb-ot-map.cc \ hb-ot-map-private.hh \
diff --git a/src/hb-ot-layout-math-table.hh b/src/hb-ot-layout-math-table.hh new file mode 100644 index 0000000..f4ecf3f --- /dev/null +++ b/src/hb-ot-layout-math-table.hh
@@ -0,0 +1,60 @@ +/* + * Copyright © 2016 Igalia S.L. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Igalia Author(s): Frédéric Wang + */ + +#ifndef HB_OT_LAYOUT_MATH_TABLE_HH +#define HB_OT_LAYOUT_MATH_TABLE_HH + +#include "hb-open-type-private.hh" +#include "hb-ot-layout-common-private.hh" + +namespace OT { + +/* + * MATH -- The MATH Table + */ + +struct MATH +{ + static const hb_tag_t tableTag = HB_OT_TAG_MATH; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + likely (version.major == 1)); + } + +protected: + FixedVersion<>version; /* Version of the MATH table + initially set to 0x00010000u */ +public: + DEFINE_SIZE_STATIC (4); +}; + +} /* mathspace OT */ + + +#endif /* HB_OT_LAYOUT_MATH_TABLE_HH */
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 778b2c4..a4272de 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh
@@ -124,6 +124,7 @@ struct GDEF; struct GSUB; struct GPOS; + struct MATH; } struct hb_ot_layout_lookup_accelerator_t @@ -152,10 +153,12 @@ hb_blob_t *gdef_blob; hb_blob_t *gsub_blob; hb_blob_t *gpos_blob; + hb_blob_t *math_blob; const struct OT::GDEF *gdef; const struct OT::GSUB *gsub; const struct OT::GPOS *gpos; + const struct OT::MATH *math; unsigned int gsub_lookup_count; unsigned int gpos_lookup_count;
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 5cb1491..24d290c 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc
@@ -35,6 +35,7 @@ #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-jstf-table.hh" +#include "hb-ot-layout-math-table.hh" #include "hb-ot-map-private.hh" @@ -60,6 +61,10 @@ layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS)); layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob); + // The MATH table is rarer so we only try and load it in _get_math + layout->math_blob = NULL; + layout->math = NULL; + { /* * The ugly business of blacklisting individual fonts' tables happen here! @@ -178,6 +183,8 @@ hb_blob_destroy (layout->gsub_blob); hb_blob_destroy (layout->gpos_blob); + if (layout->math_blob) hb_blob_destroy (layout->math_blob); + free (layout); } @@ -199,6 +206,21 @@ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS); return *hb_ot_layout_from_face (face)->gpos; } +static inline const OT::MATH& +_get_math (hb_face_t *face) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::MATH); + + hb_ot_layout_t * layout = hb_ot_layout_from_face (face); + + // If the MATH table is not loaded yet, do it now. + if (!layout->math_blob) { + layout->math_blob = OT::Sanitizer<OT::MATH>::sanitize (face->reference_table (HB_OT_TAG_MATH)); + layout->math = OT::Sanitizer<OT::MATH>::lock_instance (layout->math_blob); + } + + return *layout->math; +} /* @@ -1190,3 +1212,26 @@ { apply_string<GSUBProxy> (c, lookup, accel); } + +/* + * OT::MATH + */ + +/** + * hb_ot_layout_has_math_data: + * + * @face: #hb_face_t to test + * + * This function allows to verify the presence of an OpenType MATH table on the + * face. If so, such a table will be loaded into memory and sanitized. You can + * then safely call other functions for math layout and shaping. + * + * Return value: #TRUE if face has a MATH table and #FALSE otherwise + * + * Since: ???? + **/ +hb_bool_t +hb_ot_layout_has_math_data (hb_face_t *face) +{ + return &_get_math (face) != &OT::Null(OT::MATH); +}
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index eb23d45..7cbd794 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h
@@ -42,6 +42,7 @@ #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B') #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S') #define HB_OT_TAG_JSTF HB_TAG('J','S','T','F') +#define HB_OT_TAG_MATH HB_TAG('M','A','T','H') /* @@ -297,6 +298,12 @@ unsigned int *range_end /* OUT. May be NULL */); +/* + * MATH + */ + +HB_EXTERN hb_bool_t +hb_ot_layout_has_math_data (hb_face_t *face); HB_END_DECLS #endif /* HB_OT_LAYOUT_H */
diff --git a/test/api/Makefile.am b/test/api/Makefile.am index d7d40af..dae8700 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am
@@ -43,10 +43,22 @@ if HAVE_OT + TEST_PROGS += \ test-ot-tag \ $(NULL) -endif + +if HAVE_FREETYPE +TEST_PROGS += \ + test-ot-layout-math \ + $(NULL) +test_ot_layout_math_LDADD = $(LDADD) +test_ot_layout_math_CPPFLAGS = $(AM_CPPFLAGS) +test_ot_layout_math_CPPFLAGS += $(FREETYPE_CFLAGS) +test_ot_layout_math_LDADD += $(FREETYPE_LIBS) +endif # HAVE_FREETYPE + +endif # HAVE_OT # Tests for header compilation TEST_PROGS += \
diff --git a/test/api/fonts/MathTestFontEmpty.otf b/test/api/fonts/MathTestFontEmpty.otf new file mode 100644 index 0000000..6b50d66 --- /dev/null +++ b/test/api/fonts/MathTestFontEmpty.otf Binary files differ
diff --git a/test/api/fonts/MathTestFontNone.otf b/test/api/fonts/MathTestFontNone.otf new file mode 100644 index 0000000..52984ee --- /dev/null +++ b/test/api/fonts/MathTestFontNone.otf Binary files differ
diff --git a/test/api/test-ot-layout-math.c b/test/api/test-ot-layout-math.c new file mode 100644 index 0000000..cf7d76c --- /dev/null +++ b/test/api/test-ot-layout-math.c
@@ -0,0 +1,98 @@ +/* + * Copyright © 2016 Igalia S.L. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Igalia Author(s): Frédéric Wang + */ + + +#include "hb-test.h" + +#include "hb-ft.h" +#include "hb-ot.h" + +/* Unit tests for hb-ot-layout.h - OpenType MATH table */ + +static FT_Library ft_library; +static FT_Face ft_face; +static hb_font_t *hb_font; +static hb_face_t *hb_face; + +static void +initFreeType() +{ + FT_Error ft_error; + if ((ft_error = FT_Init_FreeType (&ft_library))) + abort(); +} + +static void +cleanupFreeType() +{ + FT_Done_FreeType (ft_library); +} + +static void +openFont(const char* fontFile) +{ + FT_Error ft_error; + if ((ft_error = FT_New_Face (ft_library, fontFile, 0, &ft_face))) + abort(); + unsigned int fontSize = 1000; + if ((ft_error = FT_Set_Char_Size (ft_face, fontSize, fontSize, 0, 0))) + abort(); + hb_font = hb_ft_font_create (ft_face, NULL); + hb_face = hb_ft_face_create_cached(ft_face); +} + +static void +closeFont() +{ + hb_font_destroy (hb_font); + FT_Done_Face (ft_face); +} + +static void +test_has_math_data (void) +{ + initFreeType(); + + openFont("fonts/MathTestFontNone.otf"); + g_assert(!hb_ot_layout_has_math_data (hb_face)); // MATH table not available + closeFont(); + + openFont("fonts/MathTestFontEmpty.otf"); + g_assert(hb_ot_layout_has_math_data (hb_face)); // MATH table available + closeFont(); + + cleanupFreeType(); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_has_math_data); + + return hb_test_run(); +}