summaryrefslogtreecommitdiffstats
path: root/libass
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 /libass
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.
Diffstat (limited to 'libass')
-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;