From e341e05fa2e034afa3f702d3d2bd1f21fa92f6a4 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Sun, 10 Jan 2010 21:09:48 +0000 Subject: [PATCH] Update libass to commit 8db4a5. Originally committed to SVN as r3970. --- aegisub/libass/Makefile.am | 1 + aegisub/libass/ass.c | 15 +- aegisub/libass/ass.h | 7 +- aegisub/libass/ass_bitmap.c | 32 ++--- aegisub/libass/ass_drawing.c | 33 +++-- aegisub/libass/ass_font.c | 12 +- aegisub/libass/ass_fontconfig.c | 130 +---------------- aegisub/libass/ass_parse.c | 109 +++++++++++--- aegisub/libass/ass_parse.h | 1 + aegisub/libass/ass_render.c | 101 ++----------- aegisub/libass/ass_strtod.c | 247 ++++++++++++++++++++++++++++++++ aegisub/libass/ass_types.h | 1 + aegisub/libass/ass_utils.c | 6 +- aegisub/libass/ass_utils.h | 18 +++ 14 files changed, 433 insertions(+), 280 deletions(-) create mode 100644 aegisub/libass/ass_strtod.c diff --git a/aegisub/libass/Makefile.am b/aegisub/libass/Makefile.am index 7aa5752dc..8a990787e 100644 --- a/aegisub/libass/Makefile.am +++ b/aegisub/libass/Makefile.am @@ -16,6 +16,7 @@ libass_aegisub_a_SOURCES = \ ass_library.c \ ass_parse.c \ ass_render.c \ + ass_strtod.c \ ass_utils.c libass_aegisub_a_SOURCES += \ diff --git a/aegisub/libass/ass.c b/aegisub/libass/ass.c index 057a6e349..6becb39e8 100644 --- a/aegisub/libass/ass.c +++ b/aegisub/libass/ass.c @@ -389,6 +389,8 @@ void ass_process_force_style(ASS_Track *track) track->WrapStyle = atoi(token); else if (!strcasecmp(*fs, "ScaledBorderAndShadow")) track->ScaledBorderAndShadow = parse_bool(token); + else if (!strcasecmp(*fs, "Kerning")) + track->Kerning = parse_bool(token); dt = strrchr(*fs, '.'); if (dt) { @@ -571,6 +573,8 @@ static int process_info_line(ASS_Track *track, char *str) track->WrapStyle = atoi(str + 10); } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { track->ScaledBorderAndShadow = parse_bool(str + 22); + } else if (!strncmp(str, "Kerning:", 8)) { + track->Kerning = parse_bool(str + 8); } return 0; } @@ -1096,12 +1100,13 @@ ASS_Track *ass_read_memory(ASS_Library *library, char *buf, return 0; #ifdef CONFIG_ICONV - if (codepage) + if (codepage) { buf = sub_recode(library, buf, bufsize, codepage); - if (!buf) - return 0; - else - need_free = 1; + if (!buf) + return 0; + else + need_free = 1; + } #endif track = parse_memory(library, buf); if (need_free) diff --git a/aegisub/libass/ass.h b/aegisub/libass/ass.h index 908b199f2..e7674a736 100644 --- a/aegisub/libass/ass.h +++ b/aegisub/libass/ass.h @@ -25,7 +25,7 @@ #include #include "ass_types.h" -#define LIBASS_VERSION 0x00907010 +#define LIBASS_VERSION 0x00908000 /* * A linked list of images produced by an ass renderer. @@ -49,7 +49,7 @@ typedef struct ass_image { } ASS_Image; /* - * Hintint type. (see ass_set_hinting below) + * Hinting type. (see ass_set_hinting below) * * FreeType's native hinter is still buggy sometimes and it is recommended * to use the light autohinter, ASS_HINTING_LIGHT, instead. For best @@ -195,6 +195,9 @@ void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing); /** * \brief Set font lookup defaults. + * \param default_font path to default font to use. Must be supplied if + * fontconfig is disabled or unavailable. + * \param default_family fallback font family for fontconfig, or NULL * \param fc whether to use fontconfig * \param config path to fontconfig configuration file, or NULL. Only relevant * if fontconfig is used. diff --git a/aegisub/libass/ass_bitmap.c b/aegisub/libass/ass_bitmap.c index 1ae2d7c3e..c7c039ddd 100644 --- a/aegisub/libass/ass_bitmap.c +++ b/aegisub/libass/ass_bitmap.c @@ -230,12 +230,12 @@ static Bitmap *glyph_to_bitmap_internal(ASS_Library *library, } /** - * \brief fix outline bitmap and generate shadow bitmap - * Two things are done here: - * 1. Glyph bitmap is subtracted from outline bitmap. This way looks much better in some cases. - * 2. Shadow bitmap is created as a sum of glyph and outline bitmaps. + * \brief fix outline bitmap + * + * The glyph bitmap is subtracted from outline bitmap. This way looks much + * better in some cases. */ -static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o) +static void fix_outline(Bitmap *bm_g, Bitmap *bm_o) { int x, y; const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left; @@ -247,14 +247,10 @@ static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o) bm_o->top + bm_o->h < bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h; - Bitmap *bm_s = copy_bitmap(bm_o); - unsigned char *g = bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left); unsigned char *o = bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left); - unsigned char *s = - bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left); for (y = 0; y < b - t; ++y) { for (x = 0; x < r - l; ++x) { @@ -262,15 +258,10 @@ static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o) c_g = g[x]; c_o = o[x]; o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0; - s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF; } g += bm_g->w; o += bm_o->w; - s += bm_s->w; } - - assert(bm_s); - return bm_s; } /** @@ -528,16 +519,19 @@ int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur, priv_blur->g_w); } - if (*bm_o && border_style == 3) + // Create shadow and fix outline as needed + if (*bm_o && border_style != 3) { *bm_s = copy_bitmap(*bm_o); - else if (*bm_o) - *bm_s = fix_outline_and_shadow(*bm_g, *bm_o); - else + fix_outline(*bm_g, *bm_o); + } else if (*bm_o) { + *bm_s = copy_bitmap(*bm_o); + } else *bm_s = copy_bitmap(*bm_g); + assert(bm_s); + shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h, shadow_offset.x, shadow_offset.y); - assert(bm_s); return 0; } diff --git a/aegisub/libass/ass_drawing.c b/aegisub/libass/ass_drawing.c index 8c5f062bc..a3207c7c3 100644 --- a/aegisub/libass/ass_drawing.c +++ b/aegisub/libass/ass_drawing.c @@ -41,14 +41,15 @@ static void drawing_make_glyph(ASS_Drawing *drawing, void *fontconfig_priv, // This is hacky... glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font, (uint32_t) ' ', hint, 0); + if (glyph) { + FT_Outline_Done(drawing->ftlibrary, &glyph->outline); + FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS, + GLYPH_INITIAL_CONTOURS, &glyph->outline); - FT_Outline_Done(drawing->ftlibrary, &glyph->outline); - FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS, - GLYPH_INITIAL_CONTOURS, &glyph->outline); - - glyph->outline.n_contours = 0; - glyph->outline.n_points = 0; - glyph->root.advance.x = glyph->root.advance.y = 0; + glyph->outline.n_contours = 0; + glyph->outline.n_points = 0; + glyph->root.advance.x = glyph->root.advance.y = 0; + } drawing->glyph = glyph; } @@ -363,15 +364,17 @@ static void drawing_evaluate_curve(ASS_Drawing *drawing, ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font, ASS_Hinting hint, FT_Library lib) { - ASS_Drawing* drawing; + ASS_Drawing *drawing; drawing = calloc(1, sizeof(*drawing)); drawing->text = calloc(1, DRAWING_INITIAL_SIZE); drawing->size = DRAWING_INITIAL_SIZE; drawing->ftlibrary = lib; - drawing->library = font->library; - drawing_make_glyph(drawing, fontconfig_priv, font, hint); + if (font) { + drawing->library = font->library; + drawing_make_glyph(drawing, fontconfig_priv, font, hint); + } drawing->scale_x = 1.; drawing->scale_y = 1.; @@ -386,8 +389,11 @@ ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font, */ void ass_drawing_free(ASS_Drawing* drawing) { - FT_Done_Glyph((FT_Glyph) drawing->glyph); - free(drawing->text); + if (drawing) { + if (drawing->glyph) + FT_Done_Glyph((FT_Glyph) drawing->glyph); + free(drawing->text); + } free(drawing); } @@ -423,6 +429,9 @@ FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode) ASS_DrawingToken *token; FT_Vector pen = {0, 0}; + if (!drawing->glyph) + return NULL; + drawing->tokens = drawing_tokenize(drawing->text); drawing_prepare(drawing); diff --git a/aegisub/libass/ass_font.c b/aegisub/libass/ass_font.c index 2e8548c5b..7db1f076f 100644 --- a/aegisub/libass/ass_font.c +++ b/aegisub/libass/ass_font.c @@ -218,7 +218,6 @@ void ass_font_set_transform(ASS_Font *font, double scale_x, static void face_set_size(FT_Face face, double size) { -#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1)) TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); double mscale = 1.; @@ -241,9 +240,6 @@ static void face_set_size(FT_Face face, double size) m->ascender /= mscale; m->descender /= mscale; m->height /= mscale; -#else - FT_Set_Char_Size(face, 0, double_to_d6(size), 0, 0); -#endif } /** @@ -421,6 +417,9 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, if (ch < 0x20) return 0; + // Handle NBSP like a regular space when rendering the glyph + if (ch == 0xa0) + ch = ' '; if (font->n_faces == 0) return 0; @@ -473,10 +472,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, index); return 0; } -#if (FREETYPE_MAJOR > 2) || \ - ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \ - ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10)) -// FreeType >= 2.1.10 required if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) && (font->desc.italic > 55)) { FT_GlyphSlot_Oblique(face->glyph); @@ -486,7 +481,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, (font->desc.bold > 80)) { ass_glyph_embolden(face->glyph); } -#endif error = FT_Get_Glyph(face->glyph, &glyph); if (error) { ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", diff --git a/aegisub/libass/ass_fontconfig.c b/aegisub/libass/ass_fontconfig.c index 006be9767..2a43694f3 100644 --- a/aegisub/libass/ass_fontconfig.c +++ b/aegisub/libass/ass_fontconfig.c @@ -51,15 +51,6 @@ struct fc_instance { #ifdef CONFIG_FONTCONFIG -// 4yo fontconfig does not have these. -// They are only needed for debug output, anyway. -#ifndef FC_FULLNAME -#define FC_FULLNAME "fullname" -#endif -#ifndef FC_EMBOLDEN -#define FC_EMBOLDEN "embolden" -#endif - /** * \brief Low-level font selection. * \param priv private data @@ -159,7 +150,6 @@ static char *_select_font(ASS_Library *library, FCInstance *priv, if (curf >= fset->nfont) goto error; -#if (FC_VERSION >= 20297) if (!treat_family_as_pattern) { // Remove all extra family names from original pattern. // After this, FcFontRenderPrepare will select the most relevant family @@ -167,7 +157,6 @@ static char *_select_font(ASS_Library *library, FCInstance *priv, for (; family_cnt > 1; --family_cnt) FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); } -#endif rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); if (!rpat) @@ -250,7 +239,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, char *res = 0; if (!priv->config) { *index = priv->index_default; - return priv->path_default; + res = priv->path_default ? strdup(priv->path_default) : 0; + return res; } if (family && *family) res = @@ -266,7 +256,7 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, family, bold, italic, res, *index); } if (!res && priv->path_default) { - res = priv->path_default; + res = strdup(priv->path_default); *index = priv->index_default; ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: " "(%s, %d, %d) -> %s, %d", family, bold, italic, @@ -287,41 +277,6 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, return res; } -#if (FC_VERSION < 20402) -static char *validate_fname(char *name) -{ - char *fname; - char *p; - char *q; - unsigned code; - int sz = strlen(name); - - q = fname = malloc(sz + 1); - p = name; - while (*p) { - code = ass_utf8_get_char(&p); - if (code == 0) - break; - if ((code > 0x7F) || - (code == '\\') || - (code == '/') || - (code == ':') || - (code == '*') || - (code == '?') || - (code == '<') || - (code == '>') || (code == '|') || (code == 0)) { - *q++ = '_'; - } else { - *q++ = code; - } - if (p - name > sz) - break; - } - *q = 0; - return fname; -} -#endif - /** * \brief Process memory font. * \param priv private data @@ -339,44 +294,6 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library, const char *data = library->fontdata[idx].data; int data_size = library->fontdata[idx].size; -#if (FC_VERSION < 20402) - struct stat st; - char *fname; - const char *fonts_dir = library->fonts_dir; - char buf[1000]; - FILE *fp = NULL; - - if (!fonts_dir) - return; - rc = stat(fonts_dir, &st); - if (rc) { - int res; -#ifndef __MINGW32__ - res = mkdir(fonts_dir, 0700); -#else - res = mkdir(fonts_dir); -#endif - if (res) { - ass_msg(library, MSGL_WARN, "Failed to create directory '%s'", - fonts_dir); - } - } else if (!S_ISDIR(st.st_mode)) { - ass_msg(library, MSGL_WARN, "Not a directory: '%s'", fonts_dir); - } - - fname = validate_fname((char *) name); - - snprintf(buf, 1000, "%s/%s", fonts_dir, fname); - free(fname); - - fp = fopen(buf, "wb"); - if (!fp) - return; - - fwrite(data, data_size, 1, fp); - fclose(fp); - -#else // (FC_VERSION >= 20402) FT_Face face; FcPattern *pattern; FcFontSet *fset; @@ -418,7 +335,6 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library, FT_Done_Face(face); } -#endif } /** @@ -472,40 +388,7 @@ FCInstance *fontconfig_init(ASS_Library *library, process_fontdata(priv, library, ftlibrary, i); if (dir) { - if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) { - ass_msg(library, MSGL_INFO, "Updating font cache"); - if (FcGetVersion() >= 20390 && FcGetVersion() < 20400) - ass_msg(library, MSGL_WARN, "Beta versions of fontconfig" - "are not supported. Update before reporting any bugs"); - // FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir() - if (FcGetVersion() < 20390) { - FcFontSet *fcs; - FcStrSet *fss; - fcs = FcFontSetCreate(); - fss = FcStrSetCreate(); - rc = FcStrSetAdd(fss, (const FcChar8 *) dir); - if (!rc) { - ass_msg(library, MSGL_WARN, "%s failed", "FcStrSetAdd"); - goto ErrorFontCache; - } - - rc = FcDirScan(fcs, fss, NULL, - FcConfigGetBlanks(priv->config), - (const FcChar8 *) dir, FcFalse); - if (!rc) { - ass_msg(library, MSGL_WARN, "%s failed", "FcDirScan"); - goto ErrorFontCache; - } - - rc = FcDirSave(fcs, fss, (const FcChar8 *) dir); - if (!rc) { - ass_msg(library, MSGL_WARN, "%s failed", "FcDirSave"); - goto ErrorFontCache; - } - ErrorFontCache: - ; - } - } + ass_msg(library, MSGL_INFO, "Updating font cache"); rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); if (!rc) { @@ -534,7 +417,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, uint32_t code) { *index = priv->index_default; - return priv->path_default; + char* res = priv->path_default ? strdup(priv->path_default) : 0; + return res; } FCInstance *fontconfig_init(ASS_Library *library, @@ -549,7 +433,7 @@ FCInstance *fontconfig_init(ASS_Library *library, priv = calloc(1, sizeof(FCInstance)); - priv->path_default = strdup(path); + priv->path_default = path ? strdup(path) : 0; priv->index_default = 0; return priv; } diff --git a/aegisub/libass/ass_parse.c b/aegisub/libass/ass_parse.c index 0f3b4414a..0ccb5a2b1 100644 --- a/aegisub/libass/ass_parse.c +++ b/aegisub/libass/ass_parse.c @@ -123,15 +123,9 @@ void change_border(ASS_Renderer *render_priv, double border_x, if (bord > 0 && border_x == border_y) { if (!render_priv->state.stroker) { int error; -#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1)) error = FT_Stroker_New(render_priv->ftlibrary, &render_priv->state.stroker); -#else // < 2.2 - error = - FT_Stroker_New(render_priv->state.font->faces[0]-> - memory, &render_priv->state.stroker); -#endif if (error) { ass_msg(render_priv->library, MSGL_V, "failed to get stroker"); @@ -164,7 +158,7 @@ inline void change_alpha(uint32_t *var, uint32_t new, double pwr) { *var = (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + - (_a(*var) * (1 - pwr) + _a(new) * pwr); + (uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr); } /** @@ -233,20 +227,20 @@ static char *parse_vector_clip(ASS_Renderer *render_priv, char *p) while (*p != ')' && *p != '}' && p != 0) ass_drawing_add_char(drawing, *p++); skipopt(')'); - ass_drawing_parse(drawing, 1); - - // We need to translate the clip according to screen borders - if (render_priv->settings.left_margin != 0 || - render_priv->settings.top_margin != 0) { - FT_Vector trans = { - .x = int_to_d6(render_priv->settings.left_margin), - .y = -int_to_d6(render_priv->settings.top_margin), - }; - FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y); + if (ass_drawing_parse(drawing, 1)) { + // We need to translate the clip according to screen borders + if (render_priv->settings.left_margin != 0 || + render_priv->settings.top_margin != 0) { + FT_Vector trans = { + .x = int_to_d6(render_priv->settings.left_margin), + .y = -int_to_d6(render_priv->settings.top_margin), + }; + FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y); + } + ass_msg(render_priv->library, MSGL_DBG2, + "Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n", + scale, drawing->scale_x, drawing->scale_y, drawing->text); } - ass_msg(render_priv->library, MSGL_DBG2, - "Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n", - scale, drawing->scale_x, drawing->scale_y, drawing->text); return p; } @@ -802,6 +796,81 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) return p; } +void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event) +{ + int v[4]; + int cnt; + char *p = event->Effect; + + if (!p || !*p) + return; + + cnt = 0; + while (cnt < 4 && (p = strchr(p, ';'))) { + v[cnt++] = atoi(++p); + } + + if (strncmp(event->Effect, "Banner;", 7) == 0) { + int delay; + if (cnt < 1) { + ass_msg(render_priv->library, MSGL_V, + "Error parsing effect: '%s'", event->Effect); + return; + } + if (cnt >= 2 && v[1] == 0) // right-to-left + render_priv->state.scroll_direction = SCROLL_RL; + else // left-to-right + render_priv->state.scroll_direction = SCROLL_LR; + + delay = v[0]; + if (delay == 0) + delay = 1; // ? + render_priv->state.scroll_shift = + (render_priv->time - render_priv->state.event->Start) / delay; + render_priv->state.evt_type = EVENT_HSCROLL; + return; + } + + if (strncmp(event->Effect, "Scroll up;", 10) == 0) { + render_priv->state.scroll_direction = SCROLL_BT; + } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { + render_priv->state.scroll_direction = SCROLL_TB; + } else { + ass_msg(render_priv->library, MSGL_V, + "Unknown transition effect: '%s'", event->Effect); + return; + } + // parse scroll up/down parameters + { + int delay; + int y0, y1; + if (cnt < 3) { + ass_msg(render_priv->library, MSGL_V, + "Error parsing effect: '%s'", event->Effect); + return; + } + delay = v[2]; + if (delay == 0) + delay = 1; // ? + render_priv->state.scroll_shift = + (render_priv->time - render_priv->state.event->Start) / delay; + if (v[0] < v[1]) { + y0 = v[0]; + y1 = v[1]; + } else { + y0 = v[1]; + y1 = v[0]; + } + if (y1 == 0) + y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling + render_priv->state.clip_y0 = y0; + render_priv->state.clip_y1 = y1; + render_priv->state.evt_type = EVENT_VSCROLL; + render_priv->state.detect_collisions = 0; + } + +} + /** * \brief Get next ucs4 char from string, parsing and executing style overrides * \param str string pointer diff --git a/aegisub/libass/ass_parse.h b/aegisub/libass/ass_parse.h index e4b37487f..c65b56515 100644 --- a/aegisub/libass/ass_parse.h +++ b/aegisub/libass/ass_parse.h @@ -29,6 +29,7 @@ void update_font(ASS_Renderer *render_priv); void change_border(ASS_Renderer *render_priv, double border_x, double border_y); +void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event); unsigned get_next_char(ASS_Renderer *render_priv, char **str); extern void change_alpha(uint32_t *var, uint32_t new, double pwr); extern uint32_t mult_alpha(uint32_t a, uint32_t b); diff --git a/aegisub/libass/ass_render.c b/aegisub/libass/ass_render.c index edb0c840a..6bc0c61ba 100644 --- a/aegisub/libass/ass_render.c +++ b/aegisub/libass/ass_render.c @@ -809,82 +809,6 @@ static void compute_string_bbox(TextInfo *info, DBBox *bbox) bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.; } -static void -apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event) -{ - int v[4]; - int cnt; - char *p = event->Effect; - - if (!p || !*p) - return; - - cnt = 0; - while (cnt < 4 && (p = strchr(p, ';'))) { - v[cnt++] = atoi(++p); - } - - if (strncmp(event->Effect, "Banner;", 7) == 0) { - int delay; - if (cnt < 1) { - ass_msg(render_priv->library, MSGL_V, - "Error parsing effect: '%s'", event->Effect); - return; - } - if (cnt >= 2 && v[1] == 0) // right-to-left - render_priv->state.scroll_direction = SCROLL_RL; - else // left-to-right - render_priv->state.scroll_direction = SCROLL_LR; - - delay = v[0]; - if (delay == 0) - delay = 1; // ? - render_priv->state.scroll_shift = - (render_priv->time - render_priv->state.event->Start) / delay; - render_priv->state.evt_type = EVENT_HSCROLL; - return; - } - - if (strncmp(event->Effect, "Scroll up;", 10) == 0) { - render_priv->state.scroll_direction = SCROLL_BT; - } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { - render_priv->state.scroll_direction = SCROLL_TB; - } else { - ass_msg(render_priv->library, MSGL_V, - "Unknown transition effect: '%s'", event->Effect); - return; - } - // parse scroll up/down parameters - { - int delay; - int y0, y1; - if (cnt < 3) { - ass_msg(render_priv->library, MSGL_V, - "Error parsing effect: '%s'", event->Effect); - return; - } - delay = v[2]; - if (delay == 0) - delay = 1; // ? - render_priv->state.scroll_shift = - (render_priv->time - render_priv->state.event->Start) / delay; - if (v[0] < v[1]) { - y0 = v[0]; - y1 = v[1]; - } else { - y0 = v[1]; - y1 = v[0]; - } - if (y1 == 0) - y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling - render_priv->state.clip_y0 = y0; - render_priv->state.clip_y1 = y1; - render_priv->state.evt_type = EVENT_VSCROLL; - render_priv->state.detect_collisions = 0; - } - -} - /** * \brief partially reset render_context to style values * Works like {\r}: resets some style overrides @@ -947,6 +871,7 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event) render_priv->state.clip_y0 = 0; render_priv->state.clip_x1 = render_priv->track->PlayResX; render_priv->state.clip_y1 = render_priv->track->PlayResY; + render_priv->state.clip_mode = 0; render_priv->state.detect_collisions = 1; render_priv->state.fade = 0; render_priv->state.drawing_mode = 0; @@ -1208,7 +1133,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, } else { GlyphHashValue v; if (drawing->hash) { - ass_drawing_parse(drawing, 0); + if(!ass_drawing_parse(drawing, 0)) + return; FT_Glyph_Copy((FT_Glyph) drawing->glyph, &info->glyph); } else { info->glyph = @@ -1816,6 +1742,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, int MarginL, MarginR, MarginV; int last_break; int alignment, halign, valign; + int kern = render_priv->track->Kerning; double device_x = 0; double device_y = 0; TextInfo *text_info = &render_priv->text_info; @@ -1879,7 +1806,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, } // Add kerning to pen - if (previous && code && !drawing->hash) { + if (kern && previous && code && !drawing->hash) { FT_Vector delta; delta = ass_font_get_kerning(render_priv->state.font, previous, @@ -1980,23 +1907,23 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, drawing->hash; text_info->glyphs[text_info->length].hash_key.ch = code; text_info->glyphs[text_info->length].hash_key.outline.x = - render_priv->state.border_x * 0xFFFF; + double_to_d16(render_priv->state.border_x); text_info->glyphs[text_info->length].hash_key.outline.y = - render_priv->state.border_y * 0xFFFF; + double_to_d16(render_priv->state.border_y); text_info->glyphs[text_info->length].hash_key.scale_x = - render_priv->state.scale_x * 0xFFFF; + double_to_d16(render_priv->state.scale_x); text_info->glyphs[text_info->length].hash_key.scale_y = - render_priv->state.scale_y * 0xFFFF; + double_to_d16(render_priv->state.scale_y); text_info->glyphs[text_info->length].hash_key.frx = - render_priv->state.frx * 0xFFFF; + rot_key(render_priv->state.frx); text_info->glyphs[text_info->length].hash_key.fry = - render_priv->state.fry * 0xFFFF; + rot_key(render_priv->state.fry); text_info->glyphs[text_info->length].hash_key.frz = - render_priv->state.frz * 0xFFFF; + rot_key(render_priv->state.frz); text_info->glyphs[text_info->length].hash_key.fax = - render_priv->state.fax * 0xFFFF; + double_to_d16(render_priv->state.fax); text_info->glyphs[text_info->length].hash_key.fay = - render_priv->state.fay * 0xFFFF; + double_to_d16(render_priv->state.fay); text_info->glyphs[text_info->length].hash_key.advance.x = pen.x; text_info->glyphs[text_info->length].hash_key.advance.y = pen.y; text_info->glyphs[text_info->length].hash_key.be = diff --git a/aegisub/libass/ass_strtod.c b/aegisub/libass/ass_strtod.c new file mode 100644 index 000000000..7b73630bc --- /dev/null +++ b/aegisub/libass/ass_strtod.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + */ + +#include +#include +#include + +static int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ + +static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* + *---------------------------------------------------------------------- + * + * strtod -- + * + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Results: + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double +ass_strtod(string, endPtr) + const char *string; /* A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ + char **endPtr; /* If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = 0; + double fraction, dblExp, *d; + register const char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + const char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = 1; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = 0; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = 1; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = 0; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = 1; + exp = -exp; + } else { + expSign = 0; + } + if (exp > maxExponent) { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/aegisub/libass/ass_types.h b/aegisub/libass/ass_types.h index d6a011101..63bc36c40 100644 --- a/aegisub/libass/ass_types.h +++ b/aegisub/libass/ass_types.h @@ -113,6 +113,7 @@ typedef struct ass_track { double Timer; int WrapStyle; int ScaledBorderAndShadow; + int Kerning; int default_style; // index of default style char *name; // file name in case of external subs, 0 for streams diff --git a/aegisub/libass/ass_utils.c b/aegisub/libass/ass_utils.c index 6ca78b860..59fdbdfb9 100644 --- a/aegisub/libass/ass_utils.c +++ b/aegisub/libass/ass_utils.c @@ -34,7 +34,7 @@ int mystrtoi(char **p, int *res) { double temp_res; char *start = *p; - temp_res = strtod(*p, p); + temp_res = ass_strtod(*p, p); *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); if (*p != start) return 1; @@ -46,7 +46,7 @@ int mystrtoll(char **p, long long *res) { double temp_res; char *start = *p; - temp_res = strtod(*p, p); + temp_res = ass_strtod(*p, p); *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); if (*p != start) return 1; @@ -67,7 +67,7 @@ int mystrtou32(char **p, int base, uint32_t *res) int mystrtod(char **p, double *res) { char *start = *p; - *res = strtod(*p, p); + *res = ass_strtod(*p, p); if (*p != start) return 1; else diff --git a/aegisub/libass/ass_utils.h b/aegisub/libass/ass_utils.h index bade57804..ad8574c1d 100644 --- a/aegisub/libass/ass_utils.h +++ b/aegisub/libass/ass_utils.h @@ -59,6 +59,9 @@ void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer, char *fallback); #endif +/* defined in ass_strtod.c */ +double ass_strtod(const char *string, char **endPtr); + static inline int d6_to_int(int x) { return (x + 32) >> 6; @@ -99,6 +102,21 @@ static inline int double_to_d16(double x) { return (int) (x * 0x10000); } +static inline double d22_to_double(int x) +{ + return ((double) x) / 0x400000; +} +static inline int double_to_d22(double x) +{ + return (int) (x * 0x400000); +} + +// Calculate cache key for a rotational angle in degrees +static inline int rot_key(double a) +{ + const int m = double_to_d22(360.0); + return double_to_d22(a) % m; +} #define FNV1_32A_INIT (unsigned)0x811c9dc5