Pango API (Re: Many fixes and enhancement about font handling)



From: Shun-ichi TAHARA <jado flowernet gr jp>
Message-Id: <20030813 231543 971168940 jado flowernet gr jp>

> # I have one more patch to submit :-)...

Here is the one.

In non-latin (especially in CJK) environment, we want to use various
cool latin fonts. But those fonts does not have glyphs for our local
language (for example, Kanji or Kana character in Japanese, or Hangul
character in Korea). We often handle strings where the latin
characters and those local characters are mixed, and we expects that
the glyph-rendering engine to fallback other existing font for local
characters. Raw Xft API does not have such features, but Pango API
does. So I implemented "Pango" font handling method on Sawfish.

The following patch can be applied after the last (in "Many fixes and
enhancement about font handling") patch.

This enable setting font as
  (setq default-font '("pango" . "Nimbus Sans L, Bold 12"))
and if Xft features is activated, sawfish-ui stores selected font as
pango-type one.
--
S. Tahara

diff -ru sawfish-1.3.fontfix/lisp/sawfish/gtk/widgets/font.jl sawfish-1.3/lisp/sawfish/gtk/widgets/font.jl
--- sawfish-1.3.fontfix/lisp/sawfish/gtk/widgets/font.jl	2003-08-12 18:56:30.000000000 +0900
+++ sawfish-1.3/lisp/sawfish/gtk/widgets/font.jl	2003-08-12 18:57:02.000000000 +0900
@@ -73,6 +73,8 @@
 			  (gtk-entry-set-text entry x))
 			 ((consp x)
 			  (let ((face (cond
+					((string-equal (car x) "pango")
+					 (pango-description->face (cdr x)))
 					((string-equal (car x) "Xft")
 					 (xft-description->face (cdr x)))
 					((string-equal (car x) "xlfd")
@@ -87,7 +89,8 @@
 		   (let* ((pango-name (gtk-entry-get-text entry))
 			  (face (pango-description->face pango-name)))
 		     (cond ((not face) nil)
-			   (use-xft (cons "Xft" (face->xft-description face)))
+			   (use-xft
+			    (cons "pango" (face->pango-description face)))
 			   (t (cons "xlfd" (face->xlfd-description face)))))))
 	  ((gtk-widget) box)
 	  ((validp) (lambda (x) (stringp x)))))))
diff -ru sawfish-1.3.fontfix/src/fonts.c sawfish-1.3/src/fonts.c
--- sawfish-1.3.fontfix/src/fonts.c	2003-08-12 18:56:30.000000000 +0900
+++ sawfish-1.3/src/fonts.c	2003-08-12 18:58:02.000000000 +0900
@@ -45,6 +45,13 @@
 #ifdef HAVE_X11_XFT_XFT_H
 # include <X11/Xft/Xft.h>
 # include <glib.h>
+# define PANGO_ENABLE_BACKEND
+# include <pango/pango.h>
+# undef PANGO_ENABLE_BACKEND
+# include <pango/pangox.h>
+# define PANGO_ENABLE_ENGINE
+# include <pango/pangoxft.h>
+# undef PANGO_ENABLE_ENGINE
 #endif
 
 static Lisp_Font *font_list;
@@ -435,6 +442,167 @@
     xft_measure, xft_draw,
 };
 
+
+/* Pango fonts */
+
+static PangoContext *pango_context;
+
+static bool
+pango_load (Lisp_Font *f)
+{
+    PangoLanguage *language;
+    PangoFontDescription *fontdesc;
+    PangoFont *font;
+    PangoFontMetrics *metrics;
+
+    if (pango_context) {
+	language = pango_context_get_language (pango_context);
+    } else {
+	char *langname, *p;
+
+	pango_context = pango_xft_get_context (dpy, screen_num);
+
+	langname = g_strdup (setlocale (LC_CTYPE, NULL));
+	p = strchr (langname, '.');
+	if (p)
+	    *p = 0;
+	p = strchr (langname, '@');
+	if (p)
+	    *p = 0;
+	language = pango_language_from_string (langname);
+	pango_context_set_language (pango_context, language);
+	g_free (langname);
+    }
+
+    fontdesc = pango_font_description_from_string (rep_STR (f->name));
+
+    if (!pango_font_description_get_family (fontdesc))
+	pango_font_description_set_family (fontdesc, "Sans");
+    if (pango_font_description_get_size (fontdesc) <= 0)
+	pango_font_description_set_size (fontdesc, 12 * PANGO_SCALE);
+
+    pango_context_set_font_description (pango_context, fontdesc);
+    font = pango_context_load_font (pango_context, fontdesc);
+
+    if (!font)
+	return FALSE;
+
+    metrics = pango_font_get_metrics (font, language);
+
+    f->font = font;
+    f->ascent = metrics->ascent / PANGO_SCALE;
+    f->descent = metrics->descent / PANGO_SCALE;
+
+    pango_font_metrics_unref (metrics);
+
+    return TRUE;
+}
+
+static void
+pango_finalize (Lisp_Font *f)
+{
+    g_object_unref (f->font);
+}
+
+static int
+pango_measure (Lisp_Font *f, u_char *string, size_t length)
+{
+    gsize r, w;
+    u_char *utf8str;
+    PangoLayout *layout;
+    PangoRectangle rect;
+
+    utf8str = g_locale_to_utf8 (string, length, &r, &w, NULL);
+    if (utf8str != NULL) {
+	string = utf8str;
+	length = w;
+    }
+
+    layout = pango_layout_new (pango_context);
+    pango_layout_set_text (layout, string, length);
+
+    pango_layout_get_extents (layout, NULL, &rect);
+
+    g_free (utf8str);
+    g_object_unref (layout);
+ 
+    return rect.width / PANGO_SCALE;
+}
+
+static void
+pango_draw_line (XftDraw *draw, Window id, GC gc, XftColor *xft_color,
+		 PangoLayoutLine *line, int x, int y)
+{
+    GSList *p;
+
+    for (p = line->runs; p != NULL; p = p->next) {
+	PangoLayoutRun *run = p->data;
+	PangoFont *font = run->item->analysis.font;
+	PangoGlyphString *glyphs = run->glyphs;
+	PangoRectangle rect;
+
+	pango_glyph_string_extents (glyphs, font, NULL, &rect);
+	if (PANGO_XFT_IS_FONT (font)) {
+	    pango_xft_render (draw, xft_color, font, glyphs, x, y);
+	} else {
+	    pango_x_render (dpy, id, gc, font, glyphs, x, y);
+	}
+	x += rect.width / PANGO_SCALE;
+    }
+}
+
+static void
+pango_draw (Lisp_Font *f, u_char *string, size_t length,
+	    Window id, GC gc, Lisp_Color *fg, int x, int y)
+{
+    static XftDraw *draw;
+    XftColor xft_color;
+    gsize r, w;
+    u_char *utf8str;
+    PangoLayout *layout;
+    PangoLayoutIter *iter;
+
+    if (draw == 0)
+	draw = XftDrawCreate (dpy, id, image_visual, image_cmap);
+    else
+	XftDrawChange (draw, id);
+
+    xft_color.pixel = fg->pixel;
+    xft_color.color.red = fg->red;
+    xft_color.color.green = fg->green;
+    xft_color.color.blue = fg->blue;
+    xft_color.color.alpha = fg->alpha;
+
+    utf8str = g_locale_to_utf8 (string, length, &r, &w, NULL);
+    if (utf8str != NULL) {
+	string = utf8str;
+	length = w;
+    }
+
+    layout = pango_layout_new (pango_context);
+    pango_layout_set_text (layout, string, length);
+    iter = pango_layout_get_iter (layout);
+
+    do {
+	PangoLayoutLine *line = pango_layout_iter_get_line (iter);
+	PangoRectangle rect;
+
+	pango_layout_iter_get_line_extents (iter, NULL, &rect);
+	pango_draw_line (draw, id, gc, &xft_color,
+			 line, x + rect.x / PANGO_SCALE, y);
+    } while (pango_layout_iter_next_line (iter));
+
+    g_free (utf8str);
+    g_object_unref (layout);
+    pango_layout_iter_free (iter);
+}
+
+static const Lisp_Font_Class pango_class = {
+    "pango",
+    pango_load, pango_finalize,
+    pango_measure, pango_draw,
+};
+
 #endif /* HAVE_X11_XFT_XFT_H */
 
 
@@ -445,6 +613,7 @@
     &fontset_class,
 #ifdef HAVE_X11_XFT_XFT_H
     &xft_class,
+    &pango_class,
 #endif
     0,
 };
@@ -810,14 +979,15 @@
     rep_INTERN_SPECIAL(default_font);
     if (!batch_mode_p ())
     {
-	DEFSTRING (xft_type, "xft");
-	DEFSTRING (xft_name, "Sans");
+	DEFSTRING (pango_type, "pango");
+	DEFSTRING (pango_name, "Sans");
 	DEFSTRING (xlfd_type, "xlfd");
 	DEFSTRING (xlfd_name, "fixed");
 	repv font;
 
 	if (use_xft ()) {
-	    font = Fget_font_typed (rep_VAL (&xft_type), rep_VAL (&xft_name));
+	    font = Fget_font_typed (
+			rep_VAL (&pango_type), rep_VAL (&pango_name));
 	} else {
 	    font = Fget_font_typed (rep_VAL (&xlfd_type), rep_VAL (&xlfd_name));
 	}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]