summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2017-07-31 06:27:09 +0300
committerDr.Smile <vabnick@gmail.com>2017-07-31 06:27:09 +0300
commit49eb2d2ecdc12d2dcd3af8ca00067cb4161679ff (patch)
tree9c69279fef4cc1e38dca2245b589c9c494b532de
parentef6cc020bc00118a5b142b37fe401327a029a1fc (diff)
downloadlibass-49eb2d2ecdc12d2dcd3af8ca00067cb4161679ff.tar.bz2
libass-49eb2d2ecdc12d2dcd3af8ca00067cb4161679ff.tar.xz
renderer: switch to using two border outlines instead of one
-rw-r--r--libass/ass_bitmap.c27
-rw-r--r--libass/ass_bitmap.h10
-rw-r--r--libass/ass_cache.c7
-rw-r--r--libass/ass_cache.h5
-rw-r--r--libass/ass_outline.c107
-rw-r--r--libass/ass_outline.h6
-rw-r--r--libass/ass_render.c102
-rw-r--r--libass/ass_render.h2
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;