From 66dba8dd21bbf81b25b26e2556c404006f80a43c Mon Sep 17 00:00:00 2001 From: Oleg Oshmyan Date: Tue, 14 Jul 2020 00:38:43 +0300 Subject: Disable bidi bracket matching unless enabled via ASS_Feature Bracket matching is incompatible with VSFilter (even on modern Windows), so disable it by default. But as it's generally a good thing (and 100% more compliant with current Unicode), keep it available as an ASS_Feature. It can be toggled individually or enabled as part of the catch-all ASS_FEATURE_INCOMPATIBLE_EXTENSIONS feature. If libass is compiled against FriBidi older than 1.0, bracket matching is impossible. Signal this at runtime by failing to recognize the ASS_FEATURE_BIDI_BRACKETS feature. This way, clients who want to use bracket matching can set the feature without any compile-time checks for FriBidi and can be freely linked against libass that is itself compiled against any version of FriBidi; and yet they can detect at runtime whether the feature is actually enabled. Fixes https://github.com/libass/libass/issues/374. --- libass/ass.c | 7 ++++++- libass/ass.h | 15 ++++++++++++++- libass/ass_priv.h | 9 +++++++-- libass/ass_render.c | 5 +++++ libass/ass_shaper.c | 33 +++++++++++++++++++++------------ libass/ass_shaper.h | 7 +++++++ 6 files changed, 60 insertions(+), 16 deletions(-) diff --git a/libass/ass.c b/libass/ass.c index 13cfea5..811a9a7 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -36,6 +36,7 @@ #include "ass_utils.h" #include "ass_library.h" #include "ass_priv.h" +#include "ass_shaper.h" #include "ass_string.h" #define ass_atof(STR) (ass_strtod((STR),NULL)) @@ -1468,7 +1469,11 @@ int ass_track_set_feature(ASS_Track *track, ASS_Feature feature, int enable) { switch (feature) { case ASS_FEATURE_INCOMPATIBLE_EXTENSIONS: - track->parser_priv->enable_extensions = !!enable; + //-fallthrough +#ifdef USE_FRIBIDI_EX_API + case ASS_FEATURE_BIDI_BRACKETS: + track->parser_priv->bidi_brackets = !!enable; +#endif return 0; default: return -1; diff --git a/libass/ass.h b/libass/ass.h index 35aeeb7..db67ed2 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -24,7 +24,7 @@ #include #include "ass_types.h" -#define LIBASS_VERSION 0x01400001 +#define LIBASS_VERSION 0x01400002 #ifdef __cplusplus extern "C" { @@ -209,6 +209,19 @@ typedef enum { */ ASS_FEATURE_INCOMPATIBLE_EXTENSIONS, + /** + * Match bracket pairs in bidirectional text according to the revised + * Unicode Bidirectional Algorithm introduced in Unicode 6.3. + * This is incompatible with VSFilter and disabled by default. + * + * (Directional isolates, also introduced in Unicode 6.3, + * are unconditionally processed when FriBidi is new enough.) + * + * This feature may be unavailable at runtime (ass_track_set_feature + * may return -1) if libass was compiled against old FriBidi. + */ + ASS_FEATURE_BIDI_BRACKETS, + // New enum values can be added here in new ABI-compatible library releases. } ASS_Feature; diff --git a/libass/ass_priv.h b/libass/ass_priv.h index 3ee2b45..98b2711 100644 --- a/libass/ass_priv.h +++ b/libass/ass_priv.h @@ -19,8 +19,11 @@ #ifndef LIBASS_PRIV_H #define LIBASS_PRIV_H +#include #include +#include "ass_shaper.h" + typedef enum { PST_UNKNOWN = 0, PST_INFO, @@ -55,10 +58,12 @@ struct parser_priv { int read_order_elems; // size in uint32_t units of read_order_bitmap int check_readorder; - int enable_extensions; - // tracks [Script Info] headers set by the script uint32_t header_flags; + +#ifdef USE_FRIBIDI_EX_API + bool bidi_brackets; +#endif }; #endif /* LIBASS_PRIV_H */ diff --git a/libass/ass_render.c b/libass/ass_render.c index 7bc9554..28b6461 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -27,6 +27,7 @@ #include "ass_outline.h" #include "ass_render.h" #include "ass_parse.h" +#include "ass_priv.h" #include "ass_shaper.h" #define MAX_GLYPHS_INITIAL 1024 @@ -2833,6 +2834,10 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, ass_shaper_set_kerning(render_priv->shaper, track->Kerning); ass_shaper_set_language(render_priv->shaper, track->Language); ass_shaper_set_level(render_priv->shaper, render_priv->settings.shaper); +#ifdef USE_FRIBIDI_EX_API + ass_shaper_set_bidi_brackets(render_priv->shaper, + track->parser_priv->bidi_brackets); +#endif // PAR correction double par = render_priv->settings.par; diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index ab94f10..fc12974 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -39,10 +39,6 @@ enum { #define NUM_FEATURES 5 #endif -#if FRIBIDI_MAJOR_VERSION >= 1 -#define USE_FRIBIDI_EX_API -#endif - struct ass_shaper { ASS_ShapingLevel shaping_level; @@ -50,9 +46,6 @@ struct ass_shaper { int n_glyphs; FriBidiChar *event_text; FriBidiCharType *ctypes; -#ifdef USE_FRIBIDI_EX_API - FriBidiBracketType *btypes; -#endif FriBidiLevel *emblevels; FriBidiStrIndex *cmap; FriBidiParType base_direction; @@ -66,6 +59,11 @@ struct ass_shaper { // Glyph metrics cache, to speed up shaping Cache *metrics_cache; #endif + +#ifdef USE_FRIBIDI_EX_API + FriBidiBracketType *btypes; + bool bidi_brackets; +#endif }; #ifdef CONFIG_HARFBUZZ @@ -105,7 +103,7 @@ static bool check_allocations(ASS_Shaper *shaper, size_t new_size) if (!ASS_REALLOC_ARRAY(shaper->event_text, new_size) || !ASS_REALLOC_ARRAY(shaper->ctypes, new_size) || #ifdef USE_FRIBIDI_EX_API - !ASS_REALLOC_ARRAY(shaper->btypes, new_size) || + (shaper->bidi_brackets && !ASS_REALLOC_ARRAY(shaper->btypes, new_size)) || #endif !ASS_REALLOC_ARRAY(shaper->emblevels, new_size) || !ASS_REALLOC_ARRAY(shaper->cmap, new_size)) @@ -860,6 +858,13 @@ void ass_shaper_set_level(ASS_Shaper *shaper, ASS_ShapingLevel level) shaper->shaping_level = level; } +#ifdef USE_FRIBIDI_EX_API +void ass_shaper_set_bidi_brackets(ASS_Shaper *shaper, bool match_brackets) +{ + shaper->bidi_brackets = match_brackets; +} +#endif + /** * \brief Remove all zero-width invisible characters from the text. * \param text_info text @@ -907,11 +912,15 @@ int ass_shaper_shape(ASS_Shaper *shaper, TextInfo *text_info) fribidi_get_bidi_types(shaper->event_text + last_break, i - last_break + 1, shaper->ctypes + last_break); #ifdef USE_FRIBIDI_EX_API - fribidi_get_bracket_types(shaper->event_text + last_break, - i - last_break + 1, shaper->ctypes + last_break, - shaper->btypes + last_break); + FriBidiBracketType *btypes = NULL; + if (shaper->bidi_brackets) { + btypes = shaper->btypes + last_break; + fribidi_get_bracket_types(shaper->event_text + last_break, + i - last_break + 1, shaper->ctypes + last_break, + btypes); + } ret = fribidi_get_par_embedding_levels_ex( - shaper->ctypes + last_break, shaper->btypes + last_break, + shaper->ctypes + last_break, btypes, i - last_break + 1, &dir, shaper->emblevels + last_break); #else ret = fribidi_get_par_embedding_levels(shaper->ctypes + last_break, diff --git a/libass/ass_shaper.h b/libass/ass_shaper.h index d12870f..9ff96e7 100644 --- a/libass/ass_shaper.h +++ b/libass/ass_shaper.h @@ -25,6 +25,10 @@ typedef struct ass_shaper ASS_Shaper; #include #include "ass_render.h" +#if FRIBIDI_MAJOR_VERSION >= 1 +#define USE_FRIBIDI_EX_API +#endif + void ass_shaper_info(ASS_Library *lib); ASS_Shaper *ass_shaper_new(void); void ass_shaper_free(ASS_Shaper *shaper); @@ -35,6 +39,9 @@ void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, void ass_shaper_set_base_direction(ASS_Shaper *shaper, FriBidiParType dir); void ass_shaper_set_language(ASS_Shaper *shaper, const char *code); 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 int 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); -- cgit v1.2.3