Over the last few days I've gotten around to finishing up GTK+ support
for PangoRenderer and adding rotation support to GtkLabel.

My initial plans (
called for having a class structure in GTK+ like:

   PangoRenderer              PangoXftRenderer
        /\                         /\
        ||                         ||
        ||                         ||
  GdkPangoRenderer --impl----> GdkX11Renderer

It turns out that this "has a" relationship where GdkPangoRenderer
chains directly to GdkX11Renderer doesn't work very well, because it
bypasses the GdkDrawable vtable. And if you bypass the GdkDrawable
vtable all the wrapper drawable, automatic double buffering, etc,
becomes a real nuisance. So, what I ended up doing was adding
'draw_glyphs_transformed' and 'draw_trapezoids' virtual functions to
the drawable vtable. draw_trapezoids has a default implementation in
terms of draw_pixbuf(), which was needed for the non-RENDER case on X,
and also should make getting this going on other backends easier.

There is still a GdkX11Renderer subclass of PangoXftRenderer, but it's
only used to implement draw_glyphs_transformed(); the complicated
chaining of property changes between the two renderers is now
gone. This allowed me to remove the 'color_set' virtual function from
PangoRenderer vtable and simplify that a bit.

Since we added Xft support to GTK+, we haven't supported tile or
stipples for text. With these patches that lack crept into the
backgrounds and underlines for the text as well since we are are now
drawing them with XRenderCompositeTrapezoids(). So, I went ahead and
fixed tile and stipple support for the render-based codepath. In the
render code path insensitive text now displays precisely as intended
-- embossed for the default colors, and stippled when the foreground
or background is set. I also added a demo to GTK+ demo showing drawing
rotated antialiased text with GDK using a tile image. Which was neat,
until it started triggering a bug in RENDER and using random bits of
the root window instead of the right tile.

Tile and stipples are not currently supported in the fallback case,
doing this for text is basically impossible because Xft doesn't expose
any way of getting at the bits; perhaps fixing this is best left until
after the Cairo switch.

The GtkLabel API for rotated labels is really simple:

void     gtk_label_set_angle (GtkLabel *label,
			      gdouble   angle);
gdouble  gtk_label_get_angle (GtkLabel *label);

And a corresponding 'angle' property. gtk_label_set_angle takes any
angle in degrees, but canonicalizes it to the [0,360] range of the

I also converted GtkTextView to use PangoRenderer. It turned out that
what gtktextdisplay.c was doing to match PangoAttrShape attributes to
embedded widgets or pixbuf was really inconvenient once PangoRenderer
was introduced: it was keeping a linked list of widgets, and pixbufs
and matching that up by order... something that didn't even work
properly for objects embedded within a right-to-left or bidi line.

So, I introduced:

typedef gpointer (*PangoAttrDataCopyFunc) (gconstpointer data);

PangoAttribute *pango_attr_shape_new_with_data (const PangoRectangle  *ink_rect,
						const PangoRectangle  *logical_rect,
						gpointer               data,
						PangoAttrDataCopyFunc  copy_func,
						GDestroyNotify         destroy_func);

to allow storing user data on a PangoAttrShape for doing the back
association, which works out much more nicely. Unfortunately, the
linked list for association is in the semi-public API ...

struct _GtkTextLineDisplay
  GSList *shaped_objects;

So I couldn't remove it. The code currently still adds the objects to the
list for maximum compatbility, but the list is otherwise unused.

I'm pretty happy about the current state of this. I've landed the Pango
changes into CVS. The only possibly open API issue with the GTK+ part
is that gdk_pango_renderer_new() and gdk_pango_renderer_get_default() 
take a screen parameter. While this was needed in the original design, the
screen parameter is currently superfluous and could be removed. 
I'm of two minds about that, while removing it would make things 
a little simpler for users, it does leave the door open for caching of 
screen specific resources. Also, for gdk_pango_renderer_get_default() 
it fits the pattern of keeping global resources per-screen or per-display
and thus freed on display close.

The main remaining issue for getting the GTK+ changes into CVS is Win32
support. Possible steps in that direction:

 - Simply implement drawable.draw_glyphs_transformed by calling
   drawable.draw_glyphs. That would at least keep what works currently
   working, but rotated text wouldn't work. Approximate time - 10 minutes.

 - Implement support in PangoWin32Font for loading fonts with transformation
   matrices and implement pango_win32_render_transformed(). This is
   sufficient to get rotated text working. Approximate time - 2-3 hours(?)

 - Implement a PangoWin32Renderer. Not really needed for GDK, but would
   clean up duplicated code and provide some new capabilities.
   Approximate time - 2-3 hours(???)

 - Implement drawable.draw_trapezoids using GDI (and/or GDI+) rather than
   the fallback code to improve efficiency and get tiles/stipples working.
   Approximate time - unknown. Note the saturated-add-then-composite
   semantic of draw_trapezoids, which is needed to prevent seams.

Attached are ChangeLog, header file snippets for new API, and the entire
patch (compressed). The patch includes docs and testgtk and gtk-demo
Sat Nov 20 15:13:51 2004  Owen Taylor  <otaylor redhat com>

	* gdk/gdkpango.[ch]: Add GdkPangoRenderer, a subclass of 
	PangoRenderer targeting GDK drawables. Use to implement the old
	gdk_draw_layout() and friends.

	* gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkwindow.c gdk/gdkpixmap.c:
	Add gdk_draw_glyphs_transformed() gdk_draw_trapezoids() and
	the corresponding members of GdkDrawableClass. Add a fallback
	implementation of gdk_draw_trapezoids() in terms of pixbufs.

	* gdk/gdkwindowing.h gdk/x11/gdkg-x11.h: Add 
	_gdk_windowing_gc_get_foreground() to enable the fallback 
	trapezoid implementation.

	* gdk/x11/gdkdrawable-x11.c gdk/x11/gdkdisplay-x11.h: Implement 
	draw_glyph_transformed,	draw_trapezoids.

	* gdk/x11/gdkdrawable-x11.[ch]: Add 
	_gdk_x11_drawable_draw_xtrapezoids, _gdk_x11_drawable_draw_xft_glyphs
	for use of GdkX11Renderer.

	* gdk/x11/gdkgc-x11.c gdk/x11/gdkprivate-x11.h: Implement

	* gdk/gdkpango-x11.c: Add GdkX11Renderer... a subclass of 
	PangoXftRenderer that does tiles/stipples and fallback rendering
	of trapezoids without the RENDER extension.

	* gdk/gdkpango-x11.c gdk/x11/gdkscreen-x11.[ch] _gdk_x11_renderer_get:
	Add _gdk_x11_renderer_get() to get a singleton GdkX11Renderer
	for the screen.

	* gdk/x11/gdkdrawable-x11.c (get_impl_drawable): Fix a None/NULL

	* gtk/gtklabel.[ch] gtk/gtk.symbols: Add gtk_label_set/get_angle(),
	and an ::angle property.

	* gtk/gtklabel.c: Remove #if 0'd dead code gtk_label_paint_word().

	* gtk/gtktextdisplay.c: Switch to using a GtkTextRenderer subclass
	of GdkPangoRenderer for drawing.

	* gtk/gtktextlayout.[ch] gtk/gtktextdisplay.c: Switch to using
	gtk_attr_shape_new_with_data() to store backreferences to 
	embedded pixmaps and widgets. Leave line_display->shaped_objects
	around for backwords compatibility.

	* gdk/gdkpango.[ch] (gdk_pango_context_set_colormap): Describe
	as deprecated, remove implementation.

	* gtk/gtkwidget.c (gtk_widget_create_pango_context): Remove
	call to gdk_pango_context_set_colormap.

	* demos/gtk-demo/ demos/gtk-demo/rotated_text.c: Add
	a demo showing drawing rotated text.

	* tests/testgtk.c: Add a rotated-label test, and also a rotated
	drawing test (differs from demos/gtk-demo/rotated_text by also
	using a tile)
typedef struct _GdkPangoRenderer        GdkPangoRenderer;
typedef struct _GdkPangoRendererClass   GdkPangoRendererClass;

struct _GdkPangoRenderer
  PangoRenderer parent_instance;

  GdkPangoRendererPrivate *priv;

struct _GdkPangoRendererClass
  PangoRendererClass parent_class;

PangoRenderer *gdk_pango_renderer_new         (GdkScreen *screen);
PangoRenderer *gdk_pango_renderer_get_default (GdkScreen *screen);

void gdk_pango_renderer_set_drawable       (GdkPangoRenderer *gdk_renderer,
					    GdkDrawable      *drawable);
void gdk_pango_renderer_set_gc             (GdkPangoRenderer *gdk_renderer,
					    GdkGC            *gc);
void gdk_pango_renderer_set_stipple        (GdkPangoRenderer *gdk_renderer,
					    PangoRenderPart   part,
					    GdkBitmap        *stipple);
void gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer,
					    PangoRenderPart   part,
					    const GdkColor   *color);

struct _GdkDrawableClass 
  GObjectClass parent_class;
  void (*draw_glyphs_transformed) (GdkDrawable      *drawable,
				   GdkGC	    *gc,
				   PangoMatrix      *matrix,
				   PangoFont        *font,
				   gint              x,
				   gint              y,
				   PangoGlyphString *glyphs);
  void (*draw_trapezoids)         (GdkDrawable      *drawable,
				   GdkGC	    *gc,
				   GdkTrapezoid     *trapezoids,
				   gint              n_trapezoids);

void gdk_draw_glyphs_transformed (GdkDrawable      *drawable,
				  GdkGC	           *gc,
				  PangoMatrix      *matrix,
				  PangoFont        *font,
				  gint              x,
				  gint              y,
				  PangoGlyphString *glyphs);
void gdk_draw_trapezoids         (GdkDrawable      *drawable,
				  GdkGC	           *gc,
				  GdkTrapezoid     *trapezoids,
				  gint              n_trapezoids);

void     gtk_label_set_angle (GtkLabel         *label,
			      gdouble           angle);
gdouble  gtk_label_get_angle (GtkLabel         *label);

Attachment: gdk-pango-renderer.diff.gz
Description: GNU Zip compressed data

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]