Re: pango_cairo_update_layout()



Behdad Esfahbod wrote:
Theo Veenker wrote:
Hi,

Hi,

A question regarding pango_cairo_update_layout(). The example in
http://library.gnome.org/devel/pango/stable/pango-Cairo-Rendering.html
contains the following fragment:
[snip]
Why is it that it doesn't make a difference whether
pango_cairo_update_layout()
is called or not. The output is the same. Is it really necessary to call
this
function if only the cairo context changes? Why? In my own code I also
don't
notice any diffrence if I just drop the pango_cairo_update_layout() call.

It's very delicate.  For example, if you have hinting enabled, then the size
of a layout with identity matrix may be different from one of a rotated matrix
as hinting is only done with axis-aligned transforms.  And for pango to pick
up the matrix from your cairo_t you need to make that function call.

Thanks for the info. But I now noticed some condition where calling
pango_cairo_update_layout() has a big unexpected impact. I've created
a little X test application that demonstrates it (attached). The program
draws a string using cairo-pango. It responds to following keys:
 - page up/down: controls scaling factor for cairo_scale()
 - up/down: controls rotate angle for cairo_rotate()
 - 1/0: enable/disable calling pango_cairo_update_layout() before
        pango_cairo_show_layout()
 - r: recreate layout object
 - R: recreate both context and layout object
 - enter: dump image as xresult.png

Start the program and scale up to a factor 5 (hit pgup). It now looks
like in attached result1.png. Hit '1' to enable calling pango_cairo_update_layout().
Now you'll see result2.png, which is rather weird. Turn off calling
pango_cairo_update_layout() (hit '0') and recreate the layout (hit 'r').
The result stays bad. After recreating both the context and layout (hit 'R')
the output is OK again. FWIW, there is no difference (in my eyes) when the
image is rotated a bit.

What's going on here? I can't believe it is a font question as the output
looks perfect to me when not calling pango_cairo_update_layout(). Hopefully
it is just a silly error on my side.

Could you please take a look at this Behdad?

Regards,
Theo
// gcc xlayoutupdate.c -o xlayoutupdate -Wall `pkg-config --cflags --libs pangocairo` -lX11 -lXext

#include <pango/pangocairo.h>
#include <cairo-xlib.h>
#include <math.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

void draw(cairo_surface_t *surface, PangoLayout *layout, 
    double rotation, double scaling, int doupdatelayout)
{
    cairo_t *cr = cairo_create(surface);

    cairo_set_source_rgb(cr, 1, 1, 0.75);
    cairo_paint(cr);

    cairo_save(cr);

    cairo_translate(cr, 5, 5);

    cairo_scale(cr, scaling, scaling);

    cairo_rotate(cr, rotation);

    cairo_set_source_rgb(cr, 0, 0, 0);

    if (doupdatelayout) pango_cairo_update_layout(cr, layout);

    pango_cairo_show_layout(cr, layout);

    cairo_new_path(cr);
    cairo_restore(cr);
    
    cairo_destroy(cr);
}

#define ROTATE_STEP	(1.0/180.0*M_PI)
#define SCALE_FACTOR	1.1
#define TEXT		"WaYo PaYo"

int main()
{
    Display *display;
    Window win;
    XEvent event;
    int quit;
    double rotation = 0.0;
    double scaling = 1.0;
    int doupdatelayout = 0;

    cairo_surface_t *surface;

    PangoContext *context;
    PangoLayout *layout;
    PangoFontDescription *fontdescrip;

#if 1
    fontdescrip = pango_font_description_new();
    pango_font_description_set_family_static(fontdescrip, "Sans-Serif");
    pango_font_description_set_size(fontdescrip, 12 * PANGO_SCALE);
    pango_font_description_set_style(fontdescrip, PANGO_STYLE_NORMAL);
    pango_font_description_set_weight(fontdescrip, PANGO_WEIGHT_NORMAL);
    pango_font_description_set_variant(fontdescrip, PANGO_VARIANT_NORMAL);
    pango_font_description_set_stretch(fontdescrip, PANGO_STRETCH_NORMAL);
#else
    fontdescrip = pango_font_description_from_string("Sans-Serif 12");
#endif

#if PANGO_VERSION_CHECK(1,21,4)
    context = pango_font_map_create_context(pango_cairo_font_map_get_default());
#else
    context = pango_cairo_font_map_create_context((PangoCairoFontMap*)pango_cairo_font_map_get_default());
#endif
    pango_context_set_font_description(context, fontdescrip);

    layout = pango_layout_new(context);
    pango_layout_set_text(layout, TEXT, -1);
    
    // Open display and create window.
    display = XOpenDisplay(NULL);
    if (!display) {
        printf("Error: unabale to open display\n");
    	return -1;
    }
    win = XCreateSimpleWindow(display, 
    	RootWindow(display, DefaultScreen(display)),
    	0, 0, 600, 100, 0, 
	BlackPixel(display, DefaultScreen(display)), 
	WhitePixel(display, DefaultScreen(display)));

    // Create xlib surface.
    surface = cairo_xlib_surface_create(display, win, 
    	DefaultVisual(display, DefaultScreen(display)), 600, 100);

    // Enter event loop.
    XSelectInput(display, win, ExposureMask | KeyPressMask | ButtonPressMask);
    XMapWindow(display, win);
    quit = 0;
    while (!quit) {
    	int index;
    	KeySym keysym;
        XNextEvent(display, &event);
        switch (event.type) {
            case Expose:
            	if (event.xexpose.count != 0) break;
    	    	// Draw to xlib surface.
    	    	draw(surface, layout, rotation, scaling, doupdatelayout);
                break;

            case ButtonPress:
		if (event.xbutton.button == 4) {
		    rotation -= ROTATE_STEP;
		    printf("rotation %g degrees\n", rotation);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (event.xbutton.button == 5) {
		    rotation += ROTATE_STEP;
		    printf("rotation %g degrees\n", rotation);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
	    	break;

            case KeyPress:
		index = (event.xkey.state & (ShiftMask|LockMask)) ? 1 : 0;
		keysym = XLookupKeysym(&event.xkey, index);
		if (keysym == XK_Escape) {
	    	    quit = 1;
		}
		else if (keysym == XK_Return) {
    	    	    if (!cairo_surface_write_to_png(surface, "xresult.png"))
		    	printf("wrote xresult.png\n");
		}
		else if (keysym == XK_1) {
		    doupdatelayout = 1;
		    printf("layout update %d\n", doupdatelayout);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_0) {
		    doupdatelayout = 0;
		    printf("layout update %d\n", doupdatelayout);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_r) {
		    printf("recreating layout\n");
    	    	    g_object_unref(layout);
    		    layout = pango_layout_new(context);
    	    	    pango_layout_set_text(layout, TEXT, -1);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_R) {
		    printf("recreating layout and context\n");
    	    	    g_object_unref(layout);
    	    	    g_object_unref(context);
#if PANGO_VERSION_CHECK(1,21,4)
    	    	    context = pango_font_map_create_context(pango_cairo_font_map_get_default());
#else
    	    	    context = pango_cairo_font_map_create_context((PangoCairoFontMap*)pango_cairo_font_map_get_default());
#endif
    	    	    pango_context_set_font_description(context, fontdescrip);
    		    layout = pango_layout_new(context);
    	    	    pango_layout_set_text(layout, TEXT, -1);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_Up) {
		    rotation -= ROTATE_STEP;
		    printf("rotation %g degrees\n", rotation);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_Down) {
		    rotation += ROTATE_STEP;
		    printf("rotation %g degrees\n", rotation);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_Page_Up) {
		    scaling *= SCALE_FACTOR;
		    printf("scaling %g\n", scaling);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
		else if (keysym == XK_Page_Down) {
		    scaling /= SCALE_FACTOR;
		    printf("scaling %g\n", scaling);
		    draw(surface, layout, rotation, scaling, doupdatelayout);
		}
	    	break;
	}
    }

    g_object_unref(layout);
    g_object_unref(context);
    cairo_surface_destroy(surface);

    XDestroyWindow(display, win);
    XCloseDisplay(display);

    return 0;
}

PNG image

PNG image



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