Computing cairo surface dimensions in advance



Hello,

in one of my pet projects I use Pango and cairo to render text into an
intensity texture for OpenGL drawing.  To save space while keeping
things flexible, I put each user interface string into a separate
rectangle texture, tightly fitting around the ink extents of the layout.

But to do that, I need to know the dimensions of the layout in advance
before creating the cairo image surface to draw on.  This leads to a
chicken'n'egg problem of course since I can't call
pango_cairo_update_layout() before creating a cairo surface.  In fact it
happens to work even if I don't call pango_cairo_update_layout() at all
(I get the PangoLayout from gtk_widget_create_pango_layout).  But that's
probably just by chance.  Trying to do things the Right Way (tm), my
code now looks like this:

  // Try to do things correctly and create a dummy cairo context with surface
  // type and transformation matching what we are going to use at draw time.
  // According to the pangocairo documentation, not doing so might result in
  // wrong measurements due to possible differences in hinting and such.
  {
    cairo_surface_t *const surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
    cairo_t *const context = cairo_create(surface);

    cairo_surface_destroy(surface); // drop reference

    cairo_scale(context, 1.0, -1.0);
    pango_cairo_update_layout(context, layout->gobj());

    layout->get_pixel_extents(ink, logical);

    cairo_destroy(context);
  }

  [... code computing the image size and other stuff ...]

  // Create a Cairo surface to draw the layout directly into the texture
  // image -- upside-down and at the right position.  This rocking new
  // functionality allows us to get away without any buffer copies, yay!
  {
    cairo_surface_t *const surface = cairo_image_surface_create_for_data(
        &tex_image[0], CAIRO_FORMAT_A8, img_width, img_height, img_width * sizeof(GLubyte));

    cairo_t *const context = cairo_create(surface);

    cairo_surface_destroy(surface); // drop reference

    cairo_scale(context, 1.0, -1.0);
    cairo_move_to(context, img_border + PADDING - ink.get_x(),
                         -(img_border + PADDING + ink.get_y() + ink.get_height()));

    pango_cairo_show_layout(context, layout->gobj());

    cairo_destroy(context);
  }

'Tis ain't pretty.  Is the code above actually correct?  Is there a
better to do this kind of thing?

Thanks a lot for your help,
--Daniel

P.S.: Sorry if this has been asked before; the search facility of the
mail.gnome.org archives is currently broken.





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