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