From 51a93b5571acf51d3c7fe841d3e1e34720524c23 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 26 Feb 2015 20:49:18 +0100 Subject: [PATCH] Allow more fine grained control over style overrides Add tons of ASS_OVERRIDE_ flags, which control whether certain ASS_Style fields are copied when doing selective style overrides with ass_set_selective_style_override_enabled(). This comes with some cleanup. It should be fully backwards-compatible. --- libass/ass.h | 87 +++++++++++++++++++++++++++++------- libass/ass_render.c | 97 +++++++++++++++++++++++++++++------------ libass/ass_render.h | 4 +- libass/ass_render_api.c | 1 - 4 files changed, 143 insertions(+), 46 deletions(-) diff --git a/libass/ass.h b/libass/ass.h index ca9d8af..80f9247 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -23,7 +23,7 @@ #include #include "ass_types.h" -#define LIBASS_VERSION 0x01201000 +#define LIBASS_VERSION 0x01201001 #ifdef __cplusplus extern "C" { @@ -96,8 +96,75 @@ typedef enum { * ass_set_selective_style_override_enabled() for details. */ typedef enum { - ASS_OVERRIDE_BIT_STYLE = 1, - ASS_OVERRIDE_BIT_FONT_SIZE = 2, + /** + * Default mode (with no other bits set). All selective override features + * as well as the style set with ass_set_selective_style_override() are + * disabled, but traditional overrides like ass_set_font_scale() are + * applied unconditionally. + */ + ASS_OVERRIDE_DEFAULT = 0, + /** + * Apply the style as set with ass_set_selective_style_override() on events + * which look like dialogue. Other style overrides are also applied this + * way, except ass_set_font_scale(). How ass_set_font_scale() is applied + * depends on the ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE flag. + * + * This is equivalent to setting all of the following bits: + * + * ASS_OVERRIDE_BIT_FONT_NAME + * ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS + * ASS_OVERRIDE_BIT_COLORS + * ASS_OVERRIDE_BIT_BORDER + * ASS_OVERRIDE_BIT_ATTRIBUTES + */ + ASS_OVERRIDE_BIT_STYLE = 1 << 0, + /** + * Apply ass_set_font_scale() only on events which look like dialogue. + * If not set, the font scale is applied to all events. (The behavior and + * name of this flag are unintuitive, but exist for compatibility) + */ + ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE = 1 << 1, + /** + * Old alias for ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE. Deprecated. Do not use. + */ + ASS_OVERRIDE_BIT_FONT_SIZE = 1 << 1, + /** + * On dialogue events override: FontSize, Spacing, Blur, ScaleX, ScaleY + */ + ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS = 1 << 2, + /** + * On dialogue events override: FontName, treat_fontname_as_pattern + */ + ASS_OVERRIDE_BIT_FONT_NAME = 1 << 3, + /** + * On dialogue events override: PrimaryColour, SecondaryColour, OutlineColour, BackColour + */ + ASS_OVERRIDE_BIT_COLORS = 1 << 4, + /** + * On dialogue events override: Bold, Italic, Underline, StrikeOut + */ + ASS_OVERRIDE_BIT_ATTRIBUTES = 1 << 5, + /** + * On dialogue events override: BorderStyle, Outline, Shadow + */ + ASS_OVERRIDE_BIT_BORDER = 1 << 6, + /** + * On dialogue events override: Alignment + */ + ASS_OVERRIDE_BIT_ALIGNMENT = 1 << 7, + /** + * On dialogue events override: MarginL, MarginR, MarginV + */ + ASS_OVERRIDE_BIT_MARGINS = 1 << 8, + /** + * Unconditionally replace all fields of all styles with the one provided + * with ass_set_selective_style_override(). + * Does not apply ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE. + * Add ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS and ASS_OVERRIDE_BIT_BORDER if + * you want FontSize, Spacing, Outline, Shadow to be scaled to the script + * resolution given by the ASS_Track. + */ + ASS_OVERRIDE_FULL_STYLE = 1 << 9, } ASS_OverrideBits; /** @@ -345,19 +412,7 @@ void ass_set_fonts(ASS_Renderer *priv, const char *default_font, * only be implemented on "best effort" basis, and has to rely on * heuristics that can easily break. * \param priv renderer handle - * \param bits bit mask comprised of ASS_OverrideBits values. If the value is - * 0, all override features are disabled, and libass will behave like libass - * versions before this feature was introduced. Possible values: - * ASS_OVERRIDE_BIT_STYLE: apply the style as set with - * ass_set_selective_style_override() on events which look like - * dialogue. Other style overrides are also applied this way, except - * ass_set_font_scale(). How ass_set_font_scale() is applied depends - * on the ASS_OVERRIDE_BIT_FONT_SIZE flag. - * ASS_OVERRIDE_BIT_FONT_SIZE: apply ass_set_font_scale() only on events - * which look like dialogue. If not set, it is applied to all - * events. - * 0: ignore ass_set_selective_style_override(), but apply all other - * overrides (traditional behavior). + * \param bits bit mask comprised of ASS_OverrideBits values. */ void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int bits); diff --git a/libass/ass_render.c b/libass/ass_render.c index 3e54710..b03fc30 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -139,6 +139,7 @@ ASS_Renderer *ass_renderer_init(ASS_Library *library) priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo)); priv->settings.font_size_coeff = 1.; + priv->settings.selective_style_overrides = ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE; priv->shaper = ass_shaper_new(0); ass_shaper_info(library); @@ -750,55 +751,95 @@ 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; + // The user style was set with ass_set_selective_style_override(). + ASS_Style *user = &render_priv->user_override_style; ASS_Style *new = &render_priv->state.override_style_temp_storage; int explicit = event_is_positioned(render_priv->state.event->Text); int requested = render_priv->settings.selective_style_overrides; double scale; + user->Name = "OverrideStyle"; // name insignificant + + // Either the event's style, or the style forced with a \r tag. if (!rstyle) rstyle = script; - render_priv->state.style = script; - render_priv->state.overrides = ASS_OVERRIDE_BIT_FONT_SIZE; // odd default - - if (explicit && (requested & ASS_OVERRIDE_BIT_FONT_SIZE)) - render_priv->state.overrides &= ~(unsigned)ASS_OVERRIDE_BIT_FONT_SIZE; - - if (!explicit && (requested & ASS_OVERRIDE_BIT_STYLE)) - render_priv->state.overrides |= ASS_OVERRIDE_BIT_STYLE; - - if (!(render_priv->state.overrides & ASS_OVERRIDE_BIT_STYLE)) - 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 = *rstyle; + + render_priv->state.apply_font_scale = + !explicit || !(requested & ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE); - new->Bold = rstyle->Bold; - new->StrikeOut = rstyle->StrikeOut; - new->Underline = rstyle->Underline; - new->Angle = rstyle->Angle; + // On positioned events, do not apply most overrides. + if (explicit) + requested = 0; - new->MarginL = rstyle->MarginL; - new->MarginR = rstyle->MarginR; - new->MarginV = rstyle->MarginV; - new->Alignment = rstyle->Alignment; - new->Encoding = rstyle->Encoding; + if (requested & ASS_OVERRIDE_BIT_STYLE) + requested |= ASS_OVERRIDE_BIT_FONT_NAME | + ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS | + ASS_OVERRIDE_BIT_COLORS | + ASS_OVERRIDE_BIT_BORDER | + ASS_OVERRIDE_BIT_ATTRIBUTES; + + // Copies fields even not covered by any of the other bits. + if (requested & ASS_OVERRIDE_FULL_STYLE) + *new = *user; // 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; + + if (requested & ASS_OVERRIDE_BIT_FONT_SIZE_FIELDS) { + new->FontSize = user->FontSize * scale; + new->Spacing = user->Spacing * scale; + new->ScaleX = user->ScaleX; + new->ScaleY = user->ScaleY; + } + + if (requested & ASS_OVERRIDE_BIT_FONT_NAME) { + new->FontName = user->FontName; + new->treat_fontname_as_pattern = user->treat_fontname_as_pattern; + } + + if (requested & ASS_OVERRIDE_BIT_COLORS) { + new->PrimaryColour = user->PrimaryColour; + new->SecondaryColour = user->SecondaryColour; + new->OutlineColour = user->OutlineColour; + new->BackColour = user->BackColour; + } + + if (requested & ASS_OVERRIDE_BIT_ATTRIBUTES) { + new->Bold = user->Bold; + new->Italic = user->Italic; + new->Underline = user->Underline; + new->StrikeOut = user->StrikeOut; + } + + if (requested & ASS_OVERRIDE_BIT_BORDER) { + new->BorderStyle = user->BorderStyle; + new->Outline = user->Outline * scale; + new->Shadow = user->Shadow * scale; + } + + if (requested & ASS_OVERRIDE_BIT_ALIGNMENT) + new->Alignment = user->Alignment; + + if (requested & ASS_OVERRIDE_BIT_MARGINS) { + new->MarginL = user->MarginL; + new->MarginR = user->MarginR; + new->MarginV = user->MarginV; + } + + if (!new->FontName) + new->FontName = rstyle->FontName; render_priv->state.style = new; + render_priv->state.overrides = requested; return new; } @@ -823,7 +864,7 @@ static void init_font_scale(ASS_Renderer *render_priv) if (!settings_priv->storage_height) render_priv->blur_scale = render_priv->border_scale; - if (render_priv->state.overrides & ASS_OVERRIDE_BIT_FONT_SIZE) { + if (render_priv->state.apply_font_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; diff --git a/libass/ass_render.h b/libass/ass_render.h index b0892ce..d7416e1 100644 --- a/libass/ass_render.h +++ b/libass/ass_render.h @@ -85,7 +85,7 @@ typedef struct { double par; // user defined pixel aspect ratio (0 = unset) ASS_Hinting hinting; ASS_ShapingLevel shaper; - int selective_style_overrides; + int selective_style_overrides; // ASS_OVERRIDE_* flags char *default_font; char *default_family; @@ -273,6 +273,8 @@ typedef struct { // combination of ASS_OVERRIDE_BIT_* flags that apply right now unsigned overrides; + // whether to apply font_scale + int apply_font_scale; // used to store RenderContext.style when doing selective style overrides ASS_Style override_style_temp_storage; diff --git a/libass/ass_render_api.c b/libass/ass_render_api.c index 8802629..2db653a 100644 --- a/libass/ass_render_api.c +++ b/libass/ass_render_api.c @@ -165,7 +165,6 @@ void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *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) -- 2.40.0