summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libass/ass_cache.c65
-rw-r--r--libass/ass_cache.h6
-rw-r--r--libass/ass_cache_template.h49
-rw-r--r--libass/ass_font.c41
-rw-r--r--libass/ass_font.h4
-rw-r--r--libass/ass_parse.c5
-rw-r--r--libass/ass_render.c631
-rw-r--r--libass/ass_render.h8
-rw-r--r--libass/ass_shaper.c73
9 files changed, 448 insertions, 434 deletions
diff --git a/libass/ass_cache.c b/libass/ass_cache.c
index 2e8d7d7..f33babc 100644
--- a/libass/ass_cache.c
+++ b/libass/ass_cache.c
@@ -79,10 +79,13 @@ static void font_destruct(void *key, void *value)
ass_font_clear(value);
}
+size_t ass_font_construct(void *key, void *value, void *priv);
+
const CacheDesc font_cache_desc = {
.hash_func = font_hash,
.compare_func = font_compare,
.key_move_func = font_key_move,
+ .construct_func = ass_font_construct,
.destruct_func = font_destruct,
.key_size = sizeof(ASS_FontDesc),
.value_size = sizeof(ASS_Font)
@@ -141,10 +144,13 @@ static void bitmap_destruct(void *key, void *value)
}
}
+size_t ass_bitmap_construct(void *key, void *value, void *priv);
+
const CacheDesc bitmap_cache_desc = {
.hash_func = bitmap_hash,
.compare_func = bitmap_compare,
.key_move_func = bitmap_key_move,
+ .construct_func = ass_bitmap_construct,
.destruct_func = bitmap_destruct,
.key_size = sizeof(BitmapHashKey),
.value_size = sizeof(BitmapHashValue)
@@ -207,10 +213,13 @@ static void composite_destruct(void *key, void *value)
free(k->bitmaps);
}
+size_t ass_composite_construct(void *key, void *value, void *priv);
+
const CacheDesc composite_cache_desc = {
.hash_func = composite_hash,
.compare_func = composite_compare,
.key_move_func = composite_key_move,
+ .construct_func = ass_composite_construct,
.destruct_func = composite_destruct,
.key_size = sizeof(CompositeHashKey),
.value_size = sizeof(CompositeHashValue)
@@ -224,7 +233,7 @@ static unsigned outline_hash(void *key, size_t key_size)
switch (k->type) {
case OUTLINE_GLYPH: return glyph_hash(&k->u, key_size);
case OUTLINE_DRAWING: return drawing_hash(&k->u, key_size);
- default: return 0;
+ default: return outline_common_hash(&k->u, key_size);
}
}
@@ -236,7 +245,7 @@ static unsigned outline_compare(void *a, void *b, size_t key_size)
switch (ak->type) {
case OUTLINE_GLYPH: return glyph_compare(&ak->u, &bk->u, key_size);
case OUTLINE_DRAWING: return drawing_compare(&ak->u, &bk->u, key_size);
- default: return 0;
+ default: return outline_common_compare(&ak->u, &bk->u, key_size);
}
}
@@ -268,10 +277,13 @@ static void outline_destruct(void *key, void *value)
}
}
+size_t ass_outline_construct(void *key, void *value, void *priv);
+
const CacheDesc outline_cache_desc = {
.hash_func = outline_hash,
.compare_func = outline_compare,
.key_move_func = outline_key_move,
+ .construct_func = ass_outline_construct,
.destruct_func = outline_destruct,
.key_size = sizeof(OutlineHashKey),
.value_size = sizeof(OutlineHashValue)
@@ -295,10 +307,13 @@ static void glyph_metrics_destruct(void *key, void *value)
ass_cache_dec_ref(k->font);
}
+size_t ass_glyph_metrics_construct(void *key, void *value, void *priv);
+
const CacheDesc glyph_metrics_cache_desc = {
.hash_func = glyph_metrics_hash,
.compare_func = glyph_metrics_compare,
.key_move_func = glyph_metrics_key_move,
+ .construct_func = ass_glyph_metrics_construct,
.destruct_func = glyph_metrics_destruct,
.key_size = sizeof(GlyphMetricsHashKey),
.value_size = sizeof(GlyphMetricsHashValue)
@@ -360,9 +375,8 @@ Cache *ass_cache_create(const CacheDesc *desc)
return cache;
}
-bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
+void *ass_cache_get(Cache *cache, void *key, void *priv)
{
- char **value = (char **) value_ptr;
const CacheDesc *desc = cache->desc;
size_t key_offs = CACHE_ITEM_SIZE + align_cache(desc->value_size);
unsigned bucket = desc->hash_func(key, desc->key_size) % cache->buckets;
@@ -383,9 +397,8 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
}
cache->hits++;
desc->key_move_func(NULL, key, desc->key_size);
- *value = (char *) item + CACHE_ITEM_SIZE;
item->ref_count++;
- return true;
+ return (char *) item + CACHE_ITEM_SIZE;
}
item = item->next;
}
@@ -394,18 +407,18 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
item = malloc(key_offs + desc->key_size);
if (!item) {
desc->key_move_func(NULL, key, desc->key_size);
- *value = NULL;
- return false;
+ return NULL;
}
- item->size = 0;
item->cache = cache;
item->desc = desc;
- if (!desc->key_move_func((char *) item + key_offs, key, desc->key_size)) {
+ void *new_key = (char *) item + key_offs;
+ if (!desc->key_move_func(new_key, key, desc->key_size)) {
free(item);
- *value = NULL;
- return false;
+ return NULL;
}
- *value = (char *) item + CACHE_ITEM_SIZE;
+ void *value = (char *) item + CACHE_ITEM_SIZE;
+ item->size = desc->construct_func(new_key, value, priv);
+ assert(item->size);
CacheItem **bucketptr = &cache->map[bucket];
if (*bucketptr)
@@ -414,10 +427,15 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
item->next = *bucketptr;
*bucketptr = item;
- item->queue_prev = NULL;
+ *cache->queue_last = item;
+ item->queue_prev = cache->queue_last;
+ cache->queue_last = &item->queue_next;
item->queue_next = NULL;
- item->ref_count = 1;
- return false;
+ item->ref_count = 2;
+
+ cache->cache_size += item->size;
+ cache->items++;
+ return value;
}
void *ass_cache_key(void *value)
@@ -426,21 +444,6 @@ void *ass_cache_key(void *value)
return (char *) value + align_cache(item->desc->value_size);
}
-void ass_cache_commit(void *value, size_t item_size)
-{
- CacheItem *item = value_to_item(value);
- assert(!item->size && item_size);
- item->size = item_size;
- Cache *cache = item->cache;
- cache->cache_size += item_size;
- cache->items++;
-
- *cache->queue_last = item;
- item->queue_prev = cache->queue_last;
- cache->queue_last = &item->queue_next;
- item->ref_count++;
-}
-
static inline void destroy_item(const CacheDesc *desc, CacheItem *item)
{
assert(item->desc == desc);
diff --git a/libass/ass_cache.h b/libass/ass_cache.h
index 6c07370..acfa4bb 100644
--- a/libass/ass_cache.h
+++ b/libass/ass_cache.h
@@ -62,6 +62,7 @@ typedef struct {
typedef unsigned(*HashFunction)(void *key, size_t key_size);
typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size);
typedef bool(*CacheKeyMove)(void *dst, void *src, size_t key_size);
+typedef size_t(*CacheValueConstructor)(void *key, void *value, void *priv);
typedef void(*CacheItemDestructor)(void *key, void *value);
// cache hash keys
@@ -74,6 +75,7 @@ typedef struct outline_hash_key {
union {
GlyphHashKey glyph;
DrawingHashKey drawing;
+ OutlineCommonKey common;
} u;
} OutlineHashKey;
@@ -111,15 +113,15 @@ typedef struct
HashFunction hash_func;
HashCompare compare_func;
CacheKeyMove key_move_func;
+ CacheValueConstructor construct_func;
CacheItemDestructor destruct_func;
size_t key_size;
size_t value_size;
} CacheDesc;
Cache *ass_cache_create(const CacheDesc *desc);
-bool ass_cache_get(Cache *cache, void *key, void *value_ptr);
+void *ass_cache_get(Cache *cache, void *key, void *priv);
void *ass_cache_key(void *value);
-void ass_cache_commit(void *value, size_t item_size);
void ass_cache_inc_ref(void *value);
void ass_cache_dec_ref(void *value);
void ass_cache_cut(Cache *cache, size_t max_size);
diff --git a/libass/ass_cache_template.h b/libass/ass_cache_template.h
index 2cb2df4..b4a6864 100644
--- a/libass/ass_cache_template.h
+++ b/libass/ass_cache_template.h
@@ -77,42 +77,55 @@ END(OutlineBitmapHashKey)
// describe a clip mask bitmap
START(clip_bitmap, clip_bitmap_hash_key)
+ GENERIC(int, scale)
STRING(text)
END(ClipMaskHashKey)
-// describes an outline glyph
-START(glyph, glyph_hash_key)
+START(glyph_metrics, glyph_metrics_hash_key)
GENERIC(ASS_Font *, font)
- GENERIC(double, size) // font size
+ GENERIC(double, size)
GENERIC(int, face_index)
GENERIC(int, glyph_index)
- GENERIC(int, bold)
- GENERIC(int, italic)
+END(GlyphMetricsHashKey)
+
+// common outline data
+START(outline_common, outline_common_hash_key)
GENERIC(unsigned, scale_x) // 16.16
GENERIC(unsigned, scale_y) // 16.16
VECTOR(outline) // border width, 26.6
- GENERIC(unsigned, flags) // glyph decoration flags
GENERIC(unsigned, border_style)
- GENERIC(int, hspacing) // 16.16
-END(GlyphHashKey)
+ GENERIC(int, scale_fix) // 16.16
+ GENERIC(int, advance) // 26.6
+END(OutlineCommonKey)
+
+// describes an outline glyph
+START(glyph, glyph_hash_key)
+ GENERIC(unsigned, scale_x) // 16.16
+ GENERIC(unsigned, scale_y) // 16.16
+ VECTOR(outline) // border width, 26.6
+ GENERIC(unsigned, border_style)
+ GENERIC(int, scale_fix) // 16.16
+ GENERIC(int, advance) // 26.6
-START(glyph_metrics, glyph_metrics_hash_key)
GENERIC(ASS_Font *, font)
- GENERIC(double, size)
+ GENERIC(double, size) // font size
GENERIC(int, face_index)
GENERIC(int, glyph_index)
- GENERIC(unsigned, scale_x)
- GENERIC(unsigned, scale_y)
-END(GlyphMetricsHashKey)
+ GENERIC(int, bold)
+ GENERIC(int, italic)
+ GENERIC(unsigned, flags) // glyph decoration flags
+END(GlyphHashKey)
// describes an outline drawing
START(drawing, drawing_hash_key)
- GENERIC(unsigned, scale_x)
- GENERIC(unsigned, scale_y)
- GENERIC(int, pbo)
- VECTOR(outline)
+ GENERIC(unsigned, scale_x) // 16.16
+ GENERIC(unsigned, scale_y) // 16.16
+ VECTOR(outline) // border width, 26.6
GENERIC(unsigned, border_style)
- GENERIC(int, hspacing)
+ GENERIC(int, scale_fix) // 16.16
+ GENERIC(int, advance) // 26.6
+
+ GENERIC(int, pbo)
GENERIC(int, scale)
STRING(text)
END(DrawingHashKey)
diff --git a/libass/ass_font.c b/libass/ass_font.c
index 6b369aa..2c488cc 100644
--- a/libass/ass_font.c
+++ b/libass/ass_font.c
@@ -224,26 +224,28 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch)
/**
* \brief Create a new ASS_Font according to "desc" argument
*/
-ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
- FT_Library ftlibrary, ASS_FontSelector *fontsel,
- ASS_FontDesc *desc)
+ASS_Font *ass_font_new(ASS_Renderer *render_priv, ASS_FontDesc *desc)
{
- ASS_Font *font;
- if (ass_cache_get(font_cache, desc, &font)) {
- if (font->desc.family)
- return font;
- ass_cache_dec_ref(font);
- return NULL;
- }
+ ASS_Font *font = ass_cache_get(render_priv->cache.font_cache, desc, render_priv);
if (!font)
return NULL;
+ if (font->desc.family)
+ return font;
+ ass_cache_dec_ref(font);
+ return NULL;
+}
+
+size_t ass_font_construct(void *key, void *value, void *priv)
+{
+ ASS_Renderer *render_priv = priv;
+ ASS_FontDesc *desc = key;
+ ASS_Font *font = value;
- font->library = library;
- font->ftlibrary = ftlibrary;
+ font->library = render_priv->library;
+ font->ftlibrary = render_priv->ftlibrary;
font->shaper_priv = NULL;
font->n_faces = 0;
- ASS_FontDesc *new_desc = ass_cache_key(font);
- font->desc.family = new_desc->family;
+ font->desc.family = desc->family;
font->desc.bold = desc->bold;
font->desc.italic = desc->italic;
font->desc.vertical = desc->vertical;
@@ -251,15 +253,10 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
font->scale_x = font->scale_y = 1.;
font->size = 0.;
- int error = add_face(fontsel, font, 0);
- if (error == -1) {
+ int error = add_face(render_priv->fontselect, font, 0);
+ if (error == -1)
font->desc.family = NULL;
- ass_cache_commit(font, 1);
- ass_cache_dec_ref(font);
- return NULL;
- }
- ass_cache_commit(font, 1);
- return font;
+ return 1;
}
/**
diff --git a/libass/ass_font.h b/libass/ass_font.h
index dd0c11a..6aa76ef 100644
--- a/libass/ass_font.h
+++ b/libass/ass_font.h
@@ -59,9 +59,7 @@ struct ass_font {
};
void charmap_magic(ASS_Library *library, FT_Face face);
-ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
- FT_Library ftlibrary, ASS_FontSelector *fontsel,
- ASS_FontDesc *desc);
+ASS_Font *ass_font_new(ASS_Renderer *render_priv, ASS_FontDesc *desc);
void ass_font_set_transform(ASS_Font *font, double scale_x, double scale_y);
void ass_face_set_size(FT_Face face, double size);
void ass_font_set_size(ASS_Font *font, double size);
diff --git a/libass/ass_parse.c b/libass/ass_parse.c
index 9397971..a3a1bdb 100644
--- a/libass/ass_parse.c
+++ b/libass/ass_parse.c
@@ -128,10 +128,7 @@ void update_font(ASS_Renderer *render_priv)
desc.italic = val;
ass_cache_dec_ref(render_priv->state.font);
- render_priv->state.font =
- ass_font_new(render_priv->cache.font_cache, render_priv->library,
- render_priv->ftlibrary, render_priv->fontselect,
- &desc);
+ render_priv->state.font = ass_font_new(render_priv, &desc);
if (render_priv->state.font)
change_font_size(render_priv, render_priv->state.font_size);
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