From b060751cfeb0a87feeb6619624a42e6b49ed2e43 Mon Sep 17 00:00:00 2001 From: Amar Takhar Date: Fri, 21 Mar 2008 05:32:23 +0000 Subject: [PATCH] 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. --- libass/ass.c | 67 ++++++++++------ libass/ass.h | 20 +++-- libass/ass_bitmap.c | 16 ++++ libass/ass_bitmap.h | 10 ++- libass/ass_cache.c | 4 +- libass/ass_cache.h | 11 ++- libass/ass_font.c | 174 ++++++++++++++++++++-------------------- libass/ass_font.h | 18 ++--- libass/ass_fontconfig.c | 69 ++++++++-------- libass/ass_fontconfig.h | 18 ++--- libass/ass_library.c | 26 +++++- libass/ass_library.h | 7 +- libass/ass_render.c | 59 ++++++++++---- libass/ass_types.h | 9 ++- libass/ass_utils.c | 28 +++++++ libass/ass_utils.h | 29 +++---- libass/help_mp.h | 1 + 17 files changed, 345 insertions(+), 221 deletions(-) diff --git a/libass/ass.c b/libass/ass.c index 30a305398..6271736e8 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -27,7 +27,7 @@ #include #include #include -//#include +#include #include #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* 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) { NEXT(q, tname); } @@ -323,13 +331,22 @@ void process_force_style(ass_track_t* track) { if (!list) return; for (fs = list; *fs; ++fs) { - eq = strchr(*fs, '='); + eq = strrchr(*fs, '='); if (!eq) continue; *eq = '\0'; 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) { *dt = '\0'; 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) { char* str = malloc(size + 1); - int sid; memcpy(str, data, size); str[size] = '\0'; @@ -705,12 +721,6 @@ void ass_process_codec_private(ass_track_t* track, char *data, int size) process_text(track, 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) { // probably an mkv produced by ancient mkvtoolnix // 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 data string to parse * \param size length of data @@ -803,7 +813,7 @@ static char* sub_recode(char* data, size_t size, char* codepage) assert(codepage); { - char* cp_tmp = codepage ? strdup(codepage) : 0; + const char* cp_tmp = codepage; #ifdef HAVE_ENCA char enca_lang[3], enca_fallback[100]; 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"); } else 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; } -/** - * \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* read_file_recode(char* fname, char* codepage, int* size) { char* buf; - ass_track_t* track; size_t 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) return 0; #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); free(buf); if (!track) diff --git a/libass/ass.h b/libass/ass.h index 2e1aa1ab9..851be6681 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -18,9 +18,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_H__ -#define __ASS_H__ +#ifndef LIBASS_ASS_H +#define LIBASS_ASS_H +#include #include "ass_types.h" /// 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_font_scale(ass_renderer_t* priv, double font_scale); void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht); +void ass_set_line_spacing(ass_renderer_t* priv, double line_spacing); /** * \brief set font lookup defaults @@ -145,7 +147,7 @@ void ass_free_style(ass_track_t* track, int sid); 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 data string to parse * \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); /** - * \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 data string to parse * \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); +char* read_file_recode(char* fname, char* codepage, int* size); + /** * \brief Read subtitles from file. * \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); +/** + * \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 * \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); -#endif - +#endif /* LIBASS_ASS_H */ diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 8aa1fe7a6..f84b453b3 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -150,6 +150,20 @@ static bitmap_t* copy_bitmap(const bitmap_t* src) 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) { FT_BitmapGlyph bg; @@ -161,6 +175,8 @@ static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord) int i; int error; + if (check_glyph_area(glyph)) + return 0; error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0); if (error) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, error); diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index ba5867f7c..634d7e41b 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -18,8 +18,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_BITMAP_H__ -#define __ASS_BITMAP_H__ +#ifndef LIBASS_BITMAP_H +#define LIBASS_BITMAP_H + +#include +#include FT_GLYPH_H 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); -#endif - +#endif /* LIBASS_BITMAP_H */ diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 797c33887..a61f9f90c 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -57,7 +57,7 @@ struct hashmap_s { #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 *be = bp + len; @@ -67,7 +67,7 @@ static unsigned fnv_32a_buf(void* buf, size_t len, unsigned 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; while (*s) { diff --git a/libass/ass_cache.h b/libass/ass_cache.h index caa750a54..289753ef6 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -18,8 +18,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_CACHE_H__ -#define __ASS_CACHE_H__ +#ifndef LIBASS_CACHE_H +#define LIBASS_CACHE_H + +#include "ass.h" +#include "ass_font.h" +#include "ass_bitmap.h" void ass_font_cache_init(void); ass_font_t* ass_font_cache_find(ass_font_desc_t* desc); @@ -94,5 +98,4 @@ void hashmap_done(hashmap_t* map); void* hashmap_insert(hashmap_t* map, void* key, void* value); void* hashmap_find(hashmap_t* map, void* key); -#endif - +#endif /* LIBASS_CACHE_H */ diff --git a/libass/ass_font.c b/libass/ass_font.c index 493a28317..4339621cd 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -87,46 +87,85 @@ static int find_font(ass_library_t* library, char* name) 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; int index; 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; ass_font_t* fontp; ass_font_t font; - int mem_idx; fontp = ass_font_cache_find(desc); if (fontp) return fontp; - path = fontconfig_select(fc_priv, desc->family, desc->bold, desc->italic, &index); - - 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.library = library; font.ftlibrary = ftlibrary; - font.faces[0] = face; - font.n_faces = 1; + font.n_faces = 0; font.desc.family = strdup(desc->family); font.desc.bold = desc->bold; 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.size = 0.; -#ifdef HAVE_FONTCONFIG - font.charset = FcCharSetCreate(); -#endif - - return ass_font_cache_add(&font); + error = add_face(fc_priv, &font, 0); + if (error == -1) { + free(font.desc.family); + return 0; + } 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; // VSFilter uses metrics from TrueType OS/2 table // The idea was borrowed from asa (http://asa.diac24.net) - if (hori && os2) - mscale = ((double)(hori->Ascender - hori->Descender)) / (os2->usWinAscent + os2->usWinDescent); + if (hori && os2) { + 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)); rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; 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. * \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) { FT_Face face = font->faces[i]; if (FT_Get_Char_Index(face, ch)) { - int v, v2; - v = face->size->metrics.ascender; - 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; + *asc = face->size->metrics.ascender; + *desc = - face->size->metrics.descender; return; } } @@ -282,16 +283,18 @@ FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch } #ifdef HAVE_FONTCONFIG - FcCharSetAddChar(font->charset, ch); if (index == 0) { + int face_idx; mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont, ch, font->desc.family, font->desc.bold, font->desc.italic); - ass_font_reselect(fontconfig_priv, font, ch); - face = font->faces[font->n_faces - 1]; - index = FT_Get_Char_Index(face, ch); - if (index == 0) { - mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound, - ch, font->desc.family, font->desc.bold, font->desc.italic); + face_idx = add_face(fontconfig_priv, font, ch); + if (face_idx >= 0) { + face = font->faces[face_idx]; + index = FT_Get_Char_Index(face, ch); + if (index == 0) { + mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound, + ch, font->desc.family, font->desc.bold, font->desc.italic); + } } } #endif @@ -359,8 +362,5 @@ void ass_font_free(ass_font_t* font) for (i = 0; i < font->n_faces; ++i) if (font->faces[i]) FT_Done_Face(font->faces[i]); if (font->desc.family) free(font->desc.family); -#ifdef HAVE_FONTCONFIG - if (font->charset) FcCharSetDestroy(font->charset); -#endif free(font); } diff --git a/libass/ass_font.h b/libass/ass_font.h index 85c0218bd..cafdc6577 100644 --- a/libass/ass_font.h +++ b/libass/ass_font.h @@ -18,12 +18,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_FONT_H__ -#define __ASS_FONT_H__ +#ifndef LIBASS_FONT_H +#define LIBASS_FONT_H -#ifdef HAVE_FONTCONFIG -#include -#endif +#include +#include +#include FT_GLYPH_H +#include "ass.h" +#include "ass_types.h" typedef struct ass_font_desc_s { char* family; @@ -35,15 +37,13 @@ typedef struct ass_font_desc_s { typedef struct ass_font_s { ass_font_desc_t desc; + ass_library_t* library; FT_Library ftlibrary; FT_Face faces[ASS_FONT_MAX_FACES]; int n_faces; double scale_x, scale_y; // current transform FT_Vector v; // current shift double size; -#ifdef HAVE_FONTCONFIG - FcCharSet* charset; -#endif } ass_font_t; 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); void ass_font_free(ass_font_t* font); -#endif +#endif /* LIBASS_FONT_H */ diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index e1579de4c..addcc8264 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -40,6 +40,8 @@ #include #endif +extern int font_fontconfig; + struct fc_instance_s { #ifdef HAVE_FONTCONFIG FcConfig* config; @@ -57,11 +59,11 @@ struct fc_instance_s { * \param bold font weight value * \param italic font slant value * \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 */ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, - FcCharSet* charset) + uint32_t code) { FcBool rc; FcResult result; @@ -71,7 +73,7 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold FcBool val_b; FcCharSet* val_cs; FcFontSet* fset = 0; - int curf, bestf, bestdiff = 0; + int curf; char* retval = 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); - bestf = -1; - if (charset) - bestdiff = FcCharSetCount(charset) + 1; for (curf = 0; curf < fset->nfont; ++curf) { rpat = fset->fonts[curf]; @@ -104,29 +103,19 @@ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold continue; if (val_b != FcTrue) continue; - - if (charset) { - int diff; - result = FcPatternGetCharSet(rpat, FC_CHARSET, 0, &val_cs); - if (result != FcResultMatch) - continue; - diff = FcCharSetSubtractCount(charset, val_cs); - if (diff < bestdiff) { - bestdiff = diff; - bestf = curf; - } - if (diff == 0) - break; - } else { - bestf = curf; + if (!code) + break; + result = FcPatternGetCharSet(rpat, FC_CHARSET, 0, &val_cs); + if (result != FcResultMatch) + continue; + if (FcCharSetHasChar(val_cs, code)) break; - } } - if (bestf < 0) + if (curf >= fset->nfont) goto error; - rpat = fset->fonts[bestf]; + rpat = fset->fonts[curf]; result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i); 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 italic font slant value * \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 */ -char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, - FcCharSet* charset) +char* fontconfig_select(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, + uint32_t code) { char* res = 0; + if (font_fontconfig < 0) { + *index = priv->index_default; + return priv->path_default; + } 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) { - res = _select_font(priv, priv->family_default, bold, italic, index, charset); + res = _select_font(priv, priv->family_default, bold, italic, index, code); if (res) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily, 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); } if (!res) { - res = _select_font(priv, "Arial", bold, italic, index, charset); + res = _select_font(priv, "Arial", bold, italic, index, code); if (res) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily, family, bold, italic, res, *index); @@ -192,11 +185,6 @@ char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, un 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) 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; 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(); assert(rc); @@ -398,7 +394,8 @@ fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, con #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; return priv->path_default; diff --git a/libass/ass_fontconfig.h b/libass/ass_fontconfig.h index a296bcef3..3806f2468 100644 --- a/libass/ass_fontconfig.h +++ b/libass/ass_fontconfig.h @@ -18,8 +18,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_FONTCONFIG_H__ -#define __ASS_FONTCONFIG_H__ +#ifndef LIBASS_FONTCONFIG_H +#define LIBASS_FONTCONFIG_H + +#include +#include "ass_types.h" +#include +#include FT_FREETYPE_H #ifdef HAVE_FONTCONFIG #include @@ -28,12 +33,7 @@ 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); -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); -#ifdef HAVE_FONTCONFIG -char* fontconfig_select_with_charset(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, FcCharSet* charset); -#endif - -#endif - +#endif /* LIBASS_FONTCONFIG_H */ diff --git a/libass/ass_library.c b/libass/ass_library.c index 107a6eda3..cda928704 100644 --- a/libass/ass_library.c +++ b/libass/ass_library.c @@ -37,6 +37,7 @@ void ass_library_done(ass_library_t* priv) if (priv) { ass_set_fonts_dir(priv, NULL); ass_set_style_overrides(priv, NULL); + ass_clear_fonts(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) { + int idx = priv->num_fontdata; + if (!name || !data || !size) + return; 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[priv->num_fontdata].size = size; + + priv->fontdata[idx].name = strdup(name); + + priv->fontdata[idx].data = malloc(size); + memcpy(priv->fontdata[idx].data, data, size); + + priv->fontdata[idx].size = size; + 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; +} diff --git a/libass/ass_library.h b/libass/ass_library.h index 34a8b7a03..adab0fdc4 100644 --- a/libass/ass_library.h +++ b/libass/ass_library.h @@ -18,8 +18,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_LIBRARY_H__ -#define __ASS_LIBRARY_H__ +#ifndef LIBASS_LIBRARY_H +#define LIBASS_LIBRARY_H typedef struct ass_fontdata_s { char* name; @@ -36,5 +36,4 @@ struct ass_library_s { int num_fontdata; }; -#endif - +#endif /* LIBASS_LIBRARY_H */ diff --git a/libass/ass_render.c b/libass/ass_render.c index a592dccf4..05657294a 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -184,6 +184,8 @@ typedef struct frame_context_s { int width, height; // screen dimensions int orig_height; // frame height ( = screen height - 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; long long time; // frame's timestamp, ms double font_scale; @@ -229,6 +231,7 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library) int error; FT_Library ft; ass_renderer_t* priv = 0; + int vmajor, vminor, vpatch; memset(&render_context, 0, sizeof(render_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; } + 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)); if (!priv) { 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 */ 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 */ 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 static int y2scr_top(int y) { 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 - 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 static int y2scr_sub(int y) { if (global_settings->use_margins) - return y * frame_context.orig_height / frame_context.track->PlayResY + - global_settings->top_margin + global_settings->bottom_margin; + return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY + + FFMAX(global_settings->top_margin, 0) + + FFMAX(global_settings->bottom_margin, 0); 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 ) { @@ -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. */ -static int mystrcmp(char** p, const char* sample) { +static inline int mystrcmp(char** p, const char* sample) { int len = strlen(sample); if (strncmp(*p, sample, len) == 0) { (*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. * The following text_info fields are filled: - * n_lines * height * lines[].height * lines[].asc @@ -1344,6 +1357,7 @@ static void measure_text(void) 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; cur_line ++; 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); } 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 * 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[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 * 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 cutoff_z = 10.; double a[4], b[4]; a[0] = d6_to_double(v->x); 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[1] *= camera; b[3] = 8 * b[2] + camera; - if (b[3] < 0.001 && b[3] > -0.001) - b[3] = b[3] < 0. ? -0.001 : 0.001; + if (b[3] < cutoff_z) + b[3] = cutoff_z; v->x = double_to_d6(b[0] / 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 * 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; FT_Outline* outline = &((FT_OutlineGlyph)glyph)->outline; 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) { if (priv->settings.default_font) @@ -2090,12 +2110,21 @@ 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) return 1; // library not initialized + + if (track->n_events == 0) + return 1; // nothing to do frame_context.ass_priv = priv; frame_context.width = global_settings->frame_width; 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_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.time = now; diff --git a/libass/ass_types.h b/libass/ass_types.h index 0795d5637..23e107412 100644 --- a/libass/ass_types.h +++ b/libass/ass_types.h @@ -18,8 +18,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_TYPES_H__ -#define __ASS_TYPES_H__ +#ifndef LIBASS_TYPES_H +#define LIBASS_TYPES_H + +#include #define VALIGN_SUB 0 #define VALIGN_CENTER 8 @@ -110,5 +112,4 @@ typedef struct ass_track_s { parser_priv_t* parser_priv; } ass_track_t; -#endif - +#endif /* LIBASS_TYPES_H */ diff --git a/libass/ass_utils.c b/libass/ass_utils.c index 3be71b8f3..f22fa8e68 100644 --- a/libass/ass_utils.c +++ b/libass/ass_utils.c @@ -22,6 +22,8 @@ #include #include +#include +#include FT_GLYPH_H #include "mputils.h" #include "ass_utils.h" @@ -79,3 +81,29 @@ int strtocolor(char** q, uint32_t* res) 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 diff --git a/libass/ass_utils.h b/libass/ass_utils.h index 252e5a8ee..7d6ffb681 100644 --- a/libass/ass_utils.h +++ b/libass/ass_utils.h @@ -18,44 +18,45 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __ASS_UTILS_H__ -#define __ASS_UTILS_H__ +#ifndef LIBASS_UTILS_H +#define LIBASS_UTILS_H + +#include int mystrtoi(char** p, int base, int* res); int mystrtou32(char** p, int base, uint32_t* res); int mystrtod(char** p, double* 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; } -static int d16_to_int(int x) { +static inline int d16_to_int(int x) { return (x + 32768) >> 16; } -static int int_to_d6(int x) { +static inline int int_to_d6(int x) { return x << 6; } -static int int_to_d16(int x) { +static inline int int_to_d16(int x) { return x << 16; } -static int d16_to_d6(int x) { +static inline int d16_to_d6(int x) { return (x + 512) >> 10; } -static int d6_to_d16(int x) { +static inline int d6_to_d16(int x) { return x << 10; } -static double d6_to_double(int x) { +static inline double d6_to_double(int x) { return x / 64.; } -static int double_to_d6(double x) { +static inline int double_to_d6(double x) { return (int)(x * 64); } -static double d16_to_double(int x) { +static inline double d16_to_double(int x) { return ((double)x) / 0x10000; } -static int double_to_d16(double x) { +static inline int double_to_d16(double x) { return (int)(x * 0x10000); } -#endif - +#endif /* LIBASS_UTILS_H */ diff --git a/libass/help_mp.h b/libass/help_mp.h index 33c79e802..a13eaed1b 100644 --- a/libass/help_mp.h +++ b/libass/help_mp.h @@ -51,5 +51,6 @@ #define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n" #define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n" #define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n" +#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n" #endif