vlc_family_t *InitDefaultList( filter_t *p_filter, const char *const *ppsz_default, int i_size ) { vlc_family_t *p_default = NULL; filter_sys_t *p_sys = p_filter->p_sys; for( int i = 0; i < i_size; ++i ) { const vlc_family_t *p_family = p_sys->pf_get_family( p_filter, ppsz_default[ i ] ); if( p_family ) { vlc_family_t *p_temp = NewFamily( p_filter, ppsz_default[ i ], &p_default, NULL, NULL ); if( unlikely( !p_temp ) ) goto error; p_temp->p_fonts = p_family->p_fonts; } } if( p_default ) vlc_dictionary_insert( &p_sys->fallback_map, FB_LIST_DEFAULT, p_default ); return p_default; error: if( p_default ) FreeFamilies( p_default, NULL ); return NULL; }
vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family, uni_char_t codepoint ) { vlc_family_t *p_family = NULL; vlc_family_t *p_fallbacks = NULL; filter_sys_t *p_sys = p_filter->p_sys; char *psz_uniscribe = NULL; char *psz_lc = ToLower( psz_family ); if( unlikely( !psz_lc ) ) return NULL; p_fallbacks = vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc ); if( p_fallbacks ) p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint ); /* * If the fallback list of psz_family has no family which contains the requested * codepoint, try UniscribeFallback(). If it returns a valid family which does * contain that codepoint, add the new family to the fallback list to speed up * later searches. */ if( !p_family ) { psz_uniscribe = UniscribeFallback( psz_lc, codepoint ); if( !psz_uniscribe ) goto done; const vlc_family_t *p_uniscribe = Win32_GetFamily( p_filter, psz_uniscribe ); if( !p_uniscribe || !p_uniscribe->p_fonts ) goto done; FT_Face p_face = GetFace( p_filter, p_uniscribe->p_fonts ); if( !p_face || !FT_Get_Char_Index( p_face, codepoint ) ) goto done; p_family = NewFamily( p_filter, psz_uniscribe, NULL, NULL, NULL ); if( unlikely( !p_family ) ) goto done; p_family->p_fonts = p_uniscribe->p_fonts; if( p_fallbacks ) AppendFamily( &p_fallbacks, p_family ); else vlc_dictionary_insert( &p_sys->fallback_map, psz_lc, p_family ); } done: free( psz_lc ); free( psz_uniscribe ); return p_family; }
const vlc_family_t *Win32_GetFamily( filter_t *p_filter, const char *psz_family ) { filter_sys_t *p_sys = p_filter->p_sys; char *psz_lc = ToLower( psz_family ); if( unlikely( !psz_lc ) ) return NULL; vlc_family_t *p_family = vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc ); free( psz_lc ); if( p_family ) return p_family; p_family = NewFamily( p_filter, psz_family, &p_sys->p_families, &p_sys->family_map, psz_family ); if( unlikely( !p_family ) ) return NULL; LOGFONT lf; lf.lfCharSet = DEFAULT_CHARSET; LPTSTR psz_fbuffer = ToT( psz_family ); _tcsncpy( (LPTSTR)&lf.lfFaceName, psz_fbuffer, LF_FACESIZE ); free( psz_fbuffer ); /* */ HDC hDC = GetDC( NULL ); EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)p_family, 0); ReleaseDC(NULL, hDC); return p_family; }
static int Android_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml ) { filter_sys_t *p_sys = p_filter->p_sys; vlc_dictionary_t *p_dict = &p_sys->family_map; vlc_family_t *p_family = NULL; char *psz_lc = NULL; int i_counter = 0; bool b_bold = false; bool b_italic = false; const char *p_node = NULL; int i_type = 0; while( ( i_type = xml_ReaderNextNode( p_xml, &p_node ) ) > 0 ) { switch( i_type ) { case XML_READER_STARTELEM: /* * Multiple names can reference the same family in Android. When * the first name is encountered we set p_family to the vlc_family_t * in the master list matching this name, and if no such family * exists we create a new one and add it to the master list. * If the master list does contain a family with that name it's one * of the font attachments, and the family will end up having embedded * fonts and system fonts. */ if( !strcasecmp( "name", p_node ) ) { i_type = xml_ReaderNextNode( p_xml, &p_node ); if( i_type != XML_READER_TEXT || !p_node || !*p_node ) { msg_Warn( p_filter, "Android_ParseFamily: empty name" ); continue; } psz_lc = ToLower( p_node ); if( unlikely( !psz_lc ) ) return VLC_ENOMEM; if( !p_family ) { p_family = vlc_dictionary_value_for_key( p_dict, psz_lc ); if( p_family == kVLCDictionaryNotFound ) { p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families, NULL, NULL ); if( unlikely( !p_family ) ) { free( psz_lc ); return VLC_ENOMEM; } } } if( vlc_dictionary_value_for_key( p_dict, psz_lc ) == kVLCDictionaryNotFound ) vlc_dictionary_insert( p_dict, psz_lc, p_family ); free( psz_lc ); } /* * If p_family has not been set by the time we encounter the first file, * it means this family has no name, and should be used only as a fallback. * We create a new family for it in the master list with the name "fallback-xx" * and later add it to the "default" fallback list. */ else if( !strcasecmp( "file", p_node ) ) { i_type = xml_ReaderNextNode( p_xml, &p_node ); if( i_type != XML_READER_TEXT || !p_node || !*p_node ) { ++i_counter; continue; } if( !p_family ) p_family = NewFamily( p_filter, NULL, &p_sys->p_families, &p_sys->family_map, NULL ); if( unlikely( !p_family ) ) return VLC_ENOMEM; switch( i_counter ) { case 0: b_bold = false; b_italic = false; break; case 1: b_bold = true; b_italic = false; break; case 2: b_bold = false; b_italic = true; break; case 3: b_bold = true; b_italic = true; break; default: msg_Warn( p_filter, "Android_ParseFamily: too many files" ); return VLC_EGENERIC; } char *psz_fontfile = NULL; if( asprintf( &psz_fontfile, "%s/%s", ANDROID_FONT_PATH, p_node ) < 0 || !NewFont( psz_fontfile, 0, b_bold, b_italic, p_family ) ) return VLC_ENOMEM; ++i_counter; } break; case XML_READER_ENDELEM: if( !strcasecmp( "family", p_node ) ) { if( !p_family ) { msg_Warn( p_filter, "Android_ParseFamily: empty family" ); return VLC_EGENERIC; } /* * If the family name has "fallback" in it, add it to the * "default" fallback list. */ if( strcasestr( p_family->psz_name, FB_NAME ) ) { vlc_family_t *p_fallback = NewFamily( p_filter, p_family->psz_name, NULL, &p_sys->fallback_map, FB_LIST_DEFAULT ); if( unlikely( !p_fallback ) ) return VLC_ENOMEM; p_fallback->p_fonts = p_family->p_fonts; } return VLC_SUCCESS; } break; } } msg_Warn( p_filter, "Android_ParseFamily: Corrupt font configuration file" ); return VLC_EGENERIC; }
const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family ) { filter_sys_t *p_sys = p_filter->p_sys; char *psz_lc = ToLower( psz_family ); if( unlikely( !psz_lc ) ) return NULL; vlc_family_t *p_family = vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc ); if( p_family != kVLCDictionaryNotFound ) { free( psz_lc ); return p_family; } p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families, &p_sys->family_map, psz_lc ); free( psz_lc ); if( !p_family ) return NULL; bool b_bold, b_italic; for( int i = 0; i < 4; ++i ) { switch( i ) { case 0: b_bold = false; b_italic = false; break; case 1: b_bold = true; b_italic = false; break; case 2: b_bold = false; b_italic = true; break; case 3: b_bold = true; b_italic = true; break; } int i_index = 0; FcResult result = FcResultMatch; FcPattern *pat, *p_pat; FcChar8* val_s; FcBool val_b; char *psz_fontfile = NULL; FcConfig* config = NULL; /* Create a pattern and fill it */ pat = FcPatternCreate(); if (!pat) continue; /* */ FcPatternAddString( pat, FC_FAMILY, (const FcChar8*) psz_family ); FcPatternAddBool( pat, FC_OUTLINE, FcTrue ); FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN ); FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL ); /* */ FcDefaultSubstitute( pat ); if( !FcConfigSubstitute( config, pat, FcMatchPattern ) ) { FcPatternDestroy( pat ); continue; } /* Find the best font for the pattern, destroy the pattern */ p_pat = FcFontMatch( config, pat, &result ); FcPatternDestroy( pat ); if( !p_pat || result == FcResultNoMatch ) continue; /* Check the new pattern */ if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) ) || ( val_b != FcTrue ) ) { FcPatternDestroy( p_pat ); continue; } if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, &i_index ) ) { i_index = 0; } if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) ) { FcPatternDestroy( p_pat ); continue; } if( FcResultMatch == FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) ) psz_fontfile = strdup( (const char*)val_s ); FcPatternDestroy( p_pat ); if( !psz_fontfile ) continue; NewFont( psz_fontfile, i_index, b_bold, b_italic, p_family ); } return p_family; }
vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_family, uni_char_t codepoint ) { VLC_UNUSED( codepoint ); vlc_family_t *p_family = NULL; filter_sys_t *p_sys = p_filter->p_sys; char *psz_lc = ToLower( psz_family ); if( unlikely( !psz_lc ) ) return NULL; p_family = vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc ); if( p_family != kVLCDictionaryNotFound ) { free( psz_lc ); return p_family; } else p_family = NULL; const char *psz_last_name = ""; FcPattern *p_pattern = FcPatternCreate(); FcValue family; family.type = FcTypeString; family.u.s = ( const FcChar8* ) psz_family; FcPatternAdd( p_pattern, FC_FAMILY, family, FcFalse ); if( FcConfigSubstitute( NULL, p_pattern, FcMatchPattern ) == FcTrue ) { FcDefaultSubstitute( p_pattern ); FcResult result; FcFontSet* p_font_set = FcFontSort( NULL, p_pattern, FcTrue, NULL, &result ); if( p_font_set ) { for( int i = 0; i < p_font_set->nfont; ++i ) { char* psz_name = NULL; FcPatternGetString( p_font_set->fonts[i], FC_FAMILY, 0, ( FcChar8** )( &psz_name ) ); /* Avoid duplicate family names */ if( strcasecmp( psz_last_name, psz_name ) ) { vlc_family_t *p_temp = NewFamily( p_filter, psz_name, &p_family, NULL, NULL ); if( unlikely( !p_temp ) ) { FcFontSetDestroy( p_font_set ); FcPatternDestroy( p_pattern ); if( p_family ) FreeFamilies( p_family, NULL ); free( psz_lc ); return NULL; } psz_last_name = p_temp->psz_name; } } FcFontSetDestroy( p_font_set ); } } FcPatternDestroy( p_pattern ); if( p_family ) vlc_dictionary_insert( &p_sys->fallback_map, psz_lc, p_family ); free( psz_lc ); return p_family; }