diff --git a/aegisub/libass/Makefile.am b/aegisub/libass/Makefile.am index cdcfd3e28..9ac93bf4f 100644 --- a/aegisub/libass/Makefile.am +++ b/aegisub/libass/Makefile.am @@ -19,6 +19,3 @@ libass_aegisub_a_SOURCES = \ libass_aegisub_a_SOURCES += \ *.h - -EXTRA_DIST= \ - ass_cache_template.c diff --git a/aegisub/libass/ass.c b/aegisub/libass/ass.c index 5aef14479..9eaa7b01d 100644 --- a/aegisub/libass/ass.c +++ b/aegisub/libass/ass.c @@ -182,25 +182,26 @@ static int lookup_style(ass_track_t *track, char *name) return i; } i = track->default_style; - ass_msg(MSGL_WARN, MSGTR_LIBASS_NoStyleNamedXFoundUsingY, - track, name, track->styles[i].Name); + ass_msg(track->library, MSGL_WARN, + "[%p]: Warning: no style named '%s' found, using '%s'", + track, name, track->styles[i].Name); return i; // use the first style } -static uint32_t string2color(char *p) +static uint32_t string2color(ass_library_t *library, char *p) { uint32_t tmp; - (void) strtocolor(&p, &tmp); + (void) strtocolor(library, &p, &tmp); return tmp; } -static long long string2timecode(char *p) +static long long string2timecode(ass_library_t *library, char *p) { unsigned h, m, s, ms; long long tm; int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms); if (res < 4) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_BadTimestamp); + ass_msg(library, MSGL_WARN, "Bad timestamp"); return 0; } tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; @@ -228,22 +229,30 @@ static int numpad2align(int val) #define ANYVAL(name,func) \ } else if (strcasecmp(tname, #name) == 0) { \ target->name = func(token); \ - ass_msg(MSGL_DBG2, "%s = %s\n", #name, token); + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); #define STRVAL(name) \ } else if (strcasecmp(tname, #name) == 0) { \ if (target->name != NULL) free(target->name); \ target->name = strdup(token); \ - ass_msg(MSGL_DBG2, "%s = %s\n", #name, token); + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); + +#define COLORVAL(name) \ + } else if (strcasecmp(tname, #name) == 0) { \ + target->name = string2color(track->library, token); \ + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); -#define COLORVAL(name) ANYVAL(name,string2color) #define INTVAL(name) ANYVAL(name,atoi) #define FPVAL(name) ANYVAL(name,atof) -#define TIMEVAL(name) ANYVAL(name,string2timecode) +#define TIMEVAL(name) \ + } else if (strcasecmp(tname, #name) == 0) { \ + target->name = string2timecode(track->library, token); \ + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); + #define STYLEVAL(name) \ } else if (strcasecmp(tname, #name) == 0) { \ target->name = lookup_style(track, token); \ - ass_msg(MSGL_DBG2, "%s = %s\n", #name, token); + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); #define ALIAS(alias,name) \ if (strcasecmp(tname, #alias) == 0) {tname = #name;} @@ -317,7 +326,7 @@ static int process_event_tail(ass_track_t *track, ass_event_t *event, if (last >= event->Text && *last == '\r') *last = 0; } - ass_msg(MSGL_DBG2, "Text = %s\n", event->Text); + ass_msg(track->library, MSGL_DBG2, "Text = %s", event->Text); event->Duration -= event->Start; free(format); return 0; // "Text" is always the last @@ -457,7 +466,7 @@ static int process_style(ass_track_t *track, char *str) q = format = strdup(track->style_format); - ass_msg(MSGL_V, "[%p] Style: %s\n", track, str); + ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str); sid = ass_alloc_style(track); @@ -534,7 +543,7 @@ static int process_styles_line(ass_track_t *track, char *str) char *p = str + 7; skip_spaces(&p); track->style_format = strdup(p); - ass_msg(MSGL_DBG2, "Style format: %s\n", + ass_msg(track->library, MSGL_DBG2, "Style format: %s", track->style_format); } else if (!strncmp(str, "Style:", 6)) { char *p = str + 6; @@ -564,14 +573,13 @@ static void event_format_fallback(ass_track_t *track) { track->parser_priv->state = PST_EVENTS; if (track->track_type == TRACK_TYPE_SSA) - track->event_format = - strdup - ("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"); + track->event_format = strdup("Format: Marked, Start, End, Style, " + "Name, MarginL, MarginR, MarginV, Effect, Text"); else - track->event_format = - strdup - ("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text"); - ass_msg(MSGL_V, "No event format found, using fallback.\n"); + track->event_format = strdup("Format: Layer, Start, End, Style, " + "Actor, MarginL, MarginR, MarginV, Effect, Text"); + ass_msg(track->library, MSGL_V, + "No event format found, using fallback"); } static int process_events_line(ass_track_t *track, char *str) @@ -580,8 +588,7 @@ static int process_events_line(ass_track_t *track, char *str) char *p = str + 7; skip_spaces(&p); track->event_format = strdup(p); - ass_msg(MSGL_DBG2, "Event format: %s\n", - track->event_format); + ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); } else if (!strncmp(str, "Dialogue:", 9)) { // This should never be reached for embedded subtitles. // They have slightly different format and are parsed in ass_process_chunk, @@ -601,7 +608,7 @@ static int process_events_line(ass_track_t *track, char *str) process_event_tail(track, event, str, 0); } else { - ass_msg(MSGL_V, "Not understood: %s \n", str); + ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); } return 0; } @@ -636,11 +643,11 @@ static int decode_font(ass_track_t *track) int dsize; // decoded size unsigned char *buf = 0; - ass_msg(MSGL_V, "font: %d bytes encoded data \n", - track->parser_priv->fontdata_used); + ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data", + track->parser_priv->fontdata_used); size = track->parser_priv->fontdata_used; if (size % 4 == 1) { - ass_msg(MSGL_ERR, MSGTR_LIBASS_BadEncodedDataSize); + ass_msg(track->library, MSGL_ERR, "Bad encoded data size"); goto error_decode_font; } buf = malloc(size / 4 * 3 + 2); @@ -686,19 +693,20 @@ static int process_fonts_line(ass_track_t *track, char *str) decode_font(track); } track->parser_priv->fontname = strdup(p); - ass_msg(MSGL_V, "fontname: %s\n", + ass_msg(track->library, MSGL_V, "Fontname: %s", track->parser_priv->fontname); return 0; } if (!track->parser_priv->fontname) { - ass_msg(MSGL_V, "Not understood: %s \n", str); + ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); return 0; } len = strlen(str); if (len > 80) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FontLineTooLong, len, str); + ass_msg(track->library, MSGL_WARN, "Font line too long: %d, %s", + len, str); return 0; } if (track->parser_priv->fontdata_used + len > @@ -801,7 +809,7 @@ void ass_process_data(ass_track_t *track, char *data, int size) memcpy(str, data, size); str[size] = '\0'; - ass_msg(MSGL_V, "event: %s\n", str); + ass_msg(track->library, MSGL_V, "Event: %s", str); process_text(track, str); free(str); } @@ -852,14 +860,14 @@ void ass_process_chunk(ass_track_t *track, char *data, int size, ass_event_t *event; if (!track->event_format) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_EventFormatHeaderMissing); + ass_msg(track->library, MSGL_WARN, "Event format header missing"); return; } str = malloc(size + 1); memcpy(str, data, size); str[size] = '\0'; - ass_msg(MSGL_V, "event at %" PRId64 ", +%" PRId64 ": %s \n", + ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", (int64_t) timecode, (int64_t) duration, str); eid = ass_alloc_event(track); @@ -898,7 +906,8 @@ void ass_process_chunk(ass_track_t *track, char *data, int size, * \param size buffer size * \return a pointer to recoded buffer, caller is responsible for freeing it **/ -static char *sub_recode(char *data, size_t size, char *codepage) +static char *sub_recode(ass_library_t *library, char *data, size_t size, + char *codepage) { iconv_t icdsc; char *tocp = "UTF-8"; @@ -913,15 +922,14 @@ static char *sub_recode(char *data, size_t size, char *codepage) || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2) { cp_tmp = - ass_guess_buffer_cp((unsigned char *) data, size, enca_lang, - enca_fallback); + ass_guess_buffer_cp(library, (unsigned char *) data, size, + enca_lang, enca_fallback); } #endif if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) { - ass_msg(MSGL_V, "LIBSUB: opened iconv descriptor.\n"); + ass_msg(library, MSGL_V, "Opened iconv descriptor"); } else - ass_msg(MSGL_ERR, - MSGTR_LIBASS_ErrorOpeningIconvDescriptor); + ass_msg(library, MSGL_ERR, "Error opening iconv descriptor"); } { @@ -952,8 +960,7 @@ static char *sub_recode(char *data, size_t size, char *codepage) osize += size; oleft += size; } else { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_ErrorRecodingFile); + ass_msg(library, MSGL_WARN, "Error recoding file"); return NULL; } } else if (clear) @@ -965,7 +972,7 @@ static char *sub_recode(char *data, size_t size, char *codepage) if (icdsc != (iconv_t) (-1)) { (void) iconv_close(icdsc); icdsc = (iconv_t) (-1); - ass_msg(MSGL_V, "LIBSUB: closed iconv descriptor.\n"); + ass_msg(library, MSGL_V, "Closed iconv descriptor"); } return outbuf; @@ -978,7 +985,7 @@ static char *sub_recode(char *data, size_t size, char *codepage) * \param bufsize out: file size * \return pointer to file contents. Caller is responsible for its deallocation. */ -static char *read_file(char *fname, size_t *bufsize) +static char *read_file(ass_library_t *library, char *fname, size_t *bufsize) { int res; long sz; @@ -987,12 +994,14 @@ static char *read_file(char *fname, size_t *bufsize) FILE *fp = fopen(fname, "rb"); if (!fp) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname); + ass_msg(library, MSGL_WARN, + "ass_read_file(%s): fopen failed", fname); return 0; } res = fseek(fp, 0, SEEK_END); if (res == -1) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FseekFailed, fname); + ass_msg(library, MSGL_WARN, + "ass_read_file(%s): fseek failed", fname); fclose(fp); return 0; } @@ -1001,13 +1010,14 @@ static char *read_file(char *fname, size_t *bufsize) rewind(fp); if (sz > 10 * 1024 * 1024) { - ass_msg(MSGL_INFO, - MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M, fname); + ass_msg(library, MSGL_INFO, + "ass_read_file(%s): Refusing to load subtitles " + "larger than 10MiB", fname); fclose(fp); return 0; } - ass_msg(MSGL_V, "file size: %ld\n", sz); + ass_msg(library, MSGL_V, "File size: %ld", sz); buf = malloc(sz + 1); assert(buf); @@ -1015,8 +1025,8 @@ static char *read_file(char *fname, size_t *bufsize) do { res = fread(buf + bytes_read, 1, sz - bytes_read, fp); if (res <= 0) { - ass_msg(MSGL_INFO, MSGTR_LIBASS_ReadFailed, errno, - strerror(errno)); + ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno, + strerror(errno)); fclose(fp); free(buf); return 0; @@ -1081,7 +1091,7 @@ ass_track_t *ass_read_memory(ass_library_t *library, char *buf, #ifdef CONFIG_ICONV if (codepage) - buf = sub_recode(buf, bufsize, codepage); + buf = sub_recode(library, buf, bufsize, codepage); if (!buf) return 0; else @@ -1093,22 +1103,24 @@ ass_track_t *ass_read_memory(ass_library_t *library, char *buf, if (!track) return 0; - ass_msg(MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileMemory, - track->n_styles, track->n_events); + ass_msg(library, MSGL_INFO, "Added subtitle file: " + " (%d styles, %d events)", + track->n_styles, track->n_events); return track; } -static char *read_file_recode(char *fname, char *codepage, size_t *size) +static char *read_file_recode(ass_library_t *library, char *fname, + char *codepage, size_t *size) { char *buf; size_t bufsize; - buf = read_file(fname, &bufsize); + buf = read_file(library, fname, &bufsize); if (!buf) return 0; #ifdef CONFIG_ICONV if (codepage) { - char *tmpbuf = sub_recode(buf, bufsize, codepage); + char *tmpbuf = sub_recode(library, buf, bufsize, codepage); free(buf); buf = tmpbuf; } @@ -1133,7 +1145,7 @@ ass_track_t *ass_read_file(ass_library_t *library, char *fname, ass_track_t *track; size_t bufsize; - buf = read_file_recode(fname, codepage, &bufsize); + buf = read_file_recode(library, fname, codepage, &bufsize); if (!buf) return 0; track = parse_memory(library, buf); @@ -1143,10 +1155,10 @@ ass_track_t *ass_read_file(ass_library_t *library, char *fname, track->name = strdup(fname); - ass_msg(MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileFname, fname, - track->n_styles, track->n_events); + ass_msg(library, MSGL_INFO, + "Added subtitle file: '%s' (%d styles, %d events)", + fname, track->n_styles, track->n_events); -// dump_events(forced_tid); return track; } @@ -1159,13 +1171,13 @@ int ass_read_styles(ass_track_t *track, char *fname, char *codepage) parser_state_t old_state; size_t sz; - buf = read_file(fname, &sz); + buf = read_file(track->library, fname, &sz); if (!buf) return 1; #ifdef CONFIG_ICONV if (codepage) { char *tmpbuf; - tmpbuf = sub_recode(buf, sz, codepage); + tmpbuf = sub_recode(track->library, buf, sz, codepage); free(buf); buf = tmpbuf; } diff --git a/aegisub/libass/ass.h b/aegisub/libass/ass.h index d911e9911..0a03ec2a0 100644 --- a/aegisub/libass/ass.h +++ b/aegisub/libass/ass.h @@ -22,6 +22,7 @@ #define LIBASS_ASS_H #include +#include #include "ass_types.h" /// Libass renderer object. Contents are private. @@ -69,6 +70,10 @@ void ass_set_style_overrides(ass_library_t *priv, char **list); void ass_process_force_style(ass_track_t *track); +void ass_set_message_cb(ass_library_t *priv, + void (*msg_cb)(int, char *, va_list *, void *), + void *data); + /** * \brief initialize the renderer * \param priv library handle diff --git a/aegisub/libass/ass_bitmap.c b/aegisub/libass/ass_bitmap.c index 16d2b351e..3642be826 100644 --- a/aegisub/libass/ass_bitmap.c +++ b/aegisub/libass/ass_bitmap.c @@ -165,7 +165,7 @@ static bitmap_t *copy_bitmap(const bitmap_t *src) return dst; } -static int check_glyph_area(FT_Glyph glyph) +static int check_glyph_area(ass_library_t *library, FT_Glyph glyph) { FT_BBox bbox; long long dx, dy; @@ -173,14 +173,15 @@ static int check_glyph_area(FT_Glyph glyph) dx = bbox.xMax - bbox.xMin; dy = bbox.yMax - bbox.yMin; if (dx * dy > 8000000) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_GlyphBBoxTooLarge, + ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx", (int) dx, (int) dy); return 1; } else return 0; } -static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord) +static bitmap_t *glyph_to_bitmap_internal(ass_library_t *library, + FT_Glyph glyph, int bord) { FT_BitmapGlyph bg; FT_Bitmap *bit; @@ -191,11 +192,11 @@ static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord) int i; int error; - if (check_glyph_area(glyph)) + if (check_glyph_area(library, glyph)) return 0; error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0); if (error) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, + ass_msg(library, MSGL_WARN, "FT_Glyph_To_Bitmap error %d", error); return 0; } @@ -203,7 +204,7 @@ static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord) bg = (FT_BitmapGlyph) glyph; bit = &(bg->bitmap); if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_UnsupportedPixelMode, + ass_msg(library, MSGL_WARN, "Unsupported pixel mode: %d", (int) (bit->pixel_mode)); FT_Done_Glyph(glyph); return 0; @@ -260,7 +261,7 @@ static bitmap_t *fix_outline_and_shadow(bitmap_t *bm_g, bitmap_t *bm_o) unsigned char c_g, c_o; c_g = g[x]; c_o = o[x]; - o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0; + o[x] = (c_o > (3 * c_g) / 5) ? c_o - (3 * c_g) / 5 : 0; s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF; } g += bm_g->w; @@ -322,6 +323,127 @@ static void shift_bitmap(unsigned char *buf, int w, int h, int shift_x, } } +/* + * Gaussian blur. An fast pure C implementation from MPlayer. + */ +static void ass_gauss_blur(unsigned char *buffer, unsigned short *tmp2, + int width, int height, int stride, int *m2, + int r, int mwidth) +{ + + int x, y; + + unsigned char *s = buffer; + unsigned short *t = tmp2 + 1; + for (y = 0; y < height; y++) { + memset(t - 1, 0, (width + 1) * sizeof(short)); + + for (x = 0; x < r; x++) { + const int src = s[x]; + if (src) { + register unsigned short *dstp = t + x - r; + int mx; + unsigned *m3 = (unsigned *) (m2 + src * mwidth); + for (mx = r - x; mx < mwidth; mx++) { + dstp[mx] += m3[mx]; + } + } + } + + for (; x < width - r; x++) { + const int src = s[x]; + if (src) { + register unsigned short *dstp = t + x - r; + int mx; + unsigned *m3 = (unsigned *) (m2 + src * mwidth); + for (mx = 0; mx < mwidth; mx++) { + dstp[mx] += m3[mx]; + } + } + } + + for (; x < width; x++) { + const int src = s[x]; + if (src) { + register unsigned short *dstp = t + x - r; + int mx; + const int x2 = r + width - x; + unsigned *m3 = (unsigned *) (m2 + src * mwidth); + for (mx = 0; mx < x2; mx++) { + dstp[mx] += m3[mx]; + } + } + } + + s += stride; + t += width + 1; + } + + t = tmp2; + for (x = 0; x < width; x++) { + for (y = 0; y < r; y++) { + unsigned short *srcp = t + y * (width + 1) + 1; + int src = *srcp; + if (src) { + register unsigned short *dstp = srcp - 1 + width + 1; + const int src2 = (src + 128) >> 8; + unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); + + int mx; + *srcp = 128; + for (mx = r - 1; mx < mwidth; mx++) { + *dstp += m3[mx]; + dstp += width + 1; + } + } + } + for (; y < height - r; y++) { + unsigned short *srcp = t + y * (width + 1) + 1; + int src = *srcp; + if (src) { + register unsigned short *dstp = srcp - 1 - r * (width + 1); + const int src2 = (src + 128) >> 8; + unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); + + int mx; + *srcp = 128; + for (mx = 0; mx < mwidth; mx++) { + *dstp += m3[mx]; + dstp += width + 1; + } + } + } + for (; y < height; y++) { + unsigned short *srcp = t + y * (width + 1) + 1; + int src = *srcp; + if (src) { + const int y2 = r + height - y; + register unsigned short *dstp = srcp - 1 - r * (width + 1); + const int src2 = (src + 128) >> 8; + unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); + + int mx; + *srcp = 128; + for (mx = 0; mx < y2; mx++) { + *dstp += m3[mx]; + dstp += width + 1; + } + } + } + t++; + } + + t = tmp2; + s = buffer; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + s[x] = t[x] >> 8; + } + s += stride; + t += width + 1; + } +} + /** * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel * This blur is the same as the one employed by vsfilter. @@ -350,14 +472,15 @@ static void be_blur(unsigned char *buf, int w, int h) } } -int glyph_to_bitmap(ass_synth_priv_t *priv_blur, +int glyph_to_bitmap(ass_library_t *library, ass_synth_priv_t *priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s, int be, double blur_radius, FT_Vector shadow_offset) { - int bord = be ? (be / 4 + 1) : 0; blur_radius *= 2; - bord = (blur_radius > 0.0) ? blur_radius + 1 : bord; + int bbord = be > 0 ? sqrt(2 * be) : 0; + int gbord = blur_radius > 0.0 ? blur_radius + 1 : 0; + int bord = FFMAX(bbord, gbord); if (bord == 0 && (shadow_offset.x || shadow_offset.y)) bord = 1; @@ -366,43 +489,45 @@ int glyph_to_bitmap(ass_synth_priv_t *priv_blur, *bm_g = *bm_o = *bm_s = 0; if (glyph) - *bm_g = glyph_to_bitmap_internal(glyph, bord); + *bm_g = glyph_to_bitmap_internal(library, glyph, bord); if (!*bm_g) return 1; if (outline_glyph) { - *bm_o = glyph_to_bitmap_internal(outline_glyph, bord); + *bm_o = glyph_to_bitmap_internal(library, outline_glyph, bord); if (!*bm_o) { ass_free_bitmap(*bm_g); return 1; } } - if (*bm_o) - resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h); - resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h); - if (be) { - while (be--) { - if (*bm_o) - be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h); - else - be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h); - } - } else { - if (blur_radius > 0.0) { - generate_tables(priv_blur, blur_radius); - if (*bm_o) - ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp, - (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, - (int *) priv_blur->gt2, priv_blur->g_r, - priv_blur->g_w); - else - ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp, - (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, - (int *) priv_blur->gt2, priv_blur->g_r, - priv_blur->g_w); - } + // Apply box blur (multiple passes, if requested) + while (be--) { + if (*bm_o) + be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h); + else + be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h); } + + // Apply gaussian blur + if (blur_radius > 0.0) { + if (*bm_o) + resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h); + else + resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h); + generate_tables(priv_blur, blur_radius); + if (*bm_o) + ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp, + (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, + (int *) priv_blur->gt2, priv_blur->g_r, + priv_blur->g_w); + else + ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp, + (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, + (int *) priv_blur->gt2, priv_blur->g_r, + priv_blur->g_w); + } + if (*bm_o) *bm_s = fix_outline_and_shadow(*bm_g, *bm_o); else diff --git a/aegisub/libass/ass_bitmap.h b/aegisub/libass/ass_bitmap.h index f6b138058..2e34a5c6d 100644 --- a/aegisub/libass/ass_bitmap.h +++ b/aegisub/libass/ass_bitmap.h @@ -24,6 +24,8 @@ #include #include FT_GLYPH_H +#include "ass.h" + typedef struct ass_synth_priv_s ass_synth_priv_t; ass_synth_priv_t *ass_synth_init(double); @@ -44,10 +46,10 @@ typedef struct bitmap_s { * \param bm_g out: pointer to the bitmap of glyph shadow is returned here * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps */ -int glyph_to_bitmap(ass_synth_priv_t *priv_blur, FT_Glyph glyph, - FT_Glyph outline_glyph, bitmap_t **bm_g, - bitmap_t **bm_o, bitmap_t **bm_s, int be, - double blur_radius, FT_Vector shadow_offset); +int glyph_to_bitmap(ass_library_t *library, ass_synth_priv_t *priv_blur, + FT_Glyph glyph, FT_Glyph outline_glyph, + bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s, + int be, double blur_radius, FT_Vector shadow_offset); void ass_free_bitmap(bitmap_t *bm); diff --git a/aegisub/libass/ass_cache.c b/aegisub/libass/ass_cache.c index fc70b0d4f..4c7a3fa53 100644 --- a/aegisub/libass/ass_cache.c +++ b/aegisub/libass/ass_cache.c @@ -51,12 +51,14 @@ static void hashmap_item_dtor(void *key, size_t key_size, void *value, free(value); } -hashmap_t *hashmap_init(size_t key_size, size_t value_size, int nbuckets, +hashmap_t *hashmap_init(ass_library_t *library, size_t key_size, + size_t value_size, int nbuckets, hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare, hashmap_hash_t hash) { hashmap_t *map = calloc(1, sizeof(hashmap_t)); + map->library = library; map->nbuckets = nbuckets; map->key_size = key_size; map->value_size = value_size; @@ -72,8 +74,9 @@ void hashmap_done(hashmap_t *map) int i; // print stats if (map->count > 0 || map->hit_count + map->miss_count > 0) - ass_msg(MSGL_V, - "cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n", + ass_msg(map->library, MSGL_V, + "cache statistics: \n total accesses: %d\n hits: %d\n " + "misses: %d\n object count: %d", map->hit_count + map->miss_count, map->hit_count, map->miss_count, map->count); @@ -178,10 +181,10 @@ void *ass_font_cache_add(hashmap_t *font_cache, ass_font_t *font) return hashmap_insert(font_cache, &(font->desc), font); } -hashmap_t *ass_font_cache_init(void) +hashmap_t *ass_font_cache_init(ass_library_t *library) { hashmap_t *font_cache; - font_cache = hashmap_init(sizeof(ass_font_desc_t), + font_cache = hashmap_init(library, sizeof(ass_font_desc_t), sizeof(ass_font_t), 1000, font_hash_dtor, font_compare, font_desc_hash); @@ -196,9 +199,9 @@ void ass_font_cache_done(hashmap_t *font_cache) // Create hash/compare functions for bitmap and glyph #define CREATE_HASH_FUNCTIONS -#include "ass_cache_template.c" +#include "ass_cache_template.h" #define CREATE_COMPARISON_FUNCTIONS -#include "ass_cache_template.c" +#include "ass_cache_template.h" //--------------------------------- // bitmap cache @@ -234,10 +237,11 @@ bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache, return hashmap_find(bitmap_cache, key); } -hashmap_t *ass_bitmap_cache_init(void) +hashmap_t *ass_bitmap_cache_init(ass_library_t *library) { hashmap_t *bitmap_cache; - bitmap_cache = hashmap_init(sizeof(bitmap_hash_key_t), + bitmap_cache = hashmap_init(library, + sizeof(bitmap_hash_key_t), sizeof(bitmap_hash_val_t), 0xFFFF + 13, bitmap_hash_dtor, bitmap_compare, @@ -252,8 +256,10 @@ void ass_bitmap_cache_done(hashmap_t *bitmap_cache) hashmap_t *ass_bitmap_cache_reset(hashmap_t *bitmap_cache) { + ass_library_t *lib = bitmap_cache->library; + ass_bitmap_cache_done(bitmap_cache); - return ass_bitmap_cache_init(); + return ass_bitmap_cache_init(lib); } //--------------------------------- @@ -288,10 +294,10 @@ glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache, return hashmap_find(glyph_cache, key); } -hashmap_t *ass_glyph_cache_init(void) +hashmap_t *ass_glyph_cache_init(ass_library_t *library) { hashmap_t *glyph_cache; - glyph_cache = hashmap_init(sizeof(glyph_hash_key_t), + glyph_cache = hashmap_init(library, sizeof(glyph_hash_key_t), sizeof(glyph_hash_val_t), 0xFFFF + 13, glyph_hash_dtor, glyph_compare, glyph_hash); @@ -305,8 +311,10 @@ void ass_glyph_cache_done(hashmap_t *glyph_cache) hashmap_t *ass_glyph_cache_reset(hashmap_t *glyph_cache) { + ass_library_t *lib = glyph_cache->library; + ass_glyph_cache_done(glyph_cache); - return ass_glyph_cache_init(); + return ass_glyph_cache_init(lib); } @@ -341,10 +349,10 @@ composite_hash_val_t *cache_find_composite(hashmap_t *composite_cache, return hashmap_find(composite_cache, key); } -hashmap_t *ass_composite_cache_init(void) +hashmap_t *ass_composite_cache_init(ass_library_t *library) { hashmap_t *composite_cache; - composite_cache = hashmap_init(sizeof(composite_hash_key_t), + composite_cache = hashmap_init(library, sizeof(composite_hash_key_t), sizeof(composite_hash_val_t), 0xFFFF + 13, composite_hash_dtor, composite_compare, @@ -359,6 +367,8 @@ void ass_composite_cache_done(hashmap_t *composite_cache) hashmap_t *ass_composite_cache_reset(hashmap_t *composite_cache) { + ass_library_t *lib = composite_cache->library; + ass_composite_cache_done(composite_cache); - return ass_composite_cache_init(); + return ass_composite_cache_init(lib); } diff --git a/aegisub/libass/ass_cache.h b/aegisub/libass/ass_cache.h index d8de97a18..83c994386 100644 --- a/aegisub/libass/ass_cache.h +++ b/aegisub/libass/ass_cache.h @@ -49,9 +49,11 @@ typedef struct hashmap_s { int hit_count; int miss_count; int count; + ass_library_t *library; } hashmap_t; -hashmap_t *hashmap_init(size_t key_size, size_t value_size, int nbuckets, +hashmap_t *hashmap_init(ass_library_t *library, size_t key_size, + size_t value_size, int nbuckets, hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare, hashmap_hash_t hash); @@ -59,14 +61,14 @@ void hashmap_done(hashmap_t *map); void *hashmap_insert(hashmap_t *map, void *key, void *value); void *hashmap_find(hashmap_t *map, void *key); -hashmap_t *ass_font_cache_init(void); +hashmap_t *ass_font_cache_init(ass_library_t *library); ass_font_t *ass_font_cache_find(hashmap_t *, ass_font_desc_t *desc); void *ass_font_cache_add(hashmap_t *, ass_font_t *font); void ass_font_cache_done(hashmap_t *); // Create definitions for bitmap_hash_key and glyph_hash_key #define CREATE_STRUCT_DEFINITIONS -#include "ass_cache_template.c" +#include "ass_cache_template.h" typedef struct bitmap_hash_val_s { bitmap_t *bm; // the actual bitmaps @@ -74,7 +76,7 @@ typedef struct bitmap_hash_val_s { bitmap_t *bm_s; } bitmap_hash_val_t; -hashmap_t *ass_bitmap_cache_init(void); +hashmap_t *ass_bitmap_cache_init(ass_library_t *library); void *cache_add_bitmap(hashmap_t *, bitmap_hash_key_t *key, bitmap_hash_val_t *val); bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache, @@ -88,7 +90,7 @@ typedef struct composite_hash_val_s { unsigned char *b; } composite_hash_val_t; -hashmap_t *ass_composite_cache_init(void); +hashmap_t *ass_composite_cache_init(ass_library_t *library); void *cache_add_composite(hashmap_t *, composite_hash_key_t *key, composite_hash_val_t *val); composite_hash_val_t *cache_find_composite(hashmap_t *composite_cache, @@ -105,7 +107,7 @@ typedef struct glyph_hash_val_s { int asc, desc; // ascender/descender of a drawing } glyph_hash_val_t; -hashmap_t *ass_glyph_cache_init(void); +hashmap_t *ass_glyph_cache_init(ass_library_t *library); void *cache_add_glyph(hashmap_t *, glyph_hash_key_t *key, glyph_hash_val_t *val); glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache, diff --git a/aegisub/libass/ass_cache_template.c b/aegisub/libass/ass_cache_template.h similarity index 100% rename from aegisub/libass/ass_cache_template.c rename to aegisub/libass/ass_cache_template.h diff --git a/aegisub/libass/ass_drawing.c b/aegisub/libass/ass_drawing.c index 09cf2d004..f75bbd9ad 100644 --- a/aegisub/libass/ass_drawing.c +++ b/aegisub/libass/ass_drawing.c @@ -138,6 +138,10 @@ static void drawing_finish(ass_drawing_t *drawing) drawing->scale_y); for (i = 0; i < ol->n_points; i++) ol->points[i].y += offset; + + ass_msg(drawing->library, MSGL_V, + "Parsed drawing with %d points and %d contours", ol->n_points, + ol->n_contours); } /* @@ -361,6 +365,7 @@ ass_drawing_t *ass_drawing_new(void *fontconfig_priv, ass_font_t *font, drawing->size = DRAWING_INITIAL_SIZE; drawing->ftlibrary = lib; + drawing->library = font->library; drawing_make_glyph(drawing, fontconfig_priv, font, hint); drawing->scale_x = 1.; diff --git a/aegisub/libass/ass_drawing.h b/aegisub/libass/ass_drawing.h index 323c05dee..dfd68f01b 100644 --- a/aegisub/libass/ass_drawing.h +++ b/aegisub/libass/ass_drawing.h @@ -58,6 +58,7 @@ typedef struct ass_drawing_s { // private FT_Library ftlibrary; // FT library instance, needed for font ops + ass_library_t *library; int size; // current buffer size ass_drawing_token_t *tokens; // tokenized drawing int max_points; // current maximum size diff --git a/aegisub/libass/ass_font.c b/aegisub/libass/ass_font.c index 0aeeec6c1..34ae292c4 100644 --- a/aegisub/libass/ass_font.c +++ b/aegisub/libass/ass_font.c @@ -39,7 +39,7 @@ * Select Microfost Unicode CharMap, if the font has one. * Otherwise, let FreeType decide. */ -static void charmap_magic(FT_Face face) +static void charmap_magic(ass_library_t *library, FT_Face face) { int i; for (i = 0; i < face->num_charmaps; ++i) { @@ -56,10 +56,11 @@ static void charmap_magic(FT_Face face) if (!face->charmap) { if (face->num_charmaps == 0) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_NoCharmaps); + ass_msg(library, MSGL_WARN, "Font face with no charmaps"); return; } - ass_msg(MSGL_WARN, MSGTR_LIBASS_NoCharmapAutodetected); + ass_msg(library, MSGL_WARN, + "No charmap autodetected, trying the first one"); FT_Set_Charmap(face, face->charmaps[0]); return; } @@ -125,7 +126,7 @@ static int add_face(void *fc_priv, ass_font_t *font, uint32_t ch) return -1; path = - fontconfig_select(fc_priv, font->desc.family, + fontconfig_select(font->library, fc_priv, font->desc.family, font->desc.treat_family_as_pattern, font->desc.bold, font->desc.italic, &index, ch); if (!path) @@ -140,21 +141,21 @@ static int add_face(void *fc_priv, ass_font_t *font, uint32_t ch) font->library->fontdata[mem_idx].size, 0, &face); if (error) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, - path); + ass_msg(font->library, MSGL_WARN, + "Error opening memory font: '%s'", path); free(path); return -1; } } else { error = FT_New_Face(font->ftlibrary, path, index, &face); if (error) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, - index); + ass_msg(font->library, MSGL_WARN, + "Error opening font: '%s', %d", path, index); free(path); return -1; } } - charmap_magic(face); + charmap_magic(font->library, face); buggy_font_workaround(face); font->faces[font->n_faces++] = face; @@ -386,17 +387,19 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, #ifdef CONFIG_FONTCONFIG if (index == 0) { int face_idx; - ass_msg(MSGL_INFO, - MSGTR_LIBASS_GlyphNotFoundReselectingFont, ch, - font->desc.family, font->desc.bold, font->desc.italic); + ass_msg(font->library, MSGL_INFO, + "Glyph 0x%X not found, selecting one more " + "font for (%s, %d, %d)", ch, font->desc.family, + font->desc.bold, font->desc.italic); face_idx = add_face(fontconfig_priv, font, ch); if (face_idx >= 0) { face = font->faces[face_idx]; index = FT_Get_Char_Index(face, ch); if (index == 0) { - ass_msg(MSGL_ERR, MSGTR_LIBASS_GlyphNotFound, - ch, font->desc.family, font->desc.bold, - font->desc.italic); + ass_msg(font->library, MSGL_ERR, + "Glyph 0x%X not found in font for (%s, %d, %d)", + ch, font->desc.family, font->desc.bold, + font->desc.italic); } } } @@ -419,7 +422,8 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags); if (error) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); + ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", + index); return 0; } #if (FREETYPE_MAJOR > 2) || \ @@ -433,7 +437,8 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, #endif error = FT_Get_Glyph(face->glyph, &glyph); if (error) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); + ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", + index); return 0; } diff --git a/aegisub/libass/ass_fontconfig.c b/aegisub/libass/ass_fontconfig.c index 2e6377a99..d8d64e229 100644 --- a/aegisub/libass/ass_fontconfig.c +++ b/aegisub/libass/ass_fontconfig.c @@ -71,9 +71,10 @@ struct fc_instance_s { * \param code: the character that should be present in the font, can be 0 * \return font file path */ -static char *_select_font(fc_instance_t *priv, const char *family, - int treat_family_as_pattern, unsigned bold, - unsigned italic, int *index, uint32_t code) +static char *_select_font(ass_library_t *library, fc_instance_t *priv, + const char *family, int treat_family_as_pattern, + unsigned bold, unsigned italic, int *index, + uint32_t code) { FcBool rc; FcResult result; @@ -193,8 +194,9 @@ static char *_select_font(fc_instance_t *priv, const char *family, if (!treat_family_as_pattern && !(r_family && strcasecmp((const char *) r_family, family) == 0) && !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) - ass_msg(MSGL_WARN, - MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne, + ass_msg(library, MSGL_WARN, + "fontconfig: Selected font is not the requested one: " + "'%s' != '%s'", (const char *) (r_fullname ? r_fullname : r_family), family); result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style); @@ -213,9 +215,9 @@ static char *_select_font(fc_instance_t *priv, const char *family, if (result != FcResultMatch) r_embolden = 0; - ass_msg(MSGL_V, - "[ass] Font info: family '%s', style '%s', fullname '%s'," - " slant %d, weight %d%s\n", (const char *) r_family, + ass_msg(library, MSGL_V, + "Font info: family '%s', style '%s', fullname '%s'," + " slant %d, weight %d%s", (const char *) r_family, (const char *) r_style, (const char *) r_fullname, r_slant, r_weight, r_embolden ? ", embolden" : ""); @@ -240,9 +242,10 @@ static char *_select_font(fc_instance_t *priv, const char *family, * \param code: the character that should be present in the font, can be 0 * \return font file path */ -char *fontconfig_select(fc_instance_t *priv, const char *family, - int treat_family_as_pattern, unsigned bold, - unsigned italic, int *index, uint32_t code) +char *fontconfig_select(ass_library_t *library, fc_instance_t *priv, + const char *family, int treat_family_as_pattern, + unsigned bold, unsigned italic, int *index, + uint32_t code) { char *res = 0; if (!priv->config) { @@ -251,32 +254,36 @@ char *fontconfig_select(fc_instance_t *priv, const char *family, } if (family && *family) res = - _select_font(priv, family, treat_family_as_pattern, bold, - italic, index, code); + _select_font(library, priv, family, treat_family_as_pattern, + bold, italic, index, code); if (!res && priv->family_default) { res = - _select_font(priv, priv->family_default, 0, bold, italic, index, - code); + _select_font(library, priv, priv->family_default, 0, bold, + italic, index, code); if (res) - ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily, - family, bold, italic, res, *index); + ass_msg(library, MSGL_WARN, "fontconfig_select: Using default " + "font family: (%s, %d, %d) -> %s, %d", + family, bold, italic, res, *index); } if (!res && priv->path_default) { res = priv->path_default; *index = priv->index_default; - ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingDefaultFont, - family, bold, italic, res, *index); + ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: " + "(%s, %d, %d) -> %s, %d", family, bold, italic, + res, *index); } if (!res) { - res = _select_font(priv, "Arial", 0, bold, italic, index, code); + res = _select_font(library, priv, "Arial", 0, bold, italic, + index, code); if (res) - ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily, - family, bold, italic, res, *index); + ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' " + "font family: (%s, %d, %d) -> %s, %d", family, bold, + italic, res, *index); } if (res) - ass_msg(MSGL_V, - "fontconfig_select: (%s, %d, %d) -> %s, %d\n", family, bold, - italic, res, *index); + ass_msg(library, MSGL_V, + "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold, + italic, res, *index); return res; } @@ -350,11 +357,11 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library, res = mkdir(fonts_dir); #endif if (res) { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_FailedToCreateDirectory, fonts_dir); + ass_msg(library, MSGL_WARN, "Failed to create directory '%s'", + fonts_dir); } } else if (!S_ISDIR(st.st_mode)) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_NotADirectory, fonts_dir); + ass_msg(library, MSGL_WARN, "Not a directory: '%s'", fonts_dir); } fname = validate_fname((char *) name); @@ -380,7 +387,7 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library, rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data, data_size, face_index, &face); if (rc) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, + ass_msg(library, MSGL_WARN, "Error opening memory font: %s", name); return; } @@ -390,24 +397,21 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library, FcFreeTypeQueryFace(face, (unsigned char *) name, 0, FcConfigGetBlanks(priv->config)); if (!pattern) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, - "FcFreeTypeQueryFace"); + ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace"); FT_Done_Face(face); return; } fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication if (!fset) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, - "FcConfigGetFonts"); + ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts"); FT_Done_Face(face); return; } res = FcFontSetAdd(fset, pattern); if (!res) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, - "FcFontSetAdd"); + ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd"); FT_Done_Face(face); return; } @@ -435,8 +439,8 @@ fc_instance_t *fontconfig_init(ass_library_t *library, int i; if (!fc) { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed); + ass_msg(library, MSGL_WARN, + "Fontconfig disabled, only default font will be used."); goto exit; } @@ -453,8 +457,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, } if (!rc || !priv->config) { - ass_msg(MSGL_FATAL, - MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed); + ass_msg(library, MSGL_FATAL, "%s failed", "FcInitLoadConfigAndFonts"); goto exit; } @@ -463,10 +466,10 @@ fc_instance_t *fontconfig_init(ass_library_t *library, if (dir) { if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) { - ass_msg(MSGL_INFO, MSGTR_LIBASS_UpdatingFontCache); + ass_msg(library, MSGL_INFO, "Updating font cache"); if (FcGetVersion() >= 20390 && FcGetVersion() < 20400) - ass_msg(MSGL_WARN, - MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported); + 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; @@ -475,8 +478,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, fss = FcStrSetCreate(); rc = FcStrSetAdd(fss, (const FcChar8 *) dir); if (!rc) { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_FcStrSetAddFailed); + ass_msg(library, MSGL_WARN, "%s failed", "FcStrSetAdd"); goto ErrorFontCache; } @@ -484,14 +486,13 @@ fc_instance_t *fontconfig_init(ass_library_t *library, FcConfigGetBlanks(priv->config), (const FcChar8 *) dir, FcFalse); if (!rc) { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_FcDirScanFailed); + ass_msg(library, MSGL_WARN, "%s failed", "FcDirScan"); goto ErrorFontCache; } rc = FcDirSave(fcs, fss, (const FcChar8 *) dir); if (!rc) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_FcDirSave); + ass_msg(library, MSGL_WARN, "%s failed", "FcDirSave"); goto ErrorFontCache; } ErrorFontCache: @@ -501,8 +502,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); if (!rc) { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_FcConfigAppFontAddDirFailed); + ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir"); } } @@ -530,8 +530,8 @@ fc_instance_t *fontconfig_init(ass_library_t *library, { fc_instance_t *priv; - ass_msg(MSGL_WARN, - MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed); + ass_msg(library, MSGL_WARN, + "Fontconfig disabled, only default font will be used."); priv = calloc(1, sizeof(fc_instance_t)); diff --git a/aegisub/libass/ass_fontconfig.h b/aegisub/libass/ass_fontconfig.h index 71b2006b0..53441cce6 100644 --- a/aegisub/libass/ass_fontconfig.h +++ b/aegisub/libass/ass_fontconfig.h @@ -35,9 +35,10 @@ typedef struct fc_instance_s fc_instance_t; fc_instance_t *fontconfig_init(ass_library_t *library, FT_Library ftlibrary, const char *family, const char *path, int fc, const char *config); -char *fontconfig_select(fc_instance_t *priv, const char *family, - int treat_family_as_pattern, unsigned bold, - unsigned italic, int *index, uint32_t code); +char *fontconfig_select(ass_library_t *library, fc_instance_t *priv, + const char *family, int treat_family_as_pattern, + unsigned bold, unsigned italic, int *index, + uint32_t code); void fontconfig_done(fc_instance_t *priv); #endif /* LIBASS_FONTCONFIG_H */ diff --git a/aegisub/libass/ass_library.c b/aegisub/libass/ass_library.c index ce877da7e..f464af7aa 100644 --- a/aegisub/libass/ass_library.c +++ b/aegisub/libass/ass_library.c @@ -22,14 +22,27 @@ #include #include #include +#include #include "ass.h" #include "ass_library.h" +#include "ass_utils.h" +static void ass_msg_handler(int level, char *fmt, va_list *va, void *data) +{ + if (level > MSGL_INFO) + return; + fprintf(stderr, "[ass] "); + vfprintf(stderr, fmt, *va); + fprintf(stderr, "\n"); +} ass_library_t *ass_library_init(void) { - return calloc(1, sizeof(ass_library_t)); + ass_library_t* lib = calloc(1, sizeof(ass_library_t)); + lib->msg_callback = ass_msg_handler; + + return lib; } void ass_library_done(ass_library_t *priv) @@ -114,3 +127,22 @@ void ass_clear_fonts(ass_library_t *priv) priv->fontdata = NULL; priv->num_fontdata = 0; } + +/* + * Register a message callback function with libass. Without setting one, + * a default handler is used which prints everything with MSGL_INFO or + * higher to the standard output. + * + * \param msg_cb the callback function + * \param data additional data that will be passed to the callback + */ +void ass_set_message_cb(ass_library_t *priv, + void (*msg_cb)(int, char *, va_list *, void *), + void *data) +{ + if (msg_cb) { + priv->msg_callback = msg_cb; + priv->msg_callback_data = data; + } +} + diff --git a/aegisub/libass/ass_library.h b/aegisub/libass/ass_library.h index 48ffefe8b..85b0842db 100644 --- a/aegisub/libass/ass_library.h +++ b/aegisub/libass/ass_library.h @@ -21,6 +21,8 @@ #ifndef LIBASS_LIBRARY_H #define LIBASS_LIBRARY_H +#include + typedef struct ass_fontdata_s { char *name; char *data; @@ -34,6 +36,8 @@ struct ass_library_s { ass_fontdata_t *fontdata; int num_fontdata; + void (*msg_callback)(int, char *, va_list *, void *); + void *msg_callback_data; }; #endif /* LIBASS_LIBRARY_H */ diff --git a/aegisub/libass/ass_render.c b/aegisub/libass/ass_render.c index e2eac7b4a..ae65119af 100644 --- a/aegisub/libass/ass_render.c +++ b/aegisub/libass/ass_render.c @@ -41,7 +41,7 @@ #define MAX_GLYPHS_INITIAL 1024 #define MAX_LINES_INITIAL 64 #define BLUR_MAX_RADIUS 100.0 -#define MAX_BE 100 +#define MAX_BE 127 #define SUBPIXEL_MASK 63 #define SUBPIXEL_ACCURACY 7 // d6 mask for subpixel accuracy adjustment @@ -245,8 +245,8 @@ static void ass_lazy_track_init(ass_renderer_t *render_priv) if (track->PlayResX && track->PlayResY) return; if (!track->PlayResX && !track->PlayResY) { - ass_msg(MSGL_WARN, - MSGTR_LIBASS_NeitherPlayResXNorPlayResYDefined); + ass_msg(render_priv->library, MSGL_WARN, + "Neither PlayResX nor PlayResY defined. Assuming 384x288"); track->PlayResX = 384; track->PlayResY = 288; } else { @@ -256,20 +256,20 @@ static void ass_lazy_track_init(ass_renderer_t *render_priv) render_priv->width; if (!track->PlayResY && track->PlayResX == 1280) { track->PlayResY = 1024; - ass_msg(MSGL_WARN, - MSGTR_LIBASS_PlayResYUndefinedSettingY, track->PlayResY); + ass_msg(render_priv->library, MSGL_WARN, + "PlayResY undefined, setting to %d", track->PlayResY); } else if (!track->PlayResY) { track->PlayResY = track->PlayResX / orig_aspect + .5; - ass_msg(MSGL_WARN, - MSGTR_LIBASS_PlayResYUndefinedSettingY, track->PlayResY); + ass_msg(render_priv->library, MSGL_WARN, + "PlayResY undefined, setting to %d", track->PlayResY); } else if (!track->PlayResX && track->PlayResY == 1024) { track->PlayResX = 1280; - ass_msg(MSGL_WARN, - MSGTR_LIBASS_PlayResXUndefinedSettingX, track->PlayResX); + ass_msg(render_priv->library, MSGL_WARN, + "PlayResX undefined, setting to %d", track->PlayResX); } else if (!track->PlayResX) { track->PlayResX = track->PlayResY * orig_aspect + .5; - ass_msg(MSGL_WARN, - MSGTR_LIBASS_PlayResXUndefinedSettingX, track->PlayResX); + ass_msg(render_priv->library, MSGL_WARN, + "PlayResX undefined, setting to %d", track->PlayResX); } } } @@ -283,14 +283,14 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library) error = FT_Init_FreeType(&ft); if (error) { - ass_msg(MSGL_FATAL, MSGTR_LIBASS_FT_Init_FreeTypeFailed); + ass_msg(library, MSGL_FATAL, "%s failed", "FT_Init_FreeType"); goto ass_init_exit; } FT_Library_Version(ft, &vmajor, &vminor, &vpatch); - ass_msg(MSGL_V, "FreeType library version: %d.%d.%d\n", + ass_msg(library, MSGL_V, "FreeType library version: %d.%d.%d", vmajor, vminor, vpatch); - ass_msg(MSGL_V, "FreeType headers version: %d.%d.%d\n", + ass_msg(library, MSGL_V, "FreeType headers version: %d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH); priv = calloc(1, sizeof(ass_renderer_t)); @@ -305,10 +305,10 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library) priv->ftlibrary = ft; // images_root and related stuff is zero-filled in calloc - priv->cache.font_cache = ass_font_cache_init(); - priv->cache.bitmap_cache = ass_bitmap_cache_init(); - priv->cache.composite_cache = ass_composite_cache_init(); - priv->cache.glyph_cache = ass_glyph_cache_init(); + priv->cache.font_cache = ass_font_cache_init(library); + priv->cache.bitmap_cache = ass_bitmap_cache_init(library); + priv->cache.composite_cache = ass_composite_cache_init(library); + priv->cache.glyph_cache = ass_glyph_cache_init(library); priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL; priv->text_info.max_lines = MAX_LINES_INITIAL; @@ -318,9 +318,9 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library) ass_init_exit: if (priv) - ass_msg(MSGL_INFO, MSGTR_LIBASS_Init); + ass_msg(library, MSGL_INFO, "Init"); else - ass_msg(MSGL_ERR, MSGTR_LIBASS_InitFailed); + ass_msg(library, MSGL_ERR, "Init failed"); return priv; } @@ -527,22 +527,22 @@ static ass_image_t **render_glyph(ass_renderer_t *render_priv, tmp = dst_x - clip_x0; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip left\n"); + ass_msg(render_priv->library, MSGL_DBG2, "clip left"); b_x0 = -tmp; } tmp = dst_y - clip_y0; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip top\n"); + ass_msg(render_priv->library, MSGL_DBG2, "clip top"); b_y0 = -tmp; } tmp = clip_x1 - dst_x - bm->w; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip right\n"); + ass_msg(render_priv->library, MSGL_DBG2, "clip right"); b_x1 = bm->w + tmp; } tmp = clip_y1 - dst_y - bm->h; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip bottom\n"); + ass_msg(render_priv->library, MSGL_DBG2, "clip bottom"); b_y1 = bm->h + tmp; } @@ -939,7 +939,8 @@ static void change_border(ass_renderer_t *render_priv, double border_x, memory, &render_priv->state.stroker); #endif if (error) { - ass_msg(MSGL_V, "failed to get stroker\n"); + ass_msg(render_priv->library, MSGL_V, + "failed to get stroker"); render_priv->state.stroker = 0; } } @@ -1172,15 +1173,15 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) mystrtoll(&p, &t1); skip(','); mystrtoll(&p, &t2); - ass_msg(MSGL_DBG2, + ass_msg(render_priv->library, MSGL_DBG2, "movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %" PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1, (int64_t) t2); } else { t1 = 0; t2 = render_priv->state.event->Duration; - ass_msg(MSGL_DBG2, - "movement: (%f, %f) -> (%f, %f)\n", x1, y1, x2, y2); + ass_msg(render_priv->library, MSGL_DBG2, + "movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2); } skip(')'); delta_t = t2 - t1; @@ -1241,7 +1242,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) } else if (mystrcmp(&p, "alpha")) { uint32_t val; int i; - if (strtocolor(&p, &val)) { + if (strtocolor(render_priv->library, &p, &val)) { unsigned char a = val >> 24; for (i = 0; i < 4; ++i) change_alpha(&render_priv->state.c[i], a, pwr); @@ -1260,12 +1261,12 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) int val; if (mystrtoi(&p, &val) && val) { int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment - ass_msg(MSGL_DBG2, "an %d\n", val); + ass_msg(render_priv->library, MSGL_DBG2, "an %d", val); if (v != 0) v = 3 - v; val = ((val - 1) % 3) + 1; // horizontal alignment val += v * 4; - ass_msg(MSGL_DBG2, "align %d\n", val); + ass_msg(render_priv->library, MSGL_DBG2, "align %d", val); render_priv->state.alignment = val; } else render_priv->state.alignment = @@ -1284,10 +1285,10 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) skip(','); mystrtod(&p, &v2); skip(')'); - ass_msg(MSGL_DBG2, "pos(%f, %f)\n", v1, v2); + ass_msg(render_priv->library, MSGL_DBG2, "pos(%f, %f)", v1, v2); if (render_priv->state.evt_type == EVENT_POSITIONED) { - ass_msg(MSGL_V, "Subtitle has a new \\pos " - "after \\move or \\pos, ignoring\n"); + ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos " + "after \\move or \\pos, ignoring"); } else { render_priv->state.evt_type = EVENT_POSITIONED; render_priv->state.detect_collisions = 0; @@ -1339,8 +1340,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) skip(','); mystrtoi(&p, &v2); skip(')'); - ass_msg(MSGL_DBG2, "org(%d, %d)\n", v1, v2); - // render_priv->state.evt_type = EVENT_POSITIONED; + ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2); if (!render_priv->state.have_origin) { render_priv->state.org_x = v1; render_priv->state.org_y = v2; @@ -1426,9 +1426,9 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) } } else if (mystrcmp(&p, "c")) { uint32_t val; - if (!strtocolor(&p, &val)) + if (!strtocolor(render_priv->library, &p, &val)) val = render_priv->state.style->PrimaryColour; - ass_msg(MSGL_DBG2, "color: %X\n", val); + ass_msg(render_priv->library, MSGL_DBG2, "color: %X", val); change_color(&render_priv->state.c[0], val, pwr); } else if ((*p >= '1') && (*p <= '4') && (++p) && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) { @@ -1437,7 +1437,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) char cmd = *(p - 1); uint32_t val; assert((n >= '1') && (n <= '4')); - if (!strtocolor(&p, &val)) + if (!strtocolor(render_priv->library, &p, &val)) switch (n) { case '1': val = render_priv->state.style->PrimaryColour; @@ -1463,10 +1463,11 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) change_alpha(render_priv->state.c + cidx, val >> 24, pwr); break; default: - ass_msg(MSGL_WARN, MSGTR_LIBASS_BadCommand, n, cmd); + ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c", + n, cmd); break; } - ass_msg(MSGL_DBG2, "single c/a at %f: %c%c = %X \n", + ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X", pwr, n, cmd, render_priv->state.c[cidx]); } else if (mystrcmp(&p, "r")) { reset_render_context(render_priv); @@ -1580,7 +1581,8 @@ static unsigned get_next_char(ass_renderer_t *render_priv, char **str) } else break; } else if (*p != '\\') - ass_msg(MSGL_V, "Unable to parse: \"%s\" \n", p); + ass_msg(render_priv->library, MSGL_V, + "Unable to parse: '%s'", p); if (*p == 0) break; } @@ -1626,8 +1628,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event) if (strncmp(event->Effect, "Banner;", 7) == 0) { int delay; if (cnt < 1) { - ass_msg(MSGL_V, "Error parsing effect: %s \n", - event->Effect); + ass_msg(render_priv->library, MSGL_V, + "Error parsing effect: '%s'", event->Effect); return; } if (cnt >= 2 && v[1] == 0) // right-to-left @@ -1649,8 +1651,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event) } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { render_priv->state.scroll_direction = SCROLL_TB; } else { - ass_msg(MSGL_V, "Unknown transition effect: %s \n", - event->Effect); + ass_msg(render_priv->library, MSGL_V, + "Unknown transition effect: '%s'", event->Effect); return; } // parse scroll up/down parameters @@ -1658,8 +1660,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event) int delay; int y0, y1; if (cnt < 3) { - ass_msg(MSGL_V, "Error parsing effect: %s \n", - event->Effect); + ass_msg(render_priv->library, MSGL_V, + "Error parsing effect: '%s'", event->Effect); return; } delay = v[2]; @@ -1865,7 +1867,8 @@ static void stroke_outline_glyph(ass_renderer_t *render_priv, error = FT_Glyph_StrokeBorder((FT_Glyph *) glyph, render_priv->state.stroker, 0, 1); if (error) - ass_msg(MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error); + ass_msg(render_priv->library, MSGL_WARN, + "FT_Glyph_Stroke error: %d", error); // "Stroke" with the outline emboldener in two passes. // The outlines look uglier, but the emboldening never adds any points @@ -2037,7 +2040,8 @@ get_bitmap_glyph(ass_renderer_t *render_priv, glyph_info_t *info) -info->hash_key.advance.y); // render glyph - error = glyph_to_bitmap(render_priv->synth_priv, + error = glyph_to_bitmap(render_priv->library, + render_priv->synth_priv, info->glyph, info->outline_glyph, &info->bm, &info->bm_o, &info->bm_s, info->be, @@ -2075,15 +2079,22 @@ static void measure_text(ass_renderer_t *render_priv) int cur_line = 0; double max_asc = 0., max_desc = 0.; int i; + int empty_line = 1; text_info->height = 0.; for (i = 0; i < text_info->length + 1; ++i) { if ((i == text_info->length) || text_info->glyphs[i].linebreak) { + if (empty_line && cur_line > 0) { + max_asc = text_info->lines[cur_line - 1].asc / 2.0; + max_desc = text_info->lines[cur_line - 1].desc / 2.0; + } text_info->lines[cur_line].asc = max_asc; text_info->lines[cur_line].desc = max_desc; text_info->height += max_asc + max_desc; cur_line++; max_asc = max_desc = 0.; - } + empty_line = 1; + } else + empty_line = 0; if (i < text_info->length) { glyph_info_t *cur = text_info->glyphs + i; if (d6_to_double(cur->asc) > max_asc) @@ -2134,8 +2145,8 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width) if (cur->symbol == '\n') { break_type = 2; break_at = i; - ass_msg(MSGL_DBG2, "forced line break at %d\n", - break_at); + ass_msg(render_priv->library, MSGL_DBG2, + "forced line break at %d", break_at); } if ((len >= max_text_width) @@ -2146,8 +2157,9 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width) break_at = i - 1; if (break_at == -1) break_at = 0; - ass_msg(MSGL_DBG2, "overfill at %d\n", i); - ass_msg(MSGL_DBG2, "line break at %d\n", break_at); + ass_msg(render_priv->library, MSGL_DBG2, "overfill at %d", i); + ass_msg(render_priv->library, MSGL_DBG2, "line break at %d", + break_at); } if (break_at != -1) { @@ -2246,8 +2258,8 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width) cur_line++; pen_shift_x = d6_to_double(-cur->pos.x); pen_shift_y += height + render_priv->settings.line_spacing; - ass_msg(MSGL_DBG2, - "shifting from %d to %d by (%f, %f)\n", i, + ass_msg(render_priv->library, MSGL_DBG2, + "shifting from %d to %d by (%f, %f)", i, text_info->length - 1, pen_shift_x, pen_shift_y); } cur->pos.x += double_to_d6(pen_shift_x); @@ -2311,8 +2323,8 @@ static void process_karaoke_effects(ass_renderer_t *render_priv) dt /= (tm_end - tm_start); x = x_start + (x_end - x_start) * dt; } else { - ass_msg(MSGL_ERR, - MSGTR_LIBASS_UnknownEffectType_InternalError); + ass_msg(render_priv->library, MSGL_ERR, + "Unknown effect type"); continue; } @@ -2465,11 +2477,11 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, ass_drawing_t *drawing; if (event->Style >= render_priv->track->n_styles) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_NoStyleFound); + ass_msg(render_priv->library, MSGL_WARN, "No style found"); return 1; } if (!event->Text) { - ass_msg(MSGL_WARN, MSGTR_LIBASS_EmptyEvent); + ass_msg(render_priv->library, MSGL_WARN, "Empty event"); return 1; } @@ -2513,14 +2525,6 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, if (code == 0) break; - // Insert space between two forced breaks to create empty lines - // FIXME: should probably be done in wrap_lines_smart, - // this is a hack - if (previous == '\n' && code == '\n') { - code = ' '; - p -= 2; - } - if (text_info->length >= text_info->max_glyphs) { // Raise maximum number of glyphs text_info->max_glyphs *= 2; @@ -2769,8 +2773,8 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, } else { // subtitle double scr_y; if (valign != VALIGN_SUB) - ass_msg(MSGL_V, - "Invalid valign, supposing 0 (subtitle)\n"); + ass_msg(render_priv->library, MSGL_V, + "Invalid valign, supposing 0 (subtitle)"); scr_y = y2scr_sub(render_priv, render_priv->track->PlayResY - MarginV); @@ -2795,7 +2799,7 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, if (render_priv->state.evt_type == EVENT_POSITIONED) { double base_x = 0; double base_y = 0; - ass_msg(MSGL_DBG2, "positioned event at %f, %f\n", + ass_msg(render_priv->library, MSGL_DBG2, "positioned event at %f, %f", render_priv->state.pos_x, render_priv->state.pos_y); get_base_point(&bbox, alignment, &base_x, &base_y); device_x = @@ -3010,6 +3014,9 @@ static int ass_start_frame(ass_renderer_t *render_priv, ass_track_t *track, long long now) { + if (render_priv->library != track->library) + return 1; + ass_settings_t *settings_priv = &render_priv->settings; if (!render_priv->settings.frame_width @@ -3176,8 +3183,8 @@ fix_collisions(ass_renderer_t *render_priv, event_images_t *imgs, int cnt) s.a = priv->top; s.b = priv->top + priv->height; if (priv->height != imgs[i].height) { // no, it's not - ass_msg(MSGL_WARN, - MSGTR_LIBASS_EventHeightHasChanged); + ass_msg(render_priv->library, MSGL_WARN, + "Warning! Event height has changed"); priv->top = 0; priv->height = 0; } diff --git a/aegisub/libass/ass_utils.c b/aegisub/libass/ass_utils.c index 5f632684c..56ca0ef63 100644 --- a/aegisub/libass/ass_utils.c +++ b/aegisub/libass/ass_utils.c @@ -21,15 +21,17 @@ #include "config.h" #include +#include #include #include #include FT_GLYPH_H +#include "ass_library.h" +#include "ass.h" #include "ass_utils.h" int mystrtoi(char **p, int *res) { - // NOTE: base argument is ignored, but not used in libass anyway double temp_res; char *start = *p; temp_res = strtod(*p, p); @@ -72,7 +74,7 @@ int mystrtod(char **p, double *res) return 0; } -int strtocolor(char **q, uint32_t *res) +int strtocolor(ass_library_t *library, char **q, uint32_t *res) { uint32_t color = 0; int result; @@ -81,7 +83,7 @@ int strtocolor(char **q, uint32_t *res) if (*p == '&') ++p; else - ass_msg(MSGL_DBG2, "suspicious color format: \"%s\"\n", p); + ass_msg(library, MSGL_DBG2, "suspicious color format: \"%s\"\n", p); if (*p == 'H' || *p == 'h') { ++p; @@ -120,13 +122,11 @@ char parse_bool(char *str) return 0; } -void ass_msg(int lvl, char *fmt, ...) +void ass_msg(ass_library_t *priv, int lvl, char *fmt, ...) { va_list va; - if (lvl > MSGL_INFO) - return; va_start(va, fmt); - vprintf(fmt, va); + priv->msg_callback(lvl, fmt, &va, priv->msg_callback_data); va_end(va); } @@ -160,128 +160,10 @@ unsigned ass_utf8_get_char(char **str) return c; } -// gaussian blur -void ass_gauss_blur(unsigned char *buffer, - unsigned short *tmp2, - int width, int height, int stride, int *m2, int r, int mwidth) -{ - - int x, y; - - unsigned char *s = buffer; - unsigned short *t = tmp2 + 1; - for (y = 0; y < height; y++) { - memset(t - 1, 0, (width + 1) * sizeof(short)); - - for (x = 0; x < r; x++) { - const int src = s[x]; - if (src) { - register unsigned short *dstp = t + x - r; - int mx; - unsigned *m3 = (unsigned *) (m2 + src * mwidth); - for (mx = r - x; mx < mwidth; mx++) { - dstp[mx] += m3[mx]; - } - } - } - - for (; x < width - r; x++) { - const int src = s[x]; - if (src) { - register unsigned short *dstp = t + x - r; - int mx; - unsigned *m3 = (unsigned *) (m2 + src * mwidth); - for (mx = 0; mx < mwidth; mx++) { - dstp[mx] += m3[mx]; - } - } - } - - for (; x < width; x++) { - const int src = s[x]; - if (src) { - register unsigned short *dstp = t + x - r; - int mx; - const int x2 = r + width - x; - unsigned *m3 = (unsigned *) (m2 + src * mwidth); - for (mx = 0; mx < x2; mx++) { - dstp[mx] += m3[mx]; - } - } - } - - s += stride; - t += width + 1; - } - - t = tmp2; - for (x = 0; x < width; x++) { - for (y = 0; y < r; y++) { - unsigned short *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - register unsigned short *dstp = srcp - 1 + width + 1; - const int src2 = (src + 128) >> 8; - unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); - - int mx; - *srcp = 128; - for (mx = r - 1; mx < mwidth; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - for (; y < height - r; y++) { - unsigned short *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - register unsigned short *dstp = srcp - 1 - r * (width + 1); - const int src2 = (src + 128) >> 8; - unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); - - int mx; - *srcp = 128; - for (mx = 0; mx < mwidth; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - for (; y < height; y++) { - unsigned short *srcp = t + y * (width + 1) + 1; - int src = *srcp; - if (src) { - const int y2 = r + height - y; - register unsigned short *dstp = srcp - 1 - r * (width + 1); - const int src2 = (src + 128) >> 8; - unsigned *m3 = (unsigned *) (m2 + src2 * mwidth); - - int mx; - *srcp = 128; - for (mx = 0; mx < y2; mx++) { - *dstp += m3[mx]; - dstp += width + 1; - } - } - } - t++; - } - - t = tmp2; - s = buffer; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - s[x] = t[x] >> 8; - } - s += stride; - t += width + 1; - } -} - #ifdef CONFIG_ENCA -void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, - char *preferred_language, char *fallback) +void *ass_guess_buffer_cp(ass_library_t *library, unsigned char *buffer, + int buflen, char *preferred_language, + char *fallback) { const char **languages; size_t langcnt; @@ -291,11 +173,10 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, int i; languages = enca_get_languages(&langcnt); - ass_msg(MSGL_V, "ENCA supported languages: "); + ass_msg(library, MSGL_V, "ENCA supported languages"); for (i = 0; i < langcnt; i++) { - ass_msg(MSGL_V, "%s ", languages[i]); + ass_msg(library, MSGL_V, "lang %s", languages[i]); } - ass_msg(MSGL_V, "\n"); for (i = 0; i < langcnt; i++) { const char *tmp; @@ -307,7 +188,7 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV); if (tmp && encoding.charset != ENCA_CS_UNKNOWN) { detected_sub_cp = strdup(tmp); - ass_msg(MSGL_INFO, "ENCA detected charset: %s\n", tmp); + ass_msg(library, MSGL_INFO, "ENCA detected charset: %s", tmp); } enca_analyser_free(analyser); } @@ -316,8 +197,8 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, if (!detected_sub_cp) { detected_sub_cp = strdup(fallback); - ass_msg(MSGL_INFO, - "ENCA detection failed: fallback to %s\n", fallback); + ass_msg(library, MSGL_INFO, + "ENCA detection failed: fallback to %s", fallback); } return detected_sub_cp; diff --git a/aegisub/libass/ass_utils.h b/aegisub/libass/ass_utils.h index cb1fae7da..a906ca57a 100644 --- a/aegisub/libass/ass_utils.h +++ b/aegisub/libass/ass_utils.h @@ -32,7 +32,7 @@ #include #endif -#include "help_mp.h" +#include "ass.h" #define MSGL_FATAL 0 #define MSGL_ERR 1 @@ -48,15 +48,15 @@ int mystrtoi(char **p, int *res); int mystrtoll(char **p, long long *res); int mystrtou32(char **p, int base, uint32_t *res); int mystrtod(char **p, double *res); -int strtocolor(char **q, uint32_t *res); +int strtocolor(ass_library_t *library, char **q, uint32_t *res); char parse_bool(char *str); unsigned ass_utf8_get_char(char **str); -void ass_msg(int lvl, char *fmt, ...); -void ass_gauss_blur(unsigned char *buffer, unsigned short *tmp2, - int width, int height, int stride, int *m2, - int r, int mwidth); -void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, - char *preferred_language, char *fallback); +void ass_msg(ass_library_t *priv, int lvl, char *fmt, ...); +#ifdef CONFIG_ENCA +void *ass_guess_buffer_cp(ass_library_t *library, unsigned char *buffer, + int buflen, char *preferred_language, + char *fallback); +#endif static inline int d6_to_int(int x) {