I've spent quite a bit of time over the last few weeks working on a
rewrite of how rendering works in Pango. At this point, the time to
get it done and API frozen for Pango-1.6 (API freezing next week)
looks too short, so I'm putting this work aside for the moment
and will resume it for Pango-1.8. (The version of Pango for
GTK+-2.6 and GNOME-2.10.)
PangoRenderer
=============
The basic idea is to have a base class, PangoRenderer that you subclass
for specific rendering devices. This avoids having the same driver logic
for rendering a layout for FT2, for Xft, for Win32, forGDK, for
GtkTextView, for gnome-print.
Once you have a PangoRenderer, the main public methods are:
void pango_renderer_draw_layout (PangoRenderer *renderer,
PangoLayout *layout,
int x,
int y);
void pango_renderer_draw_layout_line (PangoRenderer *renderer,
PangoLayoutLine *line,
int x,
int y);
void pango_renderer_draw_glyphs (PangoRenderer *renderer,
PangoFont *font,
PangoGlyphString *glyphs,
int x,
int y);
There is some flexibility in how you implement the rendering side
of PangoRenderer - at the simplest level, you can hook in at:
void (*draw_trapezoid) (PangoRenderer *renderer,
PangoRenderPart part,
double y1,
double x11,
double x21,
double y2,
double x12,
double x22);
void (*draw_glyph) (PangoRenderer *renderer,
PangoFont *font,
PangoGlyph glyph,
double x,
double y);
The coordinates here are in device-space pixels. Trapezoids are
used to decompose more complex shapes - rotated rectangles and
error underlines. Or you can move up a level and hook:
void (*draw_glyphs) (PangoRenderer *renderer,
PangoFont *font,
PangoGlyphString *glyphs,
int x,
int y);
void (*draw_rectangle) (PangoRenderer *renderer,
PangoRenderPart part,
int x,
int y,
int width,
int height);
void (*draw_error_underline) (PangoRenderer *renderer,
int x,
int y,
int width,
int height);
The coordinates for these are in user-space Pango units. The other
thing that needs to be supported is hooking in custom rendering
attributes (alpha, stipple, etc.) The main hook for this is:
void (*prepare_run) (PangoRenderer *renderer,
PangoLayoutRun *run);
This function is scans the attributes for the run for attributes
affecting rendering. If any attributes change how rendering happens (so
requiring splitting glyphs or underlines), the renderer subclass needs
to call:
void pango_renderer_part_changed (PangoRenderer *renderer,
PangoRenderPart part);
To allow efficiently combining rendering calls across runs and
lines, there is a ref-counted system for grouping rendering
requests.
void pango_renderer_activate (PangoRenderer *renderer);
void pango_renderer_deactivate (PangoRenderer *renderer);
void (*begin) (PangoRenderer *renderer);
void (*end) (PangoRenderer *renderer);
Finally setting colors and the above part_changed() call are virtualized
largely to allow chaining renderers and to allow renderer-specific
behavior on rendering changes:
void (*part_changed) (PangoRenderer *renderer,
PangoRenderPart part);
void (*color_set) (PangoRenderer *renderer,
PangoRenderPart part,
PangoColor *color);
Renderers
=========
So far, I've implemented two renderer subclasses - one for FT2 and
one for Xft. The Xft subclass is public and publically derivable because
customizing it further is needed for GDK. It has two virtual functions:
void (*composite_trapezoids) (PangoXftRenderer *xftrenderer,
PangoRenderPart part,
XTrapezoid *trapezoids,
int n_trapezoids);
void (*composite_glyphs) (PangoXftRenderer *xftrenderer,
XftFont *xft_font,
XftGlyphSpec *glyphs,
int n_glyphs);
That correspond to the low-level rendering operations. In GDK, we need
to add stippling and also to implement trapezoid rendering for
non-Render servers. (This is much easier in GDK where we have
gdk_pixbuf_from_drawable() than it is at the Pango level, so
PangoXftRenderer just doesn't draw underlines on servers without
Render.)
GDK and GTK+
============
The API sketched out above is all implemented and working pretty well;
I've added Xft rendering functions for LayoutLines and Layouts and they
work well and work rotated. What I've not really finished yet is testing
out how deriving from PangoRenderer works in practice in complex
situations. The maximally complex situation is GDK and GTK+.
The plan I have for GTK+ and GDK is
PangoRenderer PangoXftRenderer
/\ /\
|| ||
|| ||
GdkPangoRenderer --impl----> GdkX11Renderer
/\
||
||
GtkTextViewRenderer
GdkPangoRenderer delegates to a backend specific renderer
to get the effect of "multiple inheritance of implementation".
It adds the "stipple" and "emboss" attributes that we currently
have in GDK.
GdkX11Renderer implements stippling and non-RENDER rendering of
trapezoids.
GtkTextViewRenderer handles the custom GtkTextAttrAppearance
attribute.
Remaining TODO
==============
- Write a PangoRenderer for Win32 ... handling the antialiased
rotated underlines on older windows may be tricky. (Worst
case the case, the code in the pangoft2 renderer can be
used to get a gray-scale image to alpha-composite)
- Finish the GDK and GtkTextView renderers
- Work out how shaped runs work in detail; GtkTextView is a good
test case for this since it needs to associate the shaped runs
with particular embedded widgets.
- Switch gnome-print over to PangoRenderer
- Complete documentation
Regards,
Owen
Attachment:
pango-render.patch.gz
Description: GNU Zip compressed data
Attachment:
signature.asc
Description: This is a digitally signed message part