1 /*****************************************************************************
2 * freetype.c : Put text on the video, using freetype2
3 *****************************************************************************
4 * Copyright (C) 2002 - 2012 VLC authors and VideoLAN
7 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8 * Gildas Bazin <gbazin@videolan.org>
9 * Bernie Purcell <bitmap@videolan.org>
10 * Jean-Baptiste Kempf <jb@videolan.org>
11 * Felix Paul Kühne <fkuehne@videolan.org>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation, Inc.,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_filter.h> /* filter_sys_t */
38 #include <vlc_text_style.h> /* text_style_t*/
42 #include <TargetConditionals.h>
44 #include <Carbon/Carbon.h>
46 #include <sys/param.h> /* for MAXPATHLEN */
47 #undef HAVE_FONTCONFIG
54 # include <vlc_charset.h> /* FromT */
58 #ifdef HAVE_FONTCONFIG
59 # include <fontconfig/fontconfig.h>
62 #include "platform_fonts.h"
64 #ifdef HAVE_FONTCONFIG
65 void FontConfig_BuildCache( filter_t
*p_filter
)
68 msg_Dbg( p_filter
, "Building font databases.");
76 #if defined( _WIN32 ) || defined( __APPLE__ )
77 dialog_progress_bar_t
*p_dialog
= NULL
;
78 FcConfig
*fcConfig
= FcInitLoadConfig();
80 p_dialog
= dialog_ProgressCreate( p_filter
,
81 _("Building font cache"),
82 _("Please wait while your font cache is rebuilt.\n"
83 "This should take less than a few minutes."), NULL
);
86 dialog_ProgressSet( p_dialog, NULL, 0.5 ); */
88 FcConfigBuildFonts( fcConfig
);
89 #if defined( __APPLE__ )
90 // By default, scan only the directory /System/Library/Fonts.
91 // So build the set of available fonts under another directories,
92 // and add the set to the current configuration.
93 FcConfigAppFontAddDir( NULL
, "~/Library/Fonts" );
94 FcConfigAppFontAddDir( NULL
, "/Library/Fonts" );
95 FcConfigAppFontAddDir( NULL
, "/Network/Library/Fonts" );
96 //FcConfigAppFontAddDir( NULL, "/System/Library/Fonts" );
100 // dialog_ProgressSet( p_dialog, NULL, 1.0 );
101 dialog_ProgressDestroy( p_dialog
);
106 msg_Dbg( p_filter
, "Took %ld microseconds", (long)((t2
- t1
)) );
110 * \brief Selects a font matching family, bold, italic provided
112 char* FontConfig_Select( filter_t
*p_filter
, const char* family
,
113 bool b_bold
, bool b_italic
, int i_size
, int *i_idx
)
115 FcResult result
= FcResultMatch
;
116 FcPattern
*pat
, *p_pat
;
120 FcConfig
* config
= NULL
;
121 VLC_UNUSED(p_filter
);
123 /* Create a pattern and fills it */
124 pat
= FcPatternCreate();
125 if (!pat
) return NULL
;
128 FcPatternAddString( pat
, FC_FAMILY
, (const FcChar8
*)family
);
129 FcPatternAddBool( pat
, FC_OUTLINE
, FcTrue
);
130 FcPatternAddInteger( pat
, FC_SLANT
, b_italic
? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
);
131 FcPatternAddInteger( pat
, FC_WEIGHT
, b_bold
? FC_WEIGHT_EXTRABOLD
: FC_WEIGHT_NORMAL
);
134 FcPatternAddDouble( pat
, FC_SIZE
, (double)i_size
);
138 FcDefaultSubstitute( pat
);
139 if( !FcConfigSubstitute( config
, pat
, FcMatchPattern
) )
141 FcPatternDestroy( pat
);
145 /* Find the best font for the pattern, destroy the pattern */
146 p_pat
= FcFontMatch( config
, pat
, &result
);
147 FcPatternDestroy( pat
);
148 if( !p_pat
|| result
== FcResultNoMatch
) return NULL
;
150 /* Check the new pattern */
151 if( ( FcResultMatch
!= FcPatternGetBool( p_pat
, FC_OUTLINE
, 0, &val_b
) )
152 || ( val_b
!= FcTrue
) )
154 FcPatternDestroy( p_pat
);
157 if( FcResultMatch
!= FcPatternGetInteger( p_pat
, FC_INDEX
, 0, i_idx
) )
162 if( FcResultMatch
!= FcPatternGetString( p_pat
, FC_FAMILY
, 0, &val_s
) )
164 FcPatternDestroy( p_pat
);
168 /* if( strcasecmp((const char*)val_s, family ) != 0 )
169 msg_Warn( p_filter, "fontconfig: selected font family is not"
170 "the requested one: '%s' != '%s'\n",
171 (const char*)val_s, family ); */
173 if( FcResultMatch
== FcPatternGetString( p_pat
, FC_FILE
, 0, &val_s
) )
174 ret
= strdup( (const char*)val_s
);
176 FcPatternDestroy( p_pat
);
181 #if defined( _WIN32 ) && !VLC_WINSTORE_APP
182 #define FONT_DIR_NT _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts")
184 static int GetFileFontByName( LPCTSTR font_name
, char **psz_filename
)
187 TCHAR vbuffer
[MAX_PATH
];
190 if( RegOpenKeyEx(HKEY_LOCAL_MACHINE
, FONT_DIR_NT
, 0, KEY_READ
, &hKey
)
194 char *font_name_temp
= FromT( font_name
);
195 size_t fontname_len
= strlen( font_name_temp
);
197 for( int index
= 0;; index
++ )
199 DWORD vbuflen
= MAX_PATH
- 1;
202 LONG i_result
= RegEnumValue( hKey
, index
, vbuffer
, &vbuflen
,
203 NULL
, NULL
, (LPBYTE
)dbuffer
, &dbuflen
);
204 if( i_result
!= ERROR_SUCCESS
)
210 char *psz_value
= FromT( vbuffer
);
212 char *s
= strchr( psz_value
,'(' );
213 if( s
!= NULL
&& s
!= psz_value
) s
[-1] = '\0';
215 /* Manage concatenated font names */
216 if( strchr( psz_value
, '&') ) {
217 if( strcasestr( psz_value
, font_name_temp
) != NULL
)
224 if( strncasecmp( psz_value
, font_name_temp
, fontname_len
) == 0 )
234 *psz_filename
= FromT( dbuffer
);
235 free( font_name_temp
);
240 static int CALLBACK
EnumFontCallback(const ENUMLOGFONTEX
*lpelfe
, const NEWTEXTMETRICEX
*metric
,
241 DWORD type
, LPARAM lParam
)
243 VLC_UNUSED( metric
);
244 if( (type
& RASTER_FONTTYPE
) ) return 1;
245 // if( lpelfe->elfScript ) FIXME
247 return GetFileFontByName( (LPCTSTR
)lpelfe
->elfFullName
, (char **)lParam
);
250 static char* GetWindowsFontPath()
252 wchar_t wdir
[MAX_PATH
];
253 if( S_OK
!= SHGetFolderPathW( NULL
, CSIDL_FONTS
, NULL
, SHGFP_TYPE_CURRENT
, wdir
) )
255 GetWindowsDirectoryW( wdir
, MAX_PATH
);
256 wcscat( wdir
, L
"\\fonts" );
258 return FromWide( wdir
);
261 char* Win32_Select( filter_t
*p_filter
, const char* family
,
262 bool b_bold
, bool b_italic
, int i_size
, int *i_idx
)
264 VLC_UNUSED( i_size
);
266 VLC_UNUSED( p_filter
);
268 if( !family
|| strlen( family
) < 1 )
273 lf
.lfCharSet
= DEFAULT_CHARSET
;
277 lf
.lfWeight
= FW_BOLD
;
279 LPTSTR psz_fbuffer
= ToT( family
);
280 _tcsncpy( (LPTSTR
)&lf
.lfFaceName
, psz_fbuffer
, LF_FACESIZE
);
284 char *psz_filename
= NULL
;
285 HDC hDC
= GetDC( NULL
);
286 EnumFontFamiliesEx(hDC
, &lf
, (FONTENUMPROC
)&EnumFontCallback
, (LPARAM
)&psz_filename
, 0);
287 ReleaseDC(NULL
, hDC
);
290 if( psz_filename
!= NULL
)
292 /* FIXME: increase i_idx, when concatenated strings */
295 /* Prepend the Windows Font path, when only a filename was provided */
296 if( strchr( psz_filename
, DIR_SEP_CHAR
) )
300 /* Get Windows Font folder */
301 char *psz_win_fonts_path
= GetWindowsFontPath();
303 if( asprintf( &psz_tmp
, "%s\\%s", psz_win_fonts_path
, psz_filename
) == -1 )
305 free( psz_filename
);
306 free( psz_win_fonts_path
);
309 free( psz_filename
);
310 free( psz_win_fonts_path
);
315 else /* Let's take any font we can */
318 char *psz_win_fonts_path
= GetWindowsFontPath();
320 if( asprintf( &psz_tmp
, "%s\\%s", psz_win_fonts_path
, SYSTEM_DEFAULT_FONT_FILE
) == -1 )
329 #if !TARGET_OS_IPHONE
330 char* MacLegacy_Select( filter_t
*p_filter
, const char* psz_fontname
,
331 bool b_bold
, bool b_italic
, int i_size
, int *i_idx
)
333 VLC_UNUSED( b_bold
);
334 VLC_UNUSED( b_italic
);
335 VLC_UNUSED( i_size
);
337 unsigned char path
[MAXPATHLEN
];
340 CFStringRef cf_fontName
;
341 ATSFontRef ats_font_id
;
345 if( psz_fontname
== NULL
)
348 msg_Dbg( p_filter
, "looking for %s", psz_fontname
);
349 cf_fontName
= CFStringCreateWithCString( kCFAllocatorDefault
, psz_fontname
, kCFStringEncodingUTF8
);
351 ats_font_id
= ATSFontFindFromName( cf_fontName
, kATSOptionFlagsIncludeDisabledMask
);
353 if ( ats_font_id
== 0 || ats_font_id
== 0xFFFFFFFFUL
)
355 msg_Dbg( p_filter
, "ATS couldn't find %s by name, checking family", psz_fontname
);
356 ats_font_id
= ATSFontFamilyFindFromName( cf_fontName
, kATSOptionFlagsDefault
);
358 if ( ats_font_id
== 0 || ats_font_id
== 0xFFFFFFFFUL
)
360 msg_Dbg( p_filter
, "ATS couldn't find either %s nor its family, checking PS name", psz_fontname
);
361 ats_font_id
= ATSFontFindFromPostScriptName( cf_fontName
, kATSOptionFlagsDefault
);
363 if ( ats_font_id
== 0 || ats_font_id
== 0xFFFFFFFFUL
)
365 msg_Err( p_filter
, "ATS couldn't find %s (no font name, family or PS name)", psz_fontname
);
366 CFRelease( cf_fontName
);
371 CFRelease( cf_fontName
);
373 if ( noErr
!= ATSFontGetFileReference( ats_font_id
, &ref
) )
375 msg_Err( p_filter
, "ATS couldn't get file ref for %s", psz_fontname
);
379 /* i_idx calculation by searching preceding fontIDs */
380 /* with same FSRef */
382 ATSFontRef id2
= ats_font_id
- 1;
387 if ( noErr
!= ATSFontGetFileReference( id2
, &ref2
) )
389 if ( noErr
!= FSCompareFSRefs( &ref
, &ref2
) )
394 *i_idx
= ats_font_id
- ( id2
+ 1 );
397 if ( noErr
!= FSRefMakePath( &ref
, path
, sizeof(path
) ) )
399 msg_Err( p_filter
, "failure when getting path from FSRef" );
402 msg_Dbg( p_filter
, "found %s", path
);
404 psz_path
= strdup( (char *)path
);
411 char* Dummy_Select( filter_t
*p_filter
, const char* psz_font
,
412 bool b_bold
, bool b_italic
, int i_size
, int *i_idx
)
414 VLC_UNUSED(p_filter
);
416 VLC_UNUSED(b_italic
);
421 # if defined( _WIN32 ) && !VLC_WINSTORE_APP
422 /* Get Windows Font folder */
423 char *psz_win_fonts_path
= GetWindowsFontPath();
424 if( asprintf( &psz_fontname
, "%s\\%s", psz_win_fonts_path
, psz_font
) == -1 )
429 free(psz_win_fonts_path
);
431 psz_fontname
= strdup( psz_font
);