[patch] Rework of Pango integration

Owen Taylor <[email protected]>
Newsgroups gmane.comp.gnome.print
Message-ID <[email protected]>
I've been working recently on redoing the Pango support in gnome-print;
here's a first pass at a patch.

It's actually not that conceptually different from what Jean did
with gnome_print_pango_layout_print() ... it doesn't create a new
Pango backend, but simply uses the FT2 backend and converts
PangoFont to GnomeFont when creating the GnomeGlyphList structures.

Differences:

 * I've added some API so that it works the same way that I want to do
   Cairo integration. This means:

   - The fact that there isn't a separate backend is hidden
   - The API has provisions for doing resolution optimized layout,
     something that we'll need to do for Cairo though it doesn't
     make sense for gnome-print.

 * I've changed how PangoFont => GnomeFont works so that instead of
   doing it at a "naming" level, it actually maps according to font
   file.

 * I've added API for drawing PangoLayoutLine and PangoGlyphString
   as well as entire PangoLayouts.

 * I've rewritten the drawing code from scratch to use PangoLayoutIter,
   support more underline types, etc. 

Other notes:

 * Since this is the first time I've really touched the gnome-print
   code (or even used the gnome-print APIs), if someone wants to
   review the changes that would be good. 

 * I'd consider this patch "done" other than review comments; 
   it's reasonably well documented and commented and should
   be pretty much complete. The one thing I can think of that
   needs fixing is:

    http://bugzilla.gnome.org/show_bug.cgi?id=114431

   But that mostly comes up for menu-style partial-word underlines.

 * The patch makes gnome-print require CVS head Pango but for a
   pretty surface reason; all that is being used is the
   new underline and strikethrough font metrics. It would be
   pretty easy to add a configure check and fallbacks for that.

 * Code is written for simplicity rather than performance; some
   of the gnome_print_gsave/grestore could be optimized away.

The next thing in my sights is to get the gtkhtml and gtksourceview
(gedit) printing code using this stuff. That, I think, should be
a pretty good test for whether the API and implementation is
right.

Regards,
					Owen

_______________________________________________
gnome-print-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gnome-print-list
gnome-print-pango.diff (text/plain, 54.3 KB)
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libgnomeprint/ChangeLog,v
retrieving revision 1.394
diff -u -p -u -r1.394 ChangeLog
--- ChangeLog	11 Mar 2004 21:14:21 -0000	1.394
+++ ChangeLog	4 Jun 2004 00:52:08 -0000
@@ -1,3 +1,23 @@
+Thu Jun  3 19:21:22 2004  Owen Taylor  <[email protected]>
+
+	* configure.in: Require version 1.5 of Pango and the
+	PangoFT2 library.
+
+        * libgnomeprint/gnome-print-pango.[ch]: Extend printing
+	API to allow printing layout lines and glyph strings
+	as well as entire layouts. Reimplement from scratch.
+
+	* libgnomeprint/gnome-fontmap.[ch]: Add a hash table from
+	filename/index to font face to the font map.
+
+	* libgnomeprint/gnome-font-face.[ch] Add
+	gnome_font_face_find_from_filename() to
+	gnome_font_find_from_filename() allow looking up faces by
+	filename. This allows us to reliably convert a PangoFont into a
+	GnomeFont.
+
+	* tests/pango.c tests/Makefile.am: Add a test case for Pango layouts
+
 2004-03-11  Jody Goldberg <[email protected]>
 
 	* configure.in : post release bump
Index: configure.in
===================================================================
RCS file: /cvs/gnome/libgnomeprint/configure.in,v
retrieving revision 1.279
diff -u -p -u -r1.279 configure.in
--- configure.in	11 Mar 2004 21:14:21 -0000	1.279
+++ configure.in	4 Jun 2004 00:52:08 -0000
@@ -132,7 +132,7 @@ dnl pkg-config checks
 dnl =================
 glib_modules="glib-2.0 >= 1.3.10 gobject-2.0 >= 1.3.10 gmodule-2.0 >= 1.3.10"
 libart_modules="libart-2.0 >= 2.3.7"
-pango_modules="pango >= 0.21"
+pango_modules="pango >= 1.5 pangoft2 >= 1.5"
 libxml2_modules="libxml-2.0 >= 2.4.23"
 fontconfig_modules="fontconfig >= 1.0"
 PKG_CHECK_MODULES(GP, [ $glib_modules $libart_modules $pango_modules $libxml2_modules $libbonobo_modules $fontconfig_modules ])
Index: doc/reference/libgnomeprint-docs.sgml
===================================================================
RCS file: /cvs/gnome/libgnomeprint/doc/reference/libgnomeprint-docs.sgml,v
retrieving revision 1.7
diff -u -p -u -r1.7 libgnomeprint-docs.sgml
--- doc/reference/libgnomeprint-docs.sgml	1 Feb 2004 10:18:32 -0000	1.7
+++ doc/reference/libgnomeprint-docs.sgml	4 Jun 2004 00:52:08 -0000
@@ -4,6 +4,7 @@
 <!ENTITY gnome-font SYSTEM "xml/gnome-font.xml">
 <!ENTITY gnome-glyphlist SYSTEM "xml/gnome-glyphlist.xml">
 <!ENTITY gnome-pgl SYSTEM "xml/gnome-pgl.xml">
+<!ENTITY gnome-print-pango SYSTEM "xml/gnome-print-pango.xml">
 <!ENTITY gnome-print-config SYSTEM "xml/gnome-print-config.xml">
 <!ENTITY gnome-print-job SYSTEM "xml/gnome-print-job.xml">
 <!ENTITY gnome-print-paper SYSTEM "xml/gnome-print-paper.xml">
@@ -62,6 +63,7 @@ for instance, the current version of GNO
     &gnome-print-job;
     &gnome-print-paper;
     &gnome-print;
+    &gnome-print-pango;
     &gnome-print-unit;
     &gnome-rfont;
   </part>
Index: doc/reference/libgnomeprint-sections.txt
===================================================================
RCS file: /cvs/gnome/libgnomeprint/doc/reference/libgnomeprint-sections.txt,v
retrieving revision 1.6
diff -u -p -u -r1.6 libgnomeprint-sections.txt
--- doc/reference/libgnomeprint-sections.txt	6 Jan 2003 19:06:03 -0000	1.6
+++ doc/reference/libgnomeprint-sections.txt	4 Jun 2004 00:52:08 -0000
@@ -8,6 +8,7 @@ gnome_font_face_find_closest_from_weight
 gnome_font_face_find_closest_from_pango_font
 gnome_font_face_find_closest_from_pango_description
 gnome_font_face_find_from_family_and_style
+gnome_font_face_find_from_filename
 gnome_font_face_get_font
 gnome_font_face_get_font_default
 gnome_font_face_get_name
@@ -70,6 +71,7 @@ gnome_font_find_closest_from_weight_slan
 gnome_font_find
 gnome_font_find_closest
 gnome_font_find_from_full_name
+gnome_font_find_from_filename
 gnome_font_find_closest_from_full_name
 gnome_font_list
 gnome_font_list_free
@@ -183,6 +185,20 @@ GNOME_PRINT_CONTEXT
 GNOME_IS_PRINT_CONTEXT
 GNOME_TYPE_PRINT_CONTEXT
 gnome_print_context_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gnome-print-pango</FILE>
+<TITLE>Pango Integration</TITLE>
+gnome_print_pango_font_map_new
+gnome_print_pango_get_default_font_map
+gnome_print_pango_create_context
+gnome_print_pango_update_context
+gnome_print_pango_create_layout
+gnome_print_pango_glyph_string
+gnome_print_pango_layout_line
+gnome_print_pango_layout
+gnome_print_pango_layout_print
 </SECTION>
 
 <SECTION>
Index: doc/reference/tmpl/gnome-font-face.sgml
===================================================================
RCS file: /cvs/gnome/libgnomeprint/doc/reference/tmpl/gnome-font-face.sgml,v
retrieving revision 1.2
diff -u -p -u -r1.2 gnome-font-face.sgml
--- doc/reference/tmpl/gnome-font-face.sgml	2 Jun 2002 10:27:39 -0000	1.2
+++ doc/reference/tmpl/gnome-font-face.sgml	4 Jun 2004 00:52:08 -0000
@@ -87,6 +87,16 @@ gnome-font-face
 @Returns: 
 
 
+<!-- ##### FUNCTION gnome_font_face_find_from_filename ##### -->
+<para>
+
+</para>
+
+@filename: 
+@index_: 
+@Returns: 
+
+
 <!-- ##### FUNCTION gnome_font_face_get_font ##### -->
 <para>
 
Index: doc/reference/tmpl/gnome-font.sgml
===================================================================
RCS file: /cvs/gnome/libgnomeprint/doc/reference/tmpl/gnome-font.sgml,v
retrieving revision 1.3
diff -u -p -u -r1.3 gnome-font.sgml
--- doc/reference/tmpl/gnome-font.sgml	2 Jun 2002 10:27:39 -0000	1.3
+++ doc/reference/tmpl/gnome-font.sgml	4 Jun 2004 00:52:08 -0000
@@ -293,6 +293,17 @@ gnome-font
 @Returns: 
 
 
+<!-- ##### FUNCTION gnome_font_find_from_filename ##### -->
+<para>
+
+</para>
+
+@filename: 
+@index_: 
+@size: 
+@Returns: 
+
+
 <!-- ##### FUNCTION gnome_font_find_closest_from_full_name ##### -->
 <para>
 
Index: doc/reference/tmpl/gnome-print-pango.sgml
===================================================================
RCS file: doc/reference/tmpl/gnome-print-pango.sgml
diff -N doc/reference/tmpl/gnome-print-pango.sgml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ doc/reference/tmpl/gnome-print-pango.sgml	4 Jun 2004 00:52:08 -0000
@@ -0,0 +1,200 @@
+<!-- ##### SECTION Title ##### -->
+Pango Integration
+
+<!-- ##### SECTION Short_Description ##### -->
+Using gnome-print with Pango
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+The functions in this section allow you to use gnome-print to
+draw text using the sophisticated layout and internationalization
+capabilities of the Pango library. In general, for a GNOME
+application, these are the text APIs you should be using.
+</para>
+<para>
+There are a number of different types of objects involved in
+using #Pango with gnome-print.
+</para>
+<variablelist>
+  <varlistentry>
+    <term><link linkend="PangoFontMap">PangoFontMap</link></term>
+    <listitem>
+      <para>
+        A <link linkend="PangoFontMap">PangoFontMap</link> contains
+        the information necessary to resolve abstract font names
+        to particular fonts on the system. A font map appropriate
+        for use with gnome-print is created using
+<link
+linkend="gnome-print-pango-font-map-new"><function>gnome_print_pango_font_map_new()</function></link>.
+        Normally instead of creating a new font map, you can just
+        use the global default font map returned by
+<link
+linkend="gnome-print-pango-get-default-font-map"><function>gnome_print_pango_get_default_font_map()</function></link>.
+        The only exception to this is if you need to use lower level
+        Pango APIs to customize how the font name to font lookup is
+        done, since modifying the global default font map isn't allowed.
+      </para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term><link linkend="PangoContext">PangoContext</link></term>
+    <listitem>
+      <para>
+        Information about doing layout for a particular output device
+        with a particular set of options is
+        encapsulated into a <link
+        linkend="PangoContext">PangoContext</link>. Contexts for
+        gnome-print are created using
+        <link
+linkend="gnome-print-pango-create-context"><function>gnome_print_pango_create_context()</function></link>
+      </para>
+      <para>
+        A Pango context created in this way is not specific to a
+        particular <link
+        linkend="GnomePrintContext">GnomePrintContext</link> but
+        before using a Pango context to do layout for a gnome-print
+        context, it's necessary to call
+        <link
+linkend="gnome-print-pango-update-context"><function>gnome_print_pango_update_context()</function></link>.
+        This function also needs to be called if when the current
+        transformation matrix changes.
+      </para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term><link linkend="PangoLayout">PangoLayout</link></term>
+    <listitem>
+      <para>
+        A <link linkend="PangoLayout">PangoLayout</link> holds one or more paragraphs of text
+        and encapsulates all the necessary logic needed to
+        line wrap and lay out the text. Once you have a 
+        #PangoContext, you can create a layout using
+        <link linkend="pango_layout_new"><function>pango_layout_new()</function></link>.
+      </para>
+    </listitem>
+  </varlistentry>
+</variablelist>
+<para>
+In the normal case, a <link linkend="PangoFontMap">PangoFontMap</link>
+created directly with <link
+linkend="gnome-print-pango-create-layout"><function>gnome_print_pango_create_layout()</function></link>
+is all that is needed. A simple example that uses Pango to draw a string centered
+in a page looks like:
+</para>
+
+<informalexample><programlisting>
+static void
+draw_hello_world (GnomePrintContext *gpc,
+                  double             page_width,
+                  double             page_height)
+{
+  PangoLayout *layout = gnome_print_pango_create_layout (gpc);
+  int pango_width, pango_height;
+  double width, height;
+
+  pango_layout_set_text (layout, "Hello World");
+
+  pango_layout_get_size (layout, &amp;pango_width, &amp;pango_height);
+  width = (double) pango_width / PANGO_SCALE;
+  height = (double) pango_height / PANGO_SCALE;
+
+  gnome_print_moveto (gpc,
+	             (page_width - width) / 2,
+                     (page_width - height)/ 2);
+  gnome_print_pango_layout (gpc, layout);
+
+  g_object_unref (layout);
+}
+</programlisting></informalexample>
+
+<para>
+Note the need to convert from Pango units to the floating point
+units that gnome-print uses by dividing by
+<link linkend="PANGO-SCALE-CAPS"><literal>PANGO_SCALE</literal></link>.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gnome_print_pango_font_map_new ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_get_default_font_map ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_create_context ##### -->
+<para>
+
+</para>
+
+@fontmap: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_update_context ##### -->
+<para>
+
+</para>
+
+@context: 
+@gpc: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_create_layout ##### -->
+<para>
+
+</para>
+
+@gpc: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_glyph_string ##### -->
+<para>
+
+</para>
+
+@gpc: 
+@font: 
+@glyphs: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_layout_line ##### -->
+<para>
+
+</para>
+
+@gpc: 
+@line: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_layout ##### -->
+<para>
+
+</para>
+
+@gpc: 
+@layout: 
+
+
+<!-- ##### FUNCTION gnome_print_pango_layout_print ##### -->
+<para>
+
+</para>
+
+@gpc: 
+@pl: 
+
+
Index: libgnomeprint/gnome-font-face.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-font-face.c,v
retrieving revision 1.75
diff -u -p -u -r1.75 gnome-font-face.c
--- libgnomeprint/gnome-font-face.c	24 Jan 2004 22:38:14 -0000	1.75
+++ libgnomeprint/gnome-font-face.c	4 Jun 2004 00:52:08 -0000
@@ -646,6 +646,55 @@ gnome_font_face_find_from_family_and_sty
 	return face;
 }
 
+/**
+ * gnome_font_face_find_from_filename:
+ * @filename: filename of a font face in the system font database
+ * @index_: index of the face within @filename. (Font formats such as
+ *          TTC/TrueType Collections can have multiple fonts within
+ *          a single file.
+ * 
+ * Looks up the #GnomeFontFace for a particular pair of filename and
+ * index of the font within the file. The font must already be within
+ * the system font database; this can't be used to access arbitrary
+ * fonts on disk.
+ * 
+ * Return value: the matching #GnomeFontFace, if any, otherwise %NULL
+ **/
+GnomeFontFace *
+gnome_font_face_find_from_filename (const guchar *filename, gint index_)
+{
+	GPFontMap * map;
+	GPFontEntry match_e;
+	GPFontEntry * e;
+
+	/* The hash table for map->filenamedict uses this GPFontEntry
+	 * itself as a key but only the file/index are used as input
+	 * to the hash and equal functions.
+	 */
+	match_e.file = (guchar *)filename;
+	match_e.index = index_;
+
+	map = gp_fontmap_get ();
+		
+	e = g_hash_table_lookup (map->filenamedict, &match_e);
+	if (!e) {
+		gp_fontmap_release (map);
+		return NULL;
+	}
+
+	if (e->face) {
+		gnome_font_face_ref (e->face);
+		gp_fontmap_release (map);
+		return e->face;
+	}
+
+	gff_face_from_entry (e);
+
+	gp_fontmap_release (map);
+
+	return (e->face);
+}
+
 GnomeFontFace *
 gnome_font_face_find_closest_from_pango_font (PangoFont *pfont)
 {
Index: libgnomeprint/gnome-font-face.h
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-font-face.h,v
retrieving revision 1.18
diff -u -p -u -r1.18 gnome-font-face.h
--- libgnomeprint/gnome-font-face.h	6 Jan 2003 19:06:04 -0000	1.18
+++ libgnomeprint/gnome-font-face.h	4 Jun 2004 00:52:08 -0000
@@ -58,6 +58,7 @@ GnomeFontFace *gnome_font_face_find_clos
 GnomeFontFace *gnome_font_face_find_closest_from_pango_font        (PangoFont *pfont);
 GnomeFontFace *gnome_font_face_find_closest_from_pango_description (const PangoFontDescription *desc);
 GnomeFontFace *gnome_font_face_find_from_family_and_style (const guchar *family, const guchar *style);
+GnomeFontFace *gnome_font_face_find_from_filename (const guchar *filename, gint index_);
 
 /*
  * Create font
Index: libgnomeprint/gnome-font.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-font.c,v
retrieving revision 1.88
diff -u -p -u -r1.88 gnome-font.c
--- libgnomeprint/gnome-font.c	24 Jan 2004 22:38:14 -0000	1.88
+++ libgnomeprint/gnome-font.c	4 Jun 2004 00:52:08 -0000
@@ -348,6 +348,39 @@ gnome_font_find_closest_from_full_name (
 	return font;
 }
 
+/**
+ * gnome_font_find_from_filename:
+ * @filename: filename of a font face in the system font database
+ * @index_: index of the face within @filename. (Font formats such as
+ *          TTC/TrueType Collections can have multiple fonts within
+ *          a single file.
+ * @size: size (in points) at which to load the font
+ * 
+ * Creates a font using the filename and index of the face within the file to
+ * identify the #GnomeFontFace. The font must already be within
+ * the system font database; this can't be used to access arbitrary
+ * fonts on disk.
+ * 
+ * Return value: a newly created font if the face could be located,
+ *  otherwise %NULL
+ **/
+GnomeFont *
+gnome_font_find_from_filename (const guchar *filename, gint index_, gdouble size)
+{
+	GnomeFontFace *face;
+	GnomeFont *font;
+
+	face = gnome_font_face_find_from_filename (filename, index_);
+	if (!face)
+		return NULL;
+
+	font = gnome_font_face_get_font_full (face, size, NULL);
+
+	gnome_font_face_unref (face);
+
+	return font;
+}
+
 /* Find the closest weight matching the family name, weight, and italic
    specs. */
 
Index: libgnomeprint/gnome-font.h
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-font.h,v
retrieving revision 1.44
diff -u -p -u -r1.44 gnome-font.h
--- libgnomeprint/gnome-font.h	6 Jan 2003 19:06:04 -0000	1.44
+++ libgnomeprint/gnome-font.h	4 Jun 2004 00:52:08 -0000
@@ -123,8 +123,10 @@ gdouble   gnome_font_get_underline_thick
 GnomeFont *gnome_font_find                           (const guchar *name, gdouble size);
 GnomeFont *gnome_font_find_closest                   (const guchar *name, gdouble size);
 GnomeFont *gnome_font_find_from_full_name            (const guchar *string);
+GnomeFont *gnome_font_find_from_filename             (const guchar *filename, gint index_, gdouble size);
 GnomeFont *gnome_font_find_closest_from_full_name    (const guchar *string);
 GnomeFont *gnome_font_find_closest_from_weight_slant (const guchar *family, GnomeFontWeight weight, gboolean italic, gdouble size);
+
 
 /* Lists */
 GList  *gnome_font_list (void);
Index: libgnomeprint/gnome-fontmap.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-fontmap.c,v
retrieving revision 1.41
diff -u -p -u -r1.41 gnome-fontmap.c
--- libgnomeprint/gnome-fontmap.c	24 Jan 2004 22:38:14 -0000	1.41
+++ libgnomeprint/gnome-fontmap.c	4 Jun 2004 00:52:08 -0000
@@ -89,6 +89,8 @@ gp_fontmap_unref (GPFontMap * map)
 			g_hash_table_destroy (map->familydict);
 		if (map->fontdict)
 			g_hash_table_destroy (map->fontdict);
+		if (map->filenamedict)
+			g_hash_table_destroy (map->filenamedict);
 		if (map->familylist) {
 			g_hash_table_remove (familylist2map, map->familylist);
 			g_list_free (map->familylist);
@@ -335,6 +337,7 @@ gp_fontmap_load_fontconfig (GPFontMap *m
 		e = fcpattern_to_gp_font_entry (font);
 		if (e) {
 			g_hash_table_insert (map->fontdict, e->name, e);
+			g_hash_table_insert (map->filenamedict, e, e);
 			map->num_fonts++;
 			map->fonts = g_slist_prepend (map->fonts, e);
 		}
@@ -383,6 +386,23 @@ gp_fontmap_sort (GPFontMap *map)
 	}
 }
 
+static guint
+filename_hash (gconstpointer v)
+{
+	const GPFontEntry *e = v;
+
+	return g_str_hash (e->file) ^ (e->index << 16);
+}
+
+static gboolean
+filename_equal (gconstpointer v1,
+		gconstpointer v2)
+{
+	const GPFontEntry *e1 = v1;
+	const GPFontEntry *e2 = v2;
+
+	return (e1->index == e2->index) && strcmp (e1->file, e2->file) == 0;
+}
 
 static GPFontMap *
 gp_fontmap_load (void)
@@ -393,6 +413,7 @@ gp_fontmap_load (void)
 	map->refcount  = 1;
 	map->num_fonts = 0;
 	map->fontdict   = g_hash_table_new (g_str_hash, g_str_equal);
+	map->filenamedict = g_hash_table_new (filename_hash, filename_equal);
 	map->familydict = g_hash_table_new (g_str_hash, g_str_equal);
 
 	gp_fontmap_load_fontconfig (map);
Index: libgnomeprint/gnome-fontmap.h
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-fontmap.h,v
retrieving revision 1.23
diff -u -p -u -r1.23 gnome-fontmap.h
--- libgnomeprint/gnome-fontmap.h	24 Jan 2004 22:38:14 -0000	1.23
+++ libgnomeprint/gnome-fontmap.h	4 Jun 2004 00:52:08 -0000
@@ -51,8 +51,9 @@ struct _GPFontMap {
 	gint refcount;
 	gint num_fonts;
 
-	GHashTable *fontdict;	/* Name -> FontEntry */
-	GHashTable *familydict;	/* Family name -> FamilyEntry */
+	GHashTable *fontdict;	  /* Name -> FontEntry */
+	GHashTable *familydict;	  /* Family name -> FamilyEntry */
+	GHashTable *filenamedict; /* File/index -> FontEntry */
 
 	GSList *fonts;	        /* List of FontEntries, sorted A-Z */
 	GSList *families;	/* List of FamilyEntries, sorted A-Z */
Index: libgnomeprint/gnome-print-pango.c
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-print-pango.c,v
retrieving revision 1.1
diff -u -p -u -r1.1 gnome-print-pango.c
--- libgnomeprint/gnome-print-pango.c	11 Mar 2004 21:12:33 -0000	1.1
+++ libgnomeprint/gnome-print-pango.c	4 Jun 2004 00:52:08 -0000
@@ -1,9 +1,11 @@
 /* 
  * gnome-print-pango.c
  *
- * Copyright (C) 2003
+ * Copyright (C) 2003 Jean Bréfort <[email protected]>
+ * Copyright (C) 2004 Red Hat, Inc.
  *
  * Developed by Jean Bréfort <[email protected]>
+ * Rewritten by Owen Taylor <[email protected]>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,210 +23,628 @@
  * Boston, MA  02111-1307, USA.
  */
 
-#include "gnome-print-pango.h"
+#define PANGO_ENABLE_BACKEND	/* Needed to access PangoFcFont.font_pattern */
 
-void gnome_print_pango_layout_print (GnomePrintContext *gpc, PangoLayout* pl) {
-	gint i, top, bottom;
-	GnomeFont *font;
-	GnomeFontFace *face;
+#include <config.h>
+
+#include <libgnomeprint/gnome-print-pango.h>
+#include <libgnomeprint/gnome-print-private.h>
+#include <libgnomeprint/gp-gc-private.h>
+
+#include <pango/pangofc-font.h>
+#include <pango/pangoft2.h>
+
+/* This function gets called to convert a matched pattern into what
+ * we'll use to actually load the font. We turn off hinting since we
+ * want metrics that are independent of scale.
+ */
+static void
+substitute_func (FcPattern *pattern, gpointer   data)
+{
+	FcPatternDel (pattern, FC_HINTING);
+	FcPatternAddBool (pattern, FC_HINTING, FALSE);
+}
+
+/**
+ * gnome_print_pango_font_map_new:
+ * 
+ * Creates a new #PangoFontMap object suitable for use with
+ * gnome-print. In most cases, you probably want to use
+ * gnome_print_pango_get_default_font_map () instead.
+ * 
+ * Return value: a newly created #PangoFontMap object
+ **/
+PangoFontMap *
+gnome_print_pango_font_map_new (void)
+{
+	PangoFontMap *fontmap = NULL;
+	PangoFT2FontMap *ft2fontmap;
+		
+	fontmap = pango_ft2_font_map_new ();
+	ft2fontmap = PANGO_FT2_FONT_MAP (fontmap);
+	
+	pango_ft2_font_map_set_resolution (ft2fontmap, 72, 72);
+	pango_ft2_font_map_set_default_substitute (ft2fontmap, substitute_func, NULL, NULL);
+
+	return fontmap;
+}
+
+/**
+ * gnome_print_pango_get_default_font_map:
+ * 
+ * Gets a singleton #PangoFontMap object suitable for
+ * use with gnome-print.
+ * 
+ * Return value: the default #PangoFontMap object for gnome-print. The
+ * returned object is owned by gnome-print and should not be modified.
+ * (If you need to set custom options, create a new font map with
+ * gnome_print_pango_font_map_new().)  The reference count is
+ * <emphasis>not</emphasis> increased.
+ **/
+PangoFontMap *
+gnome_print_pango_get_default_font_map (void)
+{
+	static PangoFontMap *fontmap = NULL;
+
+	if (!fontmap)
+		fontmap = gnome_print_pango_font_map_new ();
+
+	return fontmap;
+}
+
+/**
+ * gnome_print_pango_create_context:
+ * @fontmap: a #PangoFontMap from gnome_print_pango_get_default_font_map()
+ *  or gnome_print_pango_create_font_map().
+ * 
+ * Creates a new #PangoContext object for the specified fontmap.
+ * 
+ * Return value: a newly created #PangoContext object
+ **/
+PangoContext *
+gnome_print_pango_create_context (PangoFontMap *fontmap)
+{
+	return pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (fontmap));
+}
+
+/**
+ * gnome_print_pango_update_context:
+ * @context: a #PangoContext from gnome_print_pango_create_context().
+ * @gpc: a #GnomePrintContext
+ * 
+ * Update a context so that layout done with it reflects the
+ * current state of @gpc. In general, every time you use a
+ * #PangoContext with a different #GnomePrintContext, or
+ * you change the transformation matrix of the #GnomePrintContext
+ * (other than pure translations) you should call this function.
+ * You also need to call pango_layout_context_changed() for any
+ * #PangoLayout objects that exit for the #PangoContext.
+ *
+ * This function currently does nothing and that isn't expected
+ * to change for gnome-print. The main benefit of calling it
+ * is that your code will be properly prepared for conversion
+ * to use with future rendering systems such as Cairo where
+ * the corresponding operation will actually do something.
+ */ 
+void
+gnome_print_pango_update_context (PangoContext      *context,
+				  GnomePrintContext *gpc)
+				  
+{
+	/* nothing */
+}
+
+/**
+ * gnome_print_pango_create_layout:
+ * @gpc: a #GnomePrintContext
+ * 
+ * Convenience function that creates a new #PangoContext, updates
+ * it for rendering to @gpc, and then creates a #PangoLayout for
+ * that #PangoContext. Generally this function suffices for
+ * most usage of gnome-print with Pango and you don't need to
+ * deal with the #PangoContext directly.
+ * 
+ * Return value: the newly created #PangoLayout. Free with
+ *  g_object_unref() when you are done with it.
+ **/
+PangoLayout *
+gnome_print_pango_create_layout (GnomePrintContext *gpc)
+{
+	PangoFontMap *fontmap = gnome_print_pango_get_default_font_map ();
+	PangoContext *context = gnome_print_pango_create_context (fontmap);
+	/* gnome_print_pango_update_context (gpc, context); */
+	
+	PangoLayout *layout = pango_layout_new (context);
+
+	g_object_unref (context);
+
+	return layout;
+}
+
+/* Finds the #GnomeFont corresponding to a #PangoFont. This differs
+ * from gnome_font_face_find_closest_from_pango_font() because it
+ * requires a PangoFcFont not an arbitrary font and works off the
+ * filename rather than making guesses about name correspondences.
+ */
+static GnomeFont *
+font_from_pango_font (PangoFont *font)
+{
+	PangoFcFont *fcfont;
+	FcChar8 *filename;
+	gint id;
+	gdouble size;
+	
+	if (!PANGO_IS_FC_FONT (font))
+		return NULL;
+
+	fcfont = PANGO_FC_FONT (font);
+
+	if (FcPatternGetString (fcfont->font_pattern, FC_FILE, 0, &filename) != FcResultMatch)
+		return NULL;
+      
+	if (FcPatternGetInteger (fcfont->font_pattern, FC_INDEX, 0, &id) != FcResultMatch)
+		return NULL;
+	
+	if (FcPatternGetDouble (fcfont->font_pattern, FC_SIZE, 0, &size) != FcResultMatch)
+		return NULL;
+
+	return gnome_font_find_from_filename (filename, id, size);
+}
+
+/**
+ * gnome_print_pango_glyph_string:
+ * @gpc: a #GnomePrintContext
+ * @font: the #PangoFont that the glyphs in @glyphs are from
+ * @glyphs: a #PangoGlyphString
+ * 
+ * Draws the glyphs in @glyphs into the specified #GnomePrintContext.
+ * Positioning information in @glyphs is transformed by the current
+ * transformation matrix, the glyphs are drawn in the current color,
+ * and the glyphs are positioned so that the left edge of the baseline
+ * is at the current point.
+ **/
+void
+gnome_print_pango_glyph_string (GnomePrintContext *gpc, PangoFont *font, PangoGlyphString  *glyphs)
+{
 	GnomeGlyphList *glyph_list;
-	GSList *extra_attrs_list;
-	PangoFontDescription *desc;
-	PangoGlyphItem *item;
-	PangoRectangle logical_rect, ink_rect, rect;
-	PangoLayout *layout;
-	ArtDRect art_rect;
-	const char *text = pango_layout_get_text (pl);
-	gboolean foreground_set;
-	guint16 foreground_red = 0, foreground_green = 0, foreground_blue = 0;
-	gboolean background_set;
-	guint16 background_red = 0, background_green = 0, background_blue = 0;
-	PangoLayoutIter *iter = pango_layout_get_iter (pl);
-	gdouble scale[6] = {1., 0., 0., 1., 0., 0.};
-	gdouble space;
-	gboolean strikethrough, underline, slant;
-#if 0
-	GtkTextAppearance* appearance;
-#endif
-	int underline_type;
-	PangoAlignment align = pango_layout_get_alignment (pl);
+	GnomeFont *gnome_font;
+	gint x_off = 0;
+	gint i;
 	
-	pango_layout_get_extents (pl, NULL, &logical_rect);
-	gnome_print_gsave (gpc);
-	switch (align) {
-	case PANGO_ALIGN_CENTER:
-		gnome_print_translate (gpc, - (double) logical_rect.width / 2., 0.);
-		break;
-	case PANGO_ALIGN_RIGHT:
-		gnome_print_translate (gpc, - (double) logical_rect.width, 0.);
-		break;
-	default:
-		break;
+	gnome_font = font_from_pango_font (font);
+	if (!gnome_font)
+		return;
+
+	glyph_list = gnome_glyphlist_new ();
+
+	gnome_glyphlist_font (glyph_list, gnome_font);
+	g_object_unref (gnome_font);
+	
+	gnome_glyphlist_color (glyph_list, gp_gc_get_rgba (gpc->gc));
+	
+	for (i = 0; i < glyphs->num_glyphs; i++) {
+		PangoGlyphInfo *gi = &glyphs->glyphs[i];
+		int x = x_off + gi->geometry.x_offset;
+		int y = gi->geometry.y_offset;
+
+		gnome_glyphlist_moveto (glyph_list,
+					(gdouble) x / PANGO_SCALE, (gdouble) y / PANGO_SCALE);
+		gnome_glyphlist_glyph (glyph_list, gi->glyph);
+		
+		x_off += glyphs->glyphs[i].geometry.width;
 	}
-	do {
-		item = pango_layout_iter_get_run (iter);
-		if (!item) break;
-		strikethrough = underline = foreground_set = background_set = FALSE;
-#if 0
-		appearance = NULL;
-#endif
-		desc = pango_font_describe (item->item->analysis.font);
-		face = gnome_font_face_find_closest_from_weight_slant (
-								pango_font_description_get_family (desc),
-								(GnomeFontWeight) pango_font_description_get_weight (desc),
-								(pango_font_description_get_style (desc) != PANGO_STYLE_NORMAL));
-		font =	gnome_font_face_get_font (face,
-					  pango_font_description_get_size(desc) / PANGO_SCALE, 72, 72);
-		if (font == NULL)
-		{
-			g_warning ("No font file for font.");
+
+	gnome_print_glyphlist (gpc, glyph_list);
+	gnome_glyphlist_unref (glyph_list);
+}
+
+typedef struct
+{
+	PangoUnderline  uline;
+	gboolean        strikethrough;
+	PangoColor     *fg_color;
+	PangoColor     *bg_color;
+	PangoRectangle *shape_ink_rect;
+	PangoRectangle *shape_logical_rect;
+	gint            rise;
+} ItemProperties;
+
+/* Retrieves the properties we care about for a single run in an
+ * easily accessible structure rather than a list of attributes
+ */
+static void
+get_item_properties (PangoItem *item, ItemProperties *properties)
+{
+	GSList *tmp_list = item->analysis.extra_attrs;
+
+	properties->uline = PANGO_UNDERLINE_NONE;
+	properties->strikethrough = FALSE;
+	properties->fg_color = NULL;
+	properties->bg_color = NULL;
+	properties->rise = 0;
+	properties->shape_ink_rect = NULL;
+	properties->shape_logical_rect = NULL;
+
+	while (tmp_list) {
+		PangoAttribute *attr = tmp_list->data;
+	  
+		switch (attr->klass->type) {
+		case PANGO_ATTR_UNDERLINE:
+			properties->uline = ((PangoAttrInt *)attr)->value;
+			break;
+		  
+		case PANGO_ATTR_STRIKETHROUGH:
+			properties->strikethrough = ((PangoAttrInt *)attr)->value;
+			break;
+		  
+		case PANGO_ATTR_FOREGROUND:
+			properties->fg_color = &((PangoAttrColor *)attr)->color;
+			break;
+		  
+		case PANGO_ATTR_BACKGROUND:
+			properties->bg_color = &((PangoAttrColor *)attr)->color;
+			break;
+		  
+		case PANGO_ATTR_SHAPE:
+			properties->shape_logical_rect = &((PangoAttrShape *)attr)->logical_rect;
+			properties->shape_ink_rect = &((PangoAttrShape *)attr)->ink_rect;
+			break;
+		
+		case PANGO_ATTR_RISE:
+			properties->rise = ((PangoAttrInt *)attr)->value;
+			break;
+		  
+		default:
+			break;
+		}
+		tmp_list = tmp_list->next;
+	}
+}
+
+/*
+ * Couple of helper functions to work in Pango units rather than doubles
+ */
+static void
+rect_filled (GnomePrintContext *gpc, gint x, gint y, gint width, gint height)
+{
+	gnome_print_rect_filled (gpc,
+				 (gdouble) x / PANGO_SCALE,     (gdouble) y / PANGO_SCALE,
+				 (gdouble) width / PANGO_SCALE, (gdouble) height / PANGO_SCALE);
+}
+
+static void
+translate (GnomePrintContext *gpc, gint x, gint y)
+{
+	gnome_print_translate (gpc,
+			       (gdouble) x / PANGO_SCALE, (gdouble) y / PANGO_SCALE);
+}
+
+static void
+moveto (GnomePrintContext *gpc, gint x, gint y)
+{
+	gnome_print_moveto (gpc,
+			    (gdouble) x / PANGO_SCALE, (gdouble) y / PANGO_SCALE);
+}
+
+/* It's easiest for us to work in coordinates where the current point (which
+ * determines the origin of drawing for the #PangoGlyphString, #PangoLayout,
+ * or #PangoLayoutLine) is at the origin. This function changes the CTM to
+ * that coordinate system.
+ */
+static void
+current_point_to_origin (GnomePrintContext *gpc)
+{
+	const gdouble *ctm;
+	const ArtPoint *cp;
+	gdouble affine[6];
+
+	ctm = gp_gc_get_ctm (gpc->gc);
+	cp = gp_gc_get_currentpoint (gpc->gc);
+
+	affine[0] = ctm[0];
+	affine[1] = ctm[1];
+	affine[2] = ctm[2];
+	affine[3] = ctm[3];
+	affine[4] = cp->x;
+	affine[5] = cp->y;
+
+	gp_gc_setmatrix (gpc->gc, affine);
+}
+
+/* Draws an error underline that looks like one of:
+ *              H       E                H
+ *     /\      /\      /\        /\      /\               -
+ *   A/  \    /  \    /  \     A/  \    /  \              |
+ *    \   \  /    \  /   /D     \   \  /    \             |
+ *     \   \/  C   \/   /        \   \/   C  \            | height = HEIGHT_SQUARES * square
+ *      \      /\  F   /          \  F   /\   \           | 
+ *       \    /  \    /            \    /  \   \G         |
+ *        \  /    \  /              \  /    \  /          |
+ *         \/      \/                \/      \/           -
+ *         B                         B       
+ * |----|
+ *   unit_width = (HEIGHT_SQUARES - 1) * square
+ *
+ * The x, y, width, height passed in give the desired bounding box;
+ * x/width are adjusted to make the underline a integer number of units
+ * wide.
+ */
+#define HEIGHT_SQUARES 2.5
+
+static void
+draw_error_underline (GnomePrintContext *gpc, gdouble x, gdouble y, gdouble width, gdouble height)
+{
+	gdouble square = height / HEIGHT_SQUARES;
+	gdouble unit_width = (HEIGHT_SQUARES - 1) * square;
+	gint width_units = (width + unit_width / 2) / unit_width;
+	gdouble y_top, y_bottom;
+	gint i;
+
+	x += (width - width_units * unit_width);
+	width = width_units * unit_width;
+
+	gnome_print_newpath (gpc);
+
+	y_top = y + height;
+	y_bottom = y;
+
+	/* Bottom of squiggle */
+	gnome_print_moveto (gpc, x - square / 2, y_top - square / 2); /* A */
+	for (i = 0; i < width_units; i += 2) {
+		gdouble x_middle = x + (i + 1) * unit_width;
+		gdouble x_right = x + (i + 2) * unit_width;
+		
+		gnome_print_lineto (gpc, x_middle, y_bottom); /* B */
+
+		if (i + 1 == width_units)
+			/* Nothing */;
+		else if (i + 2 == width_units)
+			gnome_print_lineto (gpc, x_right + square / 2, y_top - square / 2); /* D */
+		else
+			gnome_print_lineto (gpc, x_right, y_top - square); /* C */
+	}
+
+	/* Top of squiggle */
+	for (i -= 2; i >= 0; i -= 2) {
+		gdouble x_left = x + i * unit_width;
+		gdouble x_middle = x + (i + 1) * unit_width;
+		gdouble x_right = x + (i + 2) * unit_width;
+		
+		if (i + 1 == width_units)
+			gnome_print_lineto (gpc, x_middle + square / 2, y_bottom + square / 2); /* G */
+		else {
+			if (i + 2 == width_units)
+				gnome_print_lineto (gpc, x_right, y_top); /* E */
+			gnome_print_lineto (gpc, x_middle, y_bottom + square); /* F */
+		}
+		
+		gnome_print_lineto (gpc, x_left, y_top);   /* H */
+	}
+
+	gnome_print_closepath (gpc);
+	gnome_print_fill (gpc);
+}
+
+/* Helper function to draw the underline for one layout run; the descent field gives
+ * the descent of the ink for the actual text in the layout run.
+ */
+static void
+draw_underline (GnomePrintContext *gpc, PangoFontMetrics  *metrics, PangoUnderline uline, gint x, gint width, gint descent)
+{
+  gint underline_thickness = pango_font_metrics_get_underline_thickness (metrics);
+  gint underline_position = pango_font_metrics_get_underline_position (metrics);
+  gint y_off = 0;		/* Quiet GCC */
+
+  switch (uline) {
+  case PANGO_UNDERLINE_NONE:
+	  g_assert_not_reached();
+	  break;
+  case PANGO_UNDERLINE_SINGLE:
+	  y_off = underline_position - underline_thickness;
+	  break;
+  case PANGO_UNDERLINE_DOUBLE:
+	  y_off = underline_position - underline_thickness;
+	  break;
+  case PANGO_UNDERLINE_LOW:
+	  y_off = - 2 * underline_thickness - descent;
+	  break;
+  case PANGO_UNDERLINE_ERROR:
+	  draw_error_underline (gpc,
+				(gdouble) x / PANGO_SCALE,
+				(gdouble) (underline_position - 3 * underline_thickness) / PANGO_SCALE,
+				(gdouble) width / PANGO_SCALE,
+				(gdouble) (3 * underline_thickness) / PANGO_SCALE);
+	  return;
+  }
+
+  rect_filled (gpc,
+	       x, y_off,
+	       width, underline_thickness);
+
+  if (uline == PANGO_UNDERLINE_DOUBLE)
+    {
+      rect_filled (gpc,
+		   x, y_off - 2 * underline_thickness,
+		   width, underline_thickness);
+    }
+}
+
+/* Helper function to draw a strikethrough for one layout run
+ */
+static void
+draw_strikethrough (GnomePrintContext *gpc, PangoFontMetrics  *metrics, gint x, gint width)
+{
+  gint strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics);
+  gint strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics);
+
+  rect_filled (gpc,
+	       x, strikethrough_position - strikethrough_thickness,
+	       width, strikethrough_thickness);
+}
+
+/**
+ * gnome_print_pango_layout_line:
+ * @gpc: a #GnomePrintContext
+ * @line: a #PangoLayoutLine
+ * 
+ * Draws the text in @line into the specified #GnomePrintContext.  The
+ * text is drawn in the current color unless that has been overridden
+ * by attributes set on the layout and the glyphs are positioned so
+ * that the left edge of the baseline is at the current point.
+ **/
+void 
+gnome_print_pango_layout_line (GnomePrintContext *gpc, PangoLayoutLine *line)
+{
+	GSList *tmp_list = line->runs;
+	PangoRectangle overall_rect;
+	PangoRectangle logical_rect;
+	PangoRectangle ink_rect;
+	gint x_off = 0;
+	
+	gnome_print_gsave (gpc);
+
+	current_point_to_origin (gpc);
+
+	pango_layout_line_get_extents (line, NULL, &overall_rect);
+	
+	while (tmp_list) {
+		ItemProperties properties;
+		PangoLayoutRun *run = tmp_list->data;
+		
+		tmp_list = tmp_list->next;
+		
+		get_item_properties (run->item, &properties);
+
+		if (properties.shape_logical_rect) {
+			x_off += properties.shape_logical_rect->width;
 			continue;
 		}
-		glyph_list = gnome_glyphlist_new ();
-		extra_attrs_list = item->item->analysis.extra_attrs;
-		top = pango_layout_iter_get_baseline(iter) / PANGO_SCALE;
-		pango_layout_iter_get_char_extents (iter, &logical_rect);
-		bottom = 0;
-		while (extra_attrs_list)
-		{
-			PangoAttribute *attr = extra_attrs_list->data;
-			PangoAttrType attr_type = attr->klass->type;
-			switch (attr_type) {
-			case PANGO_ATTR_STYLE:
-				g_warning("style");
-				break;
-			case PANGO_ATTR_RISE:
-				bottom = ((PangoAttrInt *) attr)->value / PANGO_SCALE;
-				break;
-			case PANGO_ATTR_FOREGROUND:
-				foreground_set = TRUE;
-				foreground_red = ((PangoAttrColor *) attr)->color.red;
-				foreground_green = ((PangoAttrColor *) attr)->color.green;
-				foreground_blue = ((PangoAttrColor *) attr)->color.blue;
-				break;
-			case PANGO_ATTR_BACKGROUND:
-				background_set = TRUE;
-				background_red = ((PangoAttrColor *) attr)->color.red;
-				background_green = ((PangoAttrColor *) attr)->color.green;
-				background_blue = ((PangoAttrColor *) attr)->color.blue;
-				break;
-			case PANGO_ATTR_UNDERLINE:
-				underline_type = ((PangoAttrInt *) attr)->value;
-				underline = TRUE;
-				break;
-			case PANGO_ATTR_STRIKETHROUGH:
-				strikethrough = TRUE;
-				break;
-			case PANGO_ATTR_SHAPE:
-				g_warning ("Pango attribute PANGO_ATTR_SHAPE not supported");
-				break;
-			case PANGO_ATTR_SCALE:
-				g_warning ("Pango attribute PANGO_ATTR_SCALE not supported");
-				break;
-			default:
-#if 0
-				if (attr_type == gtk_text_attr_appearance_type)
-					appearance = &((GtkTextAttrAppearance *)attr)->appearance;
-#endif
-				break;
-			}
-			extra_attrs_list = extra_attrs_list->next;
-		}
-		pango_layout_iter_get_run_extents (iter, &ink_rect, &logical_rect);
-		layout = pango_layout_new (pango_layout_get_context (pl));
-		pango_layout_set_font_description (layout, desc);
-		pango_layout_set_text (layout, text + item->item->offset, item->item->length);
-		pango_layout_get_extents (layout, &rect, NULL);
-		g_object_unref (layout);
-		if (background_set)
-		{
-			gnome_print_setrgbcolor (gpc, (float) background_red / 0xFFFF,
-						(float) background_green / 0xFFFF, (float) background_blue / 0xFFFF);
-			gnome_print_rect_filled (gpc, logical_rect.x / PANGO_SCALE,
-						logical_rect.y / PANGO_SCALE,
-						(float) logical_rect.width / PANGO_SCALE,
-						(float) + logical_rect.height / PANGO_SCALE);
-		}
-		gnome_print_setrgbcolor (gpc, (float) foreground_red / 0xFFFF,
-						(float) foreground_green / 0xFFFF, (float) foreground_blue / 0xFFFF);
-		if (strikethrough
-#if 0
-		    || (appearance && appearance->strikethrough)
-#endif
-		    ) {
-			gnome_print_setlinewidth (gpc, .75);
-			gnome_print_setlinecap (gpc, 0);
-			gnome_print_moveto (gpc, logical_rect.x / PANGO_SCALE,
-					 - bottom + top - (0.22 * logical_rect.height) / PANGO_SCALE);
-			gnome_print_lineto (gpc, (logical_rect.x + logical_rect.width) / PANGO_SCALE,
-					 - bottom + top - (0.22 * logical_rect.height) / PANGO_SCALE);
-			gnome_print_stroke (gpc);
-		}
-		if (underline) {
-			gnome_print_setlinewidth (gpc, .75);
-			gnome_print_setlinecap (gpc, 0);
-			switch (underline_type) {
-			case PANGO_UNDERLINE_NONE:
-				break;
-			case PANGO_UNDERLINE_DOUBLE:
-				gnome_print_moveto (gpc, logical_rect.x / PANGO_SCALE,
-						 - bottom + top + 3.0);
-				gnome_print_lineto (gpc, (logical_rect.x + logical_rect.width) / PANGO_SCALE,
-						 - bottom + top + 3.0);
-				gnome_print_stroke (gpc);
-				  /* Fall through */
-			case PANGO_UNDERLINE_SINGLE:
-				gnome_print_moveto (gpc, logical_rect.x / PANGO_SCALE,
-						 - bottom + top + 1.0);
-				gnome_print_lineto (gpc, (logical_rect.x + logical_rect.width) / PANGO_SCALE,
-						 - bottom + top + 1.0);
-				gnome_print_stroke (gpc);
-				break;
-			case PANGO_UNDERLINE_LOW:
-				gnome_print_moveto (gpc, logical_rect.x / PANGO_SCALE,
-						 - bottom + top + logical_rect.y / PANGO_SCALE + 1.0);
-				gnome_print_lineto (gpc, (logical_rect.x + logical_rect.width) / PANGO_SCALE,
-						 - bottom + top + logical_rect.y / PANGO_SCALE + 1.0);
-				gnome_print_stroke (gpc);
-				break;
-			}
-		}
-		gnome_print_moveto (gpc, logical_rect.x / PANGO_SCALE,
-				 - bottom + top);
-		gnome_glyphlist_font (glyph_list, font);
-		for (i = 0; i < item->glyphs->num_glyphs; i++)
-		{
-			gnome_glyphlist_glyph (glyph_list, item->glyphs->glyphs[i].glyph);
-		}
-		gnome_glyphlist_bbox (glyph_list, scale, 0, &art_rect);
-		slant = (ink_rect.width / PANGO_SCALE)> (art_rect.x1 - art_rect.x0);
-		if (item->glyphs->num_glyphs > 1) {
-			space = (((double) ink_rect.width / PANGO_SCALE - art_rect.x1 + art_rect.x0) - (slant)? top * 0.3: 0.)
-						/ (item->glyphs->num_glyphs - 1);
-			gnome_glyphlist_unref (glyph_list);
-			glyph_list = gnome_glyphlist_new ();
-			gnome_print_moveto (gpc, logical_rect.x / PANGO_SCALE,
-					 - bottom + top);
-			gnome_glyphlist_font (glyph_list, font);
-			gnome_glyphlist_letterspace (glyph_list, space);
-			for (i = 0; i < item->glyphs->num_glyphs; i++)
-			{
-				gnome_glyphlist_glyph (glyph_list, item->glyphs->glyphs[i].glyph);
-			}
-		}
-		gnome_print_gsave(gpc);
-		if (slant) {
-		/*simulate slanted font*/
-			double matrix [6] = {
-				 1.,
-				0., .15, -1., .0, .0};
-			gnome_print_concat (gpc, matrix);
-		} else
-			gnome_print_scale(gpc, 1., -1.);
-		gnome_print_glyphlist (gpc, glyph_list);
-		gnome_print_grestore(gpc);
-		gnome_glyphlist_unref (glyph_list);
-	} while (pango_layout_iter_next_run (iter));
+
+		gnome_print_gsave (gpc);
+
+		translate (gpc, x_off, properties.rise);
+		gnome_print_moveto (gpc, 0, 0);
+
+		if (properties.uline == PANGO_UNDERLINE_NONE && !properties.strikethrough)
+			pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
+						    NULL, &logical_rect);
+		else
+			pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
+						    &ink_rect, &logical_rect);
+		
+		if (properties.bg_color) {
+			if (!properties.fg_color)
+				gnome_print_gsave (gpc);
+				
+			gnome_print_setrgbcolor (gpc,
+						 (gdouble) properties.bg_color->red / 0xFFFF,
+						 (gdouble) properties.bg_color->green / 0xFFFF,
+						 (gdouble) properties.bg_color->blue / 0xFFFF);
+			
+			rect_filled (gpc,
+				     logical_rect.x,    - overall_rect.y - overall_rect.height,
+				     logical_rect.width,  overall_rect.height);
+			
+			if (!properties.fg_color)
+				gnome_print_grestore (gpc);
+		}
+
+		if (properties.fg_color) {
+			gnome_print_setrgbcolor (gpc,
+						 (gdouble) properties.fg_color->red / 0xFFFF,
+						 (gdouble) properties.fg_color->green / 0xFFFF,
+						 (gdouble) properties.fg_color->blue / 0xFFFF);
+		}
+
+		gnome_print_pango_glyph_string (gpc, run->item->analysis.font, run->glyphs);
+		
+		if (properties.uline != PANGO_UNDERLINE_NONE || properties.strikethrough) {
+			PangoFontMetrics *metrics = pango_font_get_metrics (run->item->analysis.font,
+									    run->item->analysis.language);
+	      
+			if (properties.uline != PANGO_UNDERLINE_NONE)
+				draw_underline (gpc, metrics,
+						properties.uline,
+						ink_rect.x,
+						ink_rect.width,
+						ink_rect.y + ink_rect.height);
+			
+			if (properties.strikethrough)
+				draw_strikethrough (gpc, metrics,
+						    ink_rect.x,
+						    ink_rect.width);
+
+			pango_font_metrics_unref (metrics);
+		}
+		
+		gnome_print_grestore (gpc);
+	
+		x_off += logical_rect.width;
+	}
+	
+	gnome_print_grestore (gpc);
+}
+
+/**
+ * gnome_print_pango_layout:
+ * @gpc: a #GnomePrintContext
+ * @layout: a #PangoLayout
+ * 
+ * Draws the text in @layout into the specified #GnomePrintContext.  The
+ * text is drawn in the current color unless that has been overridden
+ * by attributes set on the layout and the glyphs are positioned so
+ * that the left edge of the baseline is at the current point.
+ **/
+void 
+gnome_print_pango_layout (GnomePrintContext *gpc, PangoLayout *layout)
+{
+	PangoLayoutIter *iter;
+	
+	g_return_if_fail (GNOME_IS_PRINT_CONTEXT (gpc));
+	g_return_if_fail (PANGO_IS_LAYOUT (layout));
+
+	gnome_print_gsave (gpc);
+	
+	current_point_to_origin (gpc);
+	
+	iter = pango_layout_get_iter (layout);
+	
+	do {
+		PangoRectangle   logical_rect;
+		PangoLayoutLine *line;
+		int              baseline;
+		
+		line = pango_layout_iter_get_line (iter);
+		
+		pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
+		baseline = pango_layout_iter_get_baseline (iter);
+		
+		moveto (gpc, logical_rect.x, - baseline);
+		gnome_print_pango_layout_line (gpc, line);
+
+	} while (pango_layout_iter_next_line (iter));
+
 	pango_layout_iter_free (iter);
+	
+	gnome_print_grestore (gpc);
+}
+
+/**
+ * gnome_print_pango_layout_print:
+ * @gpc: a #GnomePrintContext
+ * @pl: the #PangoLayout to print
+ * 
+ * Draws the text in @pl into the specified #GnomePrintContext.  The
+ * text is drawn in the current color unless that has been overridden
+ * by attributes set on the layout and the glyphs are positioned so
+ * that the left edge of the baseline is at the point (0, 0). This function
+ * is obsolete; use gnome_print_pango_layout() instead.
+ **/
+void
+gnome_print_pango_layout_print (GnomePrintContext *gpc, PangoLayout* pl)
+{
+	gnome_print_gsave (gpc);
+	gnome_print_moveto (gpc, 0, 0);
+	gnome_print_pango_layout (gpc, pl);
 	gnome_print_grestore (gpc);
 }
Index: libgnomeprint/gnome-print-pango.h
===================================================================
RCS file: /cvs/gnome/libgnomeprint/libgnomeprint/gnome-print-pango.h,v
retrieving revision 1.1
diff -u -p -u -r1.1 gnome-print-pango.h
--- libgnomeprint/gnome-print-pango.h	11 Mar 2004 21:12:33 -0000	1.1
+++ libgnomeprint/gnome-print-pango.h	4 Jun 2004 00:52:08 -0000
@@ -1,9 +1,11 @@
 /* 
  * gnome-print-pango.h
  *
- * Copyright (C) 2003
+ * Copyright (C) 2003 Jean Bréfort <[email protected]>
+ * Copyright (C) 2004 Red Hat, Inc.
  *
  * Developed by Jean Bréfort <[email protected]>
+ * Rewritten by Owen Taylor <[email protected]>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,6 +31,20 @@
 
 G_BEGIN_DECLS
 
+PangoFontMap *gnome_print_pango_font_map_new         (void);
+PangoFontMap *gnome_print_pango_get_default_font_map (void);
+PangoContext *gnome_print_pango_create_context       (PangoFontMap      *fontmap);
+void          gnome_print_pango_update_context       (PangoContext      *context,
+						      GnomePrintContext *gpc);
+PangoLayout  *gnome_print_pango_create_layout        (GnomePrintContext *gpc);
+
+void gnome_print_pango_glyph_string (GnomePrintContext *gpc, PangoFont *font, PangoGlyphString *glyphs);
+void gnome_print_pango_layout_line (GnomePrintContext *gpc, PangoLayoutLine *line);
+void gnome_print_pango_layout      (GnomePrintContext *gpc, PangoLayout *layout);
+
+
+/* Deprecated interface
+ */
 void gnome_print_pango_layout_print (GnomePrintContext *gpc, PangoLayout* pl);
 
 G_END_DECLS
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/gnome/libgnomeprint/tests/Makefile.am,v
retrieving revision 1.32
diff -u -p -u -r1.32 Makefile.am
--- tests/Makefile.am	6 Aug 2003 08:03:43 -0000	1.32
+++ tests/Makefile.am	4 Jun 2004 00:52:08 -0000
@@ -2,7 +2,7 @@ SUBDIRS = files output tools
 
 AM_CFLAGS=$(WARN_CFLAGS)
 
-noinst_PROGRAMS = generate gpa-test fonts simple
+noinst_PROGRAMS = generate gpa-test fonts simple pango
 
 INCLUDES = \
 	-I$(top_srcdir) \
@@ -21,6 +21,10 @@ generate_LDADD = $(print_libs)
 simple_SOURCES = simple.c
 simple_LDFLAGS =
 simple_LDADD = $(print_libs)
+
+pango_SOURCES = pango.c
+pango_LDFLAGS =
+pango_LDADD = $(print_libs)
 
 EXTRA_DIST = quit.txt run-test.pl quit.txt
 
Index: tests/pango.c
===================================================================
RCS file: tests/pango.c
diff -N tests/pango.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/pango.c	4 Jun 2004 00:52:08 -0000
@@ -0,0 +1,179 @@
+/*
+ * This test program tests drawing a PangoLayout to a Postscript or PDF file
+ *
+ * Assembled from other tests by Owen Taylor <[email protected]>
+ */
+#include <libgnomeprint/gnome-print.h>
+#include <libgnomeprint/gnome-print-job.h>
+#include <libgnomeprint/gnome-print-pango.h>
+
+#include <popt.h>
+
+#define TOP_MARGIN 36.
+#define LEFT_MARGIN 72.
+#define RIGHT_MARGIN 72.
+
+static char *prog_name;
+static const char *input_file;
+static char *text;
+static int len;
+static gchar*   options_font = NULL;
+static gboolean options_markup = FALSE;
+static gchar*   options_output = NULL;
+static gboolean options_pdf = FALSE;
+static int      options_rotate = 0;
+
+double page_width, page_height;
+double margin_left, margin_right, margin_top, margin_bottom;
+
+static poptContext popt;
+
+static const struct poptOption options[] = {
+	{ "markup",    'm', POPT_ARG_NONE,   &options_markup,   0,
+	  "Input uses Pango markup",  NULL},
+	{ "font",      'f', POPT_ARG_STRING, &options_font,   0,
+	  "Specify the font",  NULL},
+	{ "output",    'o', POPT_ARG_STRING, &options_output,   0,
+	  "Specify the output file",  NULL},
+	{ "pdf",       'p', POPT_ARG_NONE,    &options_pdf,   0,
+	  "Generate a pdf file instead of a Postscript one",  NULL},
+	{ "rotate",    'r', POPT_ARG_INT,    &options_rotate, 0,
+	  "Angle at which to rotate results" },
+	POPT_AUTOHELP
+	{ NULL }
+};
+
+static void
+fail (const char *format, ...)
+{
+  const char *msg;
+  
+  va_list vap;
+  va_start (vap, format);
+  msg = g_strdup_vprintf (format, vap);
+  g_printerr ("%s: %s\n", prog_name, msg);
+
+  exit (1);
+}
+
+static void
+my_draw (GnomePrintContext *gpc)
+{
+	PangoLayout *layout;
+	int width, height;
+	gnome_print_beginpage (gpc, "1");
+
+	layout = gnome_print_pango_create_layout (gpc);
+	if (options_font) {
+		PangoFontDescription *desc = pango_font_description_from_string (options_font);
+		pango_layout_set_font_description (layout, desc);
+		pango_font_description_free (desc);
+	}
+
+	pango_layout_set_width (layout, (page_width - LEFT_MARGIN - RIGHT_MARGIN) * PANGO_SCALE);
+	if (options_markup)
+		pango_layout_set_markup (layout, text, len);
+	else
+		pango_layout_set_text (layout, text, len);
+	pango_layout_get_size (layout, &width, &height);
+
+	gnome_print_translate (gpc, page_width / 2, page_height / 2);
+	gnome_print_rotate (gpc, options_rotate);
+	gnome_print_translate (gpc,
+			       - (double) width / (2 * PANGO_SCALE), (double) height / (2 * PANGO_SCALE));
+	
+	gnome_print_moveto (gpc, 0, 0);
+	gnome_print_pango_layout (gpc, layout);
+	g_object_unref (layout);
+
+	gnome_print_showpage (gpc);
+}
+
+static void
+my_print (void)
+{
+	GnomePrintJob *job;
+	GnomePrintContext *gpc;
+	GnomePrintConfig *config;
+	gchar *out_file;
+	
+	job = gnome_print_job_new (NULL);
+	gpc = gnome_print_job_get_context (job);
+	config = gnome_print_job_get_config (job);
+
+	if (options_pdf) {
+		if (!gnome_print_config_set (config, "Printer", "PDF"))
+			fail ("Could not set the printer to PDF\n");
+	} else {
+		gnome_print_config_set (config, "Printer", "GENERIC");
+	}
+	
+	out_file = options_output ? g_strdup (options_output) : g_strdup_printf ("o.%s", options_pdf ? "pdf" : "ps");
+	gnome_print_job_print_to_file (job, out_file);
+	g_free (out_file);
+	
+	gnome_print_config_set (config, GNOME_PRINT_KEY_PAPER_SIZE, "USLetter");
+	
+	/* Layout size */
+	gnome_print_job_get_page_size (job, &page_width, &page_height);
+ 
+	my_draw (gpc);
+
+	gnome_print_job_close (job);
+	gnome_print_job_print (job);
+
+	g_object_unref (G_OBJECT (config));
+	g_object_unref (G_OBJECT (gpc));
+	g_object_unref (G_OBJECT (job));
+}
+
+static void
+usage (gchar *error)
+{
+	if (error)
+		g_printerr ("Error: %s\n\n", error);
+
+	if (error)
+		poptPrintHelp (popt, stderr, 0);
+	else
+		poptPrintHelp (popt, stdout, 0);
+	
+	exit (-1);
+}
+
+int
+main (int argc, char * argv[])
+{
+	GError *error = NULL;
+	int ret;
+
+	g_type_init ();
+
+	prog_name = g_path_get_basename (argv[0]);
+	
+	popt = poptGetContext ("pango", argc, (const char **)argv, options, 0);
+
+	ret = poptGetNextOpt (popt);
+	if (ret != -1) {
+		usage (NULL);
+	}
+	
+	input_file = poptGetArg (popt);
+	if (!input_file)
+		usage ("Input file not specified");
+
+	if (!g_file_get_contents (input_file, &text, &len, &error))
+		fail ("%s\n", error->message);
+	if (!g_utf8_validate (text, len, NULL))
+		fail ("Text is not valid UTF-8");
+
+	/* Make sure we have valid markup
+	 */
+	if (options_markup &&
+	    !pango_parse_markup (text, -1, 0, NULL, NULL, NULL, &error))
+		fail ("Cannot parse input as markup: %s", error->message);
+
+	my_print ();
+
+	return 0;
+}
signature.asc (application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)

iD8DBQBAv8hiS+2LB0B90LERAh9MAJ4lG7oXhJS+Lm0NnXPOaKFjo4/q7QCgzL5n
vmN9yXDud7wV5jP5NiP2CzI=
=IxEk
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.