#include <config.h>
#include <math.h>
+#include <pango/pangocairo.h>
+#include "gdkcairo.h"
#include "gdkcolor.h"
#include "gdkgc.h"
+#include "gdkinternals.h"
#include "gdkpango.h"
#include "gdkrgb.h"
#include "gdkprivate.h"
#include "gdkscreen.h"
+#include "gdkintl.h"
#include "gdkalias.h"
-/* This is for P_() ... a bit non-kosher, but works fine */
-#include "gtk/gtkintl.h"
-
#define GDK_INFO_KEY "gdk-info"
/* We have various arrays indexed by render part; if PangoRenderPart
gboolean override_color_set[MAX_RENDER_PART + 1];
GdkBitmap *stipple[MAX_RENDER_PART + 1];
+ PangoColor emboss_color;
gboolean embossed;
- /* When switching between the normal and shadow copies when
- * drawing shadows we can get unexpected recursion into the
- * drawing functions; the 'in_emboss' flag guards against that.
- */
- gboolean in_emboss;
+ cairo_t *cr;
+ PangoRenderPart last_part;
/* Current target */
GdkDrawable *drawable;
GdkGC *base_gc;
- /* Cached GC, derived from base_gc */
- GdkGC *gc;
- PangoColor gc_color;
- gboolean gc_color_set;
- GdkBitmap *gc_stipple;
-
- /* we accumulate trapezoids for the same PangoRenderPart */
- GArray *trapezoids;
- PangoRenderPart trapezoid_part;
+ gboolean gc_changed;
};
static PangoAttrType gdk_pango_attr_stipple_type;
static PangoAttrType gdk_pango_attr_embossed_type;
-
-static void flush_trapezoids (GdkPangoRenderer *gdk_renderer);
+static PangoAttrType gdk_pango_attr_emboss_color_type;
enum {
PROP_0,
GdkPangoRendererPrivate *priv = gdk_renderer->priv;
int i;
- if (priv->gc)
- g_object_unref (priv->gc);
- if (priv->gc_stipple)
- g_object_unref (priv->gc_stipple);
if (priv->base_gc)
g_object_unref (priv->base_gc);
if (priv->drawable)
if (priv->stipple[i])
g_object_unref (priv->stipple[i]);
- g_array_free (priv->trapezoids, TRUE);
-
G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object);
}
return object;
}
-/* Adjusts matrix and color for the renderer to draw the secondar
+/* Adjusts matrix and color for the renderer to draw the secondary
* "shadow" copy for embossed text */
static void
-emboss_renderer (PangoRenderer *renderer,
- PangoRenderPart part,
- PangoMatrix **save_matrix,
- PangoColor **save_color)
+emboss_context (GdkPangoRenderer *renderer, cairo_t *cr)
{
- GdkPangoRendererPrivate *priv = GDK_PANGO_RENDERER(renderer)->priv;
- static const PangoColor white = { 0xffff, 0xffff, 0xffff };
- PangoMatrix tmp_matrix = PANGO_MATRIX_INIT;
+ GdkPangoRendererPrivate *priv = renderer->priv;
+ cairo_matrix_t tmp_matrix;
+ double red, green, blue;
- priv->in_emboss = TRUE;
-
- *save_color = pango_renderer_get_color (renderer, part);
- if (*save_color)
- *save_color = pango_color_copy (*save_color);
-
- *save_matrix = renderer->matrix;
- if (*save_matrix)
- {
- *save_matrix = pango_matrix_copy (*save_matrix);
- tmp_matrix = **save_matrix;
- }
-
/* The gymnastics here to adjust the matrix are because we want
* to offset by +1,+1 in device-space, not in user-space,
* so we can't just draw the layout at x + 1, y + 1
*/
- tmp_matrix.x0 += 1;
- tmp_matrix.y0 += 1;
-
- pango_renderer_set_matrix (renderer, &tmp_matrix);
- pango_renderer_set_color (renderer, part, &white);
+ cairo_get_matrix (cr, &tmp_matrix);
+ tmp_matrix.x0 += 1.0;
+ tmp_matrix.y0 += 1.0;
+ cairo_set_matrix (cr, &tmp_matrix);
+
+ red = (double) priv->emboss_color.red / 65535.;
+ green = (double) priv->emboss_color.green / 65535.;
+ blue = (double) priv->emboss_color.blue / 65535.;
+
+ cairo_set_source_rgb (cr, red, green, blue);
}
-/* Restores from emboss_renderer() */
-static void
-unemboss_renderer (PangoRenderer *renderer,
- PangoRenderPart part,
- PangoMatrix **save_matrix,
- PangoColor **save_color)
+static inline gboolean
+color_equal (const PangoColor *c1, const PangoColor *c2)
{
- GdkPangoRendererPrivate *priv = GDK_PANGO_RENDERER(renderer)->priv;
- pango_renderer_set_matrix (renderer, *save_matrix);
- pango_renderer_set_color (renderer, part, *save_color);
+ if (!c1 && !c2)
+ return TRUE;
- if (*save_matrix)
- pango_matrix_free (*save_matrix);
- if (*save_color)
- pango_color_free (*save_color);
+ if (c1 && c2 &&
+ c1->red == c2->red &&
+ c1->green == c2->green &&
+ c1->blue == c2->blue)
+ return TRUE;
- priv->in_emboss = FALSE;
+ return FALSE;
}
-/* Gets the GC for drawing @part. This make involve copying the base GC
- * for the renderer, in which case we keep a one-GC cache. */
-static GdkGC *
-get_gc (GdkPangoRenderer *gdk_renderer,
- PangoRenderPart part)
+static cairo_t *
+get_cairo_context (GdkPangoRenderer *gdk_renderer,
+ PangoRenderPart part)
{
PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
- PangoColor *color;
- GdkBitmap *stipple;
GdkPangoRendererPrivate *priv = gdk_renderer->priv;
- color = pango_renderer_get_color (renderer, part);
-
- if (part <= MAX_RENDER_PART)
- stipple = priv->stipple[part];
- else
- stipple = NULL;
-
- if (!color && !stipple) /* nothing override, use base_gc */
- return priv->base_gc;
- else
+ if (!priv->cr)
{
- gboolean new_stipple = FALSE;
- gboolean new_color = FALSE;
-
- if (stipple != priv->gc_stipple)
- new_stipple = TRUE;
-
- if ((priv->gc_color_set && !color) ||
- (!priv->gc_color_set && color) ||
- priv->gc_color.red != color->red ||
- priv->gc_color.green != color->green ||
- priv->gc_color.blue != color->blue)
- new_color = TRUE;
+ const PangoMatrix *matrix;
- if (!priv->gc)
- {
- priv->gc = gdk_gc_new (priv->drawable);
- gdk_gc_copy (priv->gc, priv->base_gc);
- }
- else if (new_color && priv->gc_color_set && !color)
- {
- /* We have to recopy the original GC onto the cached GC
- * to get the default color */
- new_stipple = TRUE;
- gdk_gc_copy (priv->gc, priv->base_gc);
- }
- else if (new_stipple && priv->gc_stipple && !stipple)
+ priv->cr = gdk_cairo_create (priv->drawable);
+
+ matrix = pango_renderer_get_matrix (renderer);
+ if (matrix)
{
- /* Similarly, we need to make a new copy to restore to the
- * default stipple state (the caller may have set a stipple
- * on the GC, and even if not, gdk_gc_set_stipple (gc, NULL)
- * doesn't work currently to restore to the default X stipple) */
- new_color = TRUE;
- gdk_gc_copy (priv->gc, priv->base_gc);
+ cairo_matrix_t cairo_matrix;
+
+ cairo_matrix_init (&cairo_matrix,
+ matrix->xx, matrix->yx,
+ matrix->xy, matrix->yy,
+ matrix->x0, matrix->y0);
+ cairo_set_matrix (priv->cr, &cairo_matrix);
}
+ }
+
+ if (part != priv->last_part)
+ {
+ PangoColor *pango_color;
+ GdkColor *color;
+ GdkColor tmp_color;
+ gboolean changed;
- if (new_color)
+ pango_color = pango_renderer_get_color (renderer, part);
+
+ if (priv->last_part != -1)
+ changed = priv->gc_changed ||
+ priv->stipple[priv->last_part] != priv->stipple[part] ||
+ !color_equal (pango_color,
+ pango_renderer_get_color (renderer, priv->last_part));
+ else
+ changed = TRUE;
+
+ if (changed)
{
- if (color)
+ if (pango_color)
{
- GdkColor gdk_color;
-
- gdk_color.red = color->red;
- gdk_color.green = color->green;
- gdk_color.blue = color->blue;
+ tmp_color.red = pango_color->red;
+ tmp_color.green = pango_color->green;
+ tmp_color.blue = pango_color->blue;
- gdk_gc_set_rgb_fg_color (priv->gc, &gdk_color);
-
- priv->gc_color = *color;
- priv->gc_color_set = TRUE;
+ color = &tmp_color;
}
else
- priv->gc_color_set = FALSE;
- }
+ color = NULL;
- if (new_stipple)
- {
- if (priv->gc_stipple)
- g_object_unref (priv->gc_stipple);
-
- if (stipple)
- {
- gdk_gc_set_stipple (priv->gc, stipple);
- gdk_gc_set_fill (priv->gc, GDK_STIPPLED);
- priv->gc_stipple = g_object_ref (stipple);
- }
- else
- priv->gc_stipple = NULL;
+ _gdk_gc_update_context (priv->base_gc,
+ priv->cr,
+ color,
+ priv->stipple[part],
+ priv->gc_changed);
}
- return priv->gc;
+ priv->last_part = part;
+ priv->gc_changed = FALSE;
}
+
+ return priv->cr;
}
static void
{
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
GdkPangoRendererPrivate *priv = gdk_renderer->priv;
+ cairo_t *cr;
- flush_trapezoids (gdk_renderer);
+ cr = get_cairo_context (gdk_renderer,
+ PANGO_RENDER_PART_FOREGROUND);
- if (!priv->in_emboss && priv->embossed)
+ if (priv->embossed)
{
- PangoMatrix *save_matrix;
- PangoColor *save_color;
-
- emboss_renderer (renderer, PANGO_RENDER_PART_FOREGROUND, &save_matrix, &save_color);
- gdk_draw_glyphs_transformed (priv->drawable,
- get_gc (gdk_renderer, PANGO_RENDER_PART_FOREGROUND),
- renderer->matrix, font, x, y, glyphs);
- unemboss_renderer (renderer, PANGO_RENDER_PART_FOREGROUND, &save_matrix, &save_color);
+ cairo_save (cr);
+ emboss_context (gdk_renderer, cr);
+ cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
+ pango_cairo_show_glyph_string (cr, font, glyphs);
+ cairo_restore (cr);
}
- gdk_draw_glyphs_transformed (priv->drawable,
- get_gc (gdk_renderer, PANGO_RENDER_PART_FOREGROUND),
- renderer->matrix, font, x, y, glyphs);
-}
-
-/* Outputs any pending trapezoids, we do this when the part or
- * part color changes, when we are about to draw text, etc. */
-static void
-flush_trapezoids (GdkPangoRenderer *gdk_renderer)
-{
- GdkPangoRendererPrivate *priv = gdk_renderer->priv;
-
- if (!priv->trapezoids || priv->trapezoids->len == 0)
- return;
-
- gdk_draw_trapezoids (priv->drawable,
- get_gc (gdk_renderer, priv->trapezoid_part),
- (GdkTrapezoid *)priv->trapezoids->data,
- priv->trapezoids->len);
-
- g_array_set_size (priv->trapezoids, 0);
-}
-
-/* Draws a single trapezoid ... we don't draw it immediately, but rather
- * cache it to join together with other trapezoids that form part of the
- * same logical shape */
-static void
-gdk_pango_renderer_draw_trapezoid (PangoRenderer *renderer,
- PangoRenderPart part,
- double y1,
- double x11,
- double x21,
- double y2,
- double x12,
- double x22)
-{
- GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
- GdkTrapezoid trap;
-
- if (!gdk_renderer->priv->trapezoids)
- gdk_renderer->priv->trapezoids = g_array_new (FALSE, FALSE,
- sizeof (GdkTrapezoid));
-
- if (gdk_renderer->priv->trapezoids->len > 0 &&
- gdk_renderer->priv->trapezoid_part != part)
- flush_trapezoids (gdk_renderer);
-
- gdk_renderer->priv->trapezoid_part = part;
-
- trap.y1 = y1;
- trap.x11 = x11;
- trap.x21 = x21;
- trap.y2 = y2;
- trap.x12 = x12;
- trap.x22 = x22;
-
- g_array_append_val (gdk_renderer->priv->trapezoids, trap);
+ cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
+ pango_cairo_show_glyph_string (cr, font, glyphs);
}
-/* We can't handle embossing at the level of trapezoids, because when an
- * underline is split into multiple trapezoids, the normal and shadow
- * trapezoids will be drawn mixed together. Instead, we have to emboss
- * and entire rectangle or error underline
- */
-
static void
gdk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
PangoRenderPart part,
{
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
GdkPangoRendererPrivate *priv = gdk_renderer->priv;
+ cairo_t *cr;
+
+ cr = get_cairo_context (gdk_renderer, part);
- if (!priv->in_emboss && priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
+ if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
{
- PangoMatrix *save_matrix;
- PangoColor *save_color;
-
- emboss_renderer (renderer, part, &save_matrix, &save_color);
- PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_rectangle (renderer, part,
- x, y, width, height);
- unemboss_renderer (renderer, part, &save_matrix, &save_color);
+ cairo_save (cr);
+ emboss_context (gdk_renderer, cr);
+ cairo_rectangle (cr,
+ (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+ (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+
+ cairo_fill (cr);
+ cairo_restore (cr);
}
- PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_rectangle (renderer, part,
- x, y, width, height);
+ cairo_rectangle (cr,
+ (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+ (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+ cairo_fill (cr);
}
static void
{
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
GdkPangoRendererPrivate *priv = gdk_renderer->priv;
-
- if (!priv->in_emboss && priv->embossed)
+ cairo_t *cr;
+
+ cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
+
+ if (priv->embossed)
{
- PangoMatrix *save_matrix;
- PangoColor *save_color;
-
- emboss_renderer (renderer, PANGO_RENDER_PART_UNDERLINE, &save_matrix, &save_color);
- PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_error_underline (renderer,
- x, y, width, height);
- unemboss_renderer (renderer, PANGO_RENDER_PART_UNDERLINE, &save_matrix, &save_color);
+ cairo_save (cr);
+ emboss_context (gdk_renderer, cr);
+ pango_cairo_show_error_underline (cr,
+ (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+ (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
+ cairo_restore (cr);
}
- PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->draw_error_underline (renderer,
- x, y, width, height);
+ pango_cairo_show_error_underline (cr,
+ (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
+ (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
}
static void
{
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
- if (part == gdk_renderer->priv->trapezoid_part)
- flush_trapezoids (gdk_renderer);
+ if (gdk_renderer->priv->last_part == part)
+ gdk_renderer->priv->last_part = (PangoRenderPart)-1;
}
static void
gdk_pango_renderer_begin (PangoRenderer *renderer)
{
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
-
- if (!gdk_renderer->priv->drawable || !gdk_renderer->priv->base_gc)
+ GdkPangoRendererPrivate *priv = gdk_renderer->priv;
+
+ if (!priv->drawable || !priv->base_gc)
{
g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()"
"must be used to set the target drawable and GC before using the renderer\n");
gdk_pango_renderer_end (PangoRenderer *renderer)
{
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
+ GdkPangoRendererPrivate *priv = gdk_renderer->priv;
- flush_trapezoids (gdk_renderer);
+ if (priv->cr)
+ {
+ cairo_destroy (priv->cr);
+ priv->cr = NULL;
+ }
+ priv->last_part = (PangoRenderPart)-1;
}
static void
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
gboolean embossed = FALSE;
GdkBitmap *stipple = NULL;
+ gboolean changed = FALSE;
+ PangoColor emboss_color;
GSList *l;
int i;
-
- embossed = FALSE;
- stipple = NULL;
-
+
+ emboss_color.red = 0xffff;
+ emboss_color.green = 0xffff;
+ emboss_color.blue = 0xffff;
+
for (l = run->item->analysis.extra_attrs; l; l = l->next)
{
PangoAttribute *attr = l->data;
{
embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
}
+ else if (attr->klass->type == gdk_pango_attr_emboss_color_type)
+ {
+ emboss_color = ((GdkPangoAttrEmbossColor*)attr)->color;
+ }
}
gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple);
if (embossed != gdk_renderer->priv->embossed)
{
gdk_renderer->priv->embossed = embossed;
- pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
+ changed = TRUE;
}
+ if (!color_equal (&gdk_renderer->priv->emboss_color, &emboss_color))
+ {
+ gdk_renderer->priv->emboss_color = emboss_color;
+ changed = TRUE;
+ }
+
+ if (changed)
+ pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
+
PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run);
for (i = 0; i <= MAX_RENDER_PART; i++)
renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
GDK_TYPE_PANGO_RENDERER,
GdkPangoRendererPrivate);
+
+ renderer->priv->last_part = (PangoRenderPart)-1;
+ renderer->priv->gc_changed = TRUE;
}
static void
PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
- renderer_class->draw_trapezoid = gdk_pango_renderer_draw_trapezoid;
renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
renderer_class->part_changed = gdk_pango_renderer_part_changed;
P_("Screen"),
P_("the GdkScreen for the renderer"),
GDK_TYPE_SCREEN,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate));
}
static void
on_renderer_display_closed (GdkDisplay *display,
+ gboolean is_error,
GdkPangoRenderer *renderer)
{
- g_signal_handlers_disconnect_by_func (renderer->priv->screen,
- (gpointer)on_renderer_display_closed,
+ g_signal_handlers_disconnect_by_func (display,
+ on_renderer_display_closed,
renderer);
- g_object_set_data (G_OBJECT (renderer->priv->screen), "gdk-pango-renderer", NULL);
+ g_object_set_data (G_OBJECT (renderer->priv->screen),
+ g_intern_static_string ("gdk-pango-renderer"), NULL);
}
/**
* by functions such as gdk_draw_layout().
*
* Before using the renderer, you need to call gdk_pango_renderer_set_drawable()
- * and gdk_pango_renderer_set_drawable() to set the drawable and graphics context
+ * and gdk_pango_renderer_set_gc() to set the drawable and graphics context
* to use for drawing.
*
* Return value: the default #PangoRenderer for @screen. The
if (!renderer)
{
renderer = gdk_pango_renderer_new (screen);
- g_object_set_data_full (G_OBJECT (screen), "gdk-pango-renderer", renderer,
+ g_object_set_data_full (G_OBJECT (screen),
+ g_intern_static_string ("gdk-pango-renderer"), renderer,
(GDestroyNotify)g_object_unref);
g_signal_connect (gdk_screen_get_display (screen), "closed",
priv = gdk_renderer->priv;
- flush_trapezoids (gdk_renderer);
-
if (priv->drawable != drawable)
{
if (priv->drawable)
priv = gdk_renderer->priv;
- flush_trapezoids (gdk_renderer);
-
if (priv->base_gc != gc)
{
if (priv->base_gc)
if (priv->base_gc)
g_object_ref (priv->base_gc);
- if (priv->gc)
- {
- g_object_unref (priv->gc);
- priv->gc = NULL;
- }
-
- priv->gc_color_set = FALSE;
-
- if (priv->gc_stipple)
- {
- g_object_unref (priv->gc_stipple);
- priv->gc_stipple = NULL;
- }
+ priv->gc_changed = TRUE;
}
}
PangoMatrix tmp_matrix;
tmp_matrix = *matrix;
- tmp_matrix.x0 = x;
- tmp_matrix.y0 = y;
+ tmp_matrix.x0 += x;
+ tmp_matrix.y0 += y;
+ pango_renderer_set_matrix (renderer, &tmp_matrix);
+
+ x = 0;
+ y = 0;
+ }
+ /* Fall back to introduce a matrix if the coords would scale out of range.
+ * The x and y here will be added to in-layout coordinates. So we cannot
+ * support the entire range here safely. So, we just accept the middle half
+ * and use fallback for the rest. */
+ else if (GDK_PANGO_UNITS_OVERFLOWS (x, y))
+ {
+ PangoMatrix tmp_matrix = PANGO_MATRIX_INIT;
+ tmp_matrix.x0 += x;
+ tmp_matrix.y0 += y;
pango_renderer_set_matrix (renderer, &tmp_matrix);
x = 0;
release_renderer (renderer);
}
-/* Gets the bounds of a layout in device coordinates. Note cut-and-paste
- * between here and gtklabel.c */
-static void
-get_rotated_layout_bounds (PangoLayout *layout,
- GdkRectangle *rect)
-{
- PangoContext *context = pango_layout_get_context (layout);
- const PangoMatrix *matrix = pango_context_get_matrix (context);
- gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
- PangoRectangle logical_rect;
- gint i, j;
-
- pango_layout_get_extents (layout, NULL, &logical_rect);
-
- for (i = 0; i < 2; i++)
- {
- gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
- for (j = 0; j < 2; j++)
- {
- gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
-
- gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
- gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
-
- if (i == 0 && j == 0)
- {
- x_min = x_max = xt;
- y_min = y_max = yt;
- }
- else
- {
- if (xt < x_min)
- x_min = xt;
- if (yt < y_min)
- y_min = yt;
- if (xt > x_max)
- x_max = xt;
- if (yt > y_max)
- y_max = yt;
- }
- }
- }
-
- rect->x = floor (x_min);
- rect->width = ceil (x_max) - rect->x;
- rect->y = floor (y_min);
- rect->height = floor (y_max) - rect->y;
-}
-
/**
* gdk_draw_layout_with_colors:
* @drawable: the drawable on which to draw string
if (matrix)
{
PangoMatrix tmp_matrix;
- GdkRectangle rect;
+ PangoRectangle rect;
- get_rotated_layout_bounds (layout, &rect);
+ pango_layout_get_extents (layout, NULL, &rect);
+ pango_matrix_transform_rectangle (matrix, &rect);
+ pango_extents_to_pixels (&rect, NULL);
tmp_matrix = *matrix;
tmp_matrix.x0 += x - rect.x;
tmp_matrix.y0 += y - rect.y;
pango_renderer_set_matrix (renderer, &tmp_matrix);
+ x = 0;
+ y = 0;
+ }
+ else if (GDK_PANGO_UNITS_OVERFLOWS (x, y))
+ {
+ PangoMatrix tmp_matrix = PANGO_MATRIX_INIT;
+ tmp_matrix.x0 = x;
+ tmp_matrix.y0 = y;
+ pango_renderer_set_matrix (renderer, &tmp_matrix);
+
x = 0;
y = 0;
}
else
pango_renderer_set_matrix (renderer, NULL);
-
+
pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
release_renderer (renderer);
gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
}
+/* GdkPangoAttrStipple */
+
static PangoAttribute *
gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
{
return (PangoAttribute *)result;
}
+/* GdkPangoAttrEmbossed */
+
static PangoAttribute *
gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
{
/**
* gdk_pango_attr_embossed_new:
- * @embossed: a bitmap to be set as embossed
+ * @embossed: if the region should be embossed
*
- * Creates a new attribute containing a embossed bitmap to be used when
- * rendering the text.
+ * Creates a new attribute flagging a region as embossed or not.
*
* Return value: new #PangoAttribute
**/
return (PangoAttribute *)result;
}
+/* GdkPangoAttrEmbossColor */
+
+static PangoAttribute *
+gdk_pango_attr_emboss_color_copy (const PangoAttribute *attr)
+{
+ const GdkPangoAttrEmbossColor *old = (const GdkPangoAttrEmbossColor*) attr;
+ GdkPangoAttrEmbossColor *copy;
+
+ copy = g_new (GdkPangoAttrEmbossColor, 1);
+ copy->attr.klass = old->attr.klass;
+ copy->color = old->color;
+
+ return (PangoAttribute *) copy;
+}
+
+static void
+gdk_pango_attr_emboss_color_destroy (PangoAttribute *attr)
+{
+ g_free (attr);
+}
+
+static gboolean
+gdk_pango_attr_emboss_color_compare (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const GdkPangoAttrEmbossColor *c1 = (const GdkPangoAttrEmbossColor*) attr1;
+ const GdkPangoAttrEmbossColor *c2 = (const GdkPangoAttrEmbossColor*) attr2;
+
+ return color_equal (&c1->color, &c2->color);
+}
+
+/**
+ * gdk_pango_attr_emboss_color_new:
+ * @color: a GdkColor representing the color to emboss with
+ *
+ * Creates a new attribute specifying the color to emboss text with.
+ *
+ * Return value: new #PangoAttribute
+ *
+ * Since: 2.12
+ **/
+PangoAttribute *
+gdk_pango_attr_emboss_color_new (const GdkColor *color)
+{
+ GdkPangoAttrEmbossColor *result;
+
+ static PangoAttrClass klass = {
+ 0,
+ gdk_pango_attr_emboss_color_copy,
+ gdk_pango_attr_emboss_color_destroy,
+ gdk_pango_attr_emboss_color_compare
+ };
+
+ if (!klass.type)
+ klass.type = gdk_pango_attr_emboss_color_type =
+ pango_attr_type_register ("GdkPangoAttrEmbossColor");
+
+ result = g_new (GdkPangoAttrEmbossColor, 1);
+ result->attr.klass = &klass;
+ result->color.red = color->red;
+ result->color.green = color->green;
+ result->color.blue = color->blue;
+
+ return (PangoAttribute *) result;
+}
+
/* Get a clip region to draw only part of a layout. index_ranges
* contains alternating range starts/stops. The region is the
* region which contains the given ranges, i.e. if you draw with the
* region as clip, only the given ranges are drawn.
*/
+static GdkRegion*
+layout_iter_get_line_clip_region (PangoLayoutIter *iter,
+ gint x_origin,
+ gint y_origin,
+ gint *index_ranges,
+ gint n_ranges)
+{
+ PangoLayoutLine *line;
+ GdkRegion *clip_region;
+ PangoRectangle logical_rect;
+ gint baseline;
+ gint i;
+
+ line = pango_layout_iter_get_line_readonly (iter);
+
+ clip_region = gdk_region_new ();
+
+ pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
+ baseline = pango_layout_iter_get_baseline (iter);
+
+ i = 0;
+ while (i < n_ranges)
+ {
+ gint *pixel_ranges = NULL;
+ gint n_pixel_ranges = 0;
+ gint j;
+
+ /* Note that get_x_ranges returns layout coordinates
+ */
+ if (index_ranges[i*2+1] >= line->start_index &&
+ index_ranges[i*2] < line->start_index + line->length)
+ pango_layout_line_get_x_ranges (line,
+ index_ranges[i*2],
+ index_ranges[i*2+1],
+ &pixel_ranges, &n_pixel_ranges);
+
+ for (j = 0; j < n_pixel_ranges; j++)
+ {
+ GdkRectangle rect;
+ int x_off, y_off;
+
+ x_off = PANGO_PIXELS (pixel_ranges[2*j] - logical_rect.x);
+ y_off = PANGO_PIXELS (baseline - logical_rect.y);
+
+ rect.x = x_origin + x_off;
+ rect.y = y_origin - y_off;
+ rect.width = PANGO_PIXELS (pixel_ranges[2*j + 1] - logical_rect.x) - x_off;
+ rect.height = PANGO_PIXELS (baseline - logical_rect.y + logical_rect.height) - y_off;
+
+ gdk_region_union_with_rect (clip_region, &rect);
+ }
+
+ g_free (pixel_ranges);
+ ++i;
+ }
+ return clip_region;
+}
/**
* gdk_pango_layout_line_get_clip_region:
* contained inside the line. This is to draw the selection all the way
* to the side of the layout. However, the clip region is in line coordinates,
* not layout coordinates.
+ *
+ * Note that the regions returned correspond to logical extents of the text
+ * ranges, not ink extents. So the drawn line may in fact touch areas out of
+ * the clip region. The clip region is mainly useful for highlightling parts
+ * of text, such as when text is selected.
*
* Return value: a clip region containing the given ranges
**/
gint n_ranges)
{
GdkRegion *clip_region;
- gint i;
- PangoRectangle logical_rect;
PangoLayoutIter *iter;
- gint baseline;
g_return_val_if_fail (line != NULL, NULL);
g_return_val_if_fail (index_ranges != NULL, NULL);
- clip_region = gdk_region_new ();
-
iter = pango_layout_get_iter (line->layout);
- while (pango_layout_iter_get_line (iter) != line)
+ while (pango_layout_iter_get_line_readonly (iter) != line)
pango_layout_iter_next_line (iter);
- pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
- baseline = pango_layout_iter_get_baseline (iter);
-
- pango_layout_iter_free (iter);
-
- i = 0;
- while (i < n_ranges)
- {
- gint *pixel_ranges = NULL;
- gint n_pixel_ranges = 0;
- gint j;
-
- /* Note that get_x_ranges returns layout coordinates
- */
- pango_layout_line_get_x_ranges (line,
- index_ranges[i*2],
- index_ranges[i*2+1],
- &pixel_ranges, &n_pixel_ranges);
-
- for (j=0; j < n_pixel_ranges; j++)
- {
- GdkRectangle rect;
-
- rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
- rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
- rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
- rect.height = logical_rect.height / PANGO_SCALE;
-
- gdk_region_union_with_rect (clip_region, &rect);
- }
+ clip_region = layout_iter_get_line_clip_region(iter, x_origin, y_origin, index_ranges, n_ranges);
- g_free (pixel_ranges);
- ++i;
- }
+ pango_layout_iter_free (iter);
return clip_region;
}
* you would pass to gdk_draw_layout_line(). @index_ranges should contain
* ranges of bytes in the layout's text.
*
+ * Note that the regions returned correspond to logical extents of the text
+ * ranges, not ink extents. So the drawn layout may in fact touch areas out of
+ * the clip region. The clip region is mainly useful for highlightling parts
+ * of text, such as when text is selected.
+ *
* Return value: a clip region containing the given ranges
**/
GdkRegion*
do
{
PangoRectangle logical_rect;
- PangoLayoutLine *line;
GdkRegion *line_region;
gint baseline;
- line = pango_layout_iter_get_line (iter);
-
pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
baseline = pango_layout_iter_get_baseline (iter);
- line_region = gdk_pango_layout_line_get_clip_region (line,
- x_origin + logical_rect.x / PANGO_SCALE,
- y_origin + baseline / PANGO_SCALE,
- index_ranges,
- n_ranges);
+ line_region = layout_iter_get_line_clip_region(iter,
+ x_origin + PANGO_PIXELS (logical_rect.x),
+ y_origin + PANGO_PIXELS (baseline),
+ index_ranges,
+ n_ranges);
gdk_region_union (clip_region, line_region);
gdk_region_destroy (line_region);
* instead of this function, to get the appropriate context for
* the widget you intend to render text onto.
*
+ * The newly created context will have the default font options (see
+ * #cairo_font_options_t) for the default screen; if these options
+ * change it will not be updated. Using gtk_widget_get_pango_context()
+ * is more convenient if you want to keep a context around and track
+ * changes to the screen's font rendering settings.
+ *
* Return value: a new #PangoContext for the default display
**/
PangoContext *
return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
}
+/**
+ * gdk_pango_context_get_for_screen:
+ * @screen: the #GdkScreen for which the context is to be created.
+ *
+ * Creates a #PangoContext for @screen.
+ *
+ * The context must be freed when you're finished with it.
+ *
+ * When using GTK+, normally you should use gtk_widget_get_pango_context()
+ * instead of this function, to get the appropriate context for
+ * the widget you intend to render text onto.
+ *
+ * The newly created context will have the default font options
+ * (see #cairo_font_options_t) for the screen; if these options
+ * change it will not be updated. Using gtk_widget_get_pango_context()
+ * is more convenient if you want to keep a context around and track
+ * changes to the screen's font rendering settings.
+ *
+ * Return value: a new #PangoContext for @screen
+ *
+ * Since: 2.2
+ **/
+PangoContext *
+gdk_pango_context_get_for_screen (GdkScreen *screen)
+{
+ PangoFontMap *fontmap;
+ PangoContext *context;
+ const cairo_font_options_t *options;
+ double dpi;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ fontmap = pango_cairo_font_map_get_default ();
+
+ context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
+
+ options = gdk_screen_get_font_options (screen);
+ pango_cairo_context_set_font_options (context, options);
+
+ dpi = gdk_screen_get_resolution (screen);
+ pango_cairo_context_set_resolution (context, dpi);
+
+ return context;
+}
+
#define __GDK_PANGO_C__
#include "gdkaliasdef.c"