summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Oshmyan <chortos@inbox.lv>2020-10-25 05:31:56 +0200
committerOleg Oshmyan <chortos@inbox.lv>2022-02-14 20:43:08 +0200
commitc275f0e18037155c9df24e423e1fab0417d0ef21 (patch)
tree15fa95e9e4d19a9b05807459fd7978a347d18a6c
parentc629be7d70548aea282ea4890c51094055ec66e2 (diff)
downloadlibass-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.h5
-rw-r--r--libass/ass_shaper.c33
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);
}