diff options
author | Grigori Goronzy <greg@chown.ath.cx> | 2014-01-26 03:30:45 +0100 |
---|---|---|
committer | Grigori Goronzy <greg@chown.ath.cx> | 2014-01-29 00:58:51 +0100 |
commit | 337793ee8246b44ccedf7872234bf8937608bfcd (patch) | |
tree | bb7e3940f7f3a5a1b48836fa0a23a4fec3818265 /libass/ass_shaper.c | |
parent | 39948e8f62a0d300ed262f6b0398ec9689b9f724 (diff) | |
download | libass-337793ee8246b44ccedf7872234bf8937608bfcd.tar.bz2 libass-337793ee8246b44ccedf7872234bf8937608bfcd.tar.xz |
shaper: rewrite and simplify harfbuzz shaping
Rewrite the core of the harfbuzz shaping function. Gets rid of the
MAX_RUNS limit of runs per line and reuses a single hb_buffer_t,
which should be more efficient.
Diffstat (limited to 'libass/ass_shaper.c')
-rw-r--r-- | libass/ass_shaper.c | 145 |
1 files changed, 72 insertions, 73 deletions
diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index 6aca5f5e..0e818247 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -24,8 +24,6 @@ #include "ass_parse.h" #include "ass_cache.h" -#define MAX_RUNS 50 - #ifdef CONFIG_HARFBUZZ #include <hb-ft.h> enum { @@ -526,91 +524,92 @@ hb_shaper_get_run_language(ASS_Shaper *shaper, hb_script_t script) } /** + * \brief Feed a run of shaped characters into the GlyphInfo array. + * + * \param glyphs GlyphInfo array + * \param buf buffer of shaped run + * \param offset offset into GlyphInfo array + */ +static void +shape_harfbuzz_process_run(GlyphInfo *glyphs, hb_buffer_t *buf, int offset) +{ + int j; + int num_glyphs = hb_buffer_get_length(buf); + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, NULL); + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buf, NULL); + + for (j = 0; j < num_glyphs; j++) { + unsigned idx = glyph_info[j].cluster + offset; + GlyphInfo *info = glyphs + idx; + GlyphInfo *root = info; + + // if we have more than one glyph per cluster, allocate a new one + // and attach to the root glyph + if (info->skip == 0) { + while (info->next) + info = info->next; + info->next = malloc(sizeof(GlyphInfo)); + memcpy(info->next, info, sizeof(GlyphInfo)); + info = info->next; + info->next = NULL; + } + + // set position and advance + info->skip = 0; + info->glyph_index = glyph_info[j].codepoint; + info->offset.x = pos[j].x_offset * info->scale_x; + info->offset.y = -pos[j].y_offset * info->scale_y; + info->advance.x = pos[j].x_advance * info->scale_x; + info->advance.y = -pos[j].y_advance * info->scale_y; + + // accumulate advance in the root glyph + root->cluster_advance.x += info->advance.x; + root->cluster_advance.y += info->advance.y; + } +} + +/** * \brief Shape event text with HarfBuzz. Full OpenType shaping. * \param glyphs glyph clusters * \param len number of clusters */ static void shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) { - int i, j; - int run = 0; - struct { - int offset; - int end; - hb_buffer_t *buf; - hb_font_t *font; - } runs[MAX_RUNS]; - - for (i = 0; i < len && run < MAX_RUNS; i++, run++) { - // get length and level of the current run - int k = i; - int level = glyphs[i].shape_run_id; - int direction = shaper->emblevels[k] % 2; - hb_script_t script = glyphs[i].script; - while (i < (len - 1) && level == glyphs[i+1].shape_run_id) - i++; - runs[run].offset = k; - runs[run].end = i; - runs[run].buf = hb_buffer_create(); - runs[run].font = get_hb_font(shaper, glyphs + k); - set_run_features(shaper, glyphs + k); - hb_buffer_pre_allocate(runs[run].buf, i - k + 1); - hb_buffer_set_direction(runs[run].buf, direction ? HB_DIRECTION_RTL : - HB_DIRECTION_LTR); - hb_buffer_set_language(runs[run].buf, - hb_shaper_get_run_language(shaper, script)); - hb_buffer_set_script(runs[run].buf, script); - hb_buffer_add_utf32(runs[run].buf, shaper->event_text + k, i - k + 1, - 0, i - k + 1); - hb_shape(runs[run].font, runs[run].buf, shaper->features, - shaper->n_features); - } + int i; + hb_buffer_t *buf = hb_buffer_create(); + hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; // Initialize: skip all glyphs, this is undone later as needed for (i = 0; i < len; i++) glyphs[i].skip = 1; - // Update glyph indexes, positions and advances from the shaped runs - for (i = 0; i < run; i++) { - int num_glyphs = hb_buffer_get_length(runs[i].buf); - hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(runs[i].buf, NULL); - hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(runs[i].buf, NULL); - - for (j = 0; j < num_glyphs; j++) { - int idx = glyph_info[j].cluster + runs[i].offset; - GlyphInfo *info = glyphs + idx; - GlyphInfo *root = info; - - // if we have more than one glyph per cluster, allocate a new one - // and attach to the root glyph - if (info->skip == 0) { - while (info->next) - info = info->next; - info->next = malloc(sizeof(GlyphInfo)); - memcpy(info->next, info, sizeof(GlyphInfo)); - info = info->next; - info->next = NULL; - } - - // set position and advance - info->skip = 0; - info->glyph_index = glyph_info[j].codepoint; - info->offset.x = pos[j].x_offset * info->scale_x; - info->offset.y = -pos[j].y_offset * info->scale_y; - info->advance.x = pos[j].x_advance * info->scale_x; - info->advance.y = -pos[j].y_advance * info->scale_y; - - // accumulate advance in the root glyph - root->cluster_advance.x += info->advance.x; - root->cluster_advance.y += info->advance.y; - } - } + for (i = 0; i < len; i++) { + int offset = i; + hb_font_t *font = get_hb_font(shaper, glyphs + offset); + int level = glyphs[offset].shape_run_id; + int direction = shaper->emblevels[offset] % 2; + + // advance in text until end of run + while (i < (len - 1) && level == glyphs[i+1].shape_run_id) + i++; + + hb_buffer_pre_allocate(buf, i - offset + 1); + hb_buffer_add_utf32(buf, shaper->event_text + offset, i - offset + 1, + 0, i - offset + 1); + + props.direction = direction ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; + props.script = glyphs[offset].script; + props.language = hb_shaper_get_run_language(shaper, props.script); + hb_buffer_set_segment_properties(buf, &props); + + set_run_features(shaper, glyphs + offset); + hb_shape(font, buf, shaper->features, shaper->n_features); - // Free runs and associated data - for (i = 0; i < run; i++) { - hb_buffer_destroy(runs[i].buf); + shape_harfbuzz_process_run(glyphs, buf, offset); + hb_buffer_reset(buf); } + hb_buffer_destroy(buf); } /** |