From f905a38536ad32f7a68ab86db736495fc06810b2 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Mon, 4 Jul 2011 15:19:40 +0200 Subject: [PATCH] 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. --- libass/ass_parse.c | 13 +-- libass/ass_parse.h | 1 + libass/ass_render.c | 260 +++++++++++++++++++++++++++------------------------- 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; -- 2.11.4.GIT