summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
Diffstat (limited to 'libass')
-rw-r--r--libass/ass.c1
-rw-r--r--libass/ass.h19
-rw-r--r--libass/ass_render.c2
-rw-r--r--libass/ass_shaper.c49
-rw-r--r--libass/ass_shaper.h1
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);