summaryrefslogtreecommitdiffstats
path: root/libass/ass_render.c
diff options
context:
space:
mode:
Diffstat (limited to 'libass/ass_render.c')
-rw-r--r--libass/ass_render.c631
1 files changed, 313 insertions, 318 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c
index e1cdb4f..5b790c9 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -459,48 +459,15 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
if (!render_priv->state.clip_drawing_text)
return;
- // Try to get mask from cache
+ // Get mask from cache
BitmapHashKey key;
- memset(&key, 0, sizeof(key));
key.type = BITMAP_CLIP;
+ key.u.clip.scale = render_priv->state.clip_drawing_scale;
key.u.clip.text = render_priv->state.clip_drawing_text;
- BitmapHashValue *val;
- if (!ass_cache_get(render_priv->cache.bitmap_cache, &key, &val)) {
- if (!val)
- return;
- val->bm = val->bm_o = NULL;
-
- // Not found in cache, parse and rasterize it
- ASS_Drawing drawing;
- drawing.text = render_priv->state.clip_drawing_text;
- drawing.scale = render_priv->state.clip_drawing_scale;
- drawing.pbo = 0;
- drawing.scale_x = render_priv->font_scale_x * render_priv->font_scale;
- drawing.scale_y = render_priv->font_scale;
- if (!ass_drawing_parse(&drawing, render_priv->library, true)) {
- ass_msg(render_priv->library, MSGL_WARN,
- "Clip vector parsing failed. Skipping.");
- ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
- ass_cache_dec_ref(val);
- return;
- }
-
- // We need to translate the clip according to screen borders
- if (render_priv->settings.left_margin != 0 ||
- render_priv->settings.top_margin != 0) {
- ASS_Vector trans = {
- .x = int_to_d6(render_priv->settings.left_margin),
- .y = int_to_d6(render_priv->settings.top_margin),
- };
- outline_translate(&drawing.outline, trans.x, trans.y);
- }
-
- val->bm = outline_to_bitmap(render_priv, &drawing.outline, NULL, 1);
- ass_cache_commit(val, bitmap_size(val->bm) +
- sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
- outline_free(&drawing.outline);
- }
+ BitmapHashValue *val = ass_cache_get(render_priv->cache.bitmap_cache, &key, render_priv);
+ if (!val)
+ return;
Bitmap *clip_bm = val->bm;
if (!clip_bm) {
@@ -917,20 +884,17 @@ static void free_render_context(ASS_Renderer *render_priv)
* Replace the outline of a glyph by a contour which makes up a simple
* opaque rectangle.
*/
-static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info,
+static void draw_opaque_box(ASS_Renderer *render_priv,
+ double scale_x, double scale_y,
int asc, int desc, ASS_Outline *ol,
int adv, int sx, int sy)
{
- double scale_y = info->orig_scale_y;
- double scale_x = info->orig_scale_x;
-
// to avoid gaps
sx = FFMAX(64, sx);
sy = FFMAX(64, sy);
// Emulate the WTFish behavior of VSFilter, i.e. double-scale
// the sizes of the opaque box.
- adv += double_to_d6(info->hspacing * render_priv->font_scale * scale_x);
adv *= scale_x;
sx *= scale_x;
sy *= scale_y;
@@ -967,38 +931,40 @@ static void
fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key,
GlyphInfo *info)
{
+ OutlineCommonKey *common = &outline_key->u.common;
+ common->scale_x = double_to_d16(info->scale_x);
+ common->scale_y = double_to_d16(info->scale_y);
+ common->outline.x = double_to_d6(info->border_x * priv->border_scale);
+ common->outline.y = double_to_d6(info->border_y * priv->border_scale);
+ common->border_style = info->border_style;
+ // following fields only matter for opaque box borders (see draw_opaque_box),
+ // so for normal borders, maximize cache utility by ignoring them
+ if (info->border_style == 3) {
+ common->scale_fix = double_to_d16(info->scale_fix);
+ common->advance = info->hspacing_scaled;
+ if (priv->settings.shaper != ASS_SHAPING_SIMPLE && !info->drawing_text)
+ common->advance += info->advance.x;
+ } else {
+ common->scale_fix = 0;
+ common->advance = 0;
+ }
+
if (info->drawing_text) {
- DrawingHashKey *key = &outline_key->u.drawing;
outline_key->type = OUTLINE_DRAWING;
- key->scale_x = double_to_d16(info->scale_x);
- key->scale_y = double_to_d16(info->scale_y);
- key->outline.x = double_to_d6(info->border_x * priv->border_scale);
- key->outline.y = double_to_d6(info->border_y * priv->border_scale);
- key->border_style = info->border_style;
- // hpacing only matters for opaque box borders (see draw_opaque_box),
- // so for normal borders, maximize cache utility by ignoring it
- key->hspacing =
- info->border_style == 3 ? double_to_d16(info->hspacing) : 0;
+ DrawingHashKey *key = &outline_key->u.drawing;
key->text = info->drawing_text;
key->pbo = info->drawing_pbo;
key->scale = info->drawing_scale;
} else {
- GlyphHashKey *key = &outline_key->u.glyph;
outline_key->type = OUTLINE_GLYPH;
+ GlyphHashKey *key = &outline_key->u.glyph;
key->font = info->font;
key->size = info->font_size;
key->face_index = info->face_index;
key->glyph_index = info->glyph_index;
key->bold = info->bold;
key->italic = info->italic;
- key->scale_x = double_to_d16(info->scale_x);
- key->scale_y = double_to_d16(info->scale_y);
- key->outline.x = double_to_d6(info->border_x * priv->border_scale);
- key->outline.y = double_to_d6(info->border_y * priv->border_scale);
key->flags = info->flags;
- key->border_style = info->border_style;
- key->hspacing =
- info->border_style == 3 ? double_to_d16(info->hspacing) : 0;
}
}
@@ -1018,7 +984,6 @@ static void fill_composite_hash(CompositeHashKey *hk, CombinedBitmapInfo *info)
* Tries to get both glyphs from cache.
* If they can't be found, gets a glyph from font face, generates outline,
* and add them to cache.
- * The glyphs are returned in info->glyph and info->outline_glyph
*/
static void
get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
@@ -1026,88 +991,9 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
memset(&info->hash_key, 0, sizeof(info->hash_key));
OutlineHashKey key;
- OutlineHashValue *val;
fill_glyph_hash(priv, &key, info);
- if (!ass_cache_get(priv->cache.outline_cache, &key, &val)) {
- if (!val)
- return;
- memset(val, 0, sizeof(*val));
-
- if (info->drawing_text) {
- ASS_Drawing drawing;
- drawing.text = info->drawing_text;
- drawing.scale = info->drawing_scale;
- drawing.pbo = info->drawing_pbo;
- drawing.scale_x = info->scale_x * priv->font_scale;
- drawing.scale_y = info->scale_y * priv->font_scale;
- if (!ass_drawing_parse(&drawing, priv->library, false)) {
- ass_cache_commit(val, 1);
- ass_cache_dec_ref(val);
- return;
- }
- outline_move(&val->outline, &drawing.outline);
- val->advance = drawing.advance;
- val->asc = drawing.asc;
- val->desc = drawing.desc;
- } else {
- ass_face_set_size(info->font->faces[info->face_index],
- info->font_size);
- ass_font_set_transform(info->font, info->scale_x, info->scale_y);
- FT_Glyph glyph =
- ass_font_get_glyph(info->font,
- info->face_index, info->glyph_index,
- priv->settings.hinting, info->flags);
- if (glyph != NULL) {
- FT_Outline *src = &((FT_OutlineGlyph) glyph)->outline;
- if (!outline_convert(&val->outline, src)) {
- ass_cache_commit(val, 1);
- ass_cache_dec_ref(val);
- return;
- }
- if (priv->settings.shaper == ASS_SHAPING_SIMPLE)
- val->advance = d16_to_d6(glyph->advance.x);
- FT_Done_Glyph(glyph);
- ass_font_get_asc_desc(info->font, info->face_index,
- &val->asc, &val->desc);
- val->asc *= info->scale_y;
- val->desc *= info->scale_y;
- }
- }
- val->valid = true;
-
- outline_get_cbox(&val->outline, &val->bbox_scaled);
-
- if (info->border_style == 3) {
- int advance;
- if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing_text)
- advance = val->advance;
- else
- advance = info->advance.x;
-
- 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 (val->outline.n_points && (info->border_x > 0 || info->border_y > 0)
- && double_to_d6(info->scale_x) && double_to_d6(info->scale_y)) {
- 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, 2 * val->outline.n_segments);
- outline_alloc(&val->border[1], 2 * val->outline.n_points, 2 * val->outline.n_segments);
- 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);
- } else if (!val->valid) {
+ OutlineHashValue *val = ass_cache_get(priv->cache.outline_cache, &key, priv);
+ if (!val || !val->valid) {
ass_cache_dec_ref(val);
return;
}
@@ -1125,6 +1011,84 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
info->desc = val->desc;
}
+size_t ass_outline_construct(void *key, void *value, void *priv)
+{
+ ASS_Renderer *render_priv = priv;
+ OutlineHashKey *outline_key = key;
+ OutlineHashValue *v = value;
+ memset(v, 0, sizeof(*v));
+
+ OutlineCommonKey *common = &outline_key->u.common;
+ double scale_x = d16_to_double(common->scale_x);
+ double scale_y = d16_to_double(common->scale_y);
+
+ if (outline_key->type == OUTLINE_DRAWING) {
+ DrawingHashKey *k = &outline_key->u.drawing;
+
+ ASS_Drawing drawing;
+ drawing.text = k->text;
+ drawing.scale = k->scale;
+ drawing.pbo = k->pbo;
+ drawing.scale_x = scale_x * render_priv->font_scale;
+ drawing.scale_y = scale_y * render_priv->font_scale;
+ if (!ass_drawing_parse(&drawing, render_priv->library, false))
+ return 1;
+ outline_move(&v->outline, &drawing.outline);
+ v->advance = drawing.advance;
+ v->asc = drawing.asc;
+ v->desc = drawing.desc;
+ } else {
+ GlyphHashKey *k = &outline_key->u.glyph;
+ ass_face_set_size(k->font->faces[k->face_index], k->size);
+ ass_font_set_transform(k->font, scale_x, scale_y);
+ FT_Glyph glyph =
+ ass_font_get_glyph(k->font, k->face_index, k->glyph_index,
+ render_priv->settings.hinting, k->flags);
+ if (glyph != NULL) {
+ FT_Outline *src = &((FT_OutlineGlyph) glyph)->outline;
+ if (!outline_convert(&v->outline, src))
+ return 1;
+ if (render_priv->settings.shaper == ASS_SHAPING_SIMPLE)
+ v->advance = d16_to_d6(glyph->advance.x);
+ FT_Done_Glyph(glyph);
+ ass_font_get_asc_desc(k->font, k->face_index,
+ &v->asc, &v->desc);
+ v->asc *= scale_y;
+ v->desc *= scale_y;
+ }
+ }
+ v->valid = true;
+
+ outline_get_cbox(&v->outline, &v->bbox_scaled);
+
+ if (common->border_style == 3) {
+ int advance = common->advance;
+ if (render_priv->settings.shaper == ASS_SHAPING_SIMPLE ||
+ outline_key->type == OUTLINE_DRAWING)
+ advance += v->advance;
+
+ double scale_fix = d16_to_double(common->scale_fix);
+ draw_opaque_box(priv, scale_x * scale_fix, scale_y * scale_fix,
+ v->asc, v->desc, &v->border[0], advance,
+ common->outline.x, common->outline.y);
+
+ } else if (v->outline.n_points && common->scale_x && common->scale_y) {
+ const int eps = 16;
+ if (common->outline.x >= eps || common->outline.y >= eps) {
+ outline_alloc(&v->border[0], 2 * v->outline.n_points, 2 * v->outline.n_segments);
+ outline_alloc(&v->border[1], 2 * v->outline.n_points, 2 * v->outline.n_segments);
+ if (!v->border[0].max_points || !v->border[1].max_points ||
+ !outline_stroke(&v->border[0], &v->border[1],
+ &v->outline, common->outline.x, common->outline.y, eps)) {
+ ass_msg(render_priv->library, MSGL_WARN, "Cannot stroke outline");
+ outline_free(&v->border[0]);
+ outline_free(&v->border[1]);
+ }
+ }
+ }
+ return 1;
+}
+
/**
* \brief Calculate transform matrix for transform_3d()
*/
@@ -1217,61 +1181,86 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info)
if (!info->outline || info->symbol == '\n' || info->symbol == 0 || info->skip)
return;
- BitmapHashValue *val;
- OutlineBitmapHashKey *key = &info->hash_key.u.outline;
- if (ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key, &val)) {
- info->image = val;
- if (!val->valid)
- info->symbol = 0;
- return;
- }
- if (!val) {
- info->symbol = 0;
- return;
- }
- if (!info->outline) {
- memset(val, 0, sizeof(*val));
- ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
- info->image = val;
+ BitmapHashValue *val = ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key, render_priv);
+ if (!val || !val->valid)
info->symbol = 0;
- return;
+ info->image = val;
+}
+
+size_t ass_bitmap_construct(void *key, void *value, void *priv)
+{
+ ASS_Renderer *render_priv = priv;
+ BitmapHashKey *bitmap_key = key;
+ BitmapHashValue *v = value;
+ v->bm = v->bm_o = NULL;
+ v->valid = false;
+
+ const size_t hdr = sizeof(BitmapHashKey) + sizeof(BitmapHashValue);
+
+ if (bitmap_key->type == BITMAP_CLIP) {
+ ASS_Drawing drawing;
+ drawing.text = bitmap_key->u.clip.text;
+ drawing.scale = bitmap_key->u.clip.scale;
+ drawing.pbo = 0;
+ drawing.scale_x = render_priv->font_scale_x * render_priv->font_scale;
+ drawing.scale_y = render_priv->font_scale;
+ if (!ass_drawing_parse(&drawing, render_priv->library, true)) {
+ ass_msg(render_priv->library, MSGL_WARN,
+ "Clip vector parsing failed. Skipping.");
+ return hdr;
+ }
+
+ // We need to translate the clip according to screen borders
+ if (render_priv->settings.left_margin != 0 ||
+ render_priv->settings.top_margin != 0) {
+ ASS_Vector trans = {
+ .x = int_to_d6(render_priv->settings.left_margin),
+ .y = int_to_d6(render_priv->settings.top_margin),
+ };
+ outline_translate(&drawing.outline, trans.x, trans.y);
+ }
+
+ v->bm = outline_to_bitmap(render_priv, &drawing.outline, NULL, 1);
+ outline_free(&drawing.outline);
+ v->valid = !!v->bm;
+
+ return bitmap_size(v->bm) + hdr;
}
+ OutlineBitmapHashKey *k = &bitmap_key->u.outline;
+ if (!k->outline->valid)
+ return hdr;
+
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]);
+ outline_copy(&outline[0], &k->outline->outline);
+ outline_copy(&outline[1], &k->outline->border[0]);
+ outline_copy(&outline[2], &k->outline->border[1]);
// calculating rotation shift vector (from rotation origin to the glyph basepoint)
- ASS_Vector shift = { key->shift_x, key->shift_y };
+ ASS_Vector shift = { k->shift_x, k->shift_y };
double scale_x = render_priv->font_scale_x;
- double fax_scaled = info->fax / info->scale_y * info->scale_x;
- double fay_scaled = info->fay / info->scale_x * info->scale_y;
+ double fax_scaled = d16_to_double(k->fax);
+ double fay_scaled = d16_to_double(k->fay);
// apply rotation
// use blur_scale because, like blurs, VSFilter forgets to scale this
transform_3d(shift, outline, n_outlines,
- info->frx, info->fry, info->frz, fax_scaled,
- fay_scaled, render_priv->blur_scale, info->asc);
+ d22_to_double(k->frx), d22_to_double(k->fry), d22_to_double(k->frz),
+ fax_scaled, fay_scaled, render_priv->blur_scale, k->outline->asc);
// PAR correction scaling + subpixel shift
for (int i = 0; i < n_outlines; i++)
- outline_adjust(&outline[i], scale_x, key->advance.x, key->advance.y);
+ outline_adjust(&outline[i], scale_x, k->advance.x, k->advance.y);
// render glyph
- val->valid = outline_to_bitmap2(render_priv,
- &outline[0], &outline[1], &outline[2],
- &val->bm, &val->bm_o);
- if (!val->valid)
- info->symbol = 0;
-
- ass_cache_commit(val, bitmap_size(val->bm) + bitmap_size(val->bm_o) +
- sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
- info->image = val;
-
+ v->valid = outline_to_bitmap2(render_priv,
+ &outline[0], &outline[1], &outline[2],
+ &v->bm, &v->bm_o);
for (int i = 0; i < n_outlines; i++)
outline_free(&outline[i]);
+
+ return bitmap_size(v->bm) + bitmap_size(v->bm_o) + hdr;
}
/**
@@ -1584,8 +1573,8 @@ fill_bitmap_hash(ASS_Renderer *priv, GlyphInfo *info,
hash_key->frx = rot_key(info->frx);
hash_key->fry = rot_key(info->fry);
hash_key->frz = rot_key(info->frz);
- hash_key->fax = double_to_d16(info->fax);
- hash_key->fay = double_to_d16(info->fay);
+ hash_key->fax = double_to_d16(info->fax * info->scale_x / info->scale_y);
+ hash_key->fay = double_to_d16(info->fay * info->scale_y / info->scale_x);
}
/**
@@ -1610,8 +1599,10 @@ fix_glyph_scaling(ASS_Renderer *priv, GlyphInfo *glyph)
// to freetype. Normalize scale_y to 1.0.
ft_size = glyph->scale_y * glyph->font_size;
}
- glyph->scale_x = glyph->scale_x * glyph->font_size / ft_size;
- glyph->scale_y = glyph->scale_y * glyph->font_size / ft_size;
+ double mul = glyph->font_size / ft_size;
+ glyph->scale_fix = 1 / mul;
+ glyph->scale_x *= mul;
+ glyph->scale_y *= mul;
glyph->font_size = ft_size;
}
@@ -1653,38 +1644,39 @@ static bool is_new_bm_run(GlyphInfo *info, GlyphInfo *last)
((last->flags ^ info->flags) & ~DECO_ROTATE);
}
-static void make_shadow_bitmap(CombinedBitmapInfo *info, ASS_Renderer *render_priv)
+static void make_shadow_bitmap(ASS_Renderer *render_priv,
+ CompositeHashValue *val, const FilterDesc *filter)
{
- if (!(info->filter.flags & FILTER_NONZERO_SHADOW)) {
- if (info->bm && info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) {
- fix_outline(info->bm, info->bm_o);
- } else if (info->bm_o && !(info->filter.flags & FILTER_NONZERO_BORDER)) {
- ass_free_bitmap(info->bm_o);
- info->bm_o = 0;
+ if (!(filter->flags & FILTER_NONZERO_SHADOW)) {
+ if (val->bm && val->bm_o && !(filter->flags & FILTER_BORDER_STYLE_3)) {
+ fix_outline(val->bm, val->bm_o);
+ } else if (val->bm_o && !(filter->flags & FILTER_NONZERO_BORDER)) {
+ ass_free_bitmap(val->bm_o);
+ val->bm_o = NULL;
}
return;
}
// Create shadow and fix outline as needed
- if (info->bm && info->bm_o && !(info->filter.flags & FILTER_BORDER_STYLE_3)) {
- info->bm_s = copy_bitmap(render_priv->engine, info->bm_o);
- fix_outline(info->bm, info->bm_o);
- } else if (info->bm_o && (info->filter.flags & FILTER_NONZERO_BORDER)) {
- info->bm_s = copy_bitmap(render_priv->engine, info->bm_o);
- } else if (info->bm_o) {
- info->bm_s = info->bm_o;
- info->bm_o = 0;
- } else if (info->bm)
- info->bm_s = copy_bitmap(render_priv->engine, info->bm);
-
- if (!info->bm_s)
+ if (val->bm && val->bm_o && !(filter->flags & FILTER_BORDER_STYLE_3)) {
+ val->bm_s = copy_bitmap(render_priv->engine, val->bm_o);
+ fix_outline(val->bm, val->bm_o);
+ } else if (val->bm_o && (filter->flags & FILTER_NONZERO_BORDER)) {
+ val->bm_s = copy_bitmap(render_priv->engine, val->bm_o);
+ } else if (val->bm_o) {
+ val->bm_s = val->bm_o;
+ val->bm_o = NULL;
+ } else if (val->bm)
+ val->bm_s = copy_bitmap(render_priv->engine, val->bm);
+
+ if (!val->bm_s)
return;
// Works right even for negative offsets
// '>>' rounds toward negative infinity, '&' returns correct remainder
- info->bm_s->left += info->filter.shadow.x >> 6;
- info->bm_s->top += info->filter.shadow.y >> 6;
- shift_bitmap(info->bm_s, info->filter.shadow.x & SUBPIXEL_MASK, info->filter.shadow.y & SUBPIXEL_MASK);
+ val->bm_s->left += filter->shadow.x >> 6;
+ val->bm_s->top += filter->shadow.y >> 6;
+ shift_bitmap(val->bm_s, filter->shadow.x & SUBPIXEL_MASK, filter->shadow.y & SUBPIXEL_MASK);
}
// Parse event text.
@@ -1775,10 +1767,10 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event)
info->blur = render_priv->state.blur;
info->shadow_x = render_priv->state.shadow_x;
info->shadow_y = render_priv->state.shadow_y;
- info->scale_x = info->orig_scale_x = render_priv->state.scale_x;
- info->scale_y = info->orig_scale_y = render_priv->state.scale_y;
+ info->scale_x = render_priv->state.scale_x;
+ info->scale_y = render_priv->state.scale_y;
info->border_style = render_priv->state.border_style;
- info->border_x= render_priv->state.border_x;
+ info->border_x = render_priv->state.border_x;
info->border_y = render_priv->state.border_y;
info->hspacing = render_priv->state.hspacing;
info->bold = render_priv->state.bold;
@@ -1792,6 +1784,10 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event)
info->fax = render_priv->state.fax;
info->fay = render_priv->state.fay;
+ info->hspacing_scaled = double_to_d6(info->hspacing *
+ render_priv->font_scale * info->scale_x);
+ info->scale_fix = 1;
+
if (!drawing_text)
fix_glyph_scaling(render_priv, info);
@@ -1831,8 +1827,7 @@ static void retrieve_glyphs(ASS_Renderer *render_priv)
}
// add horizontal letter spacing
- info->cluster_advance.x += double_to_d6(info->hspacing *
- render_priv->font_scale * info->orig_scale_x);
+ info->cluster_advance.x += info->hspacing_scaled;
// add displacement for vertical shearing
info->cluster_advance.y += (info->fay / info->scale_x * info->scale_y) * info->cluster_advance.x;
@@ -2014,13 +2009,6 @@ static void calculate_rotation_params(ASS_Renderer *render_priv, ASS_DRect *bbox
}
-static inline void rectangle_combine(ASS_Rect *rect, const Bitmap *bm, int x, int y)
-{
- x += bm->left;
- y += bm->top;
- rectangle_update(rect, x, y, x + bm->w, y + bm->h);
-}
-
// Convert glyphs to bitmaps, combine them, apply blur, generate shadows.
static void render_and_combine_glyphs(ASS_Renderer *render_priv,
double device_x, double device_y)
@@ -2051,7 +2039,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
int x = info->pos.x >> 6, y = info->pos.y >> 6;
get_bitmap_glyph(render_priv, info);
- if(linebreak || is_new_bm_run(info, last_info)) {
+ if (linebreak || is_new_bm_run(info, last_info)) {
linebreak = 0;
last_info = NULL;
if (nb_bitmaps >= text_info->max_bitmaps) {
@@ -2088,9 +2076,6 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
current_info->filter.shadow.y = double_to_d6(info->shadow_y * render_priv->border_scale);
current_info->x = current_info->y = INT_MAX;
- rectangle_reset(&current_info->rect);
- rectangle_reset(&current_info->rect_o);
- current_info->n_bm = current_info->n_bm_o = 0;
current_info->bm = current_info->bm_o = current_info->bm_s = NULL;
current_info->image = NULL;
@@ -2126,14 +2111,6 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
current_info->x = FFMIN(current_info->x, x);
current_info->y = FFMIN(current_info->y, y);
- if (info->image->bm) {
- rectangle_combine(&current_info->rect, info->image->bm, x, y);
- current_info->n_bm++;
- }
- if (info->image->bm_o) {
- rectangle_combine(&current_info->rect_o, info->image->bm_o, x, y);
- current_info->n_bm_o++;
- }
}
}
@@ -2144,107 +2121,125 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
info->bitmaps[j].y -= info->y;
}
- CompositeHashKey hk;
- CompositeHashValue *hv;
- fill_composite_hash(&hk, info);
- if (ass_cache_get(render_priv->cache.composite_cache, &hk, &hv)) {
- info->bm = hv->bm;
- info->bm_o = hv->bm_o;
- info->bm_s = hv->bm_s;
- info->image = hv;
+ CompositeHashKey key;
+ fill_composite_hash(&key, info);
+ CompositeHashValue *val = ass_cache_get(render_priv->cache.composite_cache, &key, render_priv);
+ if (!val)
continue;
+
+ info->bm = val->bm;
+ info->bm_o = val->bm_o;
+ info->bm_s = val->bm_s;
+ info->image = val;
+ continue;
+ }
+
+ text_info->n_bitmaps = nb_bitmaps;
+}
+
+static inline void rectangle_combine(ASS_Rect *rect, const Bitmap *bm, int x, int y)
+{
+ x += bm->left;
+ y += bm->top;
+ rectangle_update(rect, x, y, x + bm->w, y + bm->h);
+}
+
+size_t ass_composite_construct(void *key, void *value, void *priv)
+{
+ ASS_Renderer *render_priv = priv;
+ CompositeHashKey *k = key;
+ CompositeHashValue *v = value;
+ v->bm = v->bm_o = v->bm_s = NULL;
+
+ ASS_Rect rect, rect_o;
+ rectangle_reset(&rect);
+ rectangle_reset(&rect_o);
+
+ size_t n_bm = 0, n_bm_o = 0;
+ BitmapRef *last = NULL, *last_o = NULL;
+ for (int i = 0; i < k->bitmap_count; i++) {
+ BitmapRef *ref = &k->bitmaps[i];
+ if (ref->image->bm) {
+ rectangle_combine(&rect, ref->image->bm, ref->x, ref->y);
+ last = ref;
+ n_bm++;
}
- if (!hv)
- continue;
+ if (ref->image->bm_o) {
+ rectangle_combine(&rect_o, ref->image->bm_o, ref->x, ref->y);
+ last_o = ref;
+ n_bm_o++;
+ }
+ }
- int bord = be_padding(info->filter.be);
- if (!bord && info->n_bm == 1) {
- for (int j = 0; j < info->bitmap_count; j++) {
- if (!info->bitmaps[j].image->bm)
+ int bord = be_padding(k->filter.be);
+ if (!bord && n_bm == 1) {
+ v->bm = copy_bitmap(render_priv->engine, last->image->bm);
+ if (v->bm) {
+ v->bm->left += last->x;
+ v->bm->top += last->y;
+ }
+ } else if (n_bm) {
+ v->bm = alloc_bitmap(render_priv->engine,
+ rect.x_max - rect.x_min + 2 * bord,
+ rect.y_max - rect.y_min + 2 * bord, true);
+ Bitmap *dst = v->bm;
+ if (dst) {
+ dst->left = rect.x_min - bord;
+ dst->top = rect.y_min - bord;
+ for (int i = 0; i < k->bitmap_count; i++) {
+ Bitmap *src = k->bitmaps[i].image->bm;
+ if (!src)
continue;
- info->bm = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm);
- if (info->bm) {
- info->bm->left += info->bitmaps[j].x;
- info->bm->top += info->bitmaps[j].y;
- }
- break;
- }
- } else if (info->n_bm) {
- info->bm = alloc_bitmap(render_priv->engine,
- info->rect.x_max - info->rect.x_min + 2 * bord,
- info->rect.y_max - info->rect.y_min + 2 * bord, true);
- Bitmap *dst = info->bm;
- if (dst) {
- dst->left = info->rect.x_min - info->x - bord;
- dst->top = info->rect.y_min - info->y - bord;
- for (int j = 0; j < info->bitmap_count; j++) {
- Bitmap *src = info->bitmaps[j].image->bm;
- if (!src)
- continue;
- int x = info->bitmaps[j].x + src->left - dst->left;
- int y = info->bitmaps[j].y + src->top - dst->top;
- assert(x >= 0 && x + src->w <= dst->w);
- assert(y >= 0 && y + src->h <= dst->h);
- unsigned char *buf = dst->buffer + y * dst->stride + x;
- render_priv->engine->add_bitmaps(buf, dst->stride,
- src->buffer, src->stride,
- src->h, src->w);
- }
+ int x = k->bitmaps[i].x + src->left - dst->left;
+ int y = k->bitmaps[i].y + src->top - dst->top;
+ assert(x >= 0 && x + src->w <= dst->w);
+ assert(y >= 0 && y + src->h <= dst->h);
+ unsigned char *buf = dst->buffer + y * dst->stride + x;
+ render_priv->engine->add_bitmaps(buf, dst->stride,
+ src->buffer, src->stride,
+ src->h, src->w);
}
}
- if (!bord && info->n_bm_o == 1) {
- for (int j = 0; j < info->bitmap_count; j++) {
- if (!info->bitmaps[j].image->bm_o)
+ }
+ if (!bord && n_bm_o == 1) {
+ v->bm_o = copy_bitmap(render_priv->engine, last_o->image->bm_o);
+ if (v->bm_o) {
+ v->bm_o->left += last_o->x;
+ v->bm_o->top += last_o->y;
+ }
+ } else if (n_bm_o) {
+ v->bm_o = alloc_bitmap(render_priv->engine,
+ rect_o.x_max - rect_o.x_min + 2 * bord,
+ rect_o.y_max - rect_o.y_min + 2 * bord, true);
+ Bitmap *dst = v->bm_o;
+ if (dst) {
+ dst->left = rect_o.x_min - bord;
+ dst->top = rect_o.y_min - bord;
+ for (int i = 0; i < k->bitmap_count; i++) {
+ Bitmap *src = k->bitmaps[i].image->bm_o;
+ if (!src)
continue;
- info->bm_o = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm_o);
- if (info->bm_o) {
- info->bm_o->left += info->bitmaps[j].x;
- info->bm_o->top += info->bitmaps[j].y;
- }
- break;
- }
- } else if (info->n_bm_o) {
- info->bm_o = alloc_bitmap(render_priv->engine,
- info->rect_o.x_max - info->rect_o.x_min + 2 * bord,
- info->rect_o.y_max - info->rect_o.y_min + 2 * bord,
- true);
- Bitmap *dst = info->bm_o;
- if (dst) {
- dst->left = info->rect_o.x_min - info->x - bord;
- dst->top = info->rect_o.y_min - info->y - bord;
- for (int j = 0; j < info->bitmap_count; j++) {
- Bitmap *src = info->bitmaps[j].image->bm_o;
- if (!src)
- continue;
- int x = info->bitmaps[j].x + src->left - dst->left;
- int y = info->bitmaps[j].y + src->top - dst->top;
- assert(x >= 0 && x + src->w <= dst->w);
- assert(y >= 0 && y + src->h <= dst->h);
- unsigned char *buf = dst->buffer + y * dst->stride + x;
- render_priv->engine->add_bitmaps(buf, dst->stride,
- src->buffer, src->stride,
- src->h, src->w);
- }
+ int x = k->bitmaps[i].x + src->left - dst->left;
+ int y = k->bitmaps[i].y + src->top - dst->top;
+ assert(x >= 0 && x + src->w <= dst->w);
+ assert(y >= 0 && y + src->h <= dst->h);
+ unsigned char *buf = dst->buffer + y * dst->stride + x;
+ render_priv->engine->add_bitmaps(buf, dst->stride,
+ src->buffer, src->stride,
+ src->h, src->w);
}
}
+ }
- if (info->bm || info->bm_o) {
- ass_synth_blur(render_priv->engine, info->filter.flags & FILTER_BORDER_STYLE_3,
- info->filter.be, info->filter.blur, info->bm, info->bm_o);
- if (info->filter.flags & FILTER_DRAW_SHADOW)
- make_shadow_bitmap(info, render_priv);
- }
-
- hv->bm = info->bm;
- hv->bm_o = info->bm_o;
- hv->bm_s = info->bm_s;
- ass_cache_commit(hv, bitmap_size(hv->bm) +
- bitmap_size(hv->bm_o) + bitmap_size(hv->bm_s) +
- sizeof(CompositeHashKey) + sizeof(CompositeHashValue));
- info->image = hv;
+ if (v->bm || v->bm_o) {
+ ass_synth_blur(render_priv->engine, k->filter.flags & FILTER_BORDER_STYLE_3,
+ k->filter.be, k->filter.blur, v->bm, v->bm_o);
+ if (k->filter.flags & FILTER_DRAW_SHADOW)
+ make_shadow_bitmap(render_priv, v, &k->filter);
}
- text_info->n_bitmaps = nb_bitmaps;
+ return bitmap_size(v->bm) + bitmap_size(v->bm_o) + bitmap_size(v->bm_s) +
+ sizeof(CompositeHashKey) + sizeof(CompositeHashValue);
}
static void add_background(ASS_Renderer *render_priv, EventImages *event_images)