summaryrefslogtreecommitdiffstats
path: root/libass/ass_render.c
diff options
context:
space:
mode:
authorgreg <greg@blackbox>2009-06-18 14:16:07 +0200
committergreg <greg@blackbox>2009-06-20 03:37:18 +0200
commit8aa14b319b8f13bd817a116f27610173de37dae7 (patch)
treea7fc10e93ce398ea0906aa84cd718a70c1bda587 /libass/ass_render.c
parent7036f4774944d8acd2a175f1171e8c988f8c9d36 (diff)
downloadlibass-8aa14b319b8f13bd817a116f27610173de37dae7.tar.bz2
libass-8aa14b319b8f13bd817a116f27610173de37dae7.tar.xz
Fix up glyph stroker to avoid buggy rendering.
This adds pre-processing to the stroker which removes certain contours that'd lead to areas wrongly getting not filled. The approach is very simple, but works well enough for most cases.
Diffstat (limited to 'libass/ass_render.c')
-rw-r--r--libass/ass_render.c81
1 files changed, 79 insertions, 2 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 141de495..00a5f39a 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -1425,6 +1425,82 @@ static void free_render_context(void)
{
}
+// Calculate the cbox of a series of points
+static void get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end) {
+ box->xMin = box->yMin = INT_MAX;
+ box->xMax = box->yMax = INT_MIN;
+ int i;
+
+ for (i=start; i<end; i++) {
+ box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin;
+ box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax;
+ box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin;
+ box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax;
+ }
+}
+
+/**
+ * \brief Fix-up stroker result for huge borders by removing the contours from
+ * the outline that are harmful.
+*/
+static void fix_freetype_stroker(FT_OutlineGlyph glyph, int border) {
+ int nc = glyph->outline.n_contours;
+ int begin, stop;
+ char modified = 0;
+ char *valid_cont;
+ int start = 0;
+ int end = -1;
+ FT_BBox *boxes = calloc(nc, sizeof(FT_BBox));
+ int i, j;
+
+ // 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);
+ }
+
+ // if a) contour's cbox is contained in another contours cbox
+ // b) contour's height or width is smaller than the border*2
+ // the contour can be safely removed.
+ valid_cont = calloc(1, nc);
+ for (i=0; i < nc; i++) {
+ valid_cont[i] = 1;
+ for (j=0; j < nc; j++) {
+ if (i == j) continue;
+ if (boxes[i].xMin >= boxes[j].xMin &&
+ boxes[i].xMax <= boxes[j].xMax &&
+ boxes[i].yMin >= boxes[j].yMin &&
+ boxes[i].yMax <= boxes[j].yMax) {
+ int width = boxes[i].xMax - boxes[i].xMin;
+ int height = boxes[i].yMax - boxes[i].yMin;
+ if (width < border*2 || height < border*2) {
+ valid_cont[i] = 0;
+ modified = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ // Zero-out contours that can be removed; much simpler than copying
+ if (modified) {
+ 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];
+ for (j=begin; j<=stop; j++) {
+ glyph->outline.points[j].x = 0;
+ glyph->outline.points[j].y = 0;
+ glyph->outline.tags[j] = 0;
+ }
+ }
+ }
+
+ free(boxes);
+ free(valid_cont);
+}
+
/**
* \brief Get normal and outline (border) glyphs
* \param symbol ucs4 char
@@ -1471,8 +1547,9 @@ static void get_outline_glyph(ass_renderer_t* render_priv, int symbol, glyph_inf
FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox);
if (render_priv->state.stroker) {
- info->outline_glyph = info->glyph;
- error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_priv->state.stroker, 0 , 0 ); // don't destroy original
+ FT_Glyph_Copy(info->glyph, &info->outline_glyph);
+ fix_freetype_stroker((FT_OutlineGlyph) info->outline_glyph, double_to_d6(render_priv->state.border * render_priv->border_scale));
+ error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_priv->state.stroker, 0 , 1);
if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error);
}