]> granicus.if.org Git - libass/commitdiff
parse_tags: handle argumentless \t inside \t() like VSFilter
authorOleg Oshmyan <chortos@inbox.lv>
Thu, 4 Jan 2018 01:37:28 +0000 (03:37 +0200)
committerOleg Oshmyan <chortos@inbox.lv>
Mon, 8 Jan 2018 20:26:29 +0000 (22:26 +0200)
\t with no parantheses inside \t() resets the animation parameters
of the \t() for subsequent tags, so they are animated as if the \t()
was the single-argument version regardless of the actual number
of arguments the \t() has.

Equivalently, you could say parentheses are implied for \t inside \t().

For example, \t(20,60,\frx0\t\fry0\frz0) animates \frx from 20 to 60 ms
and animates \fry and \frz for the whole duration of the line,
just like \t(20,60,\frx0)\t(\fry0\frz0) or \t(20,60,\frx0\t(\fry0\frz0)).

Technically, VSFilter simply resets the animation parameters for any \t
it encounters but parses the embedded tags only if the \t has the right
number of arguments. However, top-level animation parameters don't matter
because top-level tags are not animated, while any nested \t that has
parentheses terminates the containing \t because they share the closing
parenthesis, so the fact that a nested \t with empty parentheses or with
at least four arguments changes the animation parameters also doesn't
matter because the containing \t immediately ends and the changed
parameters have nothing to apply to. Thus the only situation where
this has a visible effect is a nested \t without parentheses.

Closes https://github.com/libass/libass/pull/296.

Changelog
libass/ass_parse.c
libass/ass_parse.h
libass/ass_render.c

index ba8f6f53248794ab6040be70e1e3bd44f76f8afb..6968a53d5b851d28978ae5c596414eebd6f24405 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,4 +1,5 @@
 libass (unreleased)
+ * Treat invalid nested \t tags like VSFilter
  * Fix stack overflow on deeply nested \t tags
 
 libass (0.14.0)
index 652ffa972aa79f015540954553c7292d9fc58c51..3ccf55699849eac40cf0a3dede75b01d507ae259 100644 (file)
@@ -230,7 +230,8 @@ static int parse_vector_clip(ASS_Renderer *render_priv,
  *            of a number of spaces immediately preceding '}' or ')'
  * \param pwr multiplier for some tag effects (comes from \t tags)
  */
-char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr)
+char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr,
+                 bool nested)
 {
     for (char *q; p < end; p = q) {
         while (*p != '\\' && p != end)
@@ -630,12 +631,11 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr)
                 t1 = 0;
                 t2 = 0;
                 accel = argtod(args[0]);
-            } else if (cnt == 0) {
+            } else {
                 t1 = 0;
                 t2 = 0;
                 accel = 1.;
-            } else
-                continue;
+            }
             render_priv->state.detect_collisions = 0;
             if (t2 == 0)
                 t2 = render_priv->state.event->Duration;
@@ -649,9 +649,13 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr)
                 assert(delta_t != 0.);
                 k = pow(((double) (t - t1)) / delta_t, accel);
             }
+            if (nested)
+                pwr = k;
+            if (cnt < 0 || cnt > 3)
+                continue;
             p = args[cnt].start;
             if (args[cnt].end < end) {
-                p = parse_tags(render_priv, p, args[cnt].end, k);
+                p = parse_tags(render_priv, p, args[cnt].end, k, true);
             } else {
                 assert(q == end);
                 // No other tags can possibly follow this \t tag,
@@ -659,6 +663,7 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr)
                 // The recursive call is now essentially a tail call,
                 // so optimize it away.
                 pwr = k;
+                nested = true;
                 q = p;
             }
         } else if (complex_tag("clip")) {
index 1b1b131a184302237ac12ef7b98abc6f8e195cba..bf72b78fafb25bad9d8732d701f5d4dd3ed1c3bf 100644 (file)
@@ -31,7 +31,8 @@ double ensure_font_size(ASS_Renderer *priv, double size);
 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_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr);
+char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr,
+                 bool nested);
 int event_has_hard_overrides(char *str);
 extern void change_alpha(uint32_t *var, int32_t new, double pwr);
 extern uint32_t mult_alpha(uint32_t a, uint32_t b);
index d5f881fb6d6437f0a297c93946660ff6e7ec99e0..9ba38846d20eaa50ec75f4e9395758fff0082c92 100644 (file)
@@ -1712,7 +1712,7 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
         code = 0;
         while (*p) {
             if ((*p == '{') && (q = strchr(p, '}'))) {
-                p = parse_tags(render_priv, p, q, 1.);
+                p = parse_tags(render_priv, p, q, 1., false);
                 assert(*p == '}');
                 p++;
             } else if (render_priv->state.drawing_scale) {