#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)) {
#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;
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
/**
}
}
-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)
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
} 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);
* \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);
{
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);
} 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
#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;
}
/*
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,
* 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)
{
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);
}
/*
*/
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;
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;
}
{
if (drawing) {
free(drawing->text);
- FT_Outline_Done(drawing->ftlibrary, &drawing->outline);
+ outline_free(&drawing->outline);
}
free(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;
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;
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;
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;
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
}
// 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;
}
#include FT_OUTLINE_H
#include "ass.h"
+#include "ass_bitmap.h"
typedef enum {
TOKEN_MOVE,
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)
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
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 */
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);
}
/**
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.
* \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;
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++) {
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;
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;
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 */
}
-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];
#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,
/**
* \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)
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;
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.");
.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);
* 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;
{ .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;
}
* 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)
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
#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);
}
/**
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;
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);
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;
&& 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);
}
* 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)
{
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.;
* 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)
{
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;
// 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
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;
#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