diff --git a/src/Makefile.sources b/src/Makefile.sources index ac806838c..cd30b12f0 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -75,6 +75,7 @@ HB_OT_sources = \ 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 000000000..f4ecf3f0e --- /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 778b2c442..a4272de63 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -124,6 +124,7 @@ namespace OT { struct GDEF; struct GSUB; struct GPOS; + struct MATH; } struct hb_ot_layout_lookup_accelerator_t @@ -152,10 +153,12 @@ struct hb_ot_layout_t 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 5cb1491c3..24d290c5c 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 @@ _hb_ot_layout_create (hb_face_t *face) layout->gpos_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_GPOS)); layout->gpos = OT::Sanitizer::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_ot_layout_destroy (hb_ot_layout_t *layout) 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 @@ _get_gpos (hb_face_t *face) 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::sanitize (face->reference_table (HB_OT_TAG_MATH)); + layout->math = OT::Sanitizer::lock_instance (layout->math_blob); + } + + return *layout->math; +} /* @@ -1190,3 +1212,26 @@ hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c, { apply_string (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 eb23d45b6..7cbd794ce 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -42,6 +42,7 @@ HB_BEGIN_DECLS #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 @@ hb_ot_layout_get_size_params (hb_face_t *face, 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 d7d40af39..dae8700c3 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -43,10 +43,22 @@ endif 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 000000000..6b50d66fc Binary files /dev/null and b/test/api/fonts/MathTestFontEmpty.otf differ diff --git a/test/api/fonts/MathTestFontNone.otf b/test/api/fonts/MathTestFontNone.otf new file mode 100644 index 000000000..52984eecc Binary files /dev/null and b/test/api/fonts/MathTestFontNone.otf differ diff --git a/test/api/test-ot-layout-math.c b/test/api/test-ot-layout-math.c new file mode 100644 index 000000000..cf7d76c16 --- /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(); +}