/* viewer-pangocairo.c: PangoCairo viewer backend. * * Copyright (C) 1999,2004,2005 Red Hat, Inc. * Copyright (C) 2001 Sun Microsystems * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "renderdemo.h" #include "viewer-cairo.h" #include typedef struct { const CairoViewerIface *iface; gpointer backend; PangoFontMap *fontmap; cairo_font_options_t *font_options; } CairoViewer; /* TODO: hinting */ static gpointer pangocairo_view_create (const PangoViewer *klass) { CairoViewer *instance; instance = g_slice_new (CairoViewer); instance->iface = get_default_cairo_viewer_iface (); instance->backend = instance->iface->backend_class->create (instance->iface->backend_class); instance->fontmap = pango_cairo_font_map_get_default (); pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (instance->fontmap), opt_dpi); instance->font_options = cairo_font_options_create (); if (opt_hinting != HINT_DEFAULT) { cairo_font_options_set_hint_metrics (instance->font_options, CAIRO_HINT_METRICS_ON); if (opt_hinting == HINT_NONE) cairo_font_options_set_hint_style (instance->font_options, CAIRO_HINT_STYLE_NONE); else if (opt_hinting == HINT_FULL) cairo_font_options_set_hint_style (instance->font_options, CAIRO_HINT_STYLE_FULL); } return instance; } static void pangocairo_view_destroy (gpointer instance) { CairoViewer *c = (CairoViewer *) instance; cairo_font_options_destroy (c->font_options); g_object_unref (c->fontmap); c->iface->backend_class->destroy (c->backend); g_slice_free (CairoViewer, c); } static PangoContext * pangocairo_view_get_context (gpointer instance) { CairoViewer *c = (CairoViewer *) instance; PangoContext *context; context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (c->fontmap)); pango_cairo_context_set_font_options (context, c->font_options); return context; } typedef struct { gpointer backend; cairo_surface_t *cairo; } CairoSurface; static gpointer pangocairo_view_create_surface (gpointer instance, int width, int height) { CairoViewer *c = (CairoViewer *) instance; CairoSurface *surface; surface = g_slice_new (CairoSurface); surface->backend = c->iface->backend_class->create_surface (c->backend, width, height); surface->cairo = c->iface->create_surface (c->backend, surface->backend, width, height); return surface; } static void pangocairo_view_destroy_surface (gpointer instance, gpointer surface) { CairoViewer *c = (CairoViewer *) instance; CairoSurface *c_surface = (CairoSurface *) surface; c->iface->backend_class->destroy_surface (c->backend, c_surface->backend); cairo_surface_destroy (c_surface->cairo); g_slice_free (CairoSurface, surface); } static void render_callback (PangoLayout *layout, int x, int y, gpointer context, gpointer data) { cairo_t *cr = (cairo_t *) context; gboolean show_borders = GPOINTER_TO_UINT (data) == 0xdeadbeef; cairo_move_to (cr, x, y); pango_cairo_show_layout (cr, layout); if (show_borders) { PangoRectangle ink, logical; double lw = cairo_get_line_width (cr); pango_layout_get_extents (layout, &ink, &logical); cairo_save (cr); cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.75); cairo_rectangle (cr, (double)logical.x / PANGO_SCALE - lw / 2, (double)logical.y / PANGO_SCALE - lw / 2, (double)logical.width / PANGO_SCALE + lw, (double)logical.height / PANGO_SCALE + lw); cairo_stroke (cr); cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 0.75); cairo_rectangle (cr, (double)ink.x / PANGO_SCALE - lw / 2, (double)ink.y / PANGO_SCALE - lw / 2, (double)ink.width / PANGO_SCALE + lw, (double)ink.height / PANGO_SCALE + lw); cairo_stroke (cr); cairo_restore (cr); } } static void transform_callback (PangoContext *context, PangoMatrix *matrix, gpointer cr_context, gpointer state) { cairo_t *cr = (cairo_t *)cr_context; cairo_matrix_t cairo_matrix; if (matrix) { cairo_matrix.xx = matrix->xx; cairo_matrix.yx = matrix->yx; cairo_matrix.xy = matrix->xy; cairo_matrix.yy = matrix->yy; cairo_matrix.x0 = matrix->x0; cairo_matrix.y0 = matrix->y0; } else { cairo_matrix_init_identity (&cairo_matrix); } cairo_set_matrix (cr, &cairo_matrix); pango_context_set_matrix (context, matrix); pango_cairo_update_context (cr, context); } static void pangocairo_view_render (gpointer instance, gpointer surface, PangoContext *context, int width, int height, gpointer state) { cairo_t *cr; CairoSurface *c_surface = (CairoSurface *) surface; if (!surface) { cairo_surface_t *cs; /* This is annoying ... we have to create a temporary surface just to * get the extents of the text. */ cs = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1); cr = cairo_create (cs); cairo_surface_destroy (cs); } else cr = cairo_create (c_surface->cairo); transform_callback (context, NULL, cr, state); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_paint (cr); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); do_output (context, render_callback, transform_callback, cr, state, NULL, NULL); cairo_destroy (cr); } #ifdef HAVE_CAIRO_PNG static cairo_status_t write_func (void *closure, const unsigned char *data, unsigned int length) { FILE *stream = (FILE *) closure; unsigned int l; l = fwrite (data, 1, length, stream); return l == length ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR; } static void pangocairo_view_save (gpointer instance, gpointer surface, FILE *stream, int width, int height) { CairoSurface *c_surface = (CairoSurface *) surface; cairo_surface_write_to_png_stream (c_surface->cairo, write_func, stream); } #endif static gpointer pangocairo_view_create_window (gpointer instance, const char *title, int width, int height) { CairoViewer *c = (CairoViewer *) instance; return c->iface->backend_class->create_window (c->backend, title, width, height); } static void pangocairo_view_destroy_window (gpointer instance, gpointer window) { CairoViewer *c = (CairoViewer *) instance; c->iface->backend_class->destroy_window (c->backend, window); } static gpointer pangocairo_view_display (gpointer instance, gpointer surface, gpointer window, int width, int height, gpointer state) { CairoViewer *c = (CairoViewer *) instance; CairoSurface *c_surface = (CairoSurface *) surface; return c->iface->backend_class->display (c->backend, c_surface->backend, window, width, height, state); } const PangoViewer pangocairo_viewer = { "PangoCairo", "cairo", NULL, pangocairo_view_create, pangocairo_view_destroy, pangocairo_view_get_context, pangocairo_view_create_surface, pangocairo_view_destroy_surface, pangocairo_view_render, #ifdef HAVE_CAIRO_PNG pangocairo_view_save, #else NULL, #endif pangocairo_view_create_window, pangocairo_view_destroy_window, pangocairo_view_display };