From 2f9733ef09e6a6c57697c442e8a697728a25677c Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Mon, 13 Jun 2011 23:15:27 +0200 Subject: Stroker: process outlines directly --- libass/ass_font.c | 38 ++++++++++++++++++------------------ libass/ass_font.h | 2 +- libass/ass_render.c | 55 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/libass/ass_font.c b/libass/ass_font.c index a80c0a0..7b55e81 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -606,9 +606,9 @@ static int get_contour_direction(FT_Vector *points, int start, int end) * \brief Fix-up stroker result for huge borders by removing inside contours * that would reverse in size */ -void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) +void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y) { - int nc = glyph->outline.n_contours; + int nc = outline->n_contours; int begin, stop; char modified = 0; char *valid_cont = malloc(nc); @@ -618,14 +618,14 @@ void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) int i, j; int inside_direction; - inside_direction = FT_Outline_Get_Orientation(&glyph->outline) == + inside_direction = FT_Outline_Get_Orientation(outline) == FT_ORIENTATION_TRUETYPE; // create a list of cboxes of the contours for (i = 0; i < nc; i++) { start = end + 1; - end = glyph->outline.contours[i]; - get_contour_cbox(&boxes[i], glyph->outline.points, start, end); + end = outline->contours[i]; + get_contour_cbox(&boxes[i], outline->points, start, end); } // for each contour, check direction and whether it's "outside" @@ -633,8 +633,8 @@ void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) end = -1; for (i = 0; i < nc; i++) { start = end + 1; - end = glyph->outline.contours[i]; - int dir = get_contour_direction(glyph->outline.points, start, end); + end = outline->contours[i]; + int dir = get_contour_direction(outline->points, start, end); valid_cont[i] = 1; if (dir == inside_direction) { for (j = 0; j < nc; j++) { @@ -650,19 +650,19 @@ void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) * inside of - assume the font is buggy and it should be * an "outside" contour, and reverse it */ for (j = 0; j < (end + 1 - start) / 2; j++) { - FT_Vector temp = glyph->outline.points[start + j]; - char temp2 = glyph->outline.tags[start + j]; - glyph->outline.points[start + j] = glyph->outline.points[end - j]; - glyph->outline.points[end - j] = temp; - glyph->outline.tags[start + j] = glyph->outline.tags[end - j]; - glyph->outline.tags[end - j] = temp2; + FT_Vector temp = outline->points[start + j]; + char temp2 = outline->tags[start + j]; + outline->points[start + j] = outline->points[end - j]; + outline->points[end - j] = temp; + outline->tags[start + j] = outline->tags[end - j]; + outline->tags[end - j] = temp2; } dir ^= 1; } check_inside: if (dir == inside_direction) { FT_BBox box; - get_contour_cbox(&box, glyph->outline.points, start, end); + get_contour_cbox(&box, outline->points, start, end); int width = box.xMax - box.xMin; int height = box.yMax - box.yMin; if (width < border_x * 2 || height < border_y * 2) { @@ -677,12 +677,12 @@ void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) for (i = 0; i < nc; i++) { if (valid_cont[i]) continue; - begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1; - stop = glyph->outline.contours[i]; + begin = (i == 0) ? 0 : outline->contours[i - 1] + 1; + stop = outline->contours[i]; for (j = begin; j <= stop; j++) { - glyph->outline.points[j].x = 0; - glyph->outline.points[j].y = 0; - glyph->outline.tags[j] = 0; + outline->points[j].x = 0; + outline->points[j].y = 0; + outline->tags[j] = 0; } } } diff --git a/libass/ass_font.h b/libass/ass_font.h index a0d6660..6f16821 100644 --- a/libass/ass_font.h +++ b/libass/ass_font.h @@ -62,6 +62,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, uint32_t ch, ASS_Hinting hinting, int flags); 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_OutlineGlyph glyph, int border_x, int border_y); +void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y); #endif /* LIBASS_FONT_H */ diff --git a/libass/ass_render.c b/libass/ass_render.c index ef888ac..497d77e 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -955,40 +955,53 @@ static void draw_opaque_box(ASS_Renderer *render_priv, uint32_t ch, * Stroke an outline glyph in x/y direction. Applies various fixups to get * around limitations of the FreeType stroker. */ -static void stroke_outline_glyph(ASS_Renderer *render_priv, - FT_OutlineGlyph *glyph, int sx, int sy) +static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline, + int sx, int sy) { if (sx <= 0 && sy <= 0) return; - fix_freetype_stroker(*glyph, sx, sy); + fix_freetype_stroker(outline, sx, sy); // Borders are equal; use the regular stroker if (sx == sy && render_priv->state.stroker) { int error; - error = FT_Glyph_StrokeBorder((FT_Glyph *) glyph, - render_priv->state.stroker, 0, 1); - if (error) + unsigned n_points, n_contours; + + FT_StrokerBorder border = FT_Outline_GetOutsideBorder(outline); + error = FT_Stroker_ParseOutline(render_priv->state.stroker, outline, 0); + if (error) { ass_msg(render_priv->library, MSGL_WARN, - "FT_Glyph_Stroke error: %d", error); + "FT_Stroker_ParseOutline failed, error: %d", error); + } + error = FT_Stroker_GetBorderCounts(render_priv->state.stroker, border, + &n_points, &n_contours); + if (error) { + ass_msg(render_priv->library, MSGL_WARN, + "FT_Stroker_GetBorderCounts failed, error: %d", error); + } + FT_Outline_Done(render_priv->ftlibrary, outline); + FT_Outline_New(render_priv->ftlibrary, n_points, n_contours, outline); + outline->n_points = outline->n_contours = 0; + FT_Stroker_ExportBorder(render_priv->state.stroker, border, outline); // "Stroke" with the outline emboldener in two passes. // The outlines look uglier, but the emboldening never adds any points } else { int i; - FT_Outline *ol = &(*glyph)->outline; FT_Outline nol; - FT_Outline_New(render_priv->ftlibrary, ol->n_points, - ol->n_contours, &nol); - FT_Outline_Copy(ol, &nol); - FT_Outline_Embolden(ol, sx * 2); - FT_Outline_Translate(ol, -sx, -sx); + FT_Outline_New(render_priv->ftlibrary, outline->n_points, + outline->n_contours, &nol); + FT_Outline_Copy(outline, &nol); + + FT_Outline_Embolden(outline, sx * 2); + FT_Outline_Translate(outline, -sx, -sx); FT_Outline_Embolden(&nol, sy * 2); FT_Outline_Translate(&nol, -sy, -sy); - for (i = 0; i < ol->n_points; i++) - ol->points[i].y = nol.points[i].y; + for (i = 0; i < outline->n_points; i++) + outline->points[i].y = nol.points[i].y; FT_Outline_Done(render_priv->ftlibrary, &nol); } @@ -1091,12 +1104,12 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, && key.scale_x && key.scale_y) { FT_Glyph_Copy(info->glyph, &info->outline_glyph); - stroke_outline_glyph(render_priv, - (FT_OutlineGlyph *) &info->outline_glyph, - double_to_d6(render_priv->state.border_x * - render_priv->border_scale), - double_to_d6(render_priv->state.border_y * - render_priv->border_scale)); + stroke_outline(render_priv, + &((FT_OutlineGlyph) info->outline_glyph)->outline, + double_to_d6(render_priv->state.border_x * + render_priv->border_scale), + double_to_d6(render_priv->state.border_y * + render_priv->border_scale)); } memset(&v, 0, sizeof(v)); -- cgit v1.2.3