Fix #135098 and #322510.
authorTor Lillqvist <tml@novell.com>
Fri, 10 Feb 2006 12:57:02 +0000 (12:57 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Fri, 10 Feb 2006 12:57:02 +0000 (12:57 +0000)
2006-02-10  Tor Lillqvist  <tml@novell.com>

Fix #135098 and #322510.

* pango/pangowin32-fontmap.c (case_insensitive_hash)
(case_insensitive_equal): New helper functions for string hashing
based on ASCII case insensitivity.
(logfont_nosize_hash): Use case_insensitive_hash().
(logfont_nosize_equal): Use case_insensitive_equal().
(pango_win32_font_map_init): Use the case-insensitive functions
for the PangoWin32FontMap::families hash table.
(pango_win32_font_map_load_font): Consequently we don't need to
lowercase the name before looking up from the hash table.
(get_family_name): Constify parameter.
(get_family_name_lowercase): Not needed any longer.
(pango_win32_pango_font_description_from_logfont): New public
function. Code moved from pango_win32_insert_font(). Use family
name as such, don't lowercase it.
(pango_win32_insert_font): Use the above new function. Don't
bother looking for superfluos copies of the font entry as that
shouldn't ever happen. We have pruned out fonts that differ only
in charset already earlier.

* pango/pangowin32.h: Declare
pango_win32_pango_font_description_from_logfont().

ChangeLog
pango/pangowin32-fontmap.c
pango/pangowin32.h

index 20e2c35..cc11d32 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2006-02-10  Tor Lillqvist  <tml@novell.com>
+
+       Fix #135098 and #322510.
+
+       * pango/pangowin32-fontmap.c (case_insensitive_hash)
+       (case_insensitive_equal): New helper functions for string hashing
+       based on ASCII case insensitivity..
+       (logfont_nosize_hash): Use case_insensitive_hash().
+       (logfont_nosize_equal): Use case_insensitive_equal().
+       (pango_win32_font_map_init): Use the case-insensitive functions
+       for the PangoWin32FontMap::families hash table.
+       (pango_win32_font_map_load_font): Consequently we don't need to
+       lowercase the name before looking up from the hash table.
+       (get_family_name): Constify parameter.
+       (get_family_name_lowercase): Not needed any longer.
+       (pango_win32_pango_font_description_from_logfont): New public
+       function. Code moved from pango_win32_insert_font(). Use family
+       name as such, don't lowercase it.
+       (pango_win32_insert_font): Use the above new function. Don't
+       bother looking for superfluos copies of the font entry as that
+       shouldn't ever happen. We have pruned out fonts that differ only
+       in charset already earlier.
+
+       * pango/pangowin32.h: Declare
+       pango_win32_pango_font_description_from_logfont().
+
 2006-02-09  Behdad Esfahbod  <behdad@gnome.org>
 
        Bug 330602 – pango_parse_weight
index ca81ea0..3f70063 100644 (file)
@@ -92,31 +92,47 @@ static PangoWin32FontMap *default_fontmap = NULL;
 
 G_DEFINE_TYPE (PangoWin32FontMap, pango_win32_font_map, PANGO_TYPE_FONT_MAP)
 
+#define TOLOWER(c) \
+  (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
+
+static guint
+case_insensitive_hash (const char *key)
+{
+  const char *p = key;
+  guint h = TOLOWER (*p);
+
+  if (h)
+    {
+      for (p += 1; *p != '\0'; p++)
+       h = (h << 5) - h + TOLOWER (*p);
+    }
+
+  return h;
+}
+
+static gboolean
+case_insensitive_equal (const char *key1,
+                       const char *key2)
+{
+  return (g_ascii_strcasecmp (key1, key2) == 0);
+}
+
 /* A hash function for LOGFONTs that takes into consideration only
  * those fields that indicate a specific .ttf file is in use:
  * lfFaceName, lfItalic and lfWeight. Dunno how correct this is.
  */
-
 static guint
-logfont_nosize_hash (gconstpointer v)
+logfont_nosize_hash (const LOGFONT *lfp)
 {
-  const LOGFONT *lfp = v;
-  gchar *face = g_ascii_strdown (lfp->lfFaceName, -1);
-  guint result = g_str_hash (face) + lfp->lfItalic + lfp->lfWeight;
-
-  g_free (face);
-
-  return result;
+  return case_insensitive_hash (lfp->lfFaceName) + lfp->lfItalic + lfp->lfWeight;
 }
 
 /* Ditto comparison function */
 static gboolean
-logfont_nosize_equal (gconstpointer v1,
-                     gconstpointer v2)
+logfont_nosize_equal (const LOGFONT *lfp1,
+                     const LOGFONT *lfp2)
 {
-  const LOGFONT *lfp1 = v1, *lfp2 = v2;
-
-  return (g_ascii_strcasecmp (lfp1->lfFaceName, lfp2->lfFaceName) == 0
+  return (case_insensitive_equal (lfp1->lfFaceName, lfp2->lfFaceName)
          && lfp1->lfItalic == lfp2->lfItalic
          && lfp1->lfWeight == lfp2->lfWeight);
 }
@@ -165,9 +181,10 @@ pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
 {
   LOGFONT logfont;
 
-  win32fontmap->families = g_hash_table_new (g_str_hash, g_str_equal);
+  win32fontmap->families = g_hash_table_new ((GHashFunc) case_insensitive_hash,
+                                            (GEqualFunc) case_insensitive_equal);
   win32fontmap->size_infos =
-    g_hash_table_new (logfont_nosize_hash, logfont_nosize_equal);
+    g_hash_table_new ((GHashFunc) logfont_nosize_hash, (GEqualFunc) logfont_nosize_equal);
   win32fontmap->n_fonts = 0;
   
   win32fontmap->font_cache = pango_win32_font_cache_new ();
@@ -401,15 +418,13 @@ pango_win32_font_map_load_font (PangoFontMap               *fontmap,
   PangoWin32Family *win32family;
   PangoFont *result = NULL;
   GSList *tmp_list;
-  gchar *name;
 
   g_return_val_if_fail (description != NULL, NULL);
   
-  name = g_ascii_strdown (pango_font_description_get_family (description), -1);
-
-  PING(("name=%s", name));
+  PING(("name=%s", pango_font_description_get_family (description)));
 
-  win32family = g_hash_table_lookup (win32fontmap->families, name);
+  win32family = g_hash_table_lookup (win32fontmap->families,
+                                    pango_font_description_get_family (description));
   if (win32family)
     {
       PangoWin32Face *best_match = NULL;
@@ -436,7 +451,6 @@ pango_win32_font_map_load_font (PangoFontMap               *fontmap,
        PING(("no best match!"));
     }
 
-  g_free (name);
   return result;
 }
 
@@ -482,7 +496,7 @@ pango_win32_font_map_real_find_font (PangoWin32FontMap          *win32fontmap,
 }
 
 static gchar *
-get_family_name (LOGFONT *lfp)
+get_family_name (const LOGFONT *lfp)
 {
   HFONT hfont;
   HFONT oldhfont;
@@ -605,14 +619,72 @@ get_family_name (LOGFONT *lfp)
   return g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
 }
 
-static gchar *
-get_family_name_lowercase (LOGFONT *lfp)
+/**
+ * pango_win32_pango_font_description_from_logfont:
+ * @lfp: pointer to a LOGFONT
+ *
+ * Creates a #PangoFontDescription from a LOGFONT.
+ *
+ * The face name, italicness and weight fields in the LOGFONT are used
+ * to set up the resulting #PangoFontDescription. If the face name in
+ * the LOGFONT contains non-ASCII characters the font is temporarily
+ * loaded (using CreateFontIndirect) and an ASCII (usually English)
+ * name for it is looked up from the font name tables in the font
+ * data. If that doesn't work, the face name is converted from the
+ * system codepage to UTF-8 and that is used.
+ *
+ * Return value: a new #PangoFontDescription that should be freed with
+ * pango_font_desciption_free() when no longer needed.
+ */
+PangoFontDescription *
+pango_win32_pango_font_description_from_logfont (const LOGFONT *lfp)
 {
-  gchar *family = get_family_name (lfp);
-  gchar *lower = g_ascii_strdown (family, -1);
+  PangoFontDescription *description;
+  gchar *family;
+  PangoStyle style;
+  PangoVariant variant;
+  PangoWeight weight;
+  PangoStretch stretch;
+
+  family = get_family_name (lfp);
+
+  if (!lfp->lfItalic)
+    style = PANGO_STYLE_NORMAL;
+  else
+    style = PANGO_STYLE_ITALIC;
+
+  variant = PANGO_VARIANT_NORMAL;
+  
+  /* The PangoWeight values PANGO_WEIGHT_* map exactly do Windows FW_*
+   * values.  Is this on purpose? Quantize the weight to exact
+   * PANGO_WEIGHT_* values. Is this a good idea?
+   */
+  if (lfp->lfWeight == FW_DONTCARE)
+    weight = PANGO_WEIGHT_NORMAL;
+  else if (lfp->lfWeight <= (FW_ULTRALIGHT + FW_LIGHT) / 2)
+    weight = PANGO_WEIGHT_ULTRALIGHT;
+  else if (lfp->lfWeight <= (FW_LIGHT + FW_NORMAL) / 2)
+    weight = PANGO_WEIGHT_LIGHT;
+  else if (lfp->lfWeight <= (FW_NORMAL + FW_BOLD) / 2)
+    weight = PANGO_WEIGHT_NORMAL;
+  else if (lfp->lfWeight <= (FW_BOLD + FW_ULTRABOLD) / 2)
+    weight = PANGO_WEIGHT_BOLD;
+  else if (lfp->lfWeight <= (FW_ULTRABOLD + FW_HEAVY) / 2)
+    weight = PANGO_WEIGHT_ULTRABOLD;
+  else
+    weight = PANGO_WEIGHT_HEAVY;
+
+  /* XXX No idea how to figure out the stretch */
+  stretch = PANGO_STRETCH_NORMAL;
+  
+  description = pango_font_description_new ();
+  pango_font_description_set_family (description, family);
+  pango_font_description_set_style (description, style);
+  pango_font_description_set_weight (description, weight);
+  pango_font_description_set_stretch (description, stretch);
+  pango_font_description_set_variant (description, variant);
 
-  g_free (family);
-  return lower;
+  return description;
 }
 
 /* This inserts the given font into the size_infos table. If a SizeInfo
@@ -625,15 +697,9 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
                         LOGFONT           *lfp)
 {
   LOGFONT *lfp2 = NULL;
-  PangoFontDescription *description;
-  gchar *family_name;
   PangoWin32Family *font_family;
   PangoWin32Face *win32face;
   PangoWin32SizeInfo *size_info;
-  PangoStyle style;
-  PangoVariant variant;
-  PangoWeight weight;
-  PangoStretch stretch;
   GSList *tmp_list;
   gint i;
 
@@ -677,7 +743,10 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
              rover->lfOrientation == lfp->lfOrientation &&
              rover->lfUnderline == lfp->lfUnderline &&
              rover->lfStrikeOut == lfp->lfStrikeOut)
-           return;
+           {
+             PING(("already have it"));
+             return;
+           }
          
          tmp_list = tmp_list->next;
        }
@@ -693,68 +762,9 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
   
   PING(("g_slist_length(size_info->logfonts)=%d", g_slist_length(size_info->logfonts)));
 
-  family_name = get_family_name_lowercase (lfp);
-
-  /* Convert the LOGFONT into a PangoFontDescription
-   */
-  if (!lfp2->lfItalic)
-    style = PANGO_STYLE_NORMAL;
-  else
-    style = PANGO_STYLE_ITALIC;
-
-  variant = PANGO_VARIANT_NORMAL;
-  
-  /* The PangoWeight values PANGO_WEIGHT_* map exactly do Windows FW_*
-   * values.  Is this on purpose? Quantize the weight to exact
-   * PANGO_WEIGHT_* values. Is this a good idea?
-   */
-  if (lfp2->lfWeight == FW_DONTCARE)
-    weight = PANGO_WEIGHT_NORMAL;
-  else if (lfp2->lfWeight <= (FW_ULTRALIGHT + FW_LIGHT) / 2)
-    weight = PANGO_WEIGHT_ULTRALIGHT;
-  else if (lfp2->lfWeight <= (FW_LIGHT + FW_NORMAL) / 2)
-    weight = PANGO_WEIGHT_LIGHT;
-  else if (lfp2->lfWeight <= (FW_NORMAL + FW_BOLD) / 2)
-    weight = PANGO_WEIGHT_NORMAL;
-  else if (lfp2->lfWeight <= (FW_BOLD + FW_ULTRABOLD) / 2)
-    weight = PANGO_WEIGHT_BOLD;
-  else if (lfp2->lfWeight <= (FW_ULTRABOLD + FW_HEAVY) / 2)
-    weight = PANGO_WEIGHT_ULTRABOLD;
-  else
-    weight = PANGO_WEIGHT_HEAVY;
-
-  /* XXX No idea how to figure out the stretch */
-  stretch = PANGO_STRETCH_NORMAL;
-
-  font_family = pango_win32_get_font_family (win32fontmap, family_name);
-  g_free (family_name);
-
-  tmp_list = font_family->font_entries;
-  while (tmp_list)
-    {
-      win32face = tmp_list->data;
-
-      if (pango_font_description_get_style (win32face->description) == style &&
-         pango_font_description_get_weight (win32face->description) == weight &&
-         pango_font_description_get_stretch (win32face->description) == stretch &&
-         pango_font_description_get_variant (win32face->description) == variant)
-       {
-         PING(("returning early"));
-         return;
-       }
-
-      tmp_list = tmp_list->next;
-    }
-
-  description = pango_font_description_new ();
-  pango_font_description_set_family_static (description, font_family->family_name);
-  pango_font_description_set_style (description, style);
-  pango_font_description_set_weight (description, weight);
-  pango_font_description_set_stretch (description, stretch);
-  pango_font_description_set_variant (description, variant);
-
   win32face = g_object_new (PANGO_WIN32_TYPE_FACE, NULL);
-  win32face->description = description;
+  win32face->description = pango_win32_pango_font_description_from_logfont (lfp2);
+
   win32face->cached_fonts = NULL;
   
   for (i = 0; i < PANGO_WIN32_N_COVERAGES; i++)
@@ -762,7 +772,13 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
   win32face->logfont = *lfp;
   win32face->cmap_format = 0;
   win32face->cmap = NULL;
+
+  font_family =
+    pango_win32_get_font_family (win32fontmap,
+                                pango_font_description_get_family (win32face->description));
   font_family->font_entries = g_slist_append (font_family->font_entries, win32face);
+  PING(("g_slist_length(font_family->font_entries)=%d", g_slist_length(font_family->font_entries)));
+
   win32fontmap->n_fonts++;
 
 #if 1 /* Thought pango.aliases would make this code unnecessary, but no. */
index 6f025d7..dc1aef1 100644 (file)
@@ -106,6 +106,8 @@ PangoWin32FontCache *pango_win32_font_map_get_font_cache (PangoFontMap       *fo
 
 LOGFONT             *pango_win32_font_logfont            (PangoFont          *font);
 
+PangoFontDescription *pango_win32_pango_font_description_from_logfont (const LOGFONT *lfp);
+
 G_END_DECLS
 
 #endif /* __PANGOWIN32_H__ */