]> granicus.if.org Git - libass/commitdiff
drawing: separate drawing text reading from outline construction
authorDr.Smile <vabnick@gmail.com>
Sun, 2 Dec 2018 19:34:45 +0000 (22:34 +0300)
committerDr.Smile <vabnick@gmail.com>
Sun, 19 May 2019 17:18:51 +0000 (20:18 +0300)
Purpose of this commit is to simplify logic behind drawing handling.

libass/ass_drawing.c
libass/ass_drawing.h
libass/ass_outline.c
libass/ass_outline.h
libass/ass_parse.c
libass/ass_render.c
libass/ass_render.h

index c0ea5487d0bf76291e88b25de951a7b49214792f..11ff399d6cef7d737ccce0f204e1a4422277bf91 100644 (file)
@@ -224,57 +224,21 @@ static bool drawing_add_curve(ASS_Drawing *drawing, ASS_DrawingToken *token,
 }
 
 /*
- * \brief Create and initialize a new drawing and return it
+ * \brief Convert token list to outline.  Calls the line and curve evaluators.
  */
-ASS_Drawing *ass_drawing_new(ASS_Library *lib)
+ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_mode)
 {
-    ASS_Drawing *drawing = calloc(1, sizeof(*drawing));
-    if (!drawing)
-        return NULL;
-    rectangle_reset(&drawing->cbox);
     drawing->library = lib;
-    drawing->scale_x = 1.;
-    drawing->scale_y = 1.;
-
-    if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_SEGMENTS)) {
-        free(drawing);
+    rectangle_reset(&drawing->cbox);
+    if (!outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_SEGMENTS))
         return NULL;
-    }
-    return drawing;
-}
-
-/*
- * \brief Free a drawing
- */
-void ass_drawing_free(ASS_Drawing *drawing)
-{
-    if (drawing) {
-        free(drawing->text);
-        outline_free(&drawing->outline);
-    }
-    free(drawing);
-}
-
-/*
- * \brief Copy an ASCII string to the drawing text buffer
- */
-void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t len)
-{
-    free(drawing->text);
-    drawing->text = strndup(str, len);
-}
-
-/*
- * \brief Convert token list to outline.  Calls the line and curve evaluators.
- */
-ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode)
-{
-    bool started = false;
-    ASS_Vector pen = {0, 0};
+    drawing->outline.n_points = drawing->outline.n_segments = 0;
 
     ASS_DrawingToken *tokens = drawing_tokenize(drawing->text);
     drawing_prepare(drawing);
 
+    bool started = false;
+    ASS_Vector pen = {0, 0};
     ASS_DrawingToken *token = tokens;
     while (token) {
         // Draw something according to current command
@@ -349,5 +313,6 @@ ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode)
 
 error:
     drawing_free_tokens(tokens);
+    outline_free(&drawing->outline);
     return NULL;
 }
index 2b08e77c87be6ed2b4ca1407e918f874857aaf7b..16d85edd4b212f041073a6bd27c617edc3e42bf3 100644 (file)
@@ -59,9 +59,6 @@ typedef struct {
     ASS_Rect cbox;   // bounding box, or let's say... VSFilter's idea of it
 } ASS_Drawing;
 
-ASS_Drawing *ass_drawing_new(ASS_Library *lib);
-void ass_drawing_free(ASS_Drawing *drawing);
-void ass_drawing_set_text(ASS_Drawing *drawing, char *str, size_t n);
-ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, bool raw_mode);
+ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, ASS_Library *lib, bool raw_mode);
 
 #endif /* LIBASS_DRAWING_H */
index 1b9afe9cf523e1ce050b7ad414a90ce1a6274ce8..1ed94b87029234ec54ac566ca257d72d51ee04ea 100644 (file)
@@ -218,6 +218,17 @@ bool outline_copy(ASS_Outline *outline, const ASS_Outline *source)
     return true;
 }
 
+void outline_move(ASS_Outline *outline, ASS_Outline *source)
+{
+    if (!source || !source->n_points) {
+        outline_clear(outline);
+        return;
+    }
+
+    memcpy(outline, source, sizeof(*outline));
+    outline_clear(source);
+}
+
 void outline_free(ASS_Outline *outline)
 {
     if (!outline)
index 6be0211335b38cc8487047ce5f06fcb5362999d4..85faea917c1657a123a93b696929adb42ebd962b 100644 (file)
@@ -89,6 +89,7 @@ typedef struct {
 bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_segments);
 bool outline_convert(ASS_Outline *outline, const FT_Outline *source);
 bool outline_copy(ASS_Outline *outline, const ASS_Outline *source);
+void outline_move(ASS_Outline *outline, ASS_Outline *source);
 void outline_free(ASS_Outline *outline);
 
 bool outline_add_point(ASS_Outline *outline, ASS_Vector pt, char segment);
index 3ccf55699849eac40cf0a3dede75b01d507ae259..9397971a043aa5f593395e6502a8aaeabaa36377 100644 (file)
@@ -198,29 +198,20 @@ interpolate_alpha(long long now, long long t1, long long t2, long long t3,
  * Parse a vector clip into an outline, using the proper scaling
  * parameters.  Translate it to correct for screen borders, if needed.
  */
-static int parse_vector_clip(ASS_Renderer *render_priv,
-                             struct arg *args, int nargs)
+static bool parse_vector_clip(ASS_Renderer *render_priv,
+                              struct arg *args, int nargs)
 {
-    int scale = 1;
-    ASS_Drawing *drawing = render_priv->state.clip_drawing;
-
     if (nargs != 1 && nargs != 2)
-        return 0;
+        return false;
+
+    int scale = 1;
     if (nargs == 2)
         scale = argtoi(args[0]);
-    struct arg text = args[nargs - 1];
-
-    ass_drawing_free(drawing);
-    render_priv->state.clip_drawing = ass_drawing_new(render_priv->library);
-    drawing = render_priv->state.clip_drawing;
-    if (drawing) {
-        drawing->scale = scale;
-        drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale;
-        drawing->scale_y = render_priv->font_scale;
-        ass_drawing_set_text(drawing, text.start, text.end - text.start);
-    }
 
-    return 1;
+    struct arg text = args[nargs - 1];
+    render_priv->state.clip_drawing_text = strndup(text.start, text.end - text.start);
+    render_priv->state.clip_drawing_scale = scale;
+    return true;
 }
 
 /**
@@ -361,7 +352,7 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr,
                 render_priv->state.clip_y1 =
                     render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr;
                 render_priv->state.clip_mode = 1;
-            } else if (!render_priv->state.clip_drawing) {
+            } else if (!render_priv->state.clip_drawing_text) {
                 if (parse_vector_clip(render_priv, args, nargs))
                     render_priv->state.clip_drawing_mode = 1;
             }
@@ -682,7 +673,7 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr,
                 render_priv->state.clip_y1 =
                     render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr;
                 render_priv->state.clip_mode = 0;
-            } else if (!render_priv->state.clip_drawing) {
+            } else if (!render_priv->state.clip_drawing_text) {
                 if (parse_vector_clip(render_priv, args, nargs))
                     render_priv->state.clip_drawing_mode = 0;
             }
index 5648aff81cf2afaaa954ef6f7cd78ead0fc80666..128a0dc56ce443eaa9e43d86607cd3d3eafbcd80 100644 (file)
@@ -456,15 +456,14 @@ static inline size_t bitmap_size(Bitmap *bm)
 static void blend_vector_clip(ASS_Renderer *render_priv,
                               ASS_Image *head)
 {
-    ASS_Drawing *drawing = render_priv->state.clip_drawing;
-    if (!drawing)
+    if (!render_priv->state.clip_drawing_text)
         return;
 
     // Try to get mask from cache
     BitmapHashKey key;
     memset(&key, 0, sizeof(key));
     key.type = BITMAP_CLIP;
-    key.u.clip.text = drawing->text;
+    key.u.clip.text = render_priv->state.clip_drawing_text;
 
     BitmapHashValue *val;
     if (!ass_cache_get(render_priv->cache.bitmap_cache, &key, &val)) {
@@ -473,8 +472,13 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
         val->bm = val->bm_o = NULL;
 
         // Not found in cache, parse and rasterize it
-        ASS_Outline *outline = ass_drawing_parse(drawing, true);
-        if (!outline) {
+        ASS_Drawing drawing;
+        drawing.text = render_priv->state.clip_drawing_text;
+        drawing.scale = render_priv->state.clip_drawing_scale;
+        drawing.pbo = 0;
+        drawing.scale_x = render_priv->font_scale_x * render_priv->font_scale;
+        drawing.scale_y = render_priv->font_scale;
+        if (!ass_drawing_parse(&drawing, render_priv->library, true)) {
             ass_msg(render_priv->library, MSGL_WARN,
                     "Clip vector parsing failed. Skipping.");
             ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
@@ -489,12 +493,13 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
                 .x = int_to_d6(render_priv->settings.left_margin),
                 .y = int_to_d6(render_priv->settings.top_margin),
             };
-            outline_translate(outline, trans.x, trans.y);
+            outline_translate(&drawing.outline, trans.x, trans.y);
         }
 
-        val->bm = outline_to_bitmap(render_priv, outline, NULL, 1);
+        val->bm = outline_to_bitmap(render_priv, &drawing.outline, NULL, 1);
         ass_cache_commit(val, bitmap_size(val->bm) +
                          sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
+        outline_free(&drawing.outline);
     }
 
     Bitmap *clip_bm = val->bm;
@@ -896,15 +901,15 @@ static void free_render_context(ASS_Renderer *render_priv)
 {
     ass_cache_dec_ref(render_priv->state.font);
     free(render_priv->state.family);
-    ass_drawing_free(render_priv->state.clip_drawing);
+    free(render_priv->state.clip_drawing_text);
 
     render_priv->state.font = NULL;
     render_priv->state.family = NULL;
-    render_priv->state.clip_drawing = NULL;
+    render_priv->state.clip_drawing_text = NULL;
 
     TextInfo *text_info = &render_priv->text_info;
     for (int n = 0; n < text_info->length; n++)
-        ass_drawing_free(text_info->glyphs[n].drawing);
+        free(text_info->glyphs[n].drawing_text);
     text_info->length = 0;
 }
 
@@ -962,7 +967,7 @@ static void
 fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key,
                 GlyphInfo *info)
 {
-    if (info->drawing) {
+    if (info->drawing_text) {
         DrawingHashKey *key = &outline_key->u.drawing;
         outline_key->type = OUTLINE_DRAWING;
         key->scale_x = double_to_d16(info->scale_x);
@@ -974,9 +979,9 @@ fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key,
         // so for normal borders, maximize cache utility by ignoring it
         key->hspacing =
             info->border_style == 3 ? double_to_d16(info->hspacing) : 0;
-        key->text = info->drawing->text;
-        key->pbo = info->drawing->pbo;
-        key->scale = info->drawing->scale;
+        key->text = info->drawing_text;
+        key->pbo = info->drawing_pbo;
+        key->scale = info->drawing_scale;
     } else {
         GlyphHashKey *key = &outline_key->u.glyph;
         outline_key->type = OUTLINE_GLYPH;
@@ -1028,17 +1033,22 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
             return;
         memset(val, 0, sizeof(*val));
 
-        if (info->drawing) {
-            ASS_Drawing *drawing = info->drawing;
-            if(!ass_drawing_parse(drawing, false) ||
-                    !outline_copy(&val->outline, &drawing->outline)) {
+        if (info->drawing_text) {
+            ASS_Drawing drawing;
+            drawing.text = info->drawing_text;
+            drawing.scale = info->drawing_scale;
+            drawing.pbo = info->drawing_pbo;
+            drawing.scale_x = info->scale_x * priv->font_scale;
+            drawing.scale_y = info->scale_y * priv->font_scale;
+            if (!ass_drawing_parse(&drawing, priv->library, false)) {
                 ass_cache_commit(val, 1);
                 ass_cache_dec_ref(val);
                 return;
             }
-            val->advance = drawing->advance;
-            val->asc = drawing->asc;
-            val->desc = drawing->desc;
+            outline_move(&val->outline, &drawing.outline);
+            val->advance = drawing.advance;
+            val->asc = drawing.asc;
+            val->desc = drawing.desc;
         } else {
             ass_face_set_size(info->font->faces[info->face_index],
                               info->font_size);
@@ -1069,7 +1079,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
 
         if (info->border_style == 3) {
             int advance;
-            if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing)
+            if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing_text)
                 advance = val->advance;
             else
                 advance = info->advance.x;
@@ -1107,7 +1117,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
     info->border[0] = &val->border[0];
     info->border[1] = &val->border[1];
     info->bbox = val->bbox_scaled;
-    if (info->drawing || priv->settings.shaper == ASS_SHAPING_SIMPLE) {
+    if (info->drawing_text || priv->settings.shaper == ASS_SHAPING_SIMPLE) {
         info->cluster_advance.x = info->advance.x = val->advance;
         info->cluster_advance.y = info->advance.y = 0;
     }
@@ -1623,7 +1633,7 @@ fix_glyph_scaling(ASS_Renderer *priv, GlyphInfo *glyph)
 static int is_new_bm_run(GlyphInfo *info, GlyphInfo *last)
 {
     // FIXME: Don't break on glyph substitutions
-    return !last || info->effect || info->drawing || last->drawing ||
+    return !last || info->effect || info->drawing_text || last->drawing_text ||
         strcmp(last->font->desc.family, info->font->desc.family) ||
         last->font->desc.vertical != info->font->desc.vertical ||
         last->face_index != info->face_index ||
@@ -1691,18 +1701,15 @@ static void make_shadow_bitmap(CombinedBitmapInfo *info, ASS_Renderer *render_pr
 static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
 {
     TextInfo *text_info = &render_priv->text_info;
-    ASS_Drawing *drawing = NULL;
-    unsigned code;
-    char *p, *q;
-    int i;
 
-    p = event->Text;
+    char *p = event->Text, *q;
 
     // Event parsing.
     while (1) {
         // get next char, executing style override
         // this affects render_context
-        code = 0;
+        unsigned code = 0;
+        char *drawing_text = NULL;
         while (*p) {
             if ((*p == '{') && (q = strchr(p, '}'))) {
                 p = parse_tags(render_priv, p, q, 1., false);
@@ -1714,12 +1721,7 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
                     q++;
                 while ((*q != '{') && (*q != 0))
                     q++;
-                if (!drawing) {
-                    drawing = ass_drawing_new(render_priv->library);
-                    if (!drawing)
-                        return 1;
-                }
-                ass_drawing_set_text(drawing, p, q - p);
+                drawing_text = strndup(p, q - p);
                 code = 0xfffc; // object replacement character
                 p = q;
                 break;
@@ -1735,7 +1737,7 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
         // face could have been changed in get_next_char
         if (!render_priv->state.font) {
             free_render_context(render_priv);
-            ass_drawing_free(drawing);
+            free(drawing_text);
             return 1;
         }
 
@@ -1753,23 +1755,18 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
         memset(info, 0, sizeof(GlyphInfo));
 
         // Parse drawing
-        if (drawing && drawing->text) {
-            drawing->scale_x = render_priv->state.scale_x *
-                                     render_priv->font_scale;
-            drawing->scale_y = render_priv->state.scale_y *
-                                     render_priv->font_scale;
-            drawing->scale = render_priv->state.drawing_scale;
-            drawing->pbo = render_priv->state.pbo;
-            info->drawing = drawing;
-            drawing = NULL;
+        if (drawing_text) {
+            info->drawing_text = drawing_text;
+            info->drawing_scale = render_priv->state.drawing_scale;
+            info->drawing_pbo = render_priv->state.pbo;
         }
 
         // Fill glyph information
         info->symbol = code;
         info->font = render_priv->state.font;
-        if (!info->drawing)
+        if (!drawing_text)
             ass_cache_inc_ref(info->font);
-        for (i = 0; i < 4; ++i) {
+        for (int i = 0; i < 4; i++) {
             uint32_t clr = render_priv->state.c[i];
             // VSFilter compatibility: apply fade only when it's positive
             if (render_priv->state.fade > 0)
@@ -1802,7 +1799,7 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
         info->fax = render_priv->state.fax;
         info->fay = render_priv->state.fay;
 
-        if (!info->drawing)
+        if (!drawing_text)
             fix_glyph_scaling(render_priv, info);
 
         text_info->length++;
@@ -1812,8 +1809,6 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
         render_priv->state.effect_skip_timing = 0;
     }
 
-    ass_drawing_free(drawing);
-
     return 0;
 }
 
index c8132fc9906d8994a6133f4335ea4dfdacf4cdd5..f2af0b7aeb0db0598e63a3aa5ff69d16a81fc9eb 100644 (file)
@@ -130,7 +130,9 @@ typedef struct glyph_info {
     int script;
 #endif
     double font_size;
-    ASS_Drawing *drawing;
+    char *drawing_text;
+    int drawing_scale;
+    int drawing_pbo;
     ASS_Outline *outline;
     ASS_Outline *border[2];
     ASS_Rect bbox;
@@ -229,7 +231,8 @@ typedef struct {
     double shadow_y;
     int drawing_scale;          // currently reading: regular text if 0, drawing otherwise
     double pbo;                 // drawing baseline offset
-    ASS_Drawing *clip_drawing;  // clip vector
+    char *clip_drawing_text;
+    int clip_drawing_scale;
     int clip_drawing_mode;      // 0 = regular clip, 1 = inverse clip
 
     Effect effect_type;