summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libass/ass.h28
-rw-r--r--libass/ass_parse.c26
-rw-r--r--libass/ass_parse.h1
-rw-r--r--libass/ass_render.c101
-rw-r--r--libass/ass_render.h6
-rw-r--r--libass/ass_render_api.c18
-rw-r--r--libass/libass.sym2
7 files changed, 160 insertions, 22 deletions
diff --git a/libass/ass.h b/libass/ass.h
index b797a97..408bdeb 100644
--- a/libass/ass.h
+++ b/libass/ass.h
@@ -23,7 +23,7 @@
#include <stdarg.h>
#include "ass_types.h"
-#define LIBASS_VERSION 0x01102001
+#define LIBASS_VERSION 0x01103000
/*
* A linked list of images produced by an ass renderer.
@@ -320,6 +320,32 @@ void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
int update);
/**
+ * \brief Set selective style override mode.
+ * If enabled, the renderer attempts to override the ASS script's styling of
+ * normal subtitles, without affecting explicitly positioned text. If an event
+ * looks like a normal subtitle, parts of the font style are copied from the
+ * user style set with ass_set_selective_style_override().
+ * Warning: the heuristic used for deciding when to override the style is rather
+ * rough, and enabling this option can lead to incorrectly rendered
+ * subtitles. Since the ASS format doesn't have any support for
+ * allowing end-users to customize subtitle styling, this feature can
+ * only be implemented on "best effort" basis, and has to rely on
+ * heuristics that can easily break.
+ * \param priv renderer handle
+ * \param enable enable selective styling if the value is not 0
+ */
+void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int enable);
+
+/**
+ * \brief Set style for selective style override.
+ * See ass_set_selective_style_override_enabled().
+ * \param style style settings to use if override is enabled. Applications
+ * should initialize it with {0} before setting fields. Strings will be copied
+ * by the function.
+ */
+void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style);
+
+/**
* \brief Update/build font cache. This needs to be called if it was
* disabled when ass_set_fonts was set.
*
diff --git a/libass/ass_parse.c b/libass/ass_parse.c
index d6b2627..d0d1972 100644
--- a/libass/ass_parse.c
+++ b/libass/ass_parse.c
@@ -1025,3 +1025,29 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str)
*str = p;
return chr;
}
+
+// Return 1 if the event contains tags that will put the renderer into the
+// EVENT_POSITIONED state. Return 0 otherwise.
+int event_is_positioned(char *str)
+{
+ // look for \pos and \move tags inside {...}
+ // mirrors get_next_char, but is faster and doesn't change any global state
+ while (*str) {
+ if (str[0] == '\\' && str[1] != '\0') {
+ str += 2;
+ } else if (str[0] == '{') {
+ str++;
+ while (*str && *str != '}') {
+ if (*str == '\\') {
+ char *p = str + 1;
+ if (mystrcmp(&p, "pos") || mystrcmp(&p, "move"))
+ return 1;
+ }
+ str++;
+ }
+ } else {
+ str++;
+ }
+ }
+ return 0;
+}
diff --git a/libass/ass_parse.h b/libass/ass_parse.h
index 88fcda8..85f3d53 100644
--- a/libass/ass_parse.h
+++ b/libass/ass_parse.h
@@ -35,6 +35,7 @@ void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
void process_karaoke_effects(ASS_Renderer *render_priv);
unsigned get_next_char(ASS_Renderer *render_priv, char **str);
char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr);
+int event_is_positioned(char *str);
extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
extern uint32_t mult_alpha(uint32_t a, uint32_t b);
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 0cc1848..625a77d 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -208,6 +208,8 @@ void ass_renderer_done(ASS_Renderer *render_priv)
free(render_priv->settings.default_font);
free(render_priv->settings.default_family);
+ free(render_priv->user_override_style.FontName);
+
free_list_clear(render_priv);
free(render_priv);
}
@@ -763,14 +765,89 @@ static void compute_string_bbox(TextInfo *text, DBBox *bbox)
bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
}
+static ASS_Style *handle_selective_style_overrides(ASS_Renderer *render_priv,
+ ASS_Style *rstyle)
+{
+ // The script style is the one the event was declared with.
+ // The rstyle is either NULL, or the style used with a \r tag.
+ ASS_Style *script = render_priv->track->styles +
+ render_priv->state.event->Style;
+ ASS_Style *new = &render_priv->state.override_style_temp_storage;
+ int override = !event_is_positioned(render_priv->state.event->Text);
+ double scale;
+
+ if (!rstyle)
+ rstyle = script;
+
+ render_priv->state.style = script;
+
+ if (!override || !render_priv->settings.selective_style_overrides)
+ return rstyle;
+
+ // Create a new style that contains a mix of the original style and
+ // user_style (the user's override style). Copy only fields from the
+ // script's style that are deemed necessary.
+ *new = render_priv->user_override_style;
+
+ new->StrikeOut = rstyle->StrikeOut;
+ new->Underline = rstyle->Underline;
+ new->Angle = rstyle->Angle;
+
+ new->MarginL = script->MarginL;
+ new->MarginR = script->MarginR;
+ new->MarginV = script->MarginV;
+ new->Alignment = script->Alignment;
+ new->Encoding = script->Encoding;
+ new->treat_fontname_as_pattern = script->treat_fontname_as_pattern;
+
+ // The user style is supposed to be independent of the script resolution.
+ // Treat the user style's values as if they were specified for a script with
+ // PlayResY=288, and rescale the values to the current script.
+ scale = render_priv->track->PlayResY / 288.0;
+ new->FontSize *= scale;
+ new->Spacing *= scale;
+ new->Outline *= scale;
+ new->Shadow *= scale;
+
+ render_priv->state.style = new;
+
+ return new;
+}
+
+static void init_font_scale(ASS_Renderer *render_priv)
+{
+ ASS_Settings *settings_priv = &render_priv->settings;
+
+ render_priv->font_scale = ((double) render_priv->orig_height) /
+ render_priv->track->PlayResY;
+ if (settings_priv->storage_height)
+ render_priv->blur_scale = ((double) render_priv->orig_height) /
+ settings_priv->storage_height;
+ else
+ render_priv->blur_scale = 1.;
+ if (render_priv->track->ScaledBorderAndShadow)
+ render_priv->border_scale =
+ ((double) render_priv->orig_height) /
+ render_priv->track->PlayResY;
+ else
+ render_priv->border_scale = render_priv->blur_scale;
+ if (!settings_priv->storage_height)
+ render_priv->blur_scale = render_priv->border_scale;
+
+ render_priv->font_scale *= settings_priv->font_size_coeff;
+ render_priv->border_scale *= settings_priv->font_size_coeff;
+ render_priv->blur_scale *= settings_priv->font_size_coeff;
+}
+
/**
* \brief partially reset render_context to style values
* Works like {\r}: resets some style overrides
*/
void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style)
{
- if (!style)
- style = render_priv->state.style;
+ style = handle_selective_style_overrides(render_priv, style);
+
+ init_font_scale(render_priv);
render_priv->state.c[0] = style->PrimaryColour;
render_priv->state.c[1] = style->SecondaryColour;
@@ -814,11 +891,10 @@ static void
init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
{
render_priv->state.event = event;
- render_priv->state.style = render_priv->track->styles + event->Style;
render_priv->state.parsed_tags = 0;
render_priv->state.has_clips = 0;
- reset_render_context(render_priv, render_priv->state.style);
+ reset_render_context(render_priv, NULL);
render_priv->state.wrap_style = render_priv->track->WrapStyle;
render_priv->state.evt_type = EVENT_NORMAL;
@@ -2636,23 +2712,6 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track,
ass_lazy_track_init(render_priv->library, render_priv->track);
- render_priv->font_scale = settings_priv->font_size_coeff *
- render_priv->orig_height / render_priv->track->PlayResY;
- if (settings_priv->storage_height)
- render_priv->blur_scale = ((double) render_priv->orig_height) /
- settings_priv->storage_height;
- else
- render_priv->blur_scale = 1.;
- if (render_priv->track->ScaledBorderAndShadow)
- render_priv->border_scale =
- ((double) render_priv->orig_height) /
- render_priv->track->PlayResY;
- else
- render_priv->border_scale = render_priv->blur_scale;
- if (!settings_priv->storage_height)
- render_priv->blur_scale = render_priv->border_scale;
- render_priv->border_scale *= settings_priv->font_size_coeff;
-
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);
diff --git a/libass/ass_render.h b/libass/ass_render.h
index 8e15ad5..e1b42b2 100644
--- a/libass/ass_render.h
+++ b/libass/ass_render.h
@@ -85,6 +85,7 @@ typedef struct {
double par; // user defined pixel aspect ratio (0 = unset)
ASS_Hinting hinting;
ASS_ShapingLevel shaper;
+ int selective_style_overrides;
char *default_font;
char *default_family;
@@ -294,6 +295,9 @@ typedef struct {
int treat_family_as_pattern;
int wrap_style;
int font_encoding;
+
+ // used to store RenderContext.style when doing selective style overrides
+ ASS_Style override_style_temp_storage;
} RenderContext;
typedef struct {
@@ -360,6 +364,8 @@ struct ass_renderer {
FreeList *free_head;
FreeList *free_tail;
+
+ ASS_Style user_override_style;
};
typedef struct render_priv {
diff --git a/libass/ass_render_api.c b/libass/ass_render_api.c
index b06fc80..072b693 100644
--- a/libass/ass_render_api.c
+++ b/libass/ass_render_api.c
@@ -151,6 +151,24 @@ void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
default_font, fc, config, update);
}
+void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int enable)
+{
+ enable = !!enable;
+ if (priv->settings.selective_style_overrides != enable) {
+ priv->settings.selective_style_overrides = enable;
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style)
+{
+ ASS_Style *user_style = &priv->user_override_style;
+ free(user_style->FontName);
+ *user_style = *style;
+ user_style->FontName = strdup(user_style->FontName);
+ user_style->Name = "OverrideStyle"; // name insignificant
+}
+
int ass_fonts_update(ASS_Renderer *render_priv)
{
return fontconfig_update(render_priv->fontconfig_priv);
diff --git a/libass/libass.sym b/libass/libass.sym
index d0cc155..89e212c 100644
--- a/libass/libass.sym
+++ b/libass/libass.sym
@@ -39,3 +39,5 @@ ass_flush_events
ass_set_shaper
ass_set_line_position
ass_set_pixel_aspect
+ass_set_selective_style_override_enabled
+ass_set_selective_style_override