summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--libass/ass_cache.c12
-rw-r--r--libass/ass_cache.h5
-rw-r--r--libass/ass_font.c19
-rw-r--r--libass/ass_font.h4
-rw-r--r--libass/ass_render.c143
-rw-r--r--libass/ass_render.h4
6 files changed, 108 insertions, 79 deletions
diff --git a/libass/ass_cache.c b/libass/ass_cache.c
index e6dae0a..5f24548 100644
--- a/libass/ass_cache.c
+++ b/libass/ass_cache.c
@@ -22,7 +22,7 @@
#include <inttypes.h>
#include <ft2build.h>
#include FT_FREETYPE_H
-#include FT_GLYPH_H
+#include FT_OUTLINE_H
#include <assert.h>
@@ -105,21 +105,23 @@ static size_t bitmap_size(void *value, size_t value_size)
static void glyph_destruct(void *key, void *value)
{
GlyphHashValue *v = value;
- if (v->glyph)
- FT_Done_Glyph(v->glyph);
- if (v->outline_glyph)
- FT_Done_Glyph(v->outline_glyph);
+ if (v->outline)
+ outline_free(v->lib, v->outline);
+ if (v->border)
+ outline_free(v->lib, v->border);
free(key);
free(value);
}
static size_t glyph_size(void *value, size_t value_size)
{
+#if 0
GlyphHashValue *val = value;
if (val->glyph && val->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
FT_Bitmap *bitmap = &((FT_BitmapGlyph) val->glyph)->bitmap;
return bitmap->rows * bitmap->pitch;
}
+#endif
return 0;
}
diff --git a/libass/ass_cache.h b/libass/ass_cache.h
index 68449cf..cf2c400 100644
--- a/libass/ass_cache.h
+++ b/libass/ass_cache.h
@@ -42,8 +42,9 @@ typedef struct {
} CompositeHashValue;
typedef struct {
- FT_Glyph glyph;
- FT_Glyph outline_glyph;
+ FT_Library lib;
+ FT_Outline *outline;
+ FT_Outline *border;
FT_BBox bbox_scaled; // bbox after scaling, but before rotation
FT_Vector advance; // 26.6, advance distance to the next bitmap in line
int asc, desc; // ascender/descender of a drawing
diff --git a/libass/ass_font.c b/libass/ass_font.c
index 7b55e81..400dad6 100644
--- a/libass/ass_font.c
+++ b/libass/ass_font.c
@@ -388,6 +388,25 @@ static int ass_strike_outline_glyph(FT_Face face, ASS_Font *font,
return 0;
}
+void outline_copy(FT_Library lib, FT_Outline *source, FT_Outline **dest)
+{
+ if (source == NULL) {
+ *dest = NULL;
+ return;
+ }
+ *dest = calloc(1, sizeof(**dest));
+
+ FT_Outline_New(lib, source->n_points, source->n_contours, *dest);
+ FT_Outline_Copy(source, *dest);
+}
+
+void outline_free(FT_Library lib, FT_Outline *outline)
+{
+ if (outline)
+ FT_Outline_Done(lib, outline);
+ free(outline);
+}
+
/**
* Slightly embold a glyph without touching its metrics
*/
diff --git a/libass/ass_font.h b/libass/ass_font.h
index 6f16821..af40ce2 100644
--- a/libass/ass_font.h
+++ b/libass/ass_font.h
@@ -22,6 +22,8 @@
#include <stdint.h>
#include <ft2build.h>
#include FT_GLYPH_H
+#include FT_OUTLINE_H
+
#include "ass.h"
#include "ass_types.h"
@@ -63,5 +65,7 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2);
void ass_font_free(ASS_Font *font);
void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y);
+void outline_copy(FT_Library lib, FT_Outline *source, FT_Outline **dest);
+void outline_free(FT_Library lib, FT_Outline *outline);
#endif /* LIBASS_FONT_H */
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;
}
diff --git a/libass/ass_render.h b/libass/ass_render.h
index e19bd07..0876589 100644
--- a/libass/ass_render.h
+++ b/libass/ass_render.h
@@ -99,8 +99,8 @@ typedef enum {
typedef struct {
unsigned symbol;
unsigned skip; // skip glyph when layouting text
- FT_Glyph glyph;
- FT_Glyph outline_glyph;
+ FT_Outline *outline;
+ FT_Outline *border;
Bitmap *bm; // glyph bitmap
Bitmap *bm_o; // outline bitmap
Bitmap *bm_s; // shadow bitmap