summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr.Smile <vabnick@gmail.com>2019-05-19 20:24:29 +0300
committerDr.Smile <vabnick@gmail.com>2019-05-19 20:24:29 +0300
commite072b72b1a12837b6894d052a08ed3aed57f2f16 (patch)
tree492ddc7dbf70b70f298bcb3298b53ebad03841b6
parent5d03af99c6d8f43be973cb6dacb5d6dd0ada33b1 (diff)
downloadlibass-e072b72b1a12837b6894d052a08ed3aed57f2f16.tar.bz2
libass-e072b72b1a12837b6894d052a08ed3aed57f2f16.tar.xz
cache: construct cache values only from corresponding keys
This commit forces construction of cache values using only data available in its companion keys. That ensures logical correctness: keys are guaranteed to have all the necessary data, and prevents accidental collisions. Most fixes of cache logic correspond to minor problem when rendering is done with double parameter but cache key stores its approximate fixed-point representation. The only serious problem is missing scale of clip drawing. Also this commit removes unused scale parameters from glyph metrics cache key. Due to missing scale clip shapes that differed only in scale treated by cache system as identical. That can lead to incorrect reuse of cached bitmap of different scale instead of correct one. The only hack left is in glyph metrics cache with its unicode >= VERTICAL_LOWER_BOUND check.
-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;
+