diff options
Diffstat (limited to 'pango')
-rw-r--r-- | pango/Makefile.am | 21 | ||||
-rw-r--r-- | pango/makefile.mingw.in (renamed from pango/makefile.mingw) | 70 | ||||
-rw-r--r-- | pango/pango-utils.c | 74 | ||||
-rw-r--r-- | pango/pango-utils.h | 16 | ||||
-rw-r--r-- | pango/pangoft2-fontcache.c | 305 | ||||
-rw-r--r-- | pango/pangoft2-fontmap.c | 1110 | ||||
-rw-r--r-- | pango/pangoft2-private.h | 97 | ||||
-rw-r--r-- | pango/pangoft2.c | 1126 | ||||
-rw-r--r-- | pango/pangoft2.h | 107 | ||||
-rw-r--r-- | pango/pangowin32-fontmap.c | 104 | ||||
-rw-r--r-- | pango/pangowin32.c | 27 | ||||
-rw-r--r-- | pango/pangowin32.h | 93 | ||||
-rw-r--r-- | pango/pangox-fontmap.c | 8 |
13 files changed, 2969 insertions, 189 deletions
diff --git a/pango/Makefile.am b/pango/Makefile.am index ee780e98..df653b17 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -66,10 +66,19 @@ pango_querymodules_SOURCES = \ querymodules.c pango_querymodules_LDADD = libpangox.la libpango.la $(GLIB_LIBS) $(FRIBIDI_LIBS) $(UNICODE_LIBS) $(X_LIBS) -EXTRA_DIST = \ - pangowin32.h \ - pangowin32.c \ - pangowin32-private.h \ - pangowin32-fontcache.c \ - pangowin32-fontmap.c +EXTRA_DIST = \ + pangowin32.h \ + pangowin32.c \ + pangowin32-private.h \ + pangowin32-fontcache.c \ + pangowin32-fontmap.c \ + pangoft2.h \ + pangoft2.c \ + pangoft2-private.h \ + pangoft2-fontcache.c \ + pangoft2-fontmap.c \ + makefile.mingw \ + makefile.mingw.in +makefile.mingw: $(top_builddir)/config.status $(top_srcdir)/pango/makefile.mingw.in + cd $(top_builddir) && CONFIG_FILES=pango/$@ CONFIG_HEADERS= $(SHELL) ./config.status diff --git a/pango/makefile.mingw b/pango/makefile.mingw.in index dca8e55d..3bcc4beb 100644 --- a/pango/makefile.mingw +++ b/pango/makefile.mingw.in @@ -1,44 +1,51 @@ -PANGO_VER = 0.12 - TOP = ../.. include $(TOP)/build/win32/make.mingw -OPTIMIZE = -g +# Possibly override Pango version from build/win32/module.defs +PANGO_VER = @VERSION@ + +OPTIMIZE = -g -Wall INCLUDES = -I .. -I . DEFINES = -DEPCFLAGS = $(GLIB_CFLAGS) $(LIBICONV_CFLAGS) $(FRIBIDI_CFLAGS) +DEPCFLAGS = $(GLIB_CFLAGS) $(LIBICONV_CFLAGS) $(FRIBIDI_CFLAGS) $(FREETYPE2_CFLAGS) -all : \ - ../config.h \ - pango-$(PANGO_VER).dll \ - pangowin32-$(PANGO_VER).dll \ +all : \ + ../config.h \ + pango-$(PANGO_VER).dll \ + pangowin32-$(PANGO_VER).dll \ + pangoft2-$(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 \ +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_OBJS = \ + pangowin32.o \ + pangowin32-fontcache.o \ pangowin32-fontmap.o -PANGO_QUERYMODULES_OBJS = \ +PANGOFT2_OBJS = \ + pangoft2.o \ + pangoft2-fontcache.o \ + pangoft2-fontmap.o + +PANGO_QUERYMODULES_OBJS = \ querymodules.o ../config.h : ../config.h.win32 @@ -53,7 +60,10 @@ pango-$(PANGO_VER).dll : $(PANGO_OBJS) pango.def pangowin32-$(PANGO_VER).dll : $(PANGOWIN32_OBJS) pangowin32.def $(GLIB)/build-dll pangowin32 $(PANGO_VER) pangowin32.def $(OPTIMIZE) $(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 +pangoft2-$(PANGO_VER).dll : $(PANGOFT2_OBJS) pangoft2.def + $(GLIB)/build-dll pangoft2 $(PANGO_VER) pangoft2.def $(OPTIMIZE) $(PANGOFT2_OBJS) -L . -lpango-$(PANGO_VER) $(GLIB_LIBS) $(FRIBIDI_LIBS) $(FREETYPE2_LIBS) -lgdi32 + +pango-querymodules.exe : $(PANGO_QUERYMODULES_OBJS) pango-$(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 @@ -71,3 +81,7 @@ test4.exe : test4.o pango-$(PANGO_VER).dll pangowin32-$(PANGO_VER).dll test5.exe : test5.o $(CC) -o $@ $(CFLAGS) test5.o -lgdi32 +# Hack to get an updated makefile.mingw automatically after updating +# makefile.mingw.in. Only for developer use. +makefile.mingw: makefile.mingw.in + sed -e 's,@VER[S]ION@,@VERSION@,' <$< >$@ diff --git a/pango/pango-utils.c b/pango/pango-utils.c index f48b197b..807adac8 100644 --- a/pango/pango-utils.c +++ b/pango/pango-utils.c @@ -657,7 +657,8 @@ pango_get_lib_subdirectory (void) gboolean pango_parse_style (GString *str, - PangoFontDescription *desc) + PangoFontDescription *desc, + gboolean warn) { if (str->len == 0) return FALSE; @@ -666,35 +667,37 @@ pango_parse_style (GString *str, { case 'n': case 'N': - if (strncasecmp (str->str, "normal", str->len) == 0) + if (g_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) + if (g_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) + if (g_strncasecmp (str->str, "oblique", str->len) == 0) { desc->style = PANGO_STYLE_OBLIQUE; return TRUE; } break; } - g_warning ("Style must be normal, italic, or oblique"); + if (warn) + g_warning ("Style must be normal, italic, or oblique"); return FALSE; } gboolean pango_parse_variant (GString *str, - PangoFontDescription *desc) + PangoFontDescription *desc, + gboolean warn) { if (str->len == 0) return FALSE; @@ -703,7 +706,7 @@ pango_parse_variant (GString *str, { case 'n': case 'N': - if (strncasecmp (str->str, "normal", str->len) == 0) + if (g_strncasecmp (str->str, "normal", str->len) == 0) { desc->variant = PANGO_VARIANT_NORMAL; return TRUE; @@ -711,7 +714,8 @@ pango_parse_variant (GString *str, break; case 's': case 'S': - if (strncasecmp (str->str, "small_caps", str->len) == 0) + if (g_strncasecmp (str->str, "small_caps", str->len) == 0 || + g_strncasecmp (str->str, "smallcaps", str->len) == 0) { desc->variant = PANGO_VARIANT_SMALL_CAPS; return TRUE; @@ -719,13 +723,15 @@ pango_parse_variant (GString *str, break; } - g_warning ("Variant must be normal, or small_caps"); + if (warn) + g_warning ("Variant must be normal or small_caps"); return FALSE; } gboolean pango_parse_weight (GString *str, - PangoFontDescription *desc) + PangoFontDescription *desc, + gboolean warn) { if (str->len == 0) return FALSE; @@ -734,7 +740,7 @@ pango_parse_weight (GString *str, { case 'b': case 'B': - if (strncasecmp (str->str, "bold", str->len) == 0) + if (g_strncasecmp (str->str, "bold", str->len) == 0) { desc->weight = PANGO_WEIGHT_BOLD; return TRUE; @@ -742,7 +748,7 @@ pango_parse_weight (GString *str, break; case 'h': case 'H': - if (strncasecmp (str->str, "heavy", str->len) == 0) + if (g_strncasecmp (str->str, "heavy", str->len) == 0) { desc->weight = PANGO_WEIGHT_HEAVY; return TRUE; @@ -750,7 +756,7 @@ pango_parse_weight (GString *str, break; case 'l': case 'L': - if (strncasecmp (str->str, "light", str->len) == 0) + if (g_strncasecmp (str->str, "light", str->len) == 0) { desc->weight = PANGO_WEIGHT_LIGHT; return TRUE; @@ -758,7 +764,7 @@ pango_parse_weight (GString *str, break; case 'n': case 'N': - if (strncasecmp (str->str, "normal", str->len) == 0) + if (g_strncasecmp (str->str, "normal", str->len) == 0) { desc->weight = PANGO_WEIGHT_NORMAL; return TRUE; @@ -766,12 +772,12 @@ pango_parse_weight (GString *str, break; case 'u': case 'U': - if (strncasecmp (str->str, "ultralight", str->len) == 0) + if (g_strncasecmp (str->str, "ultralight", str->len) == 0) { desc->weight = PANGO_WEIGHT_ULTRALIGHT; return TRUE; } - else if (strncasecmp (str->str, "ultrabold", str->len) == 0) + else if (g_strncasecmp (str->str, "ultrabold", str->len) == 0) { desc->weight = PANGO_WEIGHT_ULTRABOLD; return TRUE; @@ -795,7 +801,8 @@ pango_parse_weight (GString *str, desc->weight = strtol (numstr, &end, 0); if (*end != '\0') { - g_warning ("Cannot parse numerical weight '%s'", numstr); + if (warn) + g_warning ("Cannot parse numerical weight '%s'", numstr); g_free (numstr); return FALSE; } @@ -805,13 +812,15 @@ pango_parse_weight (GString *str, } } - g_warning ("Weight must be ultralight, light, normal, bold, ultrabold, heavy, or an integer"); + if (warn) + g_warning ("Weight must be ultralight, light, normal, bold, ultrabold, heavy, or an integer"); return FALSE; } gboolean pango_parse_stretch (GString *str, - PangoFontDescription *desc) + PangoFontDescription *desc, + gboolean warn) { if (str->len == 0) return FALSE; @@ -820,7 +829,7 @@ pango_parse_stretch (GString *str, { case 'c': case 'C': - if (strncasecmp (str->str, "condensed", str->len) == 0) + if (g_strncasecmp (str->str, "condensed", str->len) == 0) { desc->stretch = PANGO_STRETCH_CONDENSED; return TRUE; @@ -828,17 +837,19 @@ pango_parse_stretch (GString *str, break; case 'e': case 'E': - if (strncasecmp (str->str, "extra_condensed", str->len) == 0) + if (g_strncasecmp (str->str, "extra_condensed", str->len) == 0 || + g_strncasecmp (str->str, "extracondensed", str->len) == 0) { desc->stretch = PANGO_STRETCH_EXTRA_CONDENSED; return TRUE; } - if (strncasecmp (str->str, "extra_expanded", str->len) == 0) + if (g_strncasecmp (str->str, "extra_expanded", str->len) == 0 || + g_strncasecmp (str->str, "extraexpanded", str->len) == 0) { desc->stretch = PANGO_STRETCH_EXTRA_EXPANDED; return TRUE; } - if (strncasecmp (str->str, "expanded", str->len) == 0) + if (g_strncasecmp (str->str, "expanded", str->len) == 0) { desc->stretch = PANGO_STRETCH_EXPANDED; return TRUE; @@ -846,7 +857,7 @@ pango_parse_stretch (GString *str, break; case 'n': case 'N': - if (strncasecmp (str->str, "normal", str->len) == 0) + if (g_strncasecmp (str->str, "normal", str->len) == 0) { desc->stretch = PANGO_STRETCH_NORMAL; return TRUE; @@ -854,12 +865,14 @@ pango_parse_stretch (GString *str, break; case 's': case 'S': - if (strncasecmp (str->str, "semi_condensed", str->len) == 0) + if (g_strncasecmp (str->str, "semi_condensed", str->len) == 0 || + g_strncasecmp (str->str, "semicondensed", str->len) == 0) { desc->stretch = PANGO_STRETCH_SEMI_CONDENSED; return TRUE; } - if (strncasecmp (str->str, "semi_expanded", str->len) == 0) + if (g_strncasecmp (str->str, "semi_expanded", str->len) == 0 || + g_strncasecmp (str->str, "semiexpanded", str->len) == 0) { desc->stretch = PANGO_STRETCH_SEMI_EXPANDED; return TRUE; @@ -867,12 +880,14 @@ pango_parse_stretch (GString *str, break; case 'u': case 'U': - if (strncasecmp (str->str, "ultra_condensed", str->len) == 0) + if (g_strncasecmp (str->str, "ultra_condensed", str->len) == 0 || + g_strncasecmp (str->str, "ultracondensed", str->len) == 0) { desc->stretch = PANGO_STRETCH_ULTRA_CONDENSED; return TRUE; } - if (strncasecmp (str->str, "ultra_expanded", str->len) == 0) + if (g_strncasecmp (str->str, "ultra_expanded", str->len) == 0 || + g_strncasecmp (str->str, "ultraexpanded", str->len) == 0) { desc->variant = PANGO_STRETCH_ULTRA_EXPANDED; return TRUE; @@ -880,7 +895,8 @@ pango_parse_stretch (GString *str, break; } - g_warning ("Stretch must be ultra_condensed, extra_condensed, condensed, semi_condensed, normal, semi_expanded, expanded, extra_expanded, or ultra_expanded"); + if (warn) + g_warning ("Stretch must be ultra_condensed, extra_condensed, condensed, semi_condensed, normal, semi_expanded, expanded, extra_expanded, or ultra_expanded"); return FALSE; } diff --git a/pango/pango-utils.h b/pango/pango-utils.h index 941ad515..4891767e 100644 --- a/pango/pango-utils.h +++ b/pango/pango-utils.h @@ -41,16 +41,22 @@ char * pango_config_key_get (const char *key); /* Functions for parsing textual representations * of PangoFontDescription fields. They return TRUE if the input string * contains a valid value, which then has been assigned to the corresponding - * field in the PangoFontDescription. + * field in the PangoFontDescription. If the warn parameter is TRUE, + * a warning is printed (with g_warning) if the string does not + * contain a valid value. */ gboolean pango_parse_style (GString *str, - PangoFontDescription *desc); + PangoFontDescription *desc, + gboolean warn); gboolean pango_parse_variant (GString *str, - PangoFontDescription *desc); + PangoFontDescription *desc, + gboolean warn); gboolean pango_parse_weight (GString *str, - PangoFontDescription *desc); + PangoFontDescription *desc, + gboolean warn); gboolean pango_parse_stretch (GString *str, - PangoFontDescription *desc); + PangoFontDescription *desc, + gboolean warn); /* On Unix, return the name of the "pango" subdirectory of SYSCONFDIR * (which is set at compile time). On Win32, return the Pango diff --git a/pango/pangoft2-fontcache.c b/pango/pangoft2-fontcache.c new file mode 100644 index 00000000..4f7f82b5 --- /dev/null +++ b/pango/pangoft2-fontcache.c @@ -0,0 +1,305 @@ +/* Pango + * pangoft2-fontcache.c: Cache of FreeType2 faces (FT_Face) + * + * 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 "pangoft2-private.h" + +/* Font cache + */ + +/* Number of fonts to retain after they are not otherwise referenced. + */ +#define CACHE_SIZE 3 + +typedef struct _CacheEntry CacheEntry; + +struct _PangoFT2FontCache +{ + FT_Library library; + + GHashTable *forward; + GHashTable *back; + + GList *mru; + GList *mru_tail; + int mru_count; +}; + +struct _CacheEntry +{ + PangoFT2OA oa; + FT_Face face; + + gint ref_count; + GList *mru; +}; + +static void +free_cache_entry (PangoFT2OA *oa, + CacheEntry *entry, + PangoFT2FontCache *cache) +{ + FT_Error error; + + PING (("FT_Done_Face (%p)\n", entry->face)); + + error = FT_Done_Face (entry->face); + if (error != FT_Err_Ok) + g_warning ("Error from FT_Done_Face: %s", + pango_ft2_ft_strerror (error)); + + g_free (entry); +} + +/** + * pango_ft2_font_cache_free: + * @cache: a #PangoFT2FontCache + * + * Free a #PangoFT2FontCache and all associated memory. All fonts loaded + * through this font cache will be freed along with the cache. + **/ +void +pango_ft2_font_cache_free (PangoFT2FontCache *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 +oa_hash (gconstpointer v) +{ + PangoFT2OA *oa = (PangoFT2OA *) v; + + if (oa->open_args->flags & ft_open_memory) + return (guint) oa->open_args->memory_base; + else if (oa->open_args->flags == ft_open_pathname) + return g_str_hash (oa->open_args->pathname); + else if (oa->open_args->flags & ft_open_stream) + return (guint) oa->open_args->stream; + else + return 0; +} + +static gint +oa_equal (gconstpointer v1, + gconstpointer v2) +{ + PangoFT2OA *oa1 = (PangoFT2OA *) v1; + PangoFT2OA *oa2 = (PangoFT2OA *) v2; + + if (oa1->open_args->flags != oa2->open_args->flags) + return 0; + else if (oa1->open_args->flags & ft_open_memory) + return (oa1->open_args->memory_base == oa2->open_args->memory_base && + oa1->face_index == oa2->face_index); + else if (oa1->open_args->flags == ft_open_pathname) + return (strcmp (oa1->open_args->pathname, + oa2->open_args->pathname) == 0 && + oa1->face_index == oa2->face_index); + else if (oa1->open_args->flags & ft_open_stream) + return (oa1->open_args->stream == oa2->open_args->stream && + oa1->face_index == oa2->face_index); + else + return 0; +} + +/** + * pango_ft2_font_cache_new: + * + * Create a font cache. + * + * Return value: The new font cache. This must be freed with + * pango_ft2_font_cache_free(). + **/ +PangoFT2FontCache * +pango_ft2_font_cache_new (FT_Library library) +{ + PangoFT2FontCache *cache; + + cache = g_new (PangoFT2FontCache, 1); + + cache->library = library; + + cache->forward = g_hash_table_new (oa_hash, oa_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 (PangoFT2FontCache *cache, + CacheEntry *entry) +{ + entry->ref_count--; + PING (("face:%p ref_count:%d\n", entry->face, entry->ref_count)); + if (entry->ref_count == 0) + { + g_hash_table_remove (cache->forward, &entry->oa); + g_hash_table_remove (cache->back, entry->face); + + free_cache_entry (NULL, entry, cache); + } +} + +/** + * pango_ft2_font_cache_load: + * @cache: a #PangoFT2FontCache + * + * Load a #FT_Face from #FT_Open_Args and a face index. The + * result may be newly loaded, or it may have been previously + * stored + * + * Return value: The #FT_Face, or %NULL if the font could + * not be loaded. In order to free this structure, you must call + * pango_ft2_font_cache_unload(). + **/ +FT_Face +pango_ft2_font_cache_load (PangoFT2FontCache *cache, + FT_Open_Args *args, + FT_Long face_index) +{ + CacheEntry *entry; + PangoFT2OA oa; + + g_return_val_if_fail (cache != NULL, NULL); + g_return_val_if_fail (args != NULL, NULL); + + oa.open_args = args; + oa.face_index = face_index; + + entry = g_hash_table_lookup (cache->forward, &oa); + + if (entry) + entry->ref_count++; + else + { + FT_Face face; + FT_Error error; + + PING (("FT_Open_Face (%s,%ld)\n", args->pathname, face_index)); + + error = FT_Open_Face (cache->library, args, face_index, &face); + if (error != FT_Err_Ok) + { + g_warning ("Error from FT_Open_Face: %s", + pango_ft2_ft_strerror (error)); + return NULL; + } + +#if DEBUGGING + g_print (" = %p\n", face); +#endif + + entry = g_new (CacheEntry, 1); + + entry->oa = oa; + entry->face = face; + + entry->ref_count = 1; + entry->mru = NULL; + + g_hash_table_insert (cache->forward, &entry->oa, entry); + g_hash_table_insert (cache->back, entry->face, 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->face; +} + +/** + * pango_ft2_font_cache_unload: + * @cache: a #PangoFT2FontCache + * @face: the face to unload + * + * Free a font structure previously loaded with pango_ft2_font_cache_load() + **/ +void +pango_ft2_font_cache_unload (PangoFT2FontCache *cache, + FT_Face face) +{ + CacheEntry *entry; + + g_return_if_fail (cache != NULL); + g_return_if_fail (face != NULL); + + entry = g_hash_table_lookup (cache->back, face); + g_return_if_fail (entry != NULL); + + PING (("pango_ft2_font_cache_unload\n")); + cache_entry_unref (cache, entry); +} diff --git a/pango/pangoft2-fontmap.c b/pango/pangoft2-fontmap.c new file mode 100644 index 00000000..a81c8639 --- /dev/null +++ b/pango/pangoft2-fontmap.c @@ -0,0 +1,1110 @@ +/* Pango + * pangoft2-fontmap.c: + * + * 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> +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#endif +#include <sys/stat.h> + +#include "pango-fontmap.h" +#include "pango-utils.h" +#include "pangoft2-private.h" + +#define PANGO_TYPE_FT2_FONT_MAP (pango_ft2_font_map_get_type ()) +#define PANGO_FT2_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_FT2_FONT_MAP, PangoFT2FontMap)) +#define PANGO_FT2_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_FONT_MAP, PangoFT2FontMapClass)) +#define PANGO_FT2_IS_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_FT2_FONT_MAP)) +#define PANGO_FT2_IS_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_FONT_MAP)) +#define PANGO_FT2_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_FONT_MAP, PangoFontMapClass)) + +typedef struct _PangoFT2FamilyEntry PangoFT2FamilyEntry; +typedef struct _PangoFT2FontMap PangoFT2FontMap; +typedef struct _PangoFT2FontMapClass PangoFT2FontMapClass; +typedef struct _PangoFT2SizeInfo PangoFT2SizeInfo; + +/* Number of freed fonts */ +#define MAX_FREED_FONTS 16 + +struct _PangoFT2FontMap +{ + PangoFontMap parent_instance; + + FT_Library library; + + PangoFT2FontCache *font_cache; + GQueue *freed_fonts; + + /* Maps Pango family names to PangoFT2FamilyEntry structs */ + GHashTable *families; + + /* Maps the family and style of a face to a PangoFT2OA struct */ + GHashTable *faces; + + int n_fonts; + + double resolution; /* (points / pixel) * PANGO_SCALE */ +}; + +struct _PangoFT2FontMapClass +{ + PangoFontMapClass parent_class; +}; + +struct _PangoFT2FamilyEntry +{ + char *family_name; + + /* List of PangoFT2FontEntry structs */ + GSList *font_entries; +}; + +struct _PangoFT2FontEntry +{ + FT_Open_Args **open_args; + FT_Long *face_indices; + int n_fonts; + PangoFontDescription description; + PangoCoverage *coverage; + + GSList *cached_fonts; +}; + +static GType pango_ft2_font_map_get_type (void); + +static void pango_ft2_font_map_init (PangoFT2FontMap *fontmap); + +static void pango_ft2_font_map_class_init (PangoFT2FontMapClass *class); + +static void pango_ft2_font_map_finalize (GObject *object); + +static PangoFont *pango_ft2_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *description); + +static void pango_ft2_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs); +static void pango_ft2_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families); + +static void pango_ft2_fontmap_cache_clear (PangoFT2FontMap *ft2fontmap); + +static void pango_ft2_font_map_read_aliases (PangoFT2FontMap *ft2fontmap); + +static void pango_ft2_insert_face (PangoFT2FontMap *fontmap, + FT_Face face, + const char *path, + int face_index); + +static PangoFontClass *parent_class; /* Parent class structure for PangoFT2FontMap */ + +static PangoFT2FontMap *pango_ft2_global_fontmap = NULL; +static GSList *pango_ft2_font_directories = NULL; + +static GType +pango_ft2_font_map_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (PangoFT2FontMapClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) pango_ft2_font_map_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PangoFT2FontMap), + 0, /* n_preallocs */ + (GInstanceInitFunc) pango_ft2_font_map_init, + }; + + object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, + "PangoFT2FontMap", + &object_info); + } + + return object_type; +} + +static guint +face_style_hash (gconstpointer v) +{ + PangoFontDescription *desc = (PangoFontDescription *)v; + + return g_str_hash (desc->family_name) + + desc->style + desc->variant + desc->weight + desc->stretch; +} + +static gint +face_style_equal (gconstpointer v1, + gconstpointer v2) +{ + PangoFontDescription *desc1 = (PangoFontDescription *)v1; + PangoFontDescription *desc2 = (PangoFontDescription *)v2; + + return (g_strcasecmp (desc1->family_name, desc2->family_name) == 0 && + desc1->style == desc2->style && + desc1->variant == desc2->variant && + desc1->weight == desc2->weight && + desc1->stretch == desc2->stretch); +} + +static void +pango_ft2_font_map_init (PangoFT2FontMap *ft2fontmap) +{ + ft2fontmap->families = g_hash_table_new (g_str_hash, g_str_equal); + ft2fontmap->faces = g_hash_table_new (face_style_hash, face_style_equal); + ft2fontmap->n_fonts = 0; +} + +static void +pango_ft2_font_map_class_init (PangoFT2FontMapClass *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_ft2_font_map_finalize; + font_map_class->load_font = pango_ft2_font_map_load_font; + font_map_class->list_fonts = pango_ft2_font_map_list_fonts; + font_map_class->list_families = pango_ft2_font_map_list_families; + + /* FIXME */ + pango_ft2_font_directories = g_slist_append (pango_ft2_font_directories, "C:\\windows\\fonts"); +} + +static gboolean +pango_ft2_is_font_file (const char *name) +{ + struct stat filestat; + int err, len; + + err = stat (name, &filestat); + + if (!err && S_ISREG (filestat.st_mode)) + { + len = strlen (name); + if (len > 4 && + (g_strncasecmp (&name[len-4], ".pfa", 4) == 0 || + g_strncasecmp (&name[len-4], ".pfb", 4) == 0 || + g_strncasecmp (&name[len-4], ".ttf", 4) == 0)) + { + return TRUE; + } + } + + return FALSE; +} + +static void +pango_ft2_scan_directory (const char *path, + PangoFT2FontMap *ft2fontmap) +{ + DIR *dir; + struct dirent *entry; + char *fullname; + FT_Face face; + FT_Error error; + int i; + + dir = opendir (path); + if (!dir) + g_warning ("Error opening directory '%s'", path); + else + { + while ((entry = readdir (dir)) != NULL) + { + fullname = g_strconcat (path, + (path[strlen (path)-1] == G_DIR_SEPARATOR ? + "" : G_DIR_SEPARATOR_S), + entry->d_name, + NULL); + if (pango_ft2_is_font_file (fullname)) + { + error = FT_New_Face (ft2fontmap->library, fullname, 0, &face); + if (error != FT_Err_Ok) + g_warning ("Error loading font from '%s': %s", + fullname, pango_ft2_ft_strerror (error)); + else + { + if (face->face_flags & FT_FACE_FLAG_SCALABLE) + pango_ft2_insert_face (ft2fontmap, face, fullname, 0); + + for (i = 1; i < face->num_faces; i++) + { + error = FT_Done_Face (face); + if (error != FT_Err_Ok) + g_warning ("Error from FT_Done_Face: %s", + pango_ft2_ft_strerror (error)); + error = FT_New_Face (ft2fontmap->library, fullname, i, &face); + if (error != FT_Err_Ok) + g_warning ("Error loading font %d from '%s': %s", + i, fullname, pango_ft2_ft_strerror (error)); + else if (face->face_flags & FT_FACE_FLAG_SCALABLE) + pango_ft2_insert_face (ft2fontmap, face, fullname, i); + } + error = FT_Done_Face (face); + if (error != FT_Err_Ok) + g_warning ("Error from FT_Done_Face: %s", + pango_ft2_ft_strerror (error)); + } + } + g_free (fullname); + } + closedir (dir); + } +} + +PangoFontMap * +pango_ft2_font_map_for_display (void) +{ + GSList *tmp_list; + FT_Error error; + + /* Make sure that the type system is initialized */ + g_type_init(); + + if (pango_ft2_global_fontmap != NULL) + return PANGO_FONT_MAP (pango_ft2_global_fontmap); + + pango_ft2_global_fontmap = (PangoFT2FontMap *)g_type_create_instance (PANGO_TYPE_FT2_FONT_MAP); + + error = FT_Init_FreeType (&pango_ft2_global_fontmap->library); + if (error != FT_Err_Ok) + { + g_warning ("Error from FT_Init_FreeType: %s", + pango_ft2_ft_strerror (error)); + return NULL; + } + + pango_ft2_global_fontmap->font_cache = pango_ft2_font_cache_new (pango_ft2_global_fontmap->library); + pango_ft2_global_fontmap->freed_fonts = g_queue_new (); + + tmp_list = pango_ft2_font_directories; + + while (tmp_list) + { + pango_ft2_scan_directory ((const char *) tmp_list->data, pango_ft2_global_fontmap); + tmp_list = tmp_list->next; + } + + pango_ft2_font_map_read_aliases (pango_ft2_global_fontmap); + + return PANGO_FONT_MAP (pango_ft2_global_fontmap); +} + +/** + * pango_ft2_shutdown_display: + * + * Free cached resources. + **/ +void +pango_ft2_shutdown_display (void) +{ + pango_ft2_fontmap_cache_clear (pango_ft2_global_fontmap); + + g_object_unref (G_OBJECT (pango_ft2_global_fontmap)); + + pango_ft2_global_fontmap = NULL; +} + +static void +pango_ft2_font_map_finalize (GObject *object) +{ + PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (object); + + g_list_foreach (ft2fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); + g_queue_free (ft2fontmap->freed_fonts); + + pango_ft2_font_cache_free (ft2fontmap->font_cache); + + FT_Done_FreeType (ft2fontmap->library); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +typedef struct +{ + int n_found; + PangoFontDescription **descs; +} ListFontsInfo; + +static void +list_fonts_foreach (gpointer key, + gpointer value, + gpointer user_data) +{ + PangoFT2FamilyEntry *entry = value; + ListFontsInfo *info = user_data; + + GSList *tmp_list = entry->font_entries; + + while (tmp_list) + { + PangoFT2FontEntry *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_ft2_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs) +{ + PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; + ListFontsInfo info; + + if (!n_descs) + return; + + if (family) + { + PangoFT2FamilyEntry *entry = g_hash_table_lookup (ft2fontmap->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 = ft2fontmap->n_fonts; + if (descs) + { + *descs = g_new (PangoFontDescription *, ft2fontmap->n_fonts); + + info.descs = *descs; + info.n_found = 0; + + g_hash_table_foreach (ft2fontmap->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_ft2_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families) +{ + GSList *family_list = NULL; + GSList *tmp_list; + PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; + + if (!n_families) + return; + + g_hash_table_foreach (ft2fontmap->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 PangoFT2FamilyEntry * +pango_ft2_get_family_entry (PangoFT2FontMap *ft2fontmap, + const char *family_name) +{ + PangoFT2FamilyEntry *family_entry = g_hash_table_lookup (ft2fontmap->families, family_name); + if (!family_entry) + { + family_entry = g_new (PangoFT2FamilyEntry, 1); + family_entry->family_name = g_strdup (family_name); + family_entry->font_entries = NULL; + + g_hash_table_insert (ft2fontmap->families, family_entry->family_name, family_entry); + } + + return family_entry; +} + +static PangoFont * +pango_ft2_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *description) +{ + PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; + PangoFT2FamilyEntry *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 (ft2fontmap->families, name); + if (family_entry) + { + PangoFT2FontEntry *best_match = NULL; + + tmp_list = family_entry->font_entries; + while (tmp_list) + { + PangoFT2FontEntry *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) + { + PangoFT2Font *ft2font = tmp_list->data; + + if (ft2font->size == description->size) + { + result = (PangoFont *)ft2font; + + g_object_ref (G_OBJECT (result)); + if (ft2font->in_cache) + pango_ft2_fontmap_cache_remove (fontmap, ft2font); + break; + } + tmp_list = tmp_list->next; + } + + if (!result) + { + PangoFT2Font *ft2font = + (PangoFT2Font *) pango_ft2_load_font (fontmap, + best_match->open_args, + best_match->face_indices, + best_match->n_fonts, + description->size); + + ft2font->fontmap = fontmap; + ft2font->entry = best_match; + best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, ft2font); + + result = (PangoFont *)ft2font; + } + } + } + + g_free (name); + return result; +} + +static void +pango_ft2_font_map_read_alias_file (PangoFT2FontMap *ft2fontmap, + const char *filename) +{ + FILE *infile; + int lineno = 0; + int nfaces; + int i; + PangoFT2FontEntry *font_entry = NULL; + gchar **faces; + + 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)) + { + PangoFT2FamilyEntry *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 (PangoFT2FontEntry, 1); + font_entry->n_fonts = 0; + font_entry->open_args = NULL; + font_entry->face_indices = NULL; + + 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 (!pango_parse_style (tmp_buf, &font_entry->description, TRUE)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!pango_parse_variant (tmp_buf, &font_entry->description, TRUE)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!pango_parse_weight (tmp_buf, &font_entry->description, TRUE)) + goto error; + + if (!pango_scan_string (&p, tmp_buf)) + goto error; + + if (!pango_parse_stretch (tmp_buf, &font_entry->description, TRUE)) + 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->open_args = g_new (FT_Open_Args *, nfaces); + font_entry->face_indices = g_new (FT_Long, nfaces); + + for (i = 0; i < nfaces; i++) + { + PangoFontDescription desc; + PangoFT2OA *oa; + + desc = font_entry->description; + desc.family_name = faces[i]; + oa = g_hash_table_lookup (ft2fontmap->faces, &desc); + if (!oa) + g_warning ("Face '%s' on line %d of '%s' not found", faces[i], lineno, filename); + else + { + font_entry->open_args[font_entry->n_fonts] = oa->open_args; + font_entry->face_indices[font_entry->n_fonts] = oa->face_index; + font_entry->n_fonts++; + } + } + + /* Insert the font entry into our structures */ + + family_entry = pango_ft2_get_family_entry (ft2fontmap, font_entry->description.family_name); + family_entry->font_entries = g_slist_prepend (family_entry->font_entries, font_entry); + ft2fontmap->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 file '%s': %s", filename, g_strerror(errno)); + + goto out; + + error: + if (font_entry) + { + if (font_entry->open_args) + g_free (font_entry->open_args); + if (font_entry->face_indices) + g_free (font_entry->face_indices); + 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_ft2_font_map_read_aliases (PangoFT2FontMap *ft2fontmap) +{ + char **files; + char *files_str = pango_config_key_get ("PangoFT2/AliasFiles"); + char *home; + char *tmp_str; + int n; + + if (!files_str) + { + home = g_get_home_dir (); + if (home && *home) + files_str = g_strconcat (home, "\\.pangoft2_aliases;", NULL); + + tmp_str = g_strconcat (files_str, pango_get_sysconf_subdirectory (), + "\\pangoft2.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_ft2_font_map_read_alias_file (ft2fontmap, files[n]); + + g_strfreev (files); + g_free (files_str); +} + +#if DEBUGGING + +static void +pango_print_desc (PangoFontDescription *desc) +{ + g_print ("%s%s%s%s%s", + desc->family_name, + (desc->style == PANGO_STYLE_NORMAL ? "" : + (desc->style == PANGO_STYLE_OBLIQUE ? " OBLIQUE" : + (desc->style == PANGO_STYLE_ITALIC ? " ITALIC" : " ???"))), + (desc->variant == PANGO_VARIANT_NORMAL ? "" : + (desc->variant == PANGO_VARIANT_SMALL_CAPS ? " SMALL CAPS" : "???")), + (desc->weight >= (PANGO_WEIGHT_LIGHT + PANGO_WEIGHT_NORMAL) / 2 && + desc->weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_BOLD) / 2 ? "" : + (desc->weight < (PANGO_WEIGHT_ULTRALIGHT + PANGO_WEIGHT_LIGHT) / 2 ? " ULTRALIGHT" : + (desc->weight >= (PANGO_WEIGHT_ULTRALIGHT + PANGO_WEIGHT_LIGHT) / 2 && + desc->weight < (PANGO_WEIGHT_LIGHT + PANGO_WEIGHT_NORMAL) / 2 ? " LIGHT" : + (desc->weight >= (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_BOLD) / 2 && + desc->weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2 ? " BOLD" : + (desc->weight >= (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2 && + desc->weight < (PANGO_WEIGHT_ULTRABOLD + PANGO_WEIGHT_HEAVY) / 2 ? " ULTRABOLD" : + " HEAVY"))))), + (desc->stretch == PANGO_STRETCH_ULTRA_CONDENSED ? " ULTRA CONDENSED" : + (desc->stretch == PANGO_STRETCH_EXTRA_CONDENSED ? " EXTRA CONDENSED" : + (desc->stretch == PANGO_STRETCH_CONDENSED ? " CONDENSED" : + (desc->stretch == PANGO_STRETCH_SEMI_CONDENSED ? " SEMI CONDENSED" : + (desc->stretch == PANGO_STRETCH_NORMAL ? "" : + (desc->stretch == PANGO_STRETCH_SEMI_EXPANDED ? " SEMI EXPANDED" : + (desc->stretch == PANGO_STRETCH_EXPANDED ? " EXPANDED" : + (desc->stretch == PANGO_STRETCH_EXTRA_EXPANDED ? " EXTRA EXPANDED" : + (desc->stretch == PANGO_STRETCH_ULTRA_EXPANDED ? " ULTRA EXPANDED" : " ???")))))))))); +} + +static void +pango_ft2_print_oa (PangoFT2OA *oa) +{ + g_print ("%s:%ld", oa->open_args->pathname, oa->face_index); +} + +#endif + +static void +pango_ft2_insert_face (PangoFT2FontMap *ft2fontmap, + FT_Face face, + const char *path, + int face_index) +{ + PangoFontDescription *description; + GSList *tmp_list; + PangoFT2FamilyEntry *family_entry; + PangoFT2FontEntry *font_entry; + PangoFT2OA *oa; + FT_Open_Args *open_args; + + description = g_new (PangoFontDescription, 1); + description->family_name = g_strdup (face->family_name); + g_strdown (description->family_name); + + if (face->style_flags & FT_STYLE_FLAG_ITALIC) + description->style = PANGO_STYLE_ITALIC; + else + description->style = PANGO_STYLE_NORMAL; + + description->variant = PANGO_VARIANT_NORMAL; + + if (face->style_flags & FT_STYLE_FLAG_BOLD) + description->weight = PANGO_WEIGHT_BOLD; + else + description->weight = PANGO_WEIGHT_NORMAL; + + description->stretch = PANGO_STRETCH_NORMAL; + + if (face->style_name) + { + gchar **styles = g_strsplit (face->style_name, " ", 0); + gint i = 0; + + while (styles[i]) + { + GString *s = g_string_new (styles[i]); + (void) (pango_parse_style (s, description, FALSE) || + pango_parse_variant (s, description, FALSE) || + pango_parse_weight (s, description, FALSE) || + pango_parse_stretch (s, description, FALSE)); + g_string_free (s, TRUE); + i++; + } + g_strfreev (styles); + } + + description->size = 0; + +#if 0 + PING (("")); + pango_print_desc (description); +#endif + + family_entry = pango_ft2_get_family_entry (ft2fontmap, 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) + { + g_free (description->family_name); + g_free (description); +#if 0 + PING ((" family and description matched (!)\n")); +#endif + return; + } + + tmp_list = tmp_list->next; + } + + oa = g_hash_table_lookup (ft2fontmap->faces, description); + if (!oa) + { + oa = g_new (PangoFT2OA, 1); + open_args = g_new (FT_Open_Args, 1); + open_args->flags = ft_open_pathname; + open_args->pathname = g_strdup (path); + open_args->driver = NULL; + open_args->num_params = 0; + oa->open_args = open_args; + oa->face_index = face_index; +#if 0 + PING (("adding mapping: ")); + pango_ft2_print_oa (oa); +#endif + g_hash_table_insert (ft2fontmap->faces, description, oa); + } +#if 0 + g_print ("\n"); +#endif + + font_entry = g_new (PangoFT2FontEntry, 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->open_args = g_new (FT_Open_Args *, 1); + font_entry->open_args[0] = oa->open_args; + font_entry->face_indices = g_new (FT_Long, 1); + font_entry->face_indices[0] = oa->face_index; + font_entry->n_fonts = 1; + family_entry->font_entries = g_slist_append (family_entry->font_entries, font_entry); + ft2fontmap->n_fonts++; +} + +static void +free_coverages_foreach (gpointer key, + gpointer value, + gpointer data) +{ + pango_coverage_unref (value); +} + +PangoCoverage * +pango_ft2_font_entry_get_coverage (PangoFT2FontEntry *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_ft2_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_ft2_font_entry_remove (PangoFT2FontEntry *entry, + PangoFont *font) +{ + entry->cached_fonts = g_slist_remove (entry->cached_fonts, font); +} + +PangoFT2FontCache * +pango_ft2_font_map_get_font_cache (PangoFontMap *font_map) +{ + g_return_val_if_fail (font_map != NULL, NULL); + g_return_val_if_fail (PANGO_FT2_IS_FONT_MAP (font_map), NULL); + + return PANGO_FT2_FONT_MAP (font_map)->font_cache; +} + +void +pango_ft2_fontmap_cache_add (PangoFontMap *fontmap, + PangoFT2Font *ft2font) +{ + PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (fontmap); + + if (ft2fontmap->freed_fonts->length == MAX_FREED_FONTS) + { + PangoFT2Font *old_font = g_queue_pop_tail (ft2fontmap->freed_fonts); + g_object_unref (G_OBJECT (old_font)); + } + + g_object_ref (G_OBJECT (ft2font)); + g_queue_push_head (ft2fontmap->freed_fonts, ft2font); + ft2font->in_cache = TRUE; +} + +void +pango_ft2_fontmap_cache_remove (PangoFontMap *fontmap, + PangoFT2Font *ft2font) +{ + PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (fontmap); + + GList *link = g_list_find (ft2fontmap->freed_fonts->head, ft2font); + if (link == ft2fontmap->freed_fonts->tail) + { + ft2fontmap->freed_fonts->tail = ft2fontmap->freed_fonts->tail->prev; + if (ft2fontmap->freed_fonts->tail) + ft2fontmap->freed_fonts->tail->next = NULL; + } + + ft2fontmap->freed_fonts->head = g_list_delete_link (ft2fontmap->freed_fonts->head, link); + ft2fontmap->freed_fonts->length--; + ft2font->in_cache = FALSE; + + g_object_unref (G_OBJECT (ft2font)); +} + +static void +pango_ft2_fontmap_cache_clear (PangoFT2FontMap *ft2fontmap) +{ + g_list_foreach (ft2fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); + g_list_free (ft2fontmap->freed_fonts->head); + ft2fontmap->freed_fonts->head = NULL; + ft2fontmap->freed_fonts->tail = NULL; + ft2fontmap->freed_fonts->length = 0; +} + +static void +pango_ft2_font_entry_dump (int indent, + PangoFT2FontEntry *font_entry) +{ + int i; + + printf ("%*sPangoFT2FontEntry@%p:\n" + "%*s lfp:\n", + indent, "", font_entry, + indent, ""); + + for (i = 0; i < font_entry->n_fonts; i++) + printf ("%*s PangoFT2OpenArgs:%s:%ld\n", + indent, "", font_entry->open_args[i]->pathname, font_entry->face_indices[i]); + + 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_ft2_family_entry_dump (int indent, + PangoFT2FamilyEntry *entry) +{ + GSList *tmp_list = entry->font_entries; + + printf ("%*sPangoFT2FamilyEntry@%p:\n" + "%*s family_name: %s\n" + "%*s font_entries:\n", + indent, "", entry, + indent, "", entry->family_name, + indent, ""); + + while (tmp_list) + { + PangoFT2FontEntry *font_entry = tmp_list->data; + + pango_ft2_font_entry_dump (indent + 2, font_entry); + tmp_list = tmp_list->next; + } +} + +static void +dump_family (gpointer key, + gpointer value, + gpointer user_data) +{ + PangoFT2FamilyEntry *entry = value; + int indent = (int) user_data; + + pango_ft2_family_entry_dump (indent, entry); +} + +void +pango_ft2_fontmap_dump (int indent, + PangoFontMap *fontmap) +{ + PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (fontmap); + + printf ("%*sPangoFT2FontMap@%p:\n", + indent, "", ft2fontmap); + g_hash_table_foreach (ft2fontmap->families, dump_family, (gpointer) (indent + 2)); +} diff --git a/pango/pangoft2-private.h b/pango/pangoft2-private.h new file mode 100644 index 00000000..92b1c053 --- /dev/null +++ b/pango/pangoft2-private.h @@ -0,0 +1,97 @@ +/* Pango + * pangoft2-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 __PANGOFT2_PRIVATE_H__ +#define __PANGOFT2_PRIVATE_H__ + +#include "pango-modules.h" +#include "pangoft2.h" + +/* Debugging... */ +#define DEBUGGING 1 + +#ifdef DEBUGGING +#define PING(printlist) \ +(g_print ("%s:%d ", __PRETTY_FUNCTION__, __LINE__), \ + g_print printlist) +#else +#define PING(printlist) +#endif + +#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6)) +#define PANGO_PIXELS_26_6(d) \ + (((d) >= 0) ? \ + ((d) + PANGO_SCALE_26_6 / 2) / PANGO_SCALE_26_6 : \ + ((d) - PANGO_SCALE_26_6 / 2) / PANGO_SCALE_26_6) +#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d)) + +typedef struct _PangoFT2OA PangoFT2OA; +typedef struct _PangoFT2Font PangoFT2Font; +typedef struct _PangoFT2FontEntry PangoFT2FontEntry; +typedef struct _PangoFT2SubfontInfo PangoFT2SubfontInfo; + +struct _PangoFT2OA +{ + FT_Open_Args *open_args; + FT_Long face_index; +}; + +struct _PangoFT2Font +{ + PangoFont font; + + /* A PangoFT2Font consists of one or several FT2 fonts (faces) that + * are assumed to blend visually well, and cover separate parts of + * the Unicode characters. The FT2 faces are not kept unnecessarily + * open, thus also we keep both the FT_Open_Args (and face index), + * and FT_Face. + */ + PangoFT2OA **oa; + FT_Face *faces; + int n_fonts; + + int size; + + GSList *metrics_by_lang; + + PangoFontMap *fontmap; + /* If TRUE, font is in cache of recently unused fonts and not otherwise + * in use. + */ + gboolean in_cache; + + PangoFT2FontEntry *entry; /* Used to remove cached fonts */ +}; + +PangoMap *pango_ft2_get_shaper_map (const char *lang); +PangoCoverage *pango_ft2_font_entry_get_coverage (PangoFT2FontEntry *entry, + PangoFont *font, + const char *lang); +void pango_ft2_font_entry_remove (PangoFT2FontEntry *entry, + PangoFont *font); +FT_Library *pango_ft2_fontmap_get_library (PangoFontMap *fontmap); +void pango_ft2_fontmap_cache_add (PangoFontMap *fontmap, + PangoFT2Font *ft2font); +void pango_ft2_fontmap_cache_remove (PangoFontMap *fontmap, + PangoFT2Font *ft2font); +const char *pango_ft2_ft_strerror (FT_Error error); + +#endif /* __PANGOFT2_PRIVATE_H__ */ diff --git a/pango/pangoft2.c b/pango/pangoft2.c new file mode 100644 index 00000000..faffe580 --- /dev/null +++ b/pango/pangoft2.c @@ -0,0 +1,1126 @@ +/* Pango + * pangoft2.c: Routines for handling FreeType2 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 <stdio.h> +#include <math.h> +#include <glib.h> + +#include <freetype/freetype.h> +#include <fribidi/fribidi.h> + +#include "pangoft2.h" +#include "pangoft2-private.h" + +#define PANGO_TYPE_FT2_FONT (pango_ft2_font_get_type ()) +#define PANGO_FT2_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_FT2_FONT, PangoFT2Font)) +#define PANGO_FT2_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_FONT, PangoFT2FontClass)) +#define PANGO_FT2_IS_FONT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_FT2_FONT)) +#define PANGO_FT2_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_FONT)) +#define PANGO_FT2_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_FONT, PangoFT2FontClass)) + +typedef struct _PangoFT2FontClass PangoFT2FontClass; +typedef struct _PangoFT2MetricsInfo PangoFT2MetricsInfo; +typedef struct _PangoFT2ContextInfo PangoFT2ContextInfo; + +struct _PangoFT2MetricsInfo +{ + const char *lang; + PangoFontMetrics metrics; +}; + +struct _PangoFT2FontClass +{ + PangoFontClass parent_class; +}; + +static PangoFontClass *parent_class; /* Parent class structure for PangoFT2Font */ + +static void pango_ft2_font_class_init (PangoFT2FontClass *class); +static void pango_ft2_font_init (PangoFT2Font *xfont); +static void pango_ft2_font_shutdown (GObject *object); +static void pango_ft2_font_finalize (GObject *object); + +static PangoFontDescription *pango_ft2_font_describe (PangoFont *font); + +static PangoCoverage * pango_ft2_font_get_coverage (PangoFont *font, + const char *lang); + +static PangoEngineShape * pango_ft2_font_find_shaper (PangoFont *font, + const char *lang, + guint32 ch); + +static void pango_ft2_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +static void pango_ft2_font_get_metrics (PangoFont *font, + const gchar *lang, + PangoFontMetrics *metrics); + +static void pango_ft2_get_item_properties (PangoItem *item, + PangoUnderline *uline, + PangoAttrColor *fg_color, + gboolean *fg_set, + PangoAttrColor *bg_color, + gboolean *bg_set); + +static char * +pango_ft2_open_args_describe (PangoFT2OA *oa) +{ + if (oa->open_args->flags & ft_open_memory) + return g_strdup_printf ("memory at %p", oa->open_args->memory_base); + else if (oa->open_args->flags == ft_open_pathname) + return g_strdup_printf ("file '%s'", oa->open_args->pathname); + else if (oa->open_args->flags & ft_open_stream) + return g_strdup_printf ("FT_Stream at %p", oa->open_args->stream); + else + return g_strdup_printf ("open_args at %p, face_index %ld", oa->open_args, oa->face_index); +} + +static inline FT_Face +pango_ft2_get_face (PangoFont *font, + PangoFT2Subfont subfont_index) +{ + PangoFT2Font *ft2font = (PangoFT2Font *)font; + PangoFT2FontCache *cache; + + if (subfont_index < 1 || subfont_index > ft2font->n_fonts) + { + g_warning ("Invalid subfont %d", subfont_index); + return NULL; + } + + if (!ft2font->faces[subfont_index-1]) + { + cache = pango_ft2_font_map_get_font_cache (ft2font->fontmap); + + ft2font->faces[subfont_index-1] = + pango_ft2_font_cache_load (cache, + ft2font->oa[subfont_index-1]->open_args, + ft2font->oa[subfont_index-1]->face_index); + + if (!ft2font->faces[subfont_index-1]) + g_warning ("Cannot load font for %s", + pango_ft2_open_args_describe (ft2font->oa[subfont_index-1])); + } + return ft2font->faces[subfont_index-1]; +} + +/** + * pango_ft2_get_context: + * + * Retrieves a #PangoContext appropriate for rendering with Pango fonts. + * + * Return value: the new #PangoContext + **/ +PangoContext * +pango_ft2_get_context (void) +{ + PangoContext *result; + + result = pango_context_new (); + pango_context_add_font_map (result, pango_ft2_font_map_for_display ()); + + return result; +} + +static GType +pango_ft2_font_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (PangoFT2FontClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) pango_ft2_font_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PangoFT2Font), + 0, /* n_preallocs */ + (GInstanceInitFunc) pango_ft2_font_init, + }; + + object_type = g_type_register_static (PANGO_TYPE_FONT, + "PangoFT2Font", + &object_info); + } + + return object_type; +} + +static void +pango_ft2_font_init (PangoFT2Font *ft2font) +{ + ft2font->oa = NULL; + ft2font->faces = NULL; + + ft2font->n_fonts = 0; + + ft2font->metrics_by_lang = NULL; + + ft2font->entry = NULL; +} + +static void +pango_ft2_font_class_init (PangoFT2FontClass *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_ft2_font_finalize; + object_class->shutdown = pango_ft2_font_shutdown; + + font_class->describe = pango_ft2_font_describe; + font_class->get_coverage = pango_ft2_font_get_coverage; + font_class->find_shaper = pango_ft2_font_find_shaper; + font_class->get_glyph_extents = pango_ft2_font_get_glyph_extents; + font_class->get_metrics = pango_ft2_font_get_metrics; +} + +/** + * pango_ft2_load_font: + * + * Loads a logical font based on XXX + * + * Returns a new #PangoFont + */ +PangoFont * +pango_ft2_load_font (PangoFontMap *fontmap, + FT_Open_Args **open_args, + FT_Long *face_indices, + int n_fonts, + int size) +{ + PangoFT2Font *result; + int i; + + g_return_val_if_fail (fontmap != NULL, NULL); + g_return_val_if_fail (open_args != NULL, NULL); + g_return_val_if_fail (face_indices != NULL, NULL); + g_return_val_if_fail (n_fonts > 0, NULL); + + result = (PangoFT2Font *)g_type_create_instance (PANGO_TYPE_FT2_FONT); + + result->fontmap = fontmap; + g_object_ref (G_OBJECT (result->fontmap)); + + result->oa = g_new (PangoFT2OA *, n_fonts); + result->faces = g_new (FT_Face, n_fonts); + result->n_fonts = n_fonts; + result->size = size; + + for (i = 0; i < n_fonts; i++) + { + result->oa[i] = g_new (PangoFT2OA, 1); + result->oa[i]->open_args = open_args[i]; + result->oa[i]->face_index = face_indices[i]; + result->faces[i] = NULL; + } + + return &result->font; +} + +/** + * pango_ft2_render: + * + * @bitmap: the FreeType2 bitmap onto which draw the string + * @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 FreeType2 bitmap + */ +void +pango_ft2_render (FT_Bitmap *bitmap, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + FT_Face face; + FT_Face prev_face = NULL; + FT_UInt glyph_index, prev_index; + int i; + int x_position = 0; + int ix, iy, ixoff, iyoff, y_start, y_limit, x_start, x_limit; + guint16 char_index; + PangoFT2Subfont subfont_index; + PangoGlyphInfo *gi; + guchar *p, *q; + + g_return_if_fail (bitmap != NULL); + g_return_if_fail (glyphs != NULL); + + PING (("bitmap: %dx%d@+%d+%d\n", bitmap->width, bitmap->rows, x, y)); + + gi = glyphs->glyphs; + for (i = 0; i < glyphs->num_glyphs; i++, gi++) + { + if (gi->glyph) + { + char_index = PANGO_FT2_GLYPH_INDEX (gi->glyph); + subfont_index = PANGO_FT2_GLYPH_SUBFONT (gi->glyph); + face = pango_ft2_get_face (font, subfont_index); + + if (face) + { + /* Draw glyph */ + glyph_index = FT_Get_Char_Index (face, char_index); + /* FIXME hint or not? */ + FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); + FT_Render_Glyph (face->glyph, ft_render_mode_normal); + + ixoff = x + PANGO_PIXELS (x_position + gi->geometry.x_offset); + iyoff = y + PANGO_PIXELS (gi->geometry.y_offset); + + x_start = MAX (0, -face->glyph->bitmap_left - ixoff); + x_limit = MIN (face->glyph->bitmap.width, face->glyph->bitmap_left - ixoff + bitmap->width); + + y_start = MAX (0, face->glyph->bitmap_top - iyoff); + y_limit = MIN (face->glyph->bitmap.rows, face->glyph->bitmap_top - iyoff + bitmap->rows); + + + PING (("glyph %d:%d: bitmap: %dx%d, left:%d top:%d\n", + i, glyph_index, + face->glyph->bitmap.width, face->glyph->bitmap.rows, + face->glyph->bitmap_left, face->glyph->bitmap_top)); + PING (("xstart:%d xlim:%d ystart:%d ylim:%d\n", + x_start, x_limit, y_start, y_limit)); + + for (iy = y_start; iy < y_limit; iy++) + { + p = bitmap->buffer + + (iyoff - face->glyph->bitmap_top + iy) * bitmap->pitch + + ixoff + + face->glyph->bitmap_left + x_start; + + q = face->glyph->bitmap.buffer + iy*face->glyph->bitmap.pitch; + for (ix = x_start; ix < x_limit; ix++) + { + *p = MIN (*p, 0xFF - *q); + q++; + p++; + } + } + + prev_face = face; + prev_index = glyph_index; + } + } + + x_position += glyphs->glyphs[i].geometry.width; + } +} + +static FT_Glyph_Metrics * +pango_ft2_get_per_char (PangoFont *font, + PangoFT2Subfont subfont_index, + guint16 char_index) +{ + PangoFT2Font *ft2font = (PangoFT2Font *)font; + FT_Face face; + FT_UInt glyph_index; + FT_Error error; + + if (!(face = pango_ft2_get_face (font, subfont_index))) + return NULL; + + glyph_index = FT_Get_Char_Index (face, char_index); + if (!glyph_index) + return NULL; + + error = FT_Set_Pixel_Sizes (face, PANGO_PIXELS (ft2font->size), 0); + if (error) + g_warning ("Error in FT_Set_Pixel_Sizes: %d", error); + + FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); + return &face->glyph->metrics; +} + +static void +pango_ft2_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + guint16 char_index = PANGO_FT2_GLYPH_INDEX (glyph); + PangoFT2Subfont subfont_index = PANGO_FT2_GLYPH_SUBFONT (glyph); + FT_Glyph_Metrics *gm; + + if (glyph && (gm = pango_ft2_get_per_char (font, subfont_index, char_index))) + { + if (ink_rect) + { + ink_rect->x = PANGO_UNITS_26_6 (gm->horiBearingX); + ink_rect->width = PANGO_UNITS_26_6 (gm->width); + ink_rect->y = -PANGO_UNITS_26_6 (gm->horiBearingY); + ink_rect->height = PANGO_UNITS_26_6 (gm->height); + } + if (logical_rect) + { + FT_Face face = pango_ft2_get_face (font, subfont_index); + + logical_rect->x = 0; + logical_rect->width = PANGO_UNITS_26_6 (gm->horiAdvance); + logical_rect->y = -PANGO_UNITS_26_6 (face->size->metrics.ascender + 64); + /* Some fonts report negative descender, some positive ! (?) */ + logical_rect->height = PANGO_UNITS_26_6 (face->size->metrics.ascender + ABS (face->size->metrics.descender) + 128); + } + PING (("glyph:%d logical: %dx%d@%d+%d\n", + char_index, logical_rect->width, logical_rect->height, + logical_rect->x, logical_rect->y)); + } + 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; + } + } +} + +int +pango_ft2_font_get_kerning (PangoFont *font, + PangoGlyph left, + PangoGlyph right) +{ + PangoFT2Subfont subfont_index; + guint16 left_char_index; + guint16 right_char_index; + FT_Face face; + FT_UInt left_glyph_index, right_glyph_index; + FT_Error error; + FT_Vector kerning; + + subfont_index = PANGO_FT2_GLYPH_SUBFONT (left); + if (PANGO_FT2_GLYPH_SUBFONT (right) != subfont_index) + return 0; + + face = pango_ft2_get_face (font, subfont_index); + if (!face) + return 0; + + if (!FT_HAS_KERNING (face)) + return 0; + + left_char_index = PANGO_FT2_GLYPH_INDEX (left); + right_char_index = PANGO_FT2_GLYPH_INDEX (right); + + left_glyph_index = FT_Get_Char_Index (face, left_char_index); + right_glyph_index = FT_Get_Char_Index (face, right_char_index); + if (!left_glyph_index || !right_char_index) + return 0; + + error = FT_Get_Kerning (face, left_glyph_index, right_glyph_index, + ft_kerning_default, &kerning); + if (error != FT_Err_Ok) + g_warning ("FT_Get_Kerning returns error: %s", + pango_ft2_ft_strerror (error)); + + return PANGO_UNITS_26_6 (kerning.x); +} + +/* Get composite font metrics for all subfonts in list + */ +static void +get_font_metrics_from_subfonts (PangoFont *font, + GSList *subfonts, + PangoFontMetrics *metrics) +{ + GSList *tmp_list = subfonts; + gboolean first = TRUE; + + metrics->ascent = 0; + metrics->descent = 0; + + while (tmp_list) + { + FT_Face face = pango_ft2_get_face (font, GPOINTER_TO_UINT (tmp_list->data)); + + g_assert (face != NULL); + + if (first) + { + metrics->ascent = PANGO_UNITS_26_6 (face->ascender); + metrics->descent = PANGO_UNITS_26_6 (face->descender); + first = FALSE; + } + else + { + metrics->ascent = MAX (PANGO_UNITS_26_6 (face->ascender), metrics->ascent); + metrics->descent = MAX (PANGO_UNITS_26_6 (face->descender), metrics->descent); + } + + 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++) + { + PangoFT2Subfont subfont_index = PANGO_FT2_GLYPH_SUBFONT (glyph_str->glyphs[j].glyph); + if (!g_slist_find (subfonts, GUINT_TO_POINTER ((guint)subfont_index))) + subfonts = g_slist_prepend (subfonts, GUINT_TO_POINTER ((guint)subfont_index)); + } + + 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 ا,DXXم عY(JY,CY(B" }, + { "cs", "Czech (česky) Dobrý den" }, + { "da", "Danish (Dansk) Hej, Goddag" }, + { "el", "Greek ($(GN;ληνικά(B) $(CN5ιά ,CNς(B" }, + { "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 (日語) こん, コン,Foハ(B" }, + { "ko", "Korean (한글) ,Hk하,D8요(B, ,Hk하십j(B" }, + { "mt", "Maltese Ċaw, Saħħa" }, + { "nl", "Nederlands, Vlaams Hallo, Dag" }, + { "no", "Norwegian (Norsk) Hei, God dag" }, + { "pl", "Polish Dzień dobry, Hej" }, + { "ru", "Russian (Р,CQкий(B)" }, + { "sk", "Slovak Dobrý deň" }, + { "sv", "Swedish (Svenska) Hej på dej, Goddag" }, + { "tr", "Turkish (Türkçe) Merhaba" }, + { "zh", "Chinese (中文,$(1.i话(B,(Ih(B)" } +}; + +static void +pango_ft2_font_get_metrics (PangoFont *font, + const gchar *lang, + PangoFontMetrics *metrics) +{ + PangoFT2MetricsInfo *info; + PangoFT2Font *ft2font = (PangoFT2Font *)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 = "ا,DXXم عY(JY,CY č(Besky $(GN;ληνικά (BFrançais 日語 한글 Р,CQкий 中文(B,$(1.i话(B,(Ih (BTürkçe"; + } + + tmp_list = ft2font->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 (PangoFT2MetricsInfo, 1); + info->lang = lookup_lang; + + ft2font->metrics_by_lang = g_slist_prepend (ft2font->metrics_by_lang, info); + + get_font_metrics_from_string (font, lang, str, &info->metrics); + } + + *metrics = info->metrics; +} + +/** + * pango_ft2_n_subfonts: + * @font: a PangoFont + * Returns number of subfonts in a PangoFT2Font. + **/ +int +pango_ft2_n_subfonts (PangoFont *font) +{ + PangoFT2Font *ft2font = (PangoFT2Font *)font; + + g_return_val_if_fail (font != NULL, 0); + + return ft2font->n_fonts; +} + +/** + * pango_ft2_has_glyph: + * @font: a #PangoFont which must be from the FreeType2 backend. + * @glyph: the index of a glyph in the font. (Formed + * using the PANGO_FT2_MAKE_GLYPH macro) + * + * Check if the given glyph is present in a FT2 font. + * + * Return value: %TRUE if the glyph is present. + **/ +gboolean +pango_ft2_has_glyph (PangoFont *font, + PangoGlyph glyph) +{ + guint16 char_index = PANGO_FT2_GLYPH_INDEX (glyph); + PangoFT2Subfont subfont_index = PANGO_FT2_GLYPH_SUBFONT (glyph); + FT_Face face = pango_ft2_get_face (font, subfont_index); + + if (!face) + return FALSE; + + if (FT_Get_Char_Index (face, char_index) == 0) + return FALSE; + else + return TRUE; +} + +/** + * pango_ft2_font_subfont_open_args: + * @font: a #PangoFont which must be from the FT2 backend + * @open_args: pointer where to store the #FT_Open_Args for this subfont + * @face_index: pointer where to store the face index for this subfont + * + * Determine the FT_Open_Args and face index for the specified subfont. + **/ +void +pango_ft2_font_subfont_open_args (PangoFont *font, + PangoFT2Subfont subfont_id, + FT_Open_Args **open_args, + FT_Long *face_index) +{ + PangoFT2Font *ft2font = (PangoFT2Font *)font; + *open_args = NULL; + *face_index = 0; + + g_return_if_fail (font != NULL); + g_return_if_fail (PANGO_FT2_IS_FONT (font)); + + if (subfont_id < 1 || subfont_id > ft2font->n_fonts) + g_warning ("pango_ft2_font_subfont_open_args: Invalid subfont_id specified"); + else + { + *open_args = ft2font->oa[subfont_id-1]->open_args; + *face_index = ft2font->oa[subfont_id-1]->face_index; + } +} + +static void +pango_ft2_font_shutdown (GObject *object) +{ + PangoFT2Font *ft2font = PANGO_FT2_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 (!ft2font->in_cache && ft2font->fontmap) + pango_ft2_fontmap_cache_add (ft2font->fontmap, ft2font); + + G_OBJECT_CLASS (parent_class)->shutdown (object); +} + + +static void +pango_ft2_font_finalize (GObject *object) +{ + PangoFT2Font *ft2font = (PangoFT2Font *)object; + PangoFT2FontCache *cache = pango_ft2_font_map_get_font_cache (ft2font->fontmap); + int i; + + PING (("\n")); + + for (i = 0; i < ft2font->n_fonts; i++) + { + if (ft2font->faces[i]) + pango_ft2_font_cache_unload (cache, ft2font->faces[i]); + } + + g_free (ft2font->oa); + g_free (ft2font->faces); + + g_slist_foreach (ft2font->metrics_by_lang, (GFunc)g_free, NULL); + g_slist_free (ft2font->metrics_by_lang); + + if (ft2font->entry) + pango_ft2_font_entry_remove (ft2font->entry, (PangoFont *)ft2font); + + g_object_unref (G_OBJECT (ft2font->fontmap)); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static PangoFontDescription * +pango_ft2_font_describe (PangoFont *font) +{ + /* FIXME: implement */ + return NULL; +} + +PangoMap * +pango_ft2_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_FT2); + } + + return pango_find_map (lang, engine_type_id, render_type_id); +} + +static PangoCoverage * +pango_ft2_font_get_coverage (PangoFont *font, + const char *lang) +{ + PangoFT2Font *ft2font = (PangoFT2Font *)font; + + return pango_ft2_font_entry_get_coverage (ft2font->entry, font, lang); +} + +static PangoEngineShape * +pango_ft2_font_find_shaper (PangoFont *font, + const gchar *lang, + guint32 ch) +{ + PangoMap *shape_map = NULL; + + shape_map = pango_ft2_get_shaper_map (lang); + return (PangoEngineShape *)pango_map_get_engine (shape_map, ch); +} + +/* Utility functions */ + +/** + * pango_ft2_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_ft2_get_unknown_glyph (PangoFont *font) +{ + return PANGO_FT2_MAKE_GLYPH (1, 0); +} + +/** + * pango_ft2_render_layout_line: + * @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 FreeType2 bitmap + */ +void +pango_ft2_render_layout_line (FT_Bitmap *bitmap, + PangoLayoutLine *line, + int x, + int y) +{ + GSList *tmp_list = line->runs; + PangoRectangle overall_rect; + PangoRectangle logical_rect; + PangoRectangle ink_rect; + unsigned char *p; + int ix; + int x_off = 0; + int x_limit; + + pango_layout_line_get_extents (line,NULL, &overall_rect); + + while (tmp_list) + { + 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_ft2_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); + + pango_ft2_render (bitmap, run->item->analysis.font, run->glyphs, + x + PANGO_PIXELS (x_off), y); + + x_limit = PANGO_PIXELS (ink_rect.width); + switch (uline) + { + case PANGO_UNDERLINE_NONE: + break; + case PANGO_UNDERLINE_DOUBLE: + p = bitmap->buffer + + (y + 4) * bitmap->pitch + + x + PANGO_PIXELS (x_off + ink_rect.x) - 1; + + /* Don't drawn the underline through descenders */ + for (ix = 0; ix < x_limit; ix++) + if (*p == 0xFF && + (ix == x_limit - 1 || p[1] == 0xFF)) + *p++ = 0; + /* Fall through */ + case PANGO_UNDERLINE_SINGLE: + p = bitmap->buffer + + (y + 2) * bitmap->pitch + + x + PANGO_PIXELS (x_off + ink_rect.x) - 1; + for (ix = 0; ix < x_limit; ix++) + if (*p == 0xFF && + (ix == x_limit - 1 || p[1] == 0xFF)) + *p++ = 0; + break; + case PANGO_UNDERLINE_LOW: + p = bitmap->buffer + + (y + PANGO_PIXELS (ink_rect.y + ink_rect.height)) * bitmap->pitch + + x + PANGO_PIXELS (x_off + ink_rect.x) - 1; + for (ix = 0; ix < PANGO_PIXELS (ink_rect.width); ix++) + *p++ = 0; + break; + } + + x_off += logical_rect.width; + } +} + +/** + * pango_ft2_render_layout: + * @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 a FreeType2 bitmap + */ +void +pango_ft2_render_layout (FT_Bitmap *bitmap, + 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 (bitmap != NULL); + g_return_if_fail (layout != NULL); + + indent = pango_layout_get_indent (layout); + width = pango_layout_get_width (layout); + align = pango_layout_get_alignment (layout); + + PING (("x:%d y:%d indent:%d width:%d\n", x, y, indent, width)); + + 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; + } + } + + PING (("x_offset:%d y_offset:%d logical_rect.y:%d logical_rect.height:%d\n", x_offset, y_offset, logical_rect.y, logical_rect.height)); + + pango_ft2_render_layout_line (bitmap, line, + x + PANGO_PIXELS (x_offset), + y + PANGO_PIXELS (y_offset - logical_rect.y)); + + 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_ft2_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; + } +} + +typedef struct +{ + FT_Error code; + const char* msg; +} ft_error_description; + +static int +ft_error_compare (const void *pkey, + const void *pbase) +{ + return ((ft_error_description *) pkey)->code - ((ft_error_description *) pbase)->code; +} + +const char * +pango_ft2_ft_strerror (FT_Error error) +{ +#undef FTERRORS_H +#define FT_ERRORDEF( e, v, s ) { e, s }, +#define FT_ERROR_START_LIST { +#define FT_ERROR_END_LIST { 0, 0 } } + + const ft_error_description ft_errors[] = +#include <freetype/fterrors.h> + ; + +#undef FT_ERRORDEF +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST + + ft_error_description *found = + bsearch (&error, ft_errors, G_N_ELEMENTS (ft_errors) - 1, + sizeof (ft_errors[0]), ft_error_compare); + if (found != NULL) + return found->msg; + else + { + static char default_msg[100]; + + sprintf (default_msg, "Unknown FreeType2 error %#x", error); + return default_msg; + } +} diff --git a/pango/pangoft2.h b/pango/pangoft2.h new file mode 100644 index 00000000..ededcbc9 --- /dev/null +++ b/pango/pangoft2.h @@ -0,0 +1,107 @@ +/* Pango + * pangoft2.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 __PANGOFT2_H__ +#define __PANGOFT2_H__ + +#include <glib.h> +#include <pango/pango.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <freetype/freetype.h> + +#define PANGO_RENDER_TYPE_FT2 "PangoRenderFT2" + +/* Calls for applications + */ +PangoContext *pango_ft2_get_context (void); + +PangoFont *pango_ft2_load_font (PangoFontMap *fontmap, + FT_Open_Args **args, + FT_Long *face_indices, + int n_fonts, + int size); +void pango_ft2_render (FT_Bitmap *bitmap, + PangoFont *font, + PangoGlyphString *glyphs, + gint x, + gint y); +void pango_ft2_render_layout_line (FT_Bitmap *bitmap, + PangoLayoutLine *line, + int x, + int y); +void pango_ft2_render_layout (FT_Bitmap *bitmap, + PangoLayout *layout, + int x, + int y); + + +/* API for rendering modules + */ +typedef guint16 PangoFT2Subfont; + +#define PANGO_FT2_MAKE_GLYPH(subfont,index) ((subfont)<<16 | (index)) +#define PANGO_FT2_GLYPH_SUBFONT(glyph) ((glyph)>>16) +#define PANGO_FT2_GLYPH_INDEX(glyph) ((glyph) & 0xFFFF) + +int pango_ft2_n_subfonts (PangoFont *font); +gboolean pango_ft2_has_glyph (PangoFont *font, + PangoGlyph glyph); +PangoGlyph pango_ft2_get_unknown_glyph (PangoFont *font); +int pango_ft2_font_get_kerning (PangoFont *font, + PangoGlyph left, + PangoGlyph right); + +/* API for libraries that want to use PangoFT2 mixed with classic + * FT2 fonts. + */ +typedef struct _PangoFT2FontCache PangoFT2FontCache; + +PangoFT2FontCache *pango_ft2_font_cache_new (FT_Library library); +void pango_ft2_font_cache_free (PangoFT2FontCache *cache); +FT_Face pango_ft2_font_cache_load (PangoFT2FontCache *cache, + FT_Open_Args *args, + FT_Long face_index); +void pango_ft2_font_cache_unload (PangoFT2FontCache *cache, + FT_Face face); +PangoFontMap *pango_ft2_font_map_for_display (void); +void pango_ft2_shutdown_display (void); +PangoFT2FontCache *pango_ft2_font_map_get_font_cache (PangoFontMap *font_map); +void pango_ft2_font_subfont_open_args (PangoFont *font, + PangoFT2Subfont subfont_id, + FT_Open_Args **open_args, + FT_Long *face_index); + + +/* Debugging. + */ +void pango_ft2_fontmap_dump (int indent, + PangoFontMap *fontmap); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __PANGOFT2_H__ */ diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c index 86565d26..3f9caa2d 100644 --- a/pango/pangowin32-fontmap.c +++ b/pango/pangowin32-fontmap.c @@ -53,7 +53,12 @@ struct _PangoWin32FontMap PangoWin32FontCache *font_cache; GQueue *freed_fonts; + /* Map Pango family names tp PangoWin32FamilyEntry structs */ GHashTable *families; + + /* Map LOGFONTS (taking into account only the lfFaceName, lfItalic + * and lfWeight fields) to PangoWin32SizeInfo structs. + */ GHashTable *size_infos; int n_fonts; @@ -88,18 +93,9 @@ struct _PangoWin32SizeInfo 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 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, @@ -111,12 +107,12 @@ static void pango_win32_font_map_list_fonts (PangoFontMap 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 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 */ @@ -226,7 +222,7 @@ pango_win32_enum_proc (LOGFONT *lfp, lf = *lfp; - EnumFontFamiliesEx (pango_win32_hdc, &lf, pango_win32_inner_enum_proc, lParam, 0); + EnumFontFamiliesEx (pango_win32_hdc, &lf, (FONTENUMPROC) pango_win32_inner_enum_proc, lParam, 0); return 1; } @@ -250,7 +246,7 @@ pango_win32_font_map_for_display (void) memset (&logfont, 0, sizeof (logfont)); logfont.lfCharSet = DEFAULT_CHARSET; - EnumFontFamiliesEx (pango_win32_hdc, &logfont, pango_win32_enum_proc, 0, 0); + EnumFontFamiliesEx (pango_win32_hdc, &logfont, (FONTENUMPROC) pango_win32_enum_proc, 0, 0); pango_win32_font_map_read_aliases (fontmap); @@ -270,12 +266,8 @@ pango_win32_font_map_for_display (void) void pango_win32_shutdown_display (void) { - GList *tmp_list; - pango_win32_fontmap_cache_clear (fontmap); g_object_unref (G_OBJECT (fontmap)); - - return; } static void @@ -289,6 +281,7 @@ pango_win32_font_map_finalize (GObject *object) pango_win32_font_cache_free (win32fontmap->font_cache); /* ??? */ + G_OBJECT_CLASS (parent_class)->finalize (object); } typedef struct @@ -298,7 +291,9 @@ typedef struct } ListFontsInfo; static void -list_fonts_foreach (gpointer key, gpointer value, gpointer user_data) +list_fonts_foreach (gpointer key, + gpointer value, + gpointer user_data) { PangoWin32FamilyEntry *entry = value; ListFontsInfo *info = user_data; @@ -364,7 +359,9 @@ pango_win32_font_map_list_fonts (PangoFontMap *fontmap, } static void -list_families_foreach (gpointer key, gpointer value, gpointer user_data) +list_families_foreach (gpointer key, + gpointer value, + gpointer user_data) { GSList **list = user_data; @@ -372,9 +369,9 @@ list_families_foreach (gpointer key, gpointer value, gpointer user_data) } static void -pango_win32_font_map_list_families (PangoFontMap *fontmap, - gchar ***families, - int *n_families) +pango_win32_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families) { GSList *family_list = NULL; GSList *tmp_list; @@ -931,7 +928,7 @@ pango_win32_guess_subranges (UINT charset, return retval; } -static gboolean +static void pango_win32_setup_signature (PangoWin32FontMap *win32fontmap, LOGFONT *lfp, FONTSIGNATURE *sigp) @@ -940,7 +937,6 @@ pango_win32_setup_signature (PangoWin32FontMap *win32fontmap, HFONT hfont; HGDIOBJ oldfont; int charset; - int i; logfont = *lfp; logfont.lfHeight = 40; @@ -948,11 +944,11 @@ pango_win32_setup_signature (PangoWin32FontMap *win32fontmap, &logfont); if (!hfont) { - g_warning ("font \"%s\" (%sweight:%d) not available", + g_warning ("font \"%s\" (%sweight:%ld) not available", + logfont.lfFaceName, (logfont.lfItalic ? "italic," : ""), - logfont.lfWeight, - logfont.lfFaceName); - return FALSE; + logfont.lfWeight); + return; } oldfont = SelectObject (pango_win32_hdc, hfont); memset (sigp, 0, sizeof (*sigp)); @@ -969,9 +965,7 @@ pango_win32_font_map_read_alias_file (PangoWin32FontMap *win32fontmap, PangoWin32FontEntry *font_entry = NULL; FILE *infile; char **faces; - char *buf = NULL; int lineno = 0; - int charset; int nfaces; int i; @@ -1002,25 +996,25 @@ pango_win32_font_map_read_alias_file (PangoWin32FontMap *win32fontmap, if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_style (tmp_buf, &font_entry->description)) + if (!pango_parse_style (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_variant (tmp_buf, &font_entry->description)) + if (!pango_parse_variant (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_weight (tmp_buf, &font_entry->description)) + if (!pango_parse_weight (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_stretch (tmp_buf, &font_entry->description)) + if (!pango_parse_stretch (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) @@ -1030,7 +1024,7 @@ pango_win32_font_map_read_alias_file (PangoWin32FontMap *win32fontmap, faces = g_strsplit (tmp_buf->str, ",", -1); nfaces = 0; - for (i=0; faces[i]; i++) + for (i = 0; faces[i]; i++) { char *trimmed = pango_trim_string (faces[i]); g_free (faces[i]); @@ -1039,7 +1033,7 @@ pango_win32_font_map_read_alias_file (PangoWin32FontMap *win32fontmap, } font_entry->lfp = g_new0 (LOGFONT, nfaces); font_entry->n_fonts = nfaces; - for (i=0; i<nfaces; i++) + for (i = 0; i < nfaces; i++) { strcpy (font_entry->lfp[i].lfFaceName, faces[i]); @@ -1165,9 +1159,8 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, PangoWin32FamilyEntry *family_entry; PangoWin32FontEntry *font_entry; PangoWin32SizeInfo *size_info; - int i; - PING(("lfp.face=%s,wt=%d,ht=%d",lfp->lfFaceName,lfp->lfWeight,lfp->lfHeight)); + PING(("lfp.face=%s,wt=%ld,ht=%ld",lfp->lfFaceName,lfp->lfWeight,lfp->lfHeight)); description.size = 0; /* First insert the LOGFONT into the list of LOGFONTs for the typeface name @@ -1251,19 +1244,6 @@ pango_win32_insert_font (PangoWin32FontMap *win32fontmap, 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, @@ -1298,7 +1278,7 @@ pango_win32_make_matching_logfont (PangoFontMap *fontmap, LOGFONT *result = NULL; gint match_distance = 0; - PING(("lfp.face=%s,wt=%d,ht=%d,size:%d",lfp->lfFaceName,lfp->lfWeight,lfp->lfHeight,size)); + PING(("lfp.face=%s,wt=%ld,ht=%ld,size:%d",lfp->lfFaceName,lfp->lfWeight,lfp->lfHeight,size)); win32fontmap = PANGO_WIN32_FONT_MAP (fontmap); size_info = g_hash_table_lookup (win32fontmap->size_infos, lfp); @@ -1487,7 +1467,7 @@ pango_win32_font_entry_dump (int indent, indent, "", font_entry, indent, ""); - for (i=0; i<font_entry->n_fonts; i++) + for (i = 0; i < font_entry->n_fonts; i++) printf ("%*s LOGFONT:%s\n", indent, "", font_entry->lfp[i].lfFaceName); @@ -1530,7 +1510,9 @@ pango_win32_family_entry_dump (int indent, } static void -dump_family (gpointer key, gpointer value, gpointer user_data) +dump_family (gpointer key, + gpointer value, + gpointer user_data) { PangoWin32FamilyEntry *entry = value; int indent = (int) user_data; diff --git a/pango/pangowin32.c b/pango/pangowin32.c index d5e6663f..9bf2a026 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -90,18 +90,22 @@ 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 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); @@ -110,9 +114,11 @@ 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, @@ -540,6 +546,8 @@ pango_win32_unicode_classify (wchar_t wc) else return -1; } + /* NOTREACHED */ + return 0; } static void @@ -867,7 +875,7 @@ pango_win32_list_subfonts (PangoFont *font, LOGFONT *lfp; PangoWin32Font *win32font = (PangoWin32Font *)font; PangoWin32Subfont *subfont_list; - int i, j; + int i; int n_subfonts; g_return_val_if_fail (font != NULL, 0); @@ -985,7 +993,7 @@ subfont_has_glyph (PangoFont *font, info->oldfont = SelectObject (info->buf_hdc, info->hfont); SetTextAlign (info->buf_hdc, TA_LEFT|TA_BASELINE|TA_NOUPDATECP); GetTextMetrics (info->buf_hdc, &tm); - PING(("wt:%d,ht:%d",tm.tmMaxCharWidth,tm.tmHeight)); + PING(("wt:%ld,ht:%ld",tm.tmMaxCharWidth,tm.tmHeight)); info->default_char_hbm = create_bitmap_dibsection (info->buf_hdc, &info->default_char_buf, @@ -1279,7 +1287,6 @@ pango_win32_render_layout_line (HDC hdc, PangoRectangle overall_rect; PangoRectangle logical_rect; PangoRectangle ink_rect; - PangoContext *context = pango_layout_get_context (line->layout); int x_off = 0; diff --git a/pango/pangowin32.h b/pango/pangowin32.h index 7d040f5b..64275185 100644 --- a/pango/pangowin32.h +++ b/pango/pangowin32.h @@ -34,7 +34,32 @@ extern "C" { #define PANGO_RENDER_TYPE_WIN32 "PangoRenderWin32" -/* This enum divides Unicode characters according to the Microsoft +/* 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 + */ + +/* This enum classifies 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 @@ -115,69 +140,45 @@ typedef enum 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); - - +PangoWin32UnicodeSubrange pango_win32_unicode_classify (wchar_t wc); -/* 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); +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); /* 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); +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); +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); +LOGFONT *pango_win32_font_subfont_logfont (PangoFont *font, + PangoWin32Subfont subfont_id); /* Debugging. */ -void pango_win32_fontmap_dump (int indent, - PangoFontMap *fontmap); +void pango_win32_fontmap_dump (int indent, + PangoFontMap *fontmap); #ifdef __cplusplus } diff --git a/pango/pangox-fontmap.c b/pango/pangox-fontmap.c index 34a0cc3f..4a92c816 100644 --- a/pango/pangox-fontmap.c +++ b/pango/pangox-fontmap.c @@ -853,25 +853,25 @@ pango_x_font_map_read_alias_file (PangoXFontMap *xfontmap, if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_style (tmp_buf, &font_entry->description)) + if (!pango_parse_style (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_variant (tmp_buf, &font_entry->description)) + if (!pango_parse_variant (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_weight (tmp_buf, &font_entry->description)) + if (!pango_parse_weight (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) goto error; - if (!pango_parse_stretch (tmp_buf, &font_entry->description)) + if (!pango_parse_stretch (tmp_buf, &font_entry->description, TRUE)) goto error; if (!pango_scan_string (&p, tmp_buf)) |