1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
4 Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include FT_FREETYPE_H
26 #include FT_SYNTHESIS_H
30 #include "ass_library.h"
32 #include "ass_bitmap.h"
33 #include "ass_cache.h"
34 #include "ass_fontconfig.h"
38 * Select Microfost Unicode CharMap, if the font has one.
39 * Otherwise, let FreeType decide.
41 static void charmap_magic(FT_Face face
)
44 for (i
= 0; i
< face
->num_charmaps
; ++i
) {
45 FT_CharMap cmap
= face
->charmaps
[i
];
46 unsigned pid
= cmap
->platform_id
;
47 unsigned eid
= cmap
->encoding_id
;
48 if (pid
== 3 /*microsoft*/ && (eid
== 1 /*unicode bmp*/ || eid
== 10 /*full unicode*/)) {
49 FT_Set_Charmap(face
, cmap
);
55 if (face
->num_charmaps
== 0) {
56 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_NoCharmaps
);
59 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_NoCharmapAutodetected
);
60 FT_Set_Charmap(face
, face
->charmaps
[0]);
66 * \brief find a memory font by name
68 static int find_font(ass_library_t
* library
, char* name
)
71 for (i
= 0; i
< library
->num_fontdata
; ++i
)
72 if (strcasecmp(name
, library
->fontdata
[i
].name
) == 0)
78 * \brief Create a new ass_font_t according to "desc" argument
80 ass_font_t
* ass_font_new(ass_library_t
* library
, FT_Library ftlibrary
, void* fc_priv
, ass_font_desc_t
* desc
)
89 font
= ass_font_cache_find(desc
);
93 path
= fontconfig_select(fc_priv
, desc
->family
, desc
->bold
, desc
->italic
, &index
);
95 mem_idx
= find_font(library
, path
);
97 error
= FT_New_Memory_Face(ftlibrary
, (unsigned char*)library
->fontdata
[mem_idx
].data
,
98 library
->fontdata
[mem_idx
].size
, 0, &face
);
100 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_ErrorOpeningMemoryFont
, path
);
104 error
= FT_New_Face(ftlibrary
, path
, index
, &face
);
106 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_ErrorOpeningFont
, path
, index
);
113 font
= calloc(1, sizeof(ass_font_t
));
114 font
->ftlibrary
= ftlibrary
;
115 font
->faces
[0] = face
;
117 font
->desc
.family
= strdup(desc
->family
);
118 font
->desc
.bold
= desc
->bold
;
119 font
->desc
.italic
= desc
->italic
;
121 font
->m
.xx
= font
->m
.yy
= (FT_Fixed
)0x10000L
;
122 font
->m
.xy
= font
->m
.yy
= 0;
123 font
->v
.x
= font
->v
.y
= 0;
126 #ifdef HAVE_FONTCONFIG
127 font
->charset
= FcCharSetCreate();
130 ass_font_cache_add(font
);
136 * \brief Set font transformation matrix and shift vector
138 void ass_font_set_transform(ass_font_t
* font
, FT_Matrix
* m
, FT_Vector
* v
)
147 for (i
= 0; i
< font
->n_faces
; ++i
)
148 FT_Set_Transform(font
->faces
[i
], &font
->m
, &font
->v
);
152 * \brief Set font size
154 void ass_font_set_size(ass_font_t
* font
, int size
)
157 if (font
->size
!= size
) {
159 for (i
= 0; i
< font
->n_faces
; ++i
)
160 FT_Set_Pixel_Sizes(font
->faces
[i
], 0, size
);
164 #ifdef HAVE_FONTCONFIG
166 * \brief Select a new FT_Face with the given character
167 * The new face is added to the end of font->faces.
169 static void ass_font_reselect(void* fontconfig_priv
, ass_font_t
* font
, uint32_t ch
)
176 if (font
->n_faces
== ASS_FONT_MAX_FACES
)
179 path
= fontconfig_select_with_charset(fontconfig_priv
, font
->desc
.family
, font
->desc
.bold
,
180 font
->desc
.italic
, &index
, font
->charset
);
182 error
= FT_New_Face(font
->ftlibrary
, path
, index
, &face
);
184 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_ErrorOpeningFont
, path
, index
);
189 error
= FT_Get_Char_Index(face
, ch
);
190 if (error
== 0) { // the new font face is not better then the old one
195 font
->faces
[font
->n_faces
++] = face
;
197 FT_Set_Transform(face
, &font
->m
, &font
->v
);
198 FT_Set_Pixel_Sizes(face
, 0, font
->size
);
203 * \brief Get maximal font ascender and descender.
204 * \param ch character code
205 * The values are extracted from the font face that provides glyphs for the given character
207 void ass_font_get_asc_desc(ass_font_t
* font
, uint32_t ch
, int* asc
, int* desc
)
210 for (i
= 0; i
< font
->n_faces
; ++i
) {
211 FT_Face face
= font
->faces
[i
];
212 if (FT_Get_Char_Index(face
, ch
)) {
214 v
= face
->size
->metrics
.ascender
;
215 v2
= FT_MulFix(face
->bbox
.yMax
, face
->size
->metrics
.y_scale
);
216 *asc
= (v
> v2
* 0.9) ? v
: v2
;
218 v
= - face
->size
->metrics
.descender
;
219 v2
= - FT_MulFix(face
->bbox
.yMin
, face
->size
->metrics
.y_scale
);
220 *desc
= (v
> v2
* 0.9) ? v
: v2
;
230 * \param ch character code
232 FT_Glyph
ass_font_get_glyph(void* fontconfig_priv
, ass_font_t
* font
, uint32_t ch
)
242 if (font
->n_faces
== 0)
245 for (i
= 0; i
< font
->n_faces
; ++i
) {
246 face
= font
->faces
[i
];
247 index
= FT_Get_Char_Index(face
, ch
);
252 #ifdef HAVE_FONTCONFIG
253 FcCharSetAddChar(font
->charset
, ch
);
255 mp_msg(MSGT_ASS
, MSGL_INFO
, MSGTR_LIBASS_GlyphNotFoundReselectingFont
,
256 ch
, font
->desc
.family
, font
->desc
.bold
, font
->desc
.italic
);
257 ass_font_reselect(fontconfig_priv
, font
, ch
);
258 face
= font
->faces
[font
->n_faces
- 1];
259 index
= FT_Get_Char_Index(face
, ch
);
261 mp_msg(MSGT_ASS
, MSGL_ERR
, MSGTR_LIBASS_GlyphNotFound
,
262 ch
, font
->desc
.family
, font
->desc
.bold
, font
->desc
.italic
);
267 error
= FT_Load_Glyph(face
, index
, FT_LOAD_NO_BITMAP
);
269 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_ErrorLoadingGlyph
);
273 #if (FREETYPE_MAJOR > 2) || \
274 ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \
275 ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10))
276 // FreeType >= 2.1.10 required
277 if (!(face
->style_flags
& FT_STYLE_FLAG_ITALIC
) &&
278 (font
->desc
.italic
> 55)) {
279 FT_GlyphSlot_Oblique(face
->glyph
);
282 error
= FT_Get_Glyph(face
->glyph
, &glyph
);
284 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_ErrorLoadingGlyph
);
292 * \brief Get kerning for the pair of glyphs.
294 FT_Vector
ass_font_get_kerning(ass_font_t
* font
, uint32_t c1
, uint32_t c2
)
296 FT_Vector v
= {0, 0};
299 for (i
= 0; i
< font
->n_faces
; ++i
) {
300 FT_Face face
= font
->faces
[i
];
301 int i1
= FT_Get_Char_Index(face
, c1
);
302 int i2
= FT_Get_Char_Index(face
, c2
);
304 if (FT_HAS_KERNING(face
))
305 FT_Get_Kerning(face
, i1
, i2
, FT_KERNING_DEFAULT
, &v
);
308 if (i1
|| i2
) // these glyphs are from different font faces, no kerning information
315 * \brief Deallocate ass_font_t
317 void ass_font_free(ass_font_t
* font
)
320 for (i
= 0; i
< font
->n_faces
; ++i
)
321 if (font
->faces
[i
]) FT_Done_Face(font
->faces
[i
]);
322 if (font
->desc
.family
) free(font
->desc
.family
);
323 #ifdef HAVE_FONTCONFIG
324 if (font
->charset
) FcCharSetDestroy(font
->charset
);