Update libass to 15df37.

Originally committed to SVN as r3102.
This commit is contained in:
Amar Takhar 2009-07-11 15:48:50 +00:00
parent 06259dfb1e
commit df2b0b5b67
22 changed files with 6208 additions and 4345 deletions

View file

@ -10,24 +10,16 @@ libass_aegisub_a_SOURCES = \
ass.c \
ass_bitmap.c \
ass_cache.c \
ass_drawing.c \
ass_font.c \
ass_fontconfig.c \
ass_library.c \
ass_render.c \
ass_utils.c \
mputils.c \
ass.h \
ass_bitmap.h \
ass_cache.h \
ass_font.h \
ass_fontconfig.h \
ass_library.h \
ass_types.h \
ass_utils.h \
help_mp.h \
libass_msvc.patch \
mputils.h \
msvc.h
mputils.c
libass_aegisub_a_SOURCES += \
*.h
EXTRA_DIST= \
ass_cache_template.c

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -39,9 +37,9 @@
#include "ass.h"
#include "ass_utils.h"
#include "ass_library.h"
#include "mputils.h"
typedef enum {PST_UNKNOWN = 0, PST_INFO, PST_STYLES, PST_EVENTS, PST_FONTS} parser_state_t;
typedef enum { PST_UNKNOWN =
0, PST_INFO, PST_STYLES, PST_EVENTS, PST_FONTS } parser_state_t;
struct parser_priv_s {
parser_state_t state;
@ -54,7 +52,8 @@ struct parser_priv_s {
#define ASS_STYLES_ALLOC 20
#define ASS_EVENTS_ALLOC 200
void ass_free_track(ass_track_t* track) {
void ass_free_track(ass_track_t *track)
{
int i;
if (track->parser_priv) {
@ -83,14 +82,18 @@ void ass_free_track(ass_track_t* track) {
/// \brief Allocate a new style struct
/// \param track track
/// \return style id
int ass_alloc_style(ass_track_t* track) {
int ass_alloc_style(ass_track_t *track)
{
int sid;
assert(track->n_styles <= track->max_styles);
if (track->n_styles == track->max_styles) {
track->max_styles += ASS_STYLES_ALLOC;
track->styles = (ass_style_t*)realloc(track->styles, sizeof(ass_style_t)*track->max_styles);
track->styles =
(ass_style_t *) realloc(track->styles,
sizeof(ass_style_t) *
track->max_styles);
}
sid = track->n_styles++;
@ -101,14 +104,18 @@ int ass_alloc_style(ass_track_t* track) {
/// \brief Allocate a new event struct
/// \param track track
/// \return event id
int ass_alloc_event(ass_track_t* track) {
int ass_alloc_event(ass_track_t *track)
{
int eid;
assert(track->n_events <= track->max_events);
if (track->n_events == track->max_events) {
track->max_events += ASS_EVENTS_ALLOC;
track->events = (ass_event_t*)realloc(track->events, sizeof(ass_event_t)*track->max_events);
track->events =
(ass_event_t *) realloc(track->events,
sizeof(ass_event_t) *
track->max_events);
}
eid = track->n_events++;
@ -116,7 +123,8 @@ int ass_alloc_event(ass_track_t* track) {
return eid;
}
void ass_free_event(ass_track_t* track, int eid) {
void ass_free_event(ass_track_t *track, int eid)
{
ass_event_t *event = track->events + eid;
if (event->Name)
free(event->Name);
@ -128,7 +136,8 @@ void ass_free_event(ass_track_t* track, int eid) {
free(event->render_priv);
}
void ass_free_style(ass_track_t* track, int sid) {
void ass_free_style(ass_track_t *track, int sid)
{
ass_style_t *style = track->styles + sid;
if (style->Name)
free(style->Name);
@ -138,14 +147,16 @@ void ass_free_style(ass_track_t* track, int sid) {
// ==============================================================================================
static void skip_spaces(char** str) {
static void skip_spaces(char **str)
{
char *p = *str;
while ((*p == ' ') || (*p == '\t'))
++p;
*str = p;
}
static void rskip_spaces(char** str, char* limit) {
static void rskip_spaces(char **str, char *limit)
{
char *p = *str;
while ((p >= limit) && ((*p == ' ') || (*p == '\t')))
--p;
@ -160,31 +171,36 @@ static void rskip_spaces(char** str, char* limit) {
* Returnes 0 if no styles found => expects at least 1 style.
* Parsing code always adds "Default" style in the end.
*/
static int lookup_style(ass_track_t* track, char* name) {
static int lookup_style(ass_track_t *track, char *name)
{
int i;
if (*name == '*') ++name; // FIXME: what does '*' really mean ?
if (*name == '*')
++name; // FIXME: what does '*' really mean ?
for (i = track->n_styles - 1; i >= 0; --i) {
// FIXME: mb strcasecmp ?
if (strcmp(track->styles[i].Name, name) == 0)
return i;
}
i = track->default_style;
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoStyleNamedXFoundUsingY, track, name, track->styles[i].Name);
ass_msg(MSGL_WARN, MSGTR_LIBASS_NoStyleNamedXFoundUsingY,
track, name, track->styles[i].Name);
return i; // use the first style
}
static uint32_t string2color(char* p) {
static uint32_t string2color(char *p)
{
uint32_t tmp;
(void) strtocolor(&p, &tmp);
return tmp;
}
static long long string2timecode(char* p) {
static long long string2timecode(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) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_BadTimestamp);
ass_msg(MSGL_WARN, MSGTR_LIBASS_BadTimestamp);
return 0;
}
tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10;
@ -194,10 +210,12 @@ static long long string2timecode(char* p) {
/**
* \brief converts numpad-style align to align.
*/
static int numpad2align(int val) {
static int numpad2align(int val)
{
int res, v;
v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment
if (v != 0) v = 3 - v;
if (v != 0)
v = 3 - v;
res = ((val - 1) % 3) + 1; // horizontal alignment
res += v * 4;
return res;
@ -210,13 +228,13 @@ static int numpad2align(int val) {
#define ANYVAL(name,func) \
} else if (strcasecmp(tname, #name) == 0) { \
target->name = func(token); \
mp_msg(MSGT_ASS, MSGL_DBG2, "%s = %s\n", #name, token);
ass_msg(MSGL_DBG2, "%s = %s\n", #name, token);
#define STRVAL(name) \
} else if (strcasecmp(tname, #name) == 0) { \
if (target->name != NULL) free(target->name); \
target->name = strdup(token); \
mp_msg(MSGT_ASS, MSGL_DBG2, "%s = %s\n", #name, token);
ass_msg(MSGL_DBG2, "%s = %s\n", #name, token);
#define COLORVAL(name) ANYVAL(name,string2color)
#define INTVAL(name) ANYVAL(name,atoi)
@ -225,12 +243,13 @@ static int numpad2align(int val) {
#define STYLEVAL(name) \
} else if (strcasecmp(tname, #name) == 0) { \
target->name = lookup_style(track, token); \
mp_msg(MSGT_ASS, MSGL_DBG2, "%s = %s\n", #name, token);
ass_msg(MSGL_DBG2, "%s = %s\n", #name, token);
#define ALIAS(alias,name) \
if (strcasecmp(tname, #alias) == 0) {tname = #name;}
static char* next_token(char** str) {
static char *next_token(char **str)
{
char *p = *str;
char *start;
skip_spaces(&p);
@ -239,7 +258,8 @@ static char* next_token(char** str) {
return 0;
}
start = p; // start of the token
for (; (*p != '\0') && (*p != ','); ++p) {}
for (; (*p != '\0') && (*p != ','); ++p) {
}
if (*p == '\0') {
*str = p; // eos found, str will point to '\0' at exit
} else {
@ -255,6 +275,7 @@ static char* next_token(char** str) {
*p = '\0';
return start;
}
/**
* \brief Parse the tail of Dialogue line
* \param track track
@ -262,7 +283,8 @@ static char* next_token(char** str) {
* \param str string to parse, zero-terminated
* \param n_ignored number of format options to skip at the beginning
*/
static int process_event_tail(ass_track_t* track, ass_event_t* event, char* str, int n_ignored)
static int process_event_tail(ass_track_t *track, ass_event_t *event,
char *str, int n_ignored)
{
char *token;
char *tname;
@ -295,7 +317,7 @@ static int process_event_tail(ass_track_t* track, ass_event_t* event, char* str,
if (last >= event->Text && *last == '\r')
*last = 0;
}
mp_msg(MSGT_ASS, MSGL_DBG2, "Text = %s\n", event->Text);
ass_msg(MSGL_DBG2, "Text = %s\n", event->Text);
event->Duration -= event->Start;
free(format);
return 0; // "Text" is always the last
@ -324,13 +346,15 @@ static int process_event_tail(ass_track_t* track, ass_event_t* event, char* str,
* \param track track to apply overrides to
* The format for overrides is [StyleName.]Field=Value
*/
void process_force_style(ass_track_t* track) {
void ass_process_force_style(ass_track_t *track)
{
char **fs, *eq, *dt, *style, *tname, *token;
ass_style_t *target;
int sid;
char **list = track->library->style_overrides;
if (!list) return;
if (!list)
return;
for (fs = list; *fs; ++fs) {
eq = strrchr(*fs, '=');
@ -360,7 +384,8 @@ void process_force_style(ass_track_t* track) {
tname = *fs;
}
for (sid = 0; sid < track->n_styles; ++sid) {
if (style == NULL || strcasecmp(track->styles[sid].Name, style) == 0) {
if (style == NULL
|| strcasecmp(track->styles[sid].Name, style) == 0) {
target = track->styles + sid;
if (0) {
STRVAL(FontName)
@ -389,7 +414,8 @@ void process_force_style(ass_track_t* track) {
}
}
*eq = '=';
if (dt) *dt = '.';
if (dt)
*dt = '.';
}
}
@ -415,11 +441,15 @@ static int process_style(ass_track_t* track, char *str)
// no style format header
// probably an ancient script version
if (track->track_type == TRACK_TYPE_SSA)
track->style_format = strdup("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
track->style_format =
strdup
("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
"TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline,"
"Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding");
else
track->style_format = strdup("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
track->style_format =
strdup
("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
"OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut,"
"ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow,"
"Alignment, MarginL, MarginR, MarginV, Encoding");
@ -427,7 +457,7 @@ static int process_style(ass_track_t* track, char *str)
q = format = strdup(track->style_format);
mp_msg(MSGT_ASS, MSGL_V, "[%p] Style: %s\n", track, str);
ass_msg(MSGL_V, "[%p] Style: %s\n", track, str);
sid = ass_alloc_style(track);
@ -445,7 +475,8 @@ static int process_style(ass_track_t* track, char *str)
if (0) { // cool ;)
STRVAL(Name)
if ((strcmp(target->Name, "Default")==0) || (strcmp(target->Name, "*Default")==0))
if ((strcmp(target->Name, "Default") == 0)
|| (strcmp(target->Name, "*Default") == 0))
track->default_style = sid;
STRVAL(FontName)
COLORVAL(PrimaryColour)
@ -503,7 +534,8 @@ static int process_styles_line(ass_track_t* track, char *str)
char *p = str + 7;
skip_spaces(&p);
track->style_format = strdup(p);
mp_msg(MSGT_ASS, MSGL_DBG2, "Style format: %s\n", track->style_format);
ass_msg(MSGL_DBG2, "Style format: %s\n",
track->style_format);
} else if (!strncmp(str, "Style:", 6)) {
char *p = str + 6;
skip_spaces(&p);
@ -528,13 +560,28 @@ static int process_info_line(ass_track_t* track, char *str)
return 0;
}
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");
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");
}
static int process_events_line(ass_track_t *track, char *str)
{
if (!strncmp(str, "Format:", 7)) {
char *p = str + 7;
skip_spaces(&p);
track->event_format = strdup(p);
mp_msg(MSGT_ASS, MSGL_DBG2, "Event format: %s\n", track->event_format);
ass_msg(MSGL_DBG2, "Event format: %s\n",
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,
@ -548,22 +595,29 @@ static int process_events_line(ass_track_t* track, char *str)
eid = ass_alloc_event(track);
event = track->events + eid;
// We can't parse events with event_format
if (!track->event_format)
event_format_fallback(track);
process_event_tail(track, event, str, 0);
} else {
mp_msg(MSGT_ASS, MSGL_V, "Not understood: %s \n", str);
ass_msg(MSGL_V, "Not understood: %s \n", str);
}
return 0;
}
// Copied from mkvtoolnix
static unsigned char *decode_chars(unsigned char c1, unsigned char c2,
unsigned char c3, unsigned char c4, unsigned char* dst, int cnt)
unsigned char c3, unsigned char c4,
unsigned char *dst, int cnt)
{
uint32_t value;
unsigned char bytes[3];
int i;
value = ((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 - 33);
value =
((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 -
33);
bytes[2] = value & 0xff;
bytes[1] = (value & 0xff00) >> 8;
bytes[0] = (value & 0xff0000) >> 16;
@ -582,15 +636,17 @@ static int decode_font(ass_track_t* track)
int dsize; // decoded size
unsigned char *buf = 0;
mp_msg(MSGT_ASS, MSGL_V, "font: %d bytes encoded data \n", track->parser_priv->fontdata_used);
ass_msg(MSGL_V, "font: %d bytes encoded data \n",
track->parser_priv->fontdata_used);
size = track->parser_priv->fontdata_used;
if (size % 4 == 1) {
mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_BadEncodedDataSize);
ass_msg(MSGL_ERR, MSGTR_LIBASS_BadEncodedDataSize);
goto error_decode_font;
}
buf = malloc(size / 4 * 3 + 2);
q = buf;
for (i = 0, p = (unsigned char*)track->parser_priv->fontdata; i < size / 4; i++, p+=4) {
for (i = 0, p = (unsigned char *) track->parser_priv->fontdata;
i < size / 4; i++, p += 4) {
q = decode_chars(p[0], p[1], p[2], p[3], q, 3);
}
if (size % 4 == 2) {
@ -602,12 +658,14 @@ static int decode_font(ass_track_t* track)
assert(dsize <= size / 4 * 3 + 2);
if (track->library->extract_fonts) {
ass_add_font(track->library, track->parser_priv->fontname, (char*)buf, dsize);
ass_add_font(track->library, track->parser_priv->fontname,
(char *) buf, dsize);
buf = 0;
}
error_decode_font:
if (buf) free(buf);
if (buf)
free(buf);
free(track->parser_priv->fontname);
free(track->parser_priv->fontdata);
track->parser_priv->fontname = 0;
@ -628,25 +686,30 @@ static int process_fonts_line(ass_track_t* track, char *str)
decode_font(track);
}
track->parser_priv->fontname = strdup(p);
mp_msg(MSGT_ASS, MSGL_V, "fontname: %s\n", track->parser_priv->fontname);
ass_msg(MSGL_V, "fontname: %s\n",
track->parser_priv->fontname);
return 0;
}
if (!track->parser_priv->fontname) {
mp_msg(MSGT_ASS, MSGL_V, "Not understood: %s \n", str);
ass_msg(MSGL_V, "Not understood: %s \n", str);
return 0;
}
len = strlen(str);
if (len > 80) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FontLineTooLong, len, str);
ass_msg(MSGL_WARN, MSGTR_LIBASS_FontLineTooLong, len, str);
return 0;
}
if (track->parser_priv->fontdata_used + len > track->parser_priv->fontdata_size) {
if (track->parser_priv->fontdata_used + len >
track->parser_priv->fontdata_size) {
track->parser_priv->fontdata_size += 100 * 1024;
track->parser_priv->fontdata = realloc(track->parser_priv->fontdata, track->parser_priv->fontdata_size);
track->parser_priv->fontdata =
realloc(track->parser_priv->fontdata,
track->parser_priv->fontdata_size);
}
memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, str, len);
memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used,
str, len);
track->parser_priv->fontdata_used += len;
return 0;
@ -691,7 +754,8 @@ static int process_line(ass_track_t* track, char *str)
}
// there is no explicit end-of-font marker in ssa/ass
if ((track->parser_priv->state != PST_FONTS) && (track->parser_priv->fontname))
if ((track->parser_priv->state != PST_FONTS)
&& (track->parser_priv->fontname))
decode_font(track);
return 0;
@ -703,11 +767,15 @@ static int process_text(ass_track_t* track, char* str)
while (1) {
char *q;
while (1) {
if ((*p=='\r')||(*p=='\n')) ++p;
else if (p[0]=='\xef' && p[1]=='\xbb' && p[2]=='\xbf') p+=3; // U+FFFE (BOM)
else break;
if ((*p == '\r') || (*p == '\n'))
++p;
else if (p[0] == '\xef' && p[1] == '\xbb' && p[2] == '\xbf')
p += 3; // U+FFFE (BOM)
else
break;
}
for (q=p; ((*q!='\0')&&(*q!='\r')&&(*q!='\n')); ++q) {};
for (q = p; ((*q != '\0') && (*q != '\r') && (*q != '\n')); ++q) {
};
if (q == p)
break;
if (*q != '\0')
@ -733,7 +801,7 @@ void ass_process_data(ass_track_t* track, char* data, int size)
memcpy(str, data, size);
str[size] = '\0';
mp_msg(MSGT_ASS, MSGL_V, "event: %s\n", str);
ass_msg(MSGL_V, "event: %s\n", str);
process_text(track, str);
free(str);
}
@ -749,17 +817,12 @@ void ass_process_codec_private(ass_track_t* track, char *data, int size)
{
ass_process_data(track, data, size);
if (!track->event_format) {
// probably an mkv produced by ancient mkvtoolnix
// such files don't have [Events] and Format: headers
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");
else
track->event_format = strdup("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text");
}
if (!track->event_format)
event_format_fallback(track);
process_force_style(track);
ass_process_force_style(track);
}
static int check_duplicate_event(ass_track_t *track, int ReadOrder)
@ -779,7 +842,8 @@ static int check_duplicate_event(ass_track_t* track, int ReadOrder)
* \param timecode starting time of the event (milliseconds)
* \param duration duration of the event (milliseconds)
*/
void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration)
void ass_process_chunk(ass_track_t *track, char *data, int size,
long long timecode, long long duration)
{
char *str;
int eid;
@ -788,14 +852,15 @@ void ass_process_chunk(ass_track_t* track, char *data, int size, long long timec
ass_event_t *event;
if (!track->event_format) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_EventFormatHeaderMissing);
ass_msg(MSGL_WARN, MSGTR_LIBASS_EventFormatHeaderMissing);
return;
}
str = malloc(size + 1);
memcpy(str, data, size);
str[size] = '\0';
mp_msg(MSGT_ASS, MSGL_V, "event at %" PRId64 ", +%" PRId64 ": %s \n", (int64_t)timecode, (int64_t)duration, str);
ass_msg(MSGL_V, "event at %" PRId64 ", +%" PRId64 ": %s \n",
(int64_t) timecode, (int64_t) duration, str);
eid = ass_alloc_event(track);
event = track->events + eid;
@ -835,7 +900,7 @@ void ass_process_chunk(ass_track_t* track, char *data, int size, long long timec
**/
static char *sub_recode(char *data, size_t size, char *codepage)
{
static iconv_t icdsc = (iconv_t)(-1);
iconv_t icdsc;
char *tocp = "UTF-8";
char *outbuf;
assert(codepage);
@ -845,14 +910,18 @@ static char* sub_recode(char* data, size_t size, char* codepage)
#ifdef CONFIG_ENCA
char enca_lang[3], enca_fallback[100];
if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2
|| sscanf(codepage, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2) {
cp_tmp = guess_buffer_cp((unsigned char*)data, size, enca_lang, enca_fallback);
|| sscanf(codepage, "ENCA:%2s:%99s", enca_lang,
enca_fallback) == 2) {
cp_tmp =
ass_guess_buffer_cp((unsigned char *) data, size, enca_lang,
enca_fallback);
}
#endif
if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) {
mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: opened iconv descriptor.\n");
ass_msg(MSGL_V, "LIBSUB: opened iconv descriptor.\n");
} else
mp_msg(MSGT_ASS,MSGL_ERR,MSGTR_LIBASS_ErrorOpeningIconvDescriptor);
ass_msg(MSGL_ERR,
MSGTR_LIBASS_ErrorOpeningIconvDescriptor);
}
{
@ -883,11 +952,11 @@ static char* sub_recode(char* data, size_t size, char* codepage)
osize += size;
oleft += size;
} else {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorRecodingFile);
ass_msg(MSGL_WARN,
MSGTR_LIBASS_ErrorRecodingFile);
return NULL;
}
} else
if (clear)
} else if (clear)
break;
}
outbuf[osize - oleft - 1] = 0;
@ -896,7 +965,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);
mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: closed iconv descriptor.\n");
ass_msg(MSGL_V, "LIBSUB: closed iconv descriptor.\n");
}
return outbuf;
@ -918,12 +987,12 @@ static char* read_file(char* fname, size_t *bufsize)
FILE *fp = fopen(fname, "rb");
if (!fp) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname);
ass_msg(MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname);
return 0;
}
res = fseek(fp, 0, SEEK_END);
if (res == -1) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FseekFailed, fname);
ass_msg(MSGL_WARN, MSGTR_LIBASS_FseekFailed, fname);
fclose(fp);
return 0;
}
@ -932,12 +1001,13 @@ static char* read_file(char* fname, size_t *bufsize)
rewind(fp);
if (sz > 10 * 1024 * 1024) {
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M, fname);
ass_msg(MSGL_INFO,
MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M, fname);
fclose(fp);
return 0;
}
mp_msg(MSGT_ASS, MSGL_V, "file size: %ld\n", sz);
ass_msg(MSGL_V, "file size: %ld\n", sz);
buf = malloc(sz + 1);
assert(buf);
@ -945,7 +1015,8 @@ static char* read_file(char* fname, size_t *bufsize)
do {
res = fread(buf + bytes_read, 1, sz - bytes_read, fp);
if (res <= 0) {
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_ReadFailed, errno, strerror(errno));
ass_msg(MSGL_INFO, MSGTR_LIBASS_ReadFailed, errno,
strerror(errno));
fclose(fp);
free(buf);
return 0;
@ -986,7 +1057,7 @@ static ass_track_t* parse_memory(ass_library_t* library, char* buf)
return 0;
}
process_force_style(track);
ass_process_force_style(track);
return track;
}
@ -999,7 +1070,8 @@ static ass_track_t* parse_memory(ass_library_t* library, char* buf)
* \param codepage recode buffer contents from given codepage
* \return newly allocated track
*/
ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize, char* codepage)
ass_track_t *ass_read_memory(ass_library_t *library, char *buf,
size_t bufsize, char *codepage)
{
ass_track_t *track;
int need_free = 0;
@ -1021,11 +1093,12 @@ ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize,
if (!track)
return 0;
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileMemory, track->n_styles, track->n_events);
ass_msg(MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileMemory,
track->n_styles, track->n_events);
return track;
}
char* read_file_recode(char* fname, char* codepage, size_t* size)
static char *read_file_recode(char *fname, char *codepage, size_t *size)
{
char *buf;
size_t bufsize;
@ -1053,7 +1126,8 @@ char* read_file_recode(char* fname, char* codepage, size_t* size)
* \param codepage recode buffer contents from given codepage
* \return newly allocated track
*/
ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage)
ass_track_t *ass_read_file(ass_library_t *library, char *fname,
char *codepage)
{
char *buf;
ass_track_t *track;
@ -1069,7 +1143,8 @@ ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage)
track->name = strdup(fname);
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileFname, fname, track->n_styles, track->n_events);
ass_msg(MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileFname, fname,
track->n_styles, track->n_events);
// dump_events(forced_tid);
return track;
@ -1106,30 +1181,43 @@ int ass_read_styles(ass_track_t* track, char* fname, char* codepage)
return 0;
}
long long ass_step_sub(ass_track_t* track, long long now, int movement) {
long long ass_step_sub(ass_track_t *track, long long now, int movement)
{
int i;
if (movement == 0) return 0;
if (track->n_events == 0) return 0;
if (movement == 0)
return 0;
if (track->n_events == 0)
return 0;
if (movement < 0)
for (i = 0; (i < track->n_events) && ((long long)(track->events[i].Start + track->events[i].Duration) <= now); ++i) {}
else
for (i = track->n_events - 1; (i >= 0) && ((long long)(track->events[i].Start) > now); --i) {}
for (i = 0;
(i < track->n_events)
&&
((long long) (track->events[i].Start +
track->events[i].Duration) <= now); ++i) {
} else
for (i = track->n_events - 1;
(i >= 0) && ((long long) (track->events[i].Start) > now);
--i) {
}
// -1 and n_events are ok
assert(i >= -1); assert(i <= track->n_events);
assert(i >= -1);
assert(i <= track->n_events);
i += movement;
if (i < 0) i = 0;
if (i >= track->n_events) i = track->n_events - 1;
if (i < 0)
i = 0;
if (i >= track->n_events)
i = track->n_events - 1;
return ((long long) track->events[i].Start) - now;
}
ass_track_t* ass_new_track(ass_library_t* library) {
ass_track_t *ass_new_track(ass_library_t *library)
{
ass_track_t *track = calloc(1, sizeof(ass_track_t));
track->library = library;
track->ScaledBorderAndShadow = 1;
track->parser_priv = calloc(1, sizeof(parser_priv_t));
return track;
}

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -69,6 +67,8 @@ void ass_set_extract_fonts(ass_library_t* priv, int extract);
void ass_set_style_overrides(ass_library_t *priv, char **list);
void ass_process_force_style(ass_track_t *track);
/**
* \brief initialize the renderer
* \param priv library handle
@ -85,20 +85,19 @@ void ass_renderer_done(ass_renderer_t* priv);
void ass_set_frame_size(ass_renderer_t *priv, int w, int h);
void ass_set_margins(ass_renderer_t *priv, int t, int b, int l, int r);
void ass_set_use_margins(ass_renderer_t *priv, int use);
void ass_set_aspect_ratio(ass_renderer_t* priv, double ar);
void ass_set_aspect_ratio(ass_renderer_t *priv, double ar, double par);
void ass_set_font_scale(ass_renderer_t *priv, double font_scale);
void ass_set_hinting(ass_renderer_t *priv, ass_hinting_t ht);
void ass_set_line_spacing(ass_renderer_t *priv, double line_spacing);
/**
* \brief set font lookup defaults
* \param fc bool, use fontconfig?
* \param config path to fontconfig configuration file, or NULL. Only matters
* if fontconfig is used
*/
int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family);
/**
* \brief set font lookup defaults, don't use fontconfig even if it is available
*/
int ass_set_fonts_nofc(ass_renderer_t* priv, const char* default_font, const char* default_family);
int ass_set_fonts(ass_renderer_t *priv, const char *default_font,
const char *default_family, int fc, const char *config);
/**
* \brief render a frame, producing a list of ass_image_t
@ -106,7 +105,8 @@ int ass_set_fonts_nofc(ass_renderer_t* priv, const char* default_font, const ch
* \param track subtitle track
* \param now video timestamp in milliseconds
*/
ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change);
ass_image_t *ass_render_frame(ass_renderer_t *priv, ass_track_t *track,
long long now, int *detect_change);
// The following functions operate on track objects and do not need an ass_renderer //
@ -177,16 +177,16 @@ void ass_process_codec_private(ass_track_t* track, char *data, int size);
* \param timecode starting time of the event (milliseconds)
* \param duration duration of the event (milliseconds)
*/
void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration);
char* read_file_recode(char* fname, char* codepage, size_t* size);
void ass_process_chunk(ass_track_t *track, char *data, int size,
long long timecode, long long duration);
/**
* \brief Read subtitles from file.
* \param fname file name
* \return newly allocated track
*/
ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage);
ass_track_t *ass_read_file(ass_library_t *library, char *fname,
char *codepage);
/**
* \brief Read subtitles from memory.
@ -196,7 +196,8 @@ ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage);
* \param codepage recode buffer contents from given codepage
* \return newly allocated track
*/
ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize, char* codepage);
ass_track_t *ass_read_memory(ass_library_t *library, char *buf,
size_t bufsize, char *codepage);
/**
* \brief read styles from file into already initialized track
* \return 0 on success
@ -209,7 +210,8 @@ int ass_read_styles(ass_track_t* track, char* fname, char* codepage);
* \param data binary font data
* \param data_size data size
*/
void ass_add_font(ass_library_t* library, char* name, char* data, int data_size);
void ass_add_font(ass_library_t *library, char *name, char *data,
int data_size);
/**
* \brief Remove all fonts stored in ass_library object

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -27,7 +25,7 @@
#include <ft2build.h>
#include FT_GLYPH_H
#include "mputils.h"
#include "ass_utils.h"
#include "ass_bitmap.h"
struct ass_synth_priv_s {
@ -71,18 +69,24 @@ static int generate_tables(ass_synth_priv_t* priv, double radius)
if (priv->g_r) {
// gaussian curve with volume = 256
for (volume_diff=10000000; volume_diff>0.0000001; volume_diff*=0.5){
for (volume_diff = 10000000; volume_diff > 0.0000001;
volume_diff *= 0.5) {
volume_factor += volume_diff;
volume = 0;
for (i = 0; i < priv->g_w; ++i) {
priv->g[i] = (unsigned)(exp(A * (i-priv->g_r)*(i-priv->g_r)) * volume_factor + .5);
priv->g[i] =
(unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) *
volume_factor + .5);
volume += priv->g[i];
}
if(volume>256) volume_factor-= volume_diff;
if (volume > 256)
volume_factor -= volume_diff;
}
volume = 0;
for (i = 0; i < priv->g_w; ++i) {
priv->g[i] = (unsigned)(exp(A * (i-priv->g_r)*(i-priv->g_r)) * volume_factor + .5);
priv->g[i] =
(unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) *
volume_factor + .5);
volume += priv->g[i];
}
@ -105,8 +109,10 @@ static void resize_tmp(ass_synth_priv_t* priv, int w, int h)
priv->tmp_w = 64;
if (priv->tmp_h == 0)
priv->tmp_h = 64;
while (priv->tmp_w < w) priv->tmp_w *= 2;
while (priv->tmp_h < h) priv->tmp_h *= 2;
while (priv->tmp_w < w)
priv->tmp_w *= 2;
while (priv->tmp_h < h)
priv->tmp_h *= 2;
if (priv->tmp)
free(priv->tmp);
priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
@ -144,7 +150,8 @@ static bitmap_t* alloc_bitmap(int w, int h)
void ass_free_bitmap(bitmap_t *bm)
{
if (bm) {
if (bm->buffer) free(bm->buffer);
if (bm->buffer)
free(bm->buffer);
free(bm);
}
}
@ -166,7 +173,8 @@ static int check_glyph_area(FT_Glyph glyph)
dx = bbox.xMax - bbox.xMin;
dy = bbox.yMax - bbox.yMin;
if (dx * dy > 8000000) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_GlyphBBoxTooLarge, (int)dx, (int)dy);
ass_msg(MSGL_WARN, MSGTR_LIBASS_GlyphBBoxTooLarge,
(int) dx, (int) dy);
return 1;
} else
return 0;
@ -187,14 +195,16 @@ static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
return 0;
error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, error);
ass_msg(MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError,
error);
return 0;
}
bg = (FT_BitmapGlyph) glyph;
bit = &(bg->bitmap);
if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UnsupportedPixelMode, (int)(bit->pixel_mode));
ass_msg(MSGL_WARN, MSGTR_LIBASS_UnsupportedPixelMode,
(int) (bit->pixel_mode));
FT_Done_Glyph(glyph);
return 0;
}
@ -229,14 +239,21 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
int x, y;
const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
const int r = bm_o->left + bm_o->w < bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
const int b = bm_o->top + bm_o->h < bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
const int r =
bm_o->left + bm_o->w <
bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
const int b =
bm_o->top + bm_o->h <
bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
bitmap_t *bm_s = copy_bitmap(bm_o);
unsigned char* g = bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
unsigned char* o = bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
unsigned char* s = bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left);
unsigned char *g =
bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
unsigned char *o =
bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
unsigned char *s =
bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left);
for (y = 0; y < b - t; ++y) {
for (x = 0; x < r - l; ++x) {
@ -255,11 +272,62 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
return bm_s;
}
/**
* \brief Shift a bitmap by the fraction of a pixel in x and y direction
* expressed in 26.6 fixed point
*/
static void shift_bitmap(unsigned char *buf, int w, int h, int shift_x,
int shift_y)
{
int x, y, b;
// Shift in x direction
if (shift_x > 0) {
for (y = 0; y < h; y++) {
for (x = w - 1; x > 0; x--) {
b = (buf[x + y * w - 1] * shift_x) >> 6;
buf[x + y * w - 1] -= b;
buf[x + y * w] += b;
}
}
} else if (shift_x < 0) {
shift_x = -shift_x;
for (y = 0; y < h; y++) {
for (x = 0; x < w - 1; x++) {
b = (buf[x + y * w + 1] * shift_x) >> 6;
buf[x + y * w + 1] -= b;
buf[x + y * w] += b;
}
}
}
// Shift in y direction
if (shift_y > 0) {
for (x = 0; x < w; x++) {
for (y = h - 1; y > 0; y--) {
b = (buf[x + (y - 1) * w] * shift_y) >> 6;
buf[x + (y - 1) * w] -= b;
buf[x + y * w] += b;
}
}
} else if (shift_y < 0) {
shift_y = -shift_y;
for (x = 0; x < w; x++) {
for (y = 0; y < h - 1; y++) {
b = (buf[x + (y + 1) * w] * shift_y) >> 6;
buf[x + (y + 1) * w] -= b;
buf[x + y * w] += b;
}
}
}
}
/**
* \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel
* This blur is the same as the one employed by vsfilter.
*/
static void be_blur(unsigned char *buf, int w, int h) {
static void be_blur(unsigned char *buf, int w, int h)
{
unsigned int x, y;
unsigned int old_sum, new_sum;
@ -283,12 +351,15 @@ static void be_blur(unsigned char *buf, int w, int h) {
}
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_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 : bord;
bord = (blur_radius > 0.0) ? blur_radius + 1 : bord;
if (bord == 0 && (shadow_offset.x || shadow_offset.y))
bord = 1;
assert(bm_g && bm_o && bm_s);
@ -321,9 +392,15 @@ int glyph_to_bitmap(ass_synth_priv_t* priv_blur,
if (blur_radius > 0.0) {
generate_tables(priv_blur, blur_radius);
if (*bm_o)
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);
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
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);
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)
@ -331,7 +408,9 @@ int glyph_to_bitmap(ass_synth_priv_t* priv_blur,
else
*bm_s = copy_bitmap(*bm_g);
shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h,
shadow_offset.x, shadow_offset.y);
assert(bm_s);
return 0;
}

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -46,7 +44,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);
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);
void ass_free_bitmap(bitmap_t *bm);

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -29,56 +27,13 @@
#include <assert.h>
#include "mputils.h"
#include "ass_utils.h"
#include "ass.h"
#include "ass_fontconfig.h"
#include "ass_font.h"
#include "ass_bitmap.h"
#include "ass_cache.h"
typedef struct hashmap_item_s {
void* key;
void* value;
struct hashmap_item_s* next;
} hashmap_item_t;
typedef hashmap_item_t* hashmap_item_p;
struct hashmap_s {
int nbuckets;
size_t key_size, value_size;
hashmap_item_p* root;
hashmap_item_dtor_t item_dtor; // a destructor for hashmap key/value pairs
hashmap_key_compare_t key_compare;
hashmap_hash_t hash;
// stats
int hit_count;
int miss_count;
int count;
};
#define FNV1_32A_INIT (unsigned)0x811c9dc5
static inline unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval)
{
unsigned char *bp = buf;
unsigned char *be = bp + len;
while (bp < be) {
hval ^= (unsigned)*bp++;
hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
}
return hval;
}
static inline unsigned fnv_32a_str(char* str, unsigned hval)
{
unsigned char* s = (unsigned char*)str;
while (*s) {
hval ^= (unsigned)*s++;
hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
}
return hval;
}
static unsigned hashmap_hash(void *buf, size_t len)
{
return fnv_32a_buf(buf, len, FNV1_32A_INIT);
@ -89,14 +44,16 @@ static int hashmap_key_compare(void* a, void* b, size_t size)
return memcmp(a, b, size) == 0;
}
static void hashmap_item_dtor(void* key, size_t key_size, void* value, size_t value_size)
static void hashmap_item_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
free(key);
free(value);
}
hashmap_t *hashmap_init(size_t key_size, size_t value_size, int nbuckets,
hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare,
hashmap_item_dtor_t item_dtor,
hashmap_key_compare_t key_compare,
hashmap_hash_t hash)
{
hashmap_t *map = calloc(1, sizeof(hashmap_t));
@ -115,14 +72,17 @@ void hashmap_done(hashmap_t* map)
int i;
// print stats
if (map->count > 0 || map->hit_count + map->miss_count > 0)
mp_msg(MSGT_ASS, MSGL_V, "cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n",
map->hit_count + map->miss_count, map->hit_count, map->miss_count, map->count);
ass_msg(MSGL_V,
"cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n",
map->hit_count + map->miss_count, map->hit_count,
map->miss_count, map->count);
for (i = 0; i < map->nbuckets; ++i) {
hashmap_item_t *item = map->root[i];
while (item) {
hashmap_item_t *next = item->next;
map->item_dtor(item->key, map->key_size, item->value, map->value_size);
map->item_dtor(item->key, map->key_size, item->value,
map->value_size);
free(item);
item = next;
}
@ -171,8 +131,6 @@ void* hashmap_find(hashmap_t* map, void* key)
//---------------------------------
// font cache
hashmap_t* font_cache;
static unsigned font_desc_hash(void *buf, size_t len)
{
ass_font_desc_t *desc = buf;
@ -183,7 +141,8 @@ static unsigned font_desc_hash(void* buf, size_t len)
return hval;
}
static int font_compare(void* key1, void* key2, size_t key_size) {
static int font_compare(void *key1, void *key2, size_t key_size)
{
ass_font_desc_t *a = key1;
ass_font_desc_t *b = key2;
if (strcmp(a->family, b->family) != 0)
@ -197,13 +156,15 @@ static int font_compare(void* key1, void* key2, size_t key_size) {
return 1;
}
static void font_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
static void font_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
ass_font_free(value);
free(key);
}
ass_font_t* ass_font_cache_find(ass_font_desc_t* desc)
ass_font_t *ass_font_cache_find(hashmap_t *font_cache,
ass_font_desc_t *desc)
{
return hashmap_find(font_cache, desc);
}
@ -212,20 +173,22 @@ ass_font_t* ass_font_cache_find(ass_font_desc_t* desc)
* \brief Add a face struct to cache.
* \param font font struct
*/
void* ass_font_cache_add(ass_font_t* font)
void *ass_font_cache_add(hashmap_t *font_cache, ass_font_t *font)
{
return hashmap_insert(font_cache, &(font->desc), font);
}
void ass_font_cache_init(void)
hashmap_t *ass_font_cache_init(void)
{
hashmap_t *font_cache;
font_cache = hashmap_init(sizeof(ass_font_desc_t),
sizeof(ass_font_t),
1000,
font_hash_dtor, font_compare, font_desc_hash);
return font_cache;
}
void ass_font_cache_done(void)
void ass_font_cache_done(hashmap_t *font_cache)
{
hashmap_done(font_cache);
}
@ -240,19 +203,22 @@ void ass_font_cache_done(void)
//---------------------------------
// bitmap cache
hashmap_t* bitmap_cache;
static void bitmap_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
static void bitmap_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
bitmap_hash_val_t *v = value;
if (v->bm) ass_free_bitmap(v->bm);
if (v->bm_o) ass_free_bitmap(v->bm_o);
if (v->bm_s) ass_free_bitmap(v->bm_s);
if (v->bm)
ass_free_bitmap(v->bm);
if (v->bm_o)
ass_free_bitmap(v->bm_o);
if (v->bm_s)
ass_free_bitmap(v->bm_s);
free(key);
free(value);
}
void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val)
void *cache_add_bitmap(hashmap_t *bitmap_cache, bitmap_hash_key_t *key,
bitmap_hash_val_t *val)
{
return hashmap_insert(bitmap_cache, key, val);
}
@ -262,46 +228,51 @@ void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val)
* \param key hash key
* \return requested hash val or 0 if not found
*/
bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key)
bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache,
bitmap_hash_key_t *key)
{
return hashmap_find(bitmap_cache, key);
}
void ass_bitmap_cache_init(void)
hashmap_t *ass_bitmap_cache_init(void)
{
hashmap_t *bitmap_cache;
bitmap_cache = hashmap_init(sizeof(bitmap_hash_key_t),
sizeof(bitmap_hash_val_t),
0xFFFF + 13,
bitmap_hash_dtor, bitmap_compare,
bitmap_hash);
return bitmap_cache;
}
void ass_bitmap_cache_done(void)
void ass_bitmap_cache_done(hashmap_t *bitmap_cache)
{
hashmap_done(bitmap_cache);
}
void ass_bitmap_cache_reset(void)
hashmap_t *ass_bitmap_cache_reset(hashmap_t *bitmap_cache)
{
ass_bitmap_cache_done();
ass_bitmap_cache_init();
ass_bitmap_cache_done(bitmap_cache);
return ass_bitmap_cache_init();
}
//---------------------------------
// glyph cache
hashmap_t* glyph_cache;
static void glyph_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
static void glyph_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
glyph_hash_val_t *v = value;
if (v->glyph) FT_Done_Glyph(v->glyph);
if (v->outline_glyph) FT_Done_Glyph(v->outline_glyph);
if (v->glyph)
FT_Done_Glyph(v->glyph);
if (v->outline_glyph)
FT_Done_Glyph(v->outline_glyph);
free(key);
free(value);
}
void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
void *cache_add_glyph(hashmap_t *glyph_cache, glyph_hash_key_t *key,
glyph_hash_val_t *val)
{
return hashmap_insert(glyph_cache, key, val);
}
@ -311,37 +282,39 @@ void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
* \param key hash key
* \return requested hash val or 0 if not found
*/
glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key)
glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache,
glyph_hash_key_t *key)
{
return hashmap_find(glyph_cache, key);
}
void ass_glyph_cache_init(void)
hashmap_t *ass_glyph_cache_init(void)
{
hashmap_t *glyph_cache;
glyph_cache = hashmap_init(sizeof(glyph_hash_key_t),
sizeof(glyph_hash_val_t),
0xFFFF + 13,
glyph_hash_dtor, glyph_compare, glyph_hash);
return glyph_cache;
}
void ass_glyph_cache_done(void)
void ass_glyph_cache_done(hashmap_t *glyph_cache)
{
hashmap_done(glyph_cache);
}
void ass_glyph_cache_reset(void)
hashmap_t *ass_glyph_cache_reset(hashmap_t *glyph_cache)
{
ass_glyph_cache_done();
ass_glyph_cache_init();
ass_glyph_cache_done(glyph_cache);
return ass_glyph_cache_init();
}
//---------------------------------
// composite cache
hashmap_t* composite_cache;
static void composite_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
static void composite_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
composite_hash_val_t *v = value;
free(v->a);
@ -350,7 +323,9 @@ static void composite_hash_dtor(void* key, size_t key_size, void* value, size_t
free(value);
}
void* cache_add_composite(composite_hash_key_t* key, composite_hash_val_t* val)
void *cache_add_composite(hashmap_t *composite_cache,
composite_hash_key_t *key,
composite_hash_val_t *val)
{
return hashmap_insert(composite_cache, key, val);
}
@ -360,27 +335,30 @@ void* cache_add_composite(composite_hash_key_t* key, composite_hash_val_t* val)
* \param key hash key
* \return requested hash val or 0 if not found
*/
composite_hash_val_t* cache_find_composite(composite_hash_key_t* key)
composite_hash_val_t *cache_find_composite(hashmap_t *composite_cache,
composite_hash_key_t *key)
{
return hashmap_find(composite_cache, key);
}
void ass_composite_cache_init(void)
hashmap_t *ass_composite_cache_init(void)
{
hashmap_t *composite_cache;
composite_cache = hashmap_init(sizeof(composite_hash_key_t),
sizeof(composite_hash_val_t),
0xFFFF + 13,
composite_hash_dtor, NULL, NULL);
composite_hash_dtor, composite_compare,
composite_hash);
return composite_cache;
}
void ass_composite_cache_done(void)
void ass_composite_cache_done(hashmap_t *composite_cache)
{
hashmap_done(composite_cache);
}
void ass_composite_cache_reset(void)
hashmap_t *ass_composite_cache_reset(hashmap_t *composite_cache)
{
ass_composite_cache_done();
ass_composite_cache_init();
ass_composite_cache_done(composite_cache);
return ass_composite_cache_init();
}

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -27,11 +25,44 @@
#include "ass_font.h"
#include "ass_bitmap.h"
void ass_font_cache_init(void);
ass_font_t* ass_font_cache_find(ass_font_desc_t* desc);
void* ass_font_cache_add(ass_font_t* font);
void ass_font_cache_done(void);
typedef void (*hashmap_item_dtor_t) (void *key, size_t key_size,
void *value, size_t value_size);
typedef int (*hashmap_key_compare_t) (void *key1, void *key2,
size_t key_size);
typedef unsigned (*hashmap_hash_t) (void *key, size_t key_size);
typedef struct hashmap_item_s {
void *key;
void *value;
struct hashmap_item_s *next;
} hashmap_item_t;
typedef hashmap_item_t *hashmap_item_p;
typedef struct hashmap_s {
int nbuckets;
size_t key_size, value_size;
hashmap_item_p *root;
hashmap_item_dtor_t item_dtor; // a destructor for hashmap key/value pairs
hashmap_key_compare_t key_compare;
hashmap_hash_t hash;
// stats
int hit_count;
int miss_count;
int count;
} hashmap_t;
hashmap_t *hashmap_init(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);
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);
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
@ -43,31 +74,27 @@ typedef struct bitmap_hash_val_s {
bitmap_t *bm_s;
} bitmap_hash_val_t;
void ass_bitmap_cache_init(void);
void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val);
bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key);
void ass_bitmap_cache_reset(void);
void ass_bitmap_cache_done(void);
hashmap_t *ass_bitmap_cache_init(void);
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,
bitmap_hash_key_t *key);
hashmap_t *ass_bitmap_cache_reset(hashmap_t *bitmap_cache);
void ass_bitmap_cache_done(hashmap_t *bitmap_cache);
// Cache for composited bitmaps
typedef struct composite_hash_key_s {
int aw, ah, bw, bh;
int ax, ay, bx, by;
bitmap_hash_key_t a;
bitmap_hash_key_t b;
} composite_hash_key_t;
typedef struct composite_hash_val_s {
unsigned char *a;
unsigned char *b;
} composite_hash_val_t;
void ass_composite_cache_init(void);
void* cache_add_composite(composite_hash_key_t* key, composite_hash_val_t* val);
composite_hash_val_t* cache_find_composite(composite_hash_key_t* key);
void ass_composite_cache_reset(void);
void ass_composite_cache_done(void);
hashmap_t *ass_composite_cache_init(void);
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,
composite_hash_key_t *key);
hashmap_t *ass_composite_cache_reset(hashmap_t *composite_cache);
void ass_composite_cache_done(hashmap_t *composite_cache);
typedef struct glyph_hash_val_s {
@ -75,24 +102,15 @@ typedef struct glyph_hash_val_s {
FT_Glyph outline_glyph;
FT_BBox bbox_scaled; // bbox after scaling, but before rotation
FT_Vector advance; // 26.6, advance distance to the next bitmap in line
int asc, desc; // ascender/descender of a drawing
} glyph_hash_val_t;
void ass_glyph_cache_init(void);
void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val);
glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key);
void ass_glyph_cache_reset(void);
void ass_glyph_cache_done(void);
typedef struct hashmap_s hashmap_t;
typedef void (*hashmap_item_dtor_t)(void* key, size_t key_size, void* value, size_t value_size);
typedef int (*hashmap_key_compare_t)(void* key1, void* key2, size_t key_size);
typedef unsigned (*hashmap_hash_t)(void* key, size_t key_size);
hashmap_t* hashmap_init(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);
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_glyph_cache_init(void);
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,
glyph_hash_key_t *key);
hashmap_t *ass_glyph_cache_reset(hashmap_t *glyph_cache);
void ass_glyph_cache_done(hashmap_t *glyph_cache);
#endif /* LIBASS_CACHE_H */

View file

@ -6,6 +6,8 @@
type member;
#define FTVECTOR(member) \
FT_Vector member;
#define BITMAPHASHKEY(member) \
bitmap_hash_key_t member;
#define END(typedefnamename) \
} typedefnamename;
@ -21,6 +23,8 @@
a->member == b->member &&
#define FTVECTOR(member) \
a->member.x == b->member.x && a->member.y == b->member.y &&
#define BITMAPHASHKEY(member) \
bitmap_compare(&a->member, &b->member, sizeof(a->member)) &&
#define END(typedefname) \
1; \
}
@ -35,6 +39,10 @@
#define GENERIC(type, member) \
hval = fnv_32a_buf(&p->member, sizeof(p->member), hval);
#define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y);
#define BITMAPHASHKEY(member) { \
unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \
hval = fnv_32a_buf(&temp, sizeof(temp), hval); \
}
#define END(typedefname) \
return hval; \
}
@ -51,7 +59,7 @@ START(bitmap, bipmap_hash_key_s)
GENERIC(ass_font_t *, font)
GENERIC(double, size) // font size
GENERIC(uint32_t, ch) // character code
GENERIC(unsigned, outline) // border width, 16.16 fixed point value
FTVECTOR(outline) // border width, 16.16 fixed point value
GENERIC(int, bold)
GENERIC(int, italic)
GENERIC(char, be) // blur edges
@ -61,12 +69,16 @@ START(bitmap, bipmap_hash_key_s)
GENERIC(int, frx) // signed 16.16
GENERIC(int, fry) // signed 16.16
GENERIC(int, frz) // signed 16.16
GENERIC(int, fax) // signed 16.16
GENERIC(int, fay) // signed 16.16
// shift vector that was added to glyph before applying rotation
// = 0, if frx = fry = frx = 0
// = (glyph base point) - (rotation origin), otherwise
GENERIC(int, shift_x)
GENERIC(int, shift_y)
FTVECTOR(advance) // subpixel shift vector
FTVECTOR(shadow_offset) // shadow subpixel shift
GENERIC(unsigned, drawing_hash) // hashcode of a drawing
END(bitmap_hash_key_t)
// describes an outline glyph
@ -79,10 +91,28 @@ START(glyph, glyph_hash_key_s)
GENERIC(unsigned, scale_x) // 16.16
GENERIC(unsigned, scale_y) // 16.16
FTVECTOR(advance) // subpixel shift vector
GENERIC(unsigned, outline) // border width, 16.16
FTVECTOR(outline) // border width, 16.16
GENERIC(unsigned, drawing_hash) // hashcode of a drawing
GENERIC(unsigned, flags) // glyph decoration flags
END(glyph_hash_key_t)
// Cache for composited bitmaps
START(composite, composite_hash_key_s)
GENERIC(int, aw)
GENERIC(int, ah)
GENERIC(int, bw)
GENERIC(int, bh)
GENERIC(int, ax)
GENERIC(int, ay)
GENERIC(int, bx)
GENERIC(int, by)
BITMAPHASHKEY(a)
BITMAPHASHKEY(b)
END(composite_hash_key_t)
#undef START
#undef GENERIC
#undef FTVECTOR
#undef BITMAPHASHKEY
#undef END

View file

@ -0,0 +1,477 @@
/*
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* This file is part of libass.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <ft2build.h>
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BBOX_H
#include <math.h>
#include "ass_utils.h"
#include "ass_font.h"
#include "ass_drawing.h"
#define CURVE_ACCURACY 64.0
#define GLYPH_INITIAL_POINTS 100
#define GLYPH_INITIAL_CONTOURS 5
/*
* \brief Get and prepare a FreeType glyph
*/
static void drawing_make_glyph(ass_drawing_t *drawing, void *fontconfig_priv,
ass_font_t *font, ass_hinting_t hint)
{
FT_OutlineGlyph glyph;
// This is hacky...
glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font,
(uint32_t) ' ', hint, 0);
FT_Outline_Done(drawing->ftlibrary, &glyph->outline);
FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
GLYPH_INITIAL_CONTOURS, &glyph->outline);
glyph->outline.n_contours = 0;
glyph->outline.n_points = 0;
glyph->root.advance.x = glyph->root.advance.y = 0;
drawing->glyph = glyph;
}
/*
* \brief Add a single point to a contour.
*/
static inline void drawing_add_point(ass_drawing_t *drawing,
FT_Vector *point)
{
FT_Outline *ol = &drawing->glyph->outline;
if (ol->n_points >= drawing->max_points) {
drawing->max_points *= 2;
ol->points = realloc(ol->points, sizeof(FT_Vector) *
drawing->max_points);
ol->tags = realloc(ol->tags, drawing->max_points);
}
ol->points[ol->n_points].x = point->x;
ol->points[ol->n_points].y = point->y;
ol->tags[ol->n_points] = 1;
ol->n_points++;
}
/*
* \brief Close a contour and check glyph size overflow.
*/
static inline void drawing_close_shape(ass_drawing_t *drawing)
{
FT_Outline *ol = &drawing->glyph->outline;
if (ol->n_contours >= drawing->max_contours) {
drawing->max_contours *= 2;
ol->contours = realloc(ol->contours, sizeof(short) *
drawing->max_contours);
}
ol->contours[ol->n_contours] = ol->n_points - 1;
ol->n_contours++;
}
/*
* \brief Prepare drawing for parsing. This just sets a few parameters.
*/
static void drawing_prepare(ass_drawing_t *drawing)
{
// Scaling parameters
drawing->point_scale_x = drawing->scale_x *
64.0 / (1 << (drawing->scale - 1));
drawing->point_scale_y = drawing->scale_y *
64.0 / (1 << (drawing->scale - 1));
}
/*
* \brief Finish a drawing. This only sets the horizontal advance according
* to the glyph's bbox at the moment.
*/
static void drawing_finish(ass_drawing_t *drawing)
{
int i, offset;
FT_BBox bbox;
FT_Outline *ol = &drawing->glyph->outline;
// Close the last contour
drawing_close_shape(drawing);
#if 0
// Dump points
for (i = 0; i < ol->n_points; i++) {
printf("point (%d, %d)\n", (int) ol->points[i].x,
(int) ol->points[i].y);
}
// Dump contours
for (i = 0; i < ol->n_contours; i++)
printf("contour %d\n", ol->contours[i]);
#endif
FT_Outline_Get_CBox(&drawing->glyph->outline, &bbox);
drawing->glyph->root.advance.x = d6_to_d16(bbox.xMax - bbox.xMin);
drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y);
drawing->asc = bbox.yMax - bbox.yMin + drawing->desc;
// Place it onto the baseline
offset = (bbox.yMax - bbox.yMin) + double_to_d6(-drawing->pbo *
drawing->scale_y);
for (i = 0; i < ol->n_points; i++)
ol->points[i].y += offset;
}
/*
* \brief Check whether a number of items on the list is available
*/
static int token_check_values(ass_drawing_token_t *token, int i, int type)
{
int j;
for (j = 0; j < i; j++) {
if (!token || token->type != type) return 0;
token = token->next;
}
return 1;
}
/*
* \brief Tokenize a drawing string into a list of ass_drawing_token_t
* This also expands points for closing b-splines
*/
static ass_drawing_token_t *drawing_tokenize(char *str)
{
char *p = str;
int i, val, type = -1, is_set = 0;
FT_Vector point = {0, 0};
ass_drawing_token_t *root = NULL, *tail = NULL, *spline_start = NULL;
while (*p) {
if (*p == 'c' && spline_start) {
// Close b-splines: add the first three points of the b-spline
// back to the end
if (token_check_values(spline_start->next, 2, TOKEN_B_SPLINE)) {
for (i = 0; i < 3; i++) {
tail->next = calloc(1, sizeof(ass_drawing_token_t));
tail->next->prev = tail;
tail = tail->next;
tail->type = TOKEN_B_SPLINE;
tail->point = spline_start->point;
spline_start = spline_start->next;
}
spline_start = NULL;
}
} else if (!is_set && mystrtoi(&p, &val)) {
point.x = val;
is_set = 1;
p--;
} else if (is_set == 1 && mystrtoi(&p, &val)) {
point.y = val;
is_set = 2;
p--;
} else if (*p == 'm')
type = TOKEN_MOVE;
else if (*p == 'n')
type = TOKEN_MOVE_NC;
else if (*p == 'l')
type = TOKEN_LINE;
else if (*p == 'b')
type = TOKEN_CUBIC_BEZIER;
else if (*p == 'q')
type = TOKEN_CONIC_BEZIER;
else if (*p == 's')
type = TOKEN_B_SPLINE;
// We're simply ignoring TOKEN_EXTEND_B_SPLINE here.
// This is not harmful at all, since it can be ommitted with
// similar result (the spline is extended anyway).
if (type != -1 && is_set == 2) {
if (root) {
tail->next = calloc(1, sizeof(ass_drawing_token_t));
tail->next->prev = tail;
tail = tail->next;
} else
root = tail = calloc(1, sizeof(ass_drawing_token_t));
tail->type = type;
tail->point = point;
is_set = 0;
if (type == TOKEN_B_SPLINE && !spline_start)
spline_start = tail->prev;
}
p++;
}
#if 0
// Check tokens
ass_drawing_token_t *t = root;
while(t) {
printf("token %d point (%d, %d)\n", t->type, t->point.x, t->point.y);
t = t->next;
}
#endif
return root;
}
/*
* \brief Free a list of tokens
*/
static void drawing_free_tokens(ass_drawing_token_t *token)
{
while (token) {
ass_drawing_token_t *at = token;
token = token->next;
free(at);
}
}
/*
* \brief Translate and scale a point coordinate according to baseline
* offset and scale.
*/
static inline void translate_point(ass_drawing_t *drawing, FT_Vector *point)
{
point->x = drawing->point_scale_x * point->x;
point->y = drawing->point_scale_y * -point->y;
}
/*
* \brief Evaluate a curve into lines
* This curve evaluator is also used in VSFilter (RTS.cpp); it's a simple
* implementation of the De Casteljau algorithm.
*/
static void drawing_evaluate_curve(ass_drawing_t *drawing,
ass_drawing_token_t *token, char spline,
int started)
{
double cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
double t, h, max_accel, max_accel1, max_accel2;
FT_Vector cur = {0, 0};
cur = token->point;
translate_point(drawing, &cur);
int x0 = cur.x;
int y0 = cur.y;
token = token->next;
cur = token->point;
translate_point(drawing, &cur);
int x1 = cur.x;
int y1 = cur.y;
token = token->next;
cur = token->point;
translate_point(drawing, &cur);
int x2 = cur.x;
int y2 = cur.y;
token = token->next;
cur = token->point;
translate_point(drawing, &cur);
int x3 = cur.x;
int y3 = cur.y;
if (spline) {
// 1 [-1 +3 -3 +1]
// - * [+3 -6 +3 0]
// 6 [-3 0 +3 0]
// [+1 +4 +1 0]
double div6 = 1.0/6.0;
cx3 = div6*(- x0+3*x1-3*x2+x3);
cx2 = div6*( 3*x0-6*x1+3*x2);
cx1 = div6*(-3*x0 +3*x2);
cx0 = div6*( x0+4*x1+1*x2);
cy3 = div6*(- y0+3*y1-3*y2+y3);
cy2 = div6*( 3*y0-6*y1+3*y2);
cy1 = div6*(-3*y0 +3*y2);
cy0 = div6*( y0+4*y1+1*y2);
} else {
// [-1 +3 -3 +1]
// [+3 -6 +3 0]
// [-3 +3 0 0]
// [+1 0 0 0]
cx3 = - x0+3*x1-3*x2+x3;
cx2 = 3*x0-6*x1+3*x2;
cx1 = -3*x0+3*x1;
cx0 = x0;
cy3 = - y0+3*y1-3*y2+y3;
cy2 = 3*y0-6*y1+3*y2;
cy1 = -3*y0+3*y1;
cy0 = y0;
}
max_accel1 = fabs(2 * cy2) + fabs(6 * cy3);
max_accel2 = fabs(2 * cx2) + fabs(6 * cx3);
max_accel = FFMAX(max_accel1, max_accel2);
h = 1.0;
if (max_accel > CURVE_ACCURACY)
h = sqrt(CURVE_ACCURACY / max_accel);
if (!started) {
cur.x = cx0;
cur.y = cy0;
drawing_add_point(drawing, &cur);
}
for (t = 0; t < 1.0; t += h) {
cur.x = cx0 + t * (cx1 + t * (cx2 + t * cx3));
cur.y = cy0 + t * (cy1 + t * (cy2 + t * cy3));
drawing_add_point(drawing, &cur);
}
cur.x = cx0 + cx1 + cx2 + cx3;
cur.y = cy0 + cy1 + cy2 + cy3;
drawing_add_point(drawing, &cur);
}
/*
* \brief Create and initialize a new drawing and return it
*/
ass_drawing_t *ass_drawing_new(void *fontconfig_priv, ass_font_t *font,
ass_hinting_t hint, FT_Library lib)
{
ass_drawing_t* drawing;
drawing = calloc(1, sizeof(*drawing));
drawing->text = malloc(DRAWING_INITIAL_SIZE);
drawing->size = DRAWING_INITIAL_SIZE;
drawing->ftlibrary = lib;
drawing_make_glyph(drawing, fontconfig_priv, font, hint);
drawing->scale_x = 1.;
drawing->scale_y = 1.;
drawing->max_contours = GLYPH_INITIAL_CONTOURS;
drawing->max_points = GLYPH_INITIAL_POINTS;
return drawing;
}
/*
* \brief Free a drawing
*/
void ass_drawing_free(ass_drawing_t* drawing)
{
free(drawing->text);
free(drawing);
}
/*
* \brief Add one ASCII character to the drawing text buffer
*/
void ass_drawing_add_char(ass_drawing_t* drawing, char symbol)
{
drawing->text[drawing->i++] = symbol;
drawing->text[drawing->i] = 0;
if (drawing->i + 1 >= drawing->size) {
drawing->size *= 2;
drawing->text = realloc(drawing->text, drawing->size);
}
}
/*
* \brief Create a hashcode for the drawing
* XXX: To avoid collisions a better hash algorithm might be useful.
*/
void ass_drawing_hash(ass_drawing_t* drawing)
{
drawing->hash = fnv_32a_str(drawing->text, FNV1_32A_INIT);
}
/*
* \brief Convert token list to outline. Calls the line and curve evaluators.
*/
FT_OutlineGlyph *ass_drawing_parse(ass_drawing_t *drawing)
{
int started = 0;
ass_drawing_token_t *token;
FT_Vector pen = {0, 0};
drawing->tokens = drawing_tokenize(drawing->text);
drawing_prepare(drawing);
token = drawing->tokens;
while (token) {
// Draw something according to current command
switch (token->type) {
case TOKEN_MOVE_NC:
pen = token->point;
translate_point(drawing, &pen);
token = token->next;
break;
case TOKEN_MOVE:
pen = token->point;
translate_point(drawing, &pen);
if (started) {
drawing_close_shape(drawing);
started = 0;
}
token = token->next;
break;
case TOKEN_LINE: {
FT_Vector to;
to = token->point;
translate_point(drawing, &to);
if (!started) drawing_add_point(drawing, &pen);
drawing_add_point(drawing, &to);
started = 1;
token = token->next;
break;
}
case TOKEN_CUBIC_BEZIER:
if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) &&
token->prev) {
drawing_evaluate_curve(drawing, token->prev, 0, started);
token = token->next;
token = token->next;
token = token->next;
started = 1;
} else
token = token->next;
break;
case TOKEN_B_SPLINE:
if (token_check_values(token, 3, TOKEN_B_SPLINE) &&
token->prev) {
drawing_evaluate_curve(drawing, token->prev, 1, started);
token = token->next;
started = 1;
} else
token = token->next;
break;
default:
token = token->next;
break;
}
}
drawing_finish(drawing);
drawing_free_tokens(drawing->tokens);
return &drawing->glyph;
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* This file is part of libass.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LIBASS_DRAWING_H
#define LIBASS_DRAWING_H
#include <ft2build.h>
#include FT_GLYPH_H
#include "ass.h"
#define DRAWING_INITIAL_SIZE 256
enum ass_token_type {
TOKEN_MOVE,
TOKEN_MOVE_NC,
TOKEN_LINE,
TOKEN_CUBIC_BEZIER,
TOKEN_CONIC_BEZIER,
TOKEN_B_SPLINE,
TOKEN_EXTEND_SPLINE,
TOKEN_CLOSE
};
typedef struct ass_drawing_token_s {
enum ass_token_type type;
FT_Vector point;
struct ass_drawing_token_s *next;
struct ass_drawing_token_s *prev;
} ass_drawing_token_t;
typedef struct ass_drawing_s {
char *text; // drawing string
int i; // text index
int scale; // scale (1-64) for subpixel accuracy
double pbo; // drawing will be shifted in y direction by this amount
double scale_x; // FontScaleX
double scale_y; // FontScaleY
int asc; // ascender
int desc; // descender
FT_OutlineGlyph glyph; // the "fake" glyph created for later rendering
int hash; // hash value (for caching)
// private
FT_Library ftlibrary; // FT library instance, needed for font ops
int size; // current buffer size
ass_drawing_token_t *tokens; // tokenized drawing
int max_points; // current maximum size
int max_contours;
double point_scale_x;
double point_scale_y;
} ass_drawing_t;
ass_drawing_t *ass_drawing_new(void *fontconfig_priv, ass_font_t *font,
ass_hinting_t hint, FT_Library lib);
void ass_drawing_free(ass_drawing_t* drawing);
void ass_drawing_add_char(ass_drawing_t* drawing, char symbol);
void ass_drawing_hash(ass_drawing_t* drawing);
FT_OutlineGlyph *ass_drawing_parse(ass_drawing_t *drawing);
#endif /* LIBASS_DRAWING_H */

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -36,7 +34,6 @@
#include "ass_cache.h"
#include "ass_fontconfig.h"
#include "ass_utils.h"
#include "mputils.h"
/**
* Select Microfost Unicode CharMap, if the font has one.
@ -49,7 +46,9 @@ static void charmap_magic(FT_Face face)
FT_CharMap cmap = face->charmaps[i];
unsigned pid = cmap->platform_id;
unsigned eid = cmap->encoding_id;
if (pid == 3 /*microsoft*/ && (eid == 1 /*unicode bmp*/ || eid == 10 /*full unicode*/)) {
if (pid == 3 /*microsoft */
&& (eid == 1 /*unicode bmp */
|| eid == 10 /*full unicode */ )) {
FT_Set_Charmap(face, cmap);
return;
}
@ -57,10 +56,10 @@ static void charmap_magic(FT_Face face)
if (!face->charmap) {
if (face->num_charmaps == 0) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoCharmaps);
ass_msg(MSGL_WARN, MSGTR_LIBASS_NoCharmaps);
return;
}
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoCharmapAutodetected);
ass_msg(MSGL_WARN, MSGTR_LIBASS_NoCharmapAutodetected);
FT_Set_Charmap(face, face->charmaps[0]);
return;
}
@ -125,21 +124,33 @@ static int add_face(void* fc_priv, ass_font_t* font, uint32_t ch)
if (font->n_faces == ASS_FONT_MAX_FACES)
return -1;
path = fontconfig_select(fc_priv, font->desc.family, font->desc.treat_family_as_pattern, font->desc.bold,
font->desc.italic, &index, ch);
path =
fontconfig_select(fc_priv, font->desc.family,
font->desc.treat_family_as_pattern,
font->desc.bold, font->desc.italic, &index, ch);
if (!path)
return -1;
mem_idx = find_font(font->library, path);
if (mem_idx >= 0) {
error = FT_New_Memory_Face(font->ftlibrary, (unsigned char*)font->library->fontdata[mem_idx].data,
font->library->fontdata[mem_idx].size, 0, &face);
error =
FT_New_Memory_Face(font->ftlibrary,
(unsigned char *) font->library->
fontdata[mem_idx].data,
font->library->fontdata[mem_idx].size, 0,
&face);
if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, path);
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont,
path);
free(path);
return -1;
}
} else {
error = FT_New_Face(font->ftlibrary, path, index, &face);
if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, index);
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path,
index);
free(path);
return -1;
}
}
@ -149,19 +160,22 @@ static int add_face(void* fc_priv, ass_font_t* font, uint32_t ch)
font->faces[font->n_faces++] = face;
update_transform(font);
face_set_size(face, font->size);
free(path);
return font->n_faces - 1;
}
/**
* \brief Create a new ass_font_t according to "desc" argument
*/
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc)
ass_font_t *ass_font_new(void *font_cache, ass_library_t *library,
FT_Library ftlibrary, void *fc_priv,
ass_font_desc_t *desc)
{
int error;
ass_font_t *fontp;
ass_font_t font;
fontp = ass_font_cache_find(desc);
fontp = ass_font_cache_find((hashmap_t *) font_cache, desc);
if (fontp)
return fontp;
@ -182,13 +196,14 @@ ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_
free(font.desc.family);
return 0;
} else
return ass_font_cache_add(&font);
return ass_font_cache_add((hashmap_t *) font_cache, &font);
}
/**
* \brief Set font transformation matrix and shift vector
**/
void ass_font_set_transform(ass_font_t* font, double scale_x, double scale_y, FT_Vector* v)
void ass_font_set_transform(ass_font_t *font, double scale_x,
double scale_y, FT_Vector *v)
{
font->scale_x = scale_x;
font->scale_y = scale_y;
@ -245,7 +260,8 @@ void ass_font_set_size(ass_font_t* font, double size)
* \param ch character code
* The values are extracted from the font face that provides glyphs for the given character
**/
void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc)
void ass_font_get_asc_desc(ass_font_t *font, uint32_t ch, int *asc,
int *desc)
{
int i;
for (i = 0; i < font->n_faces; ++i) {
@ -260,11 +276,93 @@ void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc)
*asc = *desc = 0;
}
/*
* Strike a glyph with a horizontal line; it's possible to underline it
* and/or strike through it. For the line's position and size, truetype
* tables are consulted. Obviously this relies on the data in the tables
* being accurate.
*
*/
static int ass_strike_outline_glyph(FT_Face face, ass_font_t *font,
FT_Glyph glyph, int under, int through)
{
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
TT_Postscript *ps = FT_Get_Sfnt_Table(face, ft_sfnt_post);
FT_Outline *ol = &((FT_OutlineGlyph) glyph)->outline;
int bear, advance, y_scale, i;
// Grow outline
i = (under ? 4 : 0) + (through ? 4 : 0);
ol->points = realloc(ol->points, sizeof(FT_Vector) *
(ol->n_points + i));
ol->tags = realloc(ol->tags, ol->n_points + i);
i = !!under + !!through;
ol->contours = realloc(ol->contours, sizeof(short) *
(ol->n_contours + i));
// If the bearing is negative, the glyph starts left of the current
// pen position
bear = FFMIN(face->glyph->metrics.horiBearingX, 0);
// We're adding half a pixel to avoid small gaps
advance = d16_to_d6(glyph->advance.x) + 32;
y_scale = face->size->metrics.y_scale;
// Add points to the outline
if (under) {
int pos, size;
pos = FT_MulFix(ps->underlinePosition, y_scale * font->scale_y);
size = FT_MulFix(ps->underlineThickness,
y_scale * font->scale_y / 2);
if (pos > 0 || size <= 0)
return 0;
FT_Vector points[4] = {
{.x = bear, .y = pos + size},
{.x = advance, .y = pos + size},
{.x = advance, .y = pos - size},
{.x = bear, .y = pos - size},
};
for (i = 0; i < 4; i++) {
ol->points[ol->n_points] = points[i];
ol->tags[ol->n_points++] = 1;
}
ol->contours[ol->n_contours++] = ol->n_points - 1;
}
if (through) {
int pos, size;
pos = FT_MulFix(os2->yStrikeoutPosition, y_scale * font->scale_y);
size = FT_MulFix(os2->yStrikeoutSize, y_scale * font->scale_y / 2);
if (pos < 0 || size <= 0)
return 0;
FT_Vector points[4] = {
{.x = bear, .y = pos + size},
{.x = advance, .y = pos + size},
{.x = advance, .y = pos - size},
{.x = bear, .y = pos - size},
};
for (i = 0; i < 4; i++) {
ol->points[ol->n_points] = points[i];
ol->tags[ol->n_points++] = 1;
}
ol->contours[ol->n_contours++] = ol->n_points - 1;
}
return 1;
}
/**
* \brief Get a glyph
* \param ch character code
**/
FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting)
FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font,
uint32_t ch, ass_hinting_t hinting, int deco)
{
int error;
int index = 0;
@ -288,33 +386,42 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch
#ifdef CONFIG_FONTCONFIG
if (index == 0) {
int face_idx;
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont,
ch, font->desc.family, font->desc.bold, font->desc.italic);
ass_msg(MSGL_INFO,
MSGTR_LIBASS_GlyphNotFoundReselectingFont, 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) {
mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound,
ch, font->desc.family, font->desc.bold, font->desc.italic);
ass_msg(MSGL_ERR, MSGTR_LIBASS_GlyphNotFound,
ch, font->desc.family, font->desc.bold,
font->desc.italic);
}
}
}
#endif
switch (hinting) {
case ASS_HINTING_NONE: flags = FT_LOAD_NO_HINTING; break;
case ASS_HINTING_LIGHT: flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; break;
case ASS_HINTING_NORMAL: flags = FT_LOAD_FORCE_AUTOHINT; break;
case ASS_HINTING_NATIVE: flags = 0; break;
case ASS_HINTING_NONE:
flags = FT_LOAD_NO_HINTING;
break;
case ASS_HINTING_LIGHT:
flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
break;
case ASS_HINTING_NORMAL:
flags = FT_LOAD_FORCE_AUTOHINT;
break;
case ASS_HINTING_NATIVE:
flags = 0;
break;
}
error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
return 0;
}
#if (FREETYPE_MAJOR > 2) || \
((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \
((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10))
@ -326,10 +433,13 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch
#endif
error = FT_Get_Glyph(face->glyph, &glyph);
if (error) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
return 0;
}
ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE,
deco & DECO_STRIKETHROUGH);
return glyph;
}
@ -363,7 +473,9 @@ void ass_font_free(ass_font_t* font)
{
int i;
for (i = 0; i < font->n_faces; ++i)
if (font->faces[i]) FT_Done_Face(font->faces[i]);
if (font->desc.family) free(font->desc.family);
if (font->faces[i])
FT_Done_Face(font->faces[i]);
if (font->desc.family)
free(font->desc.family);
free(font);
}

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -29,6 +27,10 @@
#include "ass.h"
#include "ass_types.h"
#define ASS_FONT_MAX_FACES 10
#define DECO_UNDERLINE 1
#define DECO_STRIKETHROUGH 2
typedef struct ass_font_desc_s {
char *family;
unsigned bold;
@ -36,8 +38,6 @@ typedef struct ass_font_desc_s {
int treat_family_as_pattern;
} ass_font_desc_t;
#define ASS_FONT_MAX_FACES 10
typedef struct ass_font_s {
ass_font_desc_t desc;
ass_library_t *library;
@ -49,11 +49,17 @@ typedef struct ass_font_s {
double size;
} ass_font_t;
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc);
void ass_font_set_transform(ass_font_t* font, double scale_x, double scale_y, FT_Vector* v);
// FIXME: passing the hashmap via a void pointer is very ugly.
ass_font_t *ass_font_new(void *font_cache, ass_library_t *library,
FT_Library ftlibrary, void *fc_priv,
ass_font_desc_t *desc);
void ass_font_set_transform(ass_font_t *font, double scale_x,
double scale_y, FT_Vector * v);
void ass_font_set_size(ass_font_t *font, double size);
void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc);
FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting);
void ass_font_get_asc_desc(ass_font_t *font, uint32_t ch, int *asc,
int *desc);
FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font,
uint32_t ch, ass_hinting_t hinting, int flags);
FT_Vector ass_font_get_kerning(ass_font_t *font, uint32_t c1, uint32_t c2);
void ass_font_free(ass_font_t *font);

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -32,16 +30,11 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include "mputils.h"
#include "ass_utils.h"
#include "ass.h"
#include "ass_library.h"
#include "ass_fontconfig.h"
#ifdef BUILD_DARWIN
#include "../src/libosxutil/libosxutil.h"
#include <sys/param.h>
#endif
#ifdef CONFIG_FONTCONFIG
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@ -78,8 +71,9 @@ 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(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;
@ -91,7 +85,7 @@ static char* _select_font(fc_instance_t* priv, const char* family, int treat_fam
FcFontSet *fset = NULL;
int curf;
char *retval = NULL;
int family_cnt;
int family_cnt = 0;
*index = 0;
@ -199,7 +193,8 @@ static char* _select_font(fc_instance_t* priv, const char* family, int treat_fam
if (!treat_family_as_pattern &&
!(r_family && strcasecmp((const char *) r_family, family) == 0) &&
!(r_fullname && strcasecmp((const char *) r_fullname, family) == 0))
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne,
ass_msg(MSGL_WARN,
MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne,
(const char *) (r_fullname ? r_fullname : r_family), family);
result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
@ -218,15 +213,19 @@ static char* _select_font(fc_instance_t* priv, const char* family, int treat_fam
if (result != FcResultMatch)
r_embolden = 0;
mp_msg(MSGT_ASS, MSGL_V, "[ass] Font info: family '%s', style '%s', fullname '%s',"
" slant %d, weight %d%s\n",
(const char*)r_family, (const char*)r_style, (const char*)r_fullname,
r_slant, r_weight, r_embolden ? ", embolden" : "");
ass_msg(MSGL_V,
"[ass] Font info: family '%s', style '%s', fullname '%s',"
" slant %d, weight %d%s\n", (const char *) r_family,
(const char *) r_style, (const char *) r_fullname, r_slant,
r_weight, r_embolden ? ", embolden" : "");
error:
if (pat) FcPatternDestroy(pat);
if (rpat) FcPatternDestroy(rpat);
if (fset) FcFontSetDestroy(fset);
if (pat)
FcPatternDestroy(pat);
if (rpat)
FcPatternDestroy(rpat);
if (fset)
FcFontSetDestroy(fset);
return retval;
}
@ -241,8 +240,9 @@ static char* _select_font(fc_instance_t* priv, const char* family, int treat_fam
* \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(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) {
@ -250,28 +250,33 @@ char* fontconfig_select(fc_instance_t* priv, const char* family, int treat_famil
return priv->path_default;
}
if (family && *family)
res = _select_font(priv, family, treat_family_as_pattern, bold, italic, index, code);
res =
_select_font(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);
res =
_select_font(priv, priv->family_default, 0, bold, italic, index,
code);
if (res)
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily,
ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily,
family, bold, italic, res, *index);
}
if (!res && priv->path_default) {
res = priv->path_default;
*index = priv->index_default;
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFont,
ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingDefaultFont,
family, bold, italic, res, *index);
}
if (!res) {
res = _select_font(priv, "Arial", 0, bold, italic, index, code);
if (res)
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily,
ass_msg(MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily,
family, bold, italic, res, *index);
}
if (res)
mp_msg(MSGT_ASS, MSGL_V, "fontconfig_select: (%s, %d, %d) -> %s, %d\n",
family, bold, italic, res, *index);
ass_msg(MSGL_V,
"fontconfig_select: (%s, %d, %d) -> %s, %d\n", family, bold,
italic, res, *index);
return res;
}
@ -287,7 +292,7 @@ static char* validate_fname(char* name)
q = fname = malloc(sz + 1);
p = name;
while (*p) {
code = utf8_get_char(&p);
code = ass_utf8_get_char(&p);
if (code == 0)
break;
if ((code > 0x7F) ||
@ -297,10 +302,7 @@ static char* validate_fname(char* name)
(code == '*') ||
(code == '?') ||
(code == '<') ||
(code == '>') ||
(code == '|') ||
(code == 0))
{
(code == '>') || (code == '|') || (code == 0)) {
*q++ = '_';
} else {
*q++ = code;
@ -322,7 +324,8 @@ static char* validate_fname(char* name)
* With FontConfig >= 2.4.2, builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace.
* With older FontConfig versions, save the font to ~/.mplayer/fonts.
*/
static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Library ftlibrary, int idx)
static void process_fontdata(fc_instance_t *priv, ass_library_t *library,
FT_Library ftlibrary, int idx)
{
int rc;
const char *name = library->fontdata[idx].name;
@ -347,10 +350,11 @@ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Lib
res = mkdir(fonts_dir);
#endif
if (res) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FailedToCreateDirectory, fonts_dir);
ass_msg(MSGL_WARN,
MSGTR_LIBASS_FailedToCreateDirectory, fonts_dir);
}
} else if (!S_ISDIR(st.st_mode)) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NotADirectory, fonts_dir);
ass_msg(MSGL_WARN, MSGTR_LIBASS_NotADirectory, fonts_dir);
}
fname = validate_fname((char *) name);
@ -359,7 +363,8 @@ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Lib
free(fname);
fp = fopen(buf, "wb");
if (!fp) return;
if (!fp)
return;
fwrite(data, data_size, 1, fp);
fclose(fp);
@ -372,30 +377,37 @@ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Lib
int face_index, num_faces = 1;
for (face_index = 0; face_index < num_faces; ++face_index) {
rc = FT_New_Memory_Face(ftlibrary, (unsigned char*)data, data_size, face_index, &face);
rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data,
data_size, face_index, &face);
if (rc) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, name);
ass_msg(MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont,
name);
return;
}
num_faces = face->num_faces;
pattern = FcFreeTypeQueryFace(face, (unsigned char*)name, 0, FcConfigGetBlanks(priv->config));
pattern =
FcFreeTypeQueryFace(face, (unsigned char *) name, 0,
FcConfigGetBlanks(priv->config));
if (!pattern) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcFreeTypeQueryFace");
ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed,
"FcFreeTypeQueryFace");
FT_Done_Face(face);
return;
}
fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication
if (!fset) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcConfigGetFonts");
ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed,
"FcConfigGetFonts");
FT_Done_Face(face);
return;
}
res = FcFontSetAdd(fset, pattern);
if (!res) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcFontSetAdd");
ass_msg(MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed,
"FcFontSetAdd");
FT_Done_Face(face);
return;
}
@ -413,41 +425,36 @@ static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Lib
* \param path default font path
* \return pointer to fontconfig private data
*/
fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path, int fc)
fc_instance_t *fontconfig_init(ass_library_t *library,
FT_Library ftlibrary, const char *family,
const char *path, int fc, const char *config)
{
int rc;
fc_instance_t *priv = calloc(1, sizeof(fc_instance_t));
const char *dir = library->fonts_dir;
#ifdef BUILD_DARWIN
char config_path[MAXPATHLEN];
char *config_dir;
#endif
int i;
if (!fc) {
mp_msg(MSGT_ASS, MSGL_WARN,
ass_msg(MSGL_WARN,
MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed);
goto exit;
}
#ifdef BUILD_DARWIN
config_dir = OSX_GetBundleResourcesDirectory();
snprintf(config_path, MAXPATHLEN, "%s/etc/fonts/fonts.conf", config_dir);
free(config_dir);
if (config) {
priv->config = FcConfigCreate();
rc = FcConfigParseAndLoad(priv->config, config_path, FcTrue);
rc = FcConfigParseAndLoad(priv->config, (unsigned char *)config,
FcTrue);
FcConfigBuildFonts(priv->config);
FcConfigSetCurrent(priv->config);
if (!rc) {
#else
} else {
rc = FcInit();
assert(rc);
priv->config = FcConfigGetCurrent();
if (!priv->config) {
#endif
mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed);
}
if (!rc || !priv->config) {
ass_msg(MSGL_FATAL,
MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed);
goto exit;
}
@ -455,11 +462,10 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
process_fontdata(priv, library, ftlibrary, i);
if (dir) {
if (FcDirCacheValid((const FcChar8 *)dir) == FcFalse)
{
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_UpdatingFontCache);
if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) {
ass_msg(MSGL_INFO, MSGTR_LIBASS_UpdatingFontCache);
if (FcGetVersion() >= 20390 && FcGetVersion() < 20400)
mp_msg(MSGT_ASS, MSGL_WARN,
ass_msg(MSGL_WARN,
MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported);
// FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir()
if (FcGetVersion() < 20390) {
@ -469,20 +475,23 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
fss = FcStrSetCreate();
rc = FcStrSetAdd(fss, (const FcChar8 *) dir);
if (!rc) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcStrSetAddFailed);
ass_msg(MSGL_WARN,
MSGTR_LIBASS_FcStrSetAddFailed);
goto ErrorFontCache;
}
rc = FcDirScan(fcs, fss, NULL, FcConfigGetBlanks(priv->config),
rc = FcDirScan(fcs, fss, NULL,
FcConfigGetBlanks(priv->config),
(const FcChar8 *) dir, FcFalse);
if (!rc) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcDirScanFailed);
ass_msg(MSGL_WARN,
MSGTR_LIBASS_FcDirScanFailed);
goto ErrorFontCache;
}
rc = FcDirSave(fcs, fss, (const FcChar8 *) dir);
if (!rc) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcDirSave);
ass_msg(MSGL_WARN, MSGTR_LIBASS_FcDirSave);
goto ErrorFontCache;
}
ErrorFontCache:
@ -492,7 +501,8 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
if (!rc) {
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcConfigAppFontAddDirFailed);
ass_msg(MSGL_WARN,
MSGTR_LIBASS_FcConfigAppFontAddDirFailed);
}
}
@ -506,18 +516,22 @@ exit:
#else /* CONFIG_FONTCONFIG */
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(fc_instance_t *priv, const char *family,
int treat_family_as_pattern, unsigned bold,
unsigned italic, int *index, uint32_t code)
{
*index = priv->index_default;
return priv->path_default;
}
fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path, int fc)
fc_instance_t *fontconfig_init(ass_library_t *library,
FT_Library ftlibrary, const char *family,
const char *path, int fc)
{
fc_instance_t *priv;
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed);
ass_msg(MSGL_WARN,
MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed);
priv = calloc(1, sizeof(fc_instance_t));
@ -531,9 +545,10 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
void fontconfig_done(fc_instance_t *priv)
{
// don't call FcFini() here, library can still be used by some code
if (priv && priv->path_default) free(priv->path_default);
if (priv && priv->family_default) free(priv->family_default);
if (priv) free(priv);
if (priv && priv->path_default)
free(priv->path_default);
if (priv && priv->family_default)
free(priv->family_default);
if (priv)
free(priv);
}

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -34,8 +32,12 @@
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);
char* fontconfig_select(fc_instance_t* priv, const char* family, int treat_family_as_pattern, unsigned bold, unsigned italic, int* index, uint32_t code);
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);
void fontconfig_done(fc_instance_t *priv);
#endif /* LIBASS_FONTCONFIG_H */

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -69,9 +67,11 @@ void ass_set_style_overrides(ass_library_t* priv, char** list)
free(priv->style_overrides);
}
if (!list) return;
if (!list)
return;
for (p = list, cnt = 0; *p; ++p, ++cnt) {}
for (p = list, cnt = 0; *p; ++p, ++cnt) {
}
priv->style_overrides = malloc((cnt + 1) * sizeof(char *));
for (p = list, q = priv->style_overrides; *p; ++p, ++q)
@ -90,7 +90,8 @@ void ass_add_font(ass_library_t* priv, char* name, char* data, int size)
int idx = priv->num_fontdata;
if (!name || !data || !size)
return;
grow_array((void**)&priv->fontdata, priv->num_fontdata, sizeof(*priv->fontdata));
grow_array((void **) &priv->fontdata, priv->num_fontdata,
sizeof(*priv->fontdata));
priv->fontdata[idx].name = strdup(name);

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -99,7 +97,8 @@ typedef struct ass_track_s {
char *style_format; // style format line (everything after "Format: ")
char *event_format; // event format line
enum {TRACK_TYPE_UNKNOWN = 0, TRACK_TYPE_ASS, TRACK_TYPE_SSA} track_type;
enum { TRACK_TYPE_UNKNOWN =
0, TRACK_TYPE_ASS, TRACK_TYPE_SSA } track_type;
// script header fields
int PlayResX;

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -27,7 +25,6 @@
#include <ft2build.h>
#include FT_GLYPH_H
#include "mputils.h"
#include "ass_utils.h"
int mystrtoi(char **p, int *res)
@ -36,9 +33,11 @@ int mystrtoi(char** p, int* res)
double temp_res;
char *start = *p;
temp_res = strtod(*p, p);
*res = (int) (temp_res + 0.5);
if (*p != start) return 1;
else return 0;
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
if (*p != start)
return 1;
else
return 0;
}
int mystrtoll(char **p, long long *res)
@ -46,25 +45,31 @@ int mystrtoll(char** p, long long* res)
double temp_res;
char *start = *p;
temp_res = strtod(*p, p);
*res = (long long) (temp_res + 0.5);
if (*p != start) return 1;
else return 0;
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
if (*p != start)
return 1;
else
return 0;
}
int mystrtou32(char **p, int base, uint32_t *res)
{
char *start = *p;
*res = strtoll(*p, p, base);
if (*p != start) return 1;
else return 0;
if (*p != start)
return 1;
else
return 0;
}
int mystrtod(char **p, double *res)
{
char *start = *p;
*res = strtod(*p, p);
if (*p != start) return 1;
else return 0;
if (*p != start)
return 1;
else
return 0;
}
int strtocolor(char **q, uint32_t *res)
@ -73,8 +78,10 @@ int strtocolor(char** q, uint32_t* res)
int result;
char *p = *q;
if (*p == '&') ++p;
else mp_msg(MSGT_ASS, MSGL_DBG2, "suspicious color format: \"%s\"\n", p);
if (*p == '&')
++p;
else
ass_msg(MSGL_DBG2, "suspicious color format: \"%s\"\n", p);
if (*p == 'H' || *p == 'h') {
++p;
@ -86,10 +93,15 @@ int strtocolor(char** q, uint32_t* res)
{
unsigned char *tmp = (unsigned char *) (&color);
unsigned char b;
b = tmp[0]; tmp[0] = tmp[3]; tmp[3] = b;
b = tmp[1]; tmp[1] = tmp[2]; tmp[2] = b;
b = tmp[0];
tmp[0] = tmp[3];
tmp[3] = b;
b = tmp[1];
tmp[1] = tmp[2];
tmp[2] = b;
}
if (*p == '&') ++p;
if (*p == '&')
++p;
*q = p;
*res = color;
@ -97,7 +109,8 @@ int strtocolor(char** q, uint32_t* res)
}
// Return a boolean value for a string
char parse_bool(char* str) {
char parse_bool(char *str)
{
while (*str == ' ' || *str == '\t')
str++;
if (!strncasecmp(str, "yes", 3))
@ -107,29 +120,206 @@ char parse_bool(char* str) {
return 0;
}
#if 0
static void sprint_tag(uint32_t tag, char* dst)
void ass_msg(int lvl, char *fmt, ...)
{
dst[0] = (tag >> 24) & 0xFF;
dst[1] = (tag >> 16) & 0xFF;
dst[2] = (tag >> 8) & 0xFF;
dst[3] = tag & 0xFF;
dst[4] = 0;
va_list va;
if (lvl > MSGL_INFO)
return;
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
}
void dump_glyph(FT_Glyph g)
unsigned ass_utf8_get_char(char **str)
{
char tag[5];
int i;
FT_OutlineGlyph og = (FT_OutlineGlyph)g;
FT_Outline* o = &(og->outline);
sprint_tag(g->format, tag);
printf("glyph: %p \n", g);
printf("format: %s \n", tag);
printf("outline: %p \n", o);
printf("contours: %d, points: %d, points ptr: %p \n", o->n_contours, o->n_points, o->points);
for (i = 0; i < o->n_points; ++i) {
printf(" point %f, %f \n", d6_to_double(o->points[i].x), d6_to_double(o->points[i].y));
uint8_t *strp = (uint8_t *) * str;
unsigned c = *strp++;
unsigned mask = 0x80;
int len = -1;
while (c & mask) {
mask >>= 1;
len++;
}
if (len <= 0 || len > 4)
goto no_utf8;
c &= mask - 1;
while ((*strp & 0xc0) == 0x80) {
if (len-- <= 0)
goto no_utf8;
c = (c << 6) | (*strp++ & 0x3f);
}
if (len)
goto no_utf8;
*str = (char *) strp;
return c;
no_utf8:
strp = (uint8_t *) * str;
c = *strp++;
*str = (char *) strp;
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)
{
const char **languages;
size_t langcnt;
EncaAnalyser analyser;
EncaEncoding encoding;
char *detected_sub_cp = NULL;
int i;
languages = enca_get_languages(&langcnt);
ass_msg(MSGL_V, "ENCA supported languages: ");
for (i = 0; i < langcnt; i++) {
ass_msg(MSGL_V, "%s ", languages[i]);
}
ass_msg(MSGL_V, "\n");
for (i = 0; i < langcnt; i++) {
const char *tmp;
if (strcasecmp(languages[i], preferred_language) != 0)
continue;
analyser = enca_analyser_alloc(languages[i]);
encoding = enca_analyse_const(analyser, buffer, 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);
}
enca_analyser_free(analyser);
}
free(languages);
if (!detected_sub_cp) {
detected_sub_cp = strdup(fallback);
ass_msg(MSGL_INFO,
"ENCA detection failed: fallback to %s\n", fallback);
}
return detected_sub_cp;
}
#endif

View file

@ -1,5 +1,3 @@
// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
// vim:ts=8:sw=8:noet:ai:
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
@ -23,7 +21,28 @@
#ifndef LIBASS_UTILS_H
#define LIBASS_UTILS_H
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef CONFIG_ENCA
#include <enca.h>
#endif
#include "help_mp.h"
#define MSGL_FATAL 0
#define MSGL_ERR 1
#define MSGL_WARN 2
#define MSGL_INFO 4
#define MSGL_V 6
#define MSGL_DBG2 7
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
int mystrtoi(char **p, int *res);
int mystrtoll(char **p, long long *res);
@ -31,36 +50,79 @@ int mystrtou32(char** p, int base, uint32_t* res);
int mystrtod(char **p, double *res);
int strtocolor(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);
static inline int d6_to_int(int x) {
static inline int d6_to_int(int x)
{
return (x + 32) >> 6;
}
static inline int d16_to_int(int x) {
static inline int d16_to_int(int x)
{
return (x + 32768) >> 16;
}
static inline int int_to_d6(int x) {
static inline int int_to_d6(int x)
{
return x << 6;
}
static inline int int_to_d16(int x) {
static inline int int_to_d16(int x)
{
return x << 16;
}
static inline int d16_to_d6(int x) {
static inline int d16_to_d6(int x)
{
return (x + 512) >> 10;
}
static inline int d6_to_d16(int x) {
static inline int d6_to_d16(int x)
{
return x << 10;
}
static inline double d6_to_double(int x) {
static inline double d6_to_double(int x)
{
return x / 64.;
}
static inline int double_to_d6(double x) {
static inline int double_to_d6(double x)
{
return (int) (x * 64);
}
static inline double d16_to_double(int x) {
static inline double d16_to_double(int x)
{
return ((double) x) / 0x10000;
}
static inline int double_to_d16(double x) {
static inline int double_to_d16(double x)
{
return (int) (x * 0x10000);
}
#define FNV1_32A_INIT (unsigned)0x811c9dc5
static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval)
{
unsigned char *bp = buf;
unsigned char *be = bp + len;
while (bp < be) {
hval ^= (unsigned) *bp++;
hval +=
(hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) +
(hval << 24);
}
return hval;
}
static inline unsigned fnv_32a_str(char *str, unsigned hval)
{
unsigned char *s = (unsigned char *) str;
while (*s) {
hval ^= (unsigned) *s++;
hval +=
(hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) +
(hval << 24);
}
return hval;
}
#endif /* LIBASS_UTILS_H */

View file

@ -2,6 +2,7 @@
#define __LIBASS_HELP_MP_H__
#define MSGTR_LIBASS_FT_Glyph_To_BitmapError "[ass] FT_Glyph_To_Bitmap error %d \n"
#define MSGTR_LIBASS_UnsupportedPixelMode "[ass] Unsupported pixel mode: %d\n"
#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n"
#define MSGTR_LIBASS_NoStyleNamedXFoundUsingY "[ass] [%p] Warning: no style named '%s' found, using '%s'\n"
#define MSGTR_LIBASS_BadTimestamp "[ass] bad timestamp\n"
#define MSGTR_LIBASS_BadEncodedDataSize "[ass] bad encoded data size\n"
@ -19,7 +20,7 @@
#define MSGTR_LIBASS_NotADirectory "[ass] Not a directory: %s\n"
#define MSGTR_LIBASS_TooManyFonts "[ass] Too many fonts\n"
#define MSGTR_LIBASS_ErrorOpeningFont "[ass] Error opening font: %s, %d\n"
#define MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne "[ass] fontconfig: Selected font family is not the requested one: '%s' != '%s'\n"
#define MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne "[ass] fontconfig: Selected font is not the requested one: '%s' != '%s'\n"
#define MSGTR_LIBASS_UsingDefaultFontFamily "[ass] fontconfig_select: Using default font family: (%s, %d, %d) -> %s, %d\n"
#define MSGTR_LIBASS_UsingDefaultFont "[ass] fontconfig_select: Using default font: (%s, %d, %d) -> %s, %d\n"
#define MSGTR_LIBASS_UsingArialFontFamily "[ass] fontconfig_select: Using 'Arial' font family: (%s, %d, %d) -> %s, %d\n"
@ -46,11 +47,9 @@
#define MSGTR_LIBASS_EmptyEvent "[ass] Empty event!\n"
#define MSGTR_LIBASS_MAX_GLYPHS_Reached "[ass] MAX_GLYPHS reached: event %d, start = %llu, duration = %llu\n Text = %s\n"
#define MSGTR_LIBASS_EventHeightHasChanged "[ass] Warning! Event height has changed! \n"
#define MSGTR_LIBASS_GlyphNotFoundReselectingFont "[ass] Glyph 0x%X not found, reselecting font for (%s, %d, %d)\n"
#define MSGTR_LIBASS_GlyphNotFoundReselectingFont "[ass] Glyph 0x%X not found, selecting one more font for (%s, %d, %d)\n"
#define MSGTR_LIBASS_GlyphNotFound "[ass] Glyph 0x%X not found in font for (%s, %d, %d)\n"
#define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n"
#define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n"
#define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n"
#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n"
#endif

View file

@ -73,7 +73,7 @@ LibassSubtitlesProvider::LibassSubtitlesProvider() {
ass_renderer = ass_renderer_init(ass_library);
if (!ass_renderer) throw _T("ass_renderer_init failed");
ass_set_font_scale(ass_renderer, 1.);
ass_set_fonts(ass_renderer, NULL, "Sans");
ass_set_fonts(ass_renderer, NULL, "Sans", 1, NULL);
}