gdi32: Move the font cache out of freetype.c.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a84c60ed2a
commit
19d13d0004
|
@ -44,6 +44,7 @@
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(font);
|
WINE_DEFAULT_DEBUG_CHANNEL(font);
|
||||||
|
|
||||||
static HKEY wine_fonts_key;
|
static HKEY wine_fonts_key;
|
||||||
|
static HKEY wine_fonts_cache_key;
|
||||||
|
|
||||||
struct font_physdev
|
struct font_physdev
|
||||||
{
|
{
|
||||||
|
@ -64,6 +65,8 @@ static UINT font_smoothing = GGO_BITMAP;
|
||||||
static UINT subpixel_orientation = GGO_GRAY4_BITMAP;
|
static UINT subpixel_orientation = GGO_GRAY4_BITMAP;
|
||||||
static BOOL antialias_fakes = TRUE;
|
static BOOL antialias_fakes = TRUE;
|
||||||
|
|
||||||
|
static void remove_face_from_cache( struct gdi_font_face *face );
|
||||||
|
|
||||||
/* Device -> World size conversion */
|
/* Device -> World size conversion */
|
||||||
|
|
||||||
/* Performs a device to world transformation on the specified width (which
|
/* Performs a device to world transformation on the specified width (which
|
||||||
|
@ -769,6 +772,287 @@ struct gdi_font_face *create_face( const WCHAR *style, const WCHAR *fullname, co
|
||||||
return face;
|
return face;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release_face( struct gdi_font_face *face )
|
||||||
|
{
|
||||||
|
if (--face->refcount) return;
|
||||||
|
if (face->family)
|
||||||
|
{
|
||||||
|
if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
|
||||||
|
list_remove( &face->entry );
|
||||||
|
release_family( face->family );
|
||||||
|
}
|
||||||
|
HeapFree( GetProcessHeap(), 0, face->file );
|
||||||
|
HeapFree( GetProcessHeap(), 0, face->style_name );
|
||||||
|
HeapFree( GetProcessHeap(), 0, face->full_name );
|
||||||
|
HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
|
||||||
|
HeapFree( GetProcessHeap(), 0, face );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BOOL faces_equal( const struct gdi_font_face *f1, const struct gdi_font_face *f2 )
|
||||||
|
{
|
||||||
|
if (strcmpiW( f1->full_name, f2->full_name )) return FALSE;
|
||||||
|
if (f1->scalable) return TRUE;
|
||||||
|
if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
|
||||||
|
return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int style_order( const struct gdi_font_face *face )
|
||||||
|
{
|
||||||
|
switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
|
||||||
|
{
|
||||||
|
case NTM_REGULAR:
|
||||||
|
return 0;
|
||||||
|
case NTM_BOLD:
|
||||||
|
return 1;
|
||||||
|
case NTM_ITALIC:
|
||||||
|
return 2;
|
||||||
|
case NTM_BOLD | NTM_ITALIC:
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
WARN( "Don't know how to order face %s with flags 0x%08x\n",
|
||||||
|
debugstr_w(face->full_name), face->ntmFlags );
|
||||||
|
return 9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family )
|
||||||
|
{
|
||||||
|
struct gdi_font_face *cursor;
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY( cursor, &family->faces, struct gdi_font_face, entry )
|
||||||
|
{
|
||||||
|
if (faces_equal( face, cursor ))
|
||||||
|
{
|
||||||
|
TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
|
||||||
|
debugstr_w(face->full_name), debugstr_w(family->family_name),
|
||||||
|
cursor->version, face->version );
|
||||||
|
|
||||||
|
if (face->file && !strcmpiW( face->file, cursor->file ))
|
||||||
|
{
|
||||||
|
cursor->refcount++;
|
||||||
|
TRACE("Font %s already in list, refcount now %d\n",
|
||||||
|
debugstr_w(face->file), cursor->refcount);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (face->version <= cursor->version)
|
||||||
|
{
|
||||||
|
TRACE("Original font %s is newer so skipping %s\n",
|
||||||
|
debugstr_w(cursor->file), debugstr_w(face->file));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE("Replacing original %s with %s\n",
|
||||||
|
debugstr_w(cursor->file), debugstr_w(face->file));
|
||||||
|
list_add_before( &cursor->entry, &face->entry );
|
||||||
|
face->family = family;
|
||||||
|
family->refcount++;
|
||||||
|
face->refcount++;
|
||||||
|
release_face( cursor );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (style_order( face ) < style_order( cursor )) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
|
||||||
|
debugstr_w(family->family_name), debugstr_w(face->file) );
|
||||||
|
list_add_before( &cursor->entry, &face->entry );
|
||||||
|
face->family = family;
|
||||||
|
family->refcount++;
|
||||||
|
face->refcount++;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* font cache */
|
||||||
|
|
||||||
|
struct cached_face
|
||||||
|
{
|
||||||
|
DWORD index;
|
||||||
|
DWORD flags;
|
||||||
|
DWORD ntmflags;
|
||||||
|
DWORD version;
|
||||||
|
struct bitmap_font_size size;
|
||||||
|
FONTSIGNATURE fs;
|
||||||
|
WCHAR full_name[1];
|
||||||
|
/* WCHAR file_name[]; */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void load_face_from_cache( HKEY hkey_family, struct gdi_font_family *family,
|
||||||
|
void *buffer, DWORD buffer_size, BOOL scalable )
|
||||||
|
{
|
||||||
|
DWORD type, size, needed, index = 0;
|
||||||
|
struct gdi_font_face *face;
|
||||||
|
HKEY hkey_strike;
|
||||||
|
WCHAR name[256];
|
||||||
|
struct cached_face *cached = (struct cached_face *)buffer;
|
||||||
|
|
||||||
|
size = sizeof(name);
|
||||||
|
needed = buffer_size - sizeof(DWORD);
|
||||||
|
while (!RegEnumValueW( hkey_family, index++, name, &size, NULL, &type, buffer, &needed ))
|
||||||
|
{
|
||||||
|
if (type == REG_BINARY && needed > sizeof(*cached))
|
||||||
|
{
|
||||||
|
((DWORD *)buffer)[needed / sizeof(DWORD)] = 0;
|
||||||
|
|
||||||
|
face = create_face( name, cached->full_name, cached->full_name + strlenW(cached->full_name) + 1,
|
||||||
|
cached->index, cached->fs, cached->ntmflags, cached->version,
|
||||||
|
cached->flags, scalable ? NULL : &cached->size );
|
||||||
|
if (!scalable)
|
||||||
|
TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
|
||||||
|
face->size.height, face->size.width, face->size.size >> 6,
|
||||||
|
face->size.x_ppem >> 6, face->size.y_ppem >> 6);
|
||||||
|
|
||||||
|
TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
|
||||||
|
face->fs.fsCsb[0], face->fs.fsCsb[1],
|
||||||
|
face->fs.fsUsb[0], face->fs.fsUsb[1],
|
||||||
|
face->fs.fsUsb[2], face->fs.fsUsb[3]);
|
||||||
|
|
||||||
|
insert_face_in_family_list( face, family );
|
||||||
|
release_face( face );
|
||||||
|
}
|
||||||
|
size = sizeof(name);
|
||||||
|
needed = buffer_size - sizeof(DWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load bitmap strikes */
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
needed = buffer_size;
|
||||||
|
while (!RegEnumKeyExW( hkey_family, index++, buffer, &needed, NULL, NULL, NULL, NULL ))
|
||||||
|
{
|
||||||
|
if (!RegOpenKeyExW( hkey_family, buffer, 0, KEY_ALL_ACCESS, &hkey_strike ))
|
||||||
|
{
|
||||||
|
load_face_from_cache( hkey_strike, family, buffer, buffer_size, FALSE );
|
||||||
|
RegCloseKey( hkey_strike );
|
||||||
|
}
|
||||||
|
needed = buffer_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move vertical fonts after their horizontal counterpart */
|
||||||
|
/* assumes that font_list is already sorted by family name */
|
||||||
|
static void reorder_vertical_fonts(void)
|
||||||
|
{
|
||||||
|
struct gdi_font_family *family, *next, *vert_family;
|
||||||
|
struct list *ptr, *vptr;
|
||||||
|
struct list vertical_families = LIST_INIT( vertical_families );
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, struct gdi_font_family, entry )
|
||||||
|
{
|
||||||
|
if (family->family_name[0] != '@') continue;
|
||||||
|
list_remove( &family->entry );
|
||||||
|
list_add_tail( &vertical_families, &family->entry );
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = list_head( &font_list );
|
||||||
|
vptr = list_head( &vertical_families );
|
||||||
|
while (ptr && vptr)
|
||||||
|
{
|
||||||
|
family = LIST_ENTRY( ptr, struct gdi_font_family, entry );
|
||||||
|
vert_family = LIST_ENTRY( vptr, struct gdi_font_family, entry );
|
||||||
|
if (strcmpiW( family->family_name, vert_family->family_name + 1 ) > 0)
|
||||||
|
{
|
||||||
|
list_remove( vptr );
|
||||||
|
list_add_before( ptr, vptr );
|
||||||
|
vptr = list_head( &vertical_families );
|
||||||
|
}
|
||||||
|
else ptr = list_next( &font_list, ptr );
|
||||||
|
}
|
||||||
|
list_move_tail( &font_list, &vertical_families );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_font_list_from_cache(void)
|
||||||
|
{
|
||||||
|
DWORD size, family_index = 0;
|
||||||
|
struct gdi_font_family *family;
|
||||||
|
HKEY hkey_family;
|
||||||
|
WCHAR buffer[4096], second_name[LF_FACESIZE];
|
||||||
|
|
||||||
|
size = sizeof(buffer);
|
||||||
|
while (!RegEnumKeyExW( wine_fonts_cache_key, family_index++, buffer, &size, NULL, NULL, NULL, NULL ))
|
||||||
|
{
|
||||||
|
RegOpenKeyExW( wine_fonts_cache_key, buffer, 0, KEY_ALL_ACCESS, &hkey_family );
|
||||||
|
TRACE("opened family key %s\n", debugstr_w(buffer));
|
||||||
|
size = sizeof(second_name);
|
||||||
|
if (RegQueryValueExW( hkey_family, NULL, NULL, NULL, (BYTE *)second_name, &size ))
|
||||||
|
second_name[0] = 0;
|
||||||
|
|
||||||
|
family = create_family( buffer, second_name );
|
||||||
|
|
||||||
|
load_face_from_cache( hkey_family, family, buffer, sizeof(buffer), TRUE );
|
||||||
|
|
||||||
|
RegCloseKey( hkey_family );
|
||||||
|
release_family( family );
|
||||||
|
size = sizeof(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
reorder_vertical_fonts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_face_to_cache( struct gdi_font_face *face )
|
||||||
|
{
|
||||||
|
HKEY hkey_family, hkey_face;
|
||||||
|
DWORD len, buffer[1024];
|
||||||
|
struct cached_face *cached = (struct cached_face *)buffer;
|
||||||
|
|
||||||
|
if (RegCreateKeyExW( wine_fonts_cache_key, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE,
|
||||||
|
KEY_ALL_ACCESS, NULL, &hkey_family, NULL ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (face->family->second_name[0])
|
||||||
|
RegSetValueExW( hkey_family, NULL, 0, REG_SZ, (BYTE *)face->family->second_name,
|
||||||
|
(strlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
|
||||||
|
|
||||||
|
if (!face->scalable)
|
||||||
|
{
|
||||||
|
static const WCHAR fmtW[] = {'%','d',0};
|
||||||
|
WCHAR name[10];
|
||||||
|
|
||||||
|
sprintfW( name, fmtW, face->size.y_ppem );
|
||||||
|
RegCreateKeyExW( hkey_family, name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
|
||||||
|
NULL, &hkey_face, NULL);
|
||||||
|
}
|
||||||
|
else hkey_face = hkey_family;
|
||||||
|
|
||||||
|
memset( cached, 0, sizeof(*cached) );
|
||||||
|
cached->index = face->face_index;
|
||||||
|
cached->flags = face->flags;
|
||||||
|
cached->ntmflags = face->ntmFlags;
|
||||||
|
cached->version = face->version;
|
||||||
|
cached->fs = face->fs;
|
||||||
|
if (!face->scalable) cached->size = face->size;
|
||||||
|
strcpyW( cached->full_name, face->full_name );
|
||||||
|
len = strlenW( face->full_name ) + 1;
|
||||||
|
strcpyW( cached->full_name + len, face->file );
|
||||||
|
len += strlenW( face->file ) + 1;
|
||||||
|
|
||||||
|
RegSetValueExW( hkey_face, face->style_name, 0, REG_BINARY, (BYTE *)cached,
|
||||||
|
offsetof( struct cached_face, full_name[len] ));
|
||||||
|
|
||||||
|
if (hkey_face != hkey_family) RegCloseKey( hkey_face );
|
||||||
|
RegCloseKey( hkey_family );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_face_from_cache( struct gdi_font_face *face )
|
||||||
|
{
|
||||||
|
HKEY hkey_family;
|
||||||
|
|
||||||
|
if (RegOpenKeyExW( wine_fonts_cache_key, face->family->family_name, 0, KEY_ALL_ACCESS, &hkey_family ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!face->scalable)
|
||||||
|
{
|
||||||
|
static const WCHAR fmtW[] = {'%','d',0};
|
||||||
|
WCHAR name[10];
|
||||||
|
sprintfW( name, fmtW, face->size.y_ppem );
|
||||||
|
RegDeleteKeyW( hkey_family, name );
|
||||||
|
}
|
||||||
|
else RegDeleteValueW( hkey_family, face->style_name );
|
||||||
|
|
||||||
|
RegCloseKey( hkey_family );
|
||||||
|
}
|
||||||
|
|
||||||
/* font links */
|
/* font links */
|
||||||
|
|
||||||
static struct list font_links = LIST_INIT(font_links);
|
static struct list font_links = LIST_INIT(font_links);
|
||||||
|
@ -3240,6 +3524,7 @@ void font_init(void)
|
||||||
{
|
{
|
||||||
static const WCHAR mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_',0};
|
static const WCHAR mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_',0};
|
||||||
HANDLE mutex;
|
HANDLE mutex;
|
||||||
|
DWORD disposition;
|
||||||
|
|
||||||
if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0,
|
if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0,
|
||||||
KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
|
KEY_ALL_ACCESS, NULL, &wine_fonts_key, NULL ))
|
||||||
|
@ -3251,7 +3536,13 @@ void font_init(void)
|
||||||
|
|
||||||
if (!(mutex = CreateMutexW( NULL, FALSE, mutex_nameW ))) return;
|
if (!(mutex = CreateMutexW( NULL, FALSE, mutex_nameW ))) return;
|
||||||
WaitForSingleObject( mutex, INFINITE );
|
WaitForSingleObject( mutex, INFINITE );
|
||||||
font_funcs->load_fonts();
|
|
||||||
|
RegCreateKeyExA( wine_fonts_key, "Cache", 0, NULL, REG_OPTION_VOLATILE,
|
||||||
|
KEY_ALL_ACCESS, NULL, &wine_fonts_cache_key, &disposition );
|
||||||
|
|
||||||
|
if (disposition == REG_CREATED_NEW_KEY) font_funcs->load_fonts();
|
||||||
|
else load_font_list_from_cache();
|
||||||
|
|
||||||
ReleaseMutex( mutex );
|
ReleaseMutex( mutex );
|
||||||
|
|
||||||
reorder_font_list();
|
reorder_font_list();
|
||||||
|
|
|
@ -265,12 +265,6 @@ static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','
|
||||||
|
|
||||||
static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
|
static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
|
||||||
|
|
||||||
/* Registry font cache key and value names */
|
|
||||||
static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
|
|
||||||
'F','o','n','t','s',0};
|
|
||||||
static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
|
|
||||||
|
|
||||||
|
|
||||||
struct font_mapping
|
struct font_mapping
|
||||||
{
|
{
|
||||||
struct list entry;
|
struct list entry;
|
||||||
|
@ -284,11 +278,9 @@ struct font_mapping
|
||||||
static struct list mappings_list = LIST_INIT( mappings_list );
|
static struct list mappings_list = LIST_INIT( mappings_list );
|
||||||
|
|
||||||
static UINT default_aa_flags;
|
static UINT default_aa_flags;
|
||||||
static HKEY hkey_font_cache;
|
|
||||||
|
|
||||||
static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font );
|
static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font );
|
||||||
static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font );
|
static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font );
|
||||||
static void remove_face_from_cache( Face *face );
|
|
||||||
|
|
||||||
/****************************************
|
/****************************************
|
||||||
* Notes on .fon files
|
* Notes on .fon files
|
||||||
|
@ -884,311 +876,6 @@ static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
|
||||||
return full_name;
|
return full_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BOOL faces_equal( const Face *f1, const Face *f2 )
|
|
||||||
{
|
|
||||||
if (strcmpiW( f1->full_name, f2->full_name )) return FALSE;
|
|
||||||
if (f1->scalable) return TRUE;
|
|
||||||
if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
|
|
||||||
return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void release_face( Face *face )
|
|
||||||
{
|
|
||||||
if (--face->refcount) return;
|
|
||||||
if (face->family)
|
|
||||||
{
|
|
||||||
if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
|
|
||||||
list_remove( &face->entry );
|
|
||||||
release_family( face->family );
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, face->file );
|
|
||||||
HeapFree( GetProcessHeap(), 0, face->style_name );
|
|
||||||
HeapFree( GetProcessHeap(), 0, face->full_name );
|
|
||||||
HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
|
|
||||||
HeapFree( GetProcessHeap(), 0, face );
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int style_order(const Face *face)
|
|
||||||
{
|
|
||||||
switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
|
|
||||||
{
|
|
||||||
case NTM_REGULAR:
|
|
||||||
return 0;
|
|
||||||
case NTM_BOLD:
|
|
||||||
return 1;
|
|
||||||
case NTM_ITALIC:
|
|
||||||
return 2;
|
|
||||||
case NTM_BOLD | NTM_ITALIC:
|
|
||||||
return 3;
|
|
||||||
default:
|
|
||||||
WARN( "Don't know how to order face %s with flags 0x%08x\n", debugstr_w(face->full_name), face->ntmFlags );
|
|
||||||
return 9999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL insert_face_in_family_list( Face *face, Family *family )
|
|
||||||
{
|
|
||||||
Face *cursor;
|
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
|
|
||||||
{
|
|
||||||
if (faces_equal( face, cursor ))
|
|
||||||
{
|
|
||||||
TRACE( "Already loaded face %s in family %s, original version %x, new version %x\n",
|
|
||||||
debugstr_w(face->full_name), debugstr_w(family->family_name),
|
|
||||||
cursor->version, face->version );
|
|
||||||
|
|
||||||
if (face->file && !strcmpiW( face->file, cursor->file ))
|
|
||||||
{
|
|
||||||
cursor->refcount++;
|
|
||||||
TRACE("Font %s already in list, refcount now %d\n",
|
|
||||||
debugstr_w(face->file), cursor->refcount);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (face->version <= cursor->version)
|
|
||||||
{
|
|
||||||
TRACE("Original font %s is newer so skipping %s\n",
|
|
||||||
debugstr_w(cursor->file), debugstr_w(face->file));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACE("Replacing original %s with %s\n",
|
|
||||||
debugstr_w(cursor->file), debugstr_w(face->file));
|
|
||||||
list_add_before( &cursor->entry, &face->entry );
|
|
||||||
face->family = family;
|
|
||||||
family->refcount++;
|
|
||||||
face->refcount++;
|
|
||||||
release_face( cursor );
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style_order( face ) < style_order( cursor )) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
|
|
||||||
debugstr_w(family->family_name), debugstr_w(face->file) );
|
|
||||||
list_add_before( &cursor->entry, &face->entry );
|
|
||||||
face->family = family;
|
|
||||||
family->refcount++;
|
|
||||||
face->refcount++;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct cached_face
|
|
||||||
{
|
|
||||||
DWORD index;
|
|
||||||
DWORD flags;
|
|
||||||
DWORD ntmflags;
|
|
||||||
DWORD version;
|
|
||||||
struct bitmap_font_size size;
|
|
||||||
FONTSIGNATURE fs;
|
|
||||||
WCHAR full_name[1];
|
|
||||||
/* WCHAR file_name[]; */
|
|
||||||
};
|
|
||||||
|
|
||||||
static void load_face(HKEY hkey_family, Family *family, void *buffer, DWORD buffer_size, BOOL scalable)
|
|
||||||
{
|
|
||||||
DWORD type, size, needed, index = 0;
|
|
||||||
Face *face;
|
|
||||||
HKEY hkey_strike;
|
|
||||||
WCHAR name[256];
|
|
||||||
struct cached_face *cached = (struct cached_face *)buffer;
|
|
||||||
|
|
||||||
size = sizeof(name);
|
|
||||||
needed = buffer_size - sizeof(DWORD);
|
|
||||||
while (!RegEnumValueW( hkey_family, index++, name, &size, NULL, &type, buffer, &needed ))
|
|
||||||
{
|
|
||||||
if (type == REG_BINARY && needed > sizeof(*cached))
|
|
||||||
{
|
|
||||||
((DWORD *)buffer)[needed / sizeof(DWORD)] = 0;
|
|
||||||
|
|
||||||
face = create_face( name, cached->full_name, cached->full_name + strlenW(cached->full_name) + 1,
|
|
||||||
cached->index, cached->fs, cached->ntmflags, cached->version,
|
|
||||||
cached->flags, scalable ? NULL : &cached->size );
|
|
||||||
if (!scalable)
|
|
||||||
TRACE("Adding bitmap size h %d w %d size %d x_ppem %d y_ppem %d\n",
|
|
||||||
face->size.height, face->size.width, face->size.size >> 6,
|
|
||||||
face->size.x_ppem >> 6, face->size.y_ppem >> 6);
|
|
||||||
|
|
||||||
TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
|
|
||||||
face->fs.fsCsb[0], face->fs.fsCsb[1],
|
|
||||||
face->fs.fsUsb[0], face->fs.fsUsb[1],
|
|
||||||
face->fs.fsUsb[2], face->fs.fsUsb[3]);
|
|
||||||
|
|
||||||
if (insert_face_in_family_list(face, family))
|
|
||||||
TRACE( "Added face %s to family %s\n", debugstr_w(face->full_name), debugstr_w(family->family_name) );
|
|
||||||
|
|
||||||
release_face( face );
|
|
||||||
}
|
|
||||||
size = sizeof(name);
|
|
||||||
needed = buffer_size - sizeof(DWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load bitmap strikes */
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
needed = buffer_size;
|
|
||||||
while (!RegEnumKeyExW(hkey_family, index++, buffer, &needed, NULL, NULL, NULL, NULL))
|
|
||||||
{
|
|
||||||
if (!RegOpenKeyExW(hkey_family, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
|
|
||||||
{
|
|
||||||
load_face(hkey_strike, family, buffer, buffer_size, FALSE);
|
|
||||||
RegCloseKey(hkey_strike);
|
|
||||||
}
|
|
||||||
needed = buffer_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* move vertical fonts after their horizontal counterpart */
|
|
||||||
/* assumes that font_list is already sorted by family name */
|
|
||||||
static void reorder_vertical_fonts(void)
|
|
||||||
{
|
|
||||||
Family *family, *next, *vert_family;
|
|
||||||
struct list *ptr, *vptr;
|
|
||||||
struct list vertical_families = LIST_INIT( vertical_families );
|
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
|
|
||||||
{
|
|
||||||
if (family->family_name[0] != '@') continue;
|
|
||||||
list_remove( &family->entry );
|
|
||||||
list_add_tail( &vertical_families, &family->entry );
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = list_head( &font_list );
|
|
||||||
vptr = list_head( &vertical_families );
|
|
||||||
while (ptr && vptr)
|
|
||||||
{
|
|
||||||
family = LIST_ENTRY( ptr, Family, entry );
|
|
||||||
vert_family = LIST_ENTRY( vptr, Family, entry );
|
|
||||||
if (strcmpiW( family->family_name, vert_family->family_name + 1 ) > 0)
|
|
||||||
{
|
|
||||||
list_remove( vptr );
|
|
||||||
list_add_before( ptr, vptr );
|
|
||||||
vptr = list_head( &vertical_families );
|
|
||||||
}
|
|
||||||
else ptr = list_next( &font_list, ptr );
|
|
||||||
}
|
|
||||||
list_move_tail( &font_list, &vertical_families );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_font_list_from_cache(HKEY hkey_font_cache)
|
|
||||||
{
|
|
||||||
DWORD size, family_index = 0;
|
|
||||||
Family *family;
|
|
||||||
HKEY hkey_family;
|
|
||||||
WCHAR buffer[4096];
|
|
||||||
|
|
||||||
size = sizeof(buffer);
|
|
||||||
while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
|
|
||||||
{
|
|
||||||
WCHAR *second_name = NULL;
|
|
||||||
WCHAR *family_name = strdupW( buffer );
|
|
||||||
|
|
||||||
RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
|
|
||||||
TRACE("opened family key %s\n", debugstr_w(family_name));
|
|
||||||
size = sizeof(buffer);
|
|
||||||
if (!RegQueryValueExW( hkey_family, NULL, NULL, NULL, (BYTE *)buffer, &size ))
|
|
||||||
second_name = strdupW( buffer );
|
|
||||||
|
|
||||||
family = create_family( family_name, second_name );
|
|
||||||
|
|
||||||
load_face(hkey_family, family, buffer, sizeof(buffer), TRUE);
|
|
||||||
|
|
||||||
HeapFree( GetProcessHeap(), 0, family_name );
|
|
||||||
HeapFree( GetProcessHeap(), 0, second_name );
|
|
||||||
|
|
||||||
RegCloseKey(hkey_family);
|
|
||||||
release_family( family );
|
|
||||||
size = sizeof(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
reorder_vertical_fonts();
|
|
||||||
}
|
|
||||||
|
|
||||||
static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
|
|
||||||
{
|
|
||||||
LONG ret;
|
|
||||||
HKEY hkey_wine_fonts;
|
|
||||||
|
|
||||||
/* We don't want to create the fonts key as volatile, so open this first */
|
|
||||||
ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
|
|
||||||
KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
|
|
||||||
if(ret != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
|
|
||||||
KEY_ALL_ACCESS, NULL, hkey, disposition);
|
|
||||||
RegCloseKey(hkey_wine_fonts);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_face_to_cache(Face *face)
|
|
||||||
{
|
|
||||||
HKEY hkey_family, hkey_face;
|
|
||||||
DWORD len, buffer[1024];
|
|
||||||
struct cached_face *cached = (struct cached_face *)buffer;
|
|
||||||
|
|
||||||
RegCreateKeyExW( hkey_font_cache, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE,
|
|
||||||
KEY_ALL_ACCESS, NULL, &hkey_family, NULL );
|
|
||||||
if (face->family->second_name[0])
|
|
||||||
RegSetValueExW( hkey_family, NULL, 0, REG_SZ, (BYTE *)face->family->second_name,
|
|
||||||
(strlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
|
|
||||||
|
|
||||||
if (!face->scalable)
|
|
||||||
{
|
|
||||||
static const WCHAR fmtW[] = {'%','d',0};
|
|
||||||
WCHAR name[10];
|
|
||||||
|
|
||||||
sprintfW( name, fmtW, face->size.y_ppem );
|
|
||||||
RegCreateKeyExW( hkey_family, name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
|
|
||||||
NULL, &hkey_face, NULL);
|
|
||||||
}
|
|
||||||
else hkey_face = hkey_family;
|
|
||||||
|
|
||||||
memset( cached, 0, sizeof(*cached) );
|
|
||||||
cached->index = face->face_index;
|
|
||||||
cached->flags = face->flags;
|
|
||||||
cached->ntmflags = face->ntmFlags;
|
|
||||||
cached->version = face->version;
|
|
||||||
cached->fs = face->fs;
|
|
||||||
if (!face->scalable) cached->size = face->size;
|
|
||||||
strcpyW( cached->full_name, face->full_name );
|
|
||||||
len = strlenW( face->full_name ) + 1;
|
|
||||||
strcpyW( cached->full_name + len, face->file );
|
|
||||||
len += strlenW( face->file ) + 1;
|
|
||||||
|
|
||||||
RegSetValueExW( hkey_face, face->style_name, 0, REG_BINARY, (BYTE *)cached,
|
|
||||||
offsetof( struct cached_face, full_name[len] ));
|
|
||||||
|
|
||||||
if (hkey_face != hkey_family) RegCloseKey(hkey_face);
|
|
||||||
RegCloseKey(hkey_family);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_face_from_cache( Face *face )
|
|
||||||
{
|
|
||||||
HKEY hkey_family;
|
|
||||||
|
|
||||||
RegOpenKeyExW( hkey_font_cache, face->family->family_name, 0, KEY_ALL_ACCESS, &hkey_family );
|
|
||||||
|
|
||||||
if (face->scalable)
|
|
||||||
{
|
|
||||||
RegDeleteValueW( hkey_family, face->style_name );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static const WCHAR fmtW[] = {'%','d',0};
|
|
||||||
WCHAR name[10];
|
|
||||||
sprintfW( name, fmtW, face->size.y_ppem );
|
|
||||||
RegDeleteKeyW( hkey_family, name );
|
|
||||||
}
|
|
||||||
RegCloseKey(hkey_family);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WCHAR *get_vertical_name( WCHAR *name )
|
static WCHAR *get_vertical_name( WCHAR *name )
|
||||||
{
|
{
|
||||||
SIZE_T length;
|
SIZE_T length;
|
||||||
|
@ -2149,7 +1836,10 @@ sym_not_found:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_font_list(void)
|
/*************************************************************
|
||||||
|
* freetype_load_fonts
|
||||||
|
*/
|
||||||
|
static void CDECL freetype_load_fonts(void)
|
||||||
{
|
{
|
||||||
delete_external_font_keys();
|
delete_external_font_keys();
|
||||||
load_system_bitmap_fonts();
|
load_system_bitmap_fonts();
|
||||||
|
@ -2163,24 +1853,8 @@ static void init_font_list(void)
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
ReadFontDir("/system/fonts", TRUE);
|
ReadFontDir("/system/fonts", TRUE);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************
|
update_reg_entries();
|
||||||
* freetype_load_fonts
|
|
||||||
*/
|
|
||||||
static void CDECL freetype_load_fonts(void)
|
|
||||||
{
|
|
||||||
DWORD disposition;
|
|
||||||
|
|
||||||
create_font_cache_key(&hkey_font_cache, &disposition);
|
|
||||||
|
|
||||||
if(disposition == REG_CREATED_NEW_KEY)
|
|
||||||
init_font_list();
|
|
||||||
else
|
|
||||||
load_font_list_from_cache(hkey_font_cache);
|
|
||||||
|
|
||||||
if(disposition == REG_CREATED_NEW_KEY)
|
|
||||||
update_reg_entries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
|
|
|
@ -463,6 +463,9 @@ extern struct gdi_font_family *find_family_from_any_name( const WCHAR *name ) DE
|
||||||
extern struct gdi_font_face *create_face( const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
|
extern struct gdi_font_face *create_face( const WCHAR *style, const WCHAR *fullname, const WCHAR *file,
|
||||||
UINT index, FONTSIGNATURE fs, DWORD ntmflags,
|
UINT index, FONTSIGNATURE fs, DWORD ntmflags,
|
||||||
DWORD version, DWORD flags, const struct bitmap_font_size *size ) DECLSPEC_HIDDEN;
|
DWORD version, DWORD flags, const struct bitmap_font_size *size ) DECLSPEC_HIDDEN;
|
||||||
|
extern void release_face( struct gdi_font_face *face ) DECLSPEC_HIDDEN;
|
||||||
|
extern BOOL insert_face_in_family_list( struct gdi_font_face *face, struct gdi_font_family *family ) DECLSPEC_HIDDEN;
|
||||||
|
extern void add_face_to_cache( struct gdi_font_face *face ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern struct gdi_font_link *find_gdi_font_link( const WCHAR *name ) DECLSPEC_HIDDEN;
|
extern struct gdi_font_link *find_gdi_font_link( const WCHAR *name ) DECLSPEC_HIDDEN;
|
||||||
extern struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
|
extern struct gdi_font_family *find_family_from_font_links( const WCHAR *name, const WCHAR *subst,
|
||||||
|
|
Loading…
Reference in New Issue