summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@blackbox>2011-07-04 15:19:40 +0200
committerGrigori Goronzy <greg@blackbox>2011-07-04 15:19:40 +0200
commitf905a38536ad32f7a68ab86db736495fc06810b2 (patch)
treec779db060f86e257040fba61f9abe33c82c00dcb
parent910728cb031f59fc0c5972e3b5c7cf2615a1c319 (diff)
downloadlibass-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.
-rw-r--r--libass/ass_parse.c13
-rw-r--r--libass/ass_parse.h1
-rw-r--r--libass/ass_render.c260
-rw-r--r--libass/ass_render.h7
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;