]> granicus.if.org Git - libass/commitdiff
Terminate drawings immediately on a \p0 tag
authorwm4 <wm4@nowhere>
Sat, 29 Sep 2012 19:31:23 +0000 (21:31 +0200)
committerwm4 <wm4@nowhere>
Sat, 29 Sep 2012 19:31:23 +0000 (21:31 +0200)
The parsing code allowed override tags after \p0 to affect the drawing.
This is incorrect. Finish the drawing object as soon as \p0 is
encountered instead.

This requires moving the code executing the style overrides from
get_next_char() in ass_parse.c to the main render loop in
ass_renderer.c, because we have to re-enter the rendering loop
inside of a tag. The old code was simply executing all tags until
a new character could be returned to the renderer loop, mutating up
the state (RenderContext fields) for the drawing after the drawing
was closed, but before it was rendered.

This fixes libass issue #47.

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

index da75d29d8a11c938d5fa330ceee9f2be9467f594..3966a4326a1bdc935480fe8240b12e1b11a4b5a4 100644 (file)
@@ -253,7 +253,7 @@ static char *parse_vector_clip(ASS_Renderer *render_priv, char *p)
  * \param p string to parse
  * \param pwr multiplier for some tag effects (comes from \t tags)
  */
-static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
+char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
 {
     skip_to('\\');
     skip('\\');
@@ -999,7 +999,7 @@ void process_karaoke_effects(ASS_Renderer *render_priv)
 
 
 /**
- * \brief Get next ucs4 char from string, parsing and executing style overrides
+ * \brief Get next ucs4 char from string, parsing UTF-8 and escapes
  * \param str string pointer
  * \return ucs4 code of the next char
  * On return str points to the unparsed part of the string
@@ -1008,24 +1008,6 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str)
 {
     char *p = *str;
     unsigned chr;
-    if (*p == '{') {            // '\0' goes here
-        p++;
-        while (1) {
-            p = parse_tag(render_priv, p, 1.);
-            if (*p == '}') {    // end of tag
-                p++;
-                if (*p == '{') {
-                    p++;
-                    continue;
-                } else
-                    break;
-            } else if (*p != '\\')
-                ass_msg(render_priv->library, MSGL_V,
-                        "Unable to parse: '%.30s'", p);
-            if (*p == 0)
-                break;
-        }
-    }
     if (*p == '\t') {
         ++p;
         *str = p;
index fd4fd6690f63166436c819260e059e3d20a0cf5f..88fcda8dcaa9e6e01e5b9d3b51128299bcbdc409 100644 (file)
@@ -34,6 +34,7 @@ void change_border(ASS_Renderer *render_priv, double border_x,
 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);
 extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
 extern uint32_t mult_alpha(uint32_t a, uint32_t b);
 
index 02bd11165d8f59df1a8a00c23270e31c1237dda4..3e269c1668564b19fce32e29a8d78a82b894e9fe 100644 (file)
@@ -1711,15 +1711,43 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
     num_glyphs = 0;
     p = event->Text;
 
+    int in_tag = 0;
+
     // Event parsing.
     while (1) {
         // get next char, executing style override
         // this affects render_context
         do {
-            code = get_next_char(render_priv, &p);
-            if (render_priv->state.drawing_mode && code)
-                ass_drawing_add_char(drawing, (char) code);
-        } while (code && render_priv->state.drawing_mode);      // skip everything in drawing mode
+            code = 0;
+            if (!in_tag && *p == '{') {            // '\0' goes here
+                p++;
+                in_tag = 1;
+            }
+            if (in_tag) {
+                int prev_drawing_mode = render_priv->state.drawing_mode;
+                p = parse_tag(render_priv, p, 1.);
+                if (*p == '}') {    // end of tag
+                    p++;
+                    in_tag = 0;
+                } else if (*p != '\\') {
+                    ass_msg(render_priv->library, MSGL_V,
+                            "Unable to parse: '%.30s'", p);
+                }
+                if (prev_drawing_mode && !render_priv->state.drawing_mode) {
+                    // Drawing mode was just disabled. We must exit and draw it
+                    // immediately, instead of letting further tags affect it.
+                    // See bug #47.
+                    break;
+                }
+            } else {
+                code = get_next_char(render_priv, &p);
+                if (code && render_priv->state.drawing_mode) {
+                    ass_drawing_add_char(drawing, (char) code);
+                    continue;   // skip everything in drawing mode
+                }
+                break;
+            }
+        } while (*p);
 
         if (text_info->length >= text_info->max_glyphs) {
             // Raise maximum number of glyphs
@@ -1738,7 +1766,6 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
                                      render_priv->font_scale;
             drawing->scale_y = render_priv->state.scale_y *
                                      render_priv->font_scale;
-            p--;
             code = 0xfffc; // object replacement character
             glyphs[text_info->length].drawing = drawing;
         }