]> granicus.if.org Git - libass/commitdiff
Introduce bitmap runs
authorGrigori Goronzy <greg@blackbox>
Mon, 4 Jul 2011 10:59:11 +0000 (12:59 +0200)
committerGrigori Goronzy <greg@blackbox>
Mon, 4 Jul 2011 10:59:11 +0000 (12:59 +0200)
Prepare for run-based rendering. In the parser, increment a run id
according to relevant style changes (color, border, shadow, etc.) to
mark the points where a new bitmap needs to be started. Modify the line
wrapper to increment the run ids of each glyph after a break.
Add functions to calculate the render size of runs for rasterization.

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

index d9fcb76d24492ff43ce61636e52a3cc7e874f925..a0181bdf84b47cae8e668842bfabc94b51b0b9f4 100644 (file)
@@ -255,6 +255,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
         else
             val = -1.;
         change_border(render_priv, val, render_priv->state.border_y);
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "ybord")) {
         double val;
         if (mystrtod(&p, &val))
@@ -269,6 +270,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
         else
             val = 0.;
         render_priv->state.shadow_x = val;
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "yshad")) {
         double val;
         if (mystrtod(&p, &val))
@@ -276,6 +278,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
         else
             val = 0.;
         render_priv->state.shadow_y = val;
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "fax")) {
         double val;
         if (mystrtod(&p, &val))
@@ -327,6 +330,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
             render_priv->state.blur = val;
         } else
             render_priv->state.blur = 0.0;
+        render_priv->state.bm_run_id++;
         // ASS standard tags
     } else if (mystrcmp(&p, "fsc")) {
         char tp = *p++;
@@ -387,6 +391,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
         } else
             val = -1.;          // reset to default
         change_border(render_priv, val, val);
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "move")) {
         double x1, x2, y1, y2;
         long long t1, t2, delta_t, t;
@@ -488,6 +493,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
             change_alpha(&render_priv->state.c[3],
                          render_priv->state.style->BackColour, pwr);
         }
+        render_priv->state.bm_run_id++;
         // FIXME: simplify
     } else if (mystrcmp(&p, "an")) {
         int val;
@@ -678,6 +684,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
             val = render_priv->state.style->PrimaryColour;
         ass_msg(render_priv->library, MSGL_DBG2, "color: %X", val);
         change_color(&render_priv->state.c[0], val, pwr);
+        render_priv->state.bm_run_id++;
     } else if ((*p >= '1') && (*p <= '4') && (++p)
                && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) {
         char n = *(p - 2);
@@ -707,9 +714,11 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
         switch (cmd) {
         case 'c':
             change_color(render_priv->state.c + cidx, val, pwr);
+            render_priv->state.bm_run_id++;
             break;
         case 'a':
             change_alpha(render_priv->state.c + cidx, val >> 24, pwr);
+            render_priv->state.bm_run_id++;
             break;
         default:
             ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c",
@@ -729,6 +738,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
             render_priv->state.be = val;
         } else
             render_priv->state.be = 0;
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "b")) {
         int b;
         if (mystrtoi(&p, &b)) {
@@ -777,18 +787,21 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
         } else
             val = 0.;
         render_priv->state.shadow_x = render_priv->state.shadow_y = val;
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "s")) {
         int val;
         if (mystrtoi(&p, &val) && val)
             render_priv->state.flags |= DECO_STRIKETHROUGH;
         else
             render_priv->state.flags &= ~DECO_STRIKETHROUGH;
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "u")) {
         int val;
         if (mystrtoi(&p, &val) && val)
             render_priv->state.flags |= DECO_UNDERLINE;
         else
             render_priv->state.flags &= ~DECO_UNDERLINE;
+        render_priv->state.bm_run_id++;
     } else if (mystrcmp(&p, "pbo")) {
         double val = 0;
         if (mystrtod(&p, &val))
index aaa5778ebe15368aee77deb9036adaa46ec0d431..307b1e8e486dd09901644d24fd0ab893543378c7 100644 (file)
@@ -797,6 +797,37 @@ static void compute_string_bbox(TextInfo *info, DBBox *bbox)
         bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
 }
 
+/**
+  * \brief Compute the size of the target bitmap for a run of outlines.
+  * \param run first outline of the run
+  * \param len run length
+  * \param w returns target width, in pixels
+  * \param h returns target height, in pixels
+  */
+static void compute_run_size(GlyphInfo *run, size_t len, int *w, int *h)
+{
+    int i;
+    FT_BBox bbox;
+    bbox.xMin = bbox.yMin = INT_MAX;
+    bbox.xMax = bbox.yMax = INT_MIN;
+
+    for (i = 0; i < len; i++) {
+        GlyphInfo *info = run + i;
+        if (info->skip || info->symbol == 0 || info->symbol == '\n')
+            continue;
+        bbox.xMin = FFMIN(bbox.xMin, info->pos.x + info->bbox.xMin);
+        bbox.yMin = FFMIN(bbox.yMin, info->pos.y + info->bbox.yMin);
+        bbox.xMax = FFMAX(bbox.xMax, info->pos.x + info->bbox.xMax);
+        bbox.yMax = FFMAX(bbox.yMax, info->pos.y + info->bbox.yMax);
+    }
+    bbox.xMin &= ~63;
+    bbox.yMin &= ~63;
+    bbox.xMax = (bbox.xMax + 63) & ~63;
+    bbox.yMax = (bbox.yMax + 63) & ~63;
+    *w = (bbox.xMax - bbox.xMin) >> 6;
+    *h = (bbox.yMax - bbox.yMin) >> 6;
+}
+
 /**
  * \brief partially reset render_context to style values
  * Works like {\r}: resets some style overrides
@@ -865,6 +896,7 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
     render_priv->state.effect_type = EF_NONE;
     render_priv->state.effect_timing = 0;
     render_priv->state.effect_skip_timing = 0;
+    render_priv->state.bm_run_id = 0;
     ass_drawing_free(render_priv->state.drawing);
     render_priv->state.drawing = ass_drawing_new(render_priv->library,
             render_priv->ftlibrary);
@@ -1416,6 +1448,7 @@ wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width)
     double pen_shift_x;
     double pen_shift_y;
     int cur_line;
+    int run_offset;
     TextInfo *text_info = &render_priv->text_info;
 
     last_space = -1;
@@ -1525,6 +1558,7 @@ wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width)
     pen_shift_x = 0.;
     pen_shift_y = 0.;
     cur_line = 1;
+    run_offset = 0;
 
     i = 0;
     cur = text_info->glyphs + i;
@@ -1541,12 +1575,14 @@ wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width)
                 text_info->lines[cur_line - 1].desc +
                 text_info->lines[cur_line].asc;
             cur_line++;
+            run_offset++;
             pen_shift_x = d6_to_double(-cur->pos.x);
             pen_shift_y += height + render_priv->settings.line_spacing;
             ass_msg(render_priv->library, MSGL_DBG2,
                    "shifting from %d to %d by (%f, %f)", i,
                    text_info->length - 1, pen_shift_x, pen_shift_y);
         }
+        cur->bm_run_id += run_offset;
         cur->pos.x += double_to_d6(pen_shift_x);
         cur->pos.y += double_to_d6(pen_shift_y);
     }
@@ -1759,6 +1795,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
         glyphs[text_info->length].frz = render_priv->state.frz;
         glyphs[text_info->length].fax = render_priv->state.fax;
         glyphs[text_info->length].fay = render_priv->state.fay;
+        glyphs[text_info->length].bm_run_id = render_priv->state.bm_run_id;
 
         // fill bitmap hash
         glyphs[text_info->length].hash_key.type = BITMAP_OUTLINE;
@@ -2000,6 +2037,31 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
         get_bitmap_glyph(render_priv, glyphs + i);
     }
 
+    // Compute runs and their bboxes
+    // XXX: currently does nothing visible/functional
+    for (i = 0; i < text_info->length; i++) {
+        GlyphInfo *g = glyphs + i;
+        OutlineBitmapHashKey *key = &g->hash_key.u.outline;
+        int w, h;
+
+        // skip non-visual glyphs
+        if (g->skip || g->symbol == '\n' || g->symbol == 0)
+            continue;
+
+        // Determine run length and compute run bbox
+        int run_len = 0;
+        int cur_run = g->bm_run_id;
+        while (g->bm_run_id == cur_run && (i + run_len) < text_info->length) {
+            g++;
+            run_len++;
+        }
+        g = glyphs + i;
+        compute_run_size(g, run_len, &w, &h);
+        //printf("run_id %d len %d size %d %d\n", g->bm_run_id, run_len, w, h);
+
+        i += run_len - 1;
+    }
+
     memset(event_images, 0, sizeof(*event_images));
     event_images->top = device_y - text_info->lines[0].asc;
     event_images->height = text_info->height;
index 80ec394a6500ccdcbcf8b75ff29ee50517a85b4d..a204145c3afe80e2ae73896a4c8ae8cdc48b3f4f 100644 (file)
@@ -123,6 +123,8 @@ typedef struct {
     double fax, fay;            // text shearing
     unsigned italic;
 
+    int bm_run_id;
+
     BitmapHashKey hash_key;
 } GlyphInfo;
 
@@ -187,6 +189,9 @@ typedef struct {
     int effect_timing;
     int effect_skip_timing;
 
+    // bitmap run id (used for final bitmap rendering)
+    int bm_run_id;
+
     enum {
         SCROLL_LR,              // left-to-right
         SCROLL_RL,