[patch] Rework of Pango integration



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

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  <otaylor redhat com>
+
+	* 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 <jody gnome org>
 
 	* 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 <jean brefort ac-dijon fr>
+ * Copyright (C) 2004 Red Hat, Inc.
  *
  * Developed by Jean Bréfort <jean brefort ac-dijon fr>
+ * Rewritten by Owen Taylor <otaylor redhat com>
  *
  * 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 <jean brefort ac-dijon fr>
+ * Copyright (C) 2004 Red Hat, Inc.
  *
  * Developed by Jean Bréfort <jean brefort ac-dijon fr>
+ * Rewritten by Owen Taylor <otaylor redhat com>
  *
  * 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 <otaylor redhat com>
+ */
+#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;
+}

Attachment: signature.asc
Description: This is a digitally signed message part



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