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); |
} |
- |
- |