From 82b225b3d6653091d028b39d561d185ed76a7be5 Mon Sep 17 00:00:00 2001 From: "Dr.Smile" Date: Sun, 13 Dec 2020 17:23:26 +0300 Subject: parsing: use string references for font family and drawing text That eliminates most uses of strdup() in the rendering process. --- libass/ass_cache.c | 19 +++++++++-------- libass/ass_cache_template.h | 6 +++--- libass/ass_font.c | 2 +- libass/ass_fontselect.c | 2 +- libass/ass_parse.c | 31 +++++++++++++--------------- libass/ass_render.c | 50 +++++++++++++++++++-------------------------- libass/ass_render.h | 6 +++--- libass/ass_shaper.c | 4 ++-- libass/ass_utils.h | 33 ++++++++++++++++++++---------- 9 files changed, 77 insertions(+), 76 deletions(-) diff --git a/libass/ass_cache.c b/libass/ass_cache.c index d0dd6fb..70c0113 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -40,12 +40,13 @@ // font cache static bool font_key_move(void *dst, void *src) { - ASS_FontDesc *k = src; - if (dst) - memcpy(dst, src, sizeof(ASS_FontDesc)); - else - free(k->family); - return true; + if (!dst) + return true; + + ASS_FontDesc *d = dst, *s = dst; + memcpy(dst, src, sizeof(ASS_FontDesc)); + d->family.str = ass_copy_string(s->family); + return d->family.str; } static void font_destruct(void *key, void *value) @@ -207,8 +208,8 @@ static bool outline_key_move(void *dst, void *src) } memcpy(dst, src, sizeof(OutlineHashKey)); if (s->type == OUTLINE_DRAWING) { - d->u.drawing.text = strdup(s->u.drawing.text); - return d->u.drawing.text; + d->u.drawing.text.str = ass_copy_string(s->u.drawing.text); + return d->u.drawing.text.str; } if (s->type == OUTLINE_BORDER) ass_cache_inc_ref(s->u.border.outline); @@ -226,7 +227,7 @@ static void outline_destruct(void *key, void *value) ass_cache_dec_ref(k->u.glyph.font); break; case OUTLINE_DRAWING: - free(k->u.drawing.text); + free((char *) k->u.drawing.text.str); break; case OUTLINE_BORDER: ass_cache_dec_ref(k->u.border.outline); diff --git a/libass/ass_cache_template.h b/libass/ass_cache_template.h index 80515c2..3328d44 100644 --- a/libass/ass_cache_template.h +++ b/libass/ass_cache_template.h @@ -5,7 +5,7 @@ #define GENERIC(type, member) \ type member; #define STRING(member) \ - char *member; + ASS_StringView member; #define VECTOR(member) \ ASS_Vector member; #define END(typedefnamename) \ @@ -22,7 +22,7 @@ #define GENERIC(type, member) \ a->member == b->member && #define STRING(member) \ - strcmp(a->member, b->member) == 0 && + ass_string_equal(a->member, b->member) && #define VECTOR(member) \ a->member.x == b->member.x && a->member.y == b->member.y && #define END(typedefname) \ @@ -38,7 +38,7 @@ #define GENERIC(type, member) \ hval = fnv_32a_buf(&p->member, sizeof(p->member), hval); #define STRING(member) \ - hval = fnv_32a_str(p->member, hval); + hval = fnv_32a_buf(p->member.str, p->member.len, hval); #define VECTOR(member) GENERIC(, member.x); GENERIC(, member.y); #define END(typedefname) \ return hval; \ diff --git a/libass/ass_font.c b/libass/ass_font.c index 29ee877..7d79d2e 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -588,5 +588,5 @@ void ass_font_clear(ASS_Font *font) if (font->faces[i]) FT_Done_Face(font->faces[i]); } - free(font->desc.family); + free((char *) font->desc.family.str); } diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index d360e1c..3bf034b 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -692,7 +692,7 @@ char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, int *uid, ASS_FontStream *data, uint32_t code) { char *res = 0; - const char *family = font->desc.family; + const char *family = font->desc.family.str; // always zero-terminated unsigned bold = font->desc.bold; unsigned italic = font->desc.italic; ASS_FontProvider *default_provider = priv->default_provider; diff --git a/libass/ass_parse.c b/libass/ass_parse.c index 2e35e2b..8ba39c8 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -102,17 +102,16 @@ void update_font(ASS_Renderer *render_priv) unsigned val; ASS_FontDesc desc; - if (!render_priv->state.family) + desc.family = render_priv->state.family; + if (!desc.family.str) return; - if (render_priv->state.family[0] == '@') { + if (desc.family.len && desc.family.str[0] == '@') { desc.vertical = 1; - desc.family = strdup(render_priv->state.family + 1); + desc.family.str++; + desc.family.len--; } else { desc.vertical = 0; - desc.family = strdup(render_priv->state.family); } - if (!desc.family) - return; val = render_priv->state.bold; // 0 = normal, 1 = bold, >1 = exact weight @@ -234,7 +233,8 @@ static bool parse_vector_clip(ASS_Renderer *render_priv, scale = argtoi(args[0]); struct arg text = args[nargs - 1]; - render_priv->state.clip_drawing_text = strndup(text.start, text.end - text.start); + render_priv->state.clip_drawing_text.str = text.start; + render_priv->state.clip_drawing_text.len = text.end - text.start; render_priv->state.clip_drawing_scale = scale; return true; } @@ -381,7 +381,7 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr, render_priv->state.clip_y1 = render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; render_priv->state.clip_mode = 1; - } else if (!render_priv->state.clip_drawing_text) { + } else if (!render_priv->state.clip_drawing_text.str) { if (parse_vector_clip(render_priv, args, nargs)) render_priv->state.clip_drawing_mode = 1; } @@ -517,19 +517,16 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr, render_priv->state.frz = render_priv->state.style->Angle; } else if (tag("fn")) { - char *family; char *start = args->start; if (nargs && strncmp(start, "0", args->end - start)) { skip_spaces(&start); - family = strndup(start, args->end - start); + render_priv->state.family.str = start; + render_priv->state.family.len = args->end - start; } else { - family = strdup(render_priv->state.style->FontName); - } - if (family) { - free(render_priv->state.family); - render_priv->state.family = family; - update_font(render_priv); + render_priv->state.family.str = render_priv->state.style->FontName; + render_priv->state.family.len = strlen(render_priv->state.style->FontName); } + update_font(render_priv); } else if (tag("alpha")) { int i; if (nargs) { @@ -708,7 +705,7 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr, render_priv->state.clip_y1 = render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr; render_priv->state.clip_mode = 0; - } else if (!render_priv->state.clip_drawing_text) { + } else if (!render_priv->state.clip_drawing_text.str) { if (parse_vector_clip(render_priv, args, nargs)) render_priv->state.clip_drawing_mode = 0; } diff --git a/libass/ass_render.c b/libass/ass_render.c index 56ed2f3..1962702 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -644,7 +644,7 @@ static inline size_t bitmap_size(const Bitmap *bm) */ static void blend_vector_clip(ASS_Renderer *render_priv, ASS_Image *head) { - if (!render_priv->state.clip_drawing_text) + if (!render_priv->state.clip_drawing_text.str) return; OutlineHashKey ol_key; @@ -998,13 +998,9 @@ void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style) (style->StrikeOut ? DECO_STRIKETHROUGH : 0); render_priv->state.font_size = style->FontSize; - char* new_family = strdup(style->FontName); - if (new_family) { - free(render_priv->state.family); - render_priv->state.family = new_family; - render_priv->state.treat_family_as_pattern = - style->treat_fontname_as_pattern; - } + render_priv->state.family.str = style->FontName; + render_priv->state.family.len = strlen(style->FontName); + render_priv->state.treat_family_as_pattern = style->treat_fontname_as_pattern; render_priv->state.bold = style->Bold; render_priv->state.italic = style->Italic; update_font(render_priv); @@ -1067,17 +1063,14 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event) static void free_render_context(ASS_Renderer *render_priv) { ass_cache_dec_ref(render_priv->state.font); - free(render_priv->state.family); - free(render_priv->state.clip_drawing_text); render_priv->state.font = NULL; - render_priv->state.family = NULL; - render_priv->state.clip_drawing_text = NULL; + render_priv->state.family.str = NULL; + render_priv->state.family.len = 0; + render_priv->state.clip_drawing_text.str = NULL; + render_priv->state.clip_drawing_text.len = 0; - TextInfo *text_info = &render_priv->text_info; - for (int n = 0; n < text_info->length; n++) - free(text_info->glyphs[n].drawing_text); - text_info->length = 0; + render_priv->text_info.length = 0; } /** @@ -1095,7 +1088,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) int32_t asc, desc; OutlineHashKey key; - if (info->drawing_text) { + if (info->drawing_text.str) { key.type = OUTLINE_DRAWING; key.u.drawing.text = info->drawing_text; val = ass_cache_get(priv->cache.outline_cache, &key, priv); @@ -1143,7 +1136,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) info->bbox.x_max = lrint(val->cbox.x_max * scale.x + offset.x); info->bbox.y_max = lrint(val->cbox.y_max * scale.y + offset.y); - if (info->drawing_text || priv->settings.shaper == ASS_SHAPING_SIMPLE) { + if (info->drawing_text.str || priv->settings.shaper == ASS_SHAPING_SIMPLE) { info->cluster_advance.x = info->advance.x = lrint(val->advance * scale.x); info->cluster_advance.y = info->advance.y = 0; } @@ -1180,7 +1173,7 @@ size_t ass_outline_construct(void *key, void *value, void *priv) case OUTLINE_DRAWING: { ASS_Rect bbox; - const char *text = outline_key->u.drawing.text; + const char *text = outline_key->u.drawing.text.str; // always zero-terminated if (!ass_drawing_parse(&v->outline[0], &bbox, text, render_priv->library)) return 1; @@ -1874,9 +1867,9 @@ static void split_style_runs(ASS_Renderer *render_priv) info->starts_new_run = info->effect_timing || // but ignore effect_skip_timing (effect_type != EF_NONE && effect_type != last_effect_type) || - info->drawing_text || - last->drawing_text || - strcmp(last->font->desc.family, info->font->desc.family) || + info->drawing_text.str || + last->drawing_text.str || + !ass_string_equal(last->font->desc.family, info->font->desc.family) || last->font->desc.vertical != info->font->desc.vertical || last->font_size != info->font_size || last->c[0] != info->c[0] || @@ -1913,11 +1906,10 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) TextInfo *text_info = &render_priv->text_info; char *p = event->Text, *q; - char *drawing_text; // Event parsing. while (true) { - drawing_text = NULL; + ASS_StringView drawing_text = {NULL, 0}; // get next char, executing style override // this affects render_context @@ -1933,7 +1925,8 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) q++; while ((*q != '{') && (*q != 0)) q++; - drawing_text = strndup(p, q - p); + drawing_text.str = p; + drawing_text.len = q - p; code = 0xfffc; // object replacement character p = q; break; @@ -1966,7 +1959,7 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) memset(info, 0, sizeof(GlyphInfo)); // Parse drawing - if (drawing_text) { + if (drawing_text.str) { info->drawing_text = drawing_text; info->drawing_scale = render_priv->state.drawing_scale; info->drawing_pbo = render_priv->state.pbo; @@ -1975,7 +1968,7 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) // Fill glyph information info->symbol = code; info->font = render_priv->state.font; - if (!drawing_text) + if (!drawing_text.str) ass_cache_inc_ref(info->font); for (int i = 0; i < 4; i++) { uint32_t clr = render_priv->state.c[i]; @@ -2018,7 +2011,7 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) render_priv->font_scale * info->scale_x); info->scale_fix = 1; - if (!drawing_text) + if (!drawing_text.str) fix_glyph_scaling(render_priv, info); text_info->length++; @@ -2032,7 +2025,6 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event) fail: free_render_context(render_priv); - free(drawing_text); return false; } diff --git a/libass/ass_render.h b/libass/ass_render.h index 43a7185..18d87ba 100644 --- a/libass/ass_render.h +++ b/libass/ass_render.h @@ -131,7 +131,7 @@ typedef struct glyph_info { int glyph_index; hb_script_t script; double font_size; - char *drawing_text; + ASS_StringView drawing_text; int drawing_scale; int drawing_pbo; OutlineHashValue *outline; @@ -239,7 +239,7 @@ typedef struct { double shadow_x; double shadow_y; double pbo; // drawing baseline offset - char *clip_drawing_text; + ASS_StringView clip_drawing_text; // used to store RenderContext.style when doing selective style overrides ASS_Style override_style_temp_storage; @@ -262,7 +262,7 @@ typedef struct { int scroll_y0, scroll_y1; // face properties - char *family; + ASS_StringView family; unsigned bold; unsigned italic; int treat_family_as_pattern; diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index 41392c6..4665e7a 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -665,7 +665,7 @@ static bool shape_harfbuzz(ASS_Shaper *shaper, GlyphInfo *glyphs, size_t len) glyphs[i].skip = true; for (i = 0; i < len; i++) { - if (glyphs[i].drawing_text) { + if (glyphs[i].drawing_text.str) { glyphs[i].skip = false; continue; } @@ -805,7 +805,7 @@ void ass_shaper_find_runs(ASS_Shaper *shaper, ASS_Renderer *render_priv, // find appropriate fonts for the shape runs for (i = 0; i < len; i++) { GlyphInfo *info = glyphs + i; - if (!info->drawing_text) { + if (!info->drawing_text.str) { // set size and get glyph index ass_font_get_index(render_priv->fontselect, info->font, info->symbol, &info->face_index, &info->glyph_index); diff --git a/libass/ass_utils.h b/libass/ass_utils.h index 1108c90..3f65b87 100644 --- a/libass/ass_utils.h +++ b/libass/ass_utils.h @@ -52,6 +52,26 @@ int has_avx(void); int has_avx2(void); #endif +typedef struct { + const char *str; + size_t len; +} ASS_StringView; + +static inline char *ass_copy_string(ASS_StringView src) +{ + char *buf = malloc(src.len + 1); + if (buf) { + memcpy(buf, src.str, src.len); + buf[src.len] = '\0'; + } + return buf; +} + +static inline bool ass_string_equal(ASS_StringView str1, ASS_StringView str2) +{ + return str1.len == str2.len && !memcmp(str1.str, str2.str, str1.len); +} + #ifndef HAVE_STRNDUP char *ass_strndup(const char *s, size_t n); #define strndup ass_strndup @@ -163,9 +183,9 @@ static inline int double_to_d22(double x) #define FNV1_32A_INIT 0x811c9dc5U #define FNV1_32A_PRIME 16777619U -static inline uint32_t fnv_32a_buf(void *buf, size_t len, uint32_t hval) +static inline uint32_t fnv_32a_buf(const void *buf, size_t len, uint32_t hval) { - unsigned char *bp = (unsigned char *) buf; + const uint8_t *bp = buf; size_t n = (len + 3) / 4; switch (len % 4) { @@ -178,15 +198,6 @@ static inline uint32_t fnv_32a_buf(void *buf, size_t len, uint32_t hval) return hval; } -static inline uint32_t fnv_32a_str(const char *str, uint32_t hval) -{ - unsigned char *s = (unsigned char *) str; - while (*s) { - hval ^= *s++; - hval *= FNV1_32A_PRIME; - } - return hval; -} static inline int mystrtoi(char **p, int *res) { -- cgit v1.2.3