mirror of
https://github.com/odrling/Aegisub
synced 2025-04-11 22:56:02 +02:00
Update libass to r26265 from the MPlayer repo, I havn't checked all the changes
but one of the largest changes is that it now reads and uses Playres X/Y and the video res so \mov works correctly now. Originally committed to SVN as r2092.
This commit is contained in:
parent
005e32f3f5
commit
b060751cfe
67
libass/ass.c
67
libass/ass.c
@ -27,7 +27,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
//#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#ifdef USE_ICONV
|
#ifdef USE_ICONV
|
||||||
@ -271,6 +271,14 @@ static int process_event_tail(ass_track_t* track, ass_event_t* event, char* str,
|
|||||||
char* format = strdup(track->event_format);
|
char* format = strdup(track->event_format);
|
||||||
char* q = format; // format scanning pointer
|
char* q = format; // format scanning pointer
|
||||||
|
|
||||||
|
if (track->n_styles == 0) {
|
||||||
|
// add "Default" style to the end
|
||||||
|
// will be used if track does not contain a default style (or even does not contain styles at all)
|
||||||
|
int sid = ass_alloc_style(track);
|
||||||
|
track->styles[sid].Name = strdup("Default");
|
||||||
|
track->styles[sid].FontName = strdup("Arial");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_ignored; ++i) {
|
for (i = 0; i < n_ignored; ++i) {
|
||||||
NEXT(q, tname);
|
NEXT(q, tname);
|
||||||
}
|
}
|
||||||
@ -323,13 +331,22 @@ void process_force_style(ass_track_t* track) {
|
|||||||
if (!list) return;
|
if (!list) return;
|
||||||
|
|
||||||
for (fs = list; *fs; ++fs) {
|
for (fs = list; *fs; ++fs) {
|
||||||
eq = strchr(*fs, '=');
|
eq = strrchr(*fs, '=');
|
||||||
if (!eq)
|
if (!eq)
|
||||||
continue;
|
continue;
|
||||||
*eq = '\0';
|
*eq = '\0';
|
||||||
token = eq + 1;
|
token = eq + 1;
|
||||||
|
|
||||||
dt = strchr(*fs, '.');
|
if(!strcasecmp(*fs, "PlayResX"))
|
||||||
|
track->PlayResX = atoi(token);
|
||||||
|
else if(!strcasecmp(*fs, "PlayResY"))
|
||||||
|
track->PlayResY = atoi(token);
|
||||||
|
else if(!strcasecmp(*fs, "Timer"))
|
||||||
|
track->Timer = atof(token);
|
||||||
|
else if(!strcasecmp(*fs, "WrapStyle"))
|
||||||
|
track->WrapStyle = atoi(token);
|
||||||
|
|
||||||
|
dt = strrchr(*fs, '.');
|
||||||
if (dt) {
|
if (dt) {
|
||||||
*dt = '\0';
|
*dt = '\0';
|
||||||
style = *fs;
|
style = *fs;
|
||||||
@ -697,7 +714,6 @@ static int process_text(ass_track_t* track, char* str)
|
|||||||
void ass_process_codec_private(ass_track_t* track, char *data, int size)
|
void ass_process_codec_private(ass_track_t* track, char *data, int size)
|
||||||
{
|
{
|
||||||
char* str = malloc(size + 1);
|
char* str = malloc(size + 1);
|
||||||
int sid;
|
|
||||||
|
|
||||||
memcpy(str, data, size);
|
memcpy(str, data, size);
|
||||||
str[size] = '\0';
|
str[size] = '\0';
|
||||||
@ -705,12 +721,6 @@ void ass_process_codec_private(ass_track_t* track, char *data, int size)
|
|||||||
process_text(track, str);
|
process_text(track, str);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
// add "Default" style to the end
|
|
||||||
// will be used if track does not contain a default style (or even does not contain styles at all)
|
|
||||||
sid = ass_alloc_style(track);
|
|
||||||
track->styles[sid].Name = strdup("Default");
|
|
||||||
track->styles[sid].FontName = strdup("Arial");
|
|
||||||
|
|
||||||
if (!track->event_format) {
|
if (!track->event_format) {
|
||||||
// probably an mkv produced by ancient mkvtoolnix
|
// probably an mkv produced by ancient mkvtoolnix
|
||||||
// such files don't have [Events] and Format: headers
|
// such files don't have [Events] and Format: headers
|
||||||
@ -734,7 +744,7 @@ static int check_duplicate_event(ass_track_t* track, int ReadOrder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Process a chunk of subtitle stream data. In matroska, this containes exactly 1 event (or a commentary)
|
* \brief Process a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary).
|
||||||
* \param track track
|
* \param track track
|
||||||
* \param data string to parse
|
* \param data string to parse
|
||||||
* \param size length of data
|
* \param size length of data
|
||||||
@ -803,7 +813,7 @@ static char* sub_recode(char* data, size_t size, char* codepage)
|
|||||||
assert(codepage);
|
assert(codepage);
|
||||||
|
|
||||||
{
|
{
|
||||||
char* cp_tmp = codepage ? strdup(codepage) : 0;
|
const char* cp_tmp = codepage;
|
||||||
#ifdef HAVE_ENCA
|
#ifdef HAVE_ENCA
|
||||||
char enca_lang[3], enca_fallback[100];
|
char enca_lang[3], enca_fallback[100];
|
||||||
if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2
|
if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2
|
||||||
@ -815,9 +825,6 @@ static char* sub_recode(char* data, size_t size, char* codepage)
|
|||||||
mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: opened iconv descriptor.\n");
|
mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: opened iconv descriptor.\n");
|
||||||
} else
|
} else
|
||||||
mp_msg(MSGT_ASS,MSGL_ERR,MSGTR_LIBASS_ErrorOpeningIconvDescriptor);
|
mp_msg(MSGT_ASS,MSGL_ERR,MSGTR_LIBASS_ErrorOpeningIconvDescriptor);
|
||||||
#ifdef HAVE_ENCA
|
|
||||||
if (cp_tmp) free(cp_tmp);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -982,17 +989,9 @@ ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize,
|
|||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
char* read_file_recode(char* fname, char* codepage, int* size)
|
||||||
* \brief Read subtitles from file.
|
|
||||||
* \param library libass library object
|
|
||||||
* \param fname file name
|
|
||||||
* \param codepage recode buffer contents from given codepage
|
|
||||||
* \return newly allocated track
|
|
||||||
*/
|
|
||||||
ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage)
|
|
||||||
{
|
{
|
||||||
char* buf;
|
char* buf;
|
||||||
ass_track_t* track;
|
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
|
|
||||||
buf = read_file(fname, &bufsize);
|
buf = read_file(fname, &bufsize);
|
||||||
@ -1007,6 +1006,26 @@ ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage)
|
|||||||
if (!buf)
|
if (!buf)
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
*size = bufsize;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Read subtitles from file.
|
||||||
|
* \param library libass library object
|
||||||
|
* \param fname file name
|
||||||
|
* \param codepage recode buffer contents from given codepage
|
||||||
|
* \return newly allocated track
|
||||||
|
*/
|
||||||
|
ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage)
|
||||||
|
{
|
||||||
|
char* buf;
|
||||||
|
ass_track_t* track;
|
||||||
|
size_t bufsize;
|
||||||
|
|
||||||
|
buf = read_file_recode(fname, codepage, &bufsize);
|
||||||
|
if (!buf)
|
||||||
|
return 0;
|
||||||
track = parse_memory(library, buf);
|
track = parse_memory(library, buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
if (!track)
|
if (!track)
|
||||||
|
20
libass/ass.h
20
libass/ass.h
@ -18,9 +18,10 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_H__
|
#ifndef LIBASS_ASS_H
|
||||||
#define __ASS_H__
|
#define LIBASS_ASS_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include "ass_types.h"
|
#include "ass_types.h"
|
||||||
|
|
||||||
/// Libass renderer object. Contents are private.
|
/// Libass renderer object. Contents are private.
|
||||||
@ -85,6 +86,7 @@ void ass_set_use_margins(ass_renderer_t* priv, int use);
|
|||||||
void ass_set_aspect_ratio(ass_renderer_t* priv, double ar);
|
void ass_set_aspect_ratio(ass_renderer_t* priv, double ar);
|
||||||
void ass_set_font_scale(ass_renderer_t* priv, double font_scale);
|
void ass_set_font_scale(ass_renderer_t* priv, double font_scale);
|
||||||
void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht);
|
void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht);
|
||||||
|
void ass_set_line_spacing(ass_renderer_t* priv, double line_spacing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief set font lookup defaults
|
* \brief set font lookup defaults
|
||||||
@ -145,7 +147,7 @@ void ass_free_style(ass_track_t* track, int sid);
|
|||||||
void ass_free_event(ass_track_t* track, int eid);
|
void ass_free_event(ass_track_t* track, int eid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Process Codec Private section of subtitle stream
|
* \brief Parse Codec Private section of subtitle stream
|
||||||
* \param track target track
|
* \param track target track
|
||||||
* \param data string to parse
|
* \param data string to parse
|
||||||
* \param size length of data
|
* \param size length of data
|
||||||
@ -153,7 +155,7 @@ void ass_free_event(ass_track_t* track, int eid);
|
|||||||
void ass_process_codec_private(ass_track_t* track, char *data, int size);
|
void ass_process_codec_private(ass_track_t* track, char *data, int size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Process a chunk of subtitle stream data. In matroska, this containes exactly 1 event (or a commentary)
|
* \brief Parse a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary).
|
||||||
* \param track track
|
* \param track track
|
||||||
* \param data string to parse
|
* \param data string to parse
|
||||||
* \param size length of data
|
* \param size length of data
|
||||||
@ -162,6 +164,8 @@ void ass_process_codec_private(ass_track_t* track, char *data, int size);
|
|||||||
*/
|
*/
|
||||||
void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration);
|
void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration);
|
||||||
|
|
||||||
|
char* read_file_recode(char* fname, char* codepage, int* size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Read subtitles from file.
|
* \brief Read subtitles from file.
|
||||||
* \param fname file name
|
* \param fname file name
|
||||||
@ -192,6 +196,11 @@ int ass_read_styles(ass_track_t* track, char* fname, char* codepage);
|
|||||||
*/
|
*/
|
||||||
void ass_add_font(ass_library_t* library, char* name, char* data, int data_size);
|
void ass_add_font(ass_library_t* library, char* name, char* data, int data_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Remove all fonts stored in ass_library object
|
||||||
|
*/
|
||||||
|
void ass_clear_fonts(ass_library_t* library);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Calculates timeshift from now to the start of some other subtitle event, depending on movement parameter
|
* \brief Calculates timeshift from now to the start of some other subtitle event, depending on movement parameter
|
||||||
* \param track subtitle track
|
* \param track subtitle track
|
||||||
@ -202,5 +211,4 @@ void ass_add_font(ass_library_t* library, char* name, char* data, int data_size)
|
|||||||
*/
|
*/
|
||||||
long long ass_step_sub(ass_track_t* track, long long now, int movement);
|
long long ass_step_sub(ass_track_t* track, long long now, int movement);
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_ASS_H */
|
||||||
|
|
||||||
|
@ -150,6 +150,20 @@ static bitmap_t* copy_bitmap(const bitmap_t* src)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_glyph_area(FT_Glyph glyph)
|
||||||
|
{
|
||||||
|
FT_BBox bbox;
|
||||||
|
long long dx, dy;
|
||||||
|
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
|
||||||
|
dx = bbox.xMax - bbox.xMin;
|
||||||
|
dy = bbox.yMax - bbox.yMin;
|
||||||
|
if (dx * dy > 8000000) {
|
||||||
|
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_GlyphBBoxTooLarge, (int)dx, (int)dy);
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
|
static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
|
||||||
{
|
{
|
||||||
FT_BitmapGlyph bg;
|
FT_BitmapGlyph bg;
|
||||||
@ -161,6 +175,8 @@ static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
|
|||||||
int i;
|
int i;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
if (check_glyph_area(glyph))
|
||||||
|
return 0;
|
||||||
error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
|
error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
|
||||||
if (error) {
|
if (error) {
|
||||||
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, error);
|
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, error);
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_BITMAP_H__
|
#ifndef LIBASS_BITMAP_H
|
||||||
#define __ASS_BITMAP_H__
|
#define LIBASS_BITMAP_H
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_GLYPH_H
|
||||||
|
|
||||||
typedef struct ass_synth_priv_s ass_synth_priv_t;
|
typedef struct ass_synth_priv_s ass_synth_priv_t;
|
||||||
|
|
||||||
@ -45,5 +48,4 @@ int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_gly
|
|||||||
|
|
||||||
void ass_free_bitmap(bitmap_t* bm);
|
void ass_free_bitmap(bitmap_t* bm);
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_BITMAP_H */
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ struct hashmap_s {
|
|||||||
|
|
||||||
#define FNV1_32A_INIT (unsigned)0x811c9dc5
|
#define FNV1_32A_INIT (unsigned)0x811c9dc5
|
||||||
|
|
||||||
static unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval)
|
static inline unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval)
|
||||||
{
|
{
|
||||||
unsigned char *bp = buf;
|
unsigned char *bp = buf;
|
||||||
unsigned char *be = bp + len;
|
unsigned char *be = bp + len;
|
||||||
@ -67,7 +67,7 @@ static unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval)
|
|||||||
}
|
}
|
||||||
return hval;
|
return hval;
|
||||||
}
|
}
|
||||||
static unsigned fnv_32a_str(char* str, unsigned hval)
|
static inline unsigned fnv_32a_str(char* str, unsigned hval)
|
||||||
{
|
{
|
||||||
unsigned char* s = (unsigned char*)str;
|
unsigned char* s = (unsigned char*)str;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_CACHE_H__
|
#ifndef LIBASS_CACHE_H
|
||||||
#define __ASS_CACHE_H__
|
#define LIBASS_CACHE_H
|
||||||
|
|
||||||
|
#include "ass.h"
|
||||||
|
#include "ass_font.h"
|
||||||
|
#include "ass_bitmap.h"
|
||||||
|
|
||||||
void ass_font_cache_init(void);
|
void ass_font_cache_init(void);
|
||||||
ass_font_t* ass_font_cache_find(ass_font_desc_t* desc);
|
ass_font_t* ass_font_cache_find(ass_font_desc_t* desc);
|
||||||
@ -94,5 +98,4 @@ void hashmap_done(hashmap_t* map);
|
|||||||
void* hashmap_insert(hashmap_t* map, void* key, void* value);
|
void* hashmap_insert(hashmap_t* map, void* key, void* value);
|
||||||
void* hashmap_find(hashmap_t* map, void* key);
|
void* hashmap_find(hashmap_t* map, void* key);
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_CACHE_H */
|
||||||
|
|
||||||
|
@ -87,46 +87,85 @@ static int find_font(ass_library_t* library, char* name)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void face_set_size(FT_Face face, double size);
|
||||||
|
|
||||||
|
static void buggy_font_workaround(FT_Face face)
|
||||||
|
{
|
||||||
|
// Some fonts have zero Ascender/Descender fields in 'hhea' table.
|
||||||
|
// In this case, get the information from 'os2' table or, as
|
||||||
|
// a last resort, from face.bbox.
|
||||||
|
if (face->ascender + face->descender == 0 || face->height == 0) {
|
||||||
|
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
|
||||||
|
if (os2) {
|
||||||
|
face->ascender = os2->sTypoAscender;
|
||||||
|
face->descender = os2->sTypoDescender;
|
||||||
|
face->height = face->ascender - face->descender;
|
||||||
|
} else {
|
||||||
|
face->ascender = face->bbox.yMax;
|
||||||
|
face->descender = face->bbox.yMin;
|
||||||
|
face->height = face->ascender - face->descender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Create a new ass_font_t according to "desc" argument
|
* \brief Select a face with the given charcode and add it to ass_font_t
|
||||||
|
* \return index of the new face in font->faces, -1 if failed
|
||||||
*/
|
*/
|
||||||
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc)
|
static int add_face(void* fc_priv, ass_font_t* font, uint32_t ch)
|
||||||
{
|
{
|
||||||
char* path;
|
char* path;
|
||||||
int index;
|
int index;
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
|
int error;
|
||||||
|
int mem_idx;
|
||||||
|
|
||||||
|
if (font->n_faces == ASS_FONT_MAX_FACES)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
path = fontconfig_select(fc_priv, font->desc.family, font->desc.bold,
|
||||||
|
font->desc.italic, &index, ch);
|
||||||
|
|
||||||
|
mem_idx = find_font(font->library, path);
|
||||||
|
if (mem_idx >= 0) {
|
||||||
|
error = FT_New_Memory_Face(font->ftlibrary, (unsigned char*)font->library->fontdata[mem_idx].data,
|
||||||
|
font->library->fontdata[mem_idx].size, 0, &face);
|
||||||
|
if (error) {
|
||||||
|
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = FT_New_Face(font->ftlibrary, path, index, &face);
|
||||||
|
if (error) {
|
||||||
|
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, index);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
charmap_magic(face);
|
||||||
|
buggy_font_workaround(face);
|
||||||
|
|
||||||
|
font->faces[font->n_faces++] = face;
|
||||||
|
update_transform(font);
|
||||||
|
face_set_size(face, font->size);
|
||||||
|
return font->n_faces - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Create a new ass_font_t according to "desc" argument
|
||||||
|
*/
|
||||||
|
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc)
|
||||||
|
{
|
||||||
int error;
|
int error;
|
||||||
ass_font_t* fontp;
|
ass_font_t* fontp;
|
||||||
ass_font_t font;
|
ass_font_t font;
|
||||||
int mem_idx;
|
|
||||||
|
|
||||||
fontp = ass_font_cache_find(desc);
|
fontp = ass_font_cache_find(desc);
|
||||||
if (fontp)
|
if (fontp)
|
||||||
return fontp;
|
return fontp;
|
||||||
|
|
||||||
path = fontconfig_select(fc_priv, desc->family, desc->bold, desc->italic, &index);
|
font.library = library;
|
||||||
|
|
||||||
mem_idx = find_font(library, path);
|
|
||||||
if (mem_idx >= 0) {
|
|
||||||
error = FT_New_Memory_Face(ftlibrary, (unsigned char*)library->fontdata[mem_idx].data,
|
|
||||||
library->fontdata[mem_idx].size, 0, &face);
|
|
||||||
if (error) {
|
|
||||||
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error = FT_New_Face(ftlibrary, path, index, &face);
|
|
||||||
if (error) {
|
|
||||||
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, index);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
charmap_magic(face);
|
|
||||||
|
|
||||||
font.ftlibrary = ftlibrary;
|
font.ftlibrary = ftlibrary;
|
||||||
font.faces[0] = face;
|
font.n_faces = 0;
|
||||||
font.n_faces = 1;
|
|
||||||
font.desc.family = strdup(desc->family);
|
font.desc.family = strdup(desc->family);
|
||||||
font.desc.bold = desc->bold;
|
font.desc.bold = desc->bold;
|
||||||
font.desc.italic = desc->italic;
|
font.desc.italic = desc->italic;
|
||||||
@ -135,11 +174,12 @@ ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_
|
|||||||
font.v.x = font.v.y = 0;
|
font.v.x = font.v.y = 0;
|
||||||
font.size = 0.;
|
font.size = 0.;
|
||||||
|
|
||||||
#ifdef HAVE_FONTCONFIG
|
error = add_face(fc_priv, &font, 0);
|
||||||
font.charset = FcCharSetCreate();
|
if (error == -1) {
|
||||||
#endif
|
free(font.desc.family);
|
||||||
|
return 0;
|
||||||
return ass_font_cache_add(&font);
|
} else
|
||||||
|
return ass_font_cache_add(&font);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,8 +204,12 @@ static void face_set_size(FT_Face face, double size)
|
|||||||
FT_Size_Metrics *m = &face->size->metrics;
|
FT_Size_Metrics *m = &face->size->metrics;
|
||||||
// VSFilter uses metrics from TrueType OS/2 table
|
// VSFilter uses metrics from TrueType OS/2 table
|
||||||
// The idea was borrowed from asa (http://asa.diac24.net)
|
// The idea was borrowed from asa (http://asa.diac24.net)
|
||||||
if (hori && os2)
|
if (hori && os2) {
|
||||||
mscale = ((double)(hori->Ascender - hori->Descender)) / (os2->usWinAscent + os2->usWinDescent);
|
int hori_height = hori->Ascender - hori->Descender;
|
||||||
|
int os2_height = os2->usWinAscent + os2->usWinDescent;
|
||||||
|
if (hori_height && os2_height)
|
||||||
|
mscale = (double)hori_height / os2_height;
|
||||||
|
}
|
||||||
memset(&rq, 0, sizeof(rq));
|
memset(&rq, 0, sizeof(rq));
|
||||||
rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||||
rq.width = 0;
|
rq.width = 0;
|
||||||
@ -193,43 +237,6 @@ void ass_font_set_size(ass_font_t* font, double size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FONTCONFIG
|
|
||||||
/**
|
|
||||||
* \brief Select a new FT_Face with the given character
|
|
||||||
* The new face is added to the end of font->faces.
|
|
||||||
**/
|
|
||||||
static void ass_font_reselect(void* fontconfig_priv, ass_font_t* font, uint32_t ch)
|
|
||||||
{
|
|
||||||
char* path;
|
|
||||||
int index;
|
|
||||||
FT_Face face;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (font->n_faces == ASS_FONT_MAX_FACES)
|
|
||||||
return;
|
|
||||||
|
|
||||||
path = fontconfig_select_with_charset(fontconfig_priv, font->desc.family, font->desc.bold,
|
|
||||||
font->desc.italic, &index, font->charset);
|
|
||||||
|
|
||||||
error = FT_New_Face(font->ftlibrary, path, index, &face);
|
|
||||||
if (error) {
|
|
||||||
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
charmap_magic(face);
|
|
||||||
|
|
||||||
error = FT_Get_Char_Index(face, ch);
|
|
||||||
if (error == 0) { // the new font face is not better then the old one
|
|
||||||
FT_Done_Face(face);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
font->faces[font->n_faces++] = face;
|
|
||||||
update_transform(font);
|
|
||||||
FT_Set_Pixel_Sizes(face, 0, (int)font->size);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get maximal font ascender and descender.
|
* \brief Get maximal font ascender and descender.
|
||||||
* \param ch character code
|
* \param ch character code
|
||||||
@ -241,14 +248,8 @@ void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc)
|
|||||||
for (i = 0; i < font->n_faces; ++i) {
|
for (i = 0; i < font->n_faces; ++i) {
|
||||||
FT_Face face = font->faces[i];
|
FT_Face face = font->faces[i];
|
||||||
if (FT_Get_Char_Index(face, ch)) {
|
if (FT_Get_Char_Index(face, ch)) {
|
||||||
int v, v2;
|
*asc = face->size->metrics.ascender;
|
||||||
v = face->size->metrics.ascender;
|
*desc = - face->size->metrics.descender;
|
||||||
v2 = FT_MulFix(face->bbox.yMax, face->size->metrics.y_scale);
|
|
||||||
*asc = (v > v2 * 0.9) ? v : v2;
|
|
||||||
|
|
||||||
v = - face->size->metrics.descender;
|
|
||||||
v2 = - FT_MulFix(face->bbox.yMin, face->size->metrics.y_scale);
|
|
||||||
*desc = (v > v2 * 0.9) ? v : v2;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,16 +283,18 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FONTCONFIG
|
#ifdef HAVE_FONTCONFIG
|
||||||
FcCharSetAddChar(font->charset, ch);
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
|
int face_idx;
|
||||||
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont,
|
mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont,
|
||||||
ch, font->desc.family, font->desc.bold, font->desc.italic);
|
ch, font->desc.family, font->desc.bold, font->desc.italic);
|
||||||
ass_font_reselect(fontconfig_priv, font, ch);
|
face_idx = add_face(fontconfig_priv, font, ch);
|
||||||
face = font->faces[font->n_faces - 1];
|
if (face_idx >= 0) {
|
||||||
index = FT_Get_Char_Index(face, ch);
|
face = font->faces[face_idx];
|
||||||
if (index == 0) {
|
index = FT_Get_Char_Index(face, ch);
|
||||||
mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound,
|
if (index == 0) {
|
||||||
ch, font->desc.family, font->desc.bold, font->desc.italic);
|
mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound,
|
||||||
|
ch, font->desc.family, font->desc.bold, font->desc.italic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -359,8 +362,5 @@ void ass_font_free(ass_font_t* font)
|
|||||||
for (i = 0; i < font->n_faces; ++i)
|
for (i = 0; i < font->n_faces; ++i)
|
||||||
if (font->faces[i]) FT_Done_Face(font->faces[i]);
|
if (font->faces[i]) FT_Done_Face(font->faces[i]);
|
||||||
if (font->desc.family) free(font->desc.family);
|
if (font->desc.family) free(font->desc.family);
|
||||||
#ifdef HAVE_FONTCONFIG
|
|
||||||
if (font->charset) FcCharSetDestroy(font->charset);
|
|
||||||
#endif
|
|
||||||
free(font);
|
free(font);
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,14 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_FONT_H__
|
#ifndef LIBASS_FONT_H
|
||||||
#define __ASS_FONT_H__
|
#define LIBASS_FONT_H
|
||||||
|
|
||||||
#ifdef HAVE_FONTCONFIG
|
#include <stdint.h>
|
||||||
#include <fontconfig/fontconfig.h>
|
#include <ft2build.h>
|
||||||
#endif
|
#include FT_GLYPH_H
|
||||||
|
#include "ass.h"
|
||||||
|
#include "ass_types.h"
|
||||||
|
|
||||||
typedef struct ass_font_desc_s {
|
typedef struct ass_font_desc_s {
|
||||||
char* family;
|
char* family;
|
||||||
@ -35,15 +37,13 @@ typedef struct ass_font_desc_s {
|
|||||||
|
|
||||||
typedef struct ass_font_s {
|
typedef struct ass_font_s {
|
||||||
ass_font_desc_t desc;
|
ass_font_desc_t desc;
|
||||||
|
ass_library_t* library;
|
||||||
FT_Library ftlibrary;
|
FT_Library ftlibrary;
|
||||||
FT_Face faces[ASS_FONT_MAX_FACES];
|
FT_Face faces[ASS_FONT_MAX_FACES];
|
||||||
int n_faces;
|
int n_faces;
|
||||||
double scale_x, scale_y; // current transform
|
double scale_x, scale_y; // current transform
|
||||||
FT_Vector v; // current shift
|
FT_Vector v; // current shift
|
||||||
double size;
|
double size;
|
||||||
#ifdef HAVE_FONTCONFIG
|
|
||||||
FcCharSet* charset;
|
|
||||||
#endif
|
|
||||||
} ass_font_t;
|
} ass_font_t;
|
||||||
|
|
||||||
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc);
|
ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc);
|
||||||
@ -54,4 +54,4 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch
|
|||||||
FT_Vector ass_font_get_kerning(ass_font_t* font, uint32_t c1, uint32_t c2);
|
FT_Vector ass_font_get_kerning(ass_font_t* font, uint32_t c1, uint32_t c2);
|
||||||
void ass_font_free(ass_font_t* font);
|
void ass_font_free(ass_font_t* font);
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_FONT_H */
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
#include <fontconfig/fcfreetype.h>
|
#include <fontconfig/fcfreetype.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern int font_fontconfig;
|
||||||
|
|
||||||
struct fc_instance_s {
|
struct fc_instance_s {
|
||||||
#ifdef HAVE_FONTCONFIG
|
#ifdef HAVE_FONTCONFIG
|
||||||
FcConfig* config;
|
FcConfig* config;
|
||||||
@ -57,11 +59,11 @@ struct fc_instance_s {
|
|||||||
* \param bold font weight value
|
* \param bold font weight value
|
||||||
* \param italic font slant value
|
* \param italic font slant value
|
||||||
* \param index out: font index inside a file
|
* \param index out: font index inside a file
|
||||||
* \param charset: contains the characters that should be present in the font, can be NULL
|
* \param code: the character that should be present in the font, can be 0
|
||||||
* \return font file path
|
* \return font file path
|
||||||
*/
|
*/
|
||||||
static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index,
|
static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index,
|
||||||
FcCharSet* charset)
|
uint32_t code)
|
||||||
{
|
{
|
||||||
FcBool rc;
|
FcBool rc;
|
||||||
FcResult result;
|
FcResult result;
|
||||||
@ -71,7 +73,7 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
|
|||||||
FcBool val_b;
|
FcBool val_b;
|
||||||
FcCharSet* val_cs;
|
FcCharSet* val_cs;
|
||||||
FcFontSet* fset = 0;
|
FcFontSet* fset = 0;
|
||||||
int curf, bestf, bestdiff = 0;
|
int curf;
|
||||||
char* retval = 0;
|
char* retval = 0;
|
||||||
|
|
||||||
*index = 0;
|
*index = 0;
|
||||||
@ -93,9 +95,6 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
|
|||||||
|
|
||||||
fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
|
fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
|
||||||
|
|
||||||
bestf = -1;
|
|
||||||
if (charset)
|
|
||||||
bestdiff = FcCharSetCount(charset) + 1;
|
|
||||||
for (curf = 0; curf < fset->nfont; ++curf) {
|
for (curf = 0; curf < fset->nfont; ++curf) {
|
||||||
rpat = fset->fonts[curf];
|
rpat = fset->fonts[curf];
|
||||||
|
|
||||||
@ -104,29 +103,19 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
|
|||||||
continue;
|
continue;
|
||||||
if (val_b != FcTrue)
|
if (val_b != FcTrue)
|
||||||
continue;
|
continue;
|
||||||
|
if (!code)
|
||||||
if (charset) {
|
break;
|
||||||
int diff;
|
result = FcPatternGetCharSet(rpat, FC_CHARSET, 0, &val_cs);
|
||||||
result = FcPatternGetCharSet(rpat, FC_CHARSET, 0, &val_cs);
|
if (result != FcResultMatch)
|
||||||
if (result != FcResultMatch)
|
continue;
|
||||||
continue;
|
if (FcCharSetHasChar(val_cs, code))
|
||||||
diff = FcCharSetSubtractCount(charset, val_cs);
|
|
||||||
if (diff < bestdiff) {
|
|
||||||
bestdiff = diff;
|
|
||||||
bestf = curf;
|
|
||||||
}
|
|
||||||
if (diff == 0)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
bestf = curf;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestf < 0)
|
if (curf >= fset->nfont)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
rpat = fset->fonts[bestf];
|
rpat = fset->fonts[curf];
|
||||||
|
|
||||||
result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i);
|
result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i);
|
||||||
if (result != FcResultMatch)
|
if (result != FcResultMatch)
|
||||||
@ -159,17 +148,21 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold
|
|||||||
* \param bold font weight value
|
* \param bold font weight value
|
||||||
* \param italic font slant value
|
* \param italic font slant value
|
||||||
* \param index out: font index inside a file
|
* \param index out: font index inside a file
|
||||||
* \param charset: contains the characters that should be present in the font, can be NULL
|
* \param code: the character that should be present in the font, can be 0
|
||||||
* \return font file path
|
* \return font file path
|
||||||
*/
|
*/
|
||||||
char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index,
|
char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index,
|
||||||
FcCharSet* charset)
|
uint32_t code)
|
||||||
{
|
{
|
||||||
char* res = 0;
|
char* res = 0;
|
||||||
|
if (font_fontconfig < 0) {
|
||||||
|
*index = priv->index_default;
|
||||||
|
return priv->path_default;
|
||||||
|
}
|
||||||
if (family && *family)
|
if (family && *family)
|
||||||
res = _select_font(priv, family, bold, italic, index, charset);
|
res = _select_font(priv, family, bold, italic, index, code);
|
||||||
if (!res && priv->family_default) {
|
if (!res && priv->family_default) {
|
||||||
res = _select_font(priv, priv->family_default, bold, italic, index, charset);
|
res = _select_font(priv, priv->family_default, bold, italic, index, code);
|
||||||
if (res)
|
if (res)
|
||||||
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily,
|
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily,
|
||||||
family, bold, italic, res, *index);
|
family, bold, italic, res, *index);
|
||||||
@ -181,7 +174,7 @@ char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, un
|
|||||||
family, bold, italic, res, *index);
|
family, bold, italic, res, *index);
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
res = _select_font(priv, "Arial", bold, italic, index, charset);
|
res = _select_font(priv, "Arial", bold, italic, index, code);
|
||||||
if (res)
|
if (res)
|
||||||
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily,
|
mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily,
|
||||||
family, bold, italic, res, *index);
|
family, bold, italic, res, *index);
|
||||||
@ -192,11 +185,6 @@ char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, un
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index)
|
|
||||||
{
|
|
||||||
return fontconfig_select_with_charset(priv, family, bold, italic, index, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (FC_VERSION < 20402)
|
#if (FC_VERSION < 20402)
|
||||||
static char* validate_fname(char* name)
|
static char* validate_fname(char* name)
|
||||||
{
|
{
|
||||||
@ -338,6 +326,14 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
|
|||||||
const char* dir = library->fonts_dir;
|
const char* dir = library->fonts_dir;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (font_fontconfig < 0) {
|
||||||
|
mp_msg(MSGT_ASS, MSGL_WARN,
|
||||||
|
MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed);
|
||||||
|
priv->path_default = strdup(path);
|
||||||
|
priv->index_default = 0;
|
||||||
|
return priv;
|
||||||
|
}
|
||||||
|
|
||||||
rc = FcInit();
|
rc = FcInit();
|
||||||
assert(rc);
|
assert(rc);
|
||||||
|
|
||||||
@ -398,7 +394,8 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con
|
|||||||
|
|
||||||
#else // HAVE_FONTCONFIG
|
#else // HAVE_FONTCONFIG
|
||||||
|
|
||||||
char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index)
|
char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index,
|
||||||
|
uint32_t code)
|
||||||
{
|
{
|
||||||
*index = priv->index_default;
|
*index = priv->index_default;
|
||||||
return priv->path_default;
|
return priv->path_default;
|
||||||
|
@ -18,8 +18,13 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_FONTCONFIG_H__
|
#ifndef LIBASS_FONTCONFIG_H
|
||||||
#define __ASS_FONTCONFIG_H__
|
#define LIBASS_FONTCONFIG_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "ass_types.h"
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
#ifdef HAVE_FONTCONFIG
|
#ifdef HAVE_FONTCONFIG
|
||||||
#include <fontconfig/fontconfig.h>
|
#include <fontconfig/fontconfig.h>
|
||||||
@ -28,12 +33,7 @@
|
|||||||
typedef struct fc_instance_s fc_instance_t;
|
typedef struct fc_instance_s fc_instance_t;
|
||||||
|
|
||||||
fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path);
|
fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path);
|
||||||
char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index);
|
char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, uint32_t code);
|
||||||
void fontconfig_done(fc_instance_t* priv);
|
void fontconfig_done(fc_instance_t* priv);
|
||||||
|
|
||||||
#ifdef HAVE_FONTCONFIG
|
#endif /* LIBASS_FONTCONFIG_H */
|
||||||
char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, FcCharSet* charset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ void ass_library_done(ass_library_t* priv)
|
|||||||
if (priv) {
|
if (priv) {
|
||||||
ass_set_fonts_dir(priv, NULL);
|
ass_set_fonts_dir(priv, NULL);
|
||||||
ass_set_style_overrides(priv, NULL);
|
ass_set_style_overrides(priv, NULL);
|
||||||
|
ass_clear_fonts(priv);
|
||||||
free(priv);
|
free(priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,10 +85,29 @@ static void grow_array(void **array, int nelem, size_t elsize)
|
|||||||
|
|
||||||
void ass_add_font(ass_library_t* priv, char* name, char* data, int size)
|
void ass_add_font(ass_library_t* priv, char* name, char* data, int size)
|
||||||
{
|
{
|
||||||
|
int idx = priv->num_fontdata;
|
||||||
|
if (!name || !data || !size)
|
||||||
|
return;
|
||||||
grow_array((void**)&priv->fontdata, priv->num_fontdata, sizeof(*priv->fontdata));
|
grow_array((void**)&priv->fontdata, priv->num_fontdata, sizeof(*priv->fontdata));
|
||||||
priv->fontdata[priv->num_fontdata].name = name;
|
|
||||||
priv->fontdata[priv->num_fontdata].data = data;
|
priv->fontdata[idx].name = strdup(name);
|
||||||
priv->fontdata[priv->num_fontdata].size = size;
|
|
||||||
|
priv->fontdata[idx].data = malloc(size);
|
||||||
|
memcpy(priv->fontdata[idx].data, data, size);
|
||||||
|
|
||||||
|
priv->fontdata[idx].size = size;
|
||||||
|
|
||||||
priv->num_fontdata ++;
|
priv->num_fontdata ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ass_clear_fonts(ass_library_t* priv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < priv->num_fontdata; ++i) {
|
||||||
|
free(priv->fontdata[i].name);
|
||||||
|
free(priv->fontdata[i].data);
|
||||||
|
}
|
||||||
|
free(priv->fontdata);
|
||||||
|
priv->fontdata = NULL;
|
||||||
|
priv->num_fontdata = 0;
|
||||||
|
}
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_LIBRARY_H__
|
#ifndef LIBASS_LIBRARY_H
|
||||||
#define __ASS_LIBRARY_H__
|
#define LIBASS_LIBRARY_H
|
||||||
|
|
||||||
typedef struct ass_fontdata_s {
|
typedef struct ass_fontdata_s {
|
||||||
char* name;
|
char* name;
|
||||||
@ -36,5 +36,4 @@ struct ass_library_s {
|
|||||||
int num_fontdata;
|
int num_fontdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_LIBRARY_H */
|
||||||
|
|
||||||
|
@ -184,6 +184,8 @@ typedef struct frame_context_s {
|
|||||||
int width, height; // screen dimensions
|
int width, height; // screen dimensions
|
||||||
int orig_height; // frame height ( = screen height - margins )
|
int orig_height; // frame height ( = screen height - margins )
|
||||||
int orig_width; // frame width ( = screen width - margins )
|
int orig_width; // frame width ( = screen width - margins )
|
||||||
|
int orig_height_nocrop; // frame height ( = screen height - margins + cropheight)
|
||||||
|
int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth)
|
||||||
ass_track_t* track;
|
ass_track_t* track;
|
||||||
long long time; // frame's timestamp, ms
|
long long time; // frame's timestamp, ms
|
||||||
double font_scale;
|
double font_scale;
|
||||||
@ -229,6 +231,7 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library)
|
|||||||
int error;
|
int error;
|
||||||
FT_Library ft;
|
FT_Library ft;
|
||||||
ass_renderer_t* priv = 0;
|
ass_renderer_t* priv = 0;
|
||||||
|
int vmajor, vminor, vpatch;
|
||||||
|
|
||||||
memset(&render_context, 0, sizeof(render_context));
|
memset(&render_context, 0, sizeof(render_context));
|
||||||
memset(&frame_context, 0, sizeof(frame_context));
|
memset(&frame_context, 0, sizeof(frame_context));
|
||||||
@ -240,6 +243,12 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library)
|
|||||||
goto ass_init_exit;
|
goto ass_init_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FT_Library_Version(ft, &vmajor, &vminor, &vpatch);
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "FreeType library version: %d.%d.%d\n",
|
||||||
|
vmajor, vminor, vpatch);
|
||||||
|
mp_msg(MSGT_ASS, MSGL_V, "FreeType headers version: %d.%d.%d\n",
|
||||||
|
FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
|
||||||
|
|
||||||
priv = calloc(1, sizeof(ass_renderer_t));
|
priv = calloc(1, sizeof(ass_renderer_t));
|
||||||
if (!priv) {
|
if (!priv) {
|
||||||
FT_Done_FreeType(ft);
|
FT_Done_FreeType(ft);
|
||||||
@ -446,28 +455,33 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
|
|||||||
* \brief Mapping between script and screen coordinates
|
* \brief Mapping between script and screen coordinates
|
||||||
*/
|
*/
|
||||||
static int x2scr(int x) {
|
static int x2scr(int x) {
|
||||||
return x*frame_context.orig_width / frame_context.track->PlayResX + global_settings->left_margin;
|
return x*frame_context.orig_width_nocrop / frame_context.track->PlayResX +
|
||||||
|
FFMAX(global_settings->left_margin, 0);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* \brief Mapping between script and screen coordinates
|
* \brief Mapping between script and screen coordinates
|
||||||
*/
|
*/
|
||||||
static int y2scr(int y) {
|
static int y2scr(int y) {
|
||||||
return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin;
|
return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
|
||||||
|
FFMAX(global_settings->top_margin, 0);
|
||||||
}
|
}
|
||||||
// the same for toptitles
|
// the same for toptitles
|
||||||
static int y2scr_top(int y) {
|
static int y2scr_top(int y) {
|
||||||
if (global_settings->use_margins)
|
if (global_settings->use_margins)
|
||||||
return y * frame_context.orig_height / frame_context.track->PlayResY;
|
return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY;
|
||||||
else
|
else
|
||||||
return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin;
|
return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
|
||||||
|
FFMAX(global_settings->top_margin, 0);
|
||||||
}
|
}
|
||||||
// the same for subtitles
|
// the same for subtitles
|
||||||
static int y2scr_sub(int y) {
|
static int y2scr_sub(int y) {
|
||||||
if (global_settings->use_margins)
|
if (global_settings->use_margins)
|
||||||
return y * frame_context.orig_height / frame_context.track->PlayResY +
|
return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
|
||||||
global_settings->top_margin + global_settings->bottom_margin;
|
FFMAX(global_settings->top_margin, 0) +
|
||||||
|
FFMAX(global_settings->bottom_margin, 0);
|
||||||
else
|
else
|
||||||
return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin;
|
return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
|
||||||
|
FFMAX(global_settings->top_margin, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compute_string_bbox( text_info_t* info, FT_BBox *abbox ) {
|
static void compute_string_bbox( text_info_t* info, FT_BBox *abbox ) {
|
||||||
@ -497,7 +511,7 @@ static void compute_string_bbox( text_info_t* info, FT_BBox *abbox ) {
|
|||||||
/**
|
/**
|
||||||
* \brief Check if starting part of (*p) matches sample. If true, shift p to the first symbol after the matching part.
|
* \brief Check if starting part of (*p) matches sample. If true, shift p to the first symbol after the matching part.
|
||||||
*/
|
*/
|
||||||
static int mystrcmp(char** p, const char* sample) {
|
static inline int mystrcmp(char** p, const char* sample) {
|
||||||
int len = strlen(sample);
|
int len = strlen(sample);
|
||||||
if (strncmp(*p, sample, len) == 0) {
|
if (strncmp(*p, sample, len) == 0) {
|
||||||
(*p) += len;
|
(*p) += len;
|
||||||
@ -1317,7 +1331,6 @@ static void get_bitmap_glyph(glyph_info_t* info)
|
|||||||
/**
|
/**
|
||||||
* This function goes through text_info and calculates text parameters.
|
* This function goes through text_info and calculates text parameters.
|
||||||
* The following text_info fields are filled:
|
* The following text_info fields are filled:
|
||||||
* n_lines
|
|
||||||
* height
|
* height
|
||||||
* lines[].height
|
* lines[].height
|
||||||
* lines[].asc
|
* lines[].asc
|
||||||
@ -1344,6 +1357,7 @@ static void measure_text(void)
|
|||||||
max_desc = cur->desc;
|
max_desc = cur->desc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
text_info.height += (text_info.n_lines - 1) * double_to_d6(global_settings->line_spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1474,7 +1488,7 @@ static void wrap_lines_smart(int max_text_width)
|
|||||||
int height = text_info.lines[cur_line - 1].desc + text_info.lines[cur_line].asc;
|
int height = text_info.lines[cur_line - 1].desc + text_info.lines[cur_line].asc;
|
||||||
cur_line ++;
|
cur_line ++;
|
||||||
pen_shift_x = - cur->pos.x;
|
pen_shift_x = - cur->pos.x;
|
||||||
pen_shift_y += d6_to_int(height) + global_settings->line_spacing;
|
pen_shift_y += d6_to_int(height + double_to_d6(global_settings->line_spacing));
|
||||||
mp_msg(MSGT_ASS, MSGL_DBG2, "shifting from %d to %d by (%d, %d)\n", i, text_info.length - 1, pen_shift_x, pen_shift_y);
|
mp_msg(MSGT_ASS, MSGL_DBG2, "shifting from %d to %d by (%d, %d)\n", i, text_info.length - 1, pen_shift_x, pen_shift_y);
|
||||||
}
|
}
|
||||||
cur->pos.x += pen_shift_x;
|
cur->pos.x += pen_shift_x;
|
||||||
@ -1592,7 +1606,7 @@ static void get_base_point(FT_BBox bbox, int alignment, int* bx, int* by)
|
|||||||
* \param b out: 4-vector
|
* \param b out: 4-vector
|
||||||
* Calculates a * m and stores result in b
|
* Calculates a * m and stores result in b
|
||||||
*/
|
*/
|
||||||
static void transform_point_3d(double *a, double *m, double *b)
|
static inline void transform_point_3d(double *a, double *m, double *b)
|
||||||
{
|
{
|
||||||
b[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12];
|
b[0] = a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + a[3] * m[12];
|
||||||
b[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13];
|
b[1] = a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + a[3] * m[13];
|
||||||
@ -1607,8 +1621,9 @@ static void transform_point_3d(double *a, double *m, double *b)
|
|||||||
* Transforms v by m, projects the result back to the screen plane
|
* Transforms v by m, projects the result back to the screen plane
|
||||||
* Result is returned in v.
|
* Result is returned in v.
|
||||||
*/
|
*/
|
||||||
static void transform_vector_3d(FT_Vector* v, double *m) {
|
static inline void transform_vector_3d(FT_Vector* v, double *m) {
|
||||||
const double camera = 2500 * frame_context.border_scale; // camera distance
|
const double camera = 2500 * frame_context.border_scale; // camera distance
|
||||||
|
const double cutoff_z = 10.;
|
||||||
double a[4], b[4];
|
double a[4], b[4];
|
||||||
a[0] = d6_to_double(v->x);
|
a[0] = d6_to_double(v->x);
|
||||||
a[1] = d6_to_double(v->y);
|
a[1] = d6_to_double(v->y);
|
||||||
@ -1627,8 +1642,8 @@ static void transform_vector_3d(FT_Vector* v, double *m) {
|
|||||||
b[0] *= camera;
|
b[0] *= camera;
|
||||||
b[1] *= camera;
|
b[1] *= camera;
|
||||||
b[3] = 8 * b[2] + camera;
|
b[3] = 8 * b[2] + camera;
|
||||||
if (b[3] < 0.001 && b[3] > -0.001)
|
if (b[3] < cutoff_z)
|
||||||
b[3] = b[3] < 0. ? -0.001 : 0.001;
|
b[3] = cutoff_z;
|
||||||
v->x = double_to_d6(b[0] / b[3]);
|
v->x = double_to_d6(b[0] / b[3]);
|
||||||
v->y = double_to_d6(b[1] / b[3]);
|
v->y = double_to_d6(b[1] / b[3]);
|
||||||
}
|
}
|
||||||
@ -1640,7 +1655,7 @@ static void transform_vector_3d(FT_Vector* v, double *m) {
|
|||||||
* Transforms glyph by m, projects the result back to the screen plane
|
* Transforms glyph by m, projects the result back to the screen plane
|
||||||
* Result is returned in glyph.
|
* Result is returned in glyph.
|
||||||
*/
|
*/
|
||||||
static void transform_glyph_3d(FT_Glyph glyph, double *m, FT_Vector shift) {
|
static inline void transform_glyph_3d(FT_Glyph glyph, double *m, FT_Vector shift) {
|
||||||
int i;
|
int i;
|
||||||
FT_Outline* outline = &((FT_OutlineGlyph)glyph)->outline;
|
FT_Outline* outline = &((FT_OutlineGlyph)glyph)->outline;
|
||||||
FT_Vector* p = outline->points;
|
FT_Vector* p = outline->points;
|
||||||
@ -2063,6 +2078,11 @@ void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ass_set_line_spacing(ass_renderer_t* priv, double line_spacing)
|
||||||
|
{
|
||||||
|
priv->settings.line_spacing = line_spacing;
|
||||||
|
}
|
||||||
|
|
||||||
int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family)
|
int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family)
|
||||||
{
|
{
|
||||||
if (priv->settings.default_font)
|
if (priv->settings.default_font)
|
||||||
@ -2091,11 +2111,20 @@ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long n
|
|||||||
if (!priv->settings.frame_width && !priv->settings.frame_height)
|
if (!priv->settings.frame_width && !priv->settings.frame_height)
|
||||||
return 1; // library not initialized
|
return 1; // library not initialized
|
||||||
|
|
||||||
|
if (track->n_events == 0)
|
||||||
|
return 1; // nothing to do
|
||||||
|
|
||||||
frame_context.ass_priv = priv;
|
frame_context.ass_priv = priv;
|
||||||
frame_context.width = global_settings->frame_width;
|
frame_context.width = global_settings->frame_width;
|
||||||
frame_context.height = global_settings->frame_height;
|
frame_context.height = global_settings->frame_height;
|
||||||
frame_context.orig_width = global_settings->frame_width - global_settings->left_margin - global_settings->right_margin;
|
frame_context.orig_width = global_settings->frame_width - global_settings->left_margin - global_settings->right_margin;
|
||||||
frame_context.orig_height = global_settings->frame_height - global_settings->top_margin - global_settings->bottom_margin;
|
frame_context.orig_height = global_settings->frame_height - global_settings->top_margin - global_settings->bottom_margin;
|
||||||
|
frame_context.orig_width_nocrop = global_settings->frame_width -
|
||||||
|
FFMAX(global_settings->left_margin, 0) -
|
||||||
|
FFMAX(global_settings->right_margin, 0);
|
||||||
|
frame_context.orig_height_nocrop = global_settings->frame_height -
|
||||||
|
FFMAX(global_settings->top_margin, 0) -
|
||||||
|
FFMAX(global_settings->bottom_margin, 0);
|
||||||
frame_context.track = track;
|
frame_context.track = track;
|
||||||
frame_context.time = now;
|
frame_context.time = now;
|
||||||
|
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_TYPES_H__
|
#ifndef LIBASS_TYPES_H
|
||||||
#define __ASS_TYPES_H__
|
#define LIBASS_TYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define VALIGN_SUB 0
|
#define VALIGN_SUB 0
|
||||||
#define VALIGN_CENTER 8
|
#define VALIGN_CENTER 8
|
||||||
@ -110,5 +112,4 @@ typedef struct ass_track_s {
|
|||||||
parser_priv_t* parser_priv;
|
parser_priv_t* parser_priv;
|
||||||
} ass_track_t;
|
} ass_track_t;
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_TYPES_H */
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_GLYPH_H
|
||||||
|
|
||||||
#include "mputils.h"
|
#include "mputils.h"
|
||||||
#include "ass_utils.h"
|
#include "ass_utils.h"
|
||||||
@ -79,3 +81,29 @@ int strtocolor(char** q, uint32_t* res)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void sprint_tag(uint32_t tag, char* dst)
|
||||||
|
{
|
||||||
|
dst[0] = (tag >> 24) & 0xFF;
|
||||||
|
dst[1] = (tag >> 16) & 0xFF;
|
||||||
|
dst[2] = (tag >> 8) & 0xFF;
|
||||||
|
dst[3] = tag & 0xFF;
|
||||||
|
dst[4] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_glyph(FT_Glyph g)
|
||||||
|
{
|
||||||
|
char tag[5];
|
||||||
|
int i;
|
||||||
|
FT_OutlineGlyph og = (FT_OutlineGlyph)g;
|
||||||
|
FT_Outline* o = &(og->outline);
|
||||||
|
sprint_tag(g->format, tag);
|
||||||
|
printf("glyph: %p \n", g);
|
||||||
|
printf("format: %s \n", tag);
|
||||||
|
printf("outline: %p \n", o);
|
||||||
|
printf("contours: %d, points: %d, points ptr: %p \n", o->n_contours, o->n_points, o->points);
|
||||||
|
for (i = 0; i < o->n_points; ++i) {
|
||||||
|
printf(" point %f, %f \n", d6_to_double(o->points[i].x), d6_to_double(o->points[i].y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -18,44 +18,45 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASS_UTILS_H__
|
#ifndef LIBASS_UTILS_H
|
||||||
#define __ASS_UTILS_H__
|
#define LIBASS_UTILS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
int mystrtoi(char** p, int base, int* res);
|
int mystrtoi(char** p, int base, int* res);
|
||||||
int mystrtou32(char** p, int base, uint32_t* res);
|
int mystrtou32(char** p, int base, uint32_t* res);
|
||||||
int mystrtod(char** p, double* res);
|
int mystrtod(char** p, double* res);
|
||||||
int strtocolor(char** q, uint32_t* res);
|
int strtocolor(char** q, uint32_t* res);
|
||||||
|
|
||||||
static int d6_to_int(int x) {
|
static inline int d6_to_int(int x) {
|
||||||
return (x + 32) >> 6;
|
return (x + 32) >> 6;
|
||||||
}
|
}
|
||||||
static int d16_to_int(int x) {
|
static inline int d16_to_int(int x) {
|
||||||
return (x + 32768) >> 16;
|
return (x + 32768) >> 16;
|
||||||
}
|
}
|
||||||
static int int_to_d6(int x) {
|
static inline int int_to_d6(int x) {
|
||||||
return x << 6;
|
return x << 6;
|
||||||
}
|
}
|
||||||
static int int_to_d16(int x) {
|
static inline int int_to_d16(int x) {
|
||||||
return x << 16;
|
return x << 16;
|
||||||
}
|
}
|
||||||
static int d16_to_d6(int x) {
|
static inline int d16_to_d6(int x) {
|
||||||
return (x + 512) >> 10;
|
return (x + 512) >> 10;
|
||||||
}
|
}
|
||||||
static int d6_to_d16(int x) {
|
static inline int d6_to_d16(int x) {
|
||||||
return x << 10;
|
return x << 10;
|
||||||
}
|
}
|
||||||
static double d6_to_double(int x) {
|
static inline double d6_to_double(int x) {
|
||||||
return x / 64.;
|
return x / 64.;
|
||||||
}
|
}
|
||||||
static int double_to_d6(double x) {
|
static inline int double_to_d6(double x) {
|
||||||
return (int)(x * 64);
|
return (int)(x * 64);
|
||||||
}
|
}
|
||||||
static double d16_to_double(int x) {
|
static inline double d16_to_double(int x) {
|
||||||
return ((double)x) / 0x10000;
|
return ((double)x) / 0x10000;
|
||||||
}
|
}
|
||||||
static int double_to_d16(double x) {
|
static inline int double_to_d16(double x) {
|
||||||
return (int)(x * 0x10000);
|
return (int)(x * 0x10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* LIBASS_UTILS_H */
|
||||||
|
|
||||||
|
@ -51,5 +51,6 @@
|
|||||||
#define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n"
|
#define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n"
|
||||||
#define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n"
|
#define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n"
|
||||||
#define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n"
|
#define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n"
|
||||||
|
#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user