]> granicus.if.org Git - libass/commitdiff
Allow more fine grained control over style overrides
authorwm4 <wm4@nowhere>
Thu, 26 Feb 2015 19:49:18 +0000 (20:49 +0100)
committerwm4 <wm4@nowhere>
Thu, 26 Feb 2015 20:18:49 +0000 (21:18 +0100)
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
libass/ass_render.c
libass/ass_render.h
libass/ass_render_api.c

index ca9d8afb55cc7eb6bc208ce8223591b083a765f8..80f9247cee0f28c6e828005174197ea1a7e96fba 100644 (file)
@@ -23,7 +23,7 @@
 #include <stdarg.h>
 #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);
 
index 3e547104c1e798824b42f034c546f36b4393337c..b03fc3067233b603273357feda418660a652e699 100644 (file)
@@ -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;
index b0892ce5b9da541ee4da2ea3334929f379015639..d7416e184f696168466c2059fd1c4e83e63ed22c 100644 (file)
@@ -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;
index 8802629e59760142b0699ac72fa52746705aa1c4..2db653a6186ef3655c123f63b1a4d94f74ecab26 100644 (file)
@@ -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)