]> granicus.if.org Git - libass/commitdiff
Stroker: process outlines directly
authorGrigori Goronzy <greg@blackbox>
Mon, 13 Jun 2011 21:15:27 +0000 (23:15 +0200)
committerGrigori Goronzy <greg@blackbox>
Mon, 13 Jun 2011 21:17:28 +0000 (23:17 +0200)
libass/ass_font.c
libass/ass_font.h
libass/ass_render.c

index a80c0a01d87657ebf93f2df3881a504fa8145927..7b55e8163682ae2101f18a83cc6f5d904abe7e01 100644 (file)
@@ -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;
             }
         }
     }
index a0d66602ed26be9d8386e0ead204f8c2387c5957..6f16821f1ced9382cf1ac32a1b2b49376dda322a 100644 (file)
@@ -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 */
index ef888acf2678c9a26db57fb4539a3b092a72b3a3..497d77e6967ad007aaa41f8257889a31347b9ac1 100644 (file)
@@ -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));