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