summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@blackbox>2011-07-04 12:59:11 +0200
committerGrigori Goronzy <greg@blackbox>2011-07-04 12:59:11 +0200
commit53288ab83600d57f6082815183c068ab21959037 (patch)
treead7ab95115d80c3f48f572b0e2c327c82f93086b
parent0a539d83afef27b64228f5abd8f21c6e15972b0c (diff)
downloadlibass-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.c13
-rw-r--r--libass/ass_render.c62
-rw-r--r--libass/ass_render.h5
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,