diff options
author | Oleg Oshmyan <chortos@inbox.lv> | 2020-10-25 05:31:56 +0200 |
---|---|---|
committer | Oleg Oshmyan <chortos@inbox.lv> | 2022-02-14 20:43:08 +0200 |
commit | c275f0e18037155c9df24e423e1fab0417d0ef21 (patch) | |
tree | 15fa95e9e4d19a9b05807459fd7978a347d18a6c | |
parent | c629be7d70548aea282ea4890c51094055ec66e2 (diff) | |
download | libass-c275f0e18037155c9df24e423e1fab0417d0ef21.tar.bz2 libass-c275f0e18037155c9df24e423e1fab0417d0ef21.tar.xz |
WHOLE_TEXT_LAYOUT: give HarfBuzz context to shape correctly across runs
When WHOLE_TEXT_LAYOUT is disabled, keep calling HarfBuzz with no context at
all. It might seem sensible to give it the whole VSFilter-run as context so
it could shape Arabic correctly across font fallback in case of weird fonts,
but it seems that Uniscribe doesn't behave like this in VSFilter.
For testing that, I created a font with only two glyphs: an isolated ain
and a medial ain; and a GSUB medi lookup that links them together.
Setting \fnMyTestFont on an Arabic word with a medial ain, libass
with WHOLE_TEXT_LAYOUT (i. e. HarfBuzz with context) showed the medial
shape, but VSFilter (i. e. Uniscribe) showed the isolated shape.
BorderStyle 3 confirmed that VSFilter was treating the string
as a single run and therefore passing it to GDI/Uniscribe as a whole.
-rw-r--r-- | libass/ass.h | 5 | ||||
-rw-r--r-- | libass/ass_shaper.c | 33 |
2 files changed, 23 insertions, 15 deletions
diff --git a/libass/ass.h b/libass/ass.h index ef3ff23..6f8a1bd 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -242,13 +242,14 @@ typedef enum { * When this feature is disabled, text is split into VSFilter-compatible * segments and text in each segment is processed in isolation. * Notably, this includes running the Unicode Bidirectional - * Algorithm within each run separately. + * Algorithm and shaping the text within each run separately. * The individual runs are then laid out left-to-right, * even if they contain right-to-left text. * * When this feature is enabled, each event's text is processed as a whole * (as far as possible). In particular, the Unicode Bidirectional - * Algorithm is run on the whole text. + * Algorithm is run on the whole text, and text is shaped across + * override tags. * * This is incompatible with VSFilter and disabled by default. * diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index b05a051..0c97ccc 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -703,19 +703,25 @@ static bool shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) level == shaper->emblevels[i + 1]) i++; - int lead_context = 0, trail_context = 0; - if (offset > 0 && !glyphs[offset].starts_new_run && - is_shaping_control(glyphs[offset - 1].symbol)) - lead_context = 1; - if (i < (len - 1) && !glyphs[i + 1].starts_new_run && - is_shaping_control(glyphs[i + 1].symbol)) - trail_context = 1; - hb_buffer_pre_allocate(buf, i - offset + 1); - hb_buffer_add_utf32(buf, - shaper->event_text + offset - lead_context, - i - offset + 1 + lead_context + trail_context, - lead_context, i - offset + 1); + + int lead_context = 0, trail_context = 0; + if (shaper->whole_text_layout) { + hb_buffer_add_utf32(buf, shaper->event_text, len, + offset, i - offset + 1); + } else { + if (offset > 0 && !glyphs[offset].starts_new_run && + is_shaping_control(glyphs[offset - 1].symbol)) + lead_context = 1; + if (i < (len - 1) && !glyphs[i + 1].starts_new_run && + is_shaping_control(glyphs[i + 1].symbol)) + trail_context = 1; + + hb_buffer_add_utf32(buf, + shaper->event_text + offset - lead_context, + i - offset + 1 + lead_context + trail_context, + lead_context, i - offset + 1); + } props.direction = FRIBIDI_LEVEL_IS_RTL(level) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; @@ -726,7 +732,8 @@ static bool shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) set_run_features(shaper, glyphs + offset); hb_shape(font, buf, shaper->features, shaper->n_features); - shape_harfbuzz_process_run(glyphs, buf, offset - lead_context); + shape_harfbuzz_process_run(glyphs, buf, + shaper->whole_text_layout ? 0 : offset - lead_context); hb_buffer_reset(buf); } |