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, &pango_width, &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