[GSUB/GPOS] Use Coverage digests as gatekeeper

Gives me a good 10% speedup for the Devanagari test case.  Less so
for less lookup-intensive tests.

For the Devanagari test case, the false positive rate of the GSUB digest
is 4%.
This commit is contained in:
Behdad Esfahbod 2012-08-01 21:46:36 -04:00
parent a878c58a8f
commit 1336ecdf8e
5 changed files with 56 additions and 50 deletions

View File

@ -1551,27 +1551,15 @@ struct PosLookup : Lookup
c->buffer->idx = 0; c->buffer->idx = 0;
/* Fast path for lookups with one coverage only (which is most). */ while (c->buffer->idx < c->buffer->len)
const Coverage *coverage = get_coverage (); {
if (coverage) if ((c->buffer->cur().mask & c->lookup_mask) &&
while (c->buffer->idx < c->buffer->len) c->digest->may_have (c->buffer->cur().codepoint) &&
{ apply_once (c))
if ((c->buffer->cur().mask & c->lookup_mask) && ret = true;
coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED && else
apply_once (c)) c->buffer->idx++;
ret = true; }
else
c->buffer->idx++;
}
else
while (c->buffer->idx < c->buffer->len)
{
if ((c->buffer->cur().mask & c->lookup_mask) &&
apply_once (c))
ret = true;
else
c->buffer->idx++;
}
return ret; return ret;
} }

View File

@ -1219,28 +1219,15 @@ struct SubstLookup : Lookup
c->buffer->clear_output (); c->buffer->clear_output ();
c->buffer->idx = 0; c->buffer->idx = 0;
/* Fast path for lookups with one coverage only (which is most). */ while (c->buffer->idx < c->buffer->len)
const Coverage *coverage = get_coverage (); {
if (coverage) if ((c->buffer->cur().mask & c->lookup_mask) &&
while (c->buffer->idx < c->buffer->len) c->digest->may_have (c->buffer->cur().codepoint) &&
{ apply_once (c))
if ((c->buffer->cur().mask & c->lookup_mask) && ret = true;
coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED && else
apply_once (c)) c->buffer->next_glyph ();
ret = true; }
else
c->buffer->next_glyph ();
}
else
while (c->buffer->idx < c->buffer->len)
{
if ((c->buffer->cur().mask & c->lookup_mask) &&
apply_once (c))
ret = true;
else
c->buffer->next_glyph ();
}
if (ret) if (ret)
c->buffer->swap_buffers (); c->buffer->swap_buffers ();
} }
@ -1250,7 +1237,9 @@ struct SubstLookup : Lookup
c->buffer->idx = c->buffer->len - 1; c->buffer->idx = c->buffer->len - 1;
do do
{ {
if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) if ((c->buffer->cur().mask & c->lookup_mask) &&
c->digest->may_have (c->buffer->cur().codepoint) &&
apply_once (c))
ret = true; ret = true;
else else
c->buffer->idx--; c->buffer->idx--;

View File

@ -31,6 +31,7 @@
#include "hb-buffer-private.hh" #include "hb-buffer-private.hh"
#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gdef-table.hh"
#include "hb-set-private.hh"
@ -109,12 +110,14 @@ struct hb_apply_context_t
unsigned int debug_depth; unsigned int debug_depth;
const GDEF &gdef; const GDEF &gdef;
bool has_glyph_classes; bool has_glyph_classes;
const hb_set_digest_t *digest;
hb_apply_context_t (hb_font_t *font_, hb_apply_context_t (hb_font_t *font_,
hb_face_t *face_, hb_face_t *face_,
hb_buffer_t *buffer_, hb_buffer_t *buffer_,
hb_mask_t lookup_mask_) : hb_mask_t lookup_mask_,
const hb_set_digest_t *digest_) :
font (font_), face (face_), buffer (buffer_), font (font_), face (face_), buffer (buffer_),
direction (buffer_->props.direction), direction (buffer_->props.direction),
lookup_mask (lookup_mask_), lookup_mask (lookup_mask_),
@ -123,7 +126,8 @@ struct hb_apply_context_t
gdef (hb_ot_layout_from_face (face_) && gdef (hb_ot_layout_from_face (face_) &&
!HB_SHAPER_DATA_IS_INVALID (hb_ot_layout_from_face (face_)) ? !HB_SHAPER_DATA_IS_INVALID (hb_ot_layout_from_face (face_)) ?
*hb_ot_layout_from_face (face_)->gdef : Null(GDEF)), *hb_ot_layout_from_face (face_)->gdef : Null(GDEF)),
has_glyph_classes (gdef.has_glyph_classes ()) {} has_glyph_classes (gdef.has_glyph_classes ()),
digest (digest_) {}
void set_lookup (const Lookup &l) { void set_lookup (const Lookup &l) {
lookup_props = l.get_props (); lookup_props = l.get_props ();

View File

@ -35,6 +35,7 @@
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-buffer-private.hh" #include "hb-buffer-private.hh"
#include "hb-set-private.hh"
/* buffer var allocations, used during the GSUB/GPOS processing */ /* buffer var allocations, used during the GSUB/GPOS processing */
@ -168,6 +169,9 @@ struct hb_ot_layout_t
const struct GDEF *gdef; const struct GDEF *gdef;
const struct GSUB *gsub; const struct GSUB *gsub;
const struct GPOS *gpos; const struct GPOS *gpos;
hb_set_digest_t *gsub_digests;
hb_set_digest_t *gpos_digests;
}; };

View File

@ -58,6 +58,24 @@ _hb_ot_layout_create (hb_face_t *face)
layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS)); layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob); layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_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));
if (unlikely ((layout->gsub->get_lookup_count() && !layout->gsub_digests) ||
(layout->gpos->get_lookup_count() && !layout->gpos_digests)))
{
_hb_ot_layout_destroy (layout);
return NULL;
}
unsigned int count;
count = layout->gsub->get_lookup_count();
for (unsigned int i = 0; i < count; i++)
layout->gsub->add_coverage (&layout->gsub_digests[i], i);
count = layout->gpos->get_lookup_count();
for (unsigned int i = 0; i < count; i++)
layout->gpos->add_coverage (&layout->gpos_digests[i], i);
return layout; return layout;
} }
@ -68,6 +86,9 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
hb_blob_destroy (layout->gsub_blob); hb_blob_destroy (layout->gsub_blob);
hb_blob_destroy (layout->gpos_blob); hb_blob_destroy (layout->gpos_blob);
free (layout->gsub_digests);
free (layout->gpos_digests);
free (layout); free (layout);
} }
@ -412,7 +433,7 @@ hb_ot_layout_substitute_lookup (hb_face_t *face,
unsigned int lookup_index, unsigned int lookup_index,
hb_mask_t mask) hb_mask_t mask)
{ {
hb_apply_context_t c (NULL, face, buffer, mask); hb_apply_context_t c (NULL, face, buffer, mask, NULL);
return _get_gsub (face).substitute_lookup (&c, lookup_index); return _get_gsub (face).substitute_lookup (&c, lookup_index);
} }
@ -422,7 +443,7 @@ hb_ot_layout_substitute_lookup_fast (hb_face_t *face,
unsigned int lookup_index, unsigned int lookup_index,
hb_mask_t mask) hb_mask_t mask)
{ {
hb_apply_context_t c (NULL, face, buffer, mask); hb_apply_context_t c (NULL, face, buffer, mask, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
return hb_ot_layout_from_face (face)->gsub->substitute_lookup (&c, lookup_index); return hb_ot_layout_from_face (face)->gsub->substitute_lookup (&c, lookup_index);
} }
@ -463,7 +484,7 @@ hb_ot_layout_position_lookup (hb_font_t *font,
unsigned int lookup_index, unsigned int lookup_index,
hb_mask_t mask) hb_mask_t mask)
{ {
hb_apply_context_t c (font, font->face, buffer, mask); hb_apply_context_t c (font, font->face, buffer, mask, NULL);
return _get_gpos (font->face).position_lookup (&c, lookup_index); return _get_gpos (font->face).position_lookup (&c, lookup_index);
} }
@ -473,7 +494,7 @@ hb_ot_layout_position_lookup_fast (hb_font_t *font,
unsigned int lookup_index, unsigned int lookup_index,
hb_mask_t mask) hb_mask_t mask)
{ {
hb_apply_context_t c (font, font->face, buffer, mask); hb_apply_context_t c (font, font->face, buffer, mask, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
return hb_ot_layout_from_face (font->face)->gpos->position_lookup (&c, lookup_index); return hb_ot_layout_from_face (font->face)->gpos->position_lookup (&c, lookup_index);
} }