Skip to content

Commit

Permalink
parse_tags: handle argumentless \t inside \t() like VSFilter
Browse files Browse the repository at this point in the history
\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 #296.
  • Loading branch information
astiob committed Jan 8, 2018
1 parent 6835731 commit 3171bda
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 7 deletions.
1 change: 1 addition & 0 deletions Changelog
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
15 changes: 10 additions & 5 deletions libass/ass_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -649,16 +649,21 @@ 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,
// so we don't need to restore pwr after parsing \t.
// The recursive call is now essentially a tail call,
// so optimize it away.
pwr = k;
nested = true;
q = p;
}
} else if (complex_tag("clip")) {
Expand Down
3 changes: 2 additions & 1 deletion libass/ass_parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion libass/ass_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 3171bda

Please sign in to comment.