diff options
author | Grigori Goronzy <greg@blackbox> | 2011-07-04 15:19:40 +0200 |
---|---|---|
committer | Grigori Goronzy <greg@blackbox> | 2011-07-04 15:19:40 +0200 |
commit | f905a38536ad32f7a68ab86db736495fc06810b2 (patch) | |
tree | c779db060f86e257040fba61f9abe33c82c00dcb /libass | |
parent | 910728cb031f59fc0c5972e3b5c7cf2615a1c319 (diff) | |
download | libass-f905a38536ad32f7a68ab86db736495fc06810b2.tar.bz2 libass-f905a38536ad32f7a68ab86db736495fc06810b2.tar.xz |
Separate event parsing and layout
Split up the combined event parsing and layout loop into two passes.
State information needed for layout are duplicated in GlyphInfo
structures.
Diffstat (limited to 'libass')
-rw-r--r-- | libass/ass_parse.c | 13 | ||||
-rw-r--r-- | libass/ass_parse.h | 1 | ||||
-rw-r--r-- | libass/ass_render.c | 260 | ||||
-rw-r--r-- | libass/ass_render.h | 7 |
4 files changed, 148 insertions, 133 deletions
diff --git a/libass/ass_parse.c b/libass/ass_parse.c index a0181bd..afa0019 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -47,17 +47,18 @@ static inline int mystrcmp(char **p, const char *sample) return 0; } -static void change_font_size(ASS_Renderer *render_priv, double sz) +double ensure_font_size(ASS_Renderer *priv, double size) { - double size = sz * render_priv->font_scale; - if (size < 1) size = 1; - else if (size > render_priv->height * 2) - size = render_priv->height * 2; + else if (size > priv->height * 2) + size = priv->height * 2; - ass_font_set_size(render_priv->state.font, size); + return size; +} +static void change_font_size(ASS_Renderer *render_priv, double sz) +{ render_priv->state.font_size = sz; } diff --git a/libass/ass_parse.h b/libass/ass_parse.h index b0e4e14..2e145dc 100644 --- a/libass/ass_parse.h +++ b/libass/ass_parse.h @@ -27,6 +27,7 @@ #define _a(c) ((c) & 0xFF) void update_font(ASS_Renderer *render_priv); +double ensure_font_size(ASS_Renderer *priv, double size); void change_border(ASS_Renderer *render_priv, double border_x, double border_y); void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); diff --git a/libass/ass_render.c b/libass/ass_render.c index 307b1e8..f4fd67c 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -1028,40 +1028,39 @@ static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline, */ static void fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key, - ASS_Drawing *drawing, uint32_t ch) + GlyphInfo *info) { - if (drawing->hash) { + if (info->drawing) { DrawingHashKey *key = &outline_key->u.drawing; outline_key->type = OUTLINE_DRAWING; - key->scale_x = double_to_d16(priv->state.scale_x); - key->scale_y = double_to_d16(priv->state.scale_y); - key->outline.x = double_to_d16(priv->state.border_x); - key->outline.y = double_to_d16(priv->state.border_y); + key->scale_x = double_to_d16(info->scale_x); + key->scale_y = double_to_d16(info->scale_y); + key->outline.x = double_to_d16(info->border_x); + key->outline.y = double_to_d16(info->border_y); key->border_style = priv->state.style->BorderStyle; - key->hash = drawing->hash; - key->text = strdup(drawing->text); - key->pbo = drawing->pbo; - key->scale = drawing->scale; + key->hash = info->drawing->hash; + key->text = strdup(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; - key->font = priv->state.font; - key->size = priv->state.font_size; - key->ch = ch; - key->bold = priv->state.bold; - key->italic = priv->state.italic; - key->scale_x = double_to_d16(priv->state.scale_x); - key->scale_y = double_to_d16(priv->state.scale_y); - key->outline.x = double_to_d16(priv->state.border_x); - key->outline.y = double_to_d16(priv->state.border_y); - key->flags = priv->state.flags; + key->font = info->font; + key->size = info->font_size; + key->ch = info->symbol; + key->bold = info->bold; + key->italic = info->italic; + key->scale_x = double_to_d16(info->scale_x); + key->scale_y = double_to_d16(info->scale_y); + key->outline.x = double_to_d16(info->border_x); + key->outline.y = double_to_d16(info->border_y); + key->flags = info->flags; key->border_style = priv->state.style->BorderStyle; } } /** * \brief Get normal and outline (border) glyphs - * \param symbol ucs4 char * \param info out: struct filled with extracted data * Tries to get both glyphs from cache. * If they can't be found, gets a glyph from font face, generates outline with FT_Stroker, @@ -1069,17 +1068,14 @@ fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key, * The glyphs are returned in info->glyph and info->outline_glyph */ static void -get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, - ASS_Drawing *drawing) +get_outline_glyph(ASS_Renderer *render_priv, GlyphInfo *info) { OutlineHashValue *val; OutlineHashKey key; - memset(&key, 0, sizeof(key)); - memset(info, 0, sizeof(GlyphInfo)); + memset(&info->hash_key, 0, sizeof(key)); - info->italic = render_priv->state.italic; - fill_glyph_hash(render_priv, &key, drawing, symbol); + fill_glyph_hash(render_priv, &key, info); val = ass_cache_get(render_priv->cache.outline_cache, &key); if (val) { info->hash_key.u.outline.outline = val; @@ -1092,7 +1088,9 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, info->desc = val->desc; } else { OutlineHashValue v; - if (drawing->hash) { + if (info->drawing) { + ASS_Drawing *drawing = info->drawing; + ass_drawing_hash(drawing); if(!ass_drawing_parse(drawing, 0)) return; outline_copy(render_priv->ftlibrary, &drawing->outline, @@ -1101,22 +1099,27 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, info->advance.y = drawing->advance.y; info->asc = drawing->asc; info->desc = drawing->desc; + ass_drawing_free(drawing); } else { + double size_scaled = ensure_font_size(render_priv, + info->font_size * render_priv->font_scale); + ass_font_set_size(info->font, size_scaled); + ass_font_set_transform(info->font, info->scale_x, + info->scale_y, NULL); FT_Glyph glyph = - ass_font_get_glyph(render_priv->fontconfig_priv, - render_priv->state.font, symbol, - render_priv->settings.hinting, - render_priv->state.flags); + ass_font_get_glyph(render_priv->fontconfig_priv, info->font, + info->symbol, render_priv->settings.hinting, + info->flags); if (glyph != NULL) { outline_copy(render_priv->ftlibrary, &((FT_OutlineGlyph)glyph)->outline, &info->outline); info->advance.x = d16_to_d6(glyph->advance.x); info->advance.y = d16_to_d6(glyph->advance.y); FT_Done_Glyph(glyph); - ass_font_get_asc_desc(render_priv->state.font, symbol, + ass_font_get_asc_desc(info->font, info->symbol, &info->asc, &info->desc); - info->asc *= render_priv->state.scale_y; - info->desc *= render_priv->state.scale_y; + info->asc *= info->scale_y; + info->desc *= info->scale_y; } } if (!info->outline) @@ -1125,26 +1128,21 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, FT_Outline_Get_CBox(info->outline, &info->bbox); if (render_priv->state.style->BorderStyle == 3 && - (render_priv->state.border_x > 0|| - render_priv->state.border_y > 0)) { + (info->border_x > 0|| info->border_y > 0)) { outline_copy(render_priv->ftlibrary, info->outline, &info->border); - draw_opaque_box(render_priv, symbol, info->border, + draw_opaque_box(render_priv, info->symbol, info->border, info->advance, - double_to_d6(render_priv->state.border_x * + double_to_d6(info->border_x * render_priv->border_scale), - double_to_d6(render_priv->state.border_y * + double_to_d6(info->border_y * render_priv->border_scale)); - } else if ((render_priv->state.border_x > 0 - || render_priv->state.border_y > 0) - && double_to_d6(render_priv->state.scale_x) - && double_to_d6(render_priv->state.scale_y)) { + } else if ((info->border_x > 0 || info->border_y > 0) + && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { outline_copy(render_priv->ftlibrary, info->outline, &info->border); stroke_outline(render_priv, info->border, - double_to_d6(render_priv->state.border_x * - render_priv->border_scale), - double_to_d6(render_priv->state.border_y * - render_priv->border_scale)); + double_to_d6(info->border_x * render_priv->border_scale), + double_to_d6(info->border_y * render_priv->border_scale)); } memset(&v, 0, sizeof(v)); @@ -1628,21 +1626,22 @@ static void get_base_point(DBBox *bbox, int alignment, double *bx, double *by) * Prepare bitmap hash key of a glyph */ static void -fill_bitmap_hash(ASS_Renderer *priv, OutlineBitmapHashKey *hash_key) +fill_bitmap_hash(ASS_Renderer *priv, GlyphInfo *info, + OutlineBitmapHashKey *hash_key) { - hash_key->frx = rot_key(priv->state.frx); - hash_key->fry = rot_key(priv->state.fry); - hash_key->frz = rot_key(priv->state.frz); - hash_key->fax = double_to_d16(priv->state.fax); - hash_key->fay = double_to_d16(priv->state.fay); - hash_key->be = priv->state.be; - hash_key->blur = priv->state.blur; + hash_key->frx = rot_key(info->frx); + hash_key->fry = rot_key(info->fry); + hash_key->frz = rot_key(info->frz); + hash_key->fax = double_to_d16(info->fax); + hash_key->fay = double_to_d16(info->fay); + hash_key->be = info->be; + hash_key->blur = info->blur; hash_key->shadow_offset.x = double_to_d6( - priv->state.shadow_x * priv->border_scale - - (int) (priv->state.shadow_x * priv->border_scale)); + info->shadow_x * priv->border_scale - + (int) (info->shadow_x * priv->border_scale)); hash_key->shadow_offset.y = double_to_d6( - priv->state.shadow_y * priv->border_scale - - (int) (priv->state.shadow_y * priv->border_scale)); + info->shadow_y * priv->border_scale - + (int) (info->shadow_y * priv->border_scale)); } /** @@ -1685,11 +1684,9 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, drawing = render_priv->state.drawing; text_info->length = 0; - pen.x = 0; - pen.y = 0; - previous = 0; num_glyphs = 0; p = event->Text; + // Event parsing. while (1) { // get next char, executing style override @@ -1700,15 +1697,26 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, ass_drawing_add_char(drawing, (char) code); } while (code && render_priv->state.drawing_mode); // skip everything in drawing mode + if (text_info->length >= text_info->max_glyphs) { + // Raise maximum number of glyphs + text_info->max_glyphs *= 2; + text_info->glyphs = glyphs = + realloc(text_info->glyphs, + sizeof(GlyphInfo) * text_info->max_glyphs); + } + + // Clear current GlyphInfo + memset(&glyphs[text_info->length], 0, sizeof(GlyphInfo)); + // Parse drawing if (drawing->i) { drawing->scale_x = render_priv->state.scale_x * render_priv->font_scale; drawing->scale_y = render_priv->state.scale_y * render_priv->font_scale; - ass_drawing_hash(drawing); p--; - code = -1; + code = 0xfffc; // object replacement character + glyphs[text_info->length].drawing = drawing; } // face could have been changed in get_next_char @@ -1720,61 +1728,9 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, if (code == 0) break; - if (text_info->length >= text_info->max_glyphs) { - // Raise maximum number of glyphs - text_info->max_glyphs *= 2; - text_info->glyphs = glyphs = - realloc(text_info->glyphs, - sizeof(GlyphInfo) * text_info->max_glyphs); - } - - // Add kerning to pen - if (kern && previous && code && !drawing->hash) { - FT_Vector delta; - delta = - ass_font_get_kerning(render_priv->state.font, previous, - code); - pen.x += delta.x * render_priv->state.scale_x; - pen.y += delta.y * render_priv->state.scale_y; - } - - ass_font_set_transform(render_priv->state.font, - render_priv->state.scale_x, - render_priv->state.scale_y, NULL); - - get_outline_glyph(render_priv, code, - glyphs + text_info->length, drawing); - - // Add additional space after italic to non-italic style changes - if (text_info->length && - glyphs[text_info->length - 1].italic && - !render_priv->state.italic) { - int back = text_info->length - 1; - GlyphInfo *og = &glyphs[back]; - while (back && og->bbox.xMax - og->bbox.xMin == 0 - && og->italic) - og = &glyphs[--back]; - if (og->bbox.xMax > og->advance.x) { - // The FreeType oblique slants by 6/16 - pen.x += og->bbox.yMax * 0.375; - } - } - - glyphs[text_info->length].pos.x = pen.x; - glyphs[text_info->length].pos.y = pen.y; - - pen.x += glyphs[text_info->length].advance.x; - pen.x += double_to_d6(render_priv->state.hspacing * - render_priv->font_scale - * render_priv->state.scale_x); - pen.y += glyphs[text_info->length].advance.y; - pen.y += (render_priv->state.fay * render_priv->state.scale_y) * - glyphs[text_info->length].advance.x; - - previous = code; - + // Fill glyph information glyphs[text_info->length].symbol = code; - glyphs[text_info->length].linebreak = 0; + glyphs[text_info->length].font = render_priv->state.font; for (i = 0; i < 4; ++i) { uint32_t clr = render_priv->state.c[i]; change_alpha(&clr, @@ -1786,10 +1742,18 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, render_priv->state.effect_timing; glyphs[text_info->length].effect_skip_timing = render_priv->state.effect_skip_timing; + glyphs[text_info->length].font_size = render_priv->state.font_size; glyphs[text_info->length].be = render_priv->state.be; glyphs[text_info->length].blur = render_priv->state.blur; glyphs[text_info->length].shadow_x = render_priv->state.shadow_x; glyphs[text_info->length].shadow_y = render_priv->state.shadow_y; + glyphs[text_info->length].scale_x= render_priv->state.scale_x; + glyphs[text_info->length].scale_y = render_priv->state.scale_y; + glyphs[text_info->length].border_x= render_priv->state.border_x; + glyphs[text_info->length].border_y = render_priv->state.border_y; + glyphs[text_info->length].bold = render_priv->state.bold; + glyphs[text_info->length].italic = render_priv->state.italic; + glyphs[text_info->length].flags = render_priv->state.flags; glyphs[text_info->length].frx = render_priv->state.frx; glyphs[text_info->length].fry = render_priv->state.fry; glyphs[text_info->length].frz = render_priv->state.frz; @@ -1797,9 +1761,10 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, 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; - fill_bitmap_hash(render_priv, &glyphs[text_info->length].hash_key.u.outline); + if (glyphs[text_info->length].drawing) { + drawing = render_priv->state.drawing = + ass_drawing_new(render_priv->library, render_priv->ftlibrary); + } text_info->length++; @@ -1807,13 +1772,54 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, render_priv->state.effect_timing = 0; render_priv->state.effect_skip_timing = 0; - if (drawing->hash) { - ass_drawing_free(drawing); - drawing = render_priv->state.drawing = - ass_drawing_new(render_priv->library, render_priv->ftlibrary); - } } + // Retrieve and layout outline glyphs into a line + previous = 0; + pen.x = 0; + pen.y = 0; + for (i = 0; i < text_info->length; i++) { + GlyphInfo *info = glyphs + i; + + // Add kerning to pen + if (kern && previous && info->symbol && !info->drawing) { + FT_Vector delta; + delta = ass_font_get_kerning(info->font, previous, info->symbol); + pen.x += delta.x * info->scale_x; + pen.y += delta.y * info->scale_y; + } + + // Retrieve outline + get_outline_glyph(render_priv, info); + + // Add additional space after italic to non-italic style changes + if (i && glyphs[i - 1].italic && !info->italic) { + int back = i - 1; + GlyphInfo *og = &glyphs[back]; + while (back && og->bbox.xMax - og->bbox.xMin == 0 + && og->italic) + og = &glyphs[--back]; + if (og->bbox.xMax > og->advance.x) { + // The FreeType oblique slants by 6/16 + pen.x += og->bbox.yMax * 0.375; + } + } + + info->pos.x = pen.x; + info->pos.y = pen.y; + + pen.x += info->advance.x; + pen.x += double_to_d6(render_priv->state.hspacing * + render_priv->font_scale * info->scale_x); + pen.y += info->advance.y; + pen.y += (info->fay * info->scale_y) * info->advance.x; + + previous = info->symbol; + + // fill bitmap hash + info->hash_key.type = BITMAP_OUTLINE; + fill_bitmap_hash(render_priv, info, &info->hash_key.u.outline); + } if (text_info->length == 0) { // no valid symbols in the event; this can be smth like {comment} diff --git a/libass/ass_render.h b/libass/ass_render.h index 2911731..ea72cd0 100644 --- a/libass/ass_render.h +++ b/libass/ass_render.h @@ -99,6 +99,9 @@ typedef enum { typedef struct { unsigned symbol; unsigned skip; // skip glyph when layouting text + ASS_Font *font; + double font_size; + ASS_Drawing *drawing; FT_Outline *outline; FT_Outline *border; Bitmap *bm; // glyph bitmap @@ -121,7 +124,11 @@ typedef struct { double shadow_y; double frx, fry, frz; // rotation double fax, fay; // text shearing + double scale_x, scale_y; + double border_x, border_y; unsigned italic; + unsigned bold; + int flags; int bm_run_id; |