diff options
-rw-r--r-- | ChangeLog | 34 | ||||
-rw-r--r-- | ChangeLog.pre-1-0 | 34 | ||||
-rw-r--r-- | ChangeLog.pre-1-10 | 34 | ||||
-rw-r--r-- | ChangeLog.pre-1-2 | 34 | ||||
-rw-r--r-- | ChangeLog.pre-1-4 | 34 | ||||
-rw-r--r-- | ChangeLog.pre-1-6 | 34 | ||||
-rw-r--r-- | ChangeLog.pre-1-8 | 34 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | examples/makefile.mingw | 22 | ||||
-rw-r--r-- | examples/pangowin32.aliases | 7 | ||||
-rw-r--r-- | examples/viewer-win32.c | 742 | ||||
-rw-r--r-- | modules/basic/basic-win32.c | 363 | ||||
-rw-r--r-- | modules/basic/makefile.mingw | 21 | ||||
-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 |
23 files changed, 5453 insertions, 14 deletions
@@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/ChangeLog.pre-1-0 b/ChangeLog.pre-1-0 index 73581e5f..dcd6a5e8 100644 --- a/ChangeLog.pre-1-0 +++ b/ChangeLog.pre-1-0 @@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/ChangeLog.pre-1-10 b/ChangeLog.pre-1-10 index 73581e5f..dcd6a5e8 100644 --- a/ChangeLog.pre-1-10 +++ b/ChangeLog.pre-1-10 @@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/ChangeLog.pre-1-2 b/ChangeLog.pre-1-2 index 73581e5f..dcd6a5e8 100644 --- a/ChangeLog.pre-1-2 +++ b/ChangeLog.pre-1-2 @@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/ChangeLog.pre-1-4 b/ChangeLog.pre-1-4 index 73581e5f..dcd6a5e8 100644 --- a/ChangeLog.pre-1-4 +++ b/ChangeLog.pre-1-4 @@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/ChangeLog.pre-1-6 b/ChangeLog.pre-1-6 index 73581e5f..dcd6a5e8 100644 --- a/ChangeLog.pre-1-6 +++ b/ChangeLog.pre-1-6 @@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/ChangeLog.pre-1-8 b/ChangeLog.pre-1-8 index 73581e5f..dcd6a5e8 100644 --- a/ChangeLog.pre-1-8 +++ b/ChangeLog.pre-1-8 @@ -1,3 +1,37 @@ +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(). + Thu Jul 6 15:24:38 2000 Owen Taylor <otaylor@redhat.com> * Released 0.12 diff --git a/configure.in b/configure.in index 03a37962..c32cca2a 100644 --- a/configure.in +++ b/configure.in @@ -210,6 +210,9 @@ EOTEXT included_modules=$included_modules ]) +AC_HEADER_DIRENT +AC_CHECK_HEADER(unistd.h, AC_DEFINE(HAVE_UNISTD_H)) + AC_OUTPUT([ Makefile pango/Makefile diff --git a/examples/makefile.mingw b/examples/makefile.mingw new file mode 100644 index 00000000..259e02af --- /dev/null +++ b/examples/makefile.mingw @@ -0,0 +1,22 @@ +PANGO_VER = 0.12 + +TOP = ../.. + +include $(TOP)/build/win32/make.mingw + +OPTIMIZE = -g + +INCLUDES = -I .. -I . +DEFINES = +DEPCFLAGS = $(GTK_CFLAGS) $(GLIB_CFLAGS) + +all : \ + ../config.h \ + viewer-win32.exe + +../config.h : ../config.h.win32 + cp $< $@ + +viewer-win32.exe : viewer-win32.o + $(CC) -o $@ $< -L ../pango -lpango-$(PANGO_VER) -lpangowin32-$(PANGO_VER) $(GTK_LIBS) $(GLIB_LIBS) -gdi32 + diff --git a/examples/pangowin32.aliases b/examples/pangowin32.aliases new file mode 100644 index 00000000..948642f4 --- /dev/null +++ b/examples/pangowin32.aliases @@ -0,0 +1,7 @@ +# File defining aliases of PangoFontDescription to Windows font set +# +# family style variant weight stretch facename,... + +sans normal normal normal normal "arial,gulimche,ms gothic,ms hei,mingliu" +serif normal normal normal normal "times new roman,gulimche,ms gothic,ms song,mingliu" +monospace normal normal normal normal "courier new,gulimche,ms gothic,ms song,mingliu" diff --git a/examples/viewer-win32.c b/examples/viewer-win32.c new file mode 100644 index 00000000..9304b7d2 --- /dev/null +++ b/examples/viewer-win32.c @@ -0,0 +1,742 @@ +#define PING() g_print ("%s:%d\n", __PRETTY_FUNCTION__, __LINE__) +/* Pango + * viewer-win32.c: Example program to view a UTF-8 encoding file + * using Pango to render result. + * + * 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 <gtk/gtk.h> +#include <gdk/win32/gdkwin32.h> + +#include <pango/pango.h> +#include <pango/pangowin32.h> + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define BUFSIZE 1024 + +typedef struct _Paragraph Paragraph; + +/* Structure representing a paragraph + */ +struct _Paragraph { + char *text; + int length; + int height; /* Height, in pixels */ + PangoLayout *layout; +}; + +GList *paragraphs; + +static PangoFontDescription font_description; +static Paragraph *highlight_para; +static int highlight_offset; + +GtkWidget *styles_combo; + +static GtkWidget *message_label; +GtkWidget *layout; + +PangoContext *context; + +static void fill_styles_combo (GtkWidget *combo); + +/* Read an entire file into a string + */ +static char * +read_file(char *name) +{ + GString *inbuf; + FILE *file; + char *text; + char buffer[BUFSIZE]; + + PING(); + file = fopen (name, "r"); + if (!file) + { + fprintf (stderr, "%s: Cannot open %s\n", g_get_prgname ()); + return NULL; + } + + inbuf = g_string_new (NULL); + while (1) + { + char *bp = fgets (buffer, BUFSIZE-1, file); + if (ferror (file)) + { + fprintf(stderr, "%s: Error reading %s\n", g_get_prgname ()); + g_string_free (inbuf, TRUE); + return NULL; + } + else if (bp == NULL) + break; + + g_string_append (inbuf, buffer); + } + + fclose (file); + + text = inbuf->str; + g_string_free (inbuf, FALSE); + + return text; +} + +/* Take a UTF8 string and break it into paragraphs on \n characters + */ +static GList * +split_paragraphs (char *text) +{ + char *p = text; + char *next; + gunichar wc; + GList *result = NULL; + char *last_para = text; + + while (*p) + { + wc = g_utf8_get_char (p); + next = g_utf8_next_char (p); + if (wc == (gunichar)-1) + { + fprintf (stderr, "%s: Invalid character in input\n", g_get_prgname ()); + g_list_foreach (result, (GFunc)g_free, NULL); + return NULL; + } + if (!*p || !wc || wc == '\n') + { + Paragraph *para = g_new (Paragraph, 1); + para->text = last_para; + para->length = p - last_para; + para->layout = pango_layout_new (context); + pango_layout_set_text (para->layout, para->text, para->length); + para->height = 0; + + last_para = next; + + result = g_list_prepend (result, para); + } + if (!wc) /* incomplete character at end */ + break; + p = next; + } + + return g_list_reverse (result); +} + +/* Given an x-y position, return the paragraph and offset + * within the paragraph of the click. + */ +gboolean +xy_to_cp (int width, int x, int y, Paragraph **para_return, int *index) +{ + GList *para_list; + int height = 0; + + *para_return = NULL; + + PING(); + para_list = paragraphs; + while (para_list && height < y) + { + Paragraph *para = para_list->data; + + if (height + para->height >= y) + { + gboolean result = pango_layout_xy_to_index (para->layout, x * 1000, (y - height) * 1000, + index, NULL); + if (result && para_return) + *para_return = para; + + return result; + } + + height += para->height; + para_list = para_list->next; + } + PING(); + + return FALSE; +} + +/* Given a paragraph and offset in that paragraph, find the + * bounding rectangle for the character at the offset. + */ +void +char_bounds (Paragraph *para, int index, int width, PangoRectangle *rect) +{ + GList *para_list; + + int height = 0; + + para_list = paragraphs; + while (para_list) + { + Paragraph *cur_para = para_list->data; + + if (cur_para == para) + { + PangoRectangle pos; + + pango_layout_index_to_pos (cur_para->layout, index, &pos); + + rect->x = MIN (pos.x, pos.x + pos.width) / 1000; + rect->width = ABS (pos.width) / 1000; + rect->y = height + pos.y / 1000; + rect->height = pos.height / 1000; + } + + height += cur_para->height; + para_list = para_list->next; + } +} + +/* XOR a rectangle over a given character + */ +void +xor_char (GtkWidget *layout, GdkRectangle *clip_rect, + Paragraph *para, int offset) +{ + static GdkGC *gc; + PangoRectangle rect; /* GdkRectangle in 1.2 is too limited + */ + if (!gc) + { + GdkGCValues values; + values.foreground = layout->style->white.pixel ? + layout->style->white : layout->style->black; + values.function = GDK_XOR; + gc = gdk_gc_new_with_values (GTK_LAYOUT (layout)->bin_window, + &values, + GDK_GC_FOREGROUND | GDK_GC_FUNCTION); + } + + gdk_gc_set_clip_rectangle (gc, clip_rect); + + char_bounds (para, offset, layout->allocation.width, &rect); + + rect.y -= GTK_LAYOUT (layout)->yoffset; + + if ((rect.y + rect.height >= 0) && (rect.y < layout->allocation.height)) + gdk_draw_rectangle (GTK_LAYOUT (layout)->bin_window, gc, TRUE, + rect.x, rect.y, rect.width, rect.height); +} + +/* Handle a size allocation by re-laying-out each paragraph to + * the new width, setting the new size for the layout and + * then queing a redraw + */ +void +size_allocate (GtkWidget *layout, GtkAllocation *allocation) +{ + GList *tmp_list; + int height = 0; + PangoDirection base_dir = pango_context_get_base_dir (context); + + PING(); + tmp_list = paragraphs; + while (tmp_list) + { + Paragraph *para = tmp_list->data; + PangoRectangle logical_rect; + + tmp_list = tmp_list->next; + + pango_layout_set_alignment (para->layout, + base_dir == PANGO_DIRECTION_LTR ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); + pango_layout_set_width (para->layout, layout->allocation.width * 1000); + + pango_layout_get_extents (para->layout, NULL, &logical_rect); + para->height = logical_rect.height / 1000; + + height += para->height; + } + + gtk_layout_set_size (GTK_LAYOUT (layout), allocation->width, height); + + if (GTK_LAYOUT (layout)->yoffset + allocation->height > height) + gtk_adjustment_set_value (GTK_LAYOUT (layout)->vadjustment, height - allocation->height); +} + +/* Handle a draw/expose by finding the paragraphs that intersect + * the region and reexposing them. + */ +void +draw (GtkWidget *layout, GdkRectangle *area) +{ + GList *tmp_list; + int height = 0; + + PING(); + gdk_draw_rectangle (GTK_LAYOUT (layout)->bin_window, + layout->style->base_gc[layout->state], + TRUE, + area->x, area->y, + area->width, area->height); + + gdk_gc_set_clip_rectangle (layout->style->text_gc[layout->state], area); + + PING(); + tmp_list = paragraphs; + while (tmp_list && + height < area->y + area->height + GTK_LAYOUT (layout)->yoffset) + { + Paragraph *para = tmp_list->data; + tmp_list = tmp_list->next; + + PING(); + if (height + para->height >= GTK_LAYOUT (layout)->yoffset + area->y) + { + GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_BACKGROUND; + HDC hdc = gdk_win32_hdc_get (GDK_WINDOW_XWINDOW (GTK_LAYOUT (layout)->bin_window), + layout->style->text_gc[GTK_STATE_NORMAL], + mask); + + pango_win32_render_layout (hdc, para->layout, + 0, height - GTK_LAYOUT (layout)->yoffset); + + gdk_win32_hdc_release (GDK_WINDOW_XWINDOW (GTK_LAYOUT (layout)->bin_window), + layout->style->text_gc[GTK_STATE_NORMAL], + mask); + } + + height += para->height; + } + + PING(); + gdk_gc_set_clip_rectangle (layout->style->text_gc[layout->state], NULL); + + if (highlight_para) + xor_char (layout, area, highlight_para, highlight_offset); + PING(); +} + +gboolean +expose (GtkWidget *layout, GdkEventExpose *event) +{ + PING(); + if (event->window == GTK_LAYOUT (layout)->bin_window) + draw (layout, &event->area); + + return TRUE; +} + +void +button_press (GtkWidget *layout, GdkEventButton *event) +{ + Paragraph *para = NULL; + int offset; + gchar *message; + + PING(); + xy_to_cp (layout->allocation.width, + event->x, event->y + GTK_LAYOUT (layout)->yoffset, + ¶, &offset); + + if (highlight_para) + xor_char (layout, NULL, highlight_para, highlight_offset); + + highlight_para = para; + highlight_offset = offset; + + if (para) + { + gunichar wc; + + wc = g_utf8_get_char (para->text + offset); + message = g_strdup_printf ("Current char: U%04x", wc); + + xor_char (layout, NULL, highlight_para, highlight_offset); + } + else + message = g_strdup_printf ("Current char:"); + + PING(); + gtk_label_set_text (GTK_LABEL (message_label), message); + g_free (message); +} + +static void +checkbutton_toggled (GtkWidget *widget, gpointer data) +{ + GList *para_list; + + PING(); + pango_context_set_base_dir (context, GTK_TOGGLE_BUTTON (widget)->active ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR); + + para_list = paragraphs; + while (para_list) + { + Paragraph *para = para_list->data; + + pango_layout_context_changed (para->layout); + para_list = para_list->next; + } + + gtk_widget_queue_resize (layout); +} + +static void +reload_font () +{ + GList *para_list; + + PING(); + pango_context_set_font_description (context, &font_description); + + para_list = paragraphs; + while (para_list) + { + Paragraph *para = para_list->data; + + pango_layout_context_changed (para->layout); + para_list = para_list->next; + } + + if (layout) + gtk_widget_queue_resize (layout); + PING(); +} + +void +set_family (GtkWidget *entry, gpointer data) +{ + font_description.family_name = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + fill_styles_combo (styles_combo); +} + +void +set_style (GtkWidget *entry, gpointer data) +{ + char *str = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + PangoFontDescription *tmp_desc; + + PING(); + tmp_desc = pango_font_description_from_string (str); + + font_description.style = tmp_desc->style; + font_description.variant = tmp_desc->variant; + font_description.weight = tmp_desc->weight; + font_description.stretch = tmp_desc->stretch; + + pango_font_description_free (tmp_desc); + g_free (str); + + reload_font (); +} + +void +font_size_changed (GtkAdjustment *adj) +{ + PING(); + font_description.size = (int)(adj->value * PANGO_SCALE + 0.5); + reload_font(); +} + +static int +compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b) +{ + int val = strcmp (a->family_name, b->family_name); + if (val != 0) + return val; + + if (a->weight != b->weight) + return a->weight - b->weight; + + if (a->style != b->style) + return a->style - b->style; + + if (a->stretch != b->stretch) + return a->stretch - b->stretch; + + if (a->variant != b->variant) + return a->variant - b->variant; + + return 0; +} + +static int +font_description_sort_func (const void *a, const void *b) +{ + return compare_font_descriptions (*(PangoFontDescription **)a, *(PangoFontDescription **)b); +} + +typedef struct +{ + PangoFontDescription **descs; + int n_descs; +} FontDescInfo; + +static void +free_info (FontDescInfo *info) +{ + pango_font_descriptions_free (info->descs, info->n_descs); +} + +static void +fill_styles_combo (GtkWidget *combo) +{ + int i; + GList *style_list = NULL; + + FontDescInfo *info = g_new (FontDescInfo, 1); + PING(); + pango_context_list_fonts (context, font_description.family_name, &info->descs, &info->n_descs); + gtk_object_set_data_full (GTK_OBJECT (combo), "descs", info, (GtkDestroyNotify)free_info); + PING(); + + qsort (info->descs, info->n_descs, sizeof(PangoFontDescription *), font_description_sort_func); + + PING(); + for (i=0; i<info->n_descs; i++) + { + char *str; + + PangoFontDescription tmp_desc; + + tmp_desc = *info->descs[i]; + tmp_desc.family_name = NULL; + tmp_desc.size = 0; + + str = pango_font_description_to_string (&tmp_desc); + style_list = g_list_prepend (style_list, str); + } + + style_list = g_list_reverse (style_list); + + PING(); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), style_list); + g_list_foreach (style_list, (GFunc)g_free, NULL); +} + +static GtkWidget * +make_styles_combo () +{ + GtkWidget *combo; + + PING(); + combo = gtk_combo_new (); + gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE); + gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (combo)->entry), FALSE); + + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", + GTK_SIGNAL_FUNC (set_style), NULL); + + styles_combo = combo; + fill_styles_combo (combo); + + PING(); + return combo; +} + +static int +cmp_strings (const void *a, const void *b) +{ + return strcmp (*(const char **)a, *(const char **)b); +} + +GtkWidget * +make_families_menu () +{ + GtkWidget *combo; + gchar **families; + int n_families; + GList *family_list = NULL; + int i; + + PING(); + pango_context_list_families (context, &families, &n_families); + qsort (families, n_families, sizeof(char *), cmp_strings); + + PING(); + for (i=0; i<n_families; i++) + family_list = g_list_prepend (family_list, families[i]); + + family_list = g_list_reverse (family_list); + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), family_list); + gtk_combo_set_value_in_list (GTK_COMBO (combo), TRUE, FALSE); + gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (combo)->entry), FALSE); + + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), font_description.family_name); + + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", + GTK_SIGNAL_FUNC (set_family), NULL); + + g_list_free (family_list); + pango_font_map_free_families (families, n_families); + + PING(); + return combo; +} + + +GtkWidget * +make_font_selector (void) +{ + GtkWidget *hbox; + GtkWidget *util_hbox; + GtkWidget *label; + GtkWidget *option_menu; + GtkWidget *spin_button; + GtkAdjustment *adj; + + hbox = gtk_hbox_new (FALSE, 4); + + util_hbox = gtk_hbox_new (FALSE, 2); + label = gtk_label_new ("Family:"); + gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0); + option_menu = make_families_menu (); + gtk_box_pack_start (GTK_BOX (util_hbox), option_menu, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0); + + util_hbox = gtk_hbox_new (FALSE, 2); + label = gtk_label_new ("Style:"); + gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0); + option_menu = make_styles_combo (); + gtk_box_pack_start (GTK_BOX (util_hbox), option_menu, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0); + + util_hbox = gtk_hbox_new (FALSE, 2); + label = gtk_label_new ("Size:"); + gtk_box_pack_start (GTK_BOX (util_hbox), label, FALSE, FALSE, 0); + spin_button = gtk_spin_button_new (NULL, 1., 0); + gtk_box_pack_start (GTK_BOX (util_hbox), spin_button, FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (hbox), util_hbox, FALSE, FALSE, 0); + + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin_button)); + adj->value = font_description.size / 1000.; + adj->lower = 0; + adj->upper = 1024; + adj->step_increment = 1; + adj->page_size = 10; + gtk_adjustment_changed (adj); + gtk_adjustment_value_changed (adj); + + gtk_signal_connect (GTK_OBJECT (adj), "value_changed", + GTK_SIGNAL_FUNC (font_size_changed), NULL); + + return hbox; +} + +int +main (int argc, char **argv) +{ + char *text; + GtkWidget *window; + GtkWidget *scrollwin; + GtkWidget *vbox, *hbox; + GtkWidget *frame; + GtkWidget *checkbutton; + + gtk_init (&argc, &argv); + + if (argc != 2) + { + fprintf (stderr, "Usage: %s FILE\n", g_get_prgname ()); + exit(1); + } + + /* Create the list of paragraphs from the supplied file + */ + text = read_file (argv[1]); + if (!text) + exit(1); + + context = pango_win32_get_context (); + + paragraphs = split_paragraphs (text); + + pango_context_set_lang (context, "en_US"); + pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); + + font_description.family_name = g_strdup ("sans"); + font_description.style = PANGO_STYLE_NORMAL; + font_description.variant = PANGO_VARIANT_NORMAL; + font_description.weight = 500; + font_description.stretch = PANGO_STRETCH_NORMAL; + font_description.size = 16000; + + pango_context_set_font_description (context, &font_description); + + /* Create the user interface + */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 400, 400); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_add (GTK_CONTAINER (window), vbox); + + hbox = make_font_selector (); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + scrollwin = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0); + + layout = gtk_layout_new (NULL, NULL); + gtk_widget_set_events (layout, GDK_BUTTON_PRESS_MASK); + gtk_widget_set_app_paintable (layout, TRUE); + + gtk_signal_connect (GTK_OBJECT (layout), "size_allocate", + GTK_SIGNAL_FUNC (size_allocate), paragraphs); + gtk_signal_connect (GTK_OBJECT (layout), "expose_event", + GTK_SIGNAL_FUNC (expose), paragraphs); + gtk_signal_connect (GTK_OBJECT (layout), "draw", + GTK_SIGNAL_FUNC (draw), paragraphs); + gtk_signal_connect (GTK_OBJECT (layout), "button_press_event", + GTK_SIGNAL_FUNC (button_press), paragraphs); + + gtk_container_add (GTK_CONTAINER (scrollwin), layout); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + + PING(); + message_label = gtk_label_new ("Current char:"); + gtk_misc_set_padding (GTK_MISC (message_label), 1, 1); + gtk_misc_set_alignment (GTK_MISC (message_label), 0.0, 0.5); + gtk_container_add (GTK_CONTAINER (frame), message_label); + + checkbutton = gtk_check_button_new_with_label ("Use RTL global direction"); + gtk_signal_connect (GTK_OBJECT (checkbutton), "toggled", + GTK_SIGNAL_FUNC (checkbutton_toggled), NULL); + gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0); + + gtk_widget_show_all (window); + + PING(); + gtk_main (); + + return 0; +} diff --git a/modules/basic/basic-win32.c b/modules/basic/basic-win32.c new file mode 100644 index 00000000..d174d9e1 --- /dev/null +++ b/modules/basic/basic-win32.c @@ -0,0 +1,363 @@ +/* Pango + * basic-win32.c: + * + * 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 <glib.h> +#include "pango.h" +#include "pangowin32.h" +#include <fribidi/fribidi.h> + +typedef struct _CharCache CharCache; + +#define MAX_CHARSETS 32 + +struct _CharCache +{ + int n_subfonts; + PangoWin32Subfont *subfonts; +}; + +static PangoEngineRange basic_ranges[] = { + /* Language characters */ + { 0x0000, 0x02af, "*" }, + { 0x02b0, 0x02ff, "" }, + { 0x0380, 0x058f, "*" }, + { 0x0591, 0x05f4, "*" }, /* Hebrew */ + { 0x060c, 0x06f9, "" }, /* Arabic */ + { 0x0e01, 0x0e5b, "" }, /* Thai */ + { 0x1e00, 0x1fff, "*" }, + { 0x2000, 0x9fff, "*" }, + { 0xac00, 0xd7a3, "kr" }, + { 0xf900, 0xfa0b, "kr" }, + { 0xff00, 0xffe3, "*" } +}; + +static PangoEngineInfo script_engines[] = { + { + "BasicScriptEngineLang", + PANGO_ENGINE_TYPE_LANG, + PANGO_RENDER_TYPE_NONE, + basic_ranges, G_N_ELEMENTS(basic_ranges) + }, + { + "BasicScriptEngineWin32", + PANGO_ENGINE_TYPE_SHAPE, + PANGO_RENDER_TYPE_WIN32, + basic_ranges, G_N_ELEMENTS(basic_ranges) + } +}; + +static gint n_script_engines = G_N_ELEMENTS (script_engines); + +/* + * Language script engine + */ + +static void +basic_engine_break (const char *text, + gint len, + PangoAnalysis *analysis, + PangoLogAttr *attrs) +{ +} + +static PangoEngine * +basic_engine_lang_new () +{ + PangoEngineLang *result; + + result = g_new (PangoEngineLang, 1); + + result->engine.id = "BasicScriptEngine"; + result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.length = sizeof (result); + result->script_break = basic_engine_break; + + return (PangoEngine *)result; +} + +/* + * Win32 system script engine portion + */ + +static CharCache * +char_cache_new (void) +{ + CharCache *result; + int i; + + result = g_new (CharCache, 1); + result->subfonts = NULL; + + return result; +} + +static void +char_cache_free (CharCache *cache) +{ + g_free (cache->subfonts); + g_free (cache); +} + +static PangoGlyph +find_char (CharCache *cache, PangoFont *font, gunichar wc) +{ + PangoWin32UnicodeSubrange subrange; + PangoWin32Subfont *subfonts; + int i; + int n_subfonts; + + subrange = pango_win32_unicode_classify (wc); + + n_subfonts = pango_win32_list_subfonts (font, subrange, &subfonts); + + for (i=0; i<n_subfonts; i++) + { + PangoGlyph glyph; + + glyph = PANGO_WIN32_MAKE_GLYPH (subfonts[i], wc); + + if (pango_win32_has_glyph (font, glyph)) + return glyph; + } + + return 0; +} + +static void +set_glyph (PangoFont *font, PangoGlyphString *glyphs, int i, int offset, PangoGlyph glyph) +{ + PangoRectangle logical_rect; + + glyphs->glyphs[i].glyph = glyph; + + glyphs->glyphs[i].geometry.x_offset = 0; + glyphs->glyphs[i].geometry.y_offset = 0; + + glyphs->log_clusters[i] = offset; + + pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect); + glyphs->glyphs[i].geometry.width = logical_rect.width; +} + +static void +swap_range (PangoGlyphString *glyphs, int start, int end) +{ + int i, j; + + for (i = start, j = end - 1; i < j; i++, j--) + { + PangoGlyphInfo glyph_info; + gint log_cluster; + + glyph_info = glyphs->glyphs[i]; + glyphs->glyphs[i] = glyphs->glyphs[j]; + glyphs->glyphs[j] = glyph_info; + + log_cluster = glyphs->log_clusters[i]; + glyphs->log_clusters[i] = glyphs->log_clusters[j]; + glyphs->log_clusters[j] = log_cluster; + } +} + +static CharCache * +get_char_cache (PangoFont *font) +{ + GQuark cache_id = g_quark_from_string ("basic-char-cache"); + + CharCache *cache = g_object_get_qdata (G_OBJECT (font), cache_id); + if (!cache) + { + cache = char_cache_new (); + g_object_set_qdata_full (G_OBJECT (font), cache_id, + cache, (GDestroyNotify)char_cache_free); + } + + return cache; +} + +static void +basic_engine_shape (PangoFont *font, + const char *text, + gint length, + PangoAnalysis *analysis, + PangoGlyphString *glyphs) +{ + int n_chars; + int i; + const char *p; + + CharCache *cache; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + g_return_if_fail (length >= 0); + g_return_if_fail (analysis != NULL); + + cache = get_char_cache (font); + + n_chars = g_utf8_strlen (text, length); + pango_glyph_string_set_size (glyphs, n_chars); + + p = text; + for (i=0; i < n_chars; i++) + { + gunichar wc; + FriBidiChar mirrored_ch; + PangoGlyph index; + char buf[6]; + const char *input; + + wc = g_utf8_get_char (p); + + input = p; + if (analysis->level % 2) + if (fribidi_get_mirror_char (wc, &mirrored_ch)) + { + wc = mirrored_ch; + + g_unichar_to_utf8 (wc, buf); + input = buf; + } + + if (wc == 0x200B || wc == 0x200E || wc == 0x200F) /* Zero-width characters */ + { + set_glyph (font, glyphs, i, p - text, 0); + } + else + { + index = find_char (cache, font, wc); + if (index) + { + set_glyph (font, glyphs, i, p - text, index); + + if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK) + { + if (i > 0) + { + PangoRectangle logical_rect, ink_rect; + + glyphs->glyphs[i].geometry.width = MAX (glyphs->glyphs[i-1].geometry.width, + glyphs->glyphs[i].geometry.width); + glyphs->glyphs[i-1].geometry.width = 0; + glyphs->log_clusters[i] = glyphs->log_clusters[i-1]; + + /* Some heuristics to try to guess how overstrike glyphs are + * done and compensate + */ + pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect); + if (logical_rect.width == 0 && ink_rect.x == 0) + glyphs->glyphs[i].geometry.x_offset = (glyphs->glyphs[i].geometry.width - ink_rect.width) / 2; + } + } + } + else + set_glyph (font, glyphs, i, p - text, pango_win32_get_unknown_glyph (font)); + } + + p = g_utf8_next_char (p); + } + + /* Simple bidi support... may have separate modules later */ + + if (analysis->level % 2) + { + int start, end; + + /* Swap all glyphs */ + swap_range (glyphs, 0, n_chars); + + /* Now reorder glyphs within each cluster back to LTR */ + for (start=0; start<n_chars;) + { + end = start; + while (end < n_chars && + glyphs->log_clusters[end] == glyphs->log_clusters[start]) + end++; + + swap_range (glyphs, start, end); + start = end; + } + } +} + +static PangoCoverage * +basic_engine_get_coverage (PangoFont *font, + const char *lang) +{ + CharCache *cache = get_char_cache (font); + PangoCoverage *result = pango_coverage_new (); + gunichar wc; + + for (wc = 0; wc < 65536; wc++) + if (find_char (cache, font, wc)) + pango_coverage_set (result, wc, PANGO_COVERAGE_EXACT); + + return result; +} + +static PangoEngine * +basic_engine_win32_new () +{ + PangoEngineShape *result; + + result = g_new (PangoEngineShape, 1); + + result->engine.id = "BasicScriptEngine"; + result->engine.type = PANGO_ENGINE_TYPE_LANG; + result->engine.length = sizeof (result); + result->script_shape = basic_engine_shape; + result->get_coverage = basic_engine_get_coverage; + + return (PangoEngine *)result; +} + +/* The following three functions provide the public module API for + * Pango + */ +#ifdef MODULE_PREFIX +#define MODULE_ENTRY(func) _pango_basic_##func +#else +#define MODULE_ENTRY(func) func +#endif + +void +MODULE_ENTRY(script_engine_list) (PangoEngineInfo **engines, gint *n_engines) +{ + *engines = script_engines; + *n_engines = n_script_engines; +} + +PangoEngine * +MODULE_ENTRY(script_engine_load) (const char *id) +{ + if (!strcmp (id, "BasicScriptEngineLang")) + return basic_engine_lang_new (); + else if (!strcmp (id, "BasicScriptEngineWin32")) + return basic_engine_win32_new (); + else + return NULL; +} + +void +MODULE_ENTRY(script_engine_unload) (PangoEngine *engine) +{ +} + diff --git a/modules/basic/makefile.mingw b/modules/basic/makefile.mingw new file mode 100644 index 00000000..60377b99 --- /dev/null +++ b/modules/basic/makefile.mingw @@ -0,0 +1,21 @@ +PANGO_VER = 0.12 + +TOP = ../../.. + +include $(TOP)/build/win32/make.mingw + +OPTIMIZE = -g + +INCLUDES = -I ../../pango -I ../.. +DEFINES = +DEPCFLAGS = $(GLIB_CFLAGS) $(FRIBIDI_CFLAGS) + +all : \ + ../../config.h \ + pango-basic-win32.dll + +../../config.h : ../../config.h.win32 + cp $< $@ + +pango-basic-win32.dll : basic-win32.o + $(GLIB)/build-dll pango-basic-win32 - ../engine.def $< -L ../../pango -lpango-$(PANGO_VER) -lpangowin32-$(PANGO_VER) $(GLIB_LIBS) $(FRIBIDI_LIBS) 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); } |