diff options
author | Tor Lillqvist <tml@iki.fi> | 2000-07-15 01:06:08 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 2000-07-15 01:06:08 +0000 |
commit | 932fe1e3da39b3d8febfca65f6ca5312f0397ed1 (patch) | |
tree | d5583d408b5af1a4ed899a78937fc76ed46c442d /pango | |
parent | d4fb416c99d0066aafed26306a421a7bd22289e3 (diff) | |
download | pango-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')
-rw-r--r-- | pango/makefile.mingw | 67 | ||||
-rw-r--r-- | pango/modules.c | 14 | ||||
-rw-r--r-- | pango/pango-utils.c | 94 | ||||
-rw-r--r-- | pango/pango-utils.h | 13 | ||||
-rw-r--r-- | pango/pangowin32-fontcache.c | 341 | ||||
-rw-r--r-- | pango/pangowin32-fontmap.c | 1781 | ||||
-rw-r--r-- | pango/pangowin32-private.h | 91 | ||||
-rw-r--r-- | pango/pangowin32.c | 1465 | ||||
-rw-r--r-- | pango/pangowin32.h | 187 | ||||
-rw-r--r-- | pango/querymodules.c | 18 |
10 files changed, 4057 insertions, 14 deletions
diff --git a/pango/makefile.mingw b/pango/makefile.mingw new file mode 100644 index 00000000..e32f72f0 --- /dev/null +++ b/pango/makefile.mingw @@ -0,0 +1,67 @@ +PANGO_VER = 0.12 + +TOP = ../.. + +include $(TOP)/build/win32/make.mingw + +OPTIMIZE = -g + +INCLUDES = -I .. -I . +DEFINES = +DEPCFLAGS = $(GLIB_CFLAGS) $(LIBICONV_CFLAGS) $(FRIBIDI_CFLAGS) + +all : \ + ../config.h \ + pango-$(PANGO_VER).dll \ + pangowin32-$(PANGO_VER).dll \ + pango-querymodules.exe + +PANGO_OBJS = \ + break.o \ + fonts.o \ + glyphstring.o \ + mapping.o \ + modules.o \ + module-defs.o \ + pango-attributes.o \ + pango-context.o \ + pango-coverage.o \ + pango-fontmap.o \ + pango-item.o \ + pango-layout.o \ + pango-utils.o \ + reorder-items.o \ + shape.o + +PANGOWIN32_OBJS = \ + pangowin32.o \ + pangowin32-fontcache.o \ + pangowin32-fontmap.o + +PANGO_QUERYMODULES_OBJS = \ + querymodules.o + +../config.h : ../config.h.win32 + cp $< $@ + +module-defs.c : module-defs.c.win32 + cp $< $@ + +pango-$(PANGO_VER).dll : $(PANGO_OBJS) pango.def + $(GLIB)/build-dll pango $(PANGO_VER) pango.def $(PANGO_OBJS) $(GLIB_LIBS) $(LIBICONV_LIBS) $(FRIBIDI_LIBS) + +pangowin32-$(PANGO_VER).dll : $(PANGOWIN32_OBJS) pangowin32.def + $(GLIB)/build-dll pangowin32 $(PANGO_VER) pangowin32.def $(PANGOWIN32_OBJS) -L . -lpango-$(PANGO_VER) $(GLIB_LIBS) $(FRIBIDI_LIBS) -lgdi32 + +pango-querymodules.exe : $(PANGO_QUERYMODULES_OBJS) pango-$(PANGO_VER).dll pangowin32-$(PANGO_VER).dll + $(CC) -o $@ $(PANGO_QUERYMODULES_OBJS) -L . -lpango-$(PANGO_VER) $(GLIB_LIBS) + +test1.exe : test1.o pango-$(PANGO_VER).dll pangowin32-$(PANGO_VER).dll + $(CC) -o $@ $(CFLAGS) test1.o -L . -lpango-$(PANGO_VER) -lpangowin32-$(PANGO_VER) $(GLIB_LIBS) $(FRIBIDI_LIBS) -lgdi32 + +test2.exe : test2.o + $(CC) -o $@ $(CFLAGS) test2.o -lgdi32 + +test3.exe : test3.o + $(CC) -o $@ $(CFLAGS) test3.o -lgdi32 + diff --git a/pango/modules.c b/pango/modules.c index b7572aac..cad34866 100644 --- a/pango/modules.c +++ b/pango/modules.c @@ -19,6 +19,8 @@ * Boston, MA 02111-1307, USA. */ +#include "config.h" + #include <ctype.h> #include <stdio.h> #include <string.h> @@ -316,7 +318,9 @@ read_modules (void) int n; if (!file_str) - file_str = g_strdup (SYSCONFDIR "/pango/pango.modules"); + file_str = g_strconcat (pango_get_sysconf_subdirectory (), + G_DIR_SEPARATOR_S "pango.modules", + NULL); files = pango_split_file_list (file_str); @@ -329,9 +333,11 @@ read_modules (void) module_file = fopen (files[n], "r"); if (!module_file) g_warning ("Error opening module file '%s': %s\n", files[n], g_strerror (errno)); - - process_module_file(module_file); - fclose(module_file); + else + { + process_module_file(module_file); + fclose(module_file); + } } g_strfreev (files); diff --git a/pango/pango-utils.c b/pango/pango-utils.c index 786ae07c..c267a692 100644 --- a/pango/pango-utils.c +++ b/pango/pango-utils.c @@ -33,6 +33,13 @@ # define getc_unlocked(f) getc(f) #endif /* !HAVE_FLOCKFILE */ +#ifdef G_OS_WIN32 + +#define STRICT +#include <windows.h> + +#endif + /** * pango_trim_string: * @str: a string @@ -62,8 +69,8 @@ pango_trim_string (const char *str) * pango_split_file_list: * @str: a comma separated list of filenames * - * Split a comma-separated list of files, stripping white space - * and subsituting ~/ with $HOME/ + * Split a G_SEARCHPATH_SEPARATOR-separated list of files, stripping + * white space and subsituting ~/ with $HOME/ * * Return value: a list of strings to be freed with g_strfreev() **/ @@ -74,7 +81,7 @@ pango_split_file_list (const char *str) int j; char **files; - files = g_strsplit (str, ":", -1); + files = g_strsplit (str, G_SEARCHPATH_SEPARATOR_S, -1); while (files[i]) { @@ -93,14 +100,20 @@ pango_split_file_list (const char *str) continue; } - +#ifndef G_OS_WIN32 + /* '~' is a quite normal and common character in file names on + * Windows, especially in the 8.3 versions of long file names, which + * still occur and then. Also, few Windows user are aware of the + * Unix shell convention that '~' stands for the home directory, + * even if they happen to have a home directory. + */ if (file[0] == '~' && file[1] == G_DIR_SEPARATOR) { char *tmp = g_strconcat (g_get_home_dir(), file + 1, NULL); g_free (file); file = tmp; } - +#endif g_free (files[i]); files[i] = file; @@ -539,14 +552,25 @@ read_config () if (!config_hash) { char *filename; + char *home; config_hash = g_hash_table_new (g_str_hash, g_str_equal); - read_config_file (SYSCONFDIR "/" "pango/pangorc", FALSE); - - filename = g_strconcat (g_get_home_dir (), "/.pangorc", NULL); + filename = g_strconcat (pango_get_sysconf_subdirectory (), + G_DIR_SEPARATOR_S "pangorc", + NULL); read_config_file (filename, FALSE); g_free (filename); + home = g_get_home_dir (); + if (home && *home) + { + filename = g_strconcat (home, + G_DIR_SEPARATOR_S ".pangorc", + NULL); + read_config_file (filename, FALSE); + g_free (filename); + } + filename = g_getenv ("PANGO_RC_FILE"); if (filename) read_config_file (filename, TRUE); @@ -573,3 +597,57 @@ pango_config_key_get (const char *key) return g_strdup (g_hash_table_lookup (config_hash, key)); } + +char * +pango_get_sysconf_subdirectory (void) +{ +#ifdef G_OS_WIN32 + + /* On Windows we don't hardcode any paths (SYSCONFDIR) in the DLL, + * but rely on an installation program to store the installation + * directory in the registry. If no installation program has been + * used, punt and assume the Pango directory is %WINDIR%\Pango. + */ + + static gboolean been_here = FALSE; + static gchar pango_sysconf_dir[200]; + gchar win_dir[100]; + HKEY reg_key = NULL; + DWORD type; + DWORD nbytes = sizeof (pango_sysconf_dir); + + if (been_here) + return pango_sysconf_dir; + + been_here = TRUE; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\GNU\\Pango", 0, + KEY_QUERY_VALUE, ®_key) != ERROR_SUCCESS + || RegQueryValueEx (reg_key, "InstallationDirectory", 0, + &type, pango_sysconf_dir, &nbytes) != ERROR_SUCCESS + || type != REG_SZ) + { + /* Uh oh. Use %WinDir%\Pango */ + GetWindowsDirectory (win_dir, sizeof (win_dir)); + sprintf (pango_sysconf_dir, "%s\\pango", win_dir); + } + + if (reg_key != NULL) + RegCloseKey (reg_key); + + return pango_sysconf_dir; + +#else + return SYSCONFDIR "/pango"; +#endif +} + +char * +pango_get_lib_subdirectory (void) +{ +#ifdef G_OS_WIN32 + return pango_get_sysconf_subdirectory (); +#else + return LIBDIR "/pango"; +#endif +} diff --git a/pango/pango-utils.h b/pango/pango-utils.h index fe4f638d..1c8dfcaa 100644 --- a/pango/pango-utils.h +++ b/pango/pango-utils.h @@ -38,3 +38,16 @@ gboolean pango_scan_int (const char **pos, char * pango_config_key_get (const char *key); +/* On Unix, return the name of the "pango" subdirectory of SYSCONFDIR + * (which is set at compile time). On Win32, return the Pango + * installation directory (which is set at installation time, and + * stored in the registry). The returned string should not be + * g_free'd. + */ +char * pango_get_sysconf_subdirectory (void); + +/* Ditto for LIBDIR/pango. On Win32, use the same Pango + * installation directory. This returned string should not be + * g_free'd either. + */ +char * pango_get_lib_subdirectory (void); 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); +} diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c new file mode 100644 index 00000000..67d4129d --- /dev/null +++ b/pango/pangowin32-fontmap.c @@ -0,0 +1,1781 @@ +/* Pango + * pangowin32-fontmap.c: Font handling + * + * 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 "config.h" + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "pango-fontmap.h" +#include "pango-utils.h" +#include "pangowin32-private.h" + +#define PANGO_TYPE_WIN32_FONT_MAP (pango_win32_font_map_get_type ()) +#define PANGO_WIN32_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_WIN32_FONT_MAP, PangoWin32FontMap)) +#define PANGO_WIN32_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_WIN32_FONT_MAP, PangoWin32FontMapClass)) +#define PANGO_WIN32_IS_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_WIN32_FONT_MAP)) +#define PANGO_WIN32_IS_FONT_MAP_CLASS(klass)(G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_WIN32_FONT_MAP)) +#define PANGO_WIN32_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_WIN32_FONT_MAP, PangoWin32FontMapClass)) + +typedef struct _PangoWin32FamilyEntry PangoWin32FamilyEntry; +typedef struct _PangoWin32FontMap PangoWin32FontMap; +typedef struct _PangoWin32FontMapClass PangoWin32FontMapClass; +typedef struct _PangoWin32SizeInfo PangoWin32SizeInfo; + +/* Number of freed fonts */ +#define MAX_FREED_FONTS 16 + +struct _PangoWin32FontMap +{ + PangoFontMap parent_instance; + + PangoWin32FontCache *font_cache; + GQueue *freed_fonts; + + GHashTable *families; + GHashTable *size_infos; + + int n_fonts; + + double resolution; /* (points / pixel) * PANGO_SCALE */ +}; + +struct _PangoWin32FontMapClass +{ + PangoFontMapClass parent_class; +}; + +struct _PangoWin32FamilyEntry +{ + char *family_name; + GSList *font_entries; +}; + +struct _PangoWin32FontEntry +{ + LOGFONT *lfp; + int n_fonts; + PangoFontDescription description; + PangoCoverage *coverage; + + GSList *cached_fonts; +}; + +struct _PangoWin32SizeInfo +{ + FONTSIGNATURE signature; + GSList *logfonts; +}; + +const struct { + const gchar *text; + PangoStretch value; +} stretches_map[] = { + { "normal", PANGO_STRETCH_NORMAL }, + { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED }, + { "condensed", PANGO_STRETCH_CONDENSED }, +}; + +static GType pango_win32_font_map_get_type (void); +static void pango_win32_font_map_init (PangoWin32FontMap *fontmap); +static void pango_win32_font_map_class_init (PangoWin32FontMapClass *class); + +static void pango_win32_font_map_finalize (GObject *object); +static PangoFont *pango_win32_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *description); +static void pango_win32_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs); +static void pango_win32_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families); + +static void pango_win32_fontmap_cache_clear (PangoWin32FontMap *win32fontmap); +static void pango_win32_font_map_read_aliases (PangoWin32FontMap *win32fontmap); + +static void pango_win32_insert_font (PangoWin32FontMap *fontmap, + LOGFONT *lfp); + +static PangoFontClass *parent_class; /* Parent class structure for PangoWin32FontMap */ + +static GType +pango_win32_font_map_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (PangoWin32FontMapClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) pango_win32_font_map_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PangoWin32FontMap), + 0, /* n_preallocs */ + (GInstanceInitFunc) pango_win32_font_map_init, + }; + + object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, + "PangoWin32FontMap", + &object_info); + } + + return object_type; +} + +/* A hash function for LOGFONTs that takes into consideration + * only those fields that indicate a specific .ttf file is in + * use. Dunno how correct this is. + */ + +static guint +logfont_nosize_hash (gconstpointer v) +{ + const LOGFONT *lfp = v; + + return g_str_hash (lfp->lfFaceName) + + lfp->lfItalic + + lfp->lfWeight; +} + +/* Ditto comparison function */ +static gboolean +logfont_nosize_equal (gconstpointer v1, + gconstpointer v2) +{ + const LOGFONT *lfp1 = v1, *lfp2 = v2; + + return (strcmp (lfp1->lfFaceName, lfp2->lfFaceName) == 0 + && lfp1->lfItalic == lfp2->lfItalic + && lfp1->lfWeight == lfp2->lfWeight); +} + +static void +pango_win32_font_map_init (PangoWin32FontMap *win32fontmap) +{ + win32fontmap->families = g_hash_table_new (g_str_hash, g_str_equal); + win32fontmap->size_infos = g_hash_table_new (logfont_nosize_hash, logfont_nosize_equal); + win32fontmap->n_fonts = 0; +} + +static void +pango_win32_font_map_class_init (PangoWin32FontMapClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontMapClass *font_map_class = PANGO_FONT_MAP_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + + object_class->finalize = pango_win32_font_map_finalize; + font_map_class->load_font = pango_win32_font_map_load_font; + font_map_class->list_fonts = pango_win32_font_map_list_fonts; + font_map_class->list_families = pango_win32_font_map_list_families; + + if (pango_win32_hdc == NULL) + pango_win32_hdc = CreateDC ("DISPLAY", NULL, NULL, NULL); +} + +static PangoWin32FontMap *fontmap = NULL; + +static int CALLBACK +pango_win32_inner_enum_proc (LOGFONT *lfp, + TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + pango_win32_insert_font (fontmap, lfp); + + return 1; +} + +static int CALLBACK +pango_win32_enum_proc (LOGFONT *lfp, + TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + LOGFONT lf; + + if (fontType != TRUETYPE_FONTTYPE) + return 1; + + lf = *lfp; + + EnumFontFamiliesEx (pango_win32_hdc, &lf, pango_win32_inner_enum_proc, lParam, 0); + + return 1; +} + +PangoFontMap * +pango_win32_font_map_for_display (void) +{ + LOGFONT logfont; + int screen; + + /* Make sure that the type system is initialized */ + g_type_init(); + + if (fontmap != NULL) + return PANGO_FONT_MAP (fontmap); + + fontmap = (PangoWin32FontMap *)g_type_create_instance (PANGO_TYPE_WIN32_FONT_MAP); + + fontmap->font_cache = pango_win32_font_cache_new (); + fontmap->freed_fonts = g_queue_new (); + + memset (&logfont, 0, sizeof (logfont)); + logfont.lfCharSet = DEFAULT_CHARSET; + EnumFontFamiliesEx (pango_win32_hdc, &logfont, pango_win32_enum_proc, 0, 0); + + pango_win32_font_map_read_aliases (fontmap); + + fontmap->resolution = 0; /* ??? */ + + return PANGO_FONT_MAP (fontmap); +} + +/** + * pango_win32_shutdown_display: + * + * Free cached resources. + **/ +void +pango_win32_shutdown_display (void) +{ + GList *tmp_list; + + pango_win32_fontmap_cache_clear (fontmap); + g_object_unref (G_OBJECT (fontmap)); + + return; +} + +static void +pango_win32_font_map_finalize (GObject *object) +{ + PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (object); + + g_list_foreach (win32fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); + g_queue_free (win32fontmap->freed_fonts); + + pango_win32_font_cache_free (win32fontmap->font_cache); + + /* ??? */ +} + +typedef struct +{ + int n_found; + PangoFontDescription **descs; +} ListFontsInfo; + +static void +list_fonts_foreach (gpointer key, gpointer value, gpointer user_data) +{ + PangoWin32FamilyEntry *entry = value; + ListFontsInfo *info = user_data; + GSList *tmp_list = entry->font_entries; + + while (tmp_list) + { + PangoWin32FontEntry *font_entry = tmp_list->data; + + info->descs[info->n_found++] = pango_font_description_copy (&font_entry->description); + tmp_list = tmp_list->next; + } +} + +static void +pango_win32_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs) +{ + PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)fontmap; + ListFontsInfo info; + + if (!n_descs) + return; + + if (family) + { + PangoWin32FamilyEntry *entry = g_hash_table_lookup (win32fontmap->families, family); + if (entry) + { + *n_descs = g_slist_length (entry->font_entries); + if (descs) + { + *descs = g_new (PangoFontDescription *, *n_descs); + + info.descs = *descs; + info.n_found = 0; + + list_fonts_foreach ((gpointer)family, (gpointer)entry, &info); + } + } + else + { + *n_descs = 0; + if (descs) + *descs = NULL; + } + } + else + { + *n_descs = win32fontmap->n_fonts; + if (descs) + { + *descs = g_new (PangoFontDescription *, win32fontmap->n_fonts); + + info.descs = *descs; + info.n_found = 0; + + g_hash_table_foreach (win32fontmap->families, list_fonts_foreach, &info); + } + } +} + +static void +list_families_foreach (gpointer key, gpointer value, gpointer user_data) +{ + GSList **list = user_data; + + *list = g_slist_prepend (*list, key); +} + +static void +pango_win32_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families) +{ + GSList *family_list = NULL; + GSList *tmp_list; + PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)fontmap; + + if (!n_families) + return; + + g_hash_table_foreach (win32fontmap->families, list_families_foreach, &family_list); + + *n_families = g_slist_length (family_list); + + if (families) + { + int i = 0; + + *families = g_new (gchar *, *n_families); + + tmp_list = family_list; + while (tmp_list) + { + (*families)[i] = g_strdup (tmp_list->data); + i++; + tmp_list = tmp_list->next; + } + } + + g_slist_free (family_list); +} + +static PangoWin32FamilyEntry * +pango_win32_get_family_entry (PangoWin32FontMap *win32fontmap, + const char *family_name) +{ + PangoWin32FamilyEntry *family_entry = g_hash_table_lookup (win32fontmap->families, family_name); + if (!family_entry) + { + family_entry = g_new (PangoWin32FamilyEntry, 1); + family_entry->family_name = g_strdup (family_name); + family_entry->font_entries = NULL; + + g_hash_table_insert (win32fontmap->families, family_entry->family_name, family_entry); + } + + return family_entry; +} + +static PangoFont * +pango_win32_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *description) +{ + PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)fontmap; + PangoWin32FamilyEntry *family_entry; + PangoFont *result = NULL; + GSList *tmp_list; + gchar *name; + + g_return_val_if_fail (description != NULL, NULL); + g_return_val_if_fail (description->size > 0, NULL); + + name = g_strdup (description->family_name); + g_strdown (name); + + family_entry = g_hash_table_lookup (win32fontmap->families, name); + if (family_entry) + { + PangoWin32FontEntry *best_match = NULL; + + tmp_list = family_entry->font_entries; + while (tmp_list) + { + PangoWin32FontEntry *font_entry = tmp_list->data; + + if (font_entry->description.style == description->style && + font_entry->description.variant == description->variant && + font_entry->description.stretch == description->stretch) + { + int distance = abs(font_entry->description.weight - description->weight); + int old_distance = best_match ? abs(best_match->description.weight - description->weight) : G_MAXINT; + + if (distance < old_distance) + best_match = font_entry; + } + + tmp_list = tmp_list->next; + } + + if (best_match) + { + GSList *tmp_list = best_match->cached_fonts; + + while (tmp_list) + { + PangoWin32Font *win32font = tmp_list->data; + if (win32font->size == description->size) + { + result = (PangoFont *)win32font; + + g_object_ref (G_OBJECT (result)); + if (win32font->in_cache) + pango_win32_fontmap_cache_remove (fontmap, win32font); + + break; + } + tmp_list = tmp_list->next; + } + + if (!result) + { + PangoWin32Font *win32font; + + g_assert (best_match->lfp != NULL); + win32font = pango_win32_font_new (fontmap, best_match->lfp, best_match->n_fonts, description->size); + win32font->fontmap = fontmap; + win32font->entry = best_match; + best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, win32font); + + result = (PangoFont *)win32font; + } + } + } + + g_free (name); + return result; +} + +/* Similar to GNU libc's getline, but buffer is g_malloc'd */ +static size_t +pango_getline (char **lineptr, size_t *n, FILE *stream) +{ +#define EXPAND_CHUNK 16 + + int n_read = 0; + int result = -1; + + g_return_val_if_fail (lineptr != NULL, -1); + g_return_val_if_fail (n != NULL, -1); + g_return_val_if_fail (*lineptr != NULL || *n == 0, -1); + +#ifdef HAVE_FLOCKFILE + flockfile (stream); +#endif + + while (1) + { + int c; + +#ifdef HAVE_FLOCKFILE + c = getc_unlocked (stream); +#else + c = getc (stream); +#endif + + if (c == EOF) + { + if (n_read > 0) + { + result = n_read; + (*lineptr)[n_read] = '\0'; + } + break; + } + + if (n_read + 2 >= *n) + { + *n += EXPAND_CHUNK; + *lineptr = g_realloc (*lineptr, *n); + } + + (*lineptr)[n_read] = c; + n_read++; + + if (c == '\n' || c == '\r') + { + result = n_read; + (*lineptr)[n_read] = '\0'; + break; + } + } + +#ifdef HAVE_FLOCKFILE + funlockfile (stream); +#endif + + return n_read - 1; +} + +static int +find_tok (char **start, char **tok) +{ + char *p = *start; + + while (*p && (*p == ' ' || *p == '\t')) + p++; + + if (*p == 0 || *p == '\n' || *p == '\r') + return -1; + + if (*p == '"') + { + p++; + *tok = p; + + while (*p && *p != '"') + p++; + + if (*p != '"') + return -1; + + *start = p + 1; + return p - *tok; + } + else + { + *tok = p; + + while (*p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') + p++; + + *start = p; + return p - *tok; + } +} + +static gboolean +get_style (GString *str, PangoFontDescription *desc) +{ + if (str->len == 0) + return FALSE; + + switch (str->str[0]) + { + case 'n': + case 'N': + if (strncasecmp (str->str, "normal", str->len) == 0) + { + desc->style = PANGO_STYLE_NORMAL; + return TRUE; + } + break; + case 'i': + if (strncasecmp (str->str, "italic", str->len) == 0) + { + desc->style = PANGO_STYLE_ITALIC; + return TRUE; + } + break; + case 'o': + if (strncasecmp (str->str, "oblique", str->len) == 0) + { + desc->style = PANGO_STYLE_OBLIQUE; + return TRUE; + } + break; + } + g_warning ("Style must be normal, italic, or oblique"); + + return FALSE; +} + +static gboolean +get_variant (GString *str, PangoFontDescription *desc) +{ + if (str->len == 0) + return FALSE; + + switch (str->str[0]) + { + case 'n': + case 'N': + if (strncasecmp (str->str, "normal", str->len) == 0) + { + desc->variant = PANGO_VARIANT_NORMAL; + return TRUE; + } + break; + case 's': + case 'S': + if (strncasecmp (str->str, "small_caps", str->len) == 0) + { + desc->variant = PANGO_VARIANT_SMALL_CAPS; + return TRUE; + } + break; + } + + g_warning ("Variant must be normal, or small_caps"); + return FALSE; +} + +static gboolean +get_weight (GString *str, PangoFontDescription *desc) +{ + if (str->len == 0) + return FALSE; + + switch (str->str[0]) + { + case 'n': + case 'N': + if (strncasecmp (str->str, "normal", str->len) == 0) + { + desc->weight = PANGO_WEIGHT_NORMAL; + return TRUE; + } + break; + case 'b': + case 'B': + if (strncasecmp (str->str, "bold", str->len) == 0) + { + desc->weight = PANGO_WEIGHT_BOLD; + return TRUE; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + char *numstr, *end; + + numstr = g_strndup (str->str, str->len); + + desc->weight = strtol (numstr, &end, 0); + if (*end != '\0') + { + g_warning ("Cannot parse numerical weight '%s'", numstr); + g_free (numstr); + return FALSE; + } + + g_free (numstr); + return TRUE; + } + } + + g_warning ("Weight must be normal, bold, or an integer"); + return FALSE; +} + +static gboolean +get_stretch (GString *str, PangoFontDescription *desc) +{ + if (str->len == 0) + return FALSE; + + switch (str->str[0]) + { + case 'c': + case 'C': + if (strncasecmp (str->str, "condensed", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_CONDENSED; + return TRUE; + } + break; + case 'e': + case 'E': + if (strncasecmp (str->str, "extra_condensed", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_EXTRA_CONDENSED; + return TRUE; + } + if (strncasecmp (str->str, "extra_expanded", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_EXTRA_EXPANDED; + return TRUE; + } + if (strncasecmp (str->str, "expanded", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_EXPANDED; + return TRUE; + } + break; + case 'n': + case 'N': + if (strncasecmp (str->str, "normal", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_NORMAL; + return TRUE; + } + break; + case 's': + case 'S': + if (strncasecmp (str->str, "semi_condensed", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_SEMI_CONDENSED; + return TRUE; + } + if (strncasecmp (str->str, "semi_expanded", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_SEMI_EXPANDED; + return TRUE; + } + break; + case 'u': + case 'U': + if (strncasecmp (str->str, "ultra_condensed", str->len) == 0) + { + desc->stretch = PANGO_STRETCH_ULTRA_CONDENSED; + return TRUE; + } + if (strncasecmp (str->str, "ultra_expanded", str->len) == 0) + { + desc->variant = PANGO_STRETCH_ULTRA_EXPANDED; + return TRUE; + } + break; + } + + g_warning ("Stretch must be ultra_condensed, extra_condensed, condensed, semi_condensed, normal, semi_expanded, expanded, extra_expanded, or ultra_expanded"); + return FALSE; +} + +static gboolean +pango_win32_guess_subranges (UINT charset, + FONTSIGNATURE *fsp) +{ + gint i; + gboolean retval = FALSE; + + /* If the fsUsb bit array has at least one of the bits set, trust it */ + for (i = 0; i < PANGO_WIN32_U_LAST_PLUS_ONE; i++) + if (i != PANGO_WIN32_U_PRIVATE_USE_AREA && + (fsp->fsUsb[i/32] & (1 << (i % 32)))) + return FALSE; + + /* Otherwise, guess what subranges there should be in the font */ + fsp->fsUsb[0] = fsp->fsUsb[1] = fsp->fsUsb[2] = fsp->fsUsb[3] = 0; + + /* Set Unicode subrange bits based on code pages supported. + * This is mostly just guesswork. + */ + +#define check_cp(bit) (fsp->fsCsb[0] & (FS_##bit)) + +#define set_bit(bitno) (fsp->fsUsb[(PANGO_WIN32_U_##bitno)/32] |= (1 << ((PANGO_WIN32_U_##bitno) % 32))) + + if (check_cp(LATIN1)) + { + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (CURRENCY_SYMBOLS); + retval = TRUE; + } + if (check_cp (LATIN2)) + { + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (CURRENCY_SYMBOLS); + retval = TRUE; + } + if (check_cp (CYRILLIC)) + { + set_bit (BASIC_LATIN); + set_bit (CYRILLIC); + retval = TRUE; + } + if (check_cp (GREEK)) + { + set_bit (BASIC_LATIN); + set_bit (BASIC_GREEK); + retval = TRUE; + } + if (check_cp (TURKISH)) + { + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (CURRENCY_SYMBOLS); + retval = TRUE; + } + if (check_cp (HEBREW)) + { + set_bit (BASIC_LATIN); + set_bit (CURRENCY_SYMBOLS); + set_bit (BASIC_HEBREW); + set_bit (HEBREW_EXTENDED); + retval = TRUE; + } + if (check_cp (ARABIC)) + { + set_bit (BASIC_LATIN); + set_bit (CURRENCY_SYMBOLS); + set_bit (BASIC_ARABIC); + set_bit (ARABIC_EXTENDED); + retval = TRUE; + } + if (check_cp (BALTIC)) + { + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (CURRENCY_SYMBOLS); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + retval = TRUE; + } + if (check_cp (VIETNAMESE)) + { + /* ??? */ + set_bit (BASIC_LATIN); + retval = TRUE; + } + if (check_cp (THAI)) + { + set_bit (BASIC_LATIN); + set_bit (THAI); + retval = TRUE; + } + if (check_cp (JISJAPAN)) + { + /* Based on what's in the MS Gothic font */ + set_bit (BASIC_LATIN); + set_bit (CJK_SYMBOLS_AND_PUNCTUATION); + set_bit (HIRAGANA); + set_bit (KATAKANA); + set_bit (CJK_UNIFIED_IDEOGRAPHS); + set_bit (HALFWIDTH_AND_FULLWIDTH_FORMS); + retval = TRUE; + } + if (check_cp (CHINESESIMP)) + { + /* Based on what's in the MS Hei font */ + set_bit (BASIC_LATIN); + set_bit (HIRAGANA); + set_bit (KATAKANA); + set_bit (BOPOMOFO); + set_bit (CJK_UNIFIED_IDEOGRAPHS); + retval = TRUE; + } + if (check_cp (WANSUNG) + || check_cp (JOHAB)) /* ??? */ + { + /* Based on the GulimChe font. I wonder if all Korean fonts + * really support this large range of Unicode subranges? + */ + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (BASIC_GREEK); + set_bit (CYRILLIC); + set_bit (HANGUL_JAMO); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (CURRENCY_SYMBOLS); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (NUMBER_FORMS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (ENCLOSED_ALPHANUMERICS); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + set_bit (CJK_SYMBOLS_AND_PUNCTUATION); + set_bit (HIRAGANA); + set_bit (KATAKANA); + set_bit (HANGUL_COMPATIBILITY_JAMO); + set_bit (ENCLOSED_CJK); + set_bit (CJK_COMPATIBILITY_FORMS); + set_bit (HANGUL); + set_bit (CJK_UNIFIED_IDEOGRAPHS); + set_bit (CJK_COMPATIBILITY_IDEOGRAPHS); + set_bit (HALFWIDTH_AND_FULLWIDTH_FORMS); + retval = TRUE; + } + if (check_cp (CHINESETRAD)) + { + /* Based on the MingLiU font */ + set_bit (BASIC_LATIN); + set_bit (GENERAL_PUNCTUATION); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (CJK_SYMBOLS_AND_PUNCTUATION); + set_bit (BOPOMOFO); + set_bit (CJK_UNIFIED_IDEOGRAPHS); + set_bit (CJK_COMPATIBILITY_IDEOGRAPHS); + set_bit (SMALL_FORM_VARIANTS); + set_bit (HALFWIDTH_AND_FULLWIDTH_FORMS); + retval = TRUE; + } + if (check_cp (SYMBOL) || charset == MAC_CHARSET) + { + /* Non-Unicode encoding, I guess. Pretend it covers + * the single-byte range of values. + */ + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + retval = TRUE; + } + + if (retval) + return TRUE; + + /* Sigh. Not even any code page bits were set. Guess based on + * charset, then. These somewhat optimistic guesses are based on the + * table in Appendix M in the book "Developing ..." mentioned + * above. + */ + switch (charset) + { + case ANSI_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (COMBINING_DIACRITICAL_MARKS); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (CURRENCY_SYMBOLS); +#if 0 /* I find this too hard to believe... */ + set_bit (BASIC_GREEK); + set_bit (CYRILLIC); + set_bit (BASIC_HEBREW); + set_bit (HEBREW_EXTENDED); + set_bit (BASIC_ARABIC); + set_bit (ARABIC_EXTENDED); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (NUMBER_FORMS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (ENCLOSED_ALPHANUMERICS); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + set_bit (HIRAGANA); + set_bit (KATAKANA); + set_bit (BOPOMOFO); + set_bit (HANGUL_COMPATIBILITY_JAMO); + set_bit (CJK_MISCELLANEOUS); + set_bit (CJK_COMPATIBILITY); + set_bit (HANGUL); + set_bit (HANGUL_SUPPLEMENTARY_A); + set_bit (CJK_COMPATIBILITY_IDEOGRAPHS); + set_bit (ALPHABETIC_PRESENTATION_FORMS); + set_bit (SMALL_FORM_VARIANTS); + set_bit (ARABIC_PRESENTATION_FORMS_B); + set_bit (HALFWIDTH_AND_FULLWIDTH_FORMS); + set_bit (SPECIALS); +#endif + retval = TRUE; + break; + case SYMBOL_CHARSET: + /* Unggh */ + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + retval = TRUE; + break; + case SHIFTJIS_CHARSET: + case HANGEUL_CHARSET: + case GB2312_CHARSET: + case CHINESEBIG5_CHARSET: + case JOHAB_CHARSET: + /* The table really does claim these "locales" (it doesn't + * talk about charsets per se) cover the same Unicode + * subranges + */ + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS); + set_bit (BASIC_GREEK); + set_bit (CYRILLIC); + set_bit (HANGUL_JAMO); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (CURRENCY_SYMBOLS); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (NUMBER_FORMS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (ENCLOSED_ALPHANUMERICS); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + set_bit (CJK_SYMBOLS_AND_PUNCTUATION); + set_bit (HIRAGANA); + set_bit (KATAKANA); + set_bit (BOPOMOFO); + set_bit (HANGUL_COMPATIBILITY_JAMO); + set_bit (CJK_MISCELLANEOUS); + set_bit (CJK_COMPATIBILITY); + set_bit (HANGUL); + set_bit (HANGUL_SUPPLEMENTARY_A); + set_bit (CJK_UNIFIED_IDEOGRAPHS); + set_bit (CJK_COMPATIBILITY_IDEOGRAPHS); + set_bit (ALPHABETIC_PRESENTATION_FORMS); + set_bit (SMALL_FORM_VARIANTS); + set_bit (ARABIC_PRESENTATION_FORMS_B); + set_bit (SPECIALS); + retval = TRUE; + break; + case HEBREW_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (BASIC_HEBREW); + set_bit (HEBREW_EXTENDED); + set_bit (GENERAL_PUNCTUATION); + set_bit (LETTERLIKE_SYMBOLS); + retval = TRUE; + break; + case ARABIC_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (BASIC_GREEK); + set_bit (BASIC_ARABIC); + set_bit (ARABIC_EXTENDED); + set_bit (GENERAL_PUNCTUATION); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + set_bit (HALFWIDTH_AND_FULLWIDTH_FORMS); + retval = TRUE; + break; + case GREEK_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_B); + set_bit (BASIC_GREEK); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + retval = TRUE; + break; + case TURKISH_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (BASIC_GREEK); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (CURRENCY_SYMBOLS); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + retval = TRUE; + break; + case VIETNAMESE_CHARSET: + case THAI_CHARSET: + /* These are not in the table, so I have no idea */ + break; + case BALTIC_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (BASIC_GREEK); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (CURRENCY_SYMBOLS); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + retval = TRUE; + break; + case EASTEUROPE_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (LATIN_EXTENDED_A); + set_bit (LATIN_EXTENDED_B); + set_bit (SPACING_MODIFIER_LETTERS); + set_bit (BASIC_GREEK); + set_bit (GENERAL_PUNCTUATION); + set_bit (SUPERSCRIPTS_AND_SUBSCRIPTS); + set_bit (CURRENCY_SYMBOLS); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + retval = TRUE; + break; + case RUSSIAN_CHARSET: + set_bit (BASIC_LATIN); + set_bit (LATIN_1_SUPPLEMENT); + set_bit (CYRILLIC); + set_bit (GENERAL_PUNCTUATION); + set_bit (LETTERLIKE_SYMBOLS); + set_bit (ARROWS); + set_bit (MATHEMATICAL_OPERATORS); + set_bit (MISCELLANEOUS_TECHNICAL); + set_bit (BOX_DRAWING); + set_bit (BLOCK_ELEMENTS); + set_bit (GEOMETRIC_SHAPES); + set_bit (MISCELLANEOUS_SYMBOLS); + retval = TRUE; + break; + } +#undef check_cp +#undef set_bit + + return retval; +} + +static gboolean +pango_win32_setup_signature (PangoWin32FontMap *win32fontmap, + LOGFONT *lfp, + FONTSIGNATURE *sigp) +{ + LOGFONT logfont; + HFONT hfont; + HGDIOBJ oldfont; + int charset; + int i; + + logfont = *lfp; + logfont.lfHeight = 40; + hfont = pango_win32_font_cache_load (win32fontmap->font_cache, + &logfont); + if (!hfont) + { + g_warning ("font \"%s\" (%sweight:%d) not available", + (logfont.lfItalic ? "italic," : ""), + logfont.lfWeight, + logfont.lfFaceName); + return FALSE; + } + oldfont = SelectObject (pango_win32_hdc, hfont); + memset (sigp, 0, sizeof (*sigp)); + charset = GetTextCharsetInfo (pango_win32_hdc, sigp, 0); + SelectObject (pango_win32_hdc, oldfont); + pango_win32_guess_subranges (charset, sigp); + pango_win32_font_cache_unload (win32fontmap->font_cache, hfont); +} + +static void +pango_win32_font_map_read_alias_file (PangoWin32FontMap *win32fontmap, + const char *filename) +{ + PangoWin32FontEntry *font_entry = NULL; + FILE *infile; + char **faces; + char *buf = NULL; + int lineno = 0; + int charset; + int nfaces; + int i; + + infile = fopen (filename, "r"); + if (infile) + { + GString *line_buf = g_string_new (NULL); + GString *tmp_buf = g_string_new (NULL); + + while (pango_read_line (infile, line_buf)) + { + PangoWin32FamilyEntry *family_entry; + + const char *p = line_buf->str; + + lineno++; + + if (!pango_skip_space (&p)) + continue; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + font_entry = g_new (PangoWin32FontEntry, 1); + font_entry->description.family_name = g_strdup (tmp_buf->str); + g_strdown (font_entry->description.family_name); + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!get_style (tmp_buf, &font_entry->description)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!get_variant (tmp_buf, &font_entry->description)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!get_weight (tmp_buf, &font_entry->description)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!get_stretch (tmp_buf, &font_entry->description)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + /* Remove excess whitespace and check for complete fields */ + + faces = g_strsplit (tmp_buf->str, ",", -1); + nfaces = 0; + for (i=0; faces[i]; i++) + { + char *trimmed = pango_trim_string (faces[i]); + g_free (faces[i]); + faces[i] = trimmed; + nfaces++; + } + font_entry->lfp = g_new0 (LOGFONT, nfaces); + font_entry->n_fonts = nfaces; + for (i=0; i<nfaces; i++) + { + strcpy (font_entry->lfp[i].lfFaceName, faces[i]); + } + g_strfreev (faces); + + /* Insert the font entry into our structures */ + + family_entry = pango_win32_get_family_entry (win32fontmap, font_entry->description.family_name); + family_entry->font_entries = g_slist_prepend (family_entry->font_entries, font_entry); + win32fontmap->n_fonts++; + + g_free (font_entry->description.family_name); + font_entry->description.family_name = family_entry->family_name; + font_entry->cached_fonts = NULL; + font_entry->coverage = NULL; + } + + if (ferror (infile)) + g_warning ("Error reading '%s': %s", filename, g_strerror(errno)); + + goto out; + + error: + if (font_entry) + { + if (font_entry->lfp) + g_free (font_entry->lfp); + if (font_entry->description.family_name) + g_free (font_entry->description.family_name); + g_free (font_entry); + } + + g_warning ("Error parsing line %d of alias file '%s'", lineno, filename); + + out: + g_string_free (tmp_buf, TRUE); + g_string_free (line_buf, TRUE); + + fclose (infile); + } +} + +static void +pango_win32_font_map_read_aliases (PangoWin32FontMap *win32fontmap) +{ + char **files; + char *files_str = pango_config_key_get ("PangoWin32/AliasFiles"); + char *home; + char *tmp_str; + int n; + + if (!files_str) + { + home = g_get_home_dir (); + if (home && *home) + files_str = g_strconcat (home, "\\.pangowin32_aliases;", NULL); + + tmp_str = g_strconcat (files_str, pango_get_sysconf_subdirectory (), + "\\pangowin32.aliases", + NULL); + g_free (files_str); + files_str = tmp_str; + } + + files = pango_split_file_list (files_str); + + n = 0; + while (files[n]) + n++; + + while (n-- > 0) + pango_win32_font_map_read_alias_file (fontmap, files[n]); + + g_strfreev (files); + g_free (files_str); +} + +/* This inserts the given font into the SizeInfo table. + * If a SizeInfo already exists with the same typeface name, then the + * fontname is added to the SizeInfos list of fontnames, else a new SizeInfo + * is created and inserted in the table. + */ +static void +pango_win32_insert_font (PangoWin32FontMap *win32fontmap, + LOGFONT *lfp) +{ + LOGFONT *lfp2; + PangoFontDescription description; + GSList *tmp_list; + PangoWin32FamilyEntry *family_entry; + PangoWin32FontEntry *font_entry; + PangoWin32SizeInfo *size_info; + int i; + + description.size = 0; + + /* First insert the LOGFONT into the list of LOGFONTs for the typeface name + */ + size_info = g_hash_table_lookup (win32fontmap->size_infos, lfp); + if (!size_info) + { + size_info = g_new (PangoWin32SizeInfo, 1); + pango_win32_setup_signature (win32fontmap, lfp, &size_info->signature); + size_info->logfonts = NULL; + + g_hash_table_insert (win32fontmap->size_infos, lfp, size_info); + } + + lfp2 = g_new (LOGFONT, 1); + *lfp2 = *lfp; + size_info->logfonts = g_slist_prepend (size_info->logfonts, lfp2); + + /* Convert the LOGFONT into a PangoFontDescription */ + + description.family_name = g_strdup (lfp->lfFaceName); + g_strdown (description.family_name); + + if (!description.family_name[0]) + return; + + if (!lfp->lfItalic) + description.style = PANGO_STYLE_NORMAL; + else + description.style = PANGO_STYLE_ITALIC; + + description.variant = PANGO_VARIANT_NORMAL; + + /* The PangoWeight values PANGO_WEIGHT_* map exactly do Windows FW_* values. + * Is this on purpose? + */ + if (lfp->lfWeight == FW_DONTCARE) + description.weight = PANGO_WEIGHT_NORMAL; + else + description.weight = lfp->lfWeight; + + /* XXX No idea how to figure out the stretch */ + description.stretch = PANGO_STRETCH_NORMAL; + + family_entry = pango_win32_get_family_entry (win32fontmap, description.family_name); + + tmp_list = family_entry->font_entries; + while (tmp_list) + { + font_entry = tmp_list->data; + + if (font_entry->description.style == description.style && + font_entry->description.variant == description.variant && + font_entry->description.weight == description.weight && + font_entry->description.stretch == description.stretch) + return; + + tmp_list = tmp_list->next; + } + + font_entry = g_new (PangoWin32FontEntry, 1); + font_entry->description = description; + font_entry->description.family_name = family_entry->family_name; + font_entry->cached_fonts = NULL; + font_entry->coverage = NULL; + font_entry->lfp = g_new (LOGFONT, 1); + font_entry->n_fonts = 1; + *font_entry->lfp = *lfp; + g_strdown (font_entry->lfp->lfFaceName); + family_entry->font_entries = g_slist_append (family_entry->font_entries, font_entry); + win32fontmap->n_fonts++; +} + +/* Compare the tail of a to b */ +static gboolean +match_end (char *a, char *b) +{ + size_t len_a = strlen (a); + size_t len_b = strlen (b); + + if (len_b > len_a) + return FALSE; + else + return (strcmp (a + len_a - len_b, b) == 0); +} + +gboolean +pango_win32_logfont_has_subrange (PangoFontMap *fontmap, + LOGFONT *lfp, + PangoWin32UnicodeSubrange subrange) +{ + PangoWin32FontMap *win32fontmap; + PangoWin32SizeInfo *size_info; + + win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); + size_info = g_hash_table_lookup (win32fontmap->size_infos, lfp); + if (!size_info) + return FALSE; + + return size_info->signature.fsUsb[subrange/32] & (1 << subrange % 32); +} + +/* Given a LOGFONT and size, make a matching LOGFONT corresponding to + * an installed font. + */ +LOGFONT * +pango_win32_make_matching_logfont (PangoFontMap *fontmap, + LOGFONT *lfp, + int size) +{ + PangoWin32FontMap *win32fontmap; + GSList *tmp_list; + PangoWin32SizeInfo *size_info; + LOGFONT *closest_match = NULL; + LOGFONT *result = NULL; + gint match_distance = 0; + + win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); + + size_info = g_hash_table_lookup (win32fontmap->size_infos, lfp); + + if (!size_info) + return NULL; + + tmp_list = size_info->logfonts; + while (tmp_list) + { + LOGFONT *tmp_logfont = tmp_list->data; + int font_size = tmp_logfont->lfHeight; + + if (size != -1) + { + int new_distance = (font_size == 0) ? 0 : abs (font_size - size); + + if (!closest_match || + new_distance < match_distance || + (new_distance < PANGO_SCALE && font_size != 0)) + { + closest_match = tmp_logfont; + match_distance = new_distance; + } + } + + tmp_list = tmp_list->next; + } + + if (closest_match) + { + /* OK, we have a match; let's modify it to fit this size */ + + result = g_new (LOGFONT, 1); + result->lfHeight = (int)((double)size / win32fontmap->resolution + 0.5); + } + + return result; +} + +static void +free_coverages_foreach (gpointer key, + gpointer value, + gpointer data) +{ + pango_coverage_unref (value); +} + +PangoCoverage * +pango_win32_font_entry_get_coverage (PangoWin32FontEntry *entry, + PangoFont *font, + const char *lang) +{ + guint32 ch; + PangoMap *shape_map; + PangoCoverage *coverage; + PangoCoverage *result; + PangoCoverageLevel font_level; + PangoMapEntry *map_entry; + GHashTable *coverage_hash; + + if (entry) + if (entry->coverage) + { + pango_coverage_ref (entry->coverage); + return entry->coverage; + } + + result = pango_coverage_new (); + + coverage_hash = g_hash_table_new (g_str_hash, g_str_equal); + + shape_map = pango_win32_get_shaper_map (lang); + + for (ch = 0; ch < 65536; ch++) + { + map_entry = pango_map_get_entry (shape_map, ch); + if (map_entry->info) + { + coverage = g_hash_table_lookup (coverage_hash, map_entry->info->id); + if (!coverage) + { + PangoEngineShape *engine = (PangoEngineShape *)pango_map_get_engine (shape_map, ch); + coverage = engine->get_coverage (font, lang); + g_hash_table_insert (coverage_hash, map_entry->info->id, coverage); + } + + font_level = pango_coverage_get (coverage, ch); + if (font_level == PANGO_COVERAGE_EXACT && !map_entry->is_exact) + font_level = PANGO_COVERAGE_APPROXIMATE; + + if (font_level != PANGO_COVERAGE_NONE) + pango_coverage_set (result, ch, font_level); + } + } + + g_hash_table_foreach (coverage_hash, free_coverages_foreach, NULL); + g_hash_table_destroy (coverage_hash); + + if (entry) + { + entry->coverage = result; + pango_coverage_ref (result); + } + + return result; +} + +void +pango_win32_font_entry_remove (PangoWin32FontEntry *entry, + PangoFont *font) +{ + entry->cached_fonts = g_slist_remove (entry->cached_fonts, font); +} + +PangoWin32FontCache * +pango_win32_font_map_get_font_cache (PangoFontMap *font_map) +{ + g_return_val_if_fail (font_map != NULL, NULL); + g_return_val_if_fail (PANGO_WIN32_IS_FONT_MAP (font_map), NULL); + + return PANGO_WIN32_FONT_MAP (font_map)->font_cache; +} + +void +pango_win32_fontmap_cache_add (PangoFontMap *fontmap, + PangoWin32Font *win32font) +{ + PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); + + if (win32fontmap->freed_fonts->length == MAX_FREED_FONTS) + { + PangoWin32Font *old_font = g_queue_pop_tail (win32fontmap->freed_fonts); + g_object_unref (G_OBJECT (old_font)); + } + + g_object_ref (G_OBJECT (win32font)); + g_queue_push_head (win32fontmap->freed_fonts, win32font); + win32font->in_cache = TRUE; +} + +void +pango_win32_fontmap_cache_remove (PangoFontMap *fontmap, + PangoWin32Font *win32font) +{ + PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); + + GList *link = g_list_find (win32fontmap->freed_fonts->head, win32font); + if (link == win32fontmap->freed_fonts->tail) + { + win32fontmap->freed_fonts->tail = win32fontmap->freed_fonts->tail->prev; + if (win32fontmap->freed_fonts->tail) + win32fontmap->freed_fonts->tail->next = NULL; + } + + win32fontmap->freed_fonts->head = g_list_delete_link (win32fontmap->freed_fonts->head, link); + win32fontmap->freed_fonts->length--; + win32font->in_cache = FALSE; + + g_object_unref (G_OBJECT (win32font)); +} + +static void +pango_win32_fontmap_cache_clear (PangoWin32FontMap *win32fontmap) +{ + g_list_foreach (win32fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); + g_list_free (win32fontmap->freed_fonts->head); + win32fontmap->freed_fonts->head = NULL; + win32fontmap->freed_fonts->tail = NULL; + win32fontmap->freed_fonts->length = 0; +} + +static void +pango_win32_font_entry_dump (int indent, + PangoWin32FontEntry *font_entry) +{ + int i; + + printf ("%*sPangoWin32FontEntry@%p:\n" + "%*s lfp:\n", + indent, "", font_entry, + indent, ""); + + for (i=0; i<font_entry->n_fonts; i++) + printf ("%*s LOGFONT:%s\n", + indent, "", font_entry->lfp[i].lfFaceName); + + printf ("%*s description:\n" + "%*s family_name: %s\n" + "%*s style: %d\n" + "%*s variant: %d\n" + "%*s weight: %d\n" + "%*s stretch: %d\n" + "%*s coverage: %p\n", + indent, "", + indent, "", font_entry->description.family_name, + indent, "", font_entry->description.style, + indent, "", font_entry->description.variant, + indent, "", font_entry->description.weight, + indent, "", font_entry->description.stretch, + indent, "", font_entry->coverage); +} + +static void +pango_win32_family_entry_dump (int indent, + PangoWin32FamilyEntry *entry) +{ + GSList *tmp_list = entry->font_entries; + + printf ("%*sPangoWin32FamilyEntry@%p:\n" + "%*s family_name: %s\n" + "%*s font_entries:\n", + indent, "", entry, + indent, "", entry->family_name, + indent, ""); + + while (tmp_list) + { + PangoWin32FontEntry *font_entry = tmp_list->data; + + pango_win32_font_entry_dump (indent + 2, font_entry); + tmp_list = tmp_list->next; + } +} + +static void +dump_family (gpointer key, gpointer value, gpointer user_data) +{ + PangoWin32FamilyEntry *entry = value; + int indent = (int) user_data; + + pango_win32_family_entry_dump (indent, entry); +} + +void +pango_win32_fontmap_dump (int indent, + PangoFontMap *fontmap) +{ + PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); + + printf ("%*sPangoWin32FontMap@%p:\n", + indent, "", win32fontmap); + g_hash_table_foreach (win32fontmap->families, dump_family, (gpointer) (indent + 2)); +} diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h new file mode 100644 index 00000000..9d748798 --- /dev/null +++ b/pango/pangowin32-private.h @@ -0,0 +1,91 @@ +/* Pango + * pangowin32-private.h: + * + * Copyright (C) 1999 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. + */ + +#ifndef __PANGOWIN32_PRIVATE_H__ +#define __PANGOWIN32_PRIVATE_H__ + +#include "pango-modules.h" +#include "pangowin32.h" + +#ifndef FS_VIETNAMESE +#define FS_VIETNAMESE 0x100 +#endif + +#define PANGO_NOTE(x) x + +typedef struct _PangoWin32Font PangoWin32Font; +typedef struct _PangoWin32FontEntry PangoWin32FontEntry; +typedef struct _PangoWin32SubfontInfo PangoWin32SubfontInfo; + +struct _PangoWin32Font +{ + PangoFont font; + + LOGFONT *fonts; + int n_fonts; + int size; + + /* hash table mapping from Unicode subranges to array of PangoWin32Subfont + * ids, of length n_fonts + */ + GHashTable *subfonts_by_subrange; + + PangoWin32SubfontInfo **subfonts; + + int n_subfonts; + int max_subfonts; + + GSList *metrics_by_lang; + + PangoFontMap *fontmap; + /* If TRUE, font is in cache of recently unused fonts and not otherwise + * in use. + */ + gboolean in_cache; + + PangoWin32FontEntry *entry; /* Used to remove cached fonts */ +}; + +PangoWin32Font *pango_win32_font_new (PangoFontMap *fontmap, + const LOGFONT *lfp, + int n_fonts, + int size); +PangoMap * pango_win32_get_shaper_map (const char *lang); +gboolean pango_win32_logfont_has_subrange (PangoFontMap *fontmap, + LOGFONT *lfp, + PangoWin32UnicodeSubrange subrange); +LOGFONT * pango_win32_make_matching_logfont (PangoFontMap *fontmap, + LOGFONT *lfp, + int size); +PangoCoverage * pango_win32_font_entry_get_coverage (PangoWin32FontEntry *entry, + PangoFont *font, + const char *lang); +void pango_win32_font_entry_remove (PangoWin32FontEntry *entry, + PangoFont *font); + +void pango_win32_fontmap_cache_add (PangoFontMap *fontmap, + PangoWin32Font *xfont); +void pango_win32_fontmap_cache_remove (PangoFontMap *fontmap, + PangoWin32Font *xfont); + +extern HDC pango_win32_hdc; + +#endif /* __PANGOWIN32_PRIVATE_H__ */ diff --git a/pango/pangowin32.c b/pango/pangowin32.c new file mode 100644 index 00000000..38937184 --- /dev/null +++ b/pango/pangowin32.c @@ -0,0 +1,1465 @@ +/* Pango + * pangowin32.c: Routines for handling Windows fonts + * + * Copyright (C) 1999 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 "config.h" + +#include <string.h> +#include <stdlib.h> +#include <glib.h> + +#include <fribidi/fribidi.h> + +#include "pangowin32.h" +#include "pangowin32-private.h" + +#define PANGO_TYPE_WIN32_FONT (pango_win32_font_get_type ()) +#define PANGO_WIN32_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_WIN32_FONT, PangoWin32Font)) +#define PANGO_WIN32_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_WIN32_FONT, PangoWin32FontClass)) +#define PANGO_WIN32_IS_FONT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_WIN32_FONT)) +#define PANGO_WIN32_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_WIN32_FONT)) +#define PANGO_WIN32_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_WIN32_FONT, PangoWin32FontClass)) + +HDC pango_win32_hdc; + +static HBRUSH white_brush; + +typedef struct _PangoWin32FontClass PangoWin32FontClass; +typedef struct _PangoWin32MetricsInfo PangoWin32MetricsInfo; + +struct _PangoWin32SubfontInfo +{ + LOGFONT logfont; + HFONT hfont; + + /* The following fields are used only to check whether a glyph is + * present in the subfont. On NT, there is the API GetGlyphIndices + * that can be used to do this very simply. But on Win9x, + * this isn't available. Bummer. As fas as I can think, the only + * way to determine if a glyph is present in a HFONT is to + * actually draw the glyph and compare the result to that from + * the font's "default character". Well, one other way would be + * to parse the font's character map via GetFontData, but that does + * also seem a bit complex, and might not work with new font + * technologies. + */ + HBITMAP buf_hbm; + HDC buf_hdc; + RECT buf_rect; + int buf_x, buf_y; + HBITMAP default_char_hbm; + char *buf, *default_char_buf; + int buf_size; + HFONT oldfont; + HBITMAP oldbm; +}; + +struct _PangoWin32MetricsInfo +{ + const char *lang; + PangoFontMetrics metrics; +}; + +struct _PangoWin32FontClass +{ + PangoFontClass parent_class; +}; + +static PangoFontClass *parent_class; /* Parent class structure for PangoWin32Font */ + +static void pango_win32_font_class_init (PangoWin32FontClass *class); +static void pango_win32_font_init (PangoWin32Font *win32font); +static void pango_win32_font_shutdown (GObject *object); +static void pango_win32_font_finalize (GObject *object); + +static PangoFontDescription *pango_win32_font_describe (PangoFont *font); +static PangoCoverage *pango_win32_font_get_coverage (PangoFont *font, + const char *lang); +static PangoEngineShape *pango_win32_font_find_shaper (PangoFont *font, + const char *lang, + guint32 ch); +static void pango_win32_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); +static void pango_win32_font_get_metrics (PangoFont *font, + const gchar *lang, + PangoFontMetrics *metrics); + +static PangoWin32SubfontInfo *pango_win32_find_subfont (PangoFont *font, + PangoWin32Subfont subfont_index); + +static gboolean pango_win32_find_glyph (PangoFont *font, + PangoGlyph glyph, + PangoWin32SubfontInfo **subfont_return, + SIZE *size_return); +static HFONT pango_win32_get_hfont (PangoFont *font, + PangoWin32SubfontInfo *info); + +static void pango_win32_get_item_properties (PangoItem *item, + PangoUnderline *uline, + PangoAttrColor *fg_color, + gboolean *fg_set, + PangoAttrColor *bg_color, + gboolean *bg_set); + +static inline PangoWin32SubfontInfo * +pango_win32_find_subfont (PangoFont *font, + PangoWin32Subfont subfont_index) +{ + PangoWin32Font *win32font = (PangoWin32Font *)font; + + if (subfont_index < 1 || subfont_index > win32font->n_subfonts) + { + g_warning ("Invalid subfont %d", subfont_index); + return NULL; + } + + return win32font->subfonts[subfont_index-1]; +} + +static void +pango_win32_make_hfont (PangoFont *font, + PangoWin32SubfontInfo *info) +{ + PangoWin32Font *win32font = (PangoWin32Font *)font; + PangoWin32FontCache *cache; + + cache = pango_win32_font_map_get_font_cache (win32font->fontmap); + + info->hfont = pango_win32_font_cache_load (cache, &info->logfont); + if (!info->hfont) + g_warning ("Cannot load font '%s\n", info->logfont.lfFaceName); +} + +static inline HFONT +pango_win32_get_hfont (PangoFont *font, + PangoWin32SubfontInfo *info) +{ + if (!info->hfont) + pango_win32_make_hfont (font, info); + + return info->hfont; +} + +/** + * pango_win32_get_context: + * + * Retrieves a #PangoContext appropriate for rendering with Windows fonts. + * + * Return value: the new #PangoContext + **/ +PangoContext * +pango_win32_get_context (void) +{ + PangoContext *result; + + result = pango_context_new (); + pango_context_add_font_map (result, pango_win32_font_map_for_display ()); + + return result; +} + +static GType +pango_win32_font_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (PangoWin32FontClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) pango_win32_font_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PangoWin32Font), + 0, /* n_preallocs */ + (GInstanceInitFunc) pango_win32_font_init, + }; + + object_type = g_type_register_static (PANGO_TYPE_FONT, + "PangoWin32Font", + &object_info); + } + + return object_type; +} + +static void +pango_win32_font_init (PangoWin32Font *win32font) +{ + win32font->subfonts_by_subrange = g_hash_table_new (g_direct_hash, g_direct_equal); + win32font->subfonts = g_new (PangoWin32SubfontInfo *, 1); + + win32font->n_subfonts = 0; + win32font->max_subfonts = 1; + + win32font->metrics_by_lang = NULL; + + win32font->size = -1; + win32font->entry = NULL; +} + +static void +pango_win32_font_class_init (PangoWin32FontClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontClass *font_class = PANGO_FONT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + + object_class->finalize = pango_win32_font_finalize; + object_class->shutdown = pango_win32_font_shutdown; + + font_class->describe = pango_win32_font_describe; + font_class->get_coverage = pango_win32_font_get_coverage; + font_class->find_shaper = pango_win32_font_find_shaper; + font_class->get_glyph_extents = pango_win32_font_get_glyph_extents; + font_class->get_metrics = pango_win32_font_get_metrics; + + if (pango_win32_hdc == NULL) + { + pango_win32_hdc = CreateDC ("DISPLAY", NULL, NULL, NULL); + white_brush = GetStockObject (WHITE_BRUSH); + } +} + +PangoWin32Font * +pango_win32_font_new (PangoFontMap *fontmap, + const LOGFONT *lfp, + int n_fonts, + int size) +{ + PangoWin32Font *result; + + g_return_val_if_fail (fontmap != NULL, NULL); + g_return_val_if_fail (lfp != NULL, NULL); + + result = (PangoWin32Font *)g_type_create_instance (PANGO_TYPE_WIN32_FONT); + + result->fontmap = fontmap; + g_object_ref (G_OBJECT (fontmap)); + + result -> n_fonts = n_fonts; + result->fonts = g_new (LOGFONT, n_fonts); + memcpy (result->fonts, lfp, sizeof (LOGFONT) * n_fonts); + result->size = size; + + return result; +} + +/** + * pango_win32_load_font: + * @lfps: an array of LOGFONTs + * @n_fonts: the number of LOGFONTS + * + * Loads a logical font based on a "fontset" style specification. + * + * Returns a new #PangoFont + */ +PangoFont * +pango_win32_load_font (LOGFONT *lfp, + int n_fonts) +{ + PangoWin32Font *result; + + g_return_val_if_fail (lfp != NULL, NULL); + + result = pango_win32_font_new (pango_win32_font_map_for_display (), + lfp, n_fonts, -1); + + return (PangoFont *)result; +} + +/** + * pango_win32_render: + * @hdc: the device context + * @font: the font in which to draw the string + * @glyphs: the glyph string to draw + * @x: the x position of start of string (in pixels) + * @y: the y position of baseline (in pixels) + * + * Render a PangoGlyphString onto a Windows DC + */ +void +pango_win32_render (HDC hdc, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + /* Slow initial implementation. For speed, it should really + * collect the characters into runs, and draw multiple + * characters with each TextOutW. + */ + HFONT old_hfont = NULL; + HFONT orig_hfont = NULL; + HFONT hfont; + int i; + int x_off = 0; + + g_return_if_fail (glyphs != NULL); + + for (i=0; i<glyphs->num_glyphs; i++) + { + if (glyphs->glyphs[i].glyph) + { + guint16 index = PANGO_WIN32_GLYPH_INDEX (glyphs->glyphs[i].glyph); + guint16 subfont_index = PANGO_WIN32_GLYPH_SUBFONT (glyphs->glyphs[i].glyph); + PangoWin32SubfontInfo *info; + + info = pango_win32_find_subfont (font, subfont_index); + if (info) + { + hfont = pango_win32_get_hfont (font, info); + if (!hfont) + continue; + + if (hfont != old_hfont) + { + if (orig_hfont == NULL) + orig_hfont = SelectObject (hdc, hfont); + else + SelectObject (hdc, hfont); + old_hfont = hfont; + } + + TextOutW (hdc, + x + (x_off + glyphs->glyphs[i].geometry.x_offset) / PANGO_SCALE, + y + glyphs->glyphs[i].geometry.y_offset / PANGO_SCALE, + &index, 1); + } + } + + x_off += glyphs->glyphs[i].geometry.width; + } + if (orig_hfont != NULL) + SelectObject (hdc, orig_hfont); +} + +/* This table classifies Unicode characters according to the Microsoft + * Unicode subset numbering. This is based on the table in "Developing + * International Software for Windows 95 and Windows NT". This is almost, + * but not quite, the same as the official Unicode block table in + * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield + * number as in the FONTSIGNATURE struct's fsUsb field. + * There are some grave bugs in the table in the books. For instance + * it claims there are Hangul at U+3400..U+4DFF while this range in + * fact contains CJK Unified Ideographs Extension A. Also, the whole + * block of Hangul Syllables U+AC00..U+D7A3 is missing from the book. + */ + +static struct { + wchar_t low, high; + PangoWin32UnicodeSubrange bit; + gchar *name; +} utab[] = +{ + { 0x0000, 0x007E, + PANGO_WIN32_U_BASIC_LATIN, "Basic Latin" }, + { 0x00A0, 0x00FF, + PANGO_WIN32_U_LATIN_1_SUPPLEMENT, "Latin-1 Supplement" }, + { 0x0100, 0x017F, + PANGO_WIN32_U_LATIN_EXTENDED_A, "Latin Extended-A" }, + { 0x0180, 0x024F, + PANGO_WIN32_U_LATIN_EXTENDED_B, "Latin Extended-B" }, + { 0x0250, 0x02AF, + PANGO_WIN32_U_IPA_EXTENSIONS, "IPA Extensions" }, + { 0x02B0, 0x02FF, + PANGO_WIN32_U_SPACING_MODIFIER_LETTERS, "Spacing Modifier Letters" }, + { 0x0300, 0x036F, + PANGO_WIN32_U_COMBINING_DIACRITICAL_MARKS, "Combining Diacritical Marks" }, + { 0x0370, 0x03CF, + PANGO_WIN32_U_BASIC_GREEK, "Basic Greek" }, + { 0x03D0, 0x03FF, + PANGO_WIN32_U_GREEK_SYMBOLS_AND_COPTIC, "Greek Symbols and Coptic" }, + { 0x0400, 0x04FF, + PANGO_WIN32_U_CYRILLIC, "Cyrillic" }, + { 0x0530, 0x058F, + PANGO_WIN32_U_ARMENIAN, "Armenian" }, + { 0x0590, 0x05CF, + PANGO_WIN32_U_HEBREW_EXTENDED, "Hebrew Extended" }, + { 0x05D0, 0x05FF, + PANGO_WIN32_U_BASIC_HEBREW, "Basic Hebrew" }, + { 0x0600, 0x0652, + PANGO_WIN32_U_BASIC_ARABIC, "Basic Arabic" }, + { 0x0653, 0x06FF, + PANGO_WIN32_U_ARABIC_EXTENDED, "Arabic Extended" }, + { 0x0900, 0x097F, + PANGO_WIN32_U_DEVANAGARI, "Devanagari" }, + { 0x0980, 0x09FF, + PANGO_WIN32_U_BENGALI, "Bengali" }, + { 0x0A00, 0x0A7F, + PANGO_WIN32_U_GURMUKHI, "Gurmukhi" }, + { 0x0A80, 0x0AFF, + PANGO_WIN32_U_GUJARATI, "Gujarati" }, + { 0x0B00, 0x0B7F, + PANGO_WIN32_U_ORIYA, "Oriya" }, + { 0x0B80, 0x0BFF, + PANGO_WIN32_U_TAMIL, "Tamil" }, + { 0x0C00, 0x0C7F, + PANGO_WIN32_U_TELUGU, "Telugu" }, + { 0x0C80, 0x0CFF, + PANGO_WIN32_U_KANNADA, "Kannada" }, + { 0x0D00, 0x0D7F, + PANGO_WIN32_U_MALAYALAM, "Malayalam" }, + { 0x0E00, 0x0E7F, + PANGO_WIN32_U_THAI, "Thai" }, + { 0x0E80, 0x0EFF, + PANGO_WIN32_U_LAO, "Lao" }, + { 0x10A0, 0x10CF, + PANGO_WIN32_U_GEORGIAN_EXTENDED, "Georgian Extended" }, + { 0x10D0, 0x10FF, + PANGO_WIN32_U_BASIC_GEORGIAN, "Basic Georgian" }, + { 0x1100, 0x11FF, + PANGO_WIN32_U_HANGUL_JAMO, "Hangul Jamo" }, + { 0x1E00, 0x1EFF, + PANGO_WIN32_U_LATIN_EXTENDED_ADDITIONAL, "Latin Extended Additional" }, + { 0x1F00, 0x1FFF, + PANGO_WIN32_U_GREEK_EXTENDED, "Greek Extended" }, + { 0x2000, 0x206F, + PANGO_WIN32_U_GENERAL_PUNCTUATION, "General Punctuation" }, + { 0x2070, 0x209F, + PANGO_WIN32_U_SUPERSCRIPTS_AND_SUBSCRIPTS, "Superscripts and Subscripts" }, + { 0x20A0, 0x20CF, + PANGO_WIN32_U_CURRENCY_SYMBOLS, "Currency Symbols" }, + { 0x20D0, 0x20FF, + PANGO_WIN32_U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS, "Combining Diacritical Marks for Symbols" }, + { 0x2100, 0x214F, + PANGO_WIN32_U_LETTERLIKE_SYMBOLS, "Letterlike Symbols" }, + { 0x2150, 0x218F, + PANGO_WIN32_U_NUMBER_FORMS, "Number Forms" }, + { 0x2190, 0x21FF, + PANGO_WIN32_U_ARROWS, "Arrows" }, + { 0x2200, 0x22FF, + PANGO_WIN32_U_MATHEMATICAL_OPERATORS, "Mathematical Operators" }, + { 0x2300, 0x23FF, + PANGO_WIN32_U_MISCELLANEOUS_TECHNICAL, "Miscellaneous Technical" }, + { 0x2400, 0x243F, + PANGO_WIN32_U_CONTROL_PICTURES, "Control Pictures" }, + { 0x2440, 0x245F, + PANGO_WIN32_U_OPTICAL_CHARACTER_RECOGNITION, "Optical Character Recognition" }, + { 0x2460, 0x24FF, + PANGO_WIN32_U_ENCLOSED_ALPHANUMERICS, "Enclosed Alphanumerics" }, + { 0x2500, 0x257F, + PANGO_WIN32_U_BOX_DRAWING, "Box Drawing" }, + { 0x2580, 0x259F, + PANGO_WIN32_U_BLOCK_ELEMENTS, "Block Elements" }, + { 0x25A0, 0x25FF, + PANGO_WIN32_U_GEOMETRIC_SHAPES, "Geometric Shapes" }, + { 0x2600, 0x26FF, + PANGO_WIN32_U_MISCELLANEOUS_SYMBOLS, "Miscellaneous Symbols" }, + { 0x2700, 0x27BF, + PANGO_WIN32_U_DINGBATS, "Dingbats" }, + { 0x3000, 0x303F, + PANGO_WIN32_U_CJK_SYMBOLS_AND_PUNCTUATION, "CJK Symbols and Punctuation" }, + { 0x3040, 0x309F, + PANGO_WIN32_U_HIRAGANA, "Hiragana" }, + { 0x30A0, 0x30FF, + PANGO_WIN32_U_KATAKANA, "Katakana" }, + { 0x3100, 0x312F, + PANGO_WIN32_U_BOPOMOFO, "Bopomofo" }, + { 0x3130, 0x318F, + PANGO_WIN32_U_HANGUL_COMPATIBILITY_JAMO, "Hangul Compatibility Jamo" }, + { 0x3190, 0x319F, + PANGO_WIN32_U_CJK_MISCELLANEOUS, "CJK Miscellaneous" }, + { 0x3200, 0x32FF, + PANGO_WIN32_U_ENCLOSED_CJK, "Enclosed CJK" }, + { 0x3300, 0x33FF, + PANGO_WIN32_U_CJK_COMPATIBILITY, "CJK Compatibility" }, + /* The book claims: + * U+3400..U+3D2D Hangul + * U+3D2E..U+44B7 Hangul Supplementary A + * U+44B8..U+4DFF Hangul Supplementary B + * but actually in Unicode + * U+3400..U+4DB5 is CJK Unified Ideographs Extension A + */ + { 0x3400, 0x4DB5, + PANGO_WIN32_U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs Extension A" }, + { 0x4E00, 0x9FFF, + PANGO_WIN32_U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs" }, + /* This was missing completely from the book's table. */ + { 0xAC00, 0xD7A3, + PANGO_WIN32_U_HANGUL, "Hangul Syllables" }, + { 0xE000, 0xF8FF, + PANGO_WIN32_U_PRIVATE_USE_AREA, "Private Use Area" }, + { 0xF900, 0xFAFF, + PANGO_WIN32_U_CJK_COMPATIBILITY_IDEOGRAPHS, "CJK Compatibility Ideographs" }, + { 0xFB00, 0xFB4F, + PANGO_WIN32_U_ALPHABETIC_PRESENTATION_FORMS, "Alphabetic Presentation Forms" }, + { 0xFB50, 0xFDFF, + PANGO_WIN32_U_ARABIC_PRESENTATION_FORMS_A, "Arabic Presentation Forms-A" }, + { 0xFE20, 0xFE2F, + PANGO_WIN32_U_COMBINING_HALF_MARKS, "Combining Half Marks" }, + { 0xFE30, 0xFE4F, + PANGO_WIN32_U_CJK_COMPATIBILITY_FORMS, "CJK Compatibility Forms" }, + { 0xFE50, 0xFE6F, + PANGO_WIN32_U_SMALL_FORM_VARIANTS, "Small Form Variants" }, + { 0xFE70, 0xFEFE, + PANGO_WIN32_U_ARABIC_PRESENTATION_FORMS_B, "Arabic Presentation Forms-B" }, + { 0xFEFF, 0xFEFF, + PANGO_WIN32_U_SPECIALS, "Specials" }, + { 0xFF00, 0xFFEF, + PANGO_WIN32_U_HALFWIDTH_AND_FULLWIDTH_FORMS, "Halfwidth and Fullwidth Forms" }, + { 0xFFF0, 0xFFFD, + PANGO_WIN32_U_SPECIALS, "Specials" } +}; + +/* Return the Unicode subrange number for a Unicode character */ +PangoWin32UnicodeSubrange +pango_win32_unicode_classify (wchar_t wc) +{ + int min = 0; + int max = sizeof (utab) / sizeof (utab[0]) - 1; + int mid; + + while (max >= min) + { + mid = (min + max) / 2; + if (utab[mid].high < wc) + min = mid + 1; + else if (wc < utab[mid].low) + max = mid - 1; + else if (utab[mid].low <= wc && wc <= utab[mid].high) + return utab[mid].bit; + else + return -1; + } +} + +static void +pango_win32_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + PangoWin32SubfontInfo *info; + SIZE size; + + if (glyph && pango_win32_find_glyph (font, glyph, &info, &size)) + { + /* This is totally bogus */ + if (ink_rect) + { + ink_rect->x = PANGO_SCALE * size.cx; + ink_rect->width = ink_rect->x; + ink_rect->y = PANGO_SCALE * 0; + ink_rect->height = PANGO_SCALE * size.cy; + } + if (logical_rect) + { + logical_rect->x = 0; + logical_rect->width = PANGO_SCALE * size.cx; + logical_rect->y = 0; + logical_rect->height = PANGO_SCALE * size.cy; + } + } + else + { + if (ink_rect) + { + ink_rect->x = 0; + ink_rect->width = 0; + ink_rect->y = 0; + ink_rect->height = 0; + } + if (logical_rect) + { + logical_rect->x = 0; + logical_rect->width = 0; + logical_rect->y = 0; + logical_rect->height = 0; + } + } +} + +/* Get composite font metrics for all subfonts in list + */ +static void +get_font_metrics_from_subfonts (PangoFont *font, + GSList *subfonts, + PangoFontMetrics *metrics) +{ + HFONT hfont; + HGDIOBJ oldfont; + TEXTMETRIC tm; + GSList *tmp_list = subfonts; + gboolean first = TRUE; + + metrics->ascent = 0; + metrics->descent = 0; + + while (tmp_list) + { + PangoWin32SubfontInfo *info = pango_win32_find_subfont (font, GPOINTER_TO_UINT (tmp_list->data)); + + if (info) + { + hfont = pango_win32_get_hfont (font, info); + if (hfont != NULL) + { + oldfont = SelectObject (pango_win32_hdc, hfont); + GetTextMetrics (pango_win32_hdc, &tm); + SelectObject (pango_win32_hdc, oldfont); + if (first) + { + metrics->ascent = tm.tmAscent * PANGO_SCALE; + metrics->descent = tm.tmDescent * PANGO_SCALE; + first = FALSE; + } + else + { + metrics->ascent = MAX (tm.tmAscent * PANGO_SCALE, metrics->ascent); + metrics->descent = MAX (tm.tmDescent * PANGO_SCALE, metrics->descent); + } + } + } + else + g_warning ("Invalid subfont %d in get_font_metrics_from_subfonts", GPOINTER_TO_UINT (tmp_list->data)); + + tmp_list = tmp_list->next; + } +} + +/* Get composite font metrics for all subfonts resulting from shaping + * string str with the given font + * + * This duplicates quite a bit of code from pango_itemize. This function + * should die and we should simply add the ability to specify particular + * fonts when itemizing. + */ +static void +get_font_metrics_from_string (PangoFont *font, + const char *lang, + const char *str, + PangoFontMetrics *metrics) +{ + const char *start, *p; + PangoGlyphString *glyph_str = pango_glyph_string_new (); + PangoEngineShape *shaper, *last_shaper; + int last_level; + gunichar *text_ucs4; + int n_chars, i; + guint8 *embedding_levels; + FriBidiCharType base_dir = PANGO_DIRECTION_LTR; + GSList *subfonts = NULL; + + n_chars = g_utf8_strlen (str, -1); + + text_ucs4 = g_utf8_to_ucs4 (str, strlen (str)); + if (!text_ucs4) + return; + + embedding_levels = g_new (guint8, n_chars); + fribidi_log2vis_get_embedding_levels (text_ucs4, n_chars, &base_dir, + embedding_levels); + g_free (text_ucs4); + + last_shaper = NULL; + last_level = 0; + + i = 0; + p = start = str; + while (*p) + { + gunichar wc = g_utf8_get_char (p); + p = g_utf8_next_char (p); + + shaper = pango_font_find_shaper (font, lang, wc); + if (p > start && + (shaper != last_shaper || last_level != embedding_levels[i])) + { + PangoAnalysis analysis; + int j; + + analysis.shape_engine = shaper; + analysis.lang_engine = NULL; + analysis.font = font; + analysis.level = last_level; + + pango_shape (start, p - start, &analysis, glyph_str); + + for (j = 0; j < glyph_str->num_glyphs; j++) + { + PangoWin32Subfont subfont = PANGO_WIN32_GLYPH_SUBFONT (glyph_str->glyphs[j].glyph); + if (!g_slist_find (subfonts, GUINT_TO_POINTER ((guint)subfont))) + subfonts = g_slist_prepend (subfonts, GUINT_TO_POINTER ((guint)subfont)); + } + + start = p; + } + + last_shaper = shaper; + last_level = embedding_levels[i]; + i++; + } + + get_font_metrics_from_subfonts (font, subfonts, metrics); + g_slist_free (subfonts); + + pango_glyph_string_free (glyph_str); + g_free (embedding_levels); +} + +typedef struct { + const char *lang; + const char *str; +} LangInfo; + +int +lang_info_compare (const void *key, const void *val) +{ + const LangInfo *lang_info = val; + + return strncmp (key, lang_info->lang, 2); +} + +/* The following array is supposed to contain enough text to tickle all necessary fonts for each + * of the languages in the following. Yes, it's pretty lame. Not all of the languages + * in the following have sufficient text to excercise all the accents for the language, and + * there are obviously many more languages to include as well. + */ +LangInfo lang_texts[] = { + { "ar", "Arabic السلام عليكم" }, + { "cs", "Czech (česky) Dobrý den" }, + { "da", "Danish (Dansk) Hej, Goddag" }, + { "el", "Greek (Ελληνικά) Γειά σας" }, + { "en", "English Hello" }, + { "eo", "Esperanto Saluton" }, + { "es", "Spanish (Español) ¡Hola!" }, + { "et", "Estonian Tere, Tervist" }, + { "fi", "Finnish (Suomi) Hei, Hyvää päivää" }, + { "fr", "French (Français)" }, + { "de", "German Grüß Gott" }, + { "iw", "Hebrew שלום" }, + { "il", "Italiano Ciao, Buon giorno" }, + { "ja", "Japanese (日本語) こんにちは, コンニチハ" }, + { "ko", "Korean (한글) 안녕하세요, 안녕하십니까" }, + { "mt", "Maltese Ċaw, Saħħa" }, + { "nl", "Nederlands, Vlaams Hallo, Dag" }, + { "no", "Norwegian (Norsk) Hei, God dag" }, + { "pl", "Polish Dzień dobry, Hej" }, + { "ru", "Russian (Русский)" }, + { "sk", "Slovak Dobrý deň" }, + { "sv", "Swedish (Svenska) Hej på dej" }, + { "tr", "Turkish (Türkçe) Merhaba" }, + { "zh", "Chinese (中文,普通话,汉语)" } +}; + +static void +pango_win32_font_get_metrics (PangoFont *font, + const gchar *lang, + PangoFontMetrics *metrics) +{ + PangoWin32MetricsInfo *info; + PangoWin32Font *win32font = (PangoWin32Font *)font; + GSList *tmp_list; + + const char *lookup_lang; + const char *str; + + if (lang) + { + LangInfo *lang_info = bsearch (lang, lang_texts, + G_N_ELEMENTS (lang_texts), sizeof (LangInfo), + lang_info_compare); + + if (lang_info) + { + lookup_lang = lang_info->lang; + str = lang_info->str; + } + else + { + lookup_lang = "UNKNOWN"; + str = "French (Français)"; /* Assume iso-8859-1 */ + } + } + else + { + lookup_lang = "NONE"; + + /* Complete junk + */ + str = "السلام عليكم česky Ελληνικά Français 日本語 한글 Русский 中文,普通话,汉语 Türkçe"; + } + + tmp_list = win32font->metrics_by_lang; + while (tmp_list) + { + info = tmp_list->data; + + if (info->lang == lookup_lang) /* We _don't_ need strcmp */ + break; + + tmp_list = tmp_list->next; + } + + if (!tmp_list) + { + info = g_new (PangoWin32MetricsInfo, 1); + info->lang = lookup_lang; + + win32font->metrics_by_lang = g_slist_prepend (win32font->metrics_by_lang, info); + + get_font_metrics_from_string (font, lang, str, &info->metrics); + } + + *metrics = info->metrics; + return; +} + +static PangoWin32Subfont +pango_win32_insert_subfont (PangoFont *font, + const LOGFONT *lfp) +{ + PangoWin32Font *win32font = (PangoWin32Font *)font; + PangoWin32SubfontInfo *info; + + info = g_new (PangoWin32SubfontInfo, 1); + + info->logfont = *lfp; + info->hfont = NULL; + info->buf_hbm = NULL; + + win32font->n_subfonts++; + + if (win32font->n_subfonts > win32font->max_subfonts) + { + win32font->max_subfonts *= 2; + win32font->subfonts = g_renew (PangoWin32SubfontInfo *, win32font->subfonts, win32font->max_subfonts); + } + + win32font->subfonts[win32font->n_subfonts - 1] = info; + + return win32font->n_subfonts; +} + +/** + * pango_win32_list_subfonts: + * @font: a PangoFont + * @subrange: the Unicode subrange to list subfonts for + * @subfont_ids: location to store a pointer to an array of subfont IDs for each found subfont + * the result must be freed using g_free() + * + * Returns number of subfonts found + **/ +int +pango_win32_list_subfonts (PangoFont *font, + PangoWin32UnicodeSubrange subrange, + PangoWin32Subfont **subfont_ids) +{ + LOGFONT *lfp; + PangoWin32Font *win32font = (PangoWin32Font *)font; + PangoWin32Subfont *subfont_list; + PangoFontMap *fontmap; + int i, j; + int n_subfonts = 0; + + g_return_val_if_fail (font != NULL, 0); + + fontmap = pango_win32_font_map_for_display (); + + subfont_list = g_hash_table_lookup (win32font->subfonts_by_subrange, (gpointer) subrange); + if (!subfont_list) + { + subfont_list = g_new (PangoWin32Subfont, win32font->n_fonts); + + for (i = 0; i < win32font->n_fonts; i++) + { + /* Does this font cover the subrange? */ + PangoWin32Subfont subfont = 0; + + if (pango_win32_logfont_has_subrange (fontmap, win32font->fonts+i, subrange)) + { + lfp = pango_win32_make_matching_logfont (fontmap, win32font->fonts+i, win32font->size); + if (lfp) + { + subfont = pango_win32_insert_subfont (font, lfp); + g_free (lfp); + } + } + + subfont_list[i] = subfont; + } + + g_hash_table_insert (win32font->subfonts_by_subrange, (gpointer) subrange, subfont_list); + } + + for (i = 0; i < win32font->n_fonts; i++) + if (subfont_list[i]) + n_subfonts++; + + *subfont_ids = g_new (PangoWin32Subfont, n_subfonts); + + n_subfonts = 0; + + for (i=0; i<win32font->n_fonts; i++) + if (subfont_list[i]) + { + (*subfont_ids)[n_subfonts] = subfont_list[i]; + n_subfonts++; + } + + g_free (subfont_list); + + return n_subfonts; +} + +gboolean +subfont_has_glyph (PangoWin32SubfontInfo *info, + wchar_t c) + +{ + struct { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + } bmi; + DIBSECTION ds; + TEXTMETRIC tm; + HFONT hfont; + + if (info->buf_hbm == NULL) + { + info->buf_hdc = CreateCompatibleDC (pango_win32_hdc); + GetTextMetrics (pango_win32_hdc, &tm); + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = tm.tmMaxCharWidth; + bmi.bmiHeader.biHeight = -tm.tmHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + bmi.bmiColors[0].rgbBlue = + bmi.bmiColors[0].rgbGreen = + bmi.bmiColors[0].rgbRed = 0x00; + bmi.bmiColors[0].rgbReserved = 0x00; + + bmi.bmiColors[1].rgbBlue = + bmi.bmiColors[1].rgbGreen = + bmi.bmiColors[1].rgbRed = 0xFF; + bmi.bmiColors[1].rgbReserved = 0x00; + + info->default_char_hbm = + CreateDIBSection (info->buf_hdc, (BITMAPINFO *)&bmi, + DIB_RGB_COLORS, (PVOID *)&info->default_char_buf, NULL, 0); + GetObject (info->default_char_hbm, sizeof (ds), &ds); + info->buf_size = ds.dsBmih.biSizeImage; + + info->oldbm = SelectObject (info->buf_hdc, info->default_char_hbm); + info->buf_rect.left = 0; + info->buf_rect.top = 0; + info->buf_rect.right = tm.tmMaxCharWidth; + info->buf_rect.bottom = tm.tmHeight; + info->buf_x = 0; + info->buf_y = tm.tmHeight - tm.tmDescent; + FillRect (info->buf_hdc, &info->buf_rect, white_brush); + + info->oldfont = SelectObject (info->buf_hdc, hfont); + c = tm.tmDefaultChar; + TextOutW (info->buf_hdc, info->buf_x, info->buf_y, &c, 1); + + info->buf_hbm = + CreateDIBSection (info->buf_hdc, (BITMAPINFO *)&bmi, + DIB_RGB_COLORS, (PVOID *)&info->buf, NULL, 0); + + SelectObject (info->buf_hdc, info->buf_hbm); + } + + /* Draw character into our bitmap; compare with the bitmap for + * the default character. If they are identical, this character + * does not exist in the font. + */ + FillRect (info->buf_hdc, &info->buf_rect, white_brush); + TextOutW (info->buf_hdc, info->buf_x, info->buf_y, + &c, 1); + return (memcmp (info->buf, info->default_char_buf, info->buf_size) != 0); + } + +/** + * pango_win32_has_glyph: + * @font: a #PangoFont which must be from the Win32 backend. + * @glyph: the index of a glyph in the font. (Formed + * using the PANGO_WIN32_MAKE_GLYPH macro) + * + * Check if the given glyph is present in a Win32 font. + * + * Return value: %TRUE if the glyph is present. + **/ +gboolean +pango_win32_has_glyph (PangoFont *font, + PangoGlyph glyph) +{ + HFONT hfont; + PangoWin32SubfontInfo *info; + guint16 char_index = PANGO_WIN32_GLYPH_INDEX (glyph); + guint16 subfont_index = PANGO_WIN32_GLYPH_SUBFONT (glyph); + wchar_t c; + + info = pango_win32_find_subfont (font, subfont_index); + if (!info) + return FALSE; + + hfont = pango_win32_get_hfont (font, info); + if (hfont == NULL) + return FALSE; + + return subfont_has_glyph (info, char_index); +} + +/** + * pango_win32_font_subfont_logfont: + * @font: a #PangoFont which must be from the Win32 backend + * @subfont_id: the id of a subfont within the font. + * + * Determine the LOGFONT struct for the specified subfont. + * + * Return value: A newly allocated LOGFONT struct. It must be + * freed with g_free(). + **/ +LOGFONT * +pango_win32_font_subfont_logfont (PangoFont *font, + PangoWin32Subfont subfont_id) +{ + PangoWin32SubfontInfo *info; + LOGFONT *lfp; + + g_return_val_if_fail (font != NULL, NULL); + g_return_val_if_fail (PANGO_WIN32_IS_FONT (font), NULL); + + info = pango_win32_find_subfont (font, subfont_id); + if (!info) + { + g_warning ("pango_win32_font_subfont_logfont: Invalid subfont_id specified"); + return NULL; + } + + lfp = g_new (LOGFONT, 1); + *lfp = info->logfont; + + return lfp; +} + +static void +pango_win32_font_shutdown (GObject *object) +{ + PangoWin32Font *win32font = PANGO_WIN32_FONT (object); + + /* If the font is not already in the freed-fonts cache, add it, + * if it is already there, do nothing and the font will be + * freed. + */ + if (!win32font->in_cache && win32font->fontmap) + pango_win32_fontmap_cache_add (win32font->fontmap, win32font); + + G_OBJECT_CLASS (parent_class)->shutdown (object); +} + +static void +subfonts_foreach (gpointer key, + gpointer value, + gpointer data) +{ + g_free (value); +} + +static void +pango_win32_font_finalize (GObject *object) +{ + PangoWin32Font *win32font = (PangoWin32Font *)object; + PangoWin32FontCache *cache = pango_win32_font_map_get_font_cache (win32font->fontmap); + int i; + + for (i=0; i<win32font->n_subfonts; i++) + { + PangoWin32SubfontInfo *info = win32font->subfonts[i]; + + if (info->hfont != NULL) + pango_win32_font_cache_unload (cache, info->hfont); + + if (info->buf_hbm != NULL) + { + SelectObject (info->buf_hdc, info->oldfont); + SelectObject (info->buf_hdc, info->oldbm); + DeleteObject (info->buf_hbm); + DeleteObject (info->default_char_hbm); + DeleteDC (info->buf_hdc); + } + g_free (info); + } + + g_free (win32font->subfonts); + + g_hash_table_foreach (win32font->subfonts_by_subrange, subfonts_foreach, NULL); + g_hash_table_destroy (win32font->subfonts_by_subrange); + + g_slist_foreach (win32font->metrics_by_lang, (GFunc)g_free, NULL); + g_slist_free (win32font->metrics_by_lang); + + if (win32font->entry) + pango_win32_font_entry_remove (win32font->entry, (PangoFont *)win32font); + + g_object_unref (G_OBJECT (win32font->fontmap)); + + g_free (win32font->fonts); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static PangoFontDescription * +pango_win32_font_describe (PangoFont *font) +{ + /* FIXME: implement */ + return NULL; +} + +PangoMap * +pango_win32_get_shaper_map (const char *lang) +{ + static guint engine_type_id = 0; + static guint render_type_id = 0; + + if (engine_type_id == 0) + { + engine_type_id = g_quark_from_static_string (PANGO_ENGINE_TYPE_SHAPE); + render_type_id = g_quark_from_static_string (PANGO_RENDER_TYPE_WIN32); + } + + return pango_find_map (lang, engine_type_id, render_type_id); +} + +static PangoCoverage * +pango_win32_font_get_coverage (PangoFont *font, + const char *lang) +{ + PangoWin32Font *win32font = (PangoWin32Font *)font; + + return pango_win32_font_entry_get_coverage (win32font->entry, font, lang); +} + +static PangoEngineShape * +pango_win32_font_find_shaper (PangoFont *font, + const gchar *lang, + guint32 ch) +{ + PangoMap *shape_map = NULL; + + shape_map = pango_win32_get_shaper_map (lang); + return (PangoEngineShape *)pango_map_get_engine (shape_map, ch); +} + +/* Utility functions */ + +static gboolean +pango_win32_find_glyph (PangoFont *font, + PangoGlyph glyph, + PangoWin32SubfontInfo **subfont_return, + SIZE *size_return) +{ + SIZE size; + HFONT hfont, oldfont; + PangoWin32SubfontInfo *info; + guint16 char_index = PANGO_WIN32_GLYPH_INDEX (glyph); + guint16 subfont_index = PANGO_WIN32_GLYPH_SUBFONT (glyph); + + info = pango_win32_find_subfont (font, subfont_index); + if (!info) + return FALSE; + + if (!subfont_has_glyph (info, char_index)) + return FALSE; + + oldfont = SelectObject (pango_win32_hdc, hfont); + GetTextExtentPoint32W (pango_win32_hdc, &char_index, 1, &size); + SelectObject (pango_win32_hdc, oldfont); + + if (subfont_return) + *subfont_return = info; + + if (size_return) + *size_return = size; + + return TRUE; +} + +/** + * pango_win32_get_unknown_glyph: + * @font: a #PangoFont + * + * Return the index of a glyph suitable for drawing unknown characters. + * + * Return value: a glyph index into @font + **/ +PangoGlyph +pango_win32_get_unknown_glyph (PangoFont *font) +{ + return PANGO_WIN32_MAKE_GLYPH (0, 0); /* XXX */ +} + +/** + * pango_win32_render_layout_line: + * @hdc: HDC to use for uncolored drawing + * @line: a #PangoLayoutLine + * @x: the x position of start of string (in pixels) + * @y: the y position of baseline (in pixels) + * + * Render a #PangoLayoutLine onto a device context + */ +void +pango_win32_render_layout_line (HDC hdc, + PangoLayoutLine *line, + int x, + int y) +{ + GSList *tmp_list = line->runs; + PangoRectangle overall_rect; + PangoRectangle logical_rect; + PangoRectangle ink_rect; + PangoContext *context = pango_layout_get_context (line->layout); + + int x_off = 0; + + pango_layout_line_get_extents (line,NULL, &overall_rect); + + while (tmp_list) + { + HBRUSH oldfg; + HBRUSH brush; + POINT points[2]; + PangoUnderline uline = PANGO_UNDERLINE_NONE; + PangoLayoutRun *run = tmp_list->data; + PangoAttrColor fg_color, bg_color; + gboolean fg_set, bg_set; + + tmp_list = tmp_list->next; + + pango_win32_get_item_properties (run->item, &uline, &fg_color, &fg_set, &bg_color, &bg_set); + + if (uline == PANGO_UNDERLINE_NONE) + pango_glyph_string_extents (run->glyphs, run->item->analysis.font, + NULL, &logical_rect); + else + pango_glyph_string_extents (run->glyphs, run->item->analysis.font, + &ink_rect, &logical_rect); + + if (bg_set) + { + HBRUSH oldbrush; + + brush = CreateSolidBrush (RGB ((bg_color.red + 128) >> 8, + (bg_color.green + 128) >> 8, + (bg_color.blue + 128) >> 8)); + oldbrush = SelectObject (hdc, brush); + Rectangle (hdc, x + (x_off + logical_rect.x) / PANGO_SCALE, + y + overall_rect.y / PANGO_SCALE, + logical_rect.width / PANGO_SCALE, + overall_rect.height / PANGO_SCALE); + SelectObject (hdc, oldbrush); + DeleteObject (brush); + } + + if (fg_set) + { + brush = CreateSolidBrush (RGB ((fg_color.red + 128) >> 8, + (fg_color.green + 128) >> 8, + (fg_color.blue + 128) >> 8)); + oldfg = SelectObject (hdc, brush); + } + + pango_win32_render (hdc, run->item->analysis.font, run->glyphs, + x + x_off / PANGO_SCALE, y); + + switch (uline) + { + case PANGO_UNDERLINE_NONE: + break; + case PANGO_UNDERLINE_DOUBLE: + points[0].x = x + (x_off + ink_rect.x) / PANGO_SCALE - 1; + points[0].y = points[1].y = y + 4; + points[1].x = x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE; + Polyline (hdc, points, 2); + /* Fall through */ + case PANGO_UNDERLINE_SINGLE: + points[0].y = points[1].y = y + 2; + Polyline (hdc, points, 2); + break; + case PANGO_UNDERLINE_LOW: + points[0].x = x + (x_off + ink_rect.x) / PANGO_SCALE - 1; + points[0].y = points[1].y = y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 2; + points[1].x = x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE; + Polyline (hdc, points, 2); + break; + } + + if (fg_set) + { + SelectObject (hdc, oldfg); + DeleteObject (brush); + } + + x_off += logical_rect.width; + } +} + +/** + * pango_win32_render_layout: + * @hdc: HDC to use for uncolored drawing + * @layout: a #PangoLayout + * @x: the X position of the left of the layout (in pixels) + * @y: the Y position of the top of the layout (in pixels) + * + * Render a #PangoLayoutLine onto an X drawable + */ +void +pango_win32_render_layout (HDC hdc, + PangoLayout *layout, + int x, + int y) +{ + PangoRectangle logical_rect; + GSList *tmp_list; + PangoAlignment align; + int indent; + int width; + int y_offset = 0; + + gboolean first = FALSE; + + g_return_if_fail (layout != NULL); + + indent = pango_layout_get_indent (layout); + width = pango_layout_get_width (layout); + align = pango_layout_get_alignment (layout); + + if (width == -1 && align != PANGO_ALIGN_LEFT) + { + pango_layout_get_extents (layout, NULL, &logical_rect); + width = logical_rect.width; + } + + tmp_list = pango_layout_get_lines (layout); + while (tmp_list) + { + PangoLayoutLine *line = tmp_list->data; + int x_offset; + + pango_layout_line_get_extents (line, NULL, &logical_rect); + + if (width != 1 && align == PANGO_ALIGN_RIGHT) + x_offset = width - logical_rect.width; + else if (width != 1 && align == PANGO_ALIGN_CENTER) + x_offset = (width - logical_rect.width) / 2; + else + x_offset = 0; + + if (first) + { + if (indent > 0) + { + if (align == PANGO_ALIGN_LEFT) + x_offset += indent; + else + x_offset -= indent; + } + + first = FALSE; + } + else + { + if (indent < 0) + { + if (align == PANGO_ALIGN_LEFT) + x_offset -= indent; + else + x_offset += indent; + } + } + + pango_win32_render_layout_line (hdc, line, + x + x_offset / PANGO_SCALE, + y + (y_offset - logical_rect.y) / PANGO_SCALE); + + y_offset += logical_rect.height; + tmp_list = tmp_list->next; + } +} + +/* This utility function is duplicated here and in pango-layout.c; should it be + * public? Trouble is - what is the appropriate set of properties? + */ +static void +pango_win32_get_item_properties (PangoItem *item, + PangoUnderline *uline, + PangoAttrColor *fg_color, + gboolean *fg_set, + PangoAttrColor *bg_color, + gboolean *bg_set) +{ + GSList *tmp_list = item->extra_attrs; + + if (fg_set) + *fg_set = FALSE; + + if (bg_set) + *bg_set = FALSE; + + while (tmp_list) + { + PangoAttribute *attr = tmp_list->data; + + switch (attr->klass->type) + { + case PANGO_ATTR_UNDERLINE: + if (uline) + *uline = ((PangoAttrInt *)attr)->value; + break; + + case PANGO_ATTR_FOREGROUND: + if (fg_color) + *fg_color = *((PangoAttrColor *)attr); + if (fg_set) + *fg_set = TRUE; + + break; + + case PANGO_ATTR_BACKGROUND: + if (bg_color) + *bg_color = *((PangoAttrColor *)attr); + if (bg_set) + *bg_set = TRUE; + + break; + + default: + break; + } + tmp_list = tmp_list->next; + } +} + diff --git a/pango/pangowin32.h b/pango/pangowin32.h new file mode 100644 index 00000000..7d040f5b --- /dev/null +++ b/pango/pangowin32.h @@ -0,0 +1,187 @@ +/* Pango + * pangowin32.h: + * + * Copyright (C) 1999 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. + */ + +#ifndef __PANGOWIN32_H__ +#define __PANGOWIN32_H__ + +#include <glib.h> +#include <pango/pango.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define STRICT +#include <windows.h> + +#define PANGO_RENDER_TYPE_WIN32 "PangoRenderWin32" + +/* This enum divides Unicode characters according to the Microsoft + * Unicode subrange numbering. This is based on the table in "Developing + * International Software for Windows 95 and Windows NT". This is almost, + * but not quite, the same as the official Unicode block table in + * Blocks.txt from ftp.unicode.org. + */ +typedef enum +{ + PANGO_WIN32_U_BASIC_LATIN = 0, + PANGO_WIN32_U_LATIN_1_SUPPLEMENT = 1, + PANGO_WIN32_U_LATIN_EXTENDED_A = 2, + PANGO_WIN32_U_LATIN_EXTENDED_B = 3, + PANGO_WIN32_U_IPA_EXTENSIONS = 4, + PANGO_WIN32_U_SPACING_MODIFIER_LETTERS = 5, + PANGO_WIN32_U_COMBINING_DIACRITICAL_MARKS = 6, + PANGO_WIN32_U_BASIC_GREEK = 7, + PANGO_WIN32_U_GREEK_SYMBOLS_AND_COPTIC = 8, + PANGO_WIN32_U_CYRILLIC = 9, + PANGO_WIN32_U_ARMENIAN = 10, + PANGO_WIN32_U_HEBREW_EXTENDED = 12, + PANGO_WIN32_U_BASIC_HEBREW = 11, + PANGO_WIN32_U_BASIC_ARABIC = 13, + PANGO_WIN32_U_ARABIC_EXTENDED = 14, + PANGO_WIN32_U_DEVANAGARI = 15, + PANGO_WIN32_U_BENGALI = 16, + PANGO_WIN32_U_GURMUKHI = 17, + PANGO_WIN32_U_GUJARATI = 18, + PANGO_WIN32_U_ORIYA = 19, + PANGO_WIN32_U_TAMIL = 20, + PANGO_WIN32_U_TELUGU = 21, + PANGO_WIN32_U_KANNADA = 22, + PANGO_WIN32_U_MALAYALAM = 23, + PANGO_WIN32_U_THAI = 24, + PANGO_WIN32_U_LAO = 25, + PANGO_WIN32_U_GEORGIAN_EXTENDED = 27, + PANGO_WIN32_U_BASIC_GEORGIAN = 26, + PANGO_WIN32_U_HANGUL_JAMO = 28, + PANGO_WIN32_U_LATIN_EXTENDED_ADDITIONAL = 29, + PANGO_WIN32_U_GREEK_EXTENDED = 30, + PANGO_WIN32_U_GENERAL_PUNCTUATION = 31, + PANGO_WIN32_U_SUPERSCRIPTS_AND_SUBSCRIPTS = 32, + PANGO_WIN32_U_CURRENCY_SYMBOLS = 33, + PANGO_WIN32_U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS = 34, + PANGO_WIN32_U_LETTERLIKE_SYMBOLS = 35, + PANGO_WIN32_U_NUMBER_FORMS = 36, + PANGO_WIN32_U_ARROWS = 37, + PANGO_WIN32_U_MATHEMATICAL_OPERATORS = 38, + PANGO_WIN32_U_MISCELLANEOUS_TECHNICAL = 39, + PANGO_WIN32_U_CONTROL_PICTURES = 40, + PANGO_WIN32_U_OPTICAL_CHARACTER_RECOGNITION = 41, + PANGO_WIN32_U_ENCLOSED_ALPHANUMERICS = 42, + PANGO_WIN32_U_BOX_DRAWING = 43, + PANGO_WIN32_U_BLOCK_ELEMENTS = 44, + PANGO_WIN32_U_GEOMETRIC_SHAPES = 45, + PANGO_WIN32_U_MISCELLANEOUS_SYMBOLS = 46, + PANGO_WIN32_U_DINGBATS = 47, + PANGO_WIN32_U_CJK_SYMBOLS_AND_PUNCTUATION = 48, + PANGO_WIN32_U_HIRAGANA = 49, + PANGO_WIN32_U_KATAKANA = 50, + PANGO_WIN32_U_BOPOMOFO = 51, + PANGO_WIN32_U_HANGUL_COMPATIBILITY_JAMO = 52, + PANGO_WIN32_U_CJK_MISCELLANEOUS = 53, + PANGO_WIN32_U_ENCLOSED_CJK = 54, + PANGO_WIN32_U_CJK_COMPATIBILITY = 55, + PANGO_WIN32_U_HANGUL = 56, + PANGO_WIN32_U_HANGUL_SUPPLEMENTARY_A = 57, + PANGO_WIN32_U_HANGUL_SUPPLEMENTARY_B = 58, + PANGO_WIN32_U_CJK_UNIFIED_IDEOGRAPHS = 59, + PANGO_WIN32_U_PRIVATE_USE_AREA = 60, + PANGO_WIN32_U_CJK_COMPATIBILITY_IDEOGRAPHS = 61, + PANGO_WIN32_U_ALPHABETIC_PRESENTATION_FORMS = 62, + PANGO_WIN32_U_ARABIC_PRESENTATION_FORMS_A = 63, + PANGO_WIN32_U_COMBINING_HALF_MARKS = 64, + PANGO_WIN32_U_CJK_COMPATIBILITY_FORMS = 65, + PANGO_WIN32_U_SMALL_FORM_VARIANTS = 66, + PANGO_WIN32_U_ARABIC_PRESENTATION_FORMS_B = 67, + PANGO_WIN32_U_SPECIALS = 69, + PANGO_WIN32_U_HALFWIDTH_AND_FULLWIDTH_FORMS = 68, + PANGO_WIN32_U_LAST_PLUS_ONE +} PangoWin32UnicodeSubrange; + +/* Calls for applications + */ +PangoContext * pango_win32_get_context (void); + +PangoFont * pango_win32_load_font (LOGFONT *lfp, + int n_fonts); +void pango_win32_render (HDC hdc, + PangoFont *font, + PangoGlyphString *glyphs, + gint x, + gint y); +void pango_win32_render_layout_line (HDC hdc, + PangoLayoutLine *line, + int x, + int y); +void pango_win32_render_layout (HDC hdc, + PangoLayout *layout, + int x, + int y); + + + +/* API for rendering modules + */ +typedef guint16 PangoWin32Subfont; + +#define PANGO_WIN32_MAKE_GLYPH(subfont,index) ((subfont)<<16 | (index)) +#define PANGO_WIN32_GLYPH_SUBFONT(glyph) ((glyph)>>16) +#define PANGO_WIN32_GLYPH_INDEX(glyph) ((glyph) & 0xffff) + +int pango_win32_list_subfonts (PangoFont *font, + PangoWin32UnicodeSubrange subrange, + PangoWin32Subfont **subfont_ids); +gboolean pango_win32_has_glyph (PangoFont *font, + PangoGlyph glyph); +PangoGlyph pango_win32_get_unknown_glyph (PangoFont *font); + +PangoWin32UnicodeSubrange pango_win32_unicode_classify (wchar_t wc); + +/* API for libraries that want to use PangoWin32 mixed with classic + * Win32 fonts. + */ +typedef struct _PangoWin32FontCache PangoWin32FontCache; + +PangoWin32FontCache *pango_win32_font_cache_new (void); +void pango_win32_font_cache_free (PangoWin32FontCache *cache); + +HFONT pango_win32_font_cache_load (PangoWin32FontCache *cache, + const LOGFONT *lfp); +void pango_win32_font_cache_unload (PangoWin32FontCache *cache, + HFONT hfont); + +PangoFontMap * pango_win32_font_map_for_display (void); +void pango_win32_shutdown_display (void); +PangoWin32FontCache *pango_win32_font_map_get_font_cache (PangoFontMap *font_map); + +LOGFONT *pango_win32_font_subfont_logfont (PangoFont *font, + PangoWin32Subfont subfont_id); + +/* Debugging. + */ +void pango_win32_fontmap_dump (int indent, + PangoFontMap *fontmap); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __PANGOWIN32_H__ */ diff --git a/pango/querymodules.c b/pango/querymodules.c index 051b41d7..6d8b3210 100644 --- a/pango/querymodules.c +++ b/pango/querymodules.c @@ -19,17 +19,29 @@ * Boston, MA 02111-1307, USA. */ +#include "config.h" + #include <glib.h> +#ifdef HAVE_DIRENT_H #include <dirent.h> +#endif #include <gmodule.h> #include "pango.h" #include "pango-utils.h" #include <errno.h> #include <string.h> +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif #include <stdio.h> +#ifdef G_OS_WIN32 +#define SOEXT ".dll" +#else +#define SOEXT ".so" +#endif + void query_module (const char *dir, const char *name) { @@ -102,7 +114,9 @@ int main (int argc, char **argv) path = pango_config_key_get ("Pango/ModulesPath"); if (!path) - path = g_strdup (LIBDIR "/pango/modules"); + path = g_strconcat (pango_get_lib_subdirectory (), + G_DIR_SEPARATOR_S "modules", + NULL); printf ("# ModulesPath = %s\n#\n", path); @@ -118,7 +132,7 @@ int main (int argc, char **argv) while ((dent = readdir (dir))) { int len = strlen (dent->d_name); - if (len > 3 && strcmp (dent->d_name + len - 3, ".so") == 0) + if (len > 3 && strcmp (dent->d_name + len - strlen (SOEXT), SOEXT) == 0) query_module (dirs[i], dent->d_name); } |