]> granicus.if.org Git - libass/commitdiff
Replace FT_Outline with ASS_Outline
authorDr.Smile <vabnick@gmail.com>
Sun, 23 Nov 2014 17:01:03 +0000 (20:01 +0300)
committerDr.Smile <vabnick@gmail.com>
Sun, 23 Nov 2014 17:01:03 +0000 (20:01 +0300)
12 files changed:
libass/ass_bitmap.c
libass/ass_bitmap.h
libass/ass_cache.c
libass/ass_cache.h
libass/ass_drawing.c
libass/ass_drawing.h
libass/ass_font.c
libass/ass_font.h
libass/ass_rasterizer.c
libass/ass_rasterizer.h
libass/ass_render.c
libass/ass_render.h

index 0eb4577b5274bcf9598ce6df3be3c235b9211e91..01bf013213f68ad38828edf0cab3c8ba55f4d7e3 100644 (file)
@@ -279,7 +279,7 @@ Bitmap *copy_bitmap(const Bitmap *src)
 #if CONFIG_RASTERIZER
 
 Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
-                          FT_Outline *outline, int bord)
+                          ASS_Outline *outline, int bord)
 {
     ASS_Rasterizer *rst = &render_priv->rasterizer;
     if (!rasterizer_set_outline(rst, outline)) {
@@ -343,8 +343,8 @@ Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
 
 #else
 
-Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
-                          FT_Outline *outline, int bord)
+static Bitmap *outline_to_bitmap_ft(ASS_Renderer *render_priv,
+                                    FT_Outline *outline, int bord)
 {
     Bitmap *bm;
     int w, h;
@@ -406,6 +406,42 @@ Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
     return bm;
 }
 
+Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
+                          ASS_Outline *outline, int bord)
+{
+    size_t n_points = outline->n_points;
+    if (n_points > SHRT_MAX) {
+        ass_msg(render_priv->library, MSGL_WARN, "Too many outline points: %d",
+                outline->n_points);
+        n_points = SHRT_MAX;
+    }
+
+    size_t n_contours = FFMIN(outline->n_contours, SHRT_MAX);
+    short contours_small[EFFICIENT_CONTOUR_COUNT];
+    short *contours = contours_small;
+    short *contours_large = NULL;
+    if (n_contours > EFFICIENT_CONTOUR_COUNT) {
+        contours_large = malloc(n_contours * sizeof(short));
+        if (!contours_large)
+            return NULL;
+        contours = contours_large;
+    }
+    for (size_t i = 0; i < n_contours; ++i)
+        contours[i] = FFMIN(outline->contours[i], n_points - 1);
+
+    FT_Outline ftol;
+    ftol.n_points = n_points;
+    ftol.n_contours = n_contours;
+    ftol.points = outline->points;
+    ftol.tags = outline->tags;
+    ftol.contours = contours;
+    ftol.flags = 0;
+
+    Bitmap *bm = outline_to_bitmap_ft(render_priv, &ftol, bord);
+    free(contours_large);
+    return bm;
+}
+
 #endif
 
 /**
@@ -671,7 +707,8 @@ void be_blur_c(uint8_t *buf, intptr_t w,
     }
 }
 
-int outline_to_bitmap3(ASS_Renderer *render_priv, FT_Outline *outline, FT_Outline *border,
+int outline_to_bitmap3(ASS_Renderer *render_priv,
+                       ASS_Outline *outline, ASS_Outline *border,
                        Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
                        int be, double blur_radius, FT_Vector shadow_offset,
                        int border_style, int border_visible)
index 82a21593d1ccfeafdc83fbafabd736398e00071e..4a070baac4c50af7caccb38b0b6d38a88f04d7c0 100644 (file)
@@ -29,6 +29,16 @@ typedef struct ass_synth_priv ASS_SynthPriv;
 ASS_SynthPriv *ass_synth_init(double);
 void ass_synth_done(ASS_SynthPriv *priv);
 
+typedef struct {
+    size_t n_contours, max_contours;
+    size_t *contours;
+    size_t n_points, max_points;
+    FT_Vector *points;
+    char *tags;
+} ASS_Outline;
+
+#define EFFICIENT_CONTOUR_COUNT 8
+
 typedef struct {
     int left, top;
     int w, h;                   // width, height
@@ -37,7 +47,7 @@ typedef struct {
 } Bitmap;
 
 Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
-                          FT_Outline *outline, int bord);
+                          ASS_Outline *outline, int bord);
 
 Bitmap *alloc_bitmap(int w, int h);
 
@@ -54,7 +64,7 @@ void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be,
  * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
  * \param border_visible whether border is visible if border_style is 3
  */
-int outline_to_bitmap3(ASS_Renderer *render_priv, FT_Outline *outline, FT_Outline *border,
+int outline_to_bitmap3(ASS_Renderer *render_priv, ASS_Outline *outline, ASS_Outline *border,
                        Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
                        int be, double blur_radius, FT_Vector shadow_offset,
                        int border_style, int border_visible);
index a0a00b302ed783fa7dfcb6e59cd2b264ac63c367..062ddfa4d771e48563b767e76cbe447d4d2f7415 100644 (file)
@@ -175,10 +175,10 @@ static void outline_destruct(void *key, void *value)
 {
     OutlineHashValue *v = value;
     OutlineHashKey *k = key;
-    if (v->outline)
-        outline_free(v->lib, v->outline);
-    if (v->border)
-        outline_free(v->lib, v->border);
+    outline_free(v->outline);
+    free(v->outline);
+    outline_free(v->border);
+    free(v->border);
     if (k->type == OUTLINE_DRAWING)
         free(k->u.drawing.text);
     free(key);
index 677b705d4492e174201443216ba3d8dd2ad244b1..060014231bdaac6ae6fddf505cf1f8b5af9bc27b 100644 (file)
@@ -42,9 +42,8 @@ typedef struct {
 } CompositeHashValue;
 
 typedef struct {
-    FT_Library lib;
-    FT_Outline *outline;
-    FT_Outline *border;
+    ASS_Outline *outline;
+    ASS_Outline *border;
     FT_BBox bbox_scaled;        // bbox after scaling, but before rotation
     FT_Vector advance;          // 26.6, advance distance to the next outline in line
     int asc, desc;              // ascender/descender
index 70afae596c09fc7a2bd64220ce5ed07bf3824fa4..e2676dfc48b8075fc03832a4c01e87a5dc9654b8 100644 (file)
 #include FT_OUTLINE_H
 #include FT_BBOX_H
 #include <math.h>
+#include <stdbool.h>
 #include <limits.h>
 
 #include "ass_utils.h"
 #include "ass_drawing.h"
+#include "ass_font.h"
 
 #define CURVE_ACCURACY 64.0
 #define GLYPH_INITIAL_POINTS 100
 /*
  * \brief Add a single point to a contour.
  */
-static inline void drawing_add_point(ASS_Drawing *drawing,
+static inline bool drawing_add_point(ASS_Drawing *drawing,
                                      const FT_Vector *point, char tags)
 {
-    FT_Outline *ol = &drawing->outline;
-    if (ol->n_points == SHRT_MAX)
-        return;
-
-    if (ol->n_points >= drawing->max_points) {
-        drawing->max_points *= 2;
-        ol->points = realloc(ol->points, sizeof(FT_Vector) *
-                             drawing->max_points);
-        ol->tags = realloc(ol->tags, drawing->max_points);
+    ASS_Outline *ol = &drawing->outline;
+    if (ol->n_points >= ol->max_points) {
+        size_t new_size = 2 * ol->max_points;
+        if (!ASS_REALLOC_ARRAY(ol->points, new_size))
+            return false;
+        if (!ASS_REALLOC_ARRAY(ol->tags, new_size))
+            return false;
+        ol->max_points = new_size;
     }
 
     ol->points[ol->n_points].x = point->x;
     ol->points[ol->n_points].y = point->y;
     ol->tags[ol->n_points] = tags;
     ol->n_points++;
+    return true;
 }
 
 /*
  * \brief Close a contour and check outline size overflow.
  */
-static inline void drawing_close_shape(ASS_Drawing *drawing)
+static inline bool drawing_close_shape(ASS_Drawing *drawing)
 {
-    FT_Outline *ol = &drawing->outline;
-    if (ol->n_contours == SHRT_MAX) {
-        if (ol->n_points)
-            ol->contours[ol->n_contours] = ol->n_points - 1;
-        return;
-    }
-
-    if (ol->n_contours >= drawing->max_contours) {
-        drawing->max_contours *= 2;
-        ol->contours = realloc(ol->contours, sizeof(short) *
-                               drawing->max_contours);
+    ASS_Outline *ol = &drawing->outline;
+    if (ol->n_contours >= ol->max_contours) {
+        size_t new_size = 2 * ol->max_contours;
+        if (!ASS_REALLOC_ARRAY(ol->contours, new_size))
+            return false;
+        ol->max_contours = new_size;
     }
 
     ol->contours[ol->n_contours] = ol->n_points - 1;
     ol->n_contours++;
+    return true;
 }
 
 /*
@@ -93,7 +91,7 @@ static void drawing_finish(ASS_Drawing *drawing, int raw_mode)
     int i;
     double pbo;
     FT_BBox bbox = drawing->cbox;
-    FT_Outline *ol = &drawing->outline;
+    ASS_Outline *ol = &drawing->outline;
 
     if (drawing->library)
         ass_msg(drawing->library, MSGL_V,
@@ -241,7 +239,7 @@ static inline void translate_point(ASS_Drawing *drawing, FT_Vector *point)
  * This curve evaluator is also used in VSFilter (RTS.cpp); it's a simple
  * implementation of the De Casteljau algorithm.
  */
-static void drawing_evaluate_curve(ASS_Drawing *drawing,
+static bool drawing_evaluate_curve(ASS_Drawing *drawing,
                                    ASS_DrawingToken *token, char spline,
                                    int started)
 {
@@ -270,11 +268,10 @@ static void drawing_evaluate_curve(ASS_Drawing *drawing,
         p[2].y -= y12;
     }
 
-    if (!started)
-        drawing_add_point(drawing, &p[0], FT_CURVE_TAG_ON);
-    drawing_add_point(drawing, &p[1], FT_CURVE_TAG_CUBIC);
-    drawing_add_point(drawing, &p[2], FT_CURVE_TAG_CUBIC);
-    drawing_add_point(drawing, &p[3], FT_CURVE_TAG_ON);
+    return (started || drawing_add_point(drawing, &p[0], FT_CURVE_TAG_ON)) &&
+        drawing_add_point(drawing, &p[1], FT_CURVE_TAG_CUBIC) &&
+        drawing_add_point(drawing, &p[2], FT_CURVE_TAG_CUBIC) &&
+        drawing_add_point(drawing, &p[3], FT_CURVE_TAG_ON);
 }
 
 /*
@@ -282,9 +279,7 @@ static void drawing_evaluate_curve(ASS_Drawing *drawing,
  */
 ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib)
 {
-    ASS_Drawing *drawing;
-
-    drawing = calloc(1, sizeof(*drawing));
+    ASS_Drawing *drawing = calloc(1, sizeof(*drawing));
     if (!drawing)
         return NULL;
     drawing->cbox.xMin = drawing->cbox.yMin = INT_MAX;
@@ -293,14 +288,8 @@ ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib)
     drawing->library   = lib;
     drawing->scale_x = 1.;
     drawing->scale_y = 1.;
-    drawing->max_contours = GLYPH_INITIAL_CONTOURS;
-    drawing->max_points = GLYPH_INITIAL_POINTS;
-
-    FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
-            GLYPH_INITIAL_CONTOURS, &drawing->outline);
-    drawing->outline.n_contours = 0;
-    drawing->outline.n_points = 0;
 
+    outline_alloc(&drawing->outline, GLYPH_INITIAL_POINTS, GLYPH_INITIAL_CONTOURS);
     return drawing;
 }
 
@@ -311,7 +300,7 @@ void ass_drawing_free(ASS_Drawing* drawing)
 {
     if (drawing) {
         free(drawing->text);
-        FT_Outline_Done(drawing->ftlibrary, &drawing->outline);
+        outline_free(&drawing->outline);
     }
     free(drawing);
 }
@@ -339,7 +328,7 @@ void ass_drawing_hash(ASS_Drawing* drawing)
 /*
  * \brief Convert token list to outline.  Calls the line and curve evaluators.
  */
-FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
+ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
 {
     int started = 0;
     ASS_DrawingToken *token;
@@ -361,7 +350,8 @@ FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
             pen = token->point;
             translate_point(drawing, &pen);
             if (started) {
-                drawing_close_shape(drawing);
+                if (!drawing_close_shape(drawing))
+                    goto error;
                 started = 0;
             }
             token = token->next;
@@ -370,8 +360,10 @@ FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
             FT_Vector to;
             to = token->point;
             translate_point(drawing, &to);
-            if (!started) drawing_add_point(drawing, &pen, FT_CURVE_TAG_ON);
-            drawing_add_point(drawing, &to, FT_CURVE_TAG_ON);
+            if (!started && !drawing_add_point(drawing, &pen, FT_CURVE_TAG_ON))
+                goto error;
+            if (!drawing_add_point(drawing, &to, FT_CURVE_TAG_ON))
+                goto error;
             started = 1;
             token = token->next;
             break;
@@ -379,7 +371,8 @@ FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
         case TOKEN_CUBIC_BEZIER:
             if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) &&
                 token->prev) {
-                drawing_evaluate_curve(drawing, token->prev, 0, started);
+                if (!drawing_evaluate_curve(drawing, token->prev, 0, started))
+                    goto error;
                 token = token->next;
                 token = token->next;
                 token = token->next;
@@ -390,7 +383,8 @@ FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
         case TOKEN_B_SPLINE:
             if (token_check_values(token, 3, TOKEN_B_SPLINE) &&
                 token->prev) {
-                drawing_evaluate_curve(drawing, token->prev, 1, started);
+                if (!drawing_evaluate_curve(drawing, token->prev, 1, started))
+                    goto error;
                 token = token->next;
                 started = 1;
             } else
@@ -403,10 +397,14 @@ FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
     }
 
     // Close the last contour
-    if (started)
-        drawing_close_shape(drawing);
+    if (started && !drawing_close_shape(drawing))
+        goto error;
 
     drawing_finish(drawing, raw_mode);
     drawing_free_tokens(drawing->tokens);
     return &drawing->outline;
+
+error:
+    drawing_free_tokens(drawing->tokens);
+    return NULL;
 }
index 62010ebb0a8e15125f9149993cef70c6e44bfa86..1e73c274555c5e70114b823386ba36000d833750 100644 (file)
@@ -23,6 +23,7 @@
 #include FT_OUTLINE_H
 
 #include "ass.h"
+#include "ass_bitmap.h"
 
 typedef enum {
     TOKEN_MOVE,
@@ -50,7 +51,7 @@ typedef struct {
     double scale_y;     // FontScaleY
     int asc;            // ascender
     int desc;           // descender
-    FT_Outline outline; // target outline
+    ASS_Outline outline; // target outline
     FT_Vector advance;  // advance (from cbox)
     int hash;           // hash value (for caching)
 
@@ -58,8 +59,6 @@ typedef struct {
     FT_Library ftlibrary;   // needed for font ops
     ASS_Library *library;
     ASS_DrawingToken *tokens;    // tokenized drawing
-    int max_points;     // current maximum size
-    int max_contours;
     double point_scale_x;
     double point_scale_y;
     FT_BBox cbox;   // bounding box, or let's say... VSFilter's idea of it
@@ -69,6 +68,6 @@ ASS_Drawing *ass_drawing_new(ASS_Library *lib, FT_Library ftlib);
 void ass_drawing_free(ASS_Drawing* drawing);
 void ass_drawing_set_text(ASS_Drawing* drawing, char *str, size_t n);
 void ass_drawing_hash(ASS_Drawing* drawing);
-FT_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode);
+ASS_Outline *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode);
 
 #endif /* LIBASS_DRAWING_H */
index 69675c6076fb658fdfef892fef12eefbeadbfcfe..7b202a60527007f4e8b1eaebab51216eee6e275e 100644 (file)
@@ -392,23 +392,91 @@ 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)
+
+int outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_contours)
 {
-    if (source == NULL) {
-        *dest = NULL;
-        return;
+    outline->contours = malloc(sizeof(size_t) * n_contours);
+    outline->points = malloc(sizeof(FT_Vector) * n_points);
+    outline->tags = malloc(n_points);
+    if (!outline->contours || !outline->points || !outline->tags)
+        return 0;
+
+    outline->max_contours = n_contours;
+    outline->max_points = n_points;
+    return 1;
+}
+
+ASS_Outline *outline_convert(const FT_Outline *source)
+{
+    if (!source)
+        return NULL;
+
+    ASS_Outline *ol = calloc(1, sizeof(*ol));
+    if (!ol)
+        return NULL;
+
+    if (!outline_alloc(ol, source->n_points, source->n_contours)) {
+        outline_free(ol);
+        free(ol);
+        return NULL;
+    }
+
+    //if (source->flags & FT_OUTLINE_REVERSE_FILL) {
+    if (FT_Outline_Get_Orientation((FT_Outline *)source) != FT_ORIENTATION_TRUETYPE) {
+        int prev = 0;
+        for (int i = 0; i < source->n_contours; ++i) {
+            int last = source->contours[i];
+            ol->contours[i] = last;
+            ol->points[prev] = source->points[prev];
+            ol->tags[prev] = source->tags[prev];
+            for (int j = 0; j < last - prev; ++j) {
+                ol->points[last - j] = source->points[prev + j + 1];
+                ol->tags[last - j] = source->tags[prev + j + 1];
+            }
+            prev = last + 1;
+        }
+    } else {
+        for (int i = 0; i < source->n_contours; ++i)
+            ol->contours[i] = source->contours[i];
+        memcpy(ol->points, source->points, sizeof(FT_Vector) * source->n_points);
+        memcpy(ol->tags, source->tags, source->n_points);
+    }
+    ol->n_contours = source->n_contours;
+    ol->n_points = source->n_points;
+    return ol;
+}
+
+ASS_Outline *outline_copy(const ASS_Outline *source)
+{
+    if (!source)
+        return NULL;
+
+    ASS_Outline *ol = calloc(1, sizeof(*ol));
+    if (!ol)
+        return NULL;
+
+    if (!outline_alloc(ol, source->n_points, source->n_contours)) {
+        outline_free(ol);
+        free(ol);
+        return NULL;
     }
-    *dest = calloc(1, sizeof(**dest));
 
-    FT_Outline_New(lib, source->n_points, source->n_contours, *dest);
-    FT_Outline_Copy(source, *dest);
+    memcpy(ol->contours, source->contours, sizeof(size_t) * source->n_contours);
+    memcpy(ol->points, source->points, sizeof(FT_Vector) * source->n_points);
+    memcpy(ol->tags, source->tags, source->n_points);
+    ol->n_contours = source->n_contours;
+    ol->n_points = source->n_points;
+    return ol;
 }
 
-void outline_free(FT_Library lib, FT_Outline *outline)
+void outline_free(ASS_Outline *outline)
 {
-    if (outline)
-        FT_Outline_Done(lib, outline);
-    free(outline);
+    if (!outline)
+        return;
+
+    free(outline->contours);
+    free(outline->points);
+    free(outline->tags);
 }
 
 /**
@@ -663,6 +731,43 @@ static int get_contour_direction(FT_Vector *points, int start, int end)
     return sum > 0;
 }
 
+void outline_translate(const ASS_Outline *outline, FT_Pos dx, FT_Pos dy)
+{
+    for (size_t i = 0; i < outline->n_points; ++i) {
+        outline->points[i].x += dx;
+        outline->points[i].y += dy;
+    }
+}
+
+void outline_transform(const ASS_Outline *outline, const FT_Matrix *matrix)
+{
+    for (size_t i = 0; i < outline->n_points; ++i) {
+        FT_Pos x = FT_MulFix(outline->points[i].x, matrix->xx) +
+                   FT_MulFix(outline->points[i].y, matrix->xy);
+        FT_Pos y = FT_MulFix(outline->points[i].x, matrix->yx) +
+                   FT_MulFix(outline->points[i].y, matrix->yy);
+        outline->points[i].x = x;
+        outline->points[i].y = y;
+    }
+}
+
+void outline_get_cbox(const ASS_Outline *outline, FT_BBox *cbox)
+{
+    if (!outline->n_points) {
+        cbox->xMin = cbox->xMax = 0;
+        cbox->yMin = cbox->yMax = 0;
+        return;
+    }
+    cbox->xMin = cbox->xMax = outline->points[0].x;
+    cbox->yMin = cbox->yMax = outline->points[0].y;
+    for (size_t i = 1; i < outline->n_points; ++i) {
+        cbox->xMin = FFMIN(cbox->xMin, outline->points[i].x);
+        cbox->xMax = FFMAX(cbox->xMax, outline->points[i].x);
+        cbox->yMin = FFMIN(cbox->yMin, outline->points[i].y);
+        cbox->yMax = FFMAX(cbox->yMax, outline->points[i].y);
+    }
+}
+
 /**
  * \brief Apply fixups to please the FreeType stroker and improve the
  * rendering result, especially in case the outline has some anomalies.
@@ -679,7 +784,7 @@ static int get_contour_direction(FT_Vector *points, int start, int end)
  * \param border_x border size, x direction, d6 format
  * \param border_x border size, y direction, d6 format
  */
-void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y)
+void fix_freetype_stroker(ASS_Outline *outline, int border_x, int border_y)
 {
     int nc = outline->n_contours;
     int begin, stop;
@@ -689,10 +794,6 @@ void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y)
     int end = -1;
     FT_BBox *boxes = malloc(nc * sizeof(FT_BBox));
     int i, j;
-    int inside_direction;
-
-    inside_direction = FT_Outline_Get_Orientation(outline) ==
-        FT_ORIENTATION_TRUETYPE;
 
     // create a list of cboxes of the contours
     for (i = 0; i < nc; i++) {
@@ -709,7 +810,7 @@ void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y)
         end = outline->contours[i];
         int dir = get_contour_direction(outline->points, start, end);
         valid_cont[i] = 1;
-        if (dir == inside_direction) {
+        if (dir) {
             for (j = 0; j < nc; j++) {
                 if (i == j)
                     continue;
@@ -733,7 +834,7 @@ void fix_freetype_stroker(FT_Outline *outline, int border_x, int border_y)
             dir ^= 1;
         }
         check_inside:
-        if (dir == inside_direction) {
+        if (dir) {
             FT_BBox box;
             get_contour_cbox(&box, outline->points, start, end);
             int width = box.xMax - box.xMin;
index f80b887550d17351485992c67b6ae25285df180e..f3c3f8ebdd4617c3de20934e5bac47af3ec651ac 100644 (file)
@@ -74,8 +74,14 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
                             ASS_Hinting hinting, int deco);
 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);
+
+void outline_translate(const ASS_Outline *outline, FT_Pos dx, FT_Pos dy);
+void outline_transform(const ASS_Outline *outline, const FT_Matrix *matrix);
+void outline_get_cbox(const ASS_Outline *outline, FT_BBox *cbox);
+void fix_freetype_stroker(ASS_Outline *outline, int border_x, int border_y);
+int outline_alloc(ASS_Outline *outline, size_t n_contours, size_t n_points);
+ASS_Outline *outline_convert(const FT_Outline *source);
+ASS_Outline *outline_copy(const ASS_Outline *source);
+void outline_free(ASS_Outline *outline);
 
 #endif                          /* LIBASS_FONT_H */
index 93a4d5a653810dccd3a8898e03ea522abc0c83d9..84f9a88ba613199a92af3aaed4188179879f9983 100644 (file)
@@ -230,13 +230,13 @@ static int add_cubic(ASS_Rasterizer *rst,
 }
 
 
-int rasterizer_set_outline(ASS_Rasterizer *rst, const FT_Outline *path)
+int rasterizer_set_outline(ASS_Rasterizer *rst, const ASS_Outline *path)
 {
     enum Status {
         S_ON, S_Q, S_C1, S_C2
     };
 
-    int i, j = 0;
+    size_t i, j = 0;
     rst->size[0] = 0;
     for (i = 0; i < path->n_contours; ++i) {
         OutlinePoint start, p[4];
index 9da475e29d8fe804e1e6f5a81dfead7ce908e608..66303178aa7a375da90b551a7e6ac8e2605b956d 100644 (file)
 #ifndef LIBASS_RASTERIZER_H
 #define LIBASS_RASTERIZER_H
 
-#include <ft2build.h>
-#include FT_FREETYPE_H
 #include <stddef.h>
 #include <stdint.h>
 
+#include "ass.h"
+#include "ass_font.h"
+
 
 enum {
     SEGFLAG_DN = 1,
@@ -82,7 +83,7 @@ void rasterizer_done(ASS_Rasterizer *rst);
 /**
  * \brief Convert FreeType outline to polyline and calculate exact bounds
  */
-int rasterizer_set_outline(ASS_Rasterizer *rst, const FT_Outline *path);
+int rasterizer_set_outline(ASS_Rasterizer *rst, const ASS_Outline *path);
 /**
  * \brief Polyline rasterization function
  * \param x0, y0, width, height in: source window (full pixel units)
index d3e262f0d9bfbcee83499bda5652ee7514f48901..4371aa3e41adb7dd8bc58d0837c012c51d843f15 100644 (file)
@@ -522,7 +522,6 @@ static bool free_list_add(ASS_Renderer *render_priv, void *object)
 static void blend_vector_clip(ASS_Renderer *render_priv,
                               ASS_Image *head)
 {
-    FT_Outline *outline;
     Bitmap *clip_bm = NULL;
     ASS_Image *cur;
     ASS_Drawing *drawing = render_priv->state.clip_drawing;
@@ -544,7 +543,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
         BitmapHashValue v;
 
         // Not found in cache, parse and rasterize it
-        outline = ass_drawing_parse(drawing, 1);
+        ASS_Outline *outline = ass_drawing_parse(drawing, 1);
         if (!outline) {
             ass_msg(render_priv->library, MSGL_WARN,
                     "Clip vector parsing failed. Skipping.");
@@ -558,7 +557,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
                 .x = int_to_d6(render_priv->settings.left_margin),
                 .y = -int_to_d6(render_priv->settings.top_margin),
             };
-            FT_Outline_Translate(outline, trans.x, trans.y);
+            outline_translate(outline, trans.x, trans.y);
         }
 
         clip_bm = outline_to_bitmap(render_priv, outline, 0);
@@ -953,10 +952,9 @@ static void free_render_context(ASS_Renderer *render_priv)
  * opaque rectangle.
  */
 static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info,
-                            int asc, int desc, FT_Outline *ol,
+                            int asc, int desc, ASS_Outline *ol,
                             FT_Vector advance, int sx, int sy)
 {
-    int i;
     int adv = advance.x;
     double scale_y = info->orig_scale_y;
     double scale_x = info->orig_scale_x;
@@ -981,10 +979,10 @@ static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info,
         { .x = -sx,         .y = -desc - sy },
     };
 
-    FT_Outline_New(render_priv->ftlibrary, 4, 1, ol);
-
     ol->n_points = ol->n_contours = 0;
-    for (i = 0; i < 4; i++) {
+    if (!outline_alloc(ol, 4, 1))
+        return;
+    for (int i = 0; i < 4; ++i) {
         ol->points[ol->n_points] = points[i];
         ol->tags[ol->n_points++] = 1;
     }
@@ -995,7 +993,7 @@ static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info,
  * Stroke an outline glyph in x/y direction.  Applies various fixups to get
  * around limitations of the FreeType stroker.
  */
-static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline,
+static void stroke_outline(ASS_Renderer *render_priv, ASS_Outline *outline,
                            int sx, int sy)
 {
     if (sx <= 0 && sy <= 0)
@@ -1003,32 +1001,76 @@ static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline,
 
     fix_freetype_stroker(outline, sx, sy);
 
+    size_t n_points = outline->n_points;
+    if (n_points > SHRT_MAX) {
+        ass_msg(render_priv->library, MSGL_WARN, "Too many outline points: %d",
+                outline->n_points);
+        n_points = SHRT_MAX;
+    }
+
+    size_t n_contours = FFMIN(outline->n_contours, SHRT_MAX);
+    short contours_small[EFFICIENT_CONTOUR_COUNT];
+    short *contours = contours_small;
+    short *contours_large = NULL;
+    if (n_contours > EFFICIENT_CONTOUR_COUNT) {
+        contours_large = malloc(n_contours * sizeof(short));
+        if (!contours_large)
+            return;
+        contours = contours_large;
+    }
+    for (size_t i = 0; i < n_contours; ++i)
+        contours[i] = FFMIN(outline->contours[i], n_points - 1);
+
+    FT_Outline ftol;
+    ftol.n_points = n_points;
+    ftol.n_contours = n_contours;
+    ftol.points = outline->points;
+    ftol.tags = outline->tags;
+    ftol.contours = contours;
+    ftol.flags = 0;
+
     // Borders are equal; use the regular stroker
     if (sx == sy && render_priv->state.stroker) {
         int error;
-        unsigned n_points, n_contours;
-
-        FT_StrokerBorder border = FT_Outline_GetOutsideBorder(outline);
-        error = FT_Stroker_ParseOutline(render_priv->state.stroker, outline, 0);
+        FT_StrokerBorder border = FT_Outline_GetOutsideBorder(&ftol);
+        error = FT_Stroker_ParseOutline(render_priv->state.stroker, &ftol, 0);
         if (error) {
             ass_msg(render_priv->library, MSGL_WARN,
                     "FT_Stroker_ParseOutline failed, error: %d", error);
         }
+        unsigned new_points, new_contours;
         error = FT_Stroker_GetBorderCounts(render_priv->state.stroker, border,
-                &n_points, &n_contours);
+                &new_points, &new_contours);
         if (error) {
             ass_msg(render_priv->library, MSGL_WARN,
                     "FT_Stroker_GetBorderCounts failed, error: %d", error);
         }
-        FT_Outline_Done(render_priv->ftlibrary, outline);
-        error = FT_Outline_New(render_priv->ftlibrary, n_points, n_contours, outline);
+        outline_free(outline);
         outline->n_points = outline->n_contours = 0;
-        if (error) {
+        if (new_contours > FFMAX(EFFICIENT_CONTOUR_COUNT, n_contours)) {
+            if (!ASS_REALLOC_ARRAY(contours_large, new_contours)) {
+                free(contours_large);
+                return;
+            }
+        }
+        n_points = new_points;
+        n_contours = new_contours;
+        if (!outline_alloc(outline, n_points, n_contours)) {
             ass_msg(render_priv->library, MSGL_WARN,
-                    "FT_Outline_New failed, error: %d", error);
+                    "Not enough memory for border outline");
+            free(contours_large);
             return;
         }
-        FT_Stroker_ExportBorder(render_priv->state.stroker, border, outline);
+        ftol.n_points = ftol.n_contours = 0;
+        ftol.points = outline->points;
+        ftol.tags = outline->tags;
+
+        FT_Stroker_ExportBorder(render_priv->state.stroker, border, &ftol);
+
+        outline->n_points = n_points;
+        outline->n_contours = n_contours;
+        for (size_t i = 0; i < n_contours; ++i)
+            outline->contours[i] = contours[i];
 
     // "Stroke" with the outline emboldener (in two passes if needed).
     // The outlines look uglier, but the emboldening never adds any points
@@ -1036,27 +1078,29 @@ static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline,
 #if (FREETYPE_MAJOR > 2) || \
     ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 4)) || \
     ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 4) && (FREETYPE_PATCH >= 10))
-        FT_Outline_EmboldenXY(outline, sx * 2, sy * 2);
-        FT_Outline_Translate(outline, -sx, -sy);
+        FT_Outline_EmboldenXY(&ftol, sx * 2, sy * 2);
+        FT_Outline_Translate(&ftol, -sx, -sy);
 #else
         int i;
         FT_Outline nol;
 
-        FT_Outline_New(render_priv->ftlibrary, outline->n_points,
-                       outline->n_contours, &nol);
-        FT_Outline_Copy(outline, &nol);
+        FT_Outline_New(render_priv->ftlibrary, ftol.n_points,
+                       ftol.n_contours, &nol);
+        FT_Outline_Copy(&ftol, &nol);
 
-        FT_Outline_Embolden(outline, sx * 2);
-        FT_Outline_Translate(outline, -sx, -sx);
+        FT_Outline_Embolden(&ftol, sx * 2);
+        FT_Outline_Translate(&ftol, -sx, -sx);
         FT_Outline_Embolden(&nol, sy * 2);
         FT_Outline_Translate(&nol, -sy, -sy);
 
-        for (i = 0; i < outline->n_points; i++)
-            outline->points[i].y = nol.points[i].y;
+        for (i = 0; i < ftol.n_points; i++)
+            ftol.points[i].y = nol.points[i].y;
 
         FT_Outline_Done(render_priv->ftlibrary, &nol);
 #endif
     }
+
+    free(contours_large);
 }
 
 /**
@@ -1168,8 +1212,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
             ass_drawing_hash(drawing);
             if(!ass_drawing_parse(drawing, 0))
                 return;
-            outline_copy(priv->ftlibrary, &drawing->outline,
-                    &v.outline);
+            v.outline = outline_copy(&drawing->outline);
             v.advance.x = drawing->advance.x;
             v.advance.y = drawing->advance.y;
             v.asc = drawing->asc;
@@ -1185,8 +1228,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
                         info->symbol, info->face_index, info->glyph_index,
                         priv->settings.hinting, info->flags);
             if (glyph != NULL) {
-                outline_copy(priv->ftlibrary,
-                        &((FT_OutlineGlyph)glyph)->outline, &v.outline);
+                v.outline = outline_convert(&((FT_OutlineGlyph)glyph)->outline);
                 if (priv->settings.shaper == ASS_SHAPING_SIMPLE) {
                     v.advance.x = d16_to_d6(glyph->advance.x);
                     v.advance.y = d16_to_d6(glyph->advance.y);
@@ -1202,12 +1244,12 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
         if (!v.outline)
             return;
 
-        FT_Outline_Get_CBox(v.outline, &v.bbox_scaled);
+        outline_get_cbox(v.outline, &v.bbox_scaled);
 
         if (info->border_style == 3) {
             FT_Vector advance;
 
-            v.border = calloc(1, sizeof(FT_Outline));
+            v.border = calloc(1, sizeof(ASS_Outline));
 
             if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing)
                 advance = v.advance;
@@ -1222,13 +1264,12 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
                 && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) {
 
             change_border(priv, info->border_x, info->border_y);
-            outline_copy(priv->ftlibrary, v.outline, &v.border);
+            v.border = outline_copy(v.outline);
             stroke_outline(priv, v.border,
                     double_to_d6(info->border_x * priv->border_scale),
                     double_to_d6(info->border_y * priv->border_scale));
         }
 
-        v.lib = priv->ftlibrary;
         val = ass_cache_put(priv->cache.outline_cache, &key, &v);
     }
 
@@ -1250,7 +1291,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
  * onto the screen plane.
  */
 static void
-transform_3d_points(FT_Vector shift, FT_Outline *outline, double frx, double fry,
+transform_3d_points(FT_Vector shift, ASS_Outline *outline, double frx, double fry,
                     double frz, double fax, double fay, double scale,
                     int yshift)
 {
@@ -1262,10 +1303,10 @@ transform_3d_points(FT_Vector shift, FT_Outline *outline, double frx, double fry
     double cz = cos(frz);
     FT_Vector *p = outline->points;
     double x, y, z, xx, yy, zz;
-    int i, dist;
+    int dist;
 
     dist = 20000 * scale;
-    for (i = 0; i < outline->n_points; i++) {
+    for (size_t i = 0; i < outline->n_points; ++i) {
         x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y));
         y = (double) p[i].y + shift.y + (-fay * p[i].x);
         z = 0.;
@@ -1302,7 +1343,7 @@ transform_3d_points(FT_Vector shift, FT_Outline *outline, 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_Outline *outline, FT_Outline *border,
+transform_3d(FT_Vector shift, ASS_Outline *outline, ASS_Outline *border,
              double frx, double fry, double frz, double fax, double fay,
              double scale, int yshift)
 {
@@ -1343,13 +1384,12 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
         BitmapHashValue hash_val;
         int error;
         double fax_scaled, fay_scaled;
-        FT_Outline *outline, *border;
         double scale_x = render_priv->font_scale_x;
 
         hash_val.bm = hash_val.bm_o = hash_val.bm_s = 0;
 
-        outline_copy(render_priv->ftlibrary, info->outline, &outline);
-        outline_copy(render_priv->ftlibrary, info->border, &border);
+        ASS_Outline *outline = outline_copy(info->outline);
+        ASS_Outline *border  = outline_copy(info->border);
 
         // calculating rotation shift vector (from rotation origin to the glyph basepoint)
         shift.x = key->shift_x;
@@ -1370,13 +1410,13 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
         // subpixel shift
         if (outline) {
             if (scale_x != 1.0)
-                FT_Outline_Transform(outline, &m);
-            FT_Outline_Translate(outline, key->advance.x, -key->advance.y);
+                outline_transform(outline, &m);
+            outline_translate(outline, key->advance.x, -key->advance.y);
         }
         if (border) {
             if (scale_x != 1.0)
-                FT_Outline_Transform(border, &m);
-            FT_Outline_Translate(border, key->advance.x, -key->advance.y);
+                outline_transform(border, &m);
+            outline_translate(border, key->advance.x, -key->advance.y);
         }
 
         // render glyph
@@ -1394,8 +1434,10 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
         val = ass_cache_put(render_priv->cache.bitmap_cache, &info->hash_key,
                 &hash_val);
 
-        outline_free(render_priv->ftlibrary, outline);
-        outline_free(render_priv->ftlibrary, border);
+        outline_free(outline);
+        free(outline);
+        outline_free(border);
+        free(border);
     }
 
     info->bm = val->bm;
index 1e5fa544bd6c74162cfc6e4cf69e20a92af75d70..e99b0fa655d169e642cb4cc386f460d42e197a19 100644 (file)
@@ -166,8 +166,8 @@ typedef struct glyph_info {
 #endif
     double font_size;
     ASS_Drawing *drawing;
-    FT_Outline *outline;
-    FT_Outline *border;
+    ASS_Outline *outline;
+    ASS_Outline *border;
     Bitmap *bm;                 // glyph bitmap
     Bitmap *bm_o;               // outline bitmap
     Bitmap *bm_s;               // shadow bitmap