Update libass to 94d4104 from http://greg.geekmind.org/viewgit/.

Originally committed to SVN as r3123.
This commit is contained in:
Amar Takhar 2009-07-13 22:43:25 +00:00
parent 9bc0d84862
commit d298d21e5d
18 changed files with 504 additions and 415 deletions

View file

@ -19,6 +19,3 @@ libass_aegisub_a_SOURCES = \
libass_aegisub_a_SOURCES += \ libass_aegisub_a_SOURCES += \
*.h *.h
EXTRA_DIST= \
ass_cache_template.c

View file

@ -182,25 +182,26 @@ static int lookup_style(ass_track_t *track, char *name)
return i; return i;
} }
i = track->default_style; i = track->default_style;
ass_msg(MSGL_WARN, MSGTR_LIBASS_NoStyleNamedXFoundUsingY, ass_msg(track->library, MSGL_WARN,
track, name, track->styles[i].Name); "[%p]: Warning: no style named '%s' found, using '%s'",
track, name, track->styles[i].Name);
return i; // use the first style 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; uint32_t tmp;
(void) strtocolor(&p, &tmp); (void) strtocolor(library, &p, &tmp);
return tmp; return tmp;
} }
static long long string2timecode(char *p) static long long string2timecode(ass_library_t *library, char *p)
{ {
unsigned h, m, s, ms; unsigned h, m, s, ms;
long long tm; long long tm;
int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms); int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms);
if (res < 4) { if (res < 4) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_BadTimestamp); ass_msg(library, MSGL_WARN, "Bad timestamp");
return 0; return 0;
} }
tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10;
@ -228,22 +229,30 @@ static int numpad2align(int val)
#define ANYVAL(name,func) \ #define ANYVAL(name,func) \
} else if (strcasecmp(tname, #name) == 0) { \ } else if (strcasecmp(tname, #name) == 0) { \
target->name = func(token); \ 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) \ #define STRVAL(name) \
} else if (strcasecmp(tname, #name) == 0) { \ } else if (strcasecmp(tname, #name) == 0) { \
if (target->name != NULL) free(target->name); \ if (target->name != NULL) free(target->name); \
target->name = strdup(token); \ 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 INTVAL(name) ANYVAL(name,atoi)
#define FPVAL(name) ANYVAL(name,atof) #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) \ #define STYLEVAL(name) \
} else if (strcasecmp(tname, #name) == 0) { \ } else if (strcasecmp(tname, #name) == 0) { \
target->name = lookup_style(track, token); \ 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) \ #define ALIAS(alias,name) \
if (strcasecmp(tname, #alias) == 0) {tname = #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') if (last >= event->Text && *last == '\r')
*last = 0; *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; event->Duration -= event->Start;
free(format); free(format);
return 0; // "Text" is always the last 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); 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); sid = ass_alloc_style(track);
@ -534,7 +543,7 @@ static int process_styles_line(ass_track_t *track, char *str)
char *p = str + 7; char *p = str + 7;
skip_spaces(&p); skip_spaces(&p);
track->style_format = strdup(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); track->style_format);
} else if (!strncmp(str, "Style:", 6)) { } else if (!strncmp(str, "Style:", 6)) {
char *p = str + 6; char *p = str + 6;
@ -564,14 +573,13 @@ static void event_format_fallback(ass_track_t *track)
{ {
track->parser_priv->state = PST_EVENTS; track->parser_priv->state = PST_EVENTS;
if (track->track_type == TRACK_TYPE_SSA) if (track->track_type == TRACK_TYPE_SSA)
track->event_format = track->event_format = strdup("Format: Marked, Start, End, Style, "
strdup "Name, MarginL, MarginR, MarginV, Effect, Text");
("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text");
else else
track->event_format = track->event_format = strdup("Format: Layer, Start, End, Style, "
strdup "Actor, MarginL, MarginR, MarginV, Effect, Text");
("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text"); ass_msg(track->library, MSGL_V,
ass_msg(MSGL_V, "No event format found, using fallback.\n"); "No event format found, using fallback");
} }
static int process_events_line(ass_track_t *track, char *str) 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; char *p = str + 7;
skip_spaces(&p); skip_spaces(&p);
track->event_format = strdup(p); track->event_format = strdup(p);
ass_msg(MSGL_DBG2, "Event format: %s\n", ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format);
track->event_format);
} else if (!strncmp(str, "Dialogue:", 9)) { } else if (!strncmp(str, "Dialogue:", 9)) {
// This should never be reached for embedded subtitles. // This should never be reached for embedded subtitles.
// They have slightly different format and are parsed in ass_process_chunk, // 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); process_event_tail(track, event, str, 0);
} else { } else {
ass_msg(MSGL_V, "Not understood: %s \n", str); ass_msg(track->library, MSGL_V, "Not understood: '%s'", str);
} }
return 0; return 0;
} }
@ -636,11 +643,11 @@ static int decode_font(ass_track_t *track)
int dsize; // decoded size int dsize; // decoded size
unsigned char *buf = 0; unsigned char *buf = 0;
ass_msg(MSGL_V, "font: %d bytes encoded data \n", ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data",
track->parser_priv->fontdata_used); track->parser_priv->fontdata_used);
size = track->parser_priv->fontdata_used; size = track->parser_priv->fontdata_used;
if (size % 4 == 1) { 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; goto error_decode_font;
} }
buf = malloc(size / 4 * 3 + 2); buf = malloc(size / 4 * 3 + 2);
@ -686,19 +693,20 @@ static int process_fonts_line(ass_track_t *track, char *str)
decode_font(track); decode_font(track);
} }
track->parser_priv->fontname = strdup(p); 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); track->parser_priv->fontname);
return 0; return 0;
} }
if (!track->parser_priv->fontname) { 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; return 0;
} }
len = strlen(str); len = strlen(str);
if (len > 80) { 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; return 0;
} }
if (track->parser_priv->fontdata_used + len > 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); memcpy(str, data, size);
str[size] = '\0'; str[size] = '\0';
ass_msg(MSGL_V, "event: %s\n", str); ass_msg(track->library, MSGL_V, "Event: %s", str);
process_text(track, str); process_text(track, str);
free(str); free(str);
} }
@ -852,14 +860,14 @@ void ass_process_chunk(ass_track_t *track, char *data, int size,
ass_event_t *event; ass_event_t *event;
if (!track->event_format) { if (!track->event_format) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_EventFormatHeaderMissing); ass_msg(track->library, MSGL_WARN, "Event format header missing");
return; return;
} }
str = malloc(size + 1); str = malloc(size + 1);
memcpy(str, data, size); memcpy(str, data, size);
str[size] = '\0'; 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); (int64_t) timecode, (int64_t) duration, str);
eid = ass_alloc_event(track); 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 * \param size buffer size
* \return a pointer to recoded buffer, caller is responsible for freeing it * \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; iconv_t icdsc;
char *tocp = "UTF-8"; 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, || sscanf(codepage, "ENCA:%2s:%99s", enca_lang,
enca_fallback) == 2) { enca_fallback) == 2) {
cp_tmp = cp_tmp =
ass_guess_buffer_cp((unsigned char *) data, size, enca_lang, ass_guess_buffer_cp(library, (unsigned char *) data, size,
enca_fallback); enca_lang, enca_fallback);
} }
#endif #endif
if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) { 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 } else
ass_msg(MSGL_ERR, ass_msg(library, MSGL_ERR, "Error opening iconv descriptor");
MSGTR_LIBASS_ErrorOpeningIconvDescriptor);
} }
{ {
@ -952,8 +960,7 @@ static char *sub_recode(char *data, size_t size, char *codepage)
osize += size; osize += size;
oleft += size; oleft += size;
} else { } else {
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN, "Error recoding file");
MSGTR_LIBASS_ErrorRecodingFile);
return NULL; return NULL;
} }
} else if (clear) } else if (clear)
@ -965,7 +972,7 @@ static char *sub_recode(char *data, size_t size, char *codepage)
if (icdsc != (iconv_t) (-1)) { if (icdsc != (iconv_t) (-1)) {
(void) iconv_close(icdsc); (void) iconv_close(icdsc);
icdsc = (iconv_t) (-1); icdsc = (iconv_t) (-1);
ass_msg(MSGL_V, "LIBSUB: closed iconv descriptor.\n"); ass_msg(library, MSGL_V, "Closed iconv descriptor");
} }
return outbuf; return outbuf;
@ -978,7 +985,7 @@ static char *sub_recode(char *data, size_t size, char *codepage)
* \param bufsize out: file size * \param bufsize out: file size
* \return pointer to file contents. Caller is responsible for its deallocation. * \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; int res;
long sz; long sz;
@ -987,12 +994,14 @@ static char *read_file(char *fname, size_t *bufsize)
FILE *fp = fopen(fname, "rb"); FILE *fp = fopen(fname, "rb");
if (!fp) { if (!fp) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname); ass_msg(library, MSGL_WARN,
"ass_read_file(%s): fopen failed", fname);
return 0; return 0;
} }
res = fseek(fp, 0, SEEK_END); res = fseek(fp, 0, SEEK_END);
if (res == -1) { 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); fclose(fp);
return 0; return 0;
} }
@ -1001,13 +1010,14 @@ static char *read_file(char *fname, size_t *bufsize)
rewind(fp); rewind(fp);
if (sz > 10 * 1024 * 1024) { if (sz > 10 * 1024 * 1024) {
ass_msg(MSGL_INFO, ass_msg(library, MSGL_INFO,
MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M, fname); "ass_read_file(%s): Refusing to load subtitles "
"larger than 10MiB", fname);
fclose(fp); fclose(fp);
return 0; return 0;
} }
ass_msg(MSGL_V, "file size: %ld\n", sz); ass_msg(library, MSGL_V, "File size: %ld", sz);
buf = malloc(sz + 1); buf = malloc(sz + 1);
assert(buf); assert(buf);
@ -1015,8 +1025,8 @@ static char *read_file(char *fname, size_t *bufsize)
do { do {
res = fread(buf + bytes_read, 1, sz - bytes_read, fp); res = fread(buf + bytes_read, 1, sz - bytes_read, fp);
if (res <= 0) { if (res <= 0) {
ass_msg(MSGL_INFO, MSGTR_LIBASS_ReadFailed, errno, ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno,
strerror(errno)); strerror(errno));
fclose(fp); fclose(fp);
free(buf); free(buf);
return 0; return 0;
@ -1081,7 +1091,7 @@ ass_track_t *ass_read_memory(ass_library_t *library, char *buf,
#ifdef CONFIG_ICONV #ifdef CONFIG_ICONV
if (codepage) if (codepage)
buf = sub_recode(buf, bufsize, codepage); buf = sub_recode(library, buf, bufsize, codepage);
if (!buf) if (!buf)
return 0; return 0;
else else
@ -1093,22 +1103,24 @@ ass_track_t *ass_read_memory(ass_library_t *library, char *buf,
if (!track) if (!track)
return 0; return 0;
ass_msg(MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileMemory, ass_msg(library, MSGL_INFO, "Added subtitle file: "
track->n_styles, track->n_events); "<memory> (%d styles, %d events)",
track->n_styles, track->n_events);
return track; 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; char *buf;
size_t bufsize; size_t bufsize;
buf = read_file(fname, &bufsize); buf = read_file(library, fname, &bufsize);
if (!buf) if (!buf)
return 0; return 0;
#ifdef CONFIG_ICONV #ifdef CONFIG_ICONV
if (codepage) { if (codepage) {
char *tmpbuf = sub_recode(buf, bufsize, codepage); char *tmpbuf = sub_recode(library, buf, bufsize, codepage);
free(buf); free(buf);
buf = tmpbuf; buf = tmpbuf;
} }
@ -1133,7 +1145,7 @@ ass_track_t *ass_read_file(ass_library_t *library, char *fname,
ass_track_t *track; ass_track_t *track;
size_t bufsize; size_t bufsize;
buf = read_file_recode(fname, codepage, &bufsize); buf = read_file_recode(library, fname, codepage, &bufsize);
if (!buf) if (!buf)
return 0; return 0;
track = parse_memory(library, buf); 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); track->name = strdup(fname);
ass_msg(MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileFname, fname, ass_msg(library, MSGL_INFO,
track->n_styles, track->n_events); "Added subtitle file: '%s' (%d styles, %d events)",
fname, track->n_styles, track->n_events);
// dump_events(forced_tid);
return track; return track;
} }
@ -1159,13 +1171,13 @@ int ass_read_styles(ass_track_t *track, char *fname, char *codepage)
parser_state_t old_state; parser_state_t old_state;
size_t sz; size_t sz;
buf = read_file(fname, &sz); buf = read_file(track->library, fname, &sz);
if (!buf) if (!buf)
return 1; return 1;
#ifdef CONFIG_ICONV #ifdef CONFIG_ICONV
if (codepage) { if (codepage) {
char *tmpbuf; char *tmpbuf;
tmpbuf = sub_recode(buf, sz, codepage); tmpbuf = sub_recode(track->library, buf, sz, codepage);
free(buf); free(buf);
buf = tmpbuf; buf = tmpbuf;
} }

View file

@ -22,6 +22,7 @@
#define LIBASS_ASS_H #define LIBASS_ASS_H
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
#include "ass_types.h" #include "ass_types.h"
/// Libass renderer object. Contents are private. /// 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_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 * \brief initialize the renderer
* \param priv library handle * \param priv library handle

View file

@ -165,7 +165,7 @@ static bitmap_t *copy_bitmap(const bitmap_t *src)
return dst; 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; FT_BBox bbox;
long long dx, dy; long long dx, dy;
@ -173,14 +173,15 @@ static int check_glyph_area(FT_Glyph glyph)
dx = bbox.xMax - bbox.xMin; dx = bbox.xMax - bbox.xMin;
dy = bbox.yMax - bbox.yMin; dy = bbox.yMax - bbox.yMin;
if (dx * dy > 8000000) { 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); (int) dx, (int) dy);
return 1; return 1;
} else } else
return 0; 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_BitmapGlyph bg;
FT_Bitmap *bit; FT_Bitmap *bit;
@ -191,11 +192,11 @@ static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
int i; int i;
int error; int error;
if (check_glyph_area(glyph)) if (check_glyph_area(library, glyph))
return 0; return 0;
error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0); error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
if (error) { if (error) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, ass_msg(library, MSGL_WARN, "FT_Glyph_To_Bitmap error %d",
error); error);
return 0; return 0;
} }
@ -203,7 +204,7 @@ static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
bg = (FT_BitmapGlyph) glyph; bg = (FT_BitmapGlyph) glyph;
bit = &(bg->bitmap); bit = &(bg->bitmap);
if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) { 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)); (int) (bit->pixel_mode));
FT_Done_Glyph(glyph); FT_Done_Glyph(glyph);
return 0; 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; unsigned char c_g, c_o;
c_g = g[x]; c_g = g[x];
c_o = o[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; s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
} }
g += bm_g->w; 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 * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel
* This blur is the same as the one employed by vsfilter. * 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, FT_Glyph glyph, FT_Glyph outline_glyph,
bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s, bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s,
int be, double blur_radius, FT_Vector shadow_offset) int be, double blur_radius, FT_Vector shadow_offset)
{ {
int bord = be ? (be / 4 + 1) : 0;
blur_radius *= 2; 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)) if (bord == 0 && (shadow_offset.x || shadow_offset.y))
bord = 1; bord = 1;
@ -366,43 +489,45 @@ int glyph_to_bitmap(ass_synth_priv_t *priv_blur,
*bm_g = *bm_o = *bm_s = 0; *bm_g = *bm_o = *bm_s = 0;
if (glyph) if (glyph)
*bm_g = glyph_to_bitmap_internal(glyph, bord); *bm_g = glyph_to_bitmap_internal(library, glyph, bord);
if (!*bm_g) if (!*bm_g)
return 1; return 1;
if (outline_glyph) { 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) { if (!*bm_o) {
ass_free_bitmap(*bm_g); ass_free_bitmap(*bm_g);
return 1; 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) { // Apply box blur (multiple passes, if requested)
while (be--) { while (be--) {
if (*bm_o) if (*bm_o)
be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h); be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h);
else else
be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h); 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 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) if (*bm_o)
*bm_s = fix_outline_and_shadow(*bm_g, *bm_o); *bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
else else

View file

@ -24,6 +24,8 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_GLYPH_H #include FT_GLYPH_H
#include "ass.h"
typedef struct ass_synth_priv_s ass_synth_priv_t; typedef struct ass_synth_priv_s ass_synth_priv_t;
ass_synth_priv_t *ass_synth_init(double); 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 bm_g out: pointer to the bitmap of glyph shadow is returned here
* \param be 1 = produces blurred bitmaps, 0 = normal bitmaps * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
*/ */
int glyph_to_bitmap(ass_synth_priv_t *priv_blur, FT_Glyph glyph, int glyph_to_bitmap(ass_library_t *library, ass_synth_priv_t *priv_blur,
FT_Glyph outline_glyph, bitmap_t **bm_g, FT_Glyph glyph, FT_Glyph outline_glyph,
bitmap_t **bm_o, bitmap_t **bm_s, int be, bitmap_t **bm_g, bitmap_t **bm_o, bitmap_t **bm_s,
double blur_radius, FT_Vector shadow_offset); int be, double blur_radius, FT_Vector shadow_offset);
void ass_free_bitmap(bitmap_t *bm); void ass_free_bitmap(bitmap_t *bm);

View file

@ -51,12 +51,14 @@ static void hashmap_item_dtor(void *key, size_t key_size, void *value,
free(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_item_dtor_t item_dtor,
hashmap_key_compare_t key_compare, hashmap_key_compare_t key_compare,
hashmap_hash_t hash) hashmap_hash_t hash)
{ {
hashmap_t *map = calloc(1, sizeof(hashmap_t)); hashmap_t *map = calloc(1, sizeof(hashmap_t));
map->library = library;
map->nbuckets = nbuckets; map->nbuckets = nbuckets;
map->key_size = key_size; map->key_size = key_size;
map->value_size = value_size; map->value_size = value_size;
@ -72,8 +74,9 @@ void hashmap_done(hashmap_t *map)
int i; int i;
// print stats // print stats
if (map->count > 0 || map->hit_count + map->miss_count > 0) if (map->count > 0 || map->hit_count + map->miss_count > 0)
ass_msg(MSGL_V, ass_msg(map->library, MSGL_V,
"cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n", "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->hit_count + map->miss_count, map->hit_count,
map->miss_count, map->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); 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; 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), sizeof(ass_font_t),
1000, 1000,
font_hash_dtor, font_compare, font_desc_hash); 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 // Create hash/compare functions for bitmap and glyph
#define CREATE_HASH_FUNCTIONS #define CREATE_HASH_FUNCTIONS
#include "ass_cache_template.c" #include "ass_cache_template.h"
#define CREATE_COMPARISON_FUNCTIONS #define CREATE_COMPARISON_FUNCTIONS
#include "ass_cache_template.c" #include "ass_cache_template.h"
//--------------------------------- //---------------------------------
// bitmap cache // bitmap cache
@ -234,10 +237,11 @@ bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache,
return hashmap_find(bitmap_cache, key); 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; 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), sizeof(bitmap_hash_val_t),
0xFFFF + 13, 0xFFFF + 13,
bitmap_hash_dtor, bitmap_compare, 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) hashmap_t *ass_bitmap_cache_reset(hashmap_t *bitmap_cache)
{ {
ass_library_t *lib = bitmap_cache->library;
ass_bitmap_cache_done(bitmap_cache); 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); 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; 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), sizeof(glyph_hash_val_t),
0xFFFF + 13, 0xFFFF + 13,
glyph_hash_dtor, glyph_compare, glyph_hash); 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) hashmap_t *ass_glyph_cache_reset(hashmap_t *glyph_cache)
{ {
ass_library_t *lib = glyph_cache->library;
ass_glyph_cache_done(glyph_cache); 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); 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; 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), sizeof(composite_hash_val_t),
0xFFFF + 13, 0xFFFF + 13,
composite_hash_dtor, composite_compare, 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) hashmap_t *ass_composite_cache_reset(hashmap_t *composite_cache)
{ {
ass_library_t *lib = composite_cache->library;
ass_composite_cache_done(composite_cache); ass_composite_cache_done(composite_cache);
return ass_composite_cache_init(); return ass_composite_cache_init(lib);
} }

View file

@ -49,9 +49,11 @@ typedef struct hashmap_s {
int hit_count; int hit_count;
int miss_count; int miss_count;
int count; int count;
ass_library_t *library;
} hashmap_t; } 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_item_dtor_t item_dtor,
hashmap_key_compare_t key_compare, hashmap_key_compare_t key_compare,
hashmap_hash_t hash); 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_insert(hashmap_t *map, void *key, void *value);
void *hashmap_find(hashmap_t *map, void *key); 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); 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_add(hashmap_t *, ass_font_t *font);
void ass_font_cache_done(hashmap_t *); void ass_font_cache_done(hashmap_t *);
// Create definitions for bitmap_hash_key and glyph_hash_key // Create definitions for bitmap_hash_key and glyph_hash_key
#define CREATE_STRUCT_DEFINITIONS #define CREATE_STRUCT_DEFINITIONS
#include "ass_cache_template.c" #include "ass_cache_template.h"
typedef struct bitmap_hash_val_s { typedef struct bitmap_hash_val_s {
bitmap_t *bm; // the actual bitmaps bitmap_t *bm; // the actual bitmaps
@ -74,7 +76,7 @@ typedef struct bitmap_hash_val_s {
bitmap_t *bm_s; bitmap_t *bm_s;
} bitmap_hash_val_t; } 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, void *cache_add_bitmap(hashmap_t *, bitmap_hash_key_t *key,
bitmap_hash_val_t *val); bitmap_hash_val_t *val);
bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache, bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache,
@ -88,7 +90,7 @@ typedef struct composite_hash_val_s {
unsigned char *b; unsigned char *b;
} composite_hash_val_t; } 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, void *cache_add_composite(hashmap_t *, composite_hash_key_t *key,
composite_hash_val_t *val); composite_hash_val_t *val);
composite_hash_val_t *cache_find_composite(hashmap_t *composite_cache, 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 int asc, desc; // ascender/descender of a drawing
} glyph_hash_val_t; } 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, void *cache_add_glyph(hashmap_t *, glyph_hash_key_t *key,
glyph_hash_val_t *val); glyph_hash_val_t *val);
glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache, glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache,

View file

@ -138,6 +138,10 @@ static void drawing_finish(ass_drawing_t *drawing)
drawing->scale_y); drawing->scale_y);
for (i = 0; i < ol->n_points; i++) for (i = 0; i < ol->n_points; i++)
ol->points[i].y += offset; 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->size = DRAWING_INITIAL_SIZE;
drawing->ftlibrary = lib; drawing->ftlibrary = lib;
drawing->library = font->library;
drawing_make_glyph(drawing, fontconfig_priv, font, hint); drawing_make_glyph(drawing, fontconfig_priv, font, hint);
drawing->scale_x = 1.; drawing->scale_x = 1.;

View file

@ -58,6 +58,7 @@ typedef struct ass_drawing_s {
// private // private
FT_Library ftlibrary; // FT library instance, needed for font ops FT_Library ftlibrary; // FT library instance, needed for font ops
ass_library_t *library;
int size; // current buffer size int size; // current buffer size
ass_drawing_token_t *tokens; // tokenized drawing ass_drawing_token_t *tokens; // tokenized drawing
int max_points; // current maximum size int max_points; // current maximum size

View file

@ -39,7 +39,7 @@
* Select Microfost Unicode CharMap, if the font has one. * Select Microfost Unicode CharMap, if the font has one.
* Otherwise, let FreeType decide. * Otherwise, let FreeType decide.
*/ */
static void charmap_magic(FT_Face face) static void charmap_magic(ass_library_t *library, FT_Face face)
{ {
int i; int i;
for (i = 0; i < face->num_charmaps; ++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->charmap) {
if (face->num_charmaps == 0) { if (face->num_charmaps == 0) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_NoCharmaps); ass_msg(library, MSGL_WARN, "Font face with no charmaps");
return; 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]); FT_Set_Charmap(face, face->charmaps[0]);
return; return;
} }
@ -125,7 +126,7 @@ static int add_face(void *fc_priv, ass_font_t *font, uint32_t ch)
return -1; return -1;
path = 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.treat_family_as_pattern,
font->desc.bold, font->desc.italic, &index, ch); font->desc.bold, font->desc.italic, &index, ch);
if (!path) 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, font->library->fontdata[mem_idx].size, 0,
&face); &face);
if (error) { if (error) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, ass_msg(font->library, MSGL_WARN,
path); "Error opening memory font: '%s'", path);
free(path); free(path);
return -1; return -1;
} }
} else { } else {
error = FT_New_Face(font->ftlibrary, path, index, &face); error = FT_New_Face(font->ftlibrary, path, index, &face);
if (error) { if (error) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, ass_msg(font->library, MSGL_WARN,
index); "Error opening font: '%s', %d", path, index);
free(path); free(path);
return -1; return -1;
} }
} }
charmap_magic(face); charmap_magic(font->library, face);
buggy_font_workaround(face); buggy_font_workaround(face);
font->faces[font->n_faces++] = 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 #ifdef CONFIG_FONTCONFIG
if (index == 0) { if (index == 0) {
int face_idx; int face_idx;
ass_msg(MSGL_INFO, ass_msg(font->library, MSGL_INFO,
MSGTR_LIBASS_GlyphNotFoundReselectingFont, ch, "Glyph 0x%X not found, selecting one more "
font->desc.family, font->desc.bold, font->desc.italic); "font for (%s, %d, %d)", ch, font->desc.family,
font->desc.bold, font->desc.italic);
face_idx = add_face(fontconfig_priv, font, ch); face_idx = add_face(fontconfig_priv, font, ch);
if (face_idx >= 0) { if (face_idx >= 0) {
face = font->faces[face_idx]; face = font->faces[face_idx];
index = FT_Get_Char_Index(face, ch); index = FT_Get_Char_Index(face, ch);
if (index == 0) { if (index == 0) {
ass_msg(MSGL_ERR, MSGTR_LIBASS_GlyphNotFound, ass_msg(font->library, MSGL_ERR,
ch, font->desc.family, font->desc.bold, "Glyph 0x%X not found in font for (%s, %d, %d)",
font->desc.italic); 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); error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
if (error) { if (error) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
index);
return 0; return 0;
} }
#if (FREETYPE_MAJOR > 2) || \ #if (FREETYPE_MAJOR > 2) || \
@ -433,7 +437,8 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font,
#endif #endif
error = FT_Get_Glyph(face->glyph, &glyph); error = FT_Get_Glyph(face->glyph, &glyph);
if (error) { if (error) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph); ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
index);
return 0; return 0;
} }

View file

@ -71,9 +71,10 @@ struct fc_instance_s {
* \param code: the character that should be present in the font, can be 0 * \param code: the character that should be present in the font, can be 0
* \return font file path * \return font file path
*/ */
static char *_select_font(fc_instance_t *priv, const char *family, static char *_select_font(ass_library_t *library, fc_instance_t *priv,
int treat_family_as_pattern, unsigned bold, const char *family, int treat_family_as_pattern,
unsigned italic, int *index, uint32_t code) unsigned bold, unsigned italic, int *index,
uint32_t code)
{ {
FcBool rc; FcBool rc;
FcResult result; FcResult result;
@ -193,8 +194,9 @@ static char *_select_font(fc_instance_t *priv, const char *family,
if (!treat_family_as_pattern && if (!treat_family_as_pattern &&
!(r_family && strcasecmp((const char *) r_family, family) == 0) && !(r_family && strcasecmp((const char *) r_family, family) == 0) &&
!(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0))
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN,
MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne, "fontconfig: Selected font is not the requested one: "
"'%s' != '%s'",
(const char *) (r_fullname ? r_fullname : r_family), family); (const char *) (r_fullname ? r_fullname : r_family), family);
result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style); 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) if (result != FcResultMatch)
r_embolden = 0; r_embolden = 0;
ass_msg(MSGL_V, ass_msg(library, MSGL_V,
"[ass] Font info: family '%s', style '%s', fullname '%s'," "Font info: family '%s', style '%s', fullname '%s',"
" slant %d, weight %d%s\n", (const char *) r_family, " slant %d, weight %d%s", (const char *) r_family,
(const char *) r_style, (const char *) r_fullname, r_slant, (const char *) r_style, (const char *) r_fullname, r_slant,
r_weight, r_embolden ? ", embolden" : ""); 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 * \param code: the character that should be present in the font, can be 0
* \return font file path * \return font file path
*/ */
char *fontconfig_select(fc_instance_t *priv, const char *family, char *fontconfig_select(ass_library_t *library, fc_instance_t *priv,
int treat_family_as_pattern, unsigned bold, const char *family, int treat_family_as_pattern,
unsigned italic, int *index, uint32_t code) unsigned bold, unsigned italic, int *index,
uint32_t code)
{ {
char *res = 0; char *res = 0;
if (!priv->config) { if (!priv->config) {
@ -251,32 +254,36 @@ char *fontconfig_select(fc_instance_t *priv, const char *family,
} }
if (family && *family) if (family && *family)
res = res =
_select_font(priv, family, treat_family_as_pattern, bold, _select_font(library, priv, family, treat_family_as_pattern,
italic, index, code); bold, italic, index, code);
if (!res && priv->family_default) { if (!res && priv->family_default) {
res = res =
_select_font(priv, priv->family_default, 0, bold, italic, index, _select_font(library, priv, priv->family_default, 0, bold,
code); italic, index, code);
if (res) if (res)
ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily, ass_msg(library, MSGL_WARN, "fontconfig_select: Using default "
family, bold, italic, res, *index); "font family: (%s, %d, %d) -> %s, %d",
family, bold, italic, res, *index);
} }
if (!res && priv->path_default) { if (!res && priv->path_default) {
res = priv->path_default; res = priv->path_default;
*index = priv->index_default; *index = priv->index_default;
ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingDefaultFont, ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: "
family, bold, italic, res, *index); "(%s, %d, %d) -> %s, %d", family, bold, italic,
res, *index);
} }
if (!res) { 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) if (res)
ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily, ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' "
family, bold, italic, res, *index); "font family: (%s, %d, %d) -> %s, %d", family, bold,
italic, res, *index);
} }
if (res) if (res)
ass_msg(MSGL_V, ass_msg(library, MSGL_V,
"fontconfig_select: (%s, %d, %d) -> %s, %d\n", family, bold, "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold,
italic, res, *index); italic, res, *index);
return res; return res;
} }
@ -350,11 +357,11 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library,
res = mkdir(fonts_dir); res = mkdir(fonts_dir);
#endif #endif
if (res) { if (res) {
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN, "Failed to create directory '%s'",
MSGTR_LIBASS_FailedToCreateDirectory, fonts_dir); fonts_dir);
} }
} else if (!S_ISDIR(st.st_mode)) { } 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); 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, rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data,
data_size, face_index, &face); data_size, face_index, &face);
if (rc) { if (rc) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, ass_msg(library, MSGL_WARN, "Error opening memory font: %s",
name); name);
return; return;
} }
@ -390,24 +397,21 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library,
FcFreeTypeQueryFace(face, (unsigned char *) name, 0, FcFreeTypeQueryFace(face, (unsigned char *) name, 0,
FcConfigGetBlanks(priv->config)); FcConfigGetBlanks(priv->config));
if (!pattern) { if (!pattern) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace");
"FcFreeTypeQueryFace");
FT_Done_Face(face); FT_Done_Face(face);
return; return;
} }
fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication
if (!fset) { if (!fset) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts");
"FcConfigGetFonts");
FT_Done_Face(face); FT_Done_Face(face);
return; return;
} }
res = FcFontSetAdd(fset, pattern); res = FcFontSetAdd(fset, pattern);
if (!res) { if (!res) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd");
"FcFontSetAdd");
FT_Done_Face(face); FT_Done_Face(face);
return; return;
} }
@ -435,8 +439,8 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
int i; int i;
if (!fc) { if (!fc) {
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN,
MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed); "Fontconfig disabled, only default font will be used.");
goto exit; goto exit;
} }
@ -453,8 +457,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
} }
if (!rc || !priv->config) { if (!rc || !priv->config) {
ass_msg(MSGL_FATAL, ass_msg(library, MSGL_FATAL, "%s failed", "FcInitLoadConfigAndFonts");
MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed);
goto exit; goto exit;
} }
@ -463,10 +466,10 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
if (dir) { if (dir) {
if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) { 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) if (FcGetVersion() >= 20390 && FcGetVersion() < 20400)
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN, "Beta versions of fontconfig"
MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported); "are not supported. Update before reporting any bugs");
// FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir() // FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir()
if (FcGetVersion() < 20390) { if (FcGetVersion() < 20390) {
FcFontSet *fcs; FcFontSet *fcs;
@ -475,8 +478,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
fss = FcStrSetCreate(); fss = FcStrSetCreate();
rc = FcStrSetAdd(fss, (const FcChar8 *) dir); rc = FcStrSetAdd(fss, (const FcChar8 *) dir);
if (!rc) { if (!rc) {
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN, "%s failed", "FcStrSetAdd");
MSGTR_LIBASS_FcStrSetAddFailed);
goto ErrorFontCache; goto ErrorFontCache;
} }
@ -484,14 +486,13 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
FcConfigGetBlanks(priv->config), FcConfigGetBlanks(priv->config),
(const FcChar8 *) dir, FcFalse); (const FcChar8 *) dir, FcFalse);
if (!rc) { if (!rc) {
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN, "%s failed", "FcDirScan");
MSGTR_LIBASS_FcDirScanFailed);
goto ErrorFontCache; goto ErrorFontCache;
} }
rc = FcDirSave(fcs, fss, (const FcChar8 *) dir); rc = FcDirSave(fcs, fss, (const FcChar8 *) dir);
if (!rc) { if (!rc) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_FcDirSave); ass_msg(library, MSGL_WARN, "%s failed", "FcDirSave");
goto ErrorFontCache; goto ErrorFontCache;
} }
ErrorFontCache: ErrorFontCache:
@ -501,8 +502,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
if (!rc) { if (!rc) {
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir");
MSGTR_LIBASS_FcConfigAppFontAddDirFailed);
} }
} }
@ -530,8 +530,8 @@ fc_instance_t *fontconfig_init(ass_library_t *library,
{ {
fc_instance_t *priv; fc_instance_t *priv;
ass_msg(MSGL_WARN, ass_msg(library, MSGL_WARN,
MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed); "Fontconfig disabled, only default font will be used.");
priv = calloc(1, sizeof(fc_instance_t)); priv = calloc(1, sizeof(fc_instance_t));

View file

@ -35,9 +35,10 @@ typedef struct fc_instance_s fc_instance_t;
fc_instance_t *fontconfig_init(ass_library_t *library, fc_instance_t *fontconfig_init(ass_library_t *library,
FT_Library ftlibrary, const char *family, FT_Library ftlibrary, const char *family,
const char *path, int fc, const char *config); const char *path, int fc, const char *config);
char *fontconfig_select(fc_instance_t *priv, const char *family, char *fontconfig_select(ass_library_t *library, fc_instance_t *priv,
int treat_family_as_pattern, unsigned bold, const char *family, int treat_family_as_pattern,
unsigned italic, int *index, uint32_t code); unsigned bold, unsigned italic, int *index,
uint32_t code);
void fontconfig_done(fc_instance_t *priv); void fontconfig_done(fc_instance_t *priv);
#endif /* LIBASS_FONTCONFIG_H */ #endif /* LIBASS_FONTCONFIG_H */

View file

@ -22,14 +22,27 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include "ass.h" #include "ass.h"
#include "ass_library.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) 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) void ass_library_done(ass_library_t *priv)
@ -114,3 +127,22 @@ void ass_clear_fonts(ass_library_t *priv)
priv->fontdata = NULL; priv->fontdata = NULL;
priv->num_fontdata = 0; 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;
}
}

View file

@ -21,6 +21,8 @@
#ifndef LIBASS_LIBRARY_H #ifndef LIBASS_LIBRARY_H
#define LIBASS_LIBRARY_H #define LIBASS_LIBRARY_H
#include <stdarg.h>
typedef struct ass_fontdata_s { typedef struct ass_fontdata_s {
char *name; char *name;
char *data; char *data;
@ -34,6 +36,8 @@ struct ass_library_s {
ass_fontdata_t *fontdata; ass_fontdata_t *fontdata;
int num_fontdata; int num_fontdata;
void (*msg_callback)(int, char *, va_list *, void *);
void *msg_callback_data;
}; };
#endif /* LIBASS_LIBRARY_H */ #endif /* LIBASS_LIBRARY_H */

View file

@ -41,7 +41,7 @@
#define MAX_GLYPHS_INITIAL 1024 #define MAX_GLYPHS_INITIAL 1024
#define MAX_LINES_INITIAL 64 #define MAX_LINES_INITIAL 64
#define BLUR_MAX_RADIUS 100.0 #define BLUR_MAX_RADIUS 100.0
#define MAX_BE 100 #define MAX_BE 127
#define SUBPIXEL_MASK 63 #define SUBPIXEL_MASK 63
#define SUBPIXEL_ACCURACY 7 // d6 mask for subpixel accuracy adjustment #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) if (track->PlayResX && track->PlayResY)
return; return;
if (!track->PlayResX && !track->PlayResY) { if (!track->PlayResX && !track->PlayResY) {
ass_msg(MSGL_WARN, ass_msg(render_priv->library, MSGL_WARN,
MSGTR_LIBASS_NeitherPlayResXNorPlayResYDefined); "Neither PlayResX nor PlayResY defined. Assuming 384x288");
track->PlayResX = 384; track->PlayResX = 384;
track->PlayResY = 288; track->PlayResY = 288;
} else { } else {
@ -256,20 +256,20 @@ static void ass_lazy_track_init(ass_renderer_t *render_priv)
render_priv->width; render_priv->width;
if (!track->PlayResY && track->PlayResX == 1280) { if (!track->PlayResY && track->PlayResX == 1280) {
track->PlayResY = 1024; track->PlayResY = 1024;
ass_msg(MSGL_WARN, ass_msg(render_priv->library, MSGL_WARN,
MSGTR_LIBASS_PlayResYUndefinedSettingY, track->PlayResY); "PlayResY undefined, setting to %d", track->PlayResY);
} else if (!track->PlayResY) { } else if (!track->PlayResY) {
track->PlayResY = track->PlayResX / orig_aspect + .5; track->PlayResY = track->PlayResX / orig_aspect + .5;
ass_msg(MSGL_WARN, ass_msg(render_priv->library, MSGL_WARN,
MSGTR_LIBASS_PlayResYUndefinedSettingY, track->PlayResY); "PlayResY undefined, setting to %d", track->PlayResY);
} else if (!track->PlayResX && track->PlayResY == 1024) { } else if (!track->PlayResX && track->PlayResY == 1024) {
track->PlayResX = 1280; track->PlayResX = 1280;
ass_msg(MSGL_WARN, ass_msg(render_priv->library, MSGL_WARN,
MSGTR_LIBASS_PlayResXUndefinedSettingX, track->PlayResX); "PlayResX undefined, setting to %d", track->PlayResX);
} else if (!track->PlayResX) { } else if (!track->PlayResX) {
track->PlayResX = track->PlayResY * orig_aspect + .5; track->PlayResX = track->PlayResY * orig_aspect + .5;
ass_msg(MSGL_WARN, ass_msg(render_priv->library, MSGL_WARN,
MSGTR_LIBASS_PlayResXUndefinedSettingX, track->PlayResX); "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); error = FT_Init_FreeType(&ft);
if (error) { 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; goto ass_init_exit;
} }
FT_Library_Version(ft, &vmajor, &vminor, &vpatch); 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); 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); FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
priv = calloc(1, sizeof(ass_renderer_t)); priv = calloc(1, sizeof(ass_renderer_t));
@ -305,10 +305,10 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library)
priv->ftlibrary = ft; priv->ftlibrary = ft;
// images_root and related stuff is zero-filled in calloc // images_root and related stuff is zero-filled in calloc
priv->cache.font_cache = ass_font_cache_init(); priv->cache.font_cache = ass_font_cache_init(library);
priv->cache.bitmap_cache = ass_bitmap_cache_init(); priv->cache.bitmap_cache = ass_bitmap_cache_init(library);
priv->cache.composite_cache = ass_composite_cache_init(); priv->cache.composite_cache = ass_composite_cache_init(library);
priv->cache.glyph_cache = ass_glyph_cache_init(); priv->cache.glyph_cache = ass_glyph_cache_init(library);
priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL; priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL;
priv->text_info.max_lines = MAX_LINES_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: ass_init_exit:
if (priv) if (priv)
ass_msg(MSGL_INFO, MSGTR_LIBASS_Init); ass_msg(library, MSGL_INFO, "Init");
else else
ass_msg(MSGL_ERR, MSGTR_LIBASS_InitFailed); ass_msg(library, MSGL_ERR, "Init failed");
return priv; return priv;
} }
@ -527,22 +527,22 @@ static ass_image_t **render_glyph(ass_renderer_t *render_priv,
tmp = dst_x - clip_x0; tmp = dst_x - clip_x0;
if (tmp < 0) { if (tmp < 0) {
ass_msg(MSGL_DBG2, "clip left\n"); ass_msg(render_priv->library, MSGL_DBG2, "clip left");
b_x0 = -tmp; b_x0 = -tmp;
} }
tmp = dst_y - clip_y0; tmp = dst_y - clip_y0;
if (tmp < 0) { if (tmp < 0) {
ass_msg(MSGL_DBG2, "clip top\n"); ass_msg(render_priv->library, MSGL_DBG2, "clip top");
b_y0 = -tmp; b_y0 = -tmp;
} }
tmp = clip_x1 - dst_x - bm->w; tmp = clip_x1 - dst_x - bm->w;
if (tmp < 0) { if (tmp < 0) {
ass_msg(MSGL_DBG2, "clip right\n"); ass_msg(render_priv->library, MSGL_DBG2, "clip right");
b_x1 = bm->w + tmp; b_x1 = bm->w + tmp;
} }
tmp = clip_y1 - dst_y - bm->h; tmp = clip_y1 - dst_y - bm->h;
if (tmp < 0) { if (tmp < 0) {
ass_msg(MSGL_DBG2, "clip bottom\n"); ass_msg(render_priv->library, MSGL_DBG2, "clip bottom");
b_y1 = bm->h + tmp; 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); memory, &render_priv->state.stroker);
#endif #endif
if (error) { 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; 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); mystrtoll(&p, &t1);
skip(','); skip(',');
mystrtoll(&p, &t2); mystrtoll(&p, &t2);
ass_msg(MSGL_DBG2, ass_msg(render_priv->library, MSGL_DBG2,
"movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %" "movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %"
PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1, PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1,
(int64_t) t2); (int64_t) t2);
} else { } else {
t1 = 0; t1 = 0;
t2 = render_priv->state.event->Duration; t2 = render_priv->state.event->Duration;
ass_msg(MSGL_DBG2, ass_msg(render_priv->library, MSGL_DBG2,
"movement: (%f, %f) -> (%f, %f)\n", x1, y1, x2, y2); "movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2);
} }
skip(')'); skip(')');
delta_t = t2 - t1; 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")) { } else if (mystrcmp(&p, "alpha")) {
uint32_t val; uint32_t val;
int i; int i;
if (strtocolor(&p, &val)) { if (strtocolor(render_priv->library, &p, &val)) {
unsigned char a = val >> 24; unsigned char a = val >> 24;
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
change_alpha(&render_priv->state.c[i], a, pwr); 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; int val;
if (mystrtoi(&p, &val) && val) { if (mystrtoi(&p, &val) && val) {
int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment 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) if (v != 0)
v = 3 - v; v = 3 - v;
val = ((val - 1) % 3) + 1; // horizontal alignment val = ((val - 1) % 3) + 1; // horizontal alignment
val += v * 4; 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; render_priv->state.alignment = val;
} else } else
render_priv->state.alignment = render_priv->state.alignment =
@ -1284,10 +1285,10 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr)
skip(','); skip(',');
mystrtod(&p, &v2); mystrtod(&p, &v2);
skip(')'); 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) { if (render_priv->state.evt_type == EVENT_POSITIONED) {
ass_msg(MSGL_V, "Subtitle has a new \\pos " ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos "
"after \\move or \\pos, ignoring\n"); "after \\move or \\pos, ignoring");
} else { } else {
render_priv->state.evt_type = EVENT_POSITIONED; render_priv->state.evt_type = EVENT_POSITIONED;
render_priv->state.detect_collisions = 0; render_priv->state.detect_collisions = 0;
@ -1339,8 +1340,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr)
skip(','); skip(',');
mystrtoi(&p, &v2); mystrtoi(&p, &v2);
skip(')'); skip(')');
ass_msg(MSGL_DBG2, "org(%d, %d)\n", v1, v2); ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2);
// render_priv->state.evt_type = EVENT_POSITIONED;
if (!render_priv->state.have_origin) { if (!render_priv->state.have_origin) {
render_priv->state.org_x = v1; render_priv->state.org_x = v1;
render_priv->state.org_y = v2; 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")) { } else if (mystrcmp(&p, "c")) {
uint32_t val; uint32_t val;
if (!strtocolor(&p, &val)) if (!strtocolor(render_priv->library, &p, &val))
val = render_priv->state.style->PrimaryColour; 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); change_color(&render_priv->state.c[0], val, pwr);
} else if ((*p >= '1') && (*p <= '4') && (++p) } else if ((*p >= '1') && (*p <= '4') && (++p)
&& (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) { && (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); char cmd = *(p - 1);
uint32_t val; uint32_t val;
assert((n >= '1') && (n <= '4')); assert((n >= '1') && (n <= '4'));
if (!strtocolor(&p, &val)) if (!strtocolor(render_priv->library, &p, &val))
switch (n) { switch (n) {
case '1': case '1':
val = render_priv->state.style->PrimaryColour; 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); change_alpha(render_priv->state.c + cidx, val >> 24, pwr);
break; break;
default: default:
ass_msg(MSGL_WARN, MSGTR_LIBASS_BadCommand, n, cmd); ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c",
n, cmd);
break; 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]); pwr, n, cmd, render_priv->state.c[cidx]);
} else if (mystrcmp(&p, "r")) { } else if (mystrcmp(&p, "r")) {
reset_render_context(render_priv); reset_render_context(render_priv);
@ -1580,7 +1581,8 @@ static unsigned get_next_char(ass_renderer_t *render_priv, char **str)
} else } else
break; break;
} else if (*p != '\\') } 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) if (*p == 0)
break; break;
} }
@ -1626,8 +1628,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event)
if (strncmp(event->Effect, "Banner;", 7) == 0) { if (strncmp(event->Effect, "Banner;", 7) == 0) {
int delay; int delay;
if (cnt < 1) { if (cnt < 1) {
ass_msg(MSGL_V, "Error parsing effect: %s \n", ass_msg(render_priv->library, MSGL_V,
event->Effect); "Error parsing effect: '%s'", event->Effect);
return; return;
} }
if (cnt >= 2 && v[1] == 0) // right-to-left 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) { } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
render_priv->state.scroll_direction = SCROLL_TB; render_priv->state.scroll_direction = SCROLL_TB;
} else { } else {
ass_msg(MSGL_V, "Unknown transition effect: %s \n", ass_msg(render_priv->library, MSGL_V,
event->Effect); "Unknown transition effect: '%s'", event->Effect);
return; return;
} }
// parse scroll up/down parameters // parse scroll up/down parameters
@ -1658,8 +1660,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event)
int delay; int delay;
int y0, y1; int y0, y1;
if (cnt < 3) { if (cnt < 3) {
ass_msg(MSGL_V, "Error parsing effect: %s \n", ass_msg(render_priv->library, MSGL_V,
event->Effect); "Error parsing effect: '%s'", event->Effect);
return; return;
} }
delay = v[2]; delay = v[2];
@ -1865,7 +1867,8 @@ static void stroke_outline_glyph(ass_renderer_t *render_priv,
error = FT_Glyph_StrokeBorder((FT_Glyph *) glyph, error = FT_Glyph_StrokeBorder((FT_Glyph *) glyph,
render_priv->state.stroker, 0, 1); render_priv->state.stroker, 0, 1);
if (error) 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. // "Stroke" with the outline emboldener in two passes.
// The outlines look uglier, but the emboldening never adds any points // 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); -info->hash_key.advance.y);
// render glyph // 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->glyph, info->outline_glyph,
&info->bm, &info->bm_o, &info->bm, &info->bm_o,
&info->bm_s, info->be, &info->bm_s, info->be,
@ -2075,15 +2079,22 @@ static void measure_text(ass_renderer_t *render_priv)
int cur_line = 0; int cur_line = 0;
double max_asc = 0., max_desc = 0.; double max_asc = 0., max_desc = 0.;
int i; int i;
int empty_line = 1;
text_info->height = 0.; text_info->height = 0.;
for (i = 0; i < text_info->length + 1; ++i) { for (i = 0; i < text_info->length + 1; ++i) {
if ((i == text_info->length) || text_info->glyphs[i].linebreak) { 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].asc = max_asc;
text_info->lines[cur_line].desc = max_desc; text_info->lines[cur_line].desc = max_desc;
text_info->height += max_asc + max_desc; text_info->height += max_asc + max_desc;
cur_line++; cur_line++;
max_asc = max_desc = 0.; max_asc = max_desc = 0.;
} empty_line = 1;
} else
empty_line = 0;
if (i < text_info->length) { if (i < text_info->length) {
glyph_info_t *cur = text_info->glyphs + i; glyph_info_t *cur = text_info->glyphs + i;
if (d6_to_double(cur->asc) > max_asc) 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') { if (cur->symbol == '\n') {
break_type = 2; break_type = 2;
break_at = i; break_at = i;
ass_msg(MSGL_DBG2, "forced line break at %d\n", ass_msg(render_priv->library, MSGL_DBG2,
break_at); "forced line break at %d", break_at);
} }
if ((len >= max_text_width) 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; break_at = i - 1;
if (break_at == -1) if (break_at == -1)
break_at = 0; break_at = 0;
ass_msg(MSGL_DBG2, "overfill at %d\n", i); ass_msg(render_priv->library, MSGL_DBG2, "overfill at %d", i);
ass_msg(MSGL_DBG2, "line break at %d\n", break_at); ass_msg(render_priv->library, MSGL_DBG2, "line break at %d",
break_at);
} }
if (break_at != -1) { if (break_at != -1) {
@ -2246,8 +2258,8 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width)
cur_line++; cur_line++;
pen_shift_x = d6_to_double(-cur->pos.x); pen_shift_x = d6_to_double(-cur->pos.x);
pen_shift_y += height + render_priv->settings.line_spacing; pen_shift_y += height + render_priv->settings.line_spacing;
ass_msg(MSGL_DBG2, ass_msg(render_priv->library, MSGL_DBG2,
"shifting from %d to %d by (%f, %f)\n", i, "shifting from %d to %d by (%f, %f)", i,
text_info->length - 1, pen_shift_x, pen_shift_y); text_info->length - 1, pen_shift_x, pen_shift_y);
} }
cur->pos.x += double_to_d6(pen_shift_x); 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); dt /= (tm_end - tm_start);
x = x_start + (x_end - x_start) * dt; x = x_start + (x_end - x_start) * dt;
} else { } else {
ass_msg(MSGL_ERR, ass_msg(render_priv->library, MSGL_ERR,
MSGTR_LIBASS_UnknownEffectType_InternalError); "Unknown effect type");
continue; continue;
} }
@ -2465,11 +2477,11 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event,
ass_drawing_t *drawing; ass_drawing_t *drawing;
if (event->Style >= render_priv->track->n_styles) { 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; return 1;
} }
if (!event->Text) { if (!event->Text) {
ass_msg(MSGL_WARN, MSGTR_LIBASS_EmptyEvent); ass_msg(render_priv->library, MSGL_WARN, "Empty event");
return 1; return 1;
} }
@ -2513,14 +2525,6 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event,
if (code == 0) if (code == 0)
break; 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) { if (text_info->length >= text_info->max_glyphs) {
// Raise maximum number of glyphs // Raise maximum number of glyphs
text_info->max_glyphs *= 2; text_info->max_glyphs *= 2;
@ -2769,8 +2773,8 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event,
} else { // subtitle } else { // subtitle
double scr_y; double scr_y;
if (valign != VALIGN_SUB) if (valign != VALIGN_SUB)
ass_msg(MSGL_V, ass_msg(render_priv->library, MSGL_V,
"Invalid valign, supposing 0 (subtitle)\n"); "Invalid valign, supposing 0 (subtitle)");
scr_y = scr_y =
y2scr_sub(render_priv, y2scr_sub(render_priv,
render_priv->track->PlayResY - MarginV); 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) { if (render_priv->state.evt_type == EVENT_POSITIONED) {
double base_x = 0; double base_x = 0;
double base_y = 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); render_priv->state.pos_x, render_priv->state.pos_y);
get_base_point(&bbox, alignment, &base_x, &base_y); get_base_point(&bbox, alignment, &base_x, &base_y);
device_x = device_x =
@ -3010,6 +3014,9 @@ static int
ass_start_frame(ass_renderer_t *render_priv, ass_track_t *track, ass_start_frame(ass_renderer_t *render_priv, ass_track_t *track,
long long now) long long now)
{ {
if (render_priv->library != track->library)
return 1;
ass_settings_t *settings_priv = &render_priv->settings; ass_settings_t *settings_priv = &render_priv->settings;
if (!render_priv->settings.frame_width 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.a = priv->top;
s.b = priv->top + priv->height; s.b = priv->top + priv->height;
if (priv->height != imgs[i].height) { // no, it's not if (priv->height != imgs[i].height) { // no, it's not
ass_msg(MSGL_WARN, ass_msg(render_priv->library, MSGL_WARN,
MSGTR_LIBASS_EventHeightHasChanged); "Warning! Event height has changed");
priv->top = 0; priv->top = 0;
priv->height = 0; priv->height = 0;
} }

View file

@ -21,15 +21,17 @@
#include "config.h" #include "config.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <ft2build.h> #include <ft2build.h>
#include FT_GLYPH_H #include FT_GLYPH_H
#include "ass_library.h"
#include "ass.h"
#include "ass_utils.h" #include "ass_utils.h"
int mystrtoi(char **p, int *res) int mystrtoi(char **p, int *res)
{ {
// NOTE: base argument is ignored, but not used in libass anyway
double temp_res; double temp_res;
char *start = *p; char *start = *p;
temp_res = strtod(*p, p); temp_res = strtod(*p, p);
@ -72,7 +74,7 @@ int mystrtod(char **p, double *res)
return 0; return 0;
} }
int strtocolor(char **q, uint32_t *res) int strtocolor(ass_library_t *library, char **q, uint32_t *res)
{ {
uint32_t color = 0; uint32_t color = 0;
int result; int result;
@ -81,7 +83,7 @@ int strtocolor(char **q, uint32_t *res)
if (*p == '&') if (*p == '&')
++p; ++p;
else 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') { if (*p == 'H' || *p == 'h') {
++p; ++p;
@ -120,13 +122,11 @@ char parse_bool(char *str)
return 0; return 0;
} }
void ass_msg(int lvl, char *fmt, ...) void ass_msg(ass_library_t *priv, int lvl, char *fmt, ...)
{ {
va_list va; va_list va;
if (lvl > MSGL_INFO)
return;
va_start(va, fmt); va_start(va, fmt);
vprintf(fmt, va); priv->msg_callback(lvl, fmt, &va, priv->msg_callback_data);
va_end(va); va_end(va);
} }
@ -160,128 +160,10 @@ unsigned ass_utf8_get_char(char **str)
return c; 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 #ifdef CONFIG_ENCA
void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, void *ass_guess_buffer_cp(ass_library_t *library, unsigned char *buffer,
char *preferred_language, char *fallback) int buflen, char *preferred_language,
char *fallback)
{ {
const char **languages; const char **languages;
size_t langcnt; size_t langcnt;
@ -291,11 +173,10 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen,
int i; int i;
languages = enca_get_languages(&langcnt); 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++) { 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++) { for (i = 0; i < langcnt; i++) {
const char *tmp; 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); tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV);
if (tmp && encoding.charset != ENCA_CS_UNKNOWN) { if (tmp && encoding.charset != ENCA_CS_UNKNOWN) {
detected_sub_cp = strdup(tmp); 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); enca_analyser_free(analyser);
} }
@ -316,8 +197,8 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen,
if (!detected_sub_cp) { if (!detected_sub_cp) {
detected_sub_cp = strdup(fallback); detected_sub_cp = strdup(fallback);
ass_msg(MSGL_INFO, ass_msg(library, MSGL_INFO,
"ENCA detection failed: fallback to %s\n", fallback); "ENCA detection failed: fallback to %s", fallback);
} }
return detected_sub_cp; return detected_sub_cp;

View file

@ -32,7 +32,7 @@
#include <enca.h> #include <enca.h>
#endif #endif
#include "help_mp.h" #include "ass.h"
#define MSGL_FATAL 0 #define MSGL_FATAL 0
#define MSGL_ERR 1 #define MSGL_ERR 1
@ -48,15 +48,15 @@ int mystrtoi(char **p, int *res);
int mystrtoll(char **p, long long *res); int mystrtoll(char **p, long long *res);
int mystrtou32(char **p, int base, uint32_t *res); int mystrtou32(char **p, int base, uint32_t *res);
int mystrtod(char **p, double *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); char parse_bool(char *str);
unsigned ass_utf8_get_char(char **str); unsigned ass_utf8_get_char(char **str);
void ass_msg(int lvl, char *fmt, ...); void ass_msg(ass_library_t *priv, int lvl, char *fmt, ...);
void ass_gauss_blur(unsigned char *buffer, unsigned short *tmp2, #ifdef CONFIG_ENCA
int width, int height, int stride, int *m2, void *ass_guess_buffer_cp(ass_library_t *library, unsigned char *buffer,
int r, int mwidth); int buflen, char *preferred_language,
void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, char *fallback);
char *preferred_language, char *fallback); #endif
static inline int d6_to_int(int x) static inline int d6_to_int(int x)
{ {