diff options
Diffstat (limited to 'libass')
-rw-r--r-- | libass/ass.c | 1 | ||||
-rw-r--r-- | libass/ass.h | 19 | ||||
-rw-r--r-- | libass/ass_render.c | 2 | ||||
-rw-r--r-- | libass/ass_shaper.c | 49 | ||||
-rw-r--r-- | libass/ass_shaper.h | 1 |
5 files changed, 61 insertions, 11 deletions
diff --git a/libass/ass.c b/libass/ass.c index 79a3532..ba60eda 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -1543,6 +1543,7 @@ int ass_track_set_feature(ASS_Track *track, ASS_Feature feature, int enable) #ifdef USE_FRIBIDI_EX_API FEATURE_MASK(ASS_FEATURE_BIDI_BRACKETS) | #endif + FEATURE_MASK(ASS_FEATURE_WHOLE_TEXT_LAYOUT) | 0; uint32_t requested = 0; diff --git a/libass/ass.h b/libass/ass.h index 10d5595..ef3ff23 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -238,6 +238,25 @@ typedef enum { */ ASS_FEATURE_BIDI_BRACKETS, + /** + * 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. + * 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. + * + * This is incompatible with VSFilter and disabled by default. + * + * libass extensions to ASS such as Encoding -1 can cause individual + * events to be always processed as if this feature is enabled. + */ + ASS_FEATURE_WHOLE_TEXT_LAYOUT, + // New enum values can be added here in new ABI-compatible library releases. } ASS_Feature; diff --git a/libass/ass_render.c b/libass/ass_render.c index 5a73c35..6e9aef2 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -2885,6 +2885,8 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, ass_shaper_set_bidi_brackets(render_priv->shaper, track->parser_priv->feature_flags & FEATURE_MASK(ASS_FEATURE_BIDI_BRACKETS)); #endif + ass_shaper_set_whole_text_layout(render_priv->shaper, + track->parser_priv->feature_flags & FEATURE_MASK(ASS_FEATURE_WHOLE_TEXT_LAYOUT)); // PAR correction double par = render_priv->settings.par; diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index f95dd58..b05a051 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -39,6 +39,12 @@ enum { }; #define NUM_FEATURES 5 +enum { + WHOLE_TEXT_LAYOUT_OFF, + WHOLE_TEXT_LAYOUT_IMPLICIT, + WHOLE_TEXT_LAYOUT_EXPLICIT, +}; + struct ass_shaper { ASS_ShapingLevel shaping_level; @@ -62,6 +68,8 @@ struct ass_shaper { FriBidiBracketType *btypes; bool bidi_brackets; #endif + + char whole_text_layout; }; struct ass_shaper_metrics_data { @@ -895,6 +903,10 @@ void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir) { shaper->base_direction = dir; + + if (shaper->whole_text_layout != WHOLE_TEXT_LAYOUT_EXPLICIT) + shaper->whole_text_layout = dir == FRIBIDI_PAR_ON ? + WHOLE_TEXT_LAYOUT_IMPLICIT : WHOLE_TEXT_LAYOUT_OFF; } /** @@ -929,6 +941,14 @@ void ass_shaper_set_bidi_brackets(ASS_Shaper *shaper, bool match_brackets) } #endif +void ass_shaper_set_whole_text_layout(ASS_Shaper *shaper, bool enable) +{ + shaper->whole_text_layout = enable ? + WHOLE_TEXT_LAYOUT_EXPLICIT : + shaper->base_direction == FRIBIDI_PAR_ON ? + WHOLE_TEXT_LAYOUT_IMPLICIT : WHOLE_TEXT_LAYOUT_OFF; +} + /** * \brief Shape an event's text. Calculates directional runs and shapes them. * \param text_info event's text @@ -948,7 +968,8 @@ bool ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info) for (i = 0; i < text_info->length; i++) { shaper->event_text[i] = glyphs[i].symbol; // embedding levels should be calculated paragraph by paragraph - if (glyphs[i].symbol == '\n' || i == text_info->length - 1) { + if (glyphs[i].symbol == '\n' || i == text_info->length - 1 || + (!shaper->whole_text_layout && glyphs[i + 1].starts_new_run)) { dir = shaper->base_direction; fribidi_get_bidi_types(shaper->event_text + last_break, i - last_break + 1, shaper->ctypes + last_break); @@ -1041,17 +1062,23 @@ FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info) for (i = 0; i < text_info->length; i++) shaper->cmap[i] = i; - // Create reorder map line-by-line - for (i = 0; i < text_info->n_lines; i++) { - LineInfo *line = text_info->lines + i; - FriBidiParType dir = FRIBIDI_PAR_ON; + // Create reorder map line-by-line or run-by-run + int last_break = 0; + GlyphInfo *glyphs = text_info->glyphs; + for (i = 0; i < text_info->length; i++) { + if (i == text_info->length - 1 || glyphs[i + 1].linebreak || + (!shaper->whole_text_layout && glyphs[i + 1].starts_new_run)) { + FriBidiParType dir = FRIBIDI_PAR_ON; + + ret = fribidi_reorder_line(0, + shaper->ctypes, i - last_break + 1, last_break, dir, + shaper->emblevels, NULL, + shaper->cmap); + if (ret == 0) + return NULL; - ret = fribidi_reorder_line(0, - shaper->ctypes + line->offset, line->len, 0, dir, - shaper->emblevels + line->offset, NULL, - shaper->cmap + line->offset); - if (ret == 0) - return NULL; + last_break = i + 1; + } } return shaper->cmap; diff --git a/libass/ass_shaper.h b/libass/ass_shaper.h index 70bec9a..66bfed0 100644 --- a/libass/ass_shaper.h +++ b/libass/ass_shaper.h @@ -42,6 +42,7 @@ void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level); #ifdef USE_FRIBIDI_EX_API void ass_shaper_set_bidi_brackets(ASS_Shaper *shaper, bool match_brackets); #endif +void ass_shaper_set_whole_text_layout(ASS_Shaper *shaper, bool enable); bool ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info); void ass_shaper_cleanup(ASS_Shaper *shaper, TextInfo *text_info); FriBidiStrIndex *ass_shaper_reorder(ASS_Shaper *shaper, TextInfo *text_info); |