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_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 += \
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
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;
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue