PangoRenderer



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



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