summaryrefslogtreecommitdiff
path: root/pango/pangowin32-fontcache.c
diff options
context:
space:
mode:
authorTor Lillqvist <tml@iki.fi>2000-07-15 01:06:08 +0000
committerTor Lillqvist <tml@src.gnome.org>2000-07-15 01:06:08 +0000
commit932fe1e3da39b3d8febfca65f6ca5312f0397ed1 (patch)
treed5583d408b5af1a4ed899a78937fc76ed46c442d /pango/pangowin32-fontcache.c
parentd4fb416c99d0066aafed26306a421a7bd22289e3 (diff)
downloadpango-932fe1e3da39b3d8febfca65f6ca5312f0397ed1.tar.gz
pango/pangowin32.h pango/pangowin32-private.h pango/pangowin32-fontcache.c
2000-07-15 Tor Lillqvist <tml@iki.fi> * pango/pangowin32.h * pango/pangowin32-private.h * pango/pangowin32-fontcache.c * pango/pangowin32-fontmap.c * modules/basic/basic-win32.c * examples/viewer-win32.c * examples/pangowin32.aliases: New files. Start of a Win32 implementation. Does not work yet. * configure.in: Chek for dirent.h and unistd.h. * pango/pango-utils.h * pango/pango-utils.c (pango_get_sysconf_subdirectory, pango_get_lib_subdirectory): New functions, for better portability, to enable installation-time choice of directory (on Windows) instead of compile-time. Use these instead of SYSCONFDIR "/pango" and LIBDIR "/pango". (pango_split_file_list): Fix comment, the function splits on searchpath separators, not commas. Use G_SEARCHPATH_SEPARATOR_S for portability. Don't try to expand '~' as home directory on Windows. (read_config): Use pango_get_sysconf_subdirectory(). * pango/modules.c (read_modules): Use pango_get_sysconf_subdirectory(). Don't crash if a module file cannot be opened. * pango/querymodules.c: Include config.h Conditionalize inclusion of dirent.h and unistd.h. Use platform-specific shared library extension. Use pango_get_lib_subdirectory().
Diffstat (limited to 'pango/pangowin32-fontcache.c')
-rw-r--r--pango/pangowin32-fontcache.c341
1 files changed, 341 insertions, 0 deletions
diff --git a/pango/pangowin32-fontcache.c b/pango/pangowin32-fontcache.c
new file mode 100644
index 00000000..40d6eae3
--- /dev/null
+++ b/pango/pangowin32-fontcache.c
@@ -0,0 +1,341 @@
+/* Pango
+ * pangowin32-fontcache.c: Cache of HFONTs by LOGFONT
+ *
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include "pangowin32-private.h"
+
+/* Font cache
+ */
+
+/* Number of fonts to retain after they are not otherwise referenced.
+ */
+#define CACHE_SIZE 16
+
+typedef struct _CacheEntry CacheEntry;
+
+struct _PangoWin32FontCache
+{
+ GHashTable *forward;
+ GHashTable *back;
+
+ GList *mru;
+ GList *mru_tail;
+ int mru_count;
+};
+
+struct _CacheEntry
+{
+ LOGFONT logfont;
+ HFONT hfont;
+
+ gint ref_count;
+ GList *mru;
+};
+
+static void
+free_cache_entry (LOGFONT *logfont,
+ CacheEntry *entry,
+ PangoWin32FontCache *cache)
+{
+ DeleteObject (entry->hfont);
+
+ g_free (entry);
+}
+
+/**
+ * pango_win32_font_cache_free:
+ * @cache: a #PangoWin32FontCache
+ *
+ * Free a #PangoWin32FontCache and all associated memory. All fonts loaded
+ * through this font cache will be freed along with the cache.
+ **/
+void
+pango_win32_font_cache_free (PangoWin32FontCache *cache)
+{
+ g_return_if_fail (cache != NULL);
+
+ g_hash_table_foreach (cache->forward, (GHFunc)free_cache_entry, cache);
+
+ g_hash_table_destroy (cache->forward);
+ g_hash_table_destroy (cache->back);
+
+ g_list_free (cache->mru);
+}
+
+static guint
+logfont_hash (gconstpointer v)
+{
+ const LOGFONT *lfp = v;
+
+ return g_str_hash (lfp->lfFaceName) +
+ lfp->lfItalic +
+ lfp->lfWeight/10 +
+ lfp->lfOrientation +
+ lfp->lfHeight * 10;
+}
+
+static gint
+logfont_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ const LOGFONT *lfp1 = v1, *lfp2 = v2;
+
+ return (strcmp (lfp1->lfFaceName, lfp2->lfFaceName) == 0
+ && lfp1->lfPitchAndFamily == lfp2->lfPitchAndFamily
+ && lfp1->lfStrikeOut == lfp2->lfStrikeOut
+ && lfp1->lfUnderline == lfp2->lfUnderline
+ && lfp1->lfItalic == lfp2->lfItalic
+ && lfp1->lfWeight == lfp2->lfWeight
+ && lfp1->lfOrientation == lfp2->lfOrientation
+ && lfp1->lfEscapement == lfp2->lfEscapement
+ && lfp1->lfWidth == lfp2->lfWidth
+ && lfp1->lfHeight == lfp2->lfHeight);
+}
+
+/**
+ * pango_win32_font_cache_new:
+ *
+ * Create a font cache.
+ *
+ * Return value: The new font cache. This must be freed with
+ * pango_win32_font_cache_free().
+ **/
+PangoWin32FontCache *
+pango_win32_font_cache_new (void)
+{
+ PangoWin32FontCache *cache;
+
+ cache = g_new (PangoWin32FontCache, 1);
+
+ cache->forward = g_hash_table_new (logfont_hash, logfont_equal);
+ cache->back = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ cache->mru = NULL;
+ cache->mru_tail = NULL;
+ cache->mru_count = 0;
+
+ return cache;
+}
+
+static void
+cache_entry_unref (PangoWin32FontCache *cache,
+ CacheEntry *entry)
+{
+ entry->ref_count--;
+ if (entry->ref_count == 0)
+ {
+ g_hash_table_remove (cache->forward, &entry->logfont);
+ g_hash_table_remove (cache->back, entry->hfont);
+
+ free_cache_entry (NULL, entry, cache);
+ }
+}
+
+/**
+ * pango_win32_font_cache_load:
+ * @cache: a #PangoWin32FontCache
+ * @logfont: a pointer to a LOGFONT structure describing the font to load.
+ *
+ * Create a #HFONT from a LOGFONT. The
+ * result may be newly loaded, or it may have been previously
+ * stored
+ *
+ * Return value: The font structure, or %NULL if the font could
+ * not be loaded. In order to free this structure, you must call
+ * pango_win32_font_cache_unload().
+ **/
+HFONT
+pango_win32_font_cache_load (PangoWin32FontCache *cache,
+ const LOGFONT *lfp)
+{
+ CacheEntry *entry;
+ LOGFONT lf;
+ HFONT hfont;
+ int tries;
+
+ g_return_val_if_fail (cache != NULL, NULL);
+ g_return_val_if_fail (lfp != NULL, NULL);
+
+ entry = g_hash_table_lookup (cache->forward, lfp);
+
+ if (entry)
+ {
+ entry->ref_count++;
+ }
+ else
+ {
+ lf = *lfp;
+ for (tries = 0; ; tries++)
+ {
+#if 0
+ PANGO_NOTE
+ (g_print
+ ("... trying CreateFontIndirect, "
+ "height=%d,width=%d,escapement=%d,orientation=%d,"
+ "weight=%d,%s%s%s"
+ "charset=%d,outprecision=%d,clipprecision=%d,"
+ "quality=%d,pitchandfamily=%#.02x,facename=\"%s\")\n",
+ lf.lfHeight, lf.lfWidth, lf.lfEscapement, lf.lfOrientation,
+ lf.lfWeight, (lf.lfItalic ? "italic," : ""),
+ (lf.lfUnderline ? "underline," : ""),
+ (lf.lfStrikeOut ? "strikeout," : ""),
+ lf.lfCharSet, lf.lfOutPrecision, lf.lfClipPrecision,
+ lf.lfQuality, lf.lfPitchAndFamily, lf.lfFaceName));
+#endif
+ hfont = CreateFontIndirect (&lf);
+
+ if (hfont != NULL)
+ break;
+
+ /* If we fail, try some similar fonts often found on Windows. */
+ if (tries == 0)
+ {
+ if (g_strcasecmp (lf.lfFaceName, "helvetica") == 0)
+ strcpy (lf.lfFaceName, "arial");
+ else if (g_strcasecmp (lf.lfFaceName, "new century schoolbook") == 0)
+ strcpy (lf.lfFaceName, "century schoolbook");
+ else if (g_strcasecmp (lf.lfFaceName, "courier") == 0)
+ strcpy (lf.lfFaceName, "courier new");
+ else if (g_strcasecmp (lf.lfFaceName, "lucida") == 0)
+ strcpy (lf.lfFaceName, "lucida sans unicode");
+ else if (g_strcasecmp (lf.lfFaceName, "lucidatypewriter") == 0)
+ strcpy (lf.lfFaceName, "lucida console");
+ else if (g_strcasecmp (lf.lfFaceName, "times") == 0)
+ strcpy (lf.lfFaceName, "times new roman");
+ }
+ else if (tries == 1)
+ {
+ if (g_strcasecmp (lf.lfFaceName, "courier") == 0)
+ {
+ strcpy (lf.lfFaceName, "");
+ lf.lfPitchAndFamily |= FF_MODERN;
+ }
+ else if (g_strcasecmp (lf.lfFaceName, "times new roman") == 0)
+ {
+ strcpy (lf.lfFaceName, "");
+ lf.lfPitchAndFamily |= FF_ROMAN;
+ }
+ else if (g_strcasecmp (lf.lfFaceName, "helvetica") == 0
+ || g_strcasecmp (lf.lfFaceName, "lucida") == 0)
+ {
+ strcpy (lf.lfFaceName, "");
+ lf.lfPitchAndFamily |= FF_SWISS;
+ }
+ else
+ {
+ strcpy (lf.lfFaceName, "");
+ lf.lfPitchAndFamily = (lf.lfPitchAndFamily & 0x0F) | FF_DONTCARE;
+ }
+ }
+ else
+ break;
+ tries++;
+ }
+
+ if (!hfont)
+ return NULL;
+
+ entry = g_new (CacheEntry, 1);
+
+ entry->logfont = lf;
+ entry->hfont = hfont;
+
+ entry->ref_count = 1;
+ entry->mru = NULL;
+
+ g_hash_table_insert (cache->forward, &entry->logfont, entry);
+ g_hash_table_insert (cache->back, entry->hfont, entry);
+ }
+
+ if (entry->mru)
+ {
+ if (cache->mru_count > 1 && entry->mru->prev)
+ {
+ /* Move to the head of the mru list */
+
+ if (entry->mru == cache->mru_tail)
+ {
+ cache->mru_tail = cache->mru_tail->prev;
+ cache->mru_tail->next = NULL;
+ }
+ else
+ {
+ entry->mru->prev->next = entry->mru->next;
+ entry->mru->next->prev = entry->mru->prev;
+ }
+
+ entry->mru->next = cache->mru;
+ entry->mru->prev = NULL;
+ cache->mru->prev = entry->mru;
+ cache->mru = entry->mru;
+ }
+ }
+ else
+ {
+ entry->ref_count++;
+
+ /* Insert into the mru list */
+
+ if (cache->mru_count == CACHE_SIZE)
+ {
+ CacheEntry *old_entry = cache->mru_tail->data;
+
+ cache->mru_tail = cache->mru_tail->prev;
+ cache->mru_tail->next = NULL;
+
+ g_list_free_1 (old_entry->mru);
+ old_entry->mru = NULL;
+ cache_entry_unref (cache, old_entry);
+ }
+ else
+ cache->mru_count++;
+
+ cache->mru = g_list_prepend (cache->mru, entry);
+ if (!cache->mru_tail)
+ cache->mru_tail = cache->mru;
+ entry->mru = cache->mru;
+ }
+
+ return entry->hfont;
+}
+
+/**
+ * pango_win32_font_cache_unload:
+ * @cache: a #PangoWin32FontCache
+ * @hfont: the HFONT to unload
+ *
+ * Free a font structure previously loaded with pango_win32_font_cache_load()
+ **/
+void
+pango_win32_font_cache_unload (PangoWin32FontCache *cache,
+ HFONT hfont)
+{
+ CacheEntry *entry;
+
+ g_return_if_fail (cache != NULL);
+ g_return_if_fail (hfont != NULL);
+
+ entry = g_hash_table_lookup (cache->back, hfont);
+ g_return_if_fail (entry != NULL);
+
+ cache_entry_unref (cache, entry);
+}