forked from mia/Aegisub
Update libass to commit 8db4a5.
Originally committed to SVN as r3970.
This commit is contained in:
parent
7e079a3fc2
commit
e341e05fa2
14 changed files with 433 additions and 280 deletions
|
@ -16,6 +16,7 @@ libass_aegisub_a_SOURCES = \
|
|||
ass_library.c \
|
||||
ass_parse.c \
|
||||
ass_render.c \
|
||||
ass_strtod.c \
|
||||
ass_utils.c
|
||||
|
||||
libass_aegisub_a_SOURCES += \
|
||||
|
|
|
@ -389,6 +389,8 @@ void ass_process_force_style(ASS_Track *track)
|
|||
track->WrapStyle = atoi(token);
|
||||
else if (!strcasecmp(*fs, "ScaledBorderAndShadow"))
|
||||
track->ScaledBorderAndShadow = parse_bool(token);
|
||||
else if (!strcasecmp(*fs, "Kerning"))
|
||||
track->Kerning = parse_bool(token);
|
||||
|
||||
dt = strrchr(*fs, '.');
|
||||
if (dt) {
|
||||
|
@ -571,6 +573,8 @@ static int process_info_line(ASS_Track *track, char *str)
|
|||
track->WrapStyle = atoi(str + 10);
|
||||
} else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) {
|
||||
track->ScaledBorderAndShadow = parse_bool(str + 22);
|
||||
} else if (!strncmp(str, "Kerning:", 8)) {
|
||||
track->Kerning = parse_bool(str + 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1096,12 +1100,13 @@ ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
|
|||
return 0;
|
||||
|
||||
#ifdef CONFIG_ICONV
|
||||
if (codepage)
|
||||
if (codepage) {
|
||||
buf = sub_recode(library, buf, bufsize, codepage);
|
||||
if (!buf)
|
||||
return 0;
|
||||
else
|
||||
need_free = 1;
|
||||
if (!buf)
|
||||
return 0;
|
||||
else
|
||||
need_free = 1;
|
||||
}
|
||||
#endif
|
||||
track = parse_memory(library, buf);
|
||||
if (need_free)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <stdarg.h>
|
||||
#include "ass_types.h"
|
||||
|
||||
#define LIBASS_VERSION 0x00907010
|
||||
#define LIBASS_VERSION 0x00908000
|
||||
|
||||
/*
|
||||
* A linked list of images produced by an ass renderer.
|
||||
|
@ -49,7 +49,7 @@ typedef struct ass_image {
|
|||
} ASS_Image;
|
||||
|
||||
/*
|
||||
* Hintint type. (see ass_set_hinting below)
|
||||
* Hinting type. (see ass_set_hinting below)
|
||||
*
|
||||
* FreeType's native hinter is still buggy sometimes and it is recommended
|
||||
* to use the light autohinter, ASS_HINTING_LIGHT, instead. For best
|
||||
|
@ -195,6 +195,9 @@ void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing);
|
|||
|
||||
/**
|
||||
* \brief Set font lookup defaults.
|
||||
* \param default_font path to default font to use. Must be supplied if
|
||||
* fontconfig is disabled or unavailable.
|
||||
* \param default_family fallback font family for fontconfig, or NULL
|
||||
* \param fc whether to use fontconfig
|
||||
* \param config path to fontconfig configuration file, or NULL. Only relevant
|
||||
* if fontconfig is used.
|
||||
|
|
|
@ -230,12 +230,12 @@ static Bitmap *glyph_to_bitmap_internal(ASS_Library *library,
|
|||
}
|
||||
|
||||
/**
|
||||
* \brief fix outline bitmap and generate shadow bitmap
|
||||
* Two things are done here:
|
||||
* 1. Glyph bitmap is subtracted from outline bitmap. This way looks much better in some cases.
|
||||
* 2. Shadow bitmap is created as a sum of glyph and outline bitmaps.
|
||||
* \brief fix outline bitmap
|
||||
*
|
||||
* The glyph bitmap is subtracted from outline bitmap. This way looks much
|
||||
* better in some cases.
|
||||
*/
|
||||
static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o)
|
||||
static void fix_outline(Bitmap *bm_g, Bitmap *bm_o)
|
||||
{
|
||||
int x, y;
|
||||
const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
|
||||
|
@ -247,14 +247,10 @@ static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o)
|
|||
bm_o->top + bm_o->h <
|
||||
bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
|
||||
|
||||
Bitmap *bm_s = copy_bitmap(bm_o);
|
||||
|
||||
unsigned char *g =
|
||||
bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
|
||||
unsigned char *o =
|
||||
bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
|
||||
unsigned char *s =
|
||||
bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left);
|
||||
|
||||
for (y = 0; y < b - t; ++y) {
|
||||
for (x = 0; x < r - l; ++x) {
|
||||
|
@ -262,15 +258,10 @@ static Bitmap *fix_outline_and_shadow(Bitmap *bm_g, Bitmap *bm_o)
|
|||
c_g = g[x];
|
||||
c_o = o[x];
|
||||
o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
|
||||
s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
|
||||
}
|
||||
g += bm_g->w;
|
||||
o += bm_o->w;
|
||||
s += bm_s->w;
|
||||
}
|
||||
|
||||
assert(bm_s);
|
||||
return bm_s;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -528,16 +519,19 @@ int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
|
|||
priv_blur->g_w);
|
||||
}
|
||||
|
||||
if (*bm_o && border_style == 3)
|
||||
// Create shadow and fix outline as needed
|
||||
if (*bm_o && border_style != 3) {
|
||||
*bm_s = copy_bitmap(*bm_o);
|
||||
else if (*bm_o)
|
||||
*bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
|
||||
else
|
||||
fix_outline(*bm_g, *bm_o);
|
||||
} else if (*bm_o) {
|
||||
*bm_s = copy_bitmap(*bm_o);
|
||||
} else
|
||||
*bm_s = copy_bitmap(*bm_g);
|
||||
|
||||
assert(bm_s);
|
||||
|
||||
shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h,
|
||||
shadow_offset.x, shadow_offset.y);
|
||||
|
||||
assert(bm_s);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -41,14 +41,15 @@ static void drawing_make_glyph(ASS_Drawing *drawing, void *fontconfig_priv,
|
|||
// This is hacky...
|
||||
glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font,
|
||||
(uint32_t) ' ', hint, 0);
|
||||
if (glyph) {
|
||||
FT_Outline_Done(drawing->ftlibrary, &glyph->outline);
|
||||
FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
|
||||
GLYPH_INITIAL_CONTOURS, &glyph->outline);
|
||||
|
||||
FT_Outline_Done(drawing->ftlibrary, &glyph->outline);
|
||||
FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
|
||||
GLYPH_INITIAL_CONTOURS, &glyph->outline);
|
||||
|
||||
glyph->outline.n_contours = 0;
|
||||
glyph->outline.n_points = 0;
|
||||
glyph->root.advance.x = glyph->root.advance.y = 0;
|
||||
glyph->outline.n_contours = 0;
|
||||
glyph->outline.n_points = 0;
|
||||
glyph->root.advance.x = glyph->root.advance.y = 0;
|
||||
}
|
||||
drawing->glyph = glyph;
|
||||
}
|
||||
|
||||
|
@ -363,15 +364,17 @@ static void drawing_evaluate_curve(ASS_Drawing *drawing,
|
|||
ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
|
||||
ASS_Hinting hint, FT_Library lib)
|
||||
{
|
||||
ASS_Drawing* drawing;
|
||||
ASS_Drawing *drawing;
|
||||
|
||||
drawing = calloc(1, sizeof(*drawing));
|
||||
drawing->text = calloc(1, DRAWING_INITIAL_SIZE);
|
||||
drawing->size = DRAWING_INITIAL_SIZE;
|
||||
|
||||
drawing->ftlibrary = lib;
|
||||
drawing->library = font->library;
|
||||
drawing_make_glyph(drawing, fontconfig_priv, font, hint);
|
||||
if (font) {
|
||||
drawing->library = font->library;
|
||||
drawing_make_glyph(drawing, fontconfig_priv, font, hint);
|
||||
}
|
||||
|
||||
drawing->scale_x = 1.;
|
||||
drawing->scale_y = 1.;
|
||||
|
@ -386,8 +389,11 @@ ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
|
|||
*/
|
||||
void ass_drawing_free(ASS_Drawing* drawing)
|
||||
{
|
||||
FT_Done_Glyph((FT_Glyph) drawing->glyph);
|
||||
free(drawing->text);
|
||||
if (drawing) {
|
||||
if (drawing->glyph)
|
||||
FT_Done_Glyph((FT_Glyph) drawing->glyph);
|
||||
free(drawing->text);
|
||||
}
|
||||
free(drawing);
|
||||
}
|
||||
|
||||
|
@ -423,6 +429,9 @@ FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
|
|||
ASS_DrawingToken *token;
|
||||
FT_Vector pen = {0, 0};
|
||||
|
||||
if (!drawing->glyph)
|
||||
return NULL;
|
||||
|
||||
drawing->tokens = drawing_tokenize(drawing->text);
|
||||
drawing_prepare(drawing);
|
||||
|
||||
|
|
|
@ -218,7 +218,6 @@ void ass_font_set_transform(ASS_Font *font, double scale_x,
|
|||
|
||||
static void face_set_size(FT_Face face, double size)
|
||||
{
|
||||
#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
|
||||
TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
|
||||
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||
double mscale = 1.;
|
||||
|
@ -241,9 +240,6 @@ static void face_set_size(FT_Face face, double size)
|
|||
m->ascender /= mscale;
|
||||
m->descender /= mscale;
|
||||
m->height /= mscale;
|
||||
#else
|
||||
FT_Set_Char_Size(face, 0, double_to_d6(size), 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -421,6 +417,9 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
|
|||
|
||||
if (ch < 0x20)
|
||||
return 0;
|
||||
// Handle NBSP like a regular space when rendering the glyph
|
||||
if (ch == 0xa0)
|
||||
ch = ' ';
|
||||
if (font->n_faces == 0)
|
||||
return 0;
|
||||
|
||||
|
@ -473,10 +472,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
|
|||
index);
|
||||
return 0;
|
||||
}
|
||||
#if (FREETYPE_MAJOR > 2) || \
|
||||
((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \
|
||||
((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10))
|
||||
// FreeType >= 2.1.10 required
|
||||
if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) &&
|
||||
(font->desc.italic > 55)) {
|
||||
FT_GlyphSlot_Oblique(face->glyph);
|
||||
|
@ -486,7 +481,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
|
|||
(font->desc.bold > 80)) {
|
||||
ass_glyph_embolden(face->glyph);
|
||||
}
|
||||
#endif
|
||||
error = FT_Get_Glyph(face->glyph, &glyph);
|
||||
if (error) {
|
||||
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
|
||||
|
|
|
@ -51,15 +51,6 @@ struct fc_instance {
|
|||
|
||||
#ifdef CONFIG_FONTCONFIG
|
||||
|
||||
// 4yo fontconfig does not have these.
|
||||
// They are only needed for debug output, anyway.
|
||||
#ifndef FC_FULLNAME
|
||||
#define FC_FULLNAME "fullname"
|
||||
#endif
|
||||
#ifndef FC_EMBOLDEN
|
||||
#define FC_EMBOLDEN "embolden"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Low-level font selection.
|
||||
* \param priv private data
|
||||
|
@ -159,7 +150,6 @@ static char *_select_font(ASS_Library *library, FCInstance *priv,
|
|||
if (curf >= fset->nfont)
|
||||
goto error;
|
||||
|
||||
#if (FC_VERSION >= 20297)
|
||||
if (!treat_family_as_pattern) {
|
||||
// Remove all extra family names from original pattern.
|
||||
// After this, FcFontRenderPrepare will select the most relevant family
|
||||
|
@ -167,7 +157,6 @@ static char *_select_font(ASS_Library *library, FCInstance *priv,
|
|||
for (; family_cnt > 1; --family_cnt)
|
||||
FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
|
||||
if (!rpat)
|
||||
|
@ -250,7 +239,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
|
|||
char *res = 0;
|
||||
if (!priv->config) {
|
||||
*index = priv->index_default;
|
||||
return priv->path_default;
|
||||
res = priv->path_default ? strdup(priv->path_default) : 0;
|
||||
return res;
|
||||
}
|
||||
if (family && *family)
|
||||
res =
|
||||
|
@ -266,7 +256,7 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
|
|||
family, bold, italic, res, *index);
|
||||
}
|
||||
if (!res && priv->path_default) {
|
||||
res = priv->path_default;
|
||||
res = strdup(priv->path_default);
|
||||
*index = priv->index_default;
|
||||
ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: "
|
||||
"(%s, %d, %d) -> %s, %d", family, bold, italic,
|
||||
|
@ -287,41 +277,6 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
|
|||
return res;
|
||||
}
|
||||
|
||||
#if (FC_VERSION < 20402)
|
||||
static char *validate_fname(char *name)
|
||||
{
|
||||
char *fname;
|
||||
char *p;
|
||||
char *q;
|
||||
unsigned code;
|
||||
int sz = strlen(name);
|
||||
|
||||
q = fname = malloc(sz + 1);
|
||||
p = name;
|
||||
while (*p) {
|
||||
code = ass_utf8_get_char(&p);
|
||||
if (code == 0)
|
||||
break;
|
||||
if ((code > 0x7F) ||
|
||||
(code == '\\') ||
|
||||
(code == '/') ||
|
||||
(code == ':') ||
|
||||
(code == '*') ||
|
||||
(code == '?') ||
|
||||
(code == '<') ||
|
||||
(code == '>') || (code == '|') || (code == 0)) {
|
||||
*q++ = '_';
|
||||
} else {
|
||||
*q++ = code;
|
||||
}
|
||||
if (p - name > sz)
|
||||
break;
|
||||
}
|
||||
*q = 0;
|
||||
return fname;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Process memory font.
|
||||
* \param priv private data
|
||||
|
@ -339,44 +294,6 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library,
|
|||
const char *data = library->fontdata[idx].data;
|
||||
int data_size = library->fontdata[idx].size;
|
||||
|
||||
#if (FC_VERSION < 20402)
|
||||
struct stat st;
|
||||
char *fname;
|
||||
const char *fonts_dir = library->fonts_dir;
|
||||
char buf[1000];
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (!fonts_dir)
|
||||
return;
|
||||
rc = stat(fonts_dir, &st);
|
||||
if (rc) {
|
||||
int res;
|
||||
#ifndef __MINGW32__
|
||||
res = mkdir(fonts_dir, 0700);
|
||||
#else
|
||||
res = mkdir(fonts_dir);
|
||||
#endif
|
||||
if (res) {
|
||||
ass_msg(library, MSGL_WARN, "Failed to create directory '%s'",
|
||||
fonts_dir);
|
||||
}
|
||||
} else if (!S_ISDIR(st.st_mode)) {
|
||||
ass_msg(library, MSGL_WARN, "Not a directory: '%s'", fonts_dir);
|
||||
}
|
||||
|
||||
fname = validate_fname((char *) name);
|
||||
|
||||
snprintf(buf, 1000, "%s/%s", fonts_dir, fname);
|
||||
free(fname);
|
||||
|
||||
fp = fopen(buf, "wb");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
fwrite(data, data_size, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
#else // (FC_VERSION >= 20402)
|
||||
FT_Face face;
|
||||
FcPattern *pattern;
|
||||
FcFontSet *fset;
|
||||
|
@ -418,7 +335,6 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library,
|
|||
|
||||
FT_Done_Face(face);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -472,40 +388,7 @@ FCInstance *fontconfig_init(ASS_Library *library,
|
|||
process_fontdata(priv, library, ftlibrary, i);
|
||||
|
||||
if (dir) {
|
||||
if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) {
|
||||
ass_msg(library, MSGL_INFO, "Updating font cache");
|
||||
if (FcGetVersion() >= 20390 && FcGetVersion() < 20400)
|
||||
ass_msg(library, MSGL_WARN, "Beta versions of fontconfig"
|
||||
"are not supported. Update before reporting any bugs");
|
||||
// FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir()
|
||||
if (FcGetVersion() < 20390) {
|
||||
FcFontSet *fcs;
|
||||
FcStrSet *fss;
|
||||
fcs = FcFontSetCreate();
|
||||
fss = FcStrSetCreate();
|
||||
rc = FcStrSetAdd(fss, (const FcChar8 *) dir);
|
||||
if (!rc) {
|
||||
ass_msg(library, MSGL_WARN, "%s failed", "FcStrSetAdd");
|
||||
goto ErrorFontCache;
|
||||
}
|
||||
|
||||
rc = FcDirScan(fcs, fss, NULL,
|
||||
FcConfigGetBlanks(priv->config),
|
||||
(const FcChar8 *) dir, FcFalse);
|
||||
if (!rc) {
|
||||
ass_msg(library, MSGL_WARN, "%s failed", "FcDirScan");
|
||||
goto ErrorFontCache;
|
||||
}
|
||||
|
||||
rc = FcDirSave(fcs, fss, (const FcChar8 *) dir);
|
||||
if (!rc) {
|
||||
ass_msg(library, MSGL_WARN, "%s failed", "FcDirSave");
|
||||
goto ErrorFontCache;
|
||||
}
|
||||
ErrorFontCache:
|
||||
;
|
||||
}
|
||||
}
|
||||
ass_msg(library, MSGL_INFO, "Updating font cache");
|
||||
|
||||
rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
|
||||
if (!rc) {
|
||||
|
@ -534,7 +417,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv,
|
|||
uint32_t code)
|
||||
{
|
||||
*index = priv->index_default;
|
||||
return priv->path_default;
|
||||
char* res = priv->path_default ? strdup(priv->path_default) : 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
FCInstance *fontconfig_init(ASS_Library *library,
|
||||
|
@ -549,7 +433,7 @@ FCInstance *fontconfig_init(ASS_Library *library,
|
|||
|
||||
priv = calloc(1, sizeof(FCInstance));
|
||||
|
||||
priv->path_default = strdup(path);
|
||||
priv->path_default = path ? strdup(path) : 0;
|
||||
priv->index_default = 0;
|
||||
return priv;
|
||||
}
|
||||
|
|
|
@ -123,15 +123,9 @@ void change_border(ASS_Renderer *render_priv, double border_x,
|
|||
if (bord > 0 && border_x == border_y) {
|
||||
if (!render_priv->state.stroker) {
|
||||
int error;
|
||||
#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
|
||||
error =
|
||||
FT_Stroker_New(render_priv->ftlibrary,
|
||||
&render_priv->state.stroker);
|
||||
#else // < 2.2
|
||||
error =
|
||||
FT_Stroker_New(render_priv->state.font->faces[0]->
|
||||
memory, &render_priv->state.stroker);
|
||||
#endif
|
||||
if (error) {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"failed to get stroker");
|
||||
|
@ -164,7 +158,7 @@ inline void change_alpha(uint32_t *var, uint32_t new, double pwr)
|
|||
{
|
||||
*var =
|
||||
(_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) +
|
||||
(_a(*var) * (1 - pwr) + _a(new) * pwr);
|
||||
(uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -233,20 +227,20 @@ static char *parse_vector_clip(ASS_Renderer *render_priv, char *p)
|
|||
while (*p != ')' && *p != '}' && p != 0)
|
||||
ass_drawing_add_char(drawing, *p++);
|
||||
skipopt(')');
|
||||
ass_drawing_parse(drawing, 1);
|
||||
|
||||
// We need to translate the clip according to screen borders
|
||||
if (render_priv->settings.left_margin != 0 ||
|
||||
render_priv->settings.top_margin != 0) {
|
||||
FT_Vector trans = {
|
||||
.x = int_to_d6(render_priv->settings.left_margin),
|
||||
.y = -int_to_d6(render_priv->settings.top_margin),
|
||||
};
|
||||
FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y);
|
||||
if (ass_drawing_parse(drawing, 1)) {
|
||||
// We need to translate the clip according to screen borders
|
||||
if (render_priv->settings.left_margin != 0 ||
|
||||
render_priv->settings.top_margin != 0) {
|
||||
FT_Vector trans = {
|
||||
.x = int_to_d6(render_priv->settings.left_margin),
|
||||
.y = -int_to_d6(render_priv->settings.top_margin),
|
||||
};
|
||||
FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y);
|
||||
}
|
||||
ass_msg(render_priv->library, MSGL_DBG2,
|
||||
"Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n",
|
||||
scale, drawing->scale_x, drawing->scale_y, drawing->text);
|
||||
}
|
||||
ass_msg(render_priv->library, MSGL_DBG2,
|
||||
"Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n",
|
||||
scale, drawing->scale_x, drawing->scale_y, drawing->text);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
@ -802,6 +796,81 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
|
|||
return p;
|
||||
}
|
||||
|
||||
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event)
|
||||
{
|
||||
int v[4];
|
||||
int cnt;
|
||||
char *p = event->Effect;
|
||||
|
||||
if (!p || !*p)
|
||||
return;
|
||||
|
||||
cnt = 0;
|
||||
while (cnt < 4 && (p = strchr(p, ';'))) {
|
||||
v[cnt++] = atoi(++p);
|
||||
}
|
||||
|
||||
if (strncmp(event->Effect, "Banner;", 7) == 0) {
|
||||
int delay;
|
||||
if (cnt < 1) {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"Error parsing effect: '%s'", event->Effect);
|
||||
return;
|
||||
}
|
||||
if (cnt >= 2 && v[1] == 0) // right-to-left
|
||||
render_priv->state.scroll_direction = SCROLL_RL;
|
||||
else // left-to-right
|
||||
render_priv->state.scroll_direction = SCROLL_LR;
|
||||
|
||||
delay = v[0];
|
||||
if (delay == 0)
|
||||
delay = 1; // ?
|
||||
render_priv->state.scroll_shift =
|
||||
(render_priv->time - render_priv->state.event->Start) / delay;
|
||||
render_priv->state.evt_type = EVENT_HSCROLL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
|
||||
render_priv->state.scroll_direction = SCROLL_BT;
|
||||
} else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
|
||||
render_priv->state.scroll_direction = SCROLL_TB;
|
||||
} else {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"Unknown transition effect: '%s'", event->Effect);
|
||||
return;
|
||||
}
|
||||
// parse scroll up/down parameters
|
||||
{
|
||||
int delay;
|
||||
int y0, y1;
|
||||
if (cnt < 3) {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"Error parsing effect: '%s'", event->Effect);
|
||||
return;
|
||||
}
|
||||
delay = v[2];
|
||||
if (delay == 0)
|
||||
delay = 1; // ?
|
||||
render_priv->state.scroll_shift =
|
||||
(render_priv->time - render_priv->state.event->Start) / delay;
|
||||
if (v[0] < v[1]) {
|
||||
y0 = v[0];
|
||||
y1 = v[1];
|
||||
} else {
|
||||
y0 = v[1];
|
||||
y1 = v[0];
|
||||
}
|
||||
if (y1 == 0)
|
||||
y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling
|
||||
render_priv->state.clip_y0 = y0;
|
||||
render_priv->state.clip_y1 = y1;
|
||||
render_priv->state.evt_type = EVENT_VSCROLL;
|
||||
render_priv->state.detect_collisions = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get next ucs4 char from string, parsing and executing style overrides
|
||||
* \param str string pointer
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
void update_font(ASS_Renderer *render_priv);
|
||||
void change_border(ASS_Renderer *render_priv, double border_x,
|
||||
double border_y);
|
||||
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
|
||||
unsigned get_next_char(ASS_Renderer *render_priv, char **str);
|
||||
extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
|
||||
extern uint32_t mult_alpha(uint32_t a, uint32_t b);
|
||||
|
|
|
@ -809,82 +809,6 @@ static void compute_string_bbox(TextInfo *info, DBBox *bbox)
|
|||
bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event)
|
||||
{
|
||||
int v[4];
|
||||
int cnt;
|
||||
char *p = event->Effect;
|
||||
|
||||
if (!p || !*p)
|
||||
return;
|
||||
|
||||
cnt = 0;
|
||||
while (cnt < 4 && (p = strchr(p, ';'))) {
|
||||
v[cnt++] = atoi(++p);
|
||||
}
|
||||
|
||||
if (strncmp(event->Effect, "Banner;", 7) == 0) {
|
||||
int delay;
|
||||
if (cnt < 1) {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"Error parsing effect: '%s'", event->Effect);
|
||||
return;
|
||||
}
|
||||
if (cnt >= 2 && v[1] == 0) // right-to-left
|
||||
render_priv->state.scroll_direction = SCROLL_RL;
|
||||
else // left-to-right
|
||||
render_priv->state.scroll_direction = SCROLL_LR;
|
||||
|
||||
delay = v[0];
|
||||
if (delay == 0)
|
||||
delay = 1; // ?
|
||||
render_priv->state.scroll_shift =
|
||||
(render_priv->time - render_priv->state.event->Start) / delay;
|
||||
render_priv->state.evt_type = EVENT_HSCROLL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
|
||||
render_priv->state.scroll_direction = SCROLL_BT;
|
||||
} else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
|
||||
render_priv->state.scroll_direction = SCROLL_TB;
|
||||
} else {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"Unknown transition effect: '%s'", event->Effect);
|
||||
return;
|
||||
}
|
||||
// parse scroll up/down parameters
|
||||
{
|
||||
int delay;
|
||||
int y0, y1;
|
||||
if (cnt < 3) {
|
||||
ass_msg(render_priv->library, MSGL_V,
|
||||
"Error parsing effect: '%s'", event->Effect);
|
||||
return;
|
||||
}
|
||||
delay = v[2];
|
||||
if (delay == 0)
|
||||
delay = 1; // ?
|
||||
render_priv->state.scroll_shift =
|
||||
(render_priv->time - render_priv->state.event->Start) / delay;
|
||||
if (v[0] < v[1]) {
|
||||
y0 = v[0];
|
||||
y1 = v[1];
|
||||
} else {
|
||||
y0 = v[1];
|
||||
y1 = v[0];
|
||||
}
|
||||
if (y1 == 0)
|
||||
y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling
|
||||
render_priv->state.clip_y0 = y0;
|
||||
render_priv->state.clip_y1 = y1;
|
||||
render_priv->state.evt_type = EVENT_VSCROLL;
|
||||
render_priv->state.detect_collisions = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief partially reset render_context to style values
|
||||
* Works like {\r}: resets some style overrides
|
||||
|
@ -947,6 +871,7 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
|
|||
render_priv->state.clip_y0 = 0;
|
||||
render_priv->state.clip_x1 = render_priv->track->PlayResX;
|
||||
render_priv->state.clip_y1 = render_priv->track->PlayResY;
|
||||
render_priv->state.clip_mode = 0;
|
||||
render_priv->state.detect_collisions = 1;
|
||||
render_priv->state.fade = 0;
|
||||
render_priv->state.drawing_mode = 0;
|
||||
|
@ -1208,7 +1133,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
|
|||
} else {
|
||||
GlyphHashValue v;
|
||||
if (drawing->hash) {
|
||||
ass_drawing_parse(drawing, 0);
|
||||
if(!ass_drawing_parse(drawing, 0))
|
||||
return;
|
||||
FT_Glyph_Copy((FT_Glyph) drawing->glyph, &info->glyph);
|
||||
} else {
|
||||
info->glyph =
|
||||
|
@ -1816,6 +1742,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
|
|||
int MarginL, MarginR, MarginV;
|
||||
int last_break;
|
||||
int alignment, halign, valign;
|
||||
int kern = render_priv->track->Kerning;
|
||||
double device_x = 0;
|
||||
double device_y = 0;
|
||||
TextInfo *text_info = &render_priv->text_info;
|
||||
|
@ -1879,7 +1806,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
|
|||
}
|
||||
|
||||
// Add kerning to pen
|
||||
if (previous && code && !drawing->hash) {
|
||||
if (kern && previous && code && !drawing->hash) {
|
||||
FT_Vector delta;
|
||||
delta =
|
||||
ass_font_get_kerning(render_priv->state.font, previous,
|
||||
|
@ -1980,23 +1907,23 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
|
|||
drawing->hash;
|
||||
text_info->glyphs[text_info->length].hash_key.ch = code;
|
||||
text_info->glyphs[text_info->length].hash_key.outline.x =
|
||||
render_priv->state.border_x * 0xFFFF;
|
||||
double_to_d16(render_priv->state.border_x);
|
||||
text_info->glyphs[text_info->length].hash_key.outline.y =
|
||||
render_priv->state.border_y * 0xFFFF;
|
||||
double_to_d16(render_priv->state.border_y);
|
||||
text_info->glyphs[text_info->length].hash_key.scale_x =
|
||||
render_priv->state.scale_x * 0xFFFF;
|
||||
double_to_d16(render_priv->state.scale_x);
|
||||
text_info->glyphs[text_info->length].hash_key.scale_y =
|
||||
render_priv->state.scale_y * 0xFFFF;
|
||||
double_to_d16(render_priv->state.scale_y);
|
||||
text_info->glyphs[text_info->length].hash_key.frx =
|
||||
render_priv->state.frx * 0xFFFF;
|
||||
rot_key(render_priv->state.frx);
|
||||
text_info->glyphs[text_info->length].hash_key.fry =
|
||||
render_priv->state.fry * 0xFFFF;
|
||||
rot_key(render_priv->state.fry);
|
||||
text_info->glyphs[text_info->length].hash_key.frz =
|
||||
render_priv->state.frz * 0xFFFF;
|
||||
rot_key(render_priv->state.frz);
|
||||
text_info->glyphs[text_info->length].hash_key.fax =
|
||||
render_priv->state.fax * 0xFFFF;
|
||||
double_to_d16(render_priv->state.fax);
|
||||
text_info->glyphs[text_info->length].hash_key.fay =
|
||||
render_priv->state.fay * 0xFFFF;
|
||||
double_to_d16(render_priv->state.fay);
|
||||
text_info->glyphs[text_info->length].hash_key.advance.x = pen.x;
|
||||
text_info->glyphs[text_info->length].hash_key.advance.y = pen.y;
|
||||
text_info->glyphs[text_info->length].hash_key.be =
|
||||
|
|
247
aegisub/libass/ass_strtod.c
Normal file
247
aegisub/libass/ass_strtod.c
Normal 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;
|
||||
}
|
|
@ -113,6 +113,7 @@ typedef struct ass_track {
|
|||
double Timer;
|
||||
int WrapStyle;
|
||||
int ScaledBorderAndShadow;
|
||||
int Kerning;
|
||||
|
||||
int default_style; // index of default style
|
||||
char *name; // file name in case of external subs, 0 for streams
|
||||
|
|
|
@ -34,7 +34,7 @@ int mystrtoi(char **p, int *res)
|
|||
{
|
||||
double temp_res;
|
||||
char *start = *p;
|
||||
temp_res = strtod(*p, p);
|
||||
temp_res = ass_strtod(*p, p);
|
||||
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
|
||||
if (*p != start)
|
||||
return 1;
|
||||
|
@ -46,7 +46,7 @@ int mystrtoll(char **p, long long *res)
|
|||
{
|
||||
double temp_res;
|
||||
char *start = *p;
|
||||
temp_res = strtod(*p, p);
|
||||
temp_res = ass_strtod(*p, p);
|
||||
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
|
||||
if (*p != start)
|
||||
return 1;
|
||||
|
@ -67,7 +67,7 @@ int mystrtou32(char **p, int base, uint32_t *res)
|
|||
int mystrtod(char **p, double *res)
|
||||
{
|
||||
char *start = *p;
|
||||
*res = strtod(*p, p);
|
||||
*res = ass_strtod(*p, p);
|
||||
if (*p != start)
|
||||
return 1;
|
||||
else
|
||||
|
|
|
@ -59,6 +59,9 @@ void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
|
|||
char *fallback);
|
||||
#endif
|
||||
|
||||
/* defined in ass_strtod.c */
|
||||
double ass_strtod(const char *string, char **endPtr);
|
||||
|
||||
static inline int d6_to_int(int x)
|
||||
{
|
||||
return (x + 32) >> 6;
|
||||
|
@ -99,6 +102,21 @@ static inline int double_to_d16(double x)
|
|||
{
|
||||
return (int) (x * 0x10000);
|
||||
}
|
||||
static inline double d22_to_double(int x)
|
||||
{
|
||||
return ((double) x) / 0x400000;
|
||||
}
|
||||
static inline int double_to_d22(double x)
|
||||
{
|
||||
return (int) (x * 0x400000);
|
||||
}
|
||||
|
||||
// Calculate cache key for a rotational angle in degrees
|
||||
static inline int rot_key(double a)
|
||||
{
|
||||
const int m = double_to_d22(360.0);
|
||||
return double_to_d22(a) % m;
|
||||
}
|
||||
|
||||
#define FNV1_32A_INIT (unsigned)0x811c9dc5
|
||||
|
||||
|
|
Loading…
Reference in a new issue