/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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. */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include #include #include #include "gdkfont.h" #include "gdkprivate-fb.h" #include "gdkpango.h" #include #include #if !defined(FREETYPE_MAJOR) || FREETYPE_MAJOR != 2 #error "We need Freetype 2.0" #endif #ifdef EMULATE_GDKFONT static GHashTable *font_name_hash = NULL; static GHashTable *fontset_name_hash = NULL; static void gdk_font_hash_insert (GdkFontType type, GdkFont *font) { GdkFontPrivateFB *private = (GdkFontPrivateFB *)font; GHashTable **hashp = (type == GDK_FONT_FONT) ? &font_name_hash : &fontset_name_hash; if (!*hashp) *hashp = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (*hashp, private->name, font); } static void gdk_font_hash_remove (GdkFontType type, GdkFont *font) { GdkFontPrivateFB *private = (GdkFontPrivateFB *)font; GHashTable *hash = (type == GDK_FONT_FONT) ? font_name_hash : fontset_name_hash; g_hash_table_remove (hash, private->name); } static GdkFont * gdk_font_hash_lookup (GdkFontType type, const gchar *font_name) { GdkFont *result; GHashTable *hash = (type == GDK_FONT_FONT) ? font_name_hash : fontset_name_hash; if (!hash) return NULL; else { result = g_hash_table_lookup (hash, font_name); if (result) gdk_font_ref (result); return result; } } GdkFont* gdk_font_from_description (PangoFontDescription *desc) { GdkFont *font; GdkFontPrivateFB *private; PangoFont *pango_font; PangoContext *context; PangoFontMetrics metrics; gchar *lang; g_return_val_if_fail (desc, NULL); private = g_new0 (GdkFontPrivateFB, 1); private->base.ref_count = 1; private->name = NULL; font = (GdkFont*) private; font->type = GDK_FONT_FONT; context = gdk_pango_context_get (); pango_font = pango_context_load_font (context, desc); if (!pango_font) { desc = pango_font_description_copy (desc); g_free (desc->family_name); desc->family_name = g_strdup ("sans"); pango_font = pango_context_load_font (context, desc); if (!pango_font) { desc->style = PANGO_STYLE_NORMAL; desc->weight = PANGO_WEIGHT_NORMAL; desc->variant = PANGO_VARIANT_NORMAL; desc->stretch = PANGO_STRETCH_NORMAL; pango_font = pango_context_load_font (context, desc); } pango_font_description_free (desc); } g_assert (pango_font != NULL); if (pango_font == NULL) { g_free (private); return NULL; } metrics.ascent = 0; metrics.descent = 0; lang = pango_context_get_lang (context); pango_font_get_metrics (pango_font, "fr", &metrics); private->pango_font = pango_font; g_free (lang); g_object_unref (G_OBJECT (context)); font->ascent = PANGO_PIXELS (metrics.ascent); font->descent = PANGO_PIXELS (metrics.descent); g_assert ((font->ascent > 0) || (font->descent > 0)); return font; } GdkFont* gdk_font_load (const gchar *font_name) { GdkFont *font; GdkFontPrivateFB *private; PangoFontDescription desc; gchar **pieces; g_return_val_if_fail (font_name != NULL, NULL); font = gdk_font_hash_lookup (GDK_FONT_FONT, font_name); if (font) return font; /* Default values */ desc.family_name = NULL; desc.style = PANGO_STYLE_NORMAL; desc.weight = PANGO_WEIGHT_NORMAL; desc.variant = PANGO_VARIANT_NORMAL; desc.stretch = PANGO_STRETCH_NORMAL; desc.size = 0; pieces = g_strsplit (font_name, "-", 8); do { if (!pieces[0]) break; if (!pieces[1]) break; if (!pieces[2]) break; if (strcmp (pieces[2], "*")!=0) desc.family_name = g_strdup (pieces[2]); if (!pieces[3]) break; if (strcmp (pieces[3], "light")==0) desc.weight = PANGO_WEIGHT_LIGHT; if (strcmp (pieces[3], "medium")==0) desc.weight = PANGO_WEIGHT_NORMAL; if (strcmp (pieces[3], "bold")==0) desc.weight = PANGO_WEIGHT_BOLD; if (!pieces[4]) break; if (strcmp (pieces[4], "r")==0) desc.style = PANGO_STYLE_NORMAL; if (strcmp (pieces[4], "i")==0) desc.style = PANGO_STYLE_ITALIC; if (strcmp (pieces[4], "o")==0) desc.style = PANGO_STYLE_OBLIQUE; if (!pieces[5]) break; if (!pieces[6]) break; if (!pieces[7]) break; if (strcmp (pieces[7], "*")!=0) desc.size = atoi (pieces[7]) * PANGO_SCALE; if (desc.size == 0) desc.size = 12 * PANGO_SCALE; } while (0); font = gdk_font_from_description (&desc); private = (GdkFontPrivateFB*) font; private->name = g_strdup (font_name); gdk_font_hash_insert (GDK_FONT_FONT, font); g_strfreev(pieces); g_free (desc.family_name); return font; } GdkFont* gdk_fontset_load (const gchar *fontset_name) { return gdk_font_load(fontset_name); } void _gdk_font_destroy (GdkFont *font) { GdkFontPrivateFB *private = (GdkFontPrivateFB *)font; gdk_font_hash_remove (font->type, font); g_object_unref (G_OBJECT (private->pango_font)); g_free (private->name); g_free (font); } gint _gdk_font_strlen (GdkFont *font, const gchar *str) { GdkFontPrivateFB *font_private; g_return_val_if_fail (font != NULL, -1); g_return_val_if_fail (str != NULL, -1); font_private = (GdkFontPrivateFB*) font; return strlen (str); } gint gdk_text_width (GdkFont *font, const gchar *text, gint text_length) { gint width = -1; gdk_text_extents (font, text, text_length, NULL, NULL, &width, NULL, NULL); return width; } /* Assumes text is in Latin-1 for performance reasons. If you need another encoding, use pangofont */ void gdk_text_extents (GdkFont *font, const gchar *text, gint text_length, gint *lbearing, gint *rbearing, gint *width, gint *ascent, gint *descent) { GdkFontPrivateFB *private; guchar *utf8, *utf8_end; PangoGlyphString *glyphs = pango_glyph_string_new (); PangoEngineShape *shaper, *last_shaper; PangoAnalysis analysis; guchar *p, *start; int i; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); private = (GdkFontPrivateFB*) font; if(ascent) *ascent = 0; if(descent) *descent = 0; if(width) *width = 0; if(lbearing) *lbearing = 0; if(rbearing) *rbearing = 0; utf8 = alloca (text_length*2); /* Convert latin-1 to utf8 */ p = utf8; for (i = 0; i < text_length; i++) { if (text[i]==0) *p++ = 1; /* Hack to handle embedded nulls */ else { if(((guchar)text[i])<128) *p++ = text[i]; else { *p++ = ((((guchar)text[i])>>6) & 0x3f) | 0xC0; *p++ = (((guchar)text[i]) & 0x3f) | 0x80; } } } utf8_end = p; last_shaper = NULL; shaper = NULL; p = start = utf8; while (p < utf8_end) { gunichar wc = g_utf8_get_char (p); p = g_utf8_next_char (p); shaper = pango_font_find_shaper (private->pango_font, "fr", wc); if (shaper != last_shaper) { analysis.shape_engine = shaper; analysis.lang_engine = NULL; analysis.font = private->pango_font; analysis.level = 0; pango_shape (start, p - start, &analysis, glyphs); for (i = 0; i < glyphs->num_glyphs; i++) { PangoRectangle ink_rect; PangoGlyphGeometry *geometry = &glyphs->glyphs[i].geometry; pango_font_get_glyph_extents (private->pango_font, glyphs->glyphs[i].glyph, &ink_rect, NULL); if(ascent) *ascent = MAX (*ascent, ink_rect.y); if(descent) *descent = MAX (*descent, ink_rect.height - ink_rect.y); if(width) *width += geometry->width; if(lbearing) *lbearing = 0; if(rbearing) *rbearing = 0; } start = p; } last_shaper = shaper; } if (p > start) { analysis.shape_engine = shaper; analysis.lang_engine = NULL; analysis.font = private->pango_font; analysis.level = 0; pango_shape (start, p - start, &analysis, glyphs); for (i = 0; i < glyphs->num_glyphs; i++) { PangoRectangle ink_rect; PangoGlyphGeometry *geometry = &glyphs->glyphs[i].geometry; pango_font_get_glyph_extents (private->pango_font, glyphs->glyphs[i].glyph, &ink_rect, NULL); if(ascent) *ascent = MAX (*ascent, ink_rect.y); if(descent) *descent = MAX (*descent, ink_rect.height - ink_rect.y); if(width) *width += geometry->width; if(lbearing) *lbearing = 0; if(rbearing) *rbearing = 0; } } pango_glyph_string_free (glyphs); if(ascent) *ascent = PANGO_PIXELS (*ascent); if(descent) *descent = PANGO_PIXELS(*descent); if(width) *width = PANGO_PIXELS (*width); if(lbearing) *lbearing = PANGO_PIXELS (*lbearing); if(rbearing) *rbearing = PANGO_PIXELS (*rbearing); } #else /* Don't emulate GdkFont */ static GdkFont * gdk_fb_bogus_font (gint height) { GdkFont *font; GdkFontPrivateFB *private; private = g_new0 (GdkFontPrivateFB, 1); font = (GdkFont *)private; font->type = GDK_FONT_FONT; font->ascent = height*3/4; font->descent = height/4; private->size = height; private->base.ref_count = 1; return font; } GdkFont* gdk_font_from_description (PangoFontDescription *font_desc) { g_return_val_if_fail (font_desc, NULL); return gdk_fb_bogus_font (PANGO_PIXELS (font_desc->size)); } GdkFont* gdk_fontset_load (const gchar *fontset_name) { return gdk_fb_bogus_font (10); } GdkFont * gdk_font_load (const gchar *font_name) { return gdk_fb_bogus_font (10); } void _gdk_font_destroy (GdkFont *font) { g_free (font); } gint _gdk_font_strlen (GdkFont *font, const gchar *str) { GdkFontPrivateFB *font_private; gint length = 0; g_return_val_if_fail (font != NULL, -1); g_return_val_if_fail (str != NULL, -1); font_private = (GdkFontPrivateFB*) font; return strlen (str); } gint gdk_text_width (GdkFont *font, const gchar *text, gint text_length) { GdkFontPrivateFB *private; private = (GdkFontPrivateFB*) font; return (text_length * private->size) / 2; } void gdk_text_extents (GdkFont *font, const gchar *text, gint text_length, gint *lbearing, gint *rbearing, gint *width, gint *ascent, gint *descent) { if(ascent) *ascent = font->ascent; if(descent) *descent = font->descent; if(width) *width = gdk_text_width(font, text, text_length); if(lbearing) *lbearing = 0; if(rbearing) *rbearing = 0; } #endif gint gdk_font_id (const GdkFont *font) { const GdkFontPrivateFB *font_private; g_return_val_if_fail (font != NULL, 0); font_private = (const GdkFontPrivateFB*) font; if (font->type == GDK_FONT_FONT) { return -1; } else { return 0; } } gint gdk_font_equal (const GdkFont *fonta, const GdkFont *fontb) { const GdkFontPrivateFB *privatea; const GdkFontPrivateFB *privateb; g_return_val_if_fail (fonta != NULL, FALSE); g_return_val_if_fail (fontb != NULL, FALSE); privatea = (const GdkFontPrivateFB*) fonta; privateb = (const GdkFontPrivateFB*) fontb; if(fonta == fontb) return TRUE; return FALSE; } gint gdk_text_width_wc (GdkFont *font, const GdkWChar *text, gint text_length) { return 0; } void gdk_text_extents_wc (GdkFont *font, const GdkWChar *text, gint text_length, gint *lbearing, gint *rbearing, gint *width, gint *ascent, gint *descent) { g_warning ("gdk_text_extents_wc() is not implemented\n"); return; }