summaryrefslogtreecommitdiffstats
path: root/libass/ass_render.c
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@blackbox>2011-06-20 22:50:34 +0200
committerGrigori Goronzy <greg@blackbox>2011-06-20 22:50:34 +0200
commite5704aa76a2712782442156986f74b8766077ee1 (patch)
tree755509f7c315f4b542b6bd8b2c5e190206cdf355 /libass/ass_render.c
parent3a0055a7bd1d6378aece89db0d17cc0ac804a89b (diff)
downloadlibass-e5704aa76a2712782442156986f74b8766077ee1.tar.bz2
libass-e5704aa76a2712782442156986f74b8766077ee1.tar.xz
Convert outline processing and caching from glyphs to bare outlines
This introduces functions to use and copy pointered outline objects easily and uses these instead of glyphs everywhere. Previously the glyph cache was abused for caching vector clipping masks, but this isn't possible anymore (nor desirable), thus vector clipping cache has been disabled for the moment.
Diffstat (limited to 'libass/ass_render.c')
-rw-r--r--libass/ass_render.c143
1 files changed, 73 insertions, 70 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 1d7f7a0..9a1b911 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -532,8 +532,8 @@ static void free_list_add(ASS_Renderer *render_priv, void *object)
static void blend_vector_clip(ASS_Renderer *render_priv,
ASS_Image *head)
{
- FT_Glyph glyph;
- FT_BitmapGlyph clip_bm;
+ FT_Outline *outline;
+ Bitmap *clip_bm = NULL;
ASS_Image *cur;
ASS_Drawing *drawing = render_priv->state.clip_drawing;
GlyphHashKey key;
@@ -543,6 +543,8 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
if (!drawing)
return;
+ // FIXME: reimplement cache
+#if 0
// Try to get mask from cache
ass_drawing_hash(drawing);
memset(&key, 0, sizeof(key));
@@ -553,11 +555,13 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
if (val) {
clip_bm = (FT_BitmapGlyph) val->glyph;
} else {
+#endif
GlyphHashValue v;
// Not found in cache, parse and rasterize it
- glyph = (FT_Glyph) *ass_drawing_parse(drawing, 1);
- if (!glyph) {
+ ass_drawing_parse(drawing, 1);
+ outline = &drawing->glyph->outline;
+ if (!outline) {
ass_msg(render_priv->library, MSGL_WARN,
"Clip vector parsing failed. Skipping.");
goto blend_vector_error;
@@ -574,33 +578,28 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
trans.x, trans.y);
}
- // Check glyph bounding box size
- if (check_glyph_area(render_priv->library, glyph)) {
- FT_Done_Glyph(glyph);
- glyph = 0;
- goto blend_vector_error;
- }
-
ass_msg(render_priv->library, MSGL_DBG2,
"Parsed vector clip: scales (%f, %f) string [%s]\n",
drawing->scale_x, drawing->scale_y, drawing->text);
- error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
- if (error) {
+ clip_bm = outline_to_bitmap(render_priv->library,
+ render_priv->ftlibrary, outline, 0);
+ if (clip_bm == NULL) {
ass_msg(render_priv->library, MSGL_WARN,
"Clip vector rasterization failed: %d. Skipping.", error);
- FT_Done_Glyph(glyph);
- glyph = 0;
+ FT_Outline_Done(render_priv->ftlibrary, outline);
}
-blend_vector_error:
- clip_bm = (FT_BitmapGlyph) glyph;
+ //clip_bm = (FT_BitmapGlyph) glyph;
+#if 0
// Add to cache
memset(&v, 0, sizeof(v));
v.glyph = glyph;
ass_cache_put(render_priv->cache.glyph_cache, &key, &v);
}
+#endif
+blend_vector_error:
if (!clip_bm) goto blend_vector_exit;
@@ -613,17 +612,17 @@ blend_vector_error:
unsigned char *abuffer, *bbuffer, *nbuffer;
abuffer = cur->bitmap;
- bbuffer = clip_bm->bitmap.buffer;
+ bbuffer = clip_bm->buffer;
ax = cur->dst_x;
ay = cur->dst_y;
aw = cur->w;
ah = cur->h;
as = cur->stride;
bx = clip_bm->left;
- by = -clip_bm->top;
- bw = clip_bm->bitmap.width;
- bh = clip_bm->bitmap.rows;
- bs = clip_bm->bitmap.pitch;
+ by = clip_bm->top;
+ bw = clip_bm->w;
+ bh = clip_bm->h;
+ bs = clip_bm->w; // XXX: add real stride support
// Calculate overlap coordinates
left = (ax > bx) ? ax : bx;
@@ -682,6 +681,8 @@ blend_vector_error:
}
blend_vector_exit:
+ ass_free_bitmap(clip_bm);
+ FT_Outline_Done(render_priv->ftlibrary, outline);
ass_drawing_free(render_priv->state.clip_drawing);
render_priv->state.clip_drawing = 0;
}
@@ -899,15 +900,13 @@ static void free_render_context(ASS_Renderer *render_priv)
* opaque rectangle.
*/
static void draw_opaque_box(ASS_Renderer *render_priv, uint32_t ch,
- FT_Glyph glyph, int sx, int sy)
+ FT_Outline *ol, FT_Vector advance, int sx, int sy)
{
int asc = 0, desc = 0;
int i;
- int adv = d16_to_d6(glyph->advance.x);
+ int adv = advance.x;
double scale_y = render_priv->state.scale_y;
double scale_x = render_priv->state.scale_x;
- FT_OutlineGlyph og = (FT_OutlineGlyph) glyph;
- FT_Outline *ol;
// to avoid gaps
sx = FFMAX(64, sx);
@@ -939,10 +938,9 @@ static void draw_opaque_box(ASS_Renderer *render_priv, uint32_t ch,
{ .x = -sx, .y = -desc - sy },
};
- FT_Outline_Done(render_priv->ftlibrary, &og->outline);
- FT_Outline_New(render_priv->ftlibrary, 4, 1, &og->outline);
+ FT_Outline_Done(render_priv->ftlibrary, ol);
+ FT_Outline_New(render_priv->ftlibrary, 4, 1, ol);
- ol = &og->outline;
ol->n_points = ol->n_contours = 0;
for (i = 0; i < 4; i++) {
ol->points[ol->n_points] = points[i];
@@ -1061,8 +1059,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
fill_glyph_hash(render_priv, &key, drawing, symbol);
val = ass_cache_get(render_priv->cache.glyph_cache, &key);
if (val) {
- info->glyph = val->glyph;
- info->outline_glyph = val->outline_glyph;
+ info->outline = val->outline;
+ info->border = val->border;
info->bbox = val->bbox_scaled;
info->advance.x = val->advance.x;
info->advance.y = val->advance.y;
@@ -1075,26 +1073,36 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
if (drawing->hash) {
if(!ass_drawing_parse(drawing, 0))
return;
- info->glyph = (FT_Glyph) drawing->glyph;
+ outline_copy(render_priv->ftlibrary, &drawing->glyph->outline,
+ &info->outline);
+ info->advance.x = d16_to_d6(((FT_Glyph)drawing->glyph)->advance.x);
+ info->advance.y = d16_to_d6(((FT_Glyph)drawing->glyph)->advance.y);
+ FT_Done_Glyph((FT_Glyph)drawing->glyph);
} else {
- info->glyph =
+ FT_Glyph glyph =
ass_font_get_glyph(render_priv->fontconfig_priv,
render_priv->state.font, symbol,
render_priv->settings.hinting,
render_priv->state.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);
+ }
}
- if (!info->glyph)
+ if (!info->outline)
return;
- info->advance.x = d16_to_d6(info->glyph->advance.x);
- info->advance.y = d16_to_d6(info->glyph->advance.y);
- FT_Glyph_Get_CBox(info->glyph, FT_GLYPH_BBOX_SUBPIXELS, &info->bbox);
+ 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)) {
- FT_Glyph_Copy(info->glyph, &info->outline_glyph);
- draw_opaque_box(render_priv, symbol, info->outline_glyph,
+ outline_copy(render_priv->ftlibrary, info->outline, &info->border);
+ draw_opaque_box(render_priv, symbol, info->border,
+ info->advance,
double_to_d6(render_priv->state.border_x *
render_priv->border_scale),
double_to_d6(render_priv->state.border_y *
@@ -1103,9 +1111,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
|| render_priv->state.border_y > 0)
&& key.scale_x && key.scale_y) {
- FT_Glyph_Copy(info->glyph, &info->outline_glyph);
- stroke_outline(render_priv,
- &((FT_OutlineGlyph) info->outline_glyph)->outline,
+ 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 *
@@ -1113,8 +1120,9 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
}
memset(&v, 0, sizeof(v));
- v.glyph = info->glyph;
- v.outline_glyph = info->outline_glyph;
+ v.lib = render_priv->ftlibrary;
+ v.outline = info->outline;
+ v.border = info->border;
v.advance = info->advance;
v.bbox_scaled = info->bbox;
if (drawing->hash) {
@@ -1131,7 +1139,7 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
* onto the screen plane.
*/
static void
-transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry,
+transform_3d_points(FT_Vector shift, FT_Outline *outline, double frx, double fry,
double frz, double fax, double fay, double scale,
int yshift)
{
@@ -1141,7 +1149,6 @@ transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry,
double cx = cos(frx);
double cy = cos(fry);
double cz = cos(frz);
- FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline;
FT_Vector *p = outline->points;
double x, y, z, xx, yy, zz;
int i, dist;
@@ -1184,19 +1191,19 @@ transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry,
* Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it.
*/
static void
-transform_3d(FT_Vector shift, FT_Glyph *glyph, FT_Glyph *glyph2,
+transform_3d(FT_Vector shift, FT_Outline *outline, FT_Outline *border,
double frx, double fry, double frz, double fax, double fay,
double scale, int yshift)
{
frx = -frx;
frz = -frz;
if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) {
- if (glyph && *glyph)
- transform_3d_points(shift, *glyph, frx, fry, frz,
+ if (outline)
+ transform_3d_points(shift, outline, frx, fry, frz,
fax, fay, scale, yshift);
- if (glyph2 && *glyph2)
- transform_3d_points(shift, *glyph2, frx, fry, frz,
+ if (border)
+ transform_3d_points(shift, border, frx, fry, frz,
fax, fay, scale, yshift);
}
}
@@ -1227,14 +1234,13 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
int error;
double fax_scaled, fay_scaled;
info->bm = info->bm_o = info->bm_s = 0;
- if (info->glyph && info->symbol != '\n' && info->symbol != 0
+ if (info->outline && info->symbol != '\n' && info->symbol != 0
&& !info->skip) {
- FT_Glyph glyph;
- FT_Glyph outline;
+ FT_Outline *outline, *border;
double scale_x = render_priv->font_scale_x;
- FT_Glyph_Copy(info->glyph, &glyph);
- FT_Glyph_Copy(info->outline_glyph, &outline);
+ outline_copy(render_priv->ftlibrary, info->outline, &outline);
+ outline_copy(render_priv->ftlibrary, info->border, &border);
// calculating rotation shift vector (from rotation origin to the glyph basepoint)
shift.x = key->shift_x;
shift.y = key->shift_y;
@@ -1242,7 +1248,7 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
render_priv->state.scale_x;
fay_scaled = info->fay * render_priv->state.scale_y;
// apply rotation
- transform_3d(shift, &glyph, &outline,
+ transform_3d(shift, outline, border,
info->frx, info->fry, info->frz, fax_scaled,
fay_scaled, render_priv->font_scale, info->asc);
@@ -1251,24 +1257,21 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
0, double_to_d16(1.0) };
// subpixel shift
- if (glyph) {
- FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline;
+ if (outline) {
if (scale_x != 1.0)
- FT_Outline_Transform(outl, &m);
- FT_Outline_Translate(outl, key->advance.x, -key->advance.y);
+ FT_Outline_Transform(outline, &m);
+ FT_Outline_Translate(outline, key->advance.x, -key->advance.y);
}
- if (outline) {
- FT_Outline *outl = &((FT_OutlineGlyph) outline)->outline;
+ if (border) {
if (scale_x != 1.0)
- FT_Outline_Transform(outl, &m);
- FT_Outline_Translate(outl, key->advance.x, -key->advance.y);
+ FT_Outline_Transform(border, &m);
+ FT_Outline_Translate(border, key->advance.x, -key->advance.y);
}
// render glyph
error = outline_to_bitmap3(render_priv->library,
render_priv->synth_priv,
render_priv->ftlibrary,
- &((FT_OutlineGlyph)glyph)->outline,
- &((FT_OutlineGlyph)outline)->outline,
+ outline, border,
&info->bm, &info->bm_o,
&info->bm_s, info->be,
info->blur * render_priv->border_scale,
@@ -1282,14 +1285,14 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
hash_val.bm_s = info->bm_s;
ass_cache_put(render_priv->cache.bitmap_cache, key, &hash_val);
- FT_Done_Glyph(glyph);
- FT_Done_Glyph(outline);
+ outline_free(render_priv->ftlibrary, outline);
+ outline_free(render_priv->ftlibrary, border);
}
}
// VSFilter compatibility: invisible fill and no border?
// In this case no shadow is supposed to be rendered.
- if (!info->outline_glyph && (info->c[0] >> 24) == 0xFF)
+ if (!info->border && (info->c[0] >> 24) == 0xFF)
info->bm_s = 0;
}