| Index: third_party/harfbuzz-ng/src/hb-ot-layout.cc
|
| diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
|
| index 0621f86d3b0c5029e3418acb2698dcc30ab78252..e241e332697895aa2358ef12a292276f830b1395 100644
|
| --- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc
|
| +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
|
| @@ -2,6 +2,7 @@
|
| * Copyright © 1998-2004 David Turner and Werner Lemberg
|
| * Copyright © 2006 Behdad Esfahbod
|
| * Copyright © 2007,2008,2009 Red Hat, Inc.
|
| + * Copyright © 2012 Google, Inc.
|
| *
|
| * This is part of HarfBuzz, a text shaping library.
|
| *
|
| @@ -24,6 +25,7 @@
|
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
| *
|
| * Red Hat Author(s): Behdad Esfahbod
|
| + * Google Author(s): Behdad Esfahbod
|
| */
|
|
|
| #include "hb-ot-layout-private.hh"
|
| @@ -33,26 +35,45 @@
|
| #include "hb-ot-layout-gpos-table.hh"
|
| #include "hb-ot-maxp-table.hh"
|
|
|
| -
|
| #include <stdlib.h>
|
| #include <string.h>
|
|
|
|
|
| +HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
|
|
|
| hb_ot_layout_t *
|
| _hb_ot_layout_create (hb_face_t *face)
|
| {
|
| - /* TODO Remove this object altogether */
|
| hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
|
| + if (unlikely (!layout))
|
| + return NULL;
|
| +
|
| + layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
|
| + layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
|
| +
|
| + layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
|
| + layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
|
| +
|
| + 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);
|
|
|
| - layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF));
|
| - layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
|
| + layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
|
| + layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
|
|
|
| - layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB));
|
| - layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
|
| + layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
|
| + layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));
|
|
|
| - layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
|
| - layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
|
| + if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
|
| + (layout->gpos_lookup_count && !layout->gpos_digests)))
|
| + {
|
| + _hb_ot_layout_destroy (layout);
|
| + return NULL;
|
| + }
|
| +
|
| + for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
|
| + layout->gsub->add_coverage (&layout->gsub_digests[i], i);
|
| + for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
|
| + layout->gpos->add_coverage (&layout->gpos_digests[i], i);
|
|
|
| return layout;
|
| }
|
| @@ -64,23 +85,29 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
|
| hb_blob_destroy (layout->gsub_blob);
|
| hb_blob_destroy (layout->gpos_blob);
|
|
|
| + free (layout->gsub_digests);
|
| + free (layout->gpos_digests);
|
| +
|
| free (layout);
|
| }
|
|
|
| -static inline const GDEF&
|
| +static inline const OT::GDEF&
|
| _get_gdef (hb_face_t *face)
|
| {
|
| - return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
|
| + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
|
| + return *hb_ot_layout_from_face (face)->gdef;
|
| }
|
| -static inline const GSUB&
|
| +static inline const OT::GSUB&
|
| _get_gsub (hb_face_t *face)
|
| {
|
| - return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
|
| + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
|
| + return *hb_ot_layout_from_face (face)->gsub;
|
| }
|
| -static inline const GPOS&
|
| +static inline const OT::GPOS&
|
| _get_gpos (hb_face_t *face)
|
| {
|
| - return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
|
| + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
|
| + return *hb_ot_layout_from_face (face)->gpos;
|
| }
|
|
|
|
|
| @@ -94,84 +121,6 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face)
|
| return _get_gdef (face).has_glyph_classes ();
|
| }
|
|
|
| -unsigned int
|
| -_hb_ot_layout_get_glyph_property (hb_face_t *face,
|
| - hb_glyph_info_t *info)
|
| -{
|
| - if (!info->props_cache())
|
| - {
|
| - const GDEF &gdef = _get_gdef (face);
|
| - info->props_cache() = gdef.get_glyph_props (info->codepoint);
|
| - }
|
| -
|
| - return info->props_cache();
|
| -}
|
| -
|
| -static hb_bool_t
|
| -_hb_ot_layout_match_properties (hb_face_t *face,
|
| - hb_codepoint_t codepoint,
|
| - unsigned int glyph_props,
|
| - unsigned int lookup_props)
|
| -{
|
| - /* Not covered, if, for example, glyph class is ligature and
|
| - * lookup_props includes LookupFlags::IgnoreLigatures
|
| - */
|
| - if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
|
| - return false;
|
| -
|
| - if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
|
| - {
|
| - /* If using mark filtering sets, the high short of
|
| - * lookup_props has the set index.
|
| - */
|
| - if (lookup_props & LookupFlag::UseMarkFilteringSet)
|
| - return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
|
| -
|
| - /* The second byte of lookup_props has the meaning
|
| - * "ignore marks of attachment type different than
|
| - * the attachment type specified."
|
| - */
|
| - if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
|
| - return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -hb_bool_t
|
| -_hb_ot_layout_check_glyph_property (hb_face_t *face,
|
| - hb_glyph_info_t *ginfo,
|
| - unsigned int lookup_props,
|
| - unsigned int *property_out)
|
| -{
|
| - unsigned int property;
|
| -
|
| - property = _hb_ot_layout_get_glyph_property (face, ginfo);
|
| - (void) (property_out && (*property_out = property));
|
| -
|
| - return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
|
| -}
|
| -
|
| -hb_bool_t
|
| -_hb_ot_layout_skip_mark (hb_face_t *face,
|
| - hb_glyph_info_t *ginfo,
|
| - unsigned int lookup_props,
|
| - unsigned int *property_out)
|
| -{
|
| - unsigned int property;
|
| -
|
| - property = _hb_ot_layout_get_glyph_property (face, ginfo);
|
| - (void) (property_out && (*property_out = property));
|
| -
|
| - /* If it's a mark, skip it we don't accept it. */
|
| - if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
|
| - return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
|
| -
|
| - /* If not a mark, don't skip. */
|
| - return false;
|
| -}
|
| -
|
| -
|
|
|
| unsigned int
|
| hb_ot_layout_get_attach_points (hb_face_t *face,
|
| @@ -194,18 +143,19 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
|
| return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
|
| }
|
|
|
| +
|
| /*
|
| * GSUB/GPOS
|
| */
|
|
|
| -static const GSUBGPOS&
|
| +static const OT::GSUBGPOS&
|
| get_gsubgpos_table (hb_face_t *face,
|
| hb_tag_t table_tag)
|
| {
|
| switch (table_tag) {
|
| case HB_OT_TAG_GSUB: return _get_gsub (face);
|
| case HB_OT_TAG_GPOS: return _get_gpos (face);
|
| - default: return Null(GSUBGPOS);
|
| + default: return OT::Null(OT::GSUBGPOS);
|
| }
|
| }
|
|
|
| @@ -217,7 +167,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
|
| unsigned int *script_count /* IN/OUT */,
|
| hb_tag_t *script_tags /* OUT */)
|
| {
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
| return g.get_script_tags (start_offset, script_count, script_tags);
|
| }
|
| @@ -228,8 +178,8 @@ hb_ot_layout_table_find_script (hb_face_t *face,
|
| hb_tag_t script_tag,
|
| unsigned int *script_index)
|
| {
|
| - ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
| if (g.find_script_index (script_tag, script_index))
|
| return true;
|
| @@ -254,8 +204,8 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
|
| unsigned int *script_index,
|
| hb_tag_t *chosen_script)
|
| {
|
| - ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
| while (*script_tags)
|
| {
|
| @@ -303,7 +253,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
|
| unsigned int *feature_count /* IN/OUT */,
|
| hb_tag_t *feature_tags /* OUT */)
|
| {
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
|
|
| return g.get_feature_tags (start_offset, feature_count, feature_tags);
|
| }
|
| @@ -317,7 +267,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
|
| unsigned int *language_count /* IN/OUT */,
|
| hb_tag_t *language_tags /* OUT */)
|
| {
|
| - const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
| + const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
|
|
| return s.get_lang_sys_tags (start_offset, language_count, language_tags);
|
| }
|
| @@ -329,8 +279,8 @@ hb_ot_layout_script_find_language (hb_face_t *face,
|
| hb_tag_t language_tag,
|
| unsigned int *language_index)
|
| {
|
| - ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
|
| - const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
| + ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
|
| + const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
|
|
| if (s.find_lang_sys_index (language_tag, language_index))
|
| return true;
|
| @@ -350,7 +300,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
|
| unsigned int language_index,
|
| unsigned int *feature_index)
|
| {
|
| - const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
|
| + const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
|
|
|
| if (feature_index) *feature_index = l.get_required_feature_index ();
|
|
|
| @@ -366,8 +316,8 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
|
| unsigned int *feature_count /* IN/OUT */,
|
| unsigned int *feature_indexes /* OUT */)
|
| {
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| - const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
|
|
| return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
|
| }
|
| @@ -381,8 +331,8 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
|
| unsigned int *feature_count /* IN/OUT */,
|
| hb_tag_t *feature_tags /* OUT */)
|
| {
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| - const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
|
|
| ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
|
| unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
|
| @@ -405,9 +355,9 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
|
| hb_tag_t feature_tag,
|
| unsigned int *feature_index)
|
| {
|
| - ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| - const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
| + ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
|
|
| unsigned int num_features = l.get_feature_count ();
|
| for (unsigned int i = 0; i < num_features; i++) {
|
| @@ -431,84 +381,118 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
|
| unsigned int *lookup_count /* IN/OUT */,
|
| unsigned int *lookup_indexes /* OUT */)
|
| {
|
| - const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| - const Feature &f = g.get_feature (feature_index);
|
| + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
| + const OT::Feature &f = g.get_feature (feature_index);
|
|
|
| return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
|
| }
|
|
|
|
|
| /*
|
| - * GSUB
|
| + * OT::GSUB
|
| */
|
|
|
| hb_bool_t
|
| hb_ot_layout_has_substitution (hb_face_t *face)
|
| {
|
| - return &_get_gsub (face) != &Null(GSUB);
|
| + return &_get_gsub (face) != &OT::Null(OT::GSUB);
|
| +}
|
| +
|
| +hb_bool_t
|
| +hb_ot_layout_would_substitute_lookup (hb_face_t *face,
|
| + unsigned int lookup_index,
|
| + const hb_codepoint_t *glyphs,
|
| + unsigned int glyphs_length,
|
| + hb_bool_t zero_context)
|
| +{
|
| + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
|
| + return hb_ot_layout_would_substitute_lookup_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
|
| +}
|
| +
|
| +hb_bool_t
|
| +hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face,
|
| + unsigned int lookup_index,
|
| + const hb_codepoint_t *glyphs,
|
| + unsigned int glyphs_length,
|
| + hb_bool_t zero_context)
|
| +{
|
| + if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
|
| + OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
|
| +
|
| + const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
|
| +
|
| + return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
|
| }
|
|
|
| void
|
| -hb_ot_layout_substitute_start (hb_buffer_t *buffer)
|
| +hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
|
| {
|
| - GSUB::substitute_start (buffer);
|
| + OT::GSUB::substitute_start (font, buffer);
|
| }
|
|
|
| hb_bool_t
|
| -hb_ot_layout_substitute_lookup (hb_face_t *face,
|
| +hb_ot_layout_substitute_lookup (hb_font_t *font,
|
| hb_buffer_t *buffer,
|
| unsigned int lookup_index,
|
| hb_mask_t mask)
|
| {
|
| - hb_apply_context_t c (NULL, face, buffer, mask);
|
| - return _get_gsub (face).substitute_lookup (&c, lookup_index);
|
| + if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
|
| +
|
| + OT::hb_apply_context_t c (font, buffer, mask);
|
| +
|
| + const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
|
| +
|
| + return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
|
| }
|
|
|
| void
|
| -hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED)
|
| +hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
|
| {
|
| - GSUB::substitute_finish (buffer);
|
| + OT::GSUB::substitute_finish (font, buffer);
|
| }
|
|
|
| void
|
| hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
|
| - hb_set_t *glyphs,
|
| - unsigned int lookup_index)
|
| + unsigned int lookup_index,
|
| + hb_set_t *glyphs)
|
| {
|
| - hb_closure_context_t c (face, glyphs);
|
| + OT::hb_closure_context_t c (face, glyphs);
|
| _get_gsub (face).closure_lookup (&c, lookup_index);
|
| }
|
|
|
| /*
|
| - * GPOS
|
| + * OT::GPOS
|
| */
|
|
|
| hb_bool_t
|
| hb_ot_layout_has_positioning (hb_face_t *face)
|
| {
|
| - return &_get_gpos (face) != &Null(GPOS);
|
| + return &_get_gpos (face) != &OT::Null(OT::GPOS);
|
| }
|
|
|
| void
|
| -hb_ot_layout_position_start (hb_buffer_t *buffer)
|
| +hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
|
| {
|
| - GPOS::position_start (buffer);
|
| + OT::GPOS::position_start (font, buffer);
|
| }
|
|
|
| hb_bool_t
|
| -hb_ot_layout_position_lookup (hb_font_t *font,
|
| - hb_buffer_t *buffer,
|
| - unsigned int lookup_index,
|
| - hb_mask_t mask)
|
| +hb_ot_layout_position_lookup (hb_font_t *font,
|
| + hb_buffer_t *buffer,
|
| + unsigned int lookup_index,
|
| + hb_mask_t mask)
|
| {
|
| - hb_apply_context_t c (font, font->face, buffer, mask);
|
| - return _get_gpos (font->face).position_lookup (&c, lookup_index);
|
| + if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
|
| +
|
| + OT::hb_apply_context_t c (font, buffer, mask);
|
| +
|
| + const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
|
| +
|
| + return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
|
| }
|
|
|
| void
|
| -hb_ot_layout_position_finish (hb_buffer_t *buffer)
|
| +hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
|
| {
|
| - GPOS::position_finish (buffer);
|
| + OT::GPOS::position_finish (font, buffer, zero_width_attached_marks);
|
| }
|
| -
|
| -
|
|
|