Update libass to commit 8db4a5.

Originally committed to SVN as r3970.
This commit is contained in:
Grigori Goronzy 2010-01-10 21:09:48 +00:00
parent 7e079a3fc2
commit e341e05fa2
14 changed files with 433 additions and 280 deletions

View file

@ -16,6 +16,7 @@ libass_aegisub_a_SOURCES = \
ass_library.c \ ass_library.c \
ass_parse.c \ ass_parse.c \
ass_render.c \ ass_render.c \
ass_strtod.c \
ass_utils.c ass_utils.c
libass_aegisub_a_SOURCES += \ libass_aegisub_a_SOURCES += \

View file

@ -389,6 +389,8 @@ void ass_process_force_style(ASS_Track *track)
track->WrapStyle = atoi(token); track->WrapStyle = atoi(token);
else if (!strcasecmp(*fs, "ScaledBorderAndShadow")) else if (!strcasecmp(*fs, "ScaledBorderAndShadow"))
track->ScaledBorderAndShadow = parse_bool(token); track->ScaledBorderAndShadow = parse_bool(token);
else if (!strcasecmp(*fs, "Kerning"))
track->Kerning = parse_bool(token);
dt = strrchr(*fs, '.'); dt = strrchr(*fs, '.');
if (dt) { if (dt) {
@ -571,6 +573,8 @@ static int process_info_line(ASS_Track *track, char *str)
track->WrapStyle = atoi(str + 10); track->WrapStyle = atoi(str + 10);
} else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) {
track->ScaledBorderAndShadow = parse_bool(str + 22); track->ScaledBorderAndShadow = parse_bool(str + 22);
} else if (!strncmp(str, "Kerning:", 8)) {
track->Kerning = parse_bool(str + 8);
} }
return 0; return 0;
} }
@ -1096,12 +1100,13 @@ ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
return 0; return 0;
#ifdef CONFIG_ICONV #ifdef CONFIG_ICONV
if (codepage) if (codepage) {
buf = sub_recode(library, buf, bufsize, codepage); buf = sub_recode(library, buf, bufsize, codepage);
if (!buf) if (!buf)
return 0; return 0;
else else
need_free = 1; need_free = 1;
}
#endif #endif
track = parse_memory(library, buf); track = parse_memory(library, buf);
if (need_free) if (need_free)

View file

@ -25,7 +25,7 @@
#include <stdarg.h> #include <stdarg.h>
#include "ass_types.h" #include "ass_types.h"
#define LIBASS_VERSION 0x00907010 #define LIBASS_VERSION 0x00908000
/* /*
* A linked list of images produced by an ass renderer. * A linked list of images produced by an ass renderer.
@ -49,7 +49,7 @@ typedef struct ass_image {
} ASS_Image; } ASS_Image;
/* /*
* Hintint type. (see ass_set_hinting below) * Hinting type. (see ass_set_hinting below)
* *
* FreeType's native hinter is still buggy sometimes and it is recommended * FreeType's native hinter is still buggy sometimes and it is recommended
* to use the light autohinter, ASS_HINTING_LIGHT, instead. For best * to use the light autohinter, ASS_HINTING_LIGHT, instead. For best
@ -195,6 +195,9 @@ void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing);
/** /**
* \brief Set font lookup defaults. * \brief Set font lookup defaults.
* \param default_font path to default font to use. Must be supplied if
* fontconfig is disabled or unavailable.
* \param default_family fallback font family for fontconfig, or NULL
* \param fc whether to use fontconfig * \param fc whether to use fontconfig
* \param config path to fontconfig configuration file, or NULL. Only relevant * \param config path to fontconfig configuration file, or NULL. Only relevant
* if fontconfig is used. * if fontconfig is used.

View file

@ -230,12 +230,12 @@ static Bitmap *glyph_to_bitmap_internal(ASS_Library *library,
} }
/** /**
* \brief fix outline bitmap and generate shadow bitmap * \brief fix outline bitmap
* Two things are done here: *
* 1. Glyph bitmap is subtracted from outline bitmap. This way looks much better in some cases. * The glyph bitmap is subtracted from outline bitmap. This way looks much
* 2. Shadow bitmap is created as a sum of glyph and outline bitmaps. * better in some cases.
*/ */
static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o) static void fix_outline(Bitmap *bm_g, Bitmap *bm_o)
{ {
int x, y; int x, y;
const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left; const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
@ -247,14 +247,10 @@ static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o)
bm_o->top + bm_o->h < bm_o->top + bm_o->h <
bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h; bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
Bitmap *bm_s = copy_bitmap(bm_o);
unsigned char *g = unsigned char *g =
bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left); bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
unsigned char *o = unsigned char *o =
bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left); 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 (y = 0; y < b - t; ++y) {
for (x = 0; x < r - l; ++x) { for (x = 0; x < r - l; ++x) {
@ -262,15 +258,10 @@ static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o)
c_g = g[x]; c_g = g[x];
c_o = o[x]; c_o = o[x];
o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0; o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
} }
g += bm_g->w; g += bm_g->w;
o += bm_o->w; o += bm_o->w;
s += bm_s->w;
} }
assert(bm_s);
return bm_s;
} }
/** /**
@ -528,16 +519,19 @@ int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
priv_blur->g_w); priv_blur->g_w);
} }
if (*bm_o && border_style == 3) // Create shadow and fix outline as needed
if (*bm_o && border_style != 3) {
*bm_s = copy_bitmap(*bm_o); *bm_s = copy_bitmap(*bm_o);
else if (*bm_o) fix_outline(*bm_g, *bm_o);
*bm_s = fix_outline_and_shadow(*bm_g, *bm_o); } else if (*bm_o) {
else *bm_s = copy_bitmap(*bm_o);
} else
*bm_s = copy_bitmap(*bm_g); *bm_s = copy_bitmap(*bm_g);
assert(bm_s);
shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h, shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h,
shadow_offset.x, shadow_offset.y); shadow_offset.x, shadow_offset.y);
assert(bm_s);
return 0; return 0;
} }

View file

@ -41,14 +41,15 @@ static void drawing_make_glyph(ASS_Drawing *drawing, void *fontconfig_priv,
// This is hacky... // This is hacky...
glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font, glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font,
(uint32_t) ' ', hint, 0); (uint32_t) ' ', hint, 0);
if (glyph) {
FT_Outline_Done(drawing->ftlibrary, &glyph->outline);
FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
GLYPH_INITIAL_CONTOURS, &glyph->outline);
FT_Outline_Done(drawing->ftlibrary, &glyph->outline); glyph->outline.n_contours = 0;
FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS, glyph->outline.n_points = 0;
GLYPH_INITIAL_CONTOURS, &glyph->outline); glyph->root.advance.x = glyph->root.advance.y = 0;
}
glyph->outline.n_contours = 0;
glyph->outline.n_points = 0;
glyph->root.advance.x = glyph->root.advance.y = 0;
drawing->glyph = glyph; drawing->glyph = glyph;
} }
@ -363,15 +364,17 @@ static void drawing_evaluate_curve(ASS_Drawing *drawing,
ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font, ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
ASS_Hinting hint, FT_Library lib) ASS_Hinting hint, FT_Library lib)
{ {
ASS_Drawing* drawing; ASS_Drawing *drawing;
drawing = calloc(1, sizeof(*drawing)); drawing = calloc(1, sizeof(*drawing));
drawing->text = calloc(1, DRAWING_INITIAL_SIZE); drawing->text = calloc(1, DRAWING_INITIAL_SIZE);
drawing->size = DRAWING_INITIAL_SIZE; drawing->size = DRAWING_INITIAL_SIZE;
drawing->ftlibrary = lib; drawing->ftlibrary = lib;
drawing->library = font->library; if (font) {
drawing_make_glyph(drawing, fontconfig_priv, font, hint); drawing->library = font->library;
drawing_make_glyph(drawing, fontconfig_priv, font, hint);
}
drawing->scale_x = 1.; drawing->scale_x = 1.;
drawing->scale_y = 1.; drawing->scale_y = 1.;
@ -386,8 +389,11 @@ ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
*/ */
void ass_drawing_free(ASS_Drawing* drawing) void ass_drawing_free(ASS_Drawing* drawing)
{ {
FT_Done_Glyph((FT_Glyph) drawing->glyph); if (drawing) {
free(drawing->text); if (drawing->glyph)
FT_Done_Glyph((FT_Glyph) drawing->glyph);
free(drawing->text);
}
free(drawing); free(drawing);
} }
@ -423,6 +429,9 @@ FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
ASS_DrawingToken *token; ASS_DrawingToken *token;
FT_Vector pen = {0, 0}; FT_Vector pen = {0, 0};
if (!drawing->glyph)
return NULL;
drawing->tokens = drawing_tokenize(drawing->text); drawing->tokens = drawing_tokenize(drawing->text);
drawing_prepare(drawing); drawing_prepare(drawing);

View file

@ -218,7 +218,6 @@ void ass_font_set_transform(ASS_Font *font, double scale_x,
static void face_set_size(FT_Face face, double size) static void face_set_size(FT_Face face, double size)
{ {
#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
double mscale = 1.; double mscale = 1.;
@ -241,9 +240,6 @@ static void face_set_size(FT_Face face, double size)
m->ascender /= mscale; m->ascender /= mscale;
m->descender /= mscale; m->descender /= mscale;
m->height /= mscale; m->height /= mscale;
#else
FT_Set_Char_Size(face, 0, double_to_d6(size), 0, 0);
#endif
} }
/** /**
@ -421,6 +417,9 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
if (ch < 0x20) if (ch < 0x20)
return 0; return 0;
// Handle NBSP like a regular space when rendering the glyph
if (ch == 0xa0)
ch = ' ';
if (font->n_faces == 0) if (font->n_faces == 0)
return 0; return 0;
@ -473,10 +472,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
index); index);
return 0; return 0;
} }
#if (FREETYPE_MAJOR > 2) || \
((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \
((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10))
// FreeType >= 2.1.10 required
if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) && if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) &&
(font->desc.italic > 55)) { (font->desc.italic > 55)) {
FT_GlyphSlot_Oblique(face->glyph); FT_GlyphSlot_Oblique(face->glyph);
@ -486,7 +481,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
(font->desc.bold > 80)) { (font->desc.bold > 80)) {
ass_glyph_embolden(face->glyph); ass_glyph_embolden(face->glyph);
} }
#endif
error = FT_Get_Glyph(face->glyph, &glyph); error = FT_Get_Glyph(face->glyph, &glyph);
if (error) { if (error) {
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",

View file

@ -51,15 +51,6 @@ struct fc_instance {
#ifdef CONFIG_FONTCONFIG #ifdef CONFIG_FONTCONFIG
// 4yo fontconfig does not have these.
// They are only needed for debug output, anyway.
#ifndef FC_FULLNAME
#define FC_FULLNAME "fullname"
#endif
#ifndef FC_EMBOLDEN
#define FC_EMBOLDEN "embolden"
#endif
/** /**
* \brief Low-level font selection. * \brief Low-level font selection.
* \param priv private data * \param priv private data
@ -159,7 +150,6 @@ static char *_select_font(ASS_Library *library, FCInstance *priv,
if (curf >= fset->nfont) if (curf >= fset->nfont)
goto error; goto error;
#if (FC_VERSION >= 20297)
if (!treat_family_as_pattern) { if (!treat_family_as_pattern) {
// Remove all extra family names from original pattern. // Remove all extra family names from original pattern.
// After this, FcFontRenderPrepare will select the most relevant family // After this, FcFontRenderPrepare will select the most relevant family
@ -167,7 +157,6 @@ static char *_select_font(ASS_Library *library, FCInstance *priv,
for (; family_cnt > 1; --family_cnt) for (; family_cnt > 1; --family_cnt)
FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
} }
#endif
rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
if (!rpat) if (!rpat)
@ -250,7 +239,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
char *res = 0; char *res = 0;
if (!priv->config) { if (!priv->config) {
*index = priv->index_default; *index = priv->index_default;
return priv->path_default; res = priv->path_default ? strdup(priv->path_default) : 0;
return res;
} }
if (family && *family) if (family && *family)
res = res =
@ -266,7 +256,7 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
family, bold, italic, res, *index); family, bold, italic, res, *index);
} }
if (!res && priv->path_default) { if (!res && priv->path_default) {
res = priv->path_default; res = strdup(priv->path_default);
*index = priv->index_default; *index = priv->index_default;
ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: " ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: "
"(%s, %d, %d) -> %s, %d", family, bold, italic, "(%s, %d, %d) -> %s, %d", family, bold, italic,
@ -287,41 +277,6 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
return res; return res;
} }
#if (FC_VERSION < 20402)
static char *validate_fname(char *name)
{
char *fname;
char *p;
char *q;
unsigned code;
int sz = strlen(name);
q = fname = malloc(sz + 1);
p = name;
while (*p) {
code = ass_utf8_get_char(&p);
if (code == 0)
break;
if ((code > 0x7F) ||
(code == '\\') ||
(code == '/') ||
(code == ':') ||
(code == '*') ||
(code == '?') ||
(code == '<') ||
(code == '>') || (code == '|') || (code == 0)) {
*q++ = '_';
} else {
*q++ = code;
}
if (p - name > sz)
break;
}
*q = 0;
return fname;
}
#endif
/** /**
* \brief Process memory font. * \brief Process memory font.
* \param priv private data * \param priv private data
@ -339,44 +294,6 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library,
const char *data = library->fontdata[idx].data; const char *data = library->fontdata[idx].data;
int data_size = library->fontdata[idx].size; int data_size = library->fontdata[idx].size;
#if (FC_VERSION < 20402)
struct stat st;
char *fname;
const char *fonts_dir = library->fonts_dir;
char buf[1000];
FILE *fp = NULL;
if (!fonts_dir)
return;
rc = stat(fonts_dir, &st);
if (rc) {
int res;
#ifndef __MINGW32__
res = mkdir(fonts_dir, 0700);
#else
res = mkdir(fonts_dir);
#endif
if (res) {
ass_msg(library, MSGL_WARN, "Failed to create directory '%s'",
fonts_dir);
}
} else if (!S_ISDIR(st.st_mode)) {
ass_msg(library, MSGL_WARN, "Not a directory: '%s'", fonts_dir);
}
fname = validate_fname((char *) name);
snprintf(buf, 1000, "%s/%s", fonts_dir, fname);
free(fname);
fp = fopen(buf, "wb");
if (!fp)
return;
fwrite(data, data_size, 1, fp);
fclose(fp);
#else // (FC_VERSION >= 20402)
FT_Face face; FT_Face face;
FcPattern *pattern; FcPattern *pattern;
FcFontSet *fset; FcFontSet *fset;
@ -418,7 +335,6 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library,
FT_Done_Face(face); FT_Done_Face(face);
} }
#endif
} }
/** /**
@ -472,40 +388,7 @@ FCInstance *fontconfig_init(ASS_Library *library,
process_fontdata(priv, library, ftlibrary, i); process_fontdata(priv, library, ftlibrary, i);
if (dir) { if (dir) {
if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) { ass_msg(library, MSGL_INFO, "Updating font cache");
ass_msg(library, MSGL_INFO, "Updating font cache");
if (FcGetVersion() >= 20390 && FcGetVersion() < 20400)
ass_msg(library, MSGL_WARN, "Beta versions of fontconfig"
"are not supported. Update before reporting any bugs");
// FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir()
if (FcGetVersion() < 20390) {
FcFontSet *fcs;
FcStrSet *fss;
fcs = FcFontSetCreate();
fss = FcStrSetCreate();
rc = FcStrSetAdd(fss, (const FcChar8 *) dir);
if (!rc) {
ass_msg(library, MSGL_WARN, "%s failed", "FcStrSetAdd");
goto ErrorFontCache;
}
rc = FcDirScan(fcs, fss, NULL,
FcConfigGetBlanks(priv->config),
(const FcChar8 *) dir, FcFalse);
if (!rc) {
ass_msg(library, MSGL_WARN, "%s failed", "FcDirScan");
goto ErrorFontCache;
}
rc = FcDirSave(fcs, fss, (const FcChar8 *) dir);
if (!rc) {
ass_msg(library, MSGL_WARN, "%s failed", "FcDirSave");
goto ErrorFontCache;
}
ErrorFontCache:
;
}
}
rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
if (!rc) { if (!rc) {
@ -534,7 +417,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
uint32_t code) uint32_t code)
{ {
*index = priv->index_default; *index = priv->index_default;
return priv->path_default; char* res = priv->path_default ? strdup(priv->path_default) : 0;
return res;
} }
FCInstance *fontconfig_init(ASS_Library *library, FCInstance *fontconfig_init(ASS_Library *library,
@ -549,7 +433,7 @@ FCInstance *fontconfig_init(ASS_Library *library,
priv = calloc(1, sizeof(FCInstance)); priv = calloc(1, sizeof(FCInstance));
priv->path_default = strdup(path); priv->path_default = path ? strdup(path) : 0;
priv->index_default = 0; priv->index_default = 0;
return priv; return priv;
} }

View file

@ -123,15 +123,9 @@ void change_border(ASS_Renderer *render_priv, double border_x,
if (bord > 0 && border_x == border_y) { if (bord > 0 && border_x == border_y) {
if (!render_priv->state.stroker) { if (!render_priv->state.stroker) {
int error; int error;
#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
error = error =
FT_Stroker_New(render_priv->ftlibrary, FT_Stroker_New(render_priv->ftlibrary,
&render_priv->state.stroker); &render_priv->state.stroker);
#else // < 2.2
error =
FT_Stroker_New(render_priv->state.font->faces[0]->
memory, &render_priv->state.stroker);
#endif
if (error) { if (error) {
ass_msg(render_priv->library, MSGL_V, ass_msg(render_priv->library, MSGL_V,
"failed to get stroker"); "failed to get stroker");
@ -164,7 +158,7 @@ inline void change_alpha(uint32_t *var, uint32_t new, double pwr)
{ {
*var = *var =
(_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) +
(_a(*var) * (1 - pwr) + _a(new) * pwr); (uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr);
} }
/** /**
@ -233,20 +227,20 @@ static char *parse_vector_clip(ASS_Renderer *render_priv, char *p)
while (*p != ')' && *p != '}' && p != 0) while (*p != ')' && *p != '}' && p != 0)
ass_drawing_add_char(drawing, *p++); ass_drawing_add_char(drawing, *p++);
skipopt(')'); skipopt(')');
ass_drawing_parse(drawing, 1); if (ass_drawing_parse(drawing, 1)) {
// We need to translate the clip according to screen borders
// We need to translate the clip according to screen borders if (render_priv->settings.left_margin != 0 ||
if (render_priv->settings.left_margin != 0 || render_priv->settings.top_margin != 0) {
render_priv->settings.top_margin != 0) { FT_Vector trans = {
FT_Vector trans = { .x = int_to_d6(render_priv->settings.left_margin),
.x = int_to_d6(render_priv->settings.left_margin), .y = -int_to_d6(render_priv->settings.top_margin),
.y = -int_to_d6(render_priv->settings.top_margin), };
}; FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y);
FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y); }
ass_msg(render_priv->library, MSGL_DBG2,
"Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n",
scale, drawing->scale_x, drawing->scale_y, drawing->text);
} }
ass_msg(render_priv->library, MSGL_DBG2,
"Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n",
scale, drawing->scale_x, drawing->scale_y, drawing->text);
return p; return p;
} }
@ -802,6 +796,81 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
return p; return p;
} }
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event)
{
int v[4];
int cnt;
char *p = event->Effect;
if (!p || !*p)
return;
cnt = 0;
while (cnt < 4 && (p = strchr(p, ';'))) {
v[cnt++] = atoi(++p);
}
if (strncmp(event->Effect, "Banner;", 7) == 0) {
int delay;
if (cnt < 1) {
ass_msg(render_priv->library, MSGL_V,
"Error parsing effect: '%s'", event->Effect);
return;
}
if (cnt >= 2 && v[1] == 0) // right-to-left
render_priv->state.scroll_direction = SCROLL_RL;
else // left-to-right
render_priv->state.scroll_direction = SCROLL_LR;
delay = v[0];
if (delay == 0)
delay = 1; // ?
render_priv->state.scroll_shift =
(render_priv->time - render_priv->state.event->Start) / delay;
render_priv->state.evt_type = EVENT_HSCROLL;
return;
}
if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
render_priv->state.scroll_direction = SCROLL_BT;
} else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
render_priv->state.scroll_direction = SCROLL_TB;
} else {
ass_msg(render_priv->library, MSGL_V,
"Unknown transition effect: '%s'", event->Effect);
return;
}
// parse scroll up/down parameters
{
int delay;
int y0, y1;
if (cnt < 3) {
ass_msg(render_priv->library, MSGL_V,
"Error parsing effect: '%s'", event->Effect);
return;
}
delay = v[2];
if (delay == 0)
delay = 1; // ?
render_priv->state.scroll_shift =
(render_priv->time - render_priv->state.event->Start) / delay;
if (v[0] < v[1]) {
y0 = v[0];
y1 = v[1];
} else {
y0 = v[1];
y1 = v[0];
}
if (y1 == 0)
y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling
render_priv->state.clip_y0 = y0;
render_priv->state.clip_y1 = y1;
render_priv->state.evt_type = EVENT_VSCROLL;
render_priv->state.detect_collisions = 0;
}
}
/** /**
* \brief Get next ucs4 char from string, parsing and executing style overrides * \brief Get next ucs4 char from string, parsing and executing style overrides
* \param str string pointer * \param str string pointer

View file

@ -29,6 +29,7 @@
void update_font(ASS_Renderer *render_priv); void update_font(ASS_Renderer *render_priv);
void change_border(ASS_Renderer *render_priv, double border_x, void change_border(ASS_Renderer *render_priv, double border_x,
double border_y); double border_y);
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
unsigned get_next_char(ASS_Renderer *render_priv, char **str); unsigned get_next_char(ASS_Renderer *render_priv, char **str);
extern void change_alpha(uint32_t *var, uint32_t new, double pwr); extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
extern uint32_t mult_alpha(uint32_t a, uint32_t b); extern uint32_t mult_alpha(uint32_t a, uint32_t b);

View file

@ -809,82 +809,6 @@ static void compute_string_bbox(TextInfo *info, DBBox *bbox)
bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.; bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
} }
static void
apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event)
{
int v[4];
int cnt;
char *p = event->Effect;
if (!p || !*p)
return;
cnt = 0;
while (cnt < 4 && (p = strchr(p, ';'))) {
v[cnt++] = atoi(++p);
}
if (strncmp(event->Effect, "Banner;", 7) == 0) {
int delay;
if (cnt < 1) {
ass_msg(render_priv->library, MSGL_V,
"Error parsing effect: '%s'", event->Effect);
return;
}
if (cnt >= 2 && v[1] == 0) // right-to-left
render_priv->state.scroll_direction = SCROLL_RL;
else // left-to-right
render_priv->state.scroll_direction = SCROLL_LR;
delay = v[0];
if (delay == 0)
delay = 1; // ?
render_priv->state.scroll_shift =
(render_priv->time - render_priv->state.event->Start) / delay;
render_priv->state.evt_type = EVENT_HSCROLL;
return;
}
if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
render_priv->state.scroll_direction = SCROLL_BT;
} else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
render_priv->state.scroll_direction = SCROLL_TB;
} else {
ass_msg(render_priv->library, MSGL_V,
"Unknown transition effect: '%s'", event->Effect);
return;
}
// parse scroll up/down parameters
{
int delay;
int y0, y1;
if (cnt < 3) {
ass_msg(render_priv->library, MSGL_V,
"Error parsing effect: '%s'", event->Effect);
return;
}
delay = v[2];
if (delay == 0)
delay = 1; // ?
render_priv->state.scroll_shift =
(render_priv->time - render_priv->state.event->Start) / delay;
if (v[0] < v[1]) {
y0 = v[0];
y1 = v[1];
} else {
y0 = v[1];
y1 = v[0];
}
if (y1 == 0)
y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling
render_priv->state.clip_y0 = y0;
render_priv->state.clip_y1 = y1;
render_priv->state.evt_type = EVENT_VSCROLL;
render_priv->state.detect_collisions = 0;
}
}
/** /**
* \brief partially reset render_context to style values * \brief partially reset render_context to style values
* Works like {\r}: resets some style overrides * Works like {\r}: resets some style overrides
@ -947,6 +871,7 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
render_priv->state.clip_y0 = 0; render_priv->state.clip_y0 = 0;
render_priv->state.clip_x1 = render_priv->track->PlayResX; render_priv->state.clip_x1 = render_priv->track->PlayResX;
render_priv->state.clip_y1 = render_priv->track->PlayResY; render_priv->state.clip_y1 = render_priv->track->PlayResY;
render_priv->state.clip_mode = 0;
render_priv->state.detect_collisions = 1; render_priv->state.detect_collisions = 1;
render_priv->state.fade = 0; render_priv->state.fade = 0;
render_priv->state.drawing_mode = 0; render_priv->state.drawing_mode = 0;
@ -1208,7 +1133,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
} else { } else {
GlyphHashValue v; GlyphHashValue v;
if (drawing->hash) { if (drawing->hash) {
ass_drawing_parse(drawing, 0); if(!ass_drawing_parse(drawing, 0))
return;
FT_Glyph_Copy((FT_Glyph) drawing->glyph, &info->glyph); FT_Glyph_Copy((FT_Glyph) drawing->glyph, &info->glyph);
} else { } else {
info->glyph = info->glyph =
@ -1816,6 +1742,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
int MarginL, MarginR, MarginV; int MarginL, MarginR, MarginV;
int last_break; int last_break;
int alignment, halign, valign; int alignment, halign, valign;
int kern = render_priv->track->Kerning;
double device_x = 0; double device_x = 0;
double device_y = 0; double device_y = 0;
TextInfo *text_info = &render_priv->text_info; TextInfo *text_info = &render_priv->text_info;
@ -1879,7 +1806,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
} }
// Add kerning to pen // Add kerning to pen
if (previous && code && !drawing->hash) { if (kern && previous && code && !drawing->hash) {
FT_Vector delta; FT_Vector delta;
delta = delta =
ass_font_get_kerning(render_priv->state.font, previous, ass_font_get_kerning(render_priv->state.font, previous,
@ -1980,23 +1907,23 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
drawing->hash; drawing->hash;
text_info->glyphs[text_info->length].hash_key.ch = code; text_info->glyphs[text_info->length].hash_key.ch = code;
text_info->glyphs[text_info->length].hash_key.outline.x = text_info->glyphs[text_info->length].hash_key.outline.x =
render_priv->state.border_x * 0xFFFF; double_to_d16(render_priv->state.border_x);
text_info->glyphs[text_info->length].hash_key.outline.y = text_info->glyphs[text_info->length].hash_key.outline.y =
render_priv->state.border_y * 0xFFFF; double_to_d16(render_priv->state.border_y);
text_info->glyphs[text_info->length].hash_key.scale_x = text_info->glyphs[text_info->length].hash_key.scale_x =
render_priv->state.scale_x * 0xFFFF; double_to_d16(render_priv->state.scale_x);
text_info->glyphs[text_info->length].hash_key.scale_y = text_info->glyphs[text_info->length].hash_key.scale_y =
render_priv->state.scale_y * 0xFFFF; double_to_d16(render_priv->state.scale_y);
text_info->glyphs[text_info->length].hash_key.frx = text_info->glyphs[text_info->length].hash_key.frx =
render_priv->state.frx * 0xFFFF; rot_key(render_priv->state.frx);
text_info->glyphs[text_info->length].hash_key.fry = text_info->glyphs[text_info->length].hash_key.fry =
render_priv->state.fry * 0xFFFF; rot_key(render_priv->state.fry);
text_info->glyphs[text_info->length].hash_key.frz = text_info->glyphs[text_info->length].hash_key.frz =
render_priv->state.frz * 0xFFFF; rot_key(render_priv->state.frz);
text_info->glyphs[text_info->length].hash_key.fax = text_info->glyphs[text_info->length].hash_key.fax =
render_priv->state.fax * 0xFFFF; double_to_d16(render_priv->state.fax);
text_info->glyphs[text_info->length].hash_key.fay = text_info->glyphs[text_info->length].hash_key.fay =
render_priv->state.fay * 0xFFFF; double_to_d16(render_priv->state.fay);
text_info->glyphs[text_info->length].hash_key.advance.x = pen.x; text_info->glyphs[text_info->length].hash_key.advance.x = pen.x;
text_info->glyphs[text_info->length].hash_key.advance.y = pen.y; text_info->glyphs[text_info->length].hash_key.advance.y = pen.y;
text_info->glyphs[text_info->length].hash_key.be = text_info->glyphs[text_info->length].hash_key.be =

247
aegisub/libass/ass_strtod.c Normal file
View file

@ -0,0 +1,247 @@
/*
* Copyright (c) 1988-1993 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
*/
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
static int maxExponent = 511; /* Largest possible base 10 exponent. Any
* exponent larger than this will already
* produce underflow or overflow, so there's
* no need to worry about additional digits.
*/
static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
10., /* is 10^2^i. Used to convert decimal */
100., /* exponents into floating-point numbers. */
1.0e4,
1.0e8,
1.0e16,
1.0e32,
1.0e64,
1.0e128,
1.0e256
};
/*
*----------------------------------------------------------------------
*
* strtod --
*
* This procedure converts a floating-point number from an ASCII
* decimal representation to internal double-precision format.
*
* Results:
* The return value is the double-precision floating-point
* representation of the characters in string. If endPtr isn't
* NULL, then *endPtr is filled in with the address of the
* next character after the last one that was part of the
* floating-point number.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
double
ass_strtod(string, endPtr)
const char *string; /* A decimal ASCII floating-point number,
* optionally preceded by white space.
* Must have form "-I.FE-X", where I is the
* integer part of the mantissa, F is the
* fractional part of the mantissa, and X
* is the exponent. Either of the signs
* may be "+", "-", or omitted. Either I
* or F may be omitted, or both. The decimal
* point isn't necessary unless F is present.
* The "E" may actually be an "e". E and X
* may both be omitted (but not just one).
*/
char **endPtr; /* If non-NULL, store terminating character's
* address here. */
{
int sign, expSign = 0;
double fraction, dblExp, *d;
register const char *p;
register int c;
int exp = 0; /* Exponent read from "EX" field. */
int fracExp = 0; /* Exponent that derives from the fractional
* part. Under normal circumstatnces, it is
* the negative of the number of digits in F.
* However, if I is very long, the last digits
* of I get dropped (otherwise a long I with a
* large negative exponent could cause an
* unnecessary overflow on I alone). In this
* case, fracExp is incremented one for each
* dropped digit. */
int mantSize; /* Number of digits in mantissa. */
int decPt; /* Number of mantissa digits BEFORE decimal
* point. */
const char *pExp; /* Temporarily holds location of exponent
* in string. */
/*
* Strip off leading blanks and check for a sign.
*/
p = string;
while (isspace(*p)) {
p += 1;
}
if (*p == '-') {
sign = 1;
p += 1;
} else {
if (*p == '+') {
p += 1;
}
sign = 0;
}
/*
* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point.
*/
decPt = -1;
for (mantSize = 0; ; mantSize += 1)
{
c = *p;
if (!isdigit(c)) {
if ((c != '.') || (decPt >= 0)) {
break;
}
decPt = mantSize;
}
p += 1;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
pExp = p;
p -= mantSize;
if (decPt < 0) {
decPt = mantSize;
} else {
mantSize -= 1; /* One of the digits was the point. */
}
if (mantSize > 18) {
fracExp = decPt - 18;
mantSize = 18;
} else {
fracExp = decPt - mantSize;
}
if (mantSize == 0) {
fraction = 0.0;
p = string;
goto done;
} else {
int frac1, frac2;
frac1 = 0;
for ( ; mantSize > 9; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.') {
c = *p;
p += 1;
}
frac1 = 10*frac1 + (c - '0');
}
frac2 = 0;
for (; mantSize > 0; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.') {
c = *p;
p += 1;
}
frac2 = 10*frac2 + (c - '0');
}
fraction = (1.0e9 * frac1) + frac2;
}
/*
* Skim off the exponent.
*/
p = pExp;
if ((*p == 'E') || (*p == 'e')) {
p += 1;
if (*p == '-') {
expSign = 1;
p += 1;
} else {
if (*p == '+') {
p += 1;
}
expSign = 0;
}
while (isdigit(*p)) {
exp = exp * 10 + (*p - '0');
p += 1;
}
}
if (expSign) {
exp = fracExp - exp;
} else {
exp = fracExp + exp;
}
/*
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
* fraction.
*/
if (exp < 0) {
expSign = 1;
exp = -exp;
} else {
expSign = 0;
}
if (exp > maxExponent) {
exp = maxExponent;
errno = ERANGE;
}
dblExp = 1.0;
for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
if (exp & 01) {
dblExp *= *d;
}
}
if (expSign) {
fraction /= dblExp;
} else {
fraction *= dblExp;
}
done:
if (endPtr != NULL) {
*endPtr = (char *) p;
}
if (sign) {
return -fraction;
}
return fraction;
}

View file

@ -113,6 +113,7 @@ typedef struct ass_track {
double Timer; double Timer;
int WrapStyle; int WrapStyle;
int ScaledBorderAndShadow; int ScaledBorderAndShadow;
int Kerning;
int default_style; // index of default style int default_style; // index of default style
char *name; // file name in case of external subs, 0 for streams char *name; // file name in case of external subs, 0 for streams

View file

@ -34,7 +34,7 @@ int mystrtoi(char **p, int *res)
{ {
double temp_res; double temp_res;
char *start = *p; char *start = *p;
temp_res = strtod(*p, p); temp_res = ass_strtod(*p, p);
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
if (*p != start) if (*p != start)
return 1; return 1;
@ -46,7 +46,7 @@ int mystrtoll(char **p, long long *res)
{ {
double temp_res; double temp_res;
char *start = *p; char *start = *p;
temp_res = strtod(*p, p); temp_res = ass_strtod(*p, p);
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5)); *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
if (*p != start) if (*p != start)
return 1; return 1;
@ -67,7 +67,7 @@ int mystrtou32(char **p, int base, uint32_t *res)
int mystrtod(char **p, double *res) int mystrtod(char **p, double *res)
{ {
char *start = *p; char *start = *p;
*res = strtod(*p, p); *res = ass_strtod(*p, p);
if (*p != start) if (*p != start)
return 1; return 1;
else else

View file

@ -59,6 +59,9 @@ void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
char *fallback); char *fallback);
#endif #endif
/* defined in ass_strtod.c */
double ass_strtod(const char *string, char **endPtr);
static inline int d6_to_int(int x) static inline int d6_to_int(int x)
{ {
return (x + 32) >> 6; return (x + 32) >> 6;
@ -99,6 +102,21 @@ static inline int double_to_d16(double x)
{ {
return (int) (x * 0x10000); return (int) (x * 0x10000);
} }
static inline double d22_to_double(int x)
{
return ((double) x) / 0x400000;
}
static inline int double_to_d22(double x)
{
return (int) (x * 0x400000);
}
// Calculate cache key for a rotational angle in degrees
static inline int rot_key(double a)
{
const int m = double_to_d22(360.0);
return double_to_d22(a) % m;
}
#define FNV1_32A_INIT (unsigned)0x811c9dc5 #define FNV1_32A_INIT (unsigned)0x811c9dc5