summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2014-11-23 20:01:03 +0300
committerDr.Smile <vabnick@gmail.com>2014-11-23 20:01:03 +0300
commit507ae26358a491c7f665d32a3e07c2f176d152e9 (patch)
treee7827a525028d594eb4d3a35ea80a6a9f139da11
parentf3f8230189634e0ce4ffe06c1e380bea829d85d9 (diff)
downloadlibass-507ae26358a491c7f665d32a3e07c2f176d152e9.tar.bz2
libass-507ae26358a491c7f665d32a3e07c2f176d152e9.tar.xz
Replace FT_Outline with ASS_Outline
-rw-r--r--libass/ass_bitmap.c45
-rw-r--r--libass/ass_bitmap.h14
-rw-r--r--libass/ass_cache.c8
-rw-r--r--libass/ass_cache.h5
-rw-r--r--libass/ass_drawing.c94
-rw-r--r--libass/ass_drawing.h7
-rw-r--r--libass/ass_font.c137
-rw-r--r--libass/ass_font.h12
-rw-r--r--libass/ass_rasterizer.c4
-rw-r--r--libass/ass_rasterizer.h7
-rw-r--r--libass/ass_render.c140
-rw-r--r--libass/ass_render.h4
12 files changed, 335 insertions, 142 deletions
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c
index 0eb4577..01bf013 100644
--- a/libass/ass_bitmap.c
+++ b/libass/ass_bitmap.c
@@ -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)
diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h
index 82a2159..4a070ba 100644
--- a/libass/ass_bitmap.h
+++ b/libass/ass_bitmap.h
@@ -30,6 +30,16 @@ 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
int stride;
@@ -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);
diff --git a/libass/ass_cache.c b/libass/ass_cache.c
index a0a00b3..062ddfa 100644
--- a/libass/ass_cache.c
+++ b/libass/ass_cache.c
@@ -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);
diff --git a/libass/ass_cache.h b/libass/ass_cache.h
index 677b705..0600142 100644
--- a/libass/ass_cache.h
+++ b/libass/ass_cache.h
@@ -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
diff --git a/libass/ass_drawing.c b/libass/ass_drawing.c
index 70afae5..e2676df 100644
--- a/libass/ass_drawing.c
+++ b/libass/ass_drawing.c
@@ -20,10 +20,12 @@
#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
@@ -32,46 +34,42 @@
/*
* \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;
}
diff --git a/libass/ass_drawing.h b/libass/ass_drawing.h
index 62010eb..1e73c27 100644
--- a/libass/ass_drawing.h
+++ b/libass/ass_drawing.h
@@ -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 */
diff --git a/libass/ass_font.c b/libass/ass_font.c
index 69675c6..7b202a6 100644
--- a/libass/ass_font.c
+++ b/libass/ass_font.c
@@ -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;
diff --git a/libass/ass_font.h b/libass/ass_font.h
index f80b887..f3c3f8e 100644
--- a/libass/ass_font.h
+++ b/libass/ass_font.h
@@ -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 */
diff --git a/libass/ass_rasterizer.c b/libass/ass_rasterizer.c
index 93a4d5a..84f9a88 100644
--- a/libass/ass_rasterizer.c
+++ b/libass/ass_rasterizer.c
@@ -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];
diff --git a/libass/ass_rasterizer.h b/libass/ass_rasterizer.h
index 9da475e..6630317 100644
--- a/libass/ass_rasterizer.h
+++ b/libass/ass_rasterizer.h
@@ -19,11 +19,12 @@
#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)
diff --git a/libass/ass_render.c b/libass/ass_render.c
index d3e262f..4371aa3 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -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);
@@