#define _E_FONT_C_ /* * e-font * * Temporary wrappers around GdkFonts to get unicode displaying * * Author: Lauris Kaplinski * * Copyright (C) 2000 Helix Code, Inc. * */ #include #include #include #include "e-font.h" #define FONT_TESTING struct _EFont { gint refcount; GdkFont *font; gboolean bytes; unicode_iconv_t to; unicode_iconv_t from; }; EFont * e_font_from_gdk_name (const gchar *name) { EFont * font; GdkFont *gdkfont; gdkfont = gdk_fontset_load (name); font = e_font_from_gdk_font (gdkfont); gdk_font_unref (gdkfont); return font; } EFont * e_font_from_gdk_font (GdkFont *gdkfont) { EFont *font; XFontStruct *xfs; Atom font_atom, atom; Bool status; gdk_font_ref (gdkfont); /* Try to find iso-10646-1 encoded font with same name */ font_atom = gdk_atom_intern ("FONT", FALSE); if (gdkfont->type == GDK_FONT_FONTSET) { XFontStruct **font_structs; gint num_fonts; gchar **font_names; num_fonts = XFontsOfFontSet (GDK_FONT_XFONT (gdkfont), &font_structs, &font_names); status = XGetFontProperty (font_structs[0], font_atom, &atom); } else { status = XGetFontProperty (GDK_FONT_XFONT (gdkfont), font_atom, &atom); } if (status) { gchar *name, *p; gchar *newname; GdkFont *newfont; gint i; name = gdk_atom_name (atom); newname = alloca (strlen (name) + 12); strcpy (newname, name); p = newname; for (i = 0; i < 13; i++) { /* Skip hyphen */ while (*p && (*p != '-')) p++; if (*p) p++; } g_snprintf (p, 12, "ISO10646-1"); newfont = gdk_font_load (newname); if (newfont) { gdk_font_unref (gdkfont); gdkfont = newfont; } g_free (name); } font = g_new (EFont, 1); xfs = GDK_FONT_XFONT (gdkfont); font->refcount = 1; font->font = gdkfont; font->bytes = ((xfs->min_byte1 != 0) || (xfs->max_byte1 != 0)) ? 2 : 1; font->to = e_uiconv_to_gdk_font (font->font); font->from = e_uiconv_from_gdk_font (font->font); return font; } void e_font_ref (EFont *font) { font->refcount++; } void e_font_unref (EFont *font) { font->refcount--; if (font->refcount < 1) { gdk_font_unref (font->font); g_free (font); } } gint e_font_ascent (EFont * font) { return font->font->ascent; } gint e_font_descent (EFont * font) { return font->font->descent; } static gint e_font_to_native (EFont *font, gchar *native, gchar *utf, gint bytes) { char *ib, *ob; size_t ibl, obl; ib = utf; ibl = bytes; ob = native; obl = bytes * 4; while (ibl > 0) { unicode_iconv (font->to, (const char **) &ib, &ibl, &ob, &obl); if (ibl > 0) { gint len; if ((*ib & 0x80) == 0x00) len = 1; else if ((*ib &0xe0) == 0xc0) len = 2; else if ((*ib &0xf0) == 0xe0) len = 3; else if ((*ib &0xf80) == 0xf0) len = 4; else { g_warning ("Invalid UTF-8 sequence"); return ob - native; } ib += len; ibl = bytes - (ib - utf); if (ibl > bytes) ibl = 0; if (font->bytes == 1) { *ob++ = '_'; obl--; } else { *((guint16 *) ob) = '_'; ob += 2; obl -= 2; } } } return ob - native; } void e_font_draw_utf8_text (GdkDrawable *drawable, EFont *font, EFontStyle style, GdkGC *gc, gint x, gint y, gchar *text, gint numbytes) { gchar *native; gint native_bytes; g_return_if_fail (drawable != NULL); g_return_if_fail (font != NULL); g_return_if_fail (gc != NULL); g_return_if_fail (text != NULL); if (numbytes < 1) return; native = alloca (numbytes * 4); native_bytes = e_font_to_native (font, native, text, numbytes); gdk_draw_text (drawable, font->font, gc, x, y, native, native_bytes); if (style & E_FONT_BOLD) gdk_draw_text (drawable, font->font, gc, x + 1, y, native, native_bytes); } gint e_font_utf8_text_width (EFont *font, EFontStyle style, char *text, int numbytes) { gchar *native; gint native_bytes; gint width; g_return_val_if_fail (font != NULL, 0); g_return_val_if_fail (text != NULL, 0); if (numbytes < 1) return 0; native = alloca (numbytes * 4); native_bytes = e_font_to_native (font, native, text, numbytes); width = gdk_text_width (font->font, native, native_bytes); return width; } gint e_font_utf8_char_width (EFont *font, EFontStyle style, char *text) { gint len; g_return_val_if_fail (font != NULL, 0); g_return_val_if_fail (text != NULL, 0); if ((*text & 0x80) == 0x00) len = 1; else if ((*text &0xe0) == 0xc0) len = 2; else if ((*text &0xf0) == 0xe0) len = 3; else if ((*text &0xf80) == 0xf0) len = 4; else { g_warning ("Invalid UTF-8 sequence"); return 0; } return e_font_utf8_text_width (font, style, text, len); } static const gchar * translate_encoding (const gchar *encoding) { static GHashTable *eh = NULL; gchar e[64]; if (!eh) { eh = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (eh, "iso8859-1", "iso-8859-1"); g_hash_table_insert (eh, "iso8859-2", "iso-8859-2"); g_hash_table_insert (eh, "iso8859-3", "iso-8859-3"); g_hash_table_insert (eh, "iso8859-4", "iso-8859-4"); g_hash_table_insert (eh, "iso8859-5", "iso-8859-5"); g_hash_table_insert (eh, "iso8859-6", "iso-8859-6"); g_hash_table_insert (eh, "iso8859-7", "iso-8859-7"); g_hash_table_insert (eh, "iso8859-8", "iso-8859-8"); g_hash_table_insert (eh, "iso8859-9", "iso-8859-9"); g_hash_table_insert (eh, "iso8859-10", "iso-8859-10"); g_hash_table_insert (eh, "iso8859-13", "iso-8859-13"); g_hash_table_insert (eh, "iso8859-14", "iso-8859-14"); g_hash_table_insert (eh, "iso8859-15", "iso-8859-15"); g_hash_table_insert (eh, "iso10646-1", "UTF-16"); g_hash_table_insert (eh, "koi8-r", "koi8-r"); } strncpy (e, encoding, 64); g_strdown (e); return g_hash_table_lookup (eh, e); } const gchar * e_gdk_font_encoding (GdkFont *font) { Atom font_atom, atom; Bool status; char *name, *p; const gchar *encoding; gint i; if (!font) return NULL; font_atom = gdk_atom_intern ("FONT", FALSE); if (font->type == GDK_FONT_FONTSET) { XFontStruct **font_structs; gint num_fonts; gchar **font_names; num_fonts = XFontsOfFontSet (GDK_FONT_XFONT (font), &font_structs, &font_names); status = XGetFontProperty (font_structs[0], font_atom, &atom); } else { status = XGetFontProperty (GDK_FONT_XFONT (font), font_atom, &atom); } if (!status) return NULL; name = p = gdk_atom_name (atom); for (i = 0; i < 13; i++) { /* Skip hyphen */ while (*p && (*p != '-')) p++; if (*p) p++; } if (!*p) return NULL; encoding = translate_encoding (p); g_free (name); return encoding; } unicode_iconv_t e_uiconv_from_gdk_font (GdkFont *font) { static GHashTable *uh = NULL; const gchar *enc; unicode_iconv_t uiconv; if (!font) return (unicode_iconv_t) -1; enc = e_gdk_font_encoding (font); if (!enc) return (unicode_iconv_t) -1; if (!uh) uh = g_hash_table_new (g_str_hash, g_str_equal); uiconv = g_hash_table_lookup (uh, enc); if (!uiconv) { uiconv = unicode_iconv_open ("UTF-8", enc); if (uiconv == (unicode_iconv_t) -1) return uiconv; g_hash_table_insert (uh, (gpointer) enc, uiconv); } return uiconv; } unicode_iconv_t e_uiconv_to_gdk_font (GdkFont *font) { static GHashTable *uh = NULL; const gchar *enc; unicode_iconv_t uiconv; if (!font) return (unicode_iconv_t) -1; enc = e_gdk_font_encoding (font); if (!enc) return (unicode_iconv_t) -1; if (!uh) uh = g_hash_table_new (g_str_hash, g_str_equal); uiconv = g_hash_table_lookup (uh, enc); if (!uiconv) { uiconv = unicode_iconv_open (enc, "UTF-8"); if (uiconv == (unicode_iconv_t) -1) return uiconv; g_hash_table_insert (uh, (gpointer) enc, uiconv); } return uiconv; }