diff options
-rw-r--r-- | libass/ass.h | 28 | ||||
-rw-r--r-- | libass/ass_parse.c | 26 | ||||
-rw-r--r-- | libass/ass_parse.h | 1 | ||||
-rw-r--r-- | libass/ass_render.c | 101 | ||||
-rw-r--r-- | libass/ass_render.h | 6 | ||||
-rw-r--r-- | libass/ass_render_api.c | 18 | ||||
-rw-r--r-- | libass/libass.sym | 2 |
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 |