diff options
author | Grigori Goronzy <greg@blackbox> | 2011-07-04 12:59:11 +0200 |
---|---|---|
committer | Grigori Goronzy <greg@blackbox> | 2011-07-04 12:59:11 +0200 |
commit | 53288ab83600d57f6082815183c068ab21959037 (patch) | |
tree | ad7ab95115d80c3f48f572b0e2c327c82f93086b | |
parent | 0a539d83afef27b64228f5abd8f21c6e15972b0c (diff) | |
download | libass-53288ab83600d57f6082815183c068ab21959037.tar.bz2 libass-53288ab83600d57f6082815183c068ab21959037.tar.xz |
Introduce bitmap runs
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.
-rw-r--r-- | libass/ass_parse.c | 13 | ||||
-rw-r--r-- | libass/ass_render.c | 62 | ||||
-rw-r--r-- | libass/ass_render.h | 5 |
3 files changed, 80 insertions, 0 deletions
diff --git a/libass/ass_parse.c b/libass/ass_parse.c index d9fcb76..a0181bd 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -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)) diff --git a/libass/ass_render.c b/libass/ass_render.c index aaa5778..307b1e8 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -798,6 +798,37 @@ static void compute_string_bbox(TextInfo *info, DBBox *bbox) } /** + * \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; diff --git a/libass/ass_render.h b/libass/ass_render.h index 80ec394..a204145 100644 --- a/libass/ass_render.h +++ b/libass/ass_render.h @@ -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, |