* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2006 Behdad Esfahbod
* Copyright © 2007,2008,2009 Red Hat, Inc.
- * Copyright © 2012 Google, Inc.
+ * Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-layout-jstf-table.hh"
+
+#include "hb-ot-map-private.hh"
#include <stdlib.h>
#include <string.h>
layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
- 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->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+ layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
- if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
- (layout->gpos_lookup_count && !layout->gpos_digests)))
+ if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
+ (layout->gpos_lookup_count && !layout->gpos_accels)))
{
_hb_ot_layout_destroy (layout);
return NULL;
}
for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
- layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]);
+ layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
- layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]);
+ layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
return layout;
}
void
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
{
+ for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+ layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
+ for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+ layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
+
+ free (layout->gsub_accels);
+ free (layout->gpos_accels);
+
hb_blob_destroy (layout->gdef_blob);
hb_blob_destroy (layout->gsub_blob);
hb_blob_destroy (layout->gpos_blob);
- free (layout->gsub_digests);
- free (layout->gpos_digests);
-
free (layout);
}
unsigned int language_index,
unsigned int *feature_index)
{
- const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
+ return hb_ot_layout_language_get_required_feature (face,
+ table_tag,
+ script_index,
+ language_index,
+ feature_index,
+ NULL);
+}
- if (feature_index) *feature_index = l.get_required_feature_index ();
+hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int *feature_index,
+ hb_tag_t *feature_tag)
+{
+ 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 index = l.get_required_feature_index ();
+ if (feature_index) *feature_index = index;
+ if (feature_tag) *feature_tag = g.get_feature_tag (index);
return l.has_required_feature ();
}
return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
}
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t *face,
+ hb_tag_t table_tag)
+{
+ switch (table_tag)
+ {
+ case HB_OT_TAG_GSUB:
+ {
+ return hb_ot_layout_from_face (face)->gsub_lookup_count;
+ }
+ case HB_OT_TAG_GPOS:
+ {
+ return hb_ot_layout_from_face (face)->gpos_lookup_count;
+ }
+ }
+ return 0;
+}
+
static void
_hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */)
{
- unsigned int required_feature_index;
- if (hb_ot_layout_language_get_required_feature_index (face,
- table_tag,
- script_index,
- language_index,
- &required_feature_index))
- _hb_ot_layout_collect_lookups_lookups (face,
- table_tag,
- required_feature_index,
- lookup_indexes);
-
if (!features)
{
+ unsigned int required_feature_index;
+ if (hb_ot_layout_language_get_required_feature (face,
+ table_tag,
+ script_index,
+ language_index,
+ &required_feature_index,
+ NULL))
+ _hb_ot_layout_collect_lookups_lookups (face,
+ table_tag,
+ required_feature_index,
+ lookup_indexes);
+
/* All features */
unsigned int feature_indices[32];
unsigned int offset, len;
case HB_OT_TAG_GSUB:
{
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
- l.collect_glyphs_lookup (&c);
+ l.collect_glyphs (&c);
return;
}
case HB_OT_TAG_GPOS:
{
const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
- l.collect_glyphs_lookup (&c);
+ l.collect_glyphs (&c);
return;
}
}
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]);
+ return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
}
void
OT::GSUB::substitute_start (font, buffer);
}
-hb_bool_t
-hb_ot_layout_substitute_lookup (hb_font_t *font,
- hb_buffer_t *buffer,
- unsigned int lookup_index,
- hb_mask_t mask)
-{
- 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_font_t *font, hb_buffer_t *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)
-{
- 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_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
+hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
{
- OT::GPOS::position_finish (font, buffer, zero_width_attached_marks);
+ OT::GPOS::position_finish (font, buffer);
}
hb_bool_t
return false;
}
+
+
+/*
+ * Parts of different types are implemented here such that they have direct
+ * access to GSUB/GPOS lookups.
+ */
+
+
+struct GSUBProxy
+{
+ static const unsigned int table_index = 0;
+ static const bool inplace = false;
+ typedef OT::SubstLookup Lookup;
+
+ GSUBProxy (hb_face_t *face) :
+ table (*hb_ot_layout_from_face (face)->gsub),
+ accels (hb_ot_layout_from_face (face)->gsub_accels) {}
+
+ const OT::GSUB &table;
+ const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+struct GPOSProxy
+{
+ static const unsigned int table_index = 1;
+ static const bool inplace = true;
+ typedef OT::PosLookup Lookup;
+
+ GPOSProxy (hb_face_t *face) :
+ table (*hb_ot_layout_from_face (face)->gpos),
+ accels (hb_ot_layout_from_face (face)->gpos_accels) {}
+
+ const OT::GPOS &table;
+ const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+
+template <typename Lookup>
+static inline bool apply_once (OT::hb_apply_context_t *c,
+ const Lookup &lookup)
+{
+ if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
+ return false;
+ return lookup.dispatch (c);
+}
+
+template <typename Proxy>
+static inline bool
+apply_string (OT::hb_apply_context_t *c,
+ const typename Proxy::Lookup &lookup,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ bool ret = false;
+ hb_buffer_t *buffer = c->buffer;
+
+ if (unlikely (!buffer->len || !c->lookup_mask))
+ return false;
+
+ c->set_lookup (lookup);
+
+ if (likely (!lookup.is_reverse ()))
+ {
+ /* in/out forward substitution/positioning */
+ if (Proxy::table_index == 0)
+ buffer->clear_output ();
+ buffer->idx = 0;
+
+ while (buffer->idx < buffer->len)
+ {
+ if (accel.digest.may_have (buffer->cur().codepoint) &&
+ (buffer->cur().mask & c->lookup_mask) &&
+ apply_once (c, lookup))
+ ret = true;
+ else
+ buffer->next_glyph ();
+ }
+ if (ret)
+ {
+ if (!Proxy::inplace)
+ buffer->swap_buffers ();
+ else
+ assert (!buffer->has_separate_output ());
+ }
+ }
+ else
+ {
+ /* in-place backward substitution/positioning */
+ if (Proxy::table_index == 0)
+ buffer->remove_output ();
+ buffer->idx = buffer->len - 1;
+ do
+ {
+ if (accel.digest.may_have (buffer->cur().codepoint) &&
+ (buffer->cur().mask & c->lookup_mask) &&
+ apply_once (c, lookup))
+ ret = true;
+ /* The reverse lookup doesn't "advance" cursor (for good reason). */
+ buffer->idx--;
+
+ }
+ while ((int) buffer->idx >= 0);
+ }
+
+ return ret;
+}
+
+template <typename Proxy>
+inline void hb_ot_map_t::apply (const Proxy &proxy,
+ const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer) const
+{
+ const unsigned int table_index = proxy.table_index;
+ unsigned int i = 0;
+ OT::hb_apply_context_t c (table_index, font, buffer);
+ c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+
+ for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
+ const stage_map_t *stage = &stages[table_index][stage_index];
+ for (; i < stage->last_lookup; i++)
+ {
+ unsigned int lookup_index = lookups[table_index][i].index;
+ c.set_lookup_mask (lookups[table_index][i].mask);
+ c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+ apply_string<Proxy> (&c,
+ proxy.table.get_lookup (lookup_index),
+ proxy.accels[lookup_index]);
+ }
+
+ if (stage->pause_func)
+ {
+ buffer->clear_output ();
+ stage->pause_func (plan, font, buffer);
+ }
+ }
+}
+
+void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+ GSUBProxy proxy (font->face);
+ apply (proxy, plan, font, buffer);
+}
+
+void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+ GPOSProxy proxy (font->face);
+ apply (proxy, plan, font, buffer);
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+ const OT::SubstLookup &lookup,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ apply_string<GSUBProxy> (c, lookup, accel);
+}