From 49eb2d2ecdc12d2dcd3af8ca00067cb4161679ff Mon Sep 17 00:00:00 2001 From: "Dr.Smile" Date: Mon, 31 Jul 2017 06:27:09 +0300 Subject: renderer: switch to using two border outlines instead of one --- libass/ass_bitmap.c | 27 +++++++++---- libass/ass_bitmap.h | 10 +++-- libass/ass_cache.c | 7 ++-- libass/ass_cache.h | 5 ++- libass/ass_outline.c | 107 ++++++++++++++++++++++++++------------------------- libass/ass_outline.h | 6 +-- libass/ass_render.c | 102 +++++++++++++++++++++--------------------------- libass/ass_render.h | 2 +- 8 files changed, 134 insertions(+), 132 deletions(-) diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 80e041b..f369e25 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -187,10 +187,15 @@ Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src) } Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, - ASS_Outline *outline, int bord) + ASS_Outline *outline1, ASS_Outline *outline2, + int bord) { RasterizerData *rst = &render_priv->rasterizer; - if (!rasterizer_set_outline(rst, outline, false)) { + if (outline1 && !rasterizer_set_outline(rst, outline1, false)) { + ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); + return NULL; + } + if (outline2 && !rasterizer_set_outline(rst, outline2, !!outline1)) { ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n"); return NULL; } @@ -438,21 +443,27 @@ int be_padding(int be) return FFMAX(128 - be, 0); } -int outline_to_bitmap2(ASS_Renderer *render_priv, - ASS_Outline *outline, ASS_Outline *border, +int outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, + ASS_Outline *border1, ASS_Outline *border2, Bitmap **bm_g, Bitmap **bm_o) { assert(bm_g && bm_o); - *bm_g = *bm_o = NULL; + if (outline && !outline->n_points) + outline = NULL; + if (border1 && !border1->n_points) + border1 = NULL; + if (border2 && !border2->n_points) + border2 = NULL; + if (outline) - *bm_g = outline_to_bitmap(render_priv, outline, 1); + *bm_g = outline_to_bitmap(render_priv, outline, NULL, 1); if (!*bm_g) return 1; - if (border) { - *bm_o = outline_to_bitmap(render_priv, border, 1); + if (border1 || border2) { + *bm_o = outline_to_bitmap(render_priv, border1, border2, 1); if (!*bm_o) { return 1; } diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 3323cda..04cb51b 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -103,7 +103,8 @@ Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src); void ass_free_bitmap(Bitmap *bm); Bitmap *outline_to_bitmap(ASS_Renderer *render_priv, - ASS_Outline *outline, int bord); + ASS_Outline *outline1, ASS_Outline *outline2, + int bord); void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, double blur_radius, Bitmap *bm_g, Bitmap *bm_o); @@ -111,12 +112,13 @@ void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be, /** * \brief perform glyph rendering * \param outline original glyph - * \param border "border" glyph, produced from outline by FreeType's glyph stroker + * \param border1 inside "border" outline, produced by stroker + * \param border2 outside "border" outline, produced by stroker * \param bm_g out: pointer to the bitmap of original glyph is returned here * \param bm_o out: pointer to the bitmap of border glyph is returned here */ -int outline_to_bitmap2(ASS_Renderer *render_priv, - ASS_Outline *outline, ASS_Outline *border, +int outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, + ASS_Outline *border1, ASS_Outline *border2, Bitmap **bm_g, Bitmap **bm_o); int be_padding(int be); diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 577f7f3..2e8d7d7 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -259,10 +259,9 @@ static void outline_destruct(void *key, void *value) { OutlineHashValue *v = value; OutlineHashKey *k = key; - outline_free(v->outline); - free(v->outline); - outline_free(v->border); - free(v->border); + outline_free(&v->outline); + outline_free(&v->border[0]); + outline_free(&v->border[1]); switch (k->type) { case OUTLINE_GLYPH: ass_cache_dec_ref(k->u.glyph.font); break; case OUTLINE_DRAWING: free(k->u.drawing.text); break; diff --git a/libass/ass_cache.h b/libass/ass_cache.h index 687c197..64751df 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -22,6 +22,7 @@ #include "ass.h" #include "ass_font.h" +#include "ass_outline.h" #include "ass_bitmap.h" typedef struct cache Cache; @@ -40,8 +41,8 @@ typedef struct { } CompositeHashValue; typedef struct { - ASS_Outline *outline; - ASS_Outline *border; + ASS_Outline outline; + ASS_Outline border[2]; 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_outline.c b/libass/ass_outline.c index 1facc6d..60bb7ee 100644 --- a/libass/ass_outline.c +++ b/libass/ass_outline.c @@ -29,62 +29,61 @@ bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_contours) 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) + if (!outline->contours || !outline->points || !outline->tags) { + outline_free(outline); return false; + } outline->max_contours = n_contours; outline->max_points = n_points; return true; } -ASS_Outline *outline_create(size_t n_points, size_t n_contours) +static void outline_clear(ASS_Outline *outline) { - ASS_Outline *ol = calloc(1, sizeof(*ol)); - if (!ol) - return NULL; - - if (!outline_alloc(ol, n_points, n_contours)) { - outline_free(ol); - free(ol); - return NULL; - } + outline->contours = NULL; + outline->points = NULL; + outline->tags = NULL; - return ol; + outline->n_contours = outline->max_contours = 0; + outline->n_points = outline->max_points = 0; } -ASS_Outline *outline_convert(const FT_Outline *source) +bool outline_convert(ASS_Outline *outline, const FT_Outline *source) { - if (!source) - return NULL; + if (!source || !source->n_points) { + outline_clear(outline); + return true; + } - ASS_Outline *ol = outline_create(source->n_points, source->n_contours); - if (!ol) - return NULL; + if (!outline_alloc(outline, source->n_points, source->n_contours)) + return false; 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; + outline->contours[i] = source->contours[i]; + memcpy(outline->points, source->points, sizeof(FT_Vector) * source->n_points); + memcpy(outline->tags, source->tags, source->n_points); + outline->n_contours = source->n_contours; + outline->n_points = source->n_points; + return true; } -ASS_Outline *outline_copy(const ASS_Outline *source) +bool outline_copy(ASS_Outline *outline, const ASS_Outline *source) { - if (!source) - return NULL; - - ASS_Outline *ol = outline_create(source->n_points, source->n_contours); - if (!ol) - return NULL; - - 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; + if (!source || !source->n_points) { + outline_clear(outline); + return true; + } + + if (!outline_alloc(outline, source->n_points, source->n_contours)) + return false; + + memcpy(outline->contours, source->contours, sizeof(size_t) * source->n_contours); + memcpy(outline->points, source->points, sizeof(FT_Vector) * source->n_points); + memcpy(outline->tags, source->tags, source->n_points); + outline->n_contours = source->n_contours; + outline->n_points = source->n_points; + return true; } void outline_free(ASS_Outline *outline) @@ -95,6 +94,8 @@ void outline_free(ASS_Outline *outline) free(outline->contours); free(outline->points); free(outline->tags); + + outline_clear(outline); } @@ -154,6 +155,19 @@ void outline_transform(const ASS_Outline *outline, const FT_Matrix *matrix) } } +void outline_update_cbox(const ASS_Outline *outline, FT_BBox *cbox) +{ + if (!outline) + return; + + for (size_t i = 0; 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); + } +} + void outline_get_cbox(const ASS_Outline *outline, FT_BBox *cbox) { if (!outline->n_points) { @@ -968,24 +982,12 @@ static bool close_contour(StrokerState *str, int dir) bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, const ASS_Outline *path, int xbord, int ybord, int eps) { - if (result1) - result1->n_contours = result1->n_points = 0; - int rad = FFMAX(xbord, ybord); - if (rad < eps) { - assert(result->max_contours >= path->n_contours); - assert(result->max_points >= path->n_points); - memcpy(result->contours, path->contours, sizeof(size_t) * path->n_contours); - memcpy(result->points, path->points, sizeof(FT_Vector) * path->n_points); - memcpy(result->tags, path->tags, path->n_points); - result->n_contours = path->n_contours; - result->n_points = path->n_points; - return true; - } + assert(rad >= eps); result->n_contours = result->n_points = 0; + result1->n_contours = result1->n_points = 0; - int dir = result1 ? 3 : 1; StrokerState str; str.result[0] = result; str.result[1] = result1; @@ -1009,6 +1011,7 @@ bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, S_ON, S_Q, S_C1, S_C2 }; + const int dir = 3; for (size_t i = 0, j = 0; i < path->n_contours; i++) { OutlinePoint start, p[4]; int process_end = 1; diff --git a/libass/ass_outline.h b/libass/ass_outline.h index 9f38020..0a1b8ec 100644 --- a/libass/ass_outline.h +++ b/libass/ass_outline.h @@ -33,9 +33,8 @@ typedef struct ass_outline { } ASS_Outline; bool outline_alloc(ASS_Outline *outline, size_t n_points, size_t n_contours); -ASS_Outline *outline_create(size_t n_points, size_t n_contours); -ASS_Outline *outline_convert(const FT_Outline *source); -ASS_Outline *outline_copy(const ASS_Outline *source); +bool outline_convert(ASS_Outline *outline, const FT_Outline *source); +bool outline_copy(ASS_Outline *outline, const ASS_Outline *source); void outline_free(ASS_Outline *outline); bool outline_add_point(ASS_Outline *outline, FT_Vector pt, char tag); @@ -43,6 +42,7 @@ bool outline_close_contour(ASS_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_update_cbox(const ASS_Outline *outline, FT_BBox *cbox); void outline_get_cbox(const ASS_Outline *outline, FT_BBox *cbox); bool outline_stroke(ASS_Outline *result, ASS_Outline *result1, diff --git a/libass/ass_render.c b/libass/ass_render.c index 88e1a7d..7e8f634 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -492,7 +492,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv, outline_translate(outline, trans.x, trans.y); } - val->bm = outline_to_bitmap(render_priv, outline, 0); + val->bm = outline_to_bitmap(render_priv, outline, NULL, 1); ass_cache_commit(val, bitmap_size(val->bm) + sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); } @@ -1035,7 +1035,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) ass_cache_dec_ref(val); return; } - val->outline = outline_copy(&drawing->outline); + outline_copy(&val->outline, &drawing->outline); val->advance.x = drawing->advance.x; val->advance.y = drawing->advance.y; val->asc = drawing->asc; @@ -1050,7 +1050,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) { - val->outline = outline_convert(&((FT_OutlineGlyph) glyph)->outline); + outline_convert(&val->outline, &((FT_OutlineGlyph) glyph)->outline); if (priv->settings.shaper == ASS_SHAPING_SIMPLE) { val->advance.x = d16_to_d6(glyph->advance.x); val->advance.y = d16_to_d6(glyph->advance.y); @@ -1063,61 +1063,55 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) } } - if (!val->outline) { + if (!val->outline.n_points) { ass_cache_commit(val, 1); ass_cache_dec_ref(val); return; } - outline_get_cbox(val->outline, &val->bbox_scaled); + outline_get_cbox(&val->outline, &val->bbox_scaled); if (info->border_style == 3) { - val->border = calloc(1, sizeof(ASS_Outline)); - if (!val->border) { - outline_free(val->outline); - free(val->outline); - val->outline = NULL; - ass_cache_commit(val, 1); - ass_cache_dec_ref(val); - return; - } - FT_Vector advance; if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing) advance = val->advance; else advance = info->advance; - draw_opaque_box(priv, info, val->asc, val->desc, val->border, advance, - double_to_d6(info->border_x * priv->border_scale), - double_to_d6(info->border_y * priv->border_scale)); + draw_opaque_box(priv, info, val->asc, val->desc, &val->border[0], advance, + double_to_d6(info->border_x * priv->border_scale), + double_to_d6(info->border_y * priv->border_scale)); } else if ((info->border_x > 0 || info->border_y > 0) && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) { - - val->border = outline_create(2 * val->outline->n_points, - val->outline->n_contours); - if (val->border && !outline_stroke(val->border, NULL, val->outline, - double_to_d6(info->border_x * priv->border_scale), - double_to_d6(info->border_y * priv->border_scale), 16)) { - ass_msg(priv->library, MSGL_WARN, "Cannot stoke outline"); - outline_free(val->border); - free(val->border); - val->border = NULL; + const int eps = 16; + int xbord = double_to_d6(info->border_x * priv->border_scale); + int ybord = double_to_d6(info->border_y * priv->border_scale); + if(xbord >= eps || ybord >= eps) { + outline_alloc(&val->border[0], 2 * val->outline.n_points, val->outline.n_contours); + outline_alloc(&val->border[1], 2 * val->outline.n_points, val->outline.n_contours); + if (!val->border[0].max_points || !val->border[1].max_points || + !outline_stroke(&val->border[0], &val->border[1], + &val->outline, xbord, ybord, eps)) { + ass_msg(priv->library, MSGL_WARN, "Cannot stoke outline"); + outline_free(&val->border[0]); + outline_free(&val->border[1]); + } } } ass_cache_commit(val, 1); } - if (!val->outline) { + if (!val->outline.n_points) { ass_cache_dec_ref(val); return; } info->hash_key.u.outline.outline = val; - info->outline = val->outline; - info->border = val->border; + info->outline = &val->outline; + info->border[0] = &val->border[0]; + info->border[1] = &val->border[1]; info->bbox = val->bbox_scaled; if (info->drawing || priv->settings.shaper == ASS_SHAPING_SIMPLE) { info->cluster_advance.x = info->advance.x = val->advance.x; @@ -1185,21 +1179,16 @@ transform_3d_points(FT_Vector shift, ASS_Outline *outline, double frx, double fr * 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, ASS_Outline *outline, ASS_Outline *border, +transform_3d(FT_Vector shift, ASS_Outline *outline, int n_outlines, double frx, double fry, double frz, double fax, double fay, double scale, int yshift) { frx = -frx; frz = -frz; - if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) { - if (outline) - transform_3d_points(shift, outline, frx, fry, frz, - fax, fay, scale, yshift); - - if (border) - transform_3d_points(shift, border, frx, fry, frz, + if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) + for (int i = 0; i < n_outlines; i++) + transform_3d_points(shift, &outline[i], frx, fry, frz, fax, fay, scale, yshift); - } } /** @@ -1225,8 +1214,11 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) if (!val) return; - ASS_Outline *outline = outline_copy(info->outline); - ASS_Outline *border = outline_copy(info->border); + const int n_outlines = 3; + ASS_Outline outline[n_outlines]; + outline_copy(&outline[0], info->outline); + outline_copy(&outline[1], info->border[0]); + outline_copy(&outline[2], info->border[1]); // calculating rotation shift vector (from rotation origin to the glyph basepoint) FT_Vector shift = { key->shift_x, key->shift_y }; @@ -1236,7 +1228,7 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) // apply rotation // use blur_scale because, like blurs, VSFilter forgets to scale this - transform_3d(shift, outline, border, + transform_3d(shift, outline, n_outlines, info->frx, info->fry, info->frz, fax_scaled, fay_scaled, render_priv->blur_scale, info->asc); @@ -1245,19 +1237,15 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) 0, double_to_d16(1.0) }; // subpixel shift - if (outline) { - if (scale_x != 1.0) - outline_transform(outline, &m); - outline_translate(outline, key->advance.x, -key->advance.y); - } - if (border) { - if (scale_x != 1.0) - outline_transform(border, &m); - outline_translate(border, key->advance.x, -key->advance.y); - } + if (scale_x != 1.0) + for (int i = 0; i < n_outlines; i++) + outline_transform(&outline[i], &m); + for (int i = 0; i < n_outlines; i++) + outline_translate(&outline[i], key->advance.x, -key->advance.y); // render glyph - int error = outline_to_bitmap2(render_priv, outline, border, + int error = outline_to_bitmap2(render_priv, + &outline[0], &outline[1], &outline[2], &val->bm, &val->bm_o); if (error) info->symbol = 0; @@ -1266,10 +1254,8 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) sizeof(BitmapHashKey) + sizeof(BitmapHashValue)); info->image = val; - outline_free(outline); - free(outline); - outline_free(border); - free(border); + for (int i = 0; i < n_outlines; i++) + outline_free(&outline[i]); } /** diff --git a/libass/ass_render.h b/libass/ass_render.h index e858813..8731a96 100644 --- a/libass/ass_render.h +++ b/libass/ass_render.h @@ -149,7 +149,7 @@ typedef struct glyph_info { double font_size; ASS_Drawing *drawing; ASS_Outline *outline; - ASS_Outline *border; + ASS_Outline *border[2]; FT_BBox bbox; FT_Vector pos; FT_Vector offset; -- cgit v1.2.3