gdi32: Separate font loading from adding a font to global font list.
Dmitry Timoshkov
dmitry at codeweavers.com
Tue Nov 9 07:09:20 CST 2010
---
dlls/gdi32/freetype.c | 328 ++++++++++++++++++++++++++++++++-----------------
1 files changed, 217 insertions(+), 111 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index e2db1aa..b4169c0 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -280,7 +280,7 @@ typedef struct tagFace {
typedef struct tagFamily {
struct list entry;
- const WCHAR *FamilyName;
+ WCHAR *FamilyName;
struct list faces;
} Family;
@@ -365,7 +365,7 @@ static struct list system_links = LIST_INIT(system_links);
static struct list font_subst_list = LIST_INIT(font_subst_list);
-static struct list font_list = LIST_INIT(font_list);
+static struct list global_font_list = LIST_INIT(global_font_list);
static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
@@ -858,7 +858,7 @@ static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_n
WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
- LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
+ LIST_FOR_EACH_ENTRY(family, &global_font_list, Family, entry)
{
if(face_name && strcmpiW(face_name, family->FamilyName))
continue;
@@ -886,7 +886,7 @@ static Family *find_family_from_name(const WCHAR *name)
{
Family *family;
- LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
+ LIST_FOR_EACH_ENTRY(family, &global_font_list, Family, entry)
{
if(!strcmpiW(family->FamilyName, name))
return family;
@@ -1166,6 +1166,14 @@ static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset,
return err;
}
+static void free_face(Face *face)
+{
+ HeapFree(GetProcessHeap(), 0, face->file);
+ HeapFree(GetProcessHeap(), 0, face->StyleName);
+ HeapFree(GetProcessHeap(), 0, face->cached_enum_data);
+ HeapFree(GetProcessHeap(), 0, face);
+}
+
static inline int TestStyles(DWORD flags, DWORD styles)
{
return (flags & styles) == styles;
@@ -1205,9 +1213,121 @@ static void AddFaceToFamily(Face *face, Family *family)
list_add_before( entry, &face->entry );
}
+static int add_face_to_family(Family *family, Face *face, const WCHAR *fake_family)
+{
+ struct list *face_ptr;
+ Face *global_face;
+
+ face_ptr = list_head(&family->faces);
+ while (face_ptr)
+ {
+ global_face = LIST_ENTRY(face_ptr, Face, entry);
+ face_ptr = list_next(&family->faces, face_ptr);
+
+ if (!strcmpiW(global_face->StyleName, face->StyleName) &&
+ (face->scalable || (face->size.y_ppem == global_face->size.y_ppem && !memcmp(&face->fs, &global_face->fs, sizeof(face->fs)))))
+ {
+ TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
+ debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
+ global_face->font_version, face->font_version);
+
+ if (fake_family)
+ {
+ TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
+ return 0;
+ }
+ if (face->font_version <= global_face->font_version)
+ {
+ TRACE("Original font is newer so skipping this one\n");
+ return 0;
+ }
+
+ TRACE("Replacing original with this one\n");
+ list_remove(&global_face->entry);
+ free_face(global_face);
+ break;
+ }
+ }
+
+ TRACE("Adding face %s to family %s\n", debugstr_w(face->StyleName),
+ debugstr_w(family->FamilyName));
+
+ list_remove(&face->entry);
+ AddFaceToFamily(face, family);
+ return 1;
+}
+
+static int add_family_to_global_list(Family *family, const WCHAR *fake_family)
+{
+ struct list *family_ptr, *face_ptr, *face_ptr_safe;
+ Family *global_family = NULL;
+ int num_faces_added = 0;
+
+ LIST_FOR_EACH(family_ptr, &global_font_list)
+ {
+ global_family = LIST_ENTRY(family_ptr, Family, entry);
+ if(!strcmpiW(global_family->FamilyName, family->FamilyName))
+ break;
+ global_family = NULL;
+ }
+
+ if (!global_family)
+ {
+ TRACE("Adding new family %s\n", debugstr_w(family->FamilyName));
+ list_remove(&family->entry);
+ list_add_tail(&global_font_list, &family->entry);
+ global_family = family;
+ }
+
+ LIST_FOR_EACH_SAFE(face_ptr, face_ptr_safe, &family->faces)
+ {
+ Face *face = LIST_ENTRY(face_ptr, Face, entry);
+
+ if (add_face_to_family(global_family, face, fake_family))
+ {
+ num_faces_added++;
+
+ if (!(face->fs.fsCsb[0] & FS_SYMBOL))
+ have_installed_roman_font = TRUE;
+ }
+ }
+
+ return num_faces_added;
+}
+
+static int add_font_to_global_list(const struct list *font_list,
+ const WCHAR *fake_family, const WCHAR *target_family)
+{
+ struct list *family_ptr, *family_ptr_safe;
+ int num_faces_added = 0;
+
+ LIST_FOR_EACH_SAFE(family_ptr, family_ptr_safe, font_list)
+ {
+ Family *family = LIST_ENTRY(family_ptr, Family, entry);
+
+ if (target_family && strcmpiW(family->FamilyName, target_family) != 0)
+ {
+ TRACE("Incorrect family name for replacement\n");
+ continue;
+ }
+
+ if (fake_family)
+ {
+ HeapFree(GetProcessHeap(), 0, family->FamilyName);
+ family->FamilyName = strdupW(fake_family);
+ }
+
+ num_faces_added += add_family_to_global_list(family, fake_family);
+ }
+
+ return num_faces_added;
+}
+
#define ADDFONT_EXTERNAL_FONT 0x01
#define ADDFONT_FORCE_BITMAP 0x02
-static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
+
+static int load_font(const char *file, void *font_data_ptr, DWORD font_data_size,
+ struct list *font_list, DWORD flags)
{
FT_Face ft_face;
TT_OS2 *pOS2;
@@ -1216,7 +1336,6 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
DWORD len;
Family *family;
Face *face;
- struct list *family_elem_ptr, *face_elem_ptr;
FT_Error err;
FT_Long face_index = 0, num_faces;
#ifdef HAVE_FREETYPE_FTWINFNT_H
@@ -1239,7 +1358,7 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
for(cursor = mac_list; *cursor; cursor++)
{
had_one = TRUE;
- AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
+ load_font(*cursor, NULL, 0, font_list, flags);
HeapFree(GetProcessHeap(), 0, *cursor);
}
HeapFree(GetProcessHeap(), 0, mac_list);
@@ -1250,8 +1369,6 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
#endif /* HAVE_CARBON_CARBON_H */
do {
- char *family_name = fake_family;
-
if (file)
{
TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
@@ -1320,23 +1437,6 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
return 0;
}
- if (target_family)
- {
- localised_family = get_familyname(ft_face);
- if (localised_family && strcmpiW(localised_family,target_family)!=0)
- {
- TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
- HeapFree(GetProcessHeap(), 0, localised_family);
- num_faces = ft_face->num_faces;
- pFT_Done_Face(ft_face);
- continue;
- }
- HeapFree(GetProcessHeap(), 0, localised_family);
- }
-
- if(!family_name)
- family_name = ft_face->family_name;
-
bitmap_num = 0;
do {
My_FT_Bitmap_Size *size = NULL;
@@ -1345,41 +1445,32 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
if(!FT_IS_SCALABLE(ft_face))
size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
- len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
+ len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
-
- localised_family = NULL;
- if(!fake_family) {
- localised_family = get_familyname(ft_face);
- if(localised_family && !strcmpiW(localised_family, english_family)) {
- HeapFree(GetProcessHeap(), 0, localised_family);
- localised_family = NULL;
- }
- }
+ MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, english_family, len);
- family = NULL;
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
- family = LIST_ENTRY(family_elem_ptr, Family, entry);
- if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
- break;
- family = NULL;
+ localised_family = get_familyname(ft_face);
+ if (localised_family && !strcmpiW(localised_family, english_family))
+ {
+ HeapFree(GetProcessHeap(), 0, localised_family);
+ localised_family = NULL;
}
- if(!family) {
- family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
- family->FamilyName = strdupW(localised_family ? localised_family : english_family);
- list_init(&family->faces);
- list_add_tail(&font_list, &family->entry);
-
- if(localised_family) {
- FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
- subst->from.name = strdupW(english_family);
- subst->from.charset = -1;
- subst->to.name = strdupW(localised_family);
- subst->to.charset = -1;
- add_font_subst(&font_subst_list, subst, 0);
- }
+
+ family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
+ family->FamilyName = strdupW(localised_family ? localised_family : english_family);
+ list_init(&family->faces);
+ list_add_tail(font_list, &family->entry);
+
+ if (localised_family)
+ {
+ FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
+ subst->from.name = strdupW(english_family);
+ subst->from.charset = -1;
+ subst->to.name = strdupW(localised_family);
+ subst->to.charset = -1;
+ add_font_subst(&font_subst_list, subst, 0);
}
+
HeapFree(GetProcessHeap(), 0, localised_family);
HeapFree(GetProcessHeap(), 0, english_family);
@@ -1417,38 +1508,6 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
internal_leading = winfnt_header.internal_leading;
}
#endif
-
- face_elem_ptr = list_head(&family->faces);
- while(face_elem_ptr) {
- face = LIST_ENTRY(face_elem_ptr, Face, entry);
- face_elem_ptr = list_next(&family->faces, face_elem_ptr);
- if(!strcmpiW(face->StyleName, StyleW) &&
- (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
- TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
- debugstr_w(family->FamilyName), debugstr_w(StyleW),
- face->font_version, pHeader ? pHeader->Font_Revision : 0);
-
- if(fake_family) {
- TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
- HeapFree(GetProcessHeap(), 0, StyleW);
- pFT_Done_Face(ft_face);
- return 1;
- }
- if(!pHeader || pHeader->Font_Revision <= face->font_version) {
- TRACE("Original font is newer so skipping this one\n");
- HeapFree(GetProcessHeap(), 0, StyleW);
- pFT_Done_Face(ft_face);
- return 1;
- } else {
- TRACE("Replacing original with this one\n");
- list_remove(&face->entry);
- HeapFree(GetProcessHeap(), 0, face->file);
- HeapFree(GetProcessHeap(), 0, face->StyleName);
- HeapFree(GetProcessHeap(), 0, face);
- break;
- }
- }
- }
face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
face->cached_enum_data = NULL;
face->StyleName = StyleW;
@@ -1523,33 +1582,47 @@ static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_
}
}
- if (!(face->fs.fsCsb[0] & FS_SYMBOL))
- have_installed_roman_font = TRUE;
-
AddFaceToFamily(face, family);
} while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
num_faces = ft_face->num_faces;
pFT_Done_Face(ft_face);
- TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
- debugstr_w(StyleW));
+ TRACE("Loaded font %s %s (%ld of %ld)\n", debugstr_w(family->FamilyName),
+ debugstr_w(StyleW), face_index + 1, num_faces);
} while(num_faces > ++face_index);
return num_faces;
}
-static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
+static void free_font_list(const struct list *font_list)
{
- return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
+ struct list *family_ptr, *family_ptr_safe;
+
+ LIST_FOR_EACH_SAFE(family_ptr, family_ptr_safe, font_list)
+ {
+ struct list *face_ptr, *face_ptr_safe;
+ Family *family = LIST_ENTRY(family_ptr, Family, entry);
+
+ LIST_FOR_EACH_SAFE(face_ptr, face_ptr_safe, &family->faces)
+ {
+ Face *face = LIST_ENTRY(face_ptr, Face, entry);
+ list_remove(&face->entry);
+ free_face(face);
+ }
+
+ list_remove(&family->entry);
+ HeapFree(GetProcessHeap(), 0, family->FamilyName);
+ HeapFree(GetProcessHeap(), 0, family);
+ }
}
-static void DumpFontList(void)
+static void dump_font_list(const struct list *font_list)
{
Family *family;
Face *face;
struct list *family_elem_ptr, *face_elem_ptr;
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
TRACE("Family: %s\n", debugstr_w(family->FamilyName));
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
@@ -1563,6 +1636,41 @@ static void DumpFontList(void)
return;
}
+static void DumpFontList(void)
+{
+ dump_font_list(&global_font_list);
+}
+
+static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, const WCHAR *fake_family, const WCHAR *target_family, DWORD flags)
+{
+ struct list font_list;
+ INT ret;
+
+ list_init(&font_list);
+
+ if (!load_font(file, font_data_ptr, font_data_size, &font_list, flags))
+ {
+ free_font_list(&font_list);
+ return 0;
+ }
+
+ dump_font_list(&font_list);
+
+ ret = add_font_to_global_list(&font_list, fake_family, target_family);
+ if (!ret)
+ {
+ free_font_list(&font_list);
+ /* no added fonts means that the font is already loaded */
+ ret = 1;
+ }
+ return ret;
+}
+
+static INT AddFontFileToList(const char *file, const WCHAR *fake_family, const WCHAR *target_family, DWORD flags)
+{
+ return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
+}
+
/***********************************************************
* The replacement list is a way to map an entire font
* family onto another family. For example adding
@@ -1584,7 +1692,6 @@ static void LoadReplaceList(void)
Family *family;
Face *face;
struct list *family_elem_ptr, *face_elem_ptr;
- CHAR familyA[400];
/* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
@@ -1602,19 +1709,18 @@ static void LoadReplaceList(void)
&dlen) == ERROR_SUCCESS) {
TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
/* "NewName"="Oldname" */
- WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
/* Find the old family and hence all of the font files
in that family */
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
if(!strcmpiW(family->FamilyName, data)) {
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
face = LIST_ENTRY(face_elem_ptr, Face, entry);
TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
- debugstr_w(face->StyleName), familyA);
+ debugstr_w(face->StyleName), debugstr_w(value));
/* Now add a new entry with the new family name */
- AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
+ AddFontToList(face->file, face->font_data_ptr, face->font_data_size, value, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
}
break;
}
@@ -1988,7 +2094,7 @@ static void update_reg_entries(void)
/* enumerate the fonts and add external ones to the two keys */
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
@@ -3524,7 +3630,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
}
TRACE("not in cache\n");
- if(list_empty(&font_list)) /* No fonts installed */
+ if(list_empty(&global_font_list)) /* No fonts installed */
{
TRACE("No fonts installed\n");
LeaveCriticalSection( &freetype_cs );
@@ -3596,7 +3702,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
where we'll either use the charset of the current ansi codepage
or if that's unavailable the first charset that the font supports.
*/
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
if (!strcmpiW(family->FamilyName, FaceName) ||
(psub && !strcmpiW(family->FamilyName, psub->to.name)))
@@ -3661,7 +3767,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
strcpyW(lf.lfFaceName, defSans);
else
strcpyW(lf.lfFaceName, defSans);
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
@@ -3674,7 +3780,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
}
last_resort_family = NULL;
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
face = LIST_ENTRY(face_elem_ptr, Face, entry);
@@ -3693,7 +3799,7 @@ GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
goto found;
}
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
face = LIST_ENTRY(face_elem_ptr, Face, entry);
@@ -4096,7 +4202,7 @@ DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
plf = &lf;
}
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
LIST_FOR_EACH(face_elem_ptr, &family->faces) {
@@ -4140,7 +4246,7 @@ DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
}
}
} else {
- LIST_FOR_EACH(family_elem_ptr, &font_list) {
+ LIST_FOR_EACH(family_elem_ptr, &global_font_list) {
family = LIST_ENTRY(family_elem_ptr, Family, entry);
face_elem_ptr = list_head(&family->faces);
face = LIST_ENTRY(face_elem_ptr, Face, entry);
--
1.7.0.6
More information about the wine-patches
mailing list