diff options
Diffstat (limited to 'pango')
-rw-r--r-- | pango/Makefile.am | 7 | ||||
-rw-r--r-- | pango/pango-renderer.c | 1207 | ||||
-rw-r--r-- | pango/pango-renderer.h | 238 | ||||
-rw-r--r-- | pango/pango.h | 1 | ||||
-rw-r--r-- | pango/pangoft2-fontmap.c | 23 | ||||
-rw-r--r-- | pango/pangoft2-private.h | 11 | ||||
-rw-r--r-- | pango/pangoft2-render.c | 617 | ||||
-rw-r--r-- | pango/pangoft2.c | 562 | ||||
-rw-r--r-- | pango/pangoxft-font.c | 271 | ||||
-rw-r--r-- | pango/pangoxft-fontmap.c | 23 | ||||
-rw-r--r-- | pango/pangoxft-private.h | 12 | ||||
-rw-r--r-- | pango/pangoxft-render.c | 836 | ||||
-rw-r--r-- | pango/pangoxft-render.h | 142 | ||||
-rw-r--r-- | pango/pangoxft.h | 36 |
14 files changed, 2897 insertions, 1089 deletions
diff --git a/pango/Makefile.am b/pango/Makefile.am index ee458a27..9dbf6308 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -77,6 +77,7 @@ libpango_1_0_la_SOURCES = \ pango-layout.c \ pango-layout-private.h \ pango-markup.c \ + pango-renderer.c \ pango-script.c \ pango-script-lang-table.h \ pango-script-table.h \ @@ -101,6 +102,7 @@ pango_headers = \ pango-item.h \ pango-layout.h \ pango-modules.h \ + pango-renderer.h \ pango-script.h \ pango-tabs.h \ pango-types.h \ @@ -195,7 +197,7 @@ pangoft2-win32res.lo: pangoft2.rc # ------------------- libpangoxft ------------------- if HAVE_XFT -pangoinclude_HEADERS += pangoxft.h pango-ot.h +pangoinclude_HEADERS += pangoxft.h pangoxft-render.h pango-ot.h lib_LTLIBRARIES += libpangoxft-1.0.la endif @@ -206,7 +208,8 @@ libpangoxft_1_0_la_DEPENDENCIES = libpangoft2-$(PANGO_API_VERSION).la libpango-$ libpangoxft_1_0_la_SOURCES = \ pangoxft-font.c \ pangoxft-fontmap.c \ - pangoxft-private.h + pangoxft-private.h \ + pangoxft-render.c # ------------------- libpangowin32 ------------------- diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c new file mode 100644 index 00000000..620685d1 --- /dev/null +++ b/pango/pango-renderer.c @@ -0,0 +1,1207 @@ +/* Pango + * pango-renderer.h: Base class for rendering + * + * Copyright (C) 2004 Red Hat, Inc. + * + * 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 <stdlib.h> + +#include "pango-renderer.h" + +#define N_RENDER_PARTS 4 + +#define IS_VALID_PART(part) ((guint)part < N_RENDER_PARTS) + +typedef struct _LineState LineState; +typedef struct _Point Point; + +struct _Point +{ + double x, y; +}; + +struct _LineState +{ + PangoUnderline underline; + PangoRectangle underline_rect; + + gboolean strikethrough; + PangoRectangle strikethrough_rect; + + int logical_rect_end; +}; + +struct _PangoRendererPrivate +{ + PangoColor color[N_RENDER_PARTS]; + gboolean color_set[N_RENDER_PARTS]; + + LineState *line_state; +}; + +static void pango_renderer_finalize (GObject *gobject); +static void pango_renderer_default_draw_glyphs (PangoRenderer *renderer, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y); +static void pango_renderer_default_draw_rectangle (PangoRenderer *renderer, + PangoRenderPart part, + int x, + int y, + int width, + int height); +static void pango_renderer_default_draw_error_underline (PangoRenderer *renderer, + int x, + int y, + int width, + int height); +static void pango_renderer_default_prepare_run (PangoRenderer *renderer, + PangoLayoutRun *run); + +static void pango_renderer_prepare_run (PangoRenderer *renderer, + PangoLayoutRun *run); + +static void +to_device (PangoMatrix *matrix, + double x, + double y, + Point *result) +{ + if (matrix) + { + result->x = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0; + result->y = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0; + } + else + { + result->x = x / PANGO_SCALE; + result->y = y / PANGO_SCALE; + } +} + +G_DEFINE_ABSTRACT_TYPE (PangoRenderer, pango_renderer, G_TYPE_OBJECT) + +static void +pango_renderer_class_init (PangoRendererClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + klass->draw_glyphs = pango_renderer_default_draw_glyphs; + klass->draw_rectangle = pango_renderer_default_draw_rectangle; + klass->draw_error_underline = pango_renderer_default_draw_error_underline; + klass->prepare_run = pango_renderer_default_prepare_run; + + gobject_class->finalize = pango_renderer_finalize; + + g_type_class_add_private (gobject_class, sizeof (PangoRendererPrivate)); +} + +static void +pango_renderer_init (PangoRenderer *renderer) +{ + renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer, + PANGO_TYPE_RENDERER, + PangoRendererPrivate); + renderer->matrix = NULL; +} + +static void +pango_renderer_finalize (GObject *gobject) +{ + PangoRenderer *renderer = PANGO_RENDERER (gobject); + + if (renderer->matrix) + pango_matrix_free (renderer->matrix); +} + +/** + * pango_renderer_draw_layout: + * @renderer: a #PangoRenderer + * @layout: a #PangoLayout + * @x: x position of left edge of baseline, in user space coordinates + * in Pango units. + * @y: x position of left edge of baseline, in user space coordinates + * in Pango units. + * + * Draws @layout with the specified #PangoRenderer. + * + * Since: 1.8 + **/ +void +pango_renderer_draw_layout (PangoRenderer *renderer, + PangoLayout *layout, + int x, + int y) +{ + PangoLayoutIter *iter; + + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); + + /* We only change the matrix if the renderer isn't already + * active. + */ + if (!renderer->active_count) + { + PangoContext *context = pango_layout_get_context (layout); + pango_renderer_set_matrix (renderer, + pango_context_get_matrix (context)); + } + + pango_renderer_activate (renderer); + + iter = pango_layout_get_iter (layout); + + do + { + PangoRectangle logical_rect; + PangoLayoutLine *line; + int 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); + + pango_renderer_draw_layout_line (renderer, + line, + x + logical_rect.x, + y + baseline); + } + while (pango_layout_iter_next_line (iter)); + + pango_layout_iter_free (iter); + + pango_renderer_deactivate (renderer); +} + +static void +draw_underline (PangoRenderer *renderer, + LineState *state) +{ + PangoRectangle *rect = &state->underline_rect; + + switch (state->underline) + { + case PANGO_UNDERLINE_NONE: + break; + case PANGO_UNDERLINE_DOUBLE: + pango_renderer_draw_rectangle (renderer, + PANGO_RENDER_PART_UNDERLINE, + rect->x, + rect->y + 2 * rect->height, + rect->width, + rect->height); + /* Fall through */ + case PANGO_UNDERLINE_SINGLE: + case PANGO_UNDERLINE_LOW: + pango_renderer_draw_rectangle (renderer, + PANGO_RENDER_PART_UNDERLINE, + rect->x, + rect->y, + rect->width, + rect->height); + break; + case PANGO_UNDERLINE_ERROR: + pango_renderer_draw_error_underline (renderer, + rect->x, + rect->y, + rect->width, + 3 * rect->height); + break; + } + + state->underline = PANGO_UNDERLINE_NONE; +} + +static void +draw_strikethrough (PangoRenderer *renderer, + LineState *state) +{ + PangoRectangle *rect = &state->strikethrough_rect; + + if (state->strikethrough) + pango_renderer_draw_rectangle (renderer, + PANGO_RENDER_PART_STRIKETHROUGH, + rect->x, + rect->y, + rect->width, + rect->height); + + state->strikethrough = FALSE; +} + +static void +handle_line_state_change (PangoRenderer *renderer, + PangoRenderPart part) +{ + LineState *state = renderer->priv->line_state; + if (!state) + return; + + if (part == PANGO_RENDER_PART_UNDERLINE && + state->underline != PANGO_UNDERLINE_NONE) + { + PangoRectangle *rect = &state->underline_rect; + + rect->width = state->logical_rect_end - rect->x; + draw_underline (renderer, state); + state->underline = renderer->underline; + rect->x = state->logical_rect_end; + } + + if (part == PANGO_RENDER_PART_STRIKETHROUGH && + state->strikethrough) + { + PangoRectangle *rect = &state->strikethrough_rect; + + rect->width = state->logical_rect_end - rect->x; + draw_underline (renderer, state); + state->underline = renderer->underline; + rect->x = state->logical_rect_end; + } +} + +static void +add_underline (PangoRenderer *renderer, + LineState *state, + PangoFontMetrics *metrics, /* NULL if no underline */ + int base_x, + int base_y, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + if (renderer->underline == PANGO_UNDERLINE_NONE) + { + draw_underline (renderer, state); + } + else + { + PangoRectangle *current_rect = &state->underline_rect; + PangoRectangle new_rect; + + int underline_thickness = pango_font_metrics_get_underline_thickness (metrics); + int underline_position = pango_font_metrics_get_underline_position (metrics); + + new_rect.x = base_x + ink_rect->x; + new_rect.width = ink_rect->width; + new_rect.height = underline_thickness; + + switch (renderer->underline) + { + case PANGO_UNDERLINE_NONE: + g_assert_not_reached (); + break; + case PANGO_UNDERLINE_SINGLE: + case PANGO_UNDERLINE_DOUBLE: + case PANGO_UNDERLINE_ERROR: + new_rect.y = base_y - underline_position; + break; + case PANGO_UNDERLINE_LOW: + new_rect.y = base_y + ink_rect->y + ink_rect->height + underline_thickness; + break; + } + + if (renderer->underline == state->underline && + new_rect.y == current_rect->y && + new_rect.height == current_rect->height) + { + current_rect->y = new_rect.y; + current_rect->width = new_rect.x + new_rect.width - current_rect->x; + current_rect->height = new_rect.height; + } + else + { + draw_underline (renderer, state); + + *current_rect = new_rect; + state->underline = renderer->underline; + } + } +} + +static void +add_strikethrough (PangoRenderer *renderer, + LineState *state, + PangoFontMetrics *metrics, /* NULL if no strikethrough */ + int base_x, + int base_y, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + if (!renderer->strikethrough) + { + draw_strikethrough (renderer, state); + } + else + { + PangoRectangle *current_rect = &state->strikethrough_rect; + PangoRectangle new_rect; + + int strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics); + int strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics); + + new_rect.x = base_x + ink_rect->x; + new_rect.width = ink_rect->width; + new_rect.y = base_y - strikethrough_position; + new_rect.height = strikethrough_thickness; + + if (state->strikethrough && + new_rect.y == current_rect->y && + new_rect.height == current_rect->height) + { + current_rect->y = new_rect.y; + current_rect->width = new_rect.x + new_rect.width - current_rect->x; + current_rect->height = new_rect.height; + } + else + { + draw_strikethrough (renderer, state); + + *current_rect = new_rect; + state->strikethrough = TRUE; + } + } +} + +static void +get_item_properties (PangoItem *item, + gint *rise, + gboolean *shape_set, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + GSList *l; + + if (rise) + *rise = 0; + + if (shape_set) + *shape_set = FALSE; + + for (l = item->analysis.extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + switch (attr->klass->type) + { + case PANGO_ATTR_SHAPE: + if (shape_set) + *shape_set = TRUE; + if (logical_rect) + *logical_rect = ((PangoAttrShape *)attr)->logical_rect; + if (ink_rect) + *ink_rect = ((PangoAttrShape *)attr)->ink_rect; + break; + + case PANGO_ATTR_RISE: + if (rise) + *rise = ((PangoAttrInt *)attr)->value; + break; + + default: + break; + } + } +} + +/** + * pango_renderer_draw_layout_line: + * @renderer: a #PangoRenderer + * @line: a #PangoLayoutLine + * @x: x position of left edge of baseline, in user space coordinates + * in Pango units. + * @y: x position of left edge of baseline, in user space coordinates + * in Pango units. + * + * Draws @line with the specified #PangoRenderer. + * + * Since: 1.8 + **/ +void +pango_renderer_draw_layout_line (PangoRenderer *renderer, + PangoLayoutLine *line, + int x, + int y) +{ + int x_off = 0; + LineState state; + GSList *l; + gboolean got_overall = FALSE; + PangoRectangle overall_rect; + + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + /* We only change the matrix if the renderer isn't already + * active. + */ + if (!renderer->active_count) + { + PangoContext *context = pango_layout_get_context (line->layout); + pango_renderer_set_matrix (renderer, + pango_context_get_matrix (context)); + } + + pango_renderer_activate (renderer); + + renderer->priv->line_state = &state; + + state.underline = PANGO_UNDERLINE_NONE; + state.strikethrough = FALSE; + + for (l = line->runs; l; l = l->next) + { + PangoFontMetrics *metrics; + gint rise; + PangoLayoutRun *run = l->data; + PangoRectangle logical_rect; + PangoRectangle ink_rect; + gboolean shape_set; + + pango_renderer_prepare_run (renderer, run); + + get_item_properties (run->item, + &rise, + &shape_set, &ink_rect, &logical_rect); + + if (!shape_set) + { + if (renderer->underline != PANGO_UNDERLINE_NONE || + renderer->strikethrough) + pango_glyph_string_extents (run->glyphs, run->item->analysis.font, + &ink_rect, &logical_rect); + else + pango_glyph_string_extents (run->glyphs, run->item->analysis.font, + NULL, &logical_rect); + } + + state.logical_rect_end = x_off + logical_rect.x + logical_rect.width; + + if (renderer->priv->color_set[PANGO_RENDER_PART_BACKGROUND]) + { + if (!got_overall) + { + pango_layout_line_get_extents (line, NULL, &overall_rect); + got_overall = TRUE; + } + + pango_renderer_draw_rectangle (renderer, + PANGO_RENDER_PART_BACKGROUND, + x + x_off + logical_rect.x, + y - rise + overall_rect.y, + logical_rect.width, + overall_rect.height); + } + + if (!shape_set) + { + pango_renderer_draw_glyphs (renderer, + run->item->analysis.font, run->glyphs, + x + x_off, y - rise); + } +#if 0 + else + { + pango_renderer_draw_shaped (renderer, + x + x_off, y - rise); + } +#endif + + if (renderer->underline != PANGO_UNDERLINE_NONE || + renderer->strikethrough) + { + metrics = pango_font_get_metrics (run->item->analysis.font, + run->item->analysis.language); + + if (renderer->underline != PANGO_UNDERLINE_NONE) + add_underline (renderer, &state,metrics, + x + x_off, y - rise, + &ink_rect, &logical_rect); + + if (renderer->strikethrough) + add_strikethrough (renderer, &state, metrics, + x + x_off, y - rise, + &ink_rect, &logical_rect); + + pango_font_metrics_unref (metrics); + } + + x_off += logical_rect.width; + } + + /* Finish off any remaining underlines + */ + draw_underline (renderer, &state); + draw_strikethrough (renderer, &state); + + pango_renderer_deactivate (renderer); + +} + +/** + * pango_renderer_draw_glyphs: + * @renderer: a #PangoRenderer + * @font: a #PangoFont + * @glyphs: a #PangoGlyphString + * @x: x position of left edge of baseline, in user space coordinates + * in Pango units. + * @y: x position of left edge of baseline, in user space coordinates + * in Pango units. + * + * Draws the glyphs in @glyphs with the specified #PangoRenderer. + * + * Since: 1.8 + **/ +void +pango_renderer_draw_glyphs (PangoRenderer *renderer, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + PANGO_RENDERER_GET_CLASS (renderer)->draw_glyphs (renderer, font, glyphs, x, y); +} + +static void +pango_renderer_default_draw_glyphs (PangoRenderer *renderer, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + int i; + int x_position = 0; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + PangoGlyphInfo *gi = &glyphs->glyphs[i]; + Point p; + + to_device (renderer->matrix, + x + x_position + gi->geometry.x_offset, + y + gi->geometry.y_offset, + &p); + + pango_renderer_draw_glyph (renderer, font, gi->glyph, p.x, p.y); + + x_position += gi->geometry.width; + } +} + +/** + * pango_renderer_draw_rectangle: + * @renderer: a #PangoRenderer + * @part: type of object this rectangle is part of + * @x: x position at which to draw rectangle, in user space coordinates in Pango units + * @y: y position at which to draw rectangle, in user space coordinates in Pango units + * @width: width of rectangle in PangoUnits in user space coordinates + * @height: height of rectangle in PangoUnits in user space coordinates + * + * Draws an axis-aligned rectangle in user space coordinates with the + * specified #PangoRenderer. + * + * Since: 1.8 + **/ +void +pango_renderer_draw_rectangle (PangoRenderer *renderer, + PangoRenderPart part, + int x, + int y, + int width, + int height) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + g_return_if_fail (IS_VALID_PART (part)); + + PANGO_RENDERER_GET_CLASS (renderer)->draw_rectangle (renderer, part, x, y, width, height); +} + +static int +compare_points (const void *a, + const void *b) +{ + const Point *pa = a; + const Point *pb = b; + + if (pa->y < pb->y) + return -1; + else if (pa->y > pb->y) + return 1; + else if (pa->x < pb->x) + return -1; + else if (pa->x > pb->x) + return 1; + else + return 0; +} + +static void +draw_rectangle (PangoRenderer *renderer, + PangoMatrix *matrix, + PangoRenderPart part, + int x, + int y, + int width, + int height) +{ + Point points[4]; + + /* Convert the points to device coordinates, and sort + * in ascending Y order. (Ordering by X for ties) + */ + to_device (matrix, x, y, &points[0]); + to_device (matrix, x + width, y, &points[1]); + to_device (matrix, x, y + height, &points[2]); + to_device (matrix, x + width, y + height, &points[3]); + + qsort (points, 4, sizeof (Point), compare_points); + + /* There are essentially three cases. (There is a fourth + * case where trapezoid B is degenerate and we just have + * two triangles, but we don't need to handle it separately.) + * + * 1 2 3 + * + * ______ /\ /\ + * / / /A \ /A \ + * / B / /____\ /____\ + * /_____/ / B / \ B \ + * /_____/ \_____\ + * \ C / \ C / + * \ / \ / + * \/ \/ + */ + if (points[0].y == points[1].y) + { + /* Case 1 (pure shear) */ + pango_renderer_draw_trapezoid (renderer, part, /* B */ + points[0].y, points[0].x, points[1].x, + points[2].y, points[2].x, points[3].x); + } + else if (points[1].x < points[2].x) + { + /* Case 2 */ + double tmp_width = ((points[2].x - points[0].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y); + double base_width = tmp_width + points[0].x - points[1].x; + + pango_renderer_draw_trapezoid (renderer, part, /* A */ + points[0].y, points[0].x, points[0].x, + points[1].y, points[1].x, points[1].x + base_width); + pango_renderer_draw_trapezoid (renderer, part, /* B */ + points[1].y, points[1].x, points[1].x + base_width, + points[2].y, points[2].x - base_width, points[2].x); + pango_renderer_draw_trapezoid (renderer, part, /* C */ + points[2].y, points[2].x - base_width, points[2].x, + points[3].y, points[3].x, points[3].x); + } + else + { + /* case 3 */ + double tmp_width = ((points[0].x - points[2].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y); + double base_width = tmp_width + points[1].x - points[0].x; + + pango_renderer_draw_trapezoid (renderer, part, /* A */ + points[0].y, points[0].x, points[0].x, + points[1].y, points[1].x - base_width, points[1].x); + pango_renderer_draw_trapezoid (renderer, part, /* B */ + points[1].y, points[1].x - base_width, points[1].x, + points[2].y, points[2].x, points[2].x + base_width); + pango_renderer_draw_trapezoid (renderer, part, /* C */ + points[2].y, points[2].x, points[2].x + base_width, + points[3].y, points[3].x, points[3].x); + } +} + +static void +pango_renderer_default_draw_rectangle (PangoRenderer *renderer, + PangoRenderPart part, + int x, + int y, + int width, + int height) +{ + draw_rectangle (renderer, renderer->matrix, part, x, y, width, height); +} + +/** + * pango_renderer_draw_error_underline: + * @renderer: a #PangoRenderer + * @x: X coordinate of underline, in Pango units in user coordinate system + * @y: Y coordinate of underline, in Pango units in user coordinate system + * @width: width of underline, in Pango units in user coordinate system + * @height: height of underline, in Pango units in user coordinate system + * + * Draw a squiggly line that approximately covers the given rectangle + * in the style of an underline used to indicate a spelling error. + * (The width of the underline is rounded to an integer number + * of up/down segments and the resulting rectangle is centered + * in the original rectangle) + * + * Since: 1.8 + **/ +void +pango_renderer_draw_error_underline (PangoRenderer *renderer, + int x, + int y, + int width, + int height) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + PANGO_RENDERER_GET_CLASS (renderer)->draw_error_underline (renderer, x, y, width, height); +} + +/* We are drawing an error underline that looks like one of: + * + * /\ /\ /\ /\ /\ - + * / \ / \ / \ / \ / \ | + * \ \ /\ \ / / \ \ /\ \ | + * \ \/B \ \/ C / \ \/B \ \ | height = HEIGHT_SQUARES * square + * \ A \ /\ A \ / \ A \ /\ A \ | + * \ \/ \ \/ \ \/ \ \ | + * \ / \ / \ / \ / | + * \/ \/ \/ \/ - + * + * |----| + * unit_width = (HEIGHT_SQUARES - 1) * square + * + * To do this conveniently, we work in a coordinate system where A,B,C + * are axis aligned rectangles. (If fonts were square, the diagrams + * would be clearer) + * + * (0,0) + * /\ /\ + * / \ / \ + * /\ /\ /\ / + * / \/ \/ \/ + * / \ /\ / + * Y axis \/ \/ + * \ /\ + * \/ \ + * \ X axis + * + * Note that the long side in this coordinate system is HEIGHT_SQUARES + 1 + * units long + * + * The diagrams above are shown with HEIGHT_SQUARES an integer, but + * that is actually incidental; the value 2.5 below seems better than + * either HEIGHT_SQUARES=3 (a little long and skinny) or + * HEIGHT_SQUARES=2 (a bit short and stubby) + */ + +#define HEIGHT_SQUARES 2.5 + +static void +get_total_matrix (PangoMatrix *total, + PangoMatrix *global, + int x, + int y, + int square) +{ + PangoMatrix local; + gdouble scale = 0.5 * square; + + /* The local matrix translates from the axis aligned coordinate system + * to the original user space coordinate system. + */ + local.xx = scale; + local.xy = - scale; + local.yx = scale; + local.yy = scale; + local.x0 = 0; + local.y0 = 0; + + *total = *global; + pango_matrix_concat (total, &local); + + total->x0 = (global->xx * x + global->xy * y) / PANGO_SCALE + global->x0; + total->y0 = (global->yx * x + global->yy * y) / PANGO_SCALE + global->y0; +} + +static void +pango_renderer_default_draw_error_underline (PangoRenderer *renderer, + int x, + int y, + int width, + int height) +{ + int square = height / HEIGHT_SQUARES; + int unit_width = (HEIGHT_SQUARES - 1) * square; + int width_units = (width + unit_width / 2) / unit_width; + static const PangoMatrix identity = PANGO_MATRIX_INIT; + const PangoMatrix *matrix; + + x += (width - width_units * unit_width) / 2; + width = width_units * unit_width; + + if (renderer->matrix) + matrix = renderer->matrix; + else + matrix = &identity; + + while (TRUE) + { + PangoMatrix total; + get_total_matrix (&total, renderer->matrix, x, y, square); + + draw_rectangle (renderer, &total, PANGO_RENDER_PART_UNDERLINE, /* A */ + 0, 0, + HEIGHT_SQUARES * 2 - 1, 1); + + if (width_units > 2) + { + draw_rectangle (renderer, &total, PANGO_RENDER_PART_UNDERLINE, /* B */ + HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 3), + 1, HEIGHT_SQUARES * 2 - 3); + width_units -= 2; + x += unit_width * 2; + } + else if (width_units == 2) + { + draw_rectangle (renderer, &total, PANGO_RENDER_PART_UNDERLINE, /* C */ + HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 2), + 1, HEIGHT_SQUARES * 2 - 2); + break; + } + else + break; + } +} + +/** + * pango_renderer_draw_trapezoid: + * @renderer: a #PangoRenderer + * @part: type of object this trapezoid is part of + * @y1: Y coordinate of top of trapezoid + * @x11: X coordinate of left end of top of trapezoid + * @x21: X coordinate of right end of top of trapezoid + * @y2: X coordinate of top of trapezoid + * @x12: X coordinate of left end of top of trapezoid + * @x22: Y coordinate of left end of top of trapezoid + * + * Draws a trapezoid with the parallel sides aligned with the X axis + * using the given #PangoRenderer; coordinates are in device space. + * + * Since: 1.8 + **/ +void +pango_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + PANGO_RENDERER_GET_CLASS (renderer)->draw_trapezoid (renderer, part, + y1, x11, x21, + y2, x12, x22); +} + +/** + * pango_renderer_draw_glyph: + * @renderer: a #PangoRenderer + * @font: a #PangoFont + * @glyph: the glyph index of a single glyph + * @x: X coordinate of left edge of baseline of glyph + * @y: Y coordinate of left edge of baseline of glyph + * + * Draws a single glyph with coordinates in device space. + * + * Since: 1.8 + **/ +void +pango_renderer_draw_glyph (PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + if (glyph == 0) /* glyph 0 never renders */ + return; + + PANGO_RENDERER_GET_CLASS (renderer)->draw_glyph (renderer, font, glyph, x, y); +} + +/** + * pango_renderer_activate: + * @renderer: a #PangoRenderer + * + * Does initial setup before rendering operations on @renderer. + * pango_renderer_deactivate() should be called when done drawing. + * Calls such as pango_renderer_draw_layout() automatically + * activate the layout before drawing on it. Calls to + * pango_renderer_activate() and pango_renderer_deactivate() can + * be nested and the renderer will only be initialized and + * deinitialized once. + * + * Since: 1.8 + **/ +void +pango_renderer_activate (PangoRenderer *renderer) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + renderer->active_count++; + if (renderer->active_count == 1) + { + if (PANGO_RENDERER_GET_CLASS (renderer)->begin) + PANGO_RENDERER_GET_CLASS (renderer)->begin (renderer); + } +} + +/** + * pango_renderer_deactivate: + * @renderer: a #PangoRenderer + * + * Cleans up after rendering operations on @renderer. See + * docs for pango_renderer_activate(). + * + * Since: 1.8 + **/ +void +pango_renderer_deactivate (PangoRenderer *renderer) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + g_return_if_fail (renderer->active_count > 0); + + if (renderer->active_count == 1) + { + if (PANGO_RENDERER_GET_CLASS (renderer)->end) + PANGO_RENDERER_GET_CLASS (renderer)->end (renderer); + } + renderer->active_count--; +} + +/** + * pango_renderer_set_color: + * @renderer: a #PangoRenderer + * @part: the part to change the color of + * @color: the new color or %NULL to unset the current color + * + * Sets the color for part of the rendering. + * + * Since: 1.8 + **/ +void +pango_renderer_set_color (PangoRenderer *renderer, + PangoRenderPart part, + PangoColor *color) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + g_return_if_fail (IS_VALID_PART (part)); + + pango_renderer_part_changed (renderer, part); + + if ((!color && !renderer->priv->color_set[part]) || + (color && renderer->priv->color_set[part] && + renderer->priv->color[part].red == color->red && + renderer->priv->color[part].green == color->green && + renderer->priv->color[part].blue == color->blue)) + return; + + if (color) + { + renderer->priv->color_set[part] = TRUE; + renderer->priv->color[part] = *color; + } + else + { + renderer->priv->color_set[part] = FALSE; + } + + if (PANGO_RENDERER_GET_CLASS (renderer)->color_set) + PANGO_RENDERER_GET_CLASS (renderer)->color_set (renderer, part, color); +} + +/** + * pango_renderer_get_color: + * @renderer: a #PangoRenderer + * @part: the part to get the color for + * + * Gets the current rendering color for the specified part. + * + * Return value: the color for the specified part, or %NULL + * if it hasn't been set and should be inherited from the + * environment. + * + * Since: 1.8 + **/ +PangoColor * +pango_renderer_get_color (PangoRenderer *renderer, + PangoRenderPart part) +{ + g_return_val_if_fail (PANGO_IS_RENDERER (renderer), NULL); + g_return_val_if_fail (IS_VALID_PART (part), NULL); + + if (renderer->priv->color_set[part]) + return &renderer->priv->color[part]; + else + return NULL; +} + +/** + * pango_renderer_part_changed: + * @renderer: a #PangoRenderer + * @part: the part for which rendering has changed. + * + * Informs Pango that the way that the renderering is done + * for @part has changed in a way that would prevent multiple + * pieces being joined together into one drawing call. For + * instance, if a subclass of #PangoRenderer was to add a stipple + * option for drawing underlines, it needs to call + * + * <informalexample><programlisting> + * pango_renderer_part_changed (render, PANGO_RENDER_PART_UNDERLINE); + * </programlisting></informalexample> + * + * When the stipple changes or underlines with different stipples + * might be joined together. Pango automatically calls this for + * changes to colors. (See pango_renderer_set_color()) + * + * Since: 1.8 + **/ +void +pango_renderer_part_changed (PangoRenderer *renderer, + PangoRenderPart part) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + g_return_if_fail (IS_VALID_PART (part)); + + handle_line_state_change (renderer, part); + + if (PANGO_RENDERER_GET_CLASS (renderer)->part_changed) + PANGO_RENDERER_GET_CLASS (renderer)->part_changed (renderer, part); +} + +/** + * pango_renderer_prepare_run: + * @renderer: a #PangoRenderer + * @run: a #PangoLayoutRun + * + * Set up the state of the PangoRenderer for rendering @run. + * + * Since: 1.8 + **/ +static void +pango_renderer_prepare_run (PangoRenderer *renderer, + PangoLayoutRun *run) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + PANGO_RENDERER_GET_CLASS (renderer)->prepare_run (renderer, run); +} + +static void +pango_renderer_default_prepare_run (PangoRenderer *renderer, + PangoLayoutRun *run) +{ + PangoColor *fg_color = NULL; + PangoColor *bg_color = NULL; + GSList *l; + + renderer->underline = PANGO_UNDERLINE_NONE; + renderer->strikethrough = FALSE; + + for (l = run->item->analysis.extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + switch (attr->klass->type) + { + case PANGO_ATTR_UNDERLINE: + renderer->underline = ((PangoAttrInt *)attr)->value; + break; + + case PANGO_ATTR_STRIKETHROUGH: + renderer->strikethrough = ((PangoAttrInt *)attr)->value; + break; + + case PANGO_ATTR_FOREGROUND: + fg_color = &((PangoAttrColor *)attr)->color; + break; + + case PANGO_ATTR_BACKGROUND: + bg_color = &((PangoAttrColor *)attr)->color; + break; + + default: + break; + } + } + + pango_renderer_set_color (renderer, PANGO_RENDER_PART_FOREGROUND, fg_color); + pango_renderer_set_color (renderer, PANGO_RENDER_PART_UNDERLINE, fg_color); + pango_renderer_set_color (renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_color); + pango_renderer_set_color (renderer, PANGO_RENDER_PART_BACKGROUND, bg_color); +} + +/** + * pango_renderer_set_matrix: + * @renderer: a #PangoRenderer + * @matrix: a #PangoMatrix, or %NULL to unset any existing matrix. + * (No matrix set is the same as setting the identity matrix.) + * + * Sets the transformation matrix that will be applied when rendering. + * + * Since: 1.8 + **/ +void +pango_renderer_set_matrix (PangoRenderer *renderer, + const PangoMatrix *matrix) +{ + g_return_if_fail (PANGO_IS_RENDERER (renderer)); + + if (renderer->matrix) + pango_matrix_free (renderer->matrix); + if (matrix) + renderer->matrix = pango_matrix_copy (matrix); + else + renderer->matrix = NULL; + +} + +/** + * pango_renderer_get_matrix: + * @renderer: a #PangoRenderer + * + * Gets the transformation matrix that will be applied when + * rendering. See pango_renderer_set_matrix(). + * + * Returns: the matrix, or %NULL if no matrix has been set + * (which is the same as the identity matrix). The returned + * matrix is owned by Pango and must not be modified or + * freed. + * + * Since: 1.8 + **/ +G_CONST_RETURN PangoMatrix * +pango_renderer_get_matrix (PangoRenderer *renderer) +{ + g_return_val_if_fail (PANGO_IS_RENDERER (renderer), NULL); + + return renderer->matrix; +} diff --git a/pango/pango-renderer.h b/pango/pango-renderer.h new file mode 100644 index 00000000..5c587f85 --- /dev/null +++ b/pango/pango-renderer.h @@ -0,0 +1,238 @@ +/* Pango + * pango-renderer.h: Base class for rendering + * + * Copyright (C) 2004, Red Hat, Inc. + * + * 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. + */ +#ifndef __PANGO_RENDERER_H_ +#define __PANGO_RENDERER_H_ + +#include <pango/pango-layout.h> + +G_BEGIN_DECLS + +#define PANGO_TYPE_RENDERER (pango_renderer_get_type()) +#define PANGO_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_RENDERER, PangoRenderer)) +#define PANGO_IS_RENDERER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_RENDERER)) +#define PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_RENDERER, PangoRendererClass)) +#define PANGO_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_RENDERER)) +#define PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_RENDERER, PangoRendererClass)) + +typedef struct _PangoRenderer PangoRenderer; +typedef struct _PangoRendererClass PangoRendererClass; +typedef struct _PangoRendererPrivate PangoRendererPrivate; + +/** + * PangoRenderPart: + * @PANGO_RENDER_PART_FOREGROUND: the text itself + * @PANGO_RENDER_PART_BACKGROUND: the area behind the text + * @PANGO_RENDER_PART_UNDERLINE: underlines + * @PANGO_RENDER_PART_STRIKETHROUGH: strikethrough lines + * + * #PangoRenderPart defines different items to render for such + * purposes as setting colors. + * + * Since: 1.8 + **/ +/* When extending, note N_RENDER_PARTS #define in pango-renderer.c */ +typedef enum +{ + PANGO_RENDER_PART_FOREGROUND, + PANGO_RENDER_PART_BACKGROUND, + PANGO_RENDER_PART_UNDERLINE, + PANGO_RENDER_PART_STRIKETHROUGH +} PangoRenderPart; + +/** + * PangoRenderer: + * @matrix: the current transformation matrix for the Renderer; may + * be %NULL, which should be treated the same as the identity matrix. + * + * #PangoRenderer is a base class for objects that are used to + * render Pango objects such as #PangoGlyphString and + * #PangoLayout. + * + * Since: 1.8 + **/ +struct _PangoRenderer +{ + /*< private >*/ + GObject parent_instance; + + PangoUnderline underline; + gboolean strikethrough; + int active_count; + + /*< public >*/ + PangoMatrix *matrix; /* May be NULL */ + + /*< private >*/ + PangoRendererPrivate *priv; +}; + +/** + * PangoRendererClass: + * @draw_glyphs: draws a #PangoGlyphString + * @draw_rectangle: draws a rectangle + * @draw_error_underline: draws a squiggly line that approximately + * covers the given rectangle in the style of an underline used to + * indicate a spelling error. + * @draw_trapezoid: draws a trapezoidal filled area + * @draw_glyph: draws a single glyph + * @part_changed: do renderer specific processing when rendering + * attributes change + * @color_set: updates the renderer when a color has changed. + * if @color is %NULL, means that the color has been unset + * @begin: Do renderer-specific initialization before drawing + * @end: Do renderer-specific cleanup after drawing + * @prepare_run: updates the renderer for a new run + * + * Class structure for #PangoRenderer. + * + * Since: 1.8 + **/ +struct _PangoRendererClass +{ + /*< private >*/ + GObjectClass parent_class; + + /* vtable - not signals */ + /*< public >*/ + + /* All of the following have default implementations + * and take as coordinates user coordinates in Pango units + */ + 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); + + /* These two must be implemented and take coordinates in + * device space as doubles. + */ + 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); + + /* Notification of change in rendering attributes + */ + void (*part_changed) (PangoRenderer *renderer, + PangoRenderPart part); + void (*color_set) (PangoRenderer *renderer, + PangoRenderPart part, + PangoColor *color); + + /* Paired around drawing operations + */ + void (*begin) (PangoRenderer *renderer); + void (*end) (PangoRenderer *renderer); + + /* Hooks into the details of layout rendering + */ + void (*prepare_run) (PangoRenderer *renderer, + PangoLayoutRun *run); + + /*< private >*/ + + /* Padding for future expansion */ + void (*_pango_reserved1) (void); + void (*_pango_reserved2) (void); + void (*_pango_reserved3) (void); + void (*_pango_reserved4) (void); +}; + +GType pango_renderer_get_type (void); + +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); +void pango_renderer_draw_rectangle (PangoRenderer *renderer, + PangoRenderPart part, + int x, + int y, + int width, + int height); +void pango_renderer_draw_error_underline (PangoRenderer *renderer, + int x, + int y, + int width, + int height); +void pango_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22); +void pango_renderer_draw_glyph (PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y); + +void pango_renderer_activate (PangoRenderer *renderer); +void pango_renderer_deactivate (PangoRenderer *renderer); + +void pango_renderer_part_changed (PangoRenderer *renderer, + PangoRenderPart part); +void pango_renderer_set_color (PangoRenderer *renderer, + PangoRenderPart part, + PangoColor *color); +PangoColor *pango_renderer_get_color (PangoRenderer *renderer, + PangoRenderPart part); + +void pango_renderer_set_matrix (PangoRenderer *renderer, + const PangoMatrix *matrix); +G_CONST_RETURN PangoMatrix *pango_renderer_get_matrix (PangoRenderer *renderer); + +G_END_DECLS + +#endif /* __PANGO_RENDERER_H_ */ + diff --git a/pango/pango.h b/pango/pango.h index 592da837..8821ed4a 100644 --- a/pango/pango.h +++ b/pango/pango.h @@ -33,6 +33,7 @@ #include <pango/pango-glyph.h> #include <pango/pango-item.h> #include <pango/pango-layout.h> +#include <pango/pango-renderer.h> #include <pango/pango-script.h> #include <pango/pango-types.h> diff --git a/pango/pangoft2-fontmap.c b/pango/pangoft2-fontmap.c index 723fb495..43607b07 100644 --- a/pango/pangoft2-fontmap.c +++ b/pango/pangoft2-fontmap.c @@ -60,6 +60,8 @@ struct _PangoFT2FontMap PangoFT2SubstituteFunc substitute_func; gpointer substitute_data; GDestroyNotify substitute_destroy; + + PangoRenderer *renderer; }; struct _PangoFT2FontMapClass @@ -101,6 +103,9 @@ pango_ft2_font_map_finalize (GObject *object) { PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (object); + if (ft2fontmap->renderer) + g_object_unref (ft2fontmap->renderer); + if (ft2fontmap->substitute_destroy) ft2fontmap->substitute_destroy (ft2fontmap->substitute_data); @@ -303,6 +308,24 @@ _pango_ft2_font_map_get_library (PangoFontMap *fontmap) return ft2fontmap->library; } + +/** + * _pango_ft2_font_map_get_renderer: + * @fontmap: a #PangoFT2Fontmap + * + * Gets the singleton PangoFT2Renderer for this fontmap. + * + * Return value: + **/ +PangoRenderer * +_pango_ft2_font_map_get_renderer (PangoFT2FontMap *ft2fontmap) +{ + if (!ft2fontmap->renderer) + ft2fontmap->renderer = g_object_new (PANGO_TYPE_FT2_RENDERER, NULL); + + return ft2fontmap->renderer; +} + static void pango_ft2_font_map_default_substitute (PangoFcFontMap *fcfontmap, FcPattern *pattern) diff --git a/pango/pangoft2-private.h b/pango/pangoft2-private.h index 6011fec2..c0b8a7e5 100644 --- a/pango/pangoft2-private.h +++ b/pango/pangoft2-private.h @@ -24,6 +24,7 @@ #define __PANGOFT2_PRIVATE_H__ #include "pangoft2.h" +#include "pango-renderer.h" #include <fontconfig/fontconfig.h> #include <fontconfig/fcfreetype.h> @@ -55,7 +56,7 @@ typedef struct _PangoFT2Font PangoFT2Font; typedef struct _PangoFT2GlyphInfo PangoFT2GlyphInfo; - +typedef struct _PangoFT2Renderer PangoFT2Renderer; struct _PangoFT2Font { @@ -111,4 +112,12 @@ void _pango_ft2_draw_error_underline (FT_Bitmap *bitmap, int width, int height); +#define PANGO_TYPE_FT2_RENDERER (pango_ft2_renderer_get_type()) +#define PANGO_FT2_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_FT2_RENDERER, PangoFT2Renderer)) +#define PANGO_IS_FT2_RENDERER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_FT2_RENDERER)) + +GType pango_ft2_renderer_get_type (void); + +PangoRenderer *_pango_ft2_font_map_get_renderer (PangoFT2FontMap *ft2fontmap); + #endif /* __PANGOFT2_PRIVATE_H__ */ diff --git a/pango/pangoft2-render.c b/pango/pangoft2-render.c index 90d1ba3a..b716c0aa 100644 --- a/pango/pangoft2-render.c +++ b/pango/pangoft2-render.c @@ -24,6 +24,218 @@ #include "pangoft2-private.h" +typedef struct _PangoFT2RendererClass PangoFT2RendererClass; + +#define PANGO_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass)) +#define PANGO_IS_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_RENDERER)) +#define PANGO_FT2_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass)) + +struct _PangoFT2Renderer +{ + PangoRenderer parent_instance; + + FT_Bitmap *bitmap; +}; + +struct _PangoFT2RendererClass +{ + PangoRendererClass parent_class; +}; + +static void pango_ft2_renderer_draw_glyph (PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y); +static void pango_ft2_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22); + +G_DEFINE_TYPE (PangoFT2Renderer, pango_ft2_renderer, PANGO_TYPE_RENDERER) + +static void +pango_ft2_renderer_init (PangoFT2Renderer *renderer) +{ +} + +static void +pango_ft2_renderer_class_init (PangoFT2RendererClass *klass) +{ + PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); + + renderer_class->draw_glyph = pango_ft2_renderer_draw_glyph; + renderer_class->draw_trapezoid = pango_ft2_renderer_draw_trapezoid; +} + +static void +pango_ft2_renderer_set_bitmap (PangoFT2Renderer *renderer, + FT_Bitmap *bitmap) +{ + renderer->bitmap = bitmap; +} + +typedef struct +{ + FT_Bitmap bitmap; + int bitmap_left; + int bitmap_top; +} PangoFT2RenderedGlyph; + +static void +pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered) +{ + g_free (rendered->bitmap.buffer); + g_free (rendered); +} + +static PangoFT2RenderedGlyph * +pango_ft2_font_render_glyph (PangoFont *font, + int glyph_index) +{ + PangoFT2RenderedGlyph *rendered; + FT_Face face; + + rendered = g_new (PangoFT2RenderedGlyph, 1); + + face = pango_ft2_font_get_face (font); + + if (face) + { + PangoFT2Font *ft2font = (PangoFT2Font *) font; + + /* Draw glyph */ + FT_Load_Glyph (face, glyph_index, ft2font->load_flags); + FT_Render_Glyph (face->glyph, + (ft2font->load_flags & FT_LOAD_TARGET_MONO ? + ft_render_mode_mono : ft_render_mode_normal)); + + rendered->bitmap = face->glyph->bitmap; + rendered->bitmap.buffer = g_memdup (face->glyph->bitmap.buffer, + face->glyph->bitmap.rows * face->glyph->bitmap.pitch); + rendered->bitmap_left = face->glyph->bitmap_left; + rendered->bitmap_top = face->glyph->bitmap_top; + } + else + g_error ("Couldn't get face for PangoFT2Face"); + + return rendered; +} + +static void +pango_ft2_renderer_draw_glyph (PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y) +{ + FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap; + PangoFT2RenderedGlyph *rendered_glyph; + gboolean add_glyph_to_cache; + guchar *src, *dest; + + int x_start, x_limit; + int y_start, y_limit; + int ixoff = floor (x + 0.5); + int iyoff = floor (y + 0.5); + int ix, iy; + + rendered_glyph = _pango_ft2_font_get_cache_glyph_data (font, glyph); + add_glyph_to_cache = FALSE; + if (rendered_glyph == NULL) + { + rendered_glyph = pango_ft2_font_render_glyph (font, glyph); + add_glyph_to_cache = TRUE; + } + + x_start = MAX (0, - (ixoff + rendered_glyph->bitmap_left)); + x_limit = MIN (rendered_glyph->bitmap.width, + bitmap->width - (ixoff + rendered_glyph->bitmap_left)); + + y_start = MAX (0, - (iyoff - rendered_glyph->bitmap_top)); + y_limit = MIN (rendered_glyph->bitmap.rows, + bitmap->rows - (iyoff - rendered_glyph->bitmap_top)); + + src = rendered_glyph->bitmap.buffer + + y_start * rendered_glyph->bitmap.pitch; + + dest = bitmap->buffer + + (y_start + iyoff - rendered_glyph->bitmap_top) * bitmap->pitch + + x_start + ixoff + rendered_glyph->bitmap_left; + + switch (rendered_glyph->bitmap.pixel_mode) + { + case ft_pixel_mode_grays: + src += x_start; + for (iy = y_start; iy < y_limit; iy++) + { + guchar *s = src; + guchar *d = dest; + + for (ix = x_start; ix < x_limit; ix++) + { + switch (*s) + { + case 0: + break; + case 0xff: + *d = 0xff; + default: + *d = MIN ((gushort) *d + (gushort) *s, 0xff); + break; + } + + s++; + d++; + } + + dest += bitmap->pitch; + src += rendered_glyph->bitmap.pitch; + } + break; + + case ft_pixel_mode_mono: + src += x_start / 8; + for (iy = y_start; iy < y_limit; iy++) + { + guchar *s = src; + guchar *d = dest; + + for (ix = x_start; ix < x_limit; ix++) + { + if ((*s) & (1 << (7 - (ix % 8)))) + *d |= 0xff; + + if ((ix % 8) == 7) + s++; + d++; + } + + dest += bitmap->pitch; + src += rendered_glyph->bitmap.pitch; + } + break; + + default: + g_warning ("pango_ft2_render: " + "Unrecognized glyph bitmap pixel mode %d\n", + rendered_glyph->bitmap.pixel_mode); + break; + } + + if (add_glyph_to_cache) + { + _pango_ft2_font_set_glyph_cache_destroy (font, + (GDestroyNotify) pango_ft2_free_rendered_glyph); + _pango_ft2_font_set_cache_glyph_data (font, + glyph, rendered_glyph); + } +} + typedef struct { double y; double x1; @@ -31,10 +243,11 @@ typedef struct { } Position; static void -draw_simple_trap (FT_Bitmap *bitmap, - Position *t, - Position *b) +draw_simple_trap (PangoRenderer *renderer, + Position *t, + Position *b) { + FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap; int iy = floor (t->y); int x1, x2, x; double dy = b->y - t->y; @@ -96,13 +309,14 @@ interpolate_position (Position *result, * line so we have to accumulate to get the final result. */ static void -draw_trap (FT_Bitmap *bitmap, - double y1, - double x11, - double x21, - double y2, - double x12, - double x22) +pango_ft2_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22) { Position pos; Position t; @@ -216,267 +430,182 @@ draw_trap (FT_Bitmap *bitmap, } } - draw_simple_trap (bitmap, &pos, &pos_next); + draw_simple_trap (renderer, &pos, &pos_next); pos = pos_next; } } -typedef struct +/** + * pango_ft2_render_layout_subpixel: + * @bitmap: a FT_Bitmap to render the layout onto + * @layout: a #PangoLayout + * @x: the X position of the left of the layout (in Pango units) + * @y: the Y position of the top of the layout (in Pango units) + * + * Render a #PangoLayout onto a FreeType2 bitmap, with he + * location specified in fixed-point pango units rather than + * pixels. (Using this will avoid extra inaccuracies from + * rounding to integer pixels multiple times, even if the + * final glyph positions are integers.) + * + * Since: 1.6 + */ +void +pango_ft2_render_layout_subpixel (FT_Bitmap *bitmap, + PangoLayout *layout, + int x, + int y) { - double x, y; -} Point; + PangoContext *context; + PangoFontMap *fontmap; + PangoRenderer *renderer; -static void -to_device (const PangoMatrix *matrix, - double x, - double y, - Point *result) -{ - result->x = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0; - result->y = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0; -} + g_return_if_fail (bitmap != NULL); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); -static int -compare_points (const void *a, - const void *b) -{ - const Point *pa = a; - const Point *pb = b; - - if (pa->y < pb->y) - return -1; - else if (pa->y > pb->y) - return 1; - else if (pa->x < pb->x) - return -1; - else if (pa->x > pb->x) - return 1; - else - return 0; + context = pango_layout_get_context (layout); + fontmap = pango_context_get_font_map (context); + renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap)); + + pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap); + + pango_renderer_draw_layout (renderer, layout, x, y); } /** - * _pango_ft2_draw_rect: - * @bitmap: a #FT_Bitmap - * @matrix: a #PangoMatrix giving the user to device transformation, - * or %NULL for the identity. - * @x: X coordinate of rectangle, in Pango units in user coordinate system - * @y: Y coordinate of rectangle, in Pango units in user coordinate system - * @width: width of rectangle, in Pango units in user coordinate system - * @height: height of rectangle, in Pango units in user coordinate system + * pango_ft2_render_layout: + * @bitmap: a FT_Bitmap to render the layout onto + * @layout: a #PangoLayout + * @x: the X position of the left of the layout (in pixels) + * @y: the Y position of the top of the layout (in pixels) * - * Render an axis aligned rectangle in user coordinates onto - * a bitmap after transformation by the given matrix. Rendering - * is done anti-aliased. - **/ -void -_pango_ft2_draw_rect (FT_Bitmap *bitmap, - const PangoMatrix *matrix, - int x, - int y, - int width, - int height) + * Render a #PangoLayout onto a FreeType2 bitmap + */ +void +pango_ft2_render_layout (FT_Bitmap *bitmap, + PangoLayout *layout, + int x, + int y) { - static const PangoMatrix identity = PANGO_MATRIX_INIT; - Point points[4]; - - if (!matrix) - matrix = &identity; - - /* Convert the points to device coordinates, and sort - * in ascending Y order. (Ordering by X for ties) - */ - to_device (matrix, x, y, &points[0]); - to_device (matrix, x + width, y, &points[1]); - to_device (matrix, x, y + height, &points[2]); - to_device (matrix, x + width, y + height, &points[3]); - - qsort (points, 4, sizeof (Point), compare_points); - - /* There are essentially three cases. (There is a fourth - * case where trapezoid B is degenerate and we just have - * two triangles, but we don't need to handle it separately.) - * - * 1 2 3 - * - * ______ /\ /\ - * / / /A \ /A \ - * / B / /____\ /____\ - * /_____/ / B / \ B \ - * /_____/ \_____\ - * \ C / \ C / - * \ / \ / - * \/ \/ - */ - if (points[0].y == points[1].y) - { - /* Case 1 (pure shear) */ - draw_trap (bitmap, /* B */ - points[0].y, points[0].x, points[1].x, - points[2].y, points[2].x, points[3].x); - } - else if (points[1].x < points[2].x) - { - /* Case 2 */ - double tmp_width = ((points[2].x - points[0].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y); - double base_width = tmp_width + points[0].x - points[1].x; - - draw_trap (bitmap, /* A */ - points[0].y, points[0].x, points[0].x, - points[1].y, points[1].x, points[1].x + base_width); - draw_trap (bitmap, - points[1].y, points[1].x, points[1].x + base_width, /* B */ - points[2].y, points[2].x - base_width, points[2].x); - draw_trap (bitmap, - points[2].y, points[2].x - base_width, points[2].x, /* C */ - points[3].y, points[3].x, points[3].x); - } - else - { - /* case 3 */ - double tmp_width = ((points[0].x - points[2].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y); - double base_width = tmp_width + points[1].x - points[0].x; - - draw_trap (bitmap, /* A */ - points[0].y, points[0].x, points[0].x, - points[1].y, points[1].x - base_width, points[1].x); - draw_trap (bitmap, - points[1].y, points[1].x - base_width, points[1].x, /* B */ - points[2].y, points[2].x, points[2].x + base_width); - draw_trap (bitmap, - points[2].y, points[2].x, points[2].x + base_width, /* C */ - points[3].y, points[3].x, points[3].x); - } + pango_ft2_render_layout_subpixel (bitmap, layout, x * PANGO_SCALE, y * PANGO_SCALE); } -/* We are drawing an error underline that looks like one of: - * - * /\ /\ /\ /\ /\ - - * / \ / \ / \ / \ / \ | - * \ \ /\ \ / / \ \ /\ \ | - * \ \/B \ \/ C / \ \/B \ \ | height = HEIGHT_SQUARES * square - * \ A \ /\ A \ / \ A \ /\ A \ | - * \ \/ \ \/ \ \/ \ \ | - * \ / \ / \ / \ / | - * \/ \/ \/ \/ - - * - * |----| - * unit_width = (HEIGHT_SQUARES - 1) * square - * - * To do this conveniently, we work in a coordinate system where A,B,C - * are axis aligned rectangles. (If fonts were square, the diagrams - * would be clearer) - * - * (0,0) - * /\ /\ - * / \ / \ - * /\ /\ /\ / - * / \/ \/ \/ - * / \ /\ / - * Y axis \/ \/ - * \ /\ - * \/ \ - * \ X axis +/** + * pango_ft2_render_layout_line_subpixel: + * @bitmap: a FT_Bitmap to render the line onto + * @line: a #PangoLayoutLine + * @x: the x position of start of string (in pango units) + * @y: the y position of baseline (in pango units) * - * Note that the long side in this coordinate system is HEIGHT_SQUARES + 1 - * units long + * Render a #PangoLayoutLine onto a FreeType2 bitmap, with he + * location specified in fixed-point pango units rather than + * pixels. (Using this will avoid extra inaccuracies from + * rounding to integer pixels multiple times, even if the + * final glyph positions are integers.) * - * The diagrams above are shown with HEIGHT_SQUARES an integer, but - * that is actually incidental; the value 2.5 below seems better than - * either HEIGHT_SQUARES=3 (a little long and skinny) or - * HEIGHT_SQUARES=2 (a bit short and stubby) + * Since: 1.6 */ - -#define HEIGHT_SQUARES 2.5 +void +pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap, + PangoLayoutLine *line, + int x, + int y) +{ + PangoContext *context; + PangoFontMap *fontmap; + PangoRenderer *renderer; -static void -get_total_matrix (PangoMatrix *total, - const PangoMatrix *global, - int x, - int y, - int square) + g_return_if_fail (bitmap != NULL); + g_return_if_fail (line != NULL); + + context = pango_layout_get_context (line->layout); + fontmap = pango_context_get_font_map (context); + renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap)); + + pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap); + + pango_renderer_draw_layout_line (renderer, line, x, y); +} + +/** + * pango_ft2_render_layout_line: + * @bitmap: a FT_Bitmap to render the line onto + * @line: a #PangoLayoutLine + * @x: the x position of start of string (in pixels) + * @y: the y position of baseline (in pixels) + * + * Render a #PangoLayoutLine onto a FreeType2 bitmap + */ +void +pango_ft2_render_layout_line (FT_Bitmap *bitmap, + PangoLayoutLine *line, + int x, + int y) { - PangoMatrix local; - gdouble scale = 0.5 * square; - - /* The local matrix translates from the axis aligned coordinate system - * to the original user space coordinate system. - */ - local.xx = scale; - local.xy = - scale; - local.yx = scale; - local.yy = scale; - local.x0 = 0; - local.y0 = 0; - - *total = *global; - pango_matrix_concat (total, &local); - - total->x0 = (global->xx * x + global->xy * y) / PANGO_SCALE + global->x0; - total->y0 = (global->yx * x + global->yy * y) / PANGO_SCALE + global->y0; + pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE); } /** - * _pango_ft2_draw_error_underline: - * @bitmap: a #FT_Bitmap - * @matrix: a #PangoMatrix giving the user to device transformation, - * or %NULL for the identity. - * @x: X coordinate of underline, in Pango units in user coordinate system - * @y: Y coordinate of underline, in Pango units in user coordinate system - * @width: width of underline, in Pango units in user coordinate system - * @height: height of underline, in Pango units in user coordinate system + * pango_ft2_render_transformed: + * @bitmap: the FreeType2 bitmap onto which to draw the string + * @font: the font in which to draw the string + * @matrix: a #PangoMatrix, or %NULL to use an identity transformation + * @glyphs: the glyph string to draw + * @x: the x position of the start of the string (in Pango + * units in user space coordinates) + * @y: the y position of the baseline (in Pango units + * in user space coordinates) + * + * Renders a #PangoGlyphString onto a FreeType2 bitmap, possibly + * transforming the layed-out coordinates through a transformation + * matrix. Note that the transformation matrix for @font is not + * changed, so to produce correct rendering results, the @font + * must have been loaded using a #PangoContext with an identical + * transformation matrix to that passed in to this function. * - * Draw a squiggly line that approximately covers the given rectangle - * in the style of an underline used to indicate a spelling error. - * (The width of the underline is rounded to an integer number - * of up/down segments and the resulting rectangle is centered - * in the original rectangle) + * Since: 1.6 **/ -void -_pango_ft2_draw_error_underline (FT_Bitmap *bitmap, - const PangoMatrix *matrix, - int x, - int y, - int width, - int height) +void +pango_ft2_render_transformed (FT_Bitmap *bitmap, + const PangoMatrix *matrix, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) { + PangoFontMap *fontmap; + PangoRenderer *renderer; - int square = height / HEIGHT_SQUARES; - int unit_width = (HEIGHT_SQUARES - 1) * square; - int width_units = (width + unit_width / 2) / unit_width; - static const PangoMatrix identity = PANGO_MATRIX_INIT; + g_return_if_fail (bitmap != NULL); + g_return_if_fail (PANGO_FT2_IS_FONT (font)); + g_return_if_fail (glyphs != NULL); - x += (width - width_units * unit_width) / 2; - width = width_units * unit_width; + fontmap = PANGO_FC_FONT (font)->fontmap; + renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap)); - if (!matrix) - matrix = &identity; - - while (TRUE) - { - PangoMatrix total; - get_total_matrix (&total, matrix, x, y, square); - - _pango_ft2_draw_rect (bitmap, &total, /* A */ - 0, 0, - HEIGHT_SQUARES * 2 - 1, 1); + pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap); + pango_renderer_set_matrix (renderer, matrix); + + pango_renderer_draw_glyphs (renderer, font, glyphs, x, y); +} - if (width_units > 2) - { - _pango_ft2_draw_rect (bitmap, &total, - HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 3), - 1, HEIGHT_SQUARES * 2 - 3); /* B */ - width_units -= 2; - x += unit_width * 2; - } - else if (width_units == 2) - { - _pango_ft2_draw_rect (bitmap, &total, - HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 2), - 1, HEIGHT_SQUARES * 2 - 2); /* C */ - break; - } - else - break; - } +/** + * pango_ft2_render: + * @bitmap: the FreeType2 bitmap onto which to draw the string + * @font: the font in which to draw the string + * @glyphs: the glyph string to draw + * @x: the x position of the start of the string (in pixels) + * @y: the y position of the baseline (in pixels) + * + * Renders a #PangoGlyphString onto a FreeType2 bitmap. + **/ +void +pango_ft2_render (FT_Bitmap *bitmap, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + pango_ft2_render_transformed (bitmap, NULL, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE); } + diff --git a/pango/pangoft2.c b/pango/pangoft2.c index 78e9fb6d..268b01dc 100644 --- a/pango/pangoft2.c +++ b/pango/pangoft2.c @@ -49,13 +49,6 @@ struct _PangoFT2FontClass PangoFcFontClass parent_class; }; -typedef struct -{ - FT_Bitmap bitmap; - int bitmap_left; - int bitmap_top; -} PangoFT2RenderedGlyph; - static void pango_ft2_font_finalize (GObject *object); static void pango_ft2_font_get_glyph_extents (PangoFont *font, @@ -72,15 +65,6 @@ static guint pango_ft2_font_real_get_glyph (PangoFcFont *font, static PangoGlyph pango_ft2_font_real_get_unknown_glyph (PangoFcFont *font, gunichar wc); -static void pango_ft2_get_item_properties (PangoItem *item, - PangoUnderline *uline, - gboolean *strikethrough, - gint *rise, - gboolean *shape_set, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); - - PangoFT2Font * _pango_ft2_font_new (PangoFT2FontMap *ft2fontmap, FcPattern *pattern) @@ -284,246 +268,6 @@ pango_ft2_font_class_init (PangoFT2FontClass *class) fc_font_class->get_unknown_glyph = pango_ft2_font_real_get_unknown_glyph; } -static void -pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered) -{ - g_free (rendered->bitmap.buffer); - g_free (rendered); -} - -static PangoFT2RenderedGlyph * -pango_ft2_font_render_glyph (PangoFont *font, - int glyph_index) -{ - PangoFT2RenderedGlyph *rendered; - FT_Face face; - - rendered = g_new (PangoFT2RenderedGlyph, 1); - - face = pango_ft2_font_get_face (font); - - if (face) - { - PangoFT2Font *ft2font = (PangoFT2Font *) font; - - /* Draw glyph */ - FT_Load_Glyph (face, glyph_index, ft2font->load_flags); - FT_Render_Glyph (face->glyph, - (ft2font->load_flags & FT_LOAD_TARGET_MONO ? - ft_render_mode_mono : ft_render_mode_normal)); - - rendered->bitmap = face->glyph->bitmap; - rendered->bitmap.buffer = g_memdup (face->glyph->bitmap.buffer, - face->glyph->bitmap.rows * face->glyph->bitmap.pitch); - rendered->bitmap_left = face->glyph->bitmap_left; - rendered->bitmap_top = face->glyph->bitmap_top; - } - else - g_error ("Couldn't get face for PangoFT2Face"); - - return rendered; -} - -static void -transform_point (const PangoMatrix *matrix, - int x, - int y, - int *x_out_pixels, - int *y_out_pixels) -{ - double x_out = (matrix->xx * x + matrix->xy * y) / PANGO_SCALE + matrix->x0; - double y_out = (matrix->yx * x + matrix->yy * y) / PANGO_SCALE + matrix->y0; - - *x_out_pixels = floor (x_out + 0.5); - *y_out_pixels = floor (y_out + 0.5); -} - -/** - * pango_ft2_render_transformed: - * @bitmap: the FreeType2 bitmap onto which to draw the string - * @font: the font in which to draw the string - * @matrix: a #PangoMatrix, or %NULL to use an identity transformation - * @glyphs: the glyph string to draw - * @x: the x position of the start of the string (in Pango - * units in user space coordinates) - * @y: the y position of the baseline (in Pango units - * in user space coordinates) - * - * Renders a #PangoGlyphString onto a FreeType2 bitmap, possibly - * transforming the layed-out coordinates through a transformation - * matrix. Note that the transformation matrix for @font is not - * changed, so to produce correct rendering results, the @font - * must have been loaded using a #PangoContext with an identical - * transformation matrix to that passed in to this function. - * - * Since: 1.6 - **/ -void -pango_ft2_render_transformed (FT_Bitmap *bitmap, - const PangoMatrix *matrix, - PangoFont *font, - PangoGlyphString *glyphs, - int x, - int y) -{ - FT_UInt glyph_index; - int i; - int x_position = 0; - int ix, iy, ixoff, iyoff, y_start, y_limit, x_start, x_limit; - PangoGlyphInfo *gi; - guchar *dest, *src; - gboolean add_glyph_to_cache; - - g_return_if_fail (bitmap != NULL); - g_return_if_fail (glyphs != NULL); - - PING (("bitmap: %dx%d@+%d+%d", bitmap->width, bitmap->rows, x, y)); - - gi = glyphs->glyphs; - for (i = 0; i < glyphs->num_glyphs; i++, gi++) - { - if (gi->glyph) - { - PangoFT2RenderedGlyph *rendered_glyph; - glyph_index = gi->glyph; - - rendered_glyph = _pango_ft2_font_get_cache_glyph_data (font, - glyph_index); - add_glyph_to_cache = FALSE; - if (rendered_glyph == NULL) - { - rendered_glyph = pango_ft2_font_render_glyph (font, glyph_index); - add_glyph_to_cache = TRUE; - } - - if (matrix) - { - transform_point (matrix, - x + x_position + gi->geometry.x_offset, - y + gi->geometry.y_offset, - &ixoff, &iyoff); - } - else - { - ixoff = PANGO_PIXELS (x + x_position + gi->geometry.x_offset); - iyoff = PANGO_PIXELS (y + gi->geometry.y_offset); - } - - x_start = MAX (0, - (ixoff + rendered_glyph->bitmap_left)); - x_limit = MIN (rendered_glyph->bitmap.width, - bitmap->width - (ixoff + rendered_glyph->bitmap_left)); - - y_start = MAX (0, - (iyoff - rendered_glyph->bitmap_top)); - y_limit = MIN (rendered_glyph->bitmap.rows, - bitmap->rows - (iyoff - rendered_glyph->bitmap_top)); - - PING (("glyph %d:%d: bitmap: %dx%d, left:%d top:%d", - i, glyph_index, - rendered_glyph->bitmap.width, rendered_glyph->bitmap.rows, - rendered_glyph->bitmap_left, rendered_glyph->bitmap_top)); - PING (("xstart:%d xlim:%d ystart:%d ylim:%d", - x_start, x_limit, y_start, y_limit)); - - src = rendered_glyph->bitmap.buffer + - y_start * rendered_glyph->bitmap.pitch; - - dest = bitmap->buffer + - (y_start + iyoff - rendered_glyph->bitmap_top) * bitmap->pitch + - x_start + ixoff + rendered_glyph->bitmap_left; - - switch (rendered_glyph->bitmap.pixel_mode) - { - case ft_pixel_mode_grays: - src += x_start; - for (iy = y_start; iy < y_limit; iy++) - { - guchar *s = src; - guchar *d = dest; - - for (ix = x_start; ix < x_limit; ix++) - { - switch (*s) - { - case 0: - break; - case 0xff: - *d = 0xff; - default: - *d = MIN ((gushort) *d + (gushort) *s, 0xff); - break; - } - - s++; - d++; - } - - dest += bitmap->pitch; - src += rendered_glyph->bitmap.pitch; - } - break; - - case ft_pixel_mode_mono: - src += x_start / 8; - for (iy = y_start; iy < y_limit; iy++) - { - guchar *s = src; - guchar *d = dest; - - for (ix = x_start; ix < x_limit; ix++) - { - if ((*s) & (1 << (7 - (ix % 8)))) - *d |= 0xff; - - if ((ix % 8) == 7) - s++; - d++; - } - - dest += bitmap->pitch; - src += rendered_glyph->bitmap.pitch; - } - break; - - default: - g_warning ("pango_ft2_render: " - "Unrecognized glyph bitmap pixel mode %d\n", - rendered_glyph->bitmap.pixel_mode); - break; - } - - if (add_glyph_to_cache) - { - _pango_ft2_font_set_glyph_cache_destroy (font, - (GDestroyNotify) pango_ft2_free_rendered_glyph); - _pango_ft2_font_set_cache_glyph_data (font, - glyph_index, rendered_glyph); - } - } - - x_position += glyphs->glyphs[i].geometry.width; - } -} - -/** - * pango_ft2_render: - * @bitmap: the FreeType2 bitmap onto which to draw the string - * @font: the font in which to draw the string - * @glyphs: the glyph string to draw - * @x: the x position of the start of the string (in pixels) - * @y: the y position of the baseline (in pixels) - * - * Renders a #PangoGlyphString onto a FreeType2 bitmap. - **/ -void -pango_ft2_render (FT_Bitmap *bitmap, - PangoFont *font, - PangoGlyphString *glyphs, - int x, - int y) -{ - pango_ft2_render_transformed (bitmap, NULL, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE); -} - static PangoFT2GlyphInfo * pango_ft2_font_get_glyph_info (PangoFont *font, PangoGlyph glyph, @@ -721,311 +465,6 @@ pango_ft2_get_unknown_glyph (PangoFont *font) return 0; } -static void -draw_underline (FT_Bitmap *bitmap, - const PangoMatrix *matrix, - PangoFontMetrics *metrics, - PangoUnderline uline, - int x, - int width, - int base_y, - int descent) -{ - int underline_thickness = pango_font_metrics_get_underline_thickness (metrics); - int underline_position = pango_font_metrics_get_underline_position (metrics); - int y_off = 0; /* Quiet GCC */ - - switch (uline) - { - case PANGO_UNDERLINE_NONE: - g_assert_not_reached(); - break; - case PANGO_UNDERLINE_SINGLE: - y_off = - underline_position; - break; - case PANGO_UNDERLINE_DOUBLE: - y_off = - underline_position; - break; - case PANGO_UNDERLINE_LOW: - y_off = underline_thickness + descent; - break; - case PANGO_UNDERLINE_ERROR: - { - _pango_ft2_draw_error_underline (bitmap, matrix, - x, - base_y - underline_position, - width, - 3 * underline_thickness); - return; - } - } - - _pango_ft2_draw_rect (bitmap, matrix, - x, - base_y + y_off, - width, - underline_thickness); - - if (uline == PANGO_UNDERLINE_DOUBLE) - { - y_off += 2 * underline_thickness; - - _pango_ft2_draw_rect (bitmap, matrix, - x, - base_y + y_off, - width, - underline_thickness); - } -} - -static void -draw_strikethrough (FT_Bitmap *bitmap, - const PangoMatrix *matrix, - PangoFontMetrics *metrics, - int x, - int width, - int base_y) -{ - int strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics); - int strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics); - - _pango_ft2_draw_rect (bitmap, matrix, - x, - base_y - strikethrough_position, - width, - strikethrough_thickness); -} - -/** - * pango_ft2_render_layout_line_subpixel: - * @bitmap: a FT_Bitmap to render the line onto - * @line: a #PangoLayoutLine - * @x: the x position of start of string (in pango units) - * @y: the y position of baseline (in pango units) - * - * Render a #PangoLayoutLine onto a FreeType2 bitmap, with he - * location specified in fixed-point pango units rather than - * pixels. (Using this will avoid extra inaccuracies from - * rounding to integer pixels multiple times, even if the - * final glyph positions are integers.) - * - * Since: 1.6 - */ -void -pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap, - PangoLayoutLine *line, - int x, - int y) -{ - GSList *tmp_list = line->runs; - PangoRectangle logical_rect; - PangoRectangle ink_rect; - int x_off = 0; - const PangoMatrix *matrix; - - matrix = pango_context_get_matrix (pango_layout_get_context (line->layout)); - - while (tmp_list) - { - PangoUnderline uline = PANGO_UNDERLINE_NONE; - gboolean strike, shape_set; - gint rise; - PangoLayoutRun *run = tmp_list->data; - - tmp_list = tmp_list->next; - - pango_ft2_get_item_properties (run->item, - &uline, &strike, &rise, - &shape_set, &ink_rect, &logical_rect); - - if (!shape_set) - { - if (uline == PANGO_UNDERLINE_NONE && !strike) - pango_glyph_string_extents (run->glyphs, run->item->analysis.font, - NULL, &logical_rect); - else - pango_glyph_string_extents (run->glyphs, run->item->analysis.font, - &ink_rect, &logical_rect); - - pango_ft2_render_transformed (bitmap, matrix, - run->item->analysis.font, run->glyphs, - x + x_off, y - rise); - - if (uline != PANGO_UNDERLINE_NONE || strike) - { - PangoFontMetrics *metrics = pango_font_get_metrics (run->item->analysis.font, - run->item->analysis.language); - - if (uline != PANGO_UNDERLINE_NONE) - draw_underline (bitmap, matrix, metrics, - uline, - x_off + ink_rect.x, - ink_rect.width, - y - rise, - ink_rect.y + ink_rect.height); - - if (strike) - draw_strikethrough (bitmap, matrix, metrics, - x_off + ink_rect.x, - ink_rect.width, - y - rise); - - pango_font_metrics_unref (metrics); - } - } - - x_off += logical_rect.width; - } -} - - -/** - * pango_ft2_render_layout_line: - * @bitmap: a FT_Bitmap to render the line onto - * @line: a #PangoLayoutLine - * @x: the x position of start of string (in pixels) - * @y: the y position of baseline (in pixels) - * - * Render a #PangoLayoutLine onto a FreeType2 bitmap - */ -void -pango_ft2_render_layout_line (FT_Bitmap *bitmap, - PangoLayoutLine *line, - int x, - int y) -{ - pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE); -} - - -/** - * pango_ft2_render_layout_subpixel: - * @bitmap: a FT_Bitmap to render the layout onto - * @layout: a #PangoLayout - * @x: the X position of the left of the layout (in Pango units) - * @y: the Y position of the top of the layout (in Pango units) - * - * Render a #PangoLayout onto a FreeType2 bitmap, with he - * location specified in fixed-point pango units rather than - * pixels. (Using this will avoid extra inaccuracies from - * rounding to integer pixels multiple times, even if the - * final glyph positions are integers.) - * - * Since: 1.6 - */ -void -pango_ft2_render_layout_subpixel (FT_Bitmap *bitmap, - PangoLayout *layout, - int x, - int y) -{ - PangoLayoutIter *iter; - - g_return_if_fail (bitmap != NULL); - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - iter = pango_layout_get_iter (layout); - - do - { - PangoRectangle logical_rect; - PangoLayoutLine *line; - int 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); - - pango_ft2_render_layout_line_subpixel (bitmap, - line, - x + logical_rect.x, - y + baseline); - } - while (pango_layout_iter_next_line (iter)); - - pango_layout_iter_free (iter); -} - -/** - * pango_ft2_render_layout: - * @bitmap: a FT_Bitmap to render the layout onto - * @layout: a #PangoLayout - * @x: the X position of the left of the layout (in pixels) - * @y: the Y position of the top of the layout (in pixels) - * - * Render a #PangoLayout onto a FreeType2 bitmap - */ -void -pango_ft2_render_layout (FT_Bitmap *bitmap, - PangoLayout *layout, - int x, - int y) -{ - pango_ft2_render_layout_subpixel (bitmap, layout, x * PANGO_SCALE, y * PANGO_SCALE); -} - -/* This utility function is duplicated here and in pango-layout.c; should it be - * public? Trouble is - what is the appropriate set of properties? - */ -static void -pango_ft2_get_item_properties (PangoItem *item, - PangoUnderline *uline, - gboolean *strikethrough, - gint *rise, - gboolean *shape_set, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) -{ - GSList *tmp_list = item->analysis.extra_attrs; - - if (strikethrough) - *strikethrough = FALSE; - - if (rise) - *rise = 0; - - if (shape_set) - *shape_set = FALSE; - - while (tmp_list) - { - PangoAttribute *attr = tmp_list->data; - - switch (attr->klass->type) - { - case PANGO_ATTR_UNDERLINE: - if (uline) - *uline = ((PangoAttrInt *)attr)->value; - break; - - case PANGO_ATTR_STRIKETHROUGH: - if (strikethrough) - *strikethrough = ((PangoAttrInt *)attr)->value; - break; - - case PANGO_ATTR_SHAPE: - if (shape_set) - *shape_set = TRUE; - if (logical_rect) - *logical_rect = ((PangoAttrShape *)attr)->logical_rect; - if (ink_rect) - *ink_rect = ((PangoAttrShape *)attr)->ink_rect; - break; - - case PANGO_ATTR_RISE: - if (rise) - *rise = ((PangoAttrInt *)attr)->value; - break; - - default: - break; - } - - tmp_list = tmp_list->next; - } -} - typedef struct { FT_Error code; @@ -1068,7 +507,6 @@ _pango_ft2_ft_strerror (FT_Error error) } } - void * _pango_ft2_font_get_cache_glyph_data (PangoFont *font, int glyph_index) diff --git a/pango/pangoxft-font.c b/pango/pangoxft-font.c index 9834ba6b..884d49a5 100644 --- a/pango/pangoxft-font.c +++ b/pango/pangoxft-font.c @@ -27,13 +27,10 @@ #include "pangoxft-private.h" #include "pangofc-private.h" -#define PANGO_XFT_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_XFT_FONT, PangoXftFont)) #define PANGO_XFT_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_XFT_FONT, PangoXftFontClass)) #define PANGO_XFT_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_XFT_FONT)) #define PANGO_XFT_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_XFT_FONT, PangoXftFontClass)) -#define PANGO_XFT_UNKNOWN_FLAG 0x10000000 - typedef struct _PangoXftFontClass PangoXftFontClass; struct _PangoXftFontClass @@ -105,11 +102,21 @@ _pango_xft_font_new (PangoXftFontMap *xftfontmap, return xfont; } -static PangoFont * -get_mini_font (PangoFont *font) +/** + * _pango_xft_font_get_mini_font: + * @xfont: a #PangoXftFont + * + * Gets the font used for drawing the digits in the + * missing-character hex squares + * + * Return value: the PangoFont used for the digits; this + * value is associated with the main font and will be freed + * along with the main font. + **/ +PangoFont * +_pango_xft_font_get_mini_font (PangoXftFont *xfont) { - PangoXftFont *xfont = (PangoXftFont *)font; - PangoFcFont *fcfont = (PangoFcFont *)font; + PangoFcFont *fcfont = (PangoFcFont *)xfont; g_assert (fcfont->fontmap); @@ -142,257 +149,15 @@ get_mini_font (PangoFont *font) } - xfont->mini_width = width; - xfont->mini_height = height; - xfont->mini_pad = MAX (height / 10, 1); + xfont->mini_width = PANGO_SCALE * width; + xfont->mini_height = PANGO_SCALE * height; + xfont->mini_pad = PANGO_SCALE * MAX (height / 10, 1); } return xfont->mini_font; } static void -draw_rectangle (Display *display, - Picture src_picture, - Picture dest_picture, - XftDraw *draw, - XftColor *color, - gint x, - gint y, - gint width, - gint height) -{ - if (draw) - { - XftDrawRect (draw, color, x, y, width, height); - } - else - { - XRenderComposite (display, PictOpOver, src_picture, None, dest_picture, - 0, 0, 0, 0, x, y, width, height); - } -} - -static void -draw_box (Display *display, - Picture src_picture, - Picture dest_picture, - XftDraw *draw, - XftColor *color, - PangoXftFont *xfont, - gint x, - gint y, - gint width, - gint height) -{ - draw_rectangle (display, src_picture, dest_picture, draw, color, - x, y, width, xfont->mini_pad); - draw_rectangle (display, src_picture, dest_picture, draw, color, - x, y + xfont->mini_pad, xfont->mini_pad, height - xfont->mini_pad * 2); - draw_rectangle (display, src_picture, dest_picture, draw, color, - x + width - xfont->mini_pad, y + xfont->mini_pad, xfont->mini_pad, height - xfont->mini_pad * 2); - draw_rectangle (display, src_picture, dest_picture, draw, color, - x, y + height - xfont->mini_pad, width, xfont->mini_pad); -} - -/** - * pango_xft_render: - * @draw: the <type>XftDraw</type> object. - * @color: the color in which to draw the string - * @font: the font in which to draw the string - * @glyphs: the glyph string to draw - * @x: the x position of start of string (in pixels) - * @y: the y position of baseline (in pixels) - * - * Renders a #PangoGlyphString onto an <type>XftDraw</type> object wrapping an X drawable. - */ -static void -pango_xft_real_render (Display *display, - Picture src_picture, - Picture dest_picture, - XftDraw *draw, - XftColor *color, - PangoFont *font, - PangoGlyphString *glyphs, - gint x, - gint y) -{ - PangoXftFont *xfont = PANGO_XFT_FONT (font); - PangoFcFont *fcfont = PANGO_FC_FONT (font); - XftFont *xft_font = xft_font_get_font (font); - int i; - int x_off = 0; -#define N_XFT_LOCAL 1024 - XftGlyphSpec xft_glyphs[N_XFT_LOCAL]; - XftCharSpec chars[6]; /* for unknown */ - int n_xft_glyph = 0; - - if (!fcfont->fontmap) /* Display closed */ - return; - -#define FLUSH_GLYPHS() G_STMT_START { \ - if (n_xft_glyph) \ - { \ - if (draw) \ - XftDrawGlyphSpec (draw, color, xft_font, xft_glyphs, n_xft_glyph); \ - else \ - XftGlyphSpecRender (display, PictOpOver, src_picture, xft_font, \ - dest_picture, 0, 0, xft_glyphs, n_xft_glyph); \ - n_xft_glyph = 0; \ - } \ - } G_STMT_END - - if (!display) - _pango_xft_font_map_get_info (fcfont->fontmap, &display, NULL); - - for (i=0; i<glyphs->num_glyphs; i++) - { - PangoGlyph glyph = glyphs->glyphs[i].glyph; - int glyph_x = x + PANGO_PIXELS (x_off + glyphs->glyphs[i].geometry.x_offset); - int glyph_y = y + PANGO_PIXELS (glyphs->glyphs[i].geometry.y_offset); - - /* Clip glyphs into the X coordinate range; we really - * want to clip glyphs with an ink rect outside the - * [0,32767] x [0,32767] rectangle but looking up - * the ink rect here would be a noticeable speed hit. - * This is close enough. - */ - if (glyph && - glyph_x >= -16384 && glyph_x <= 32767 && - glyph_y >= -16384 && glyph_y <= 32767) - { - if (glyph & PANGO_XFT_UNKNOWN_FLAG) - { - char buf[7]; - int ys[3]; - int xs[4]; - int row, col; - int cols; - - PangoFont *mini_font = get_mini_font (font); - XftFont *mini_xft = xft_font_get_font (mini_font); - - glyph &= ~PANGO_XFT_UNKNOWN_FLAG; - - ys[0] = glyph_y - xft_font->ascent + (xft_font->ascent + xft_font->descent - xfont->mini_height * 2 - xfont->mini_pad * 5) / 2; - ys[1] = ys[0] + 2 * xfont->mini_pad + xfont->mini_height; - ys[2] = ys[1] + xfont->mini_height + xfont->mini_pad; - - xs[0] = glyph_x; - xs[1] = xs[0] + 2 * xfont->mini_pad; - xs[2] = xs[1] + xfont->mini_width + xfont->mini_pad; - xs[3] = xs[2] + xfont->mini_width + xfont->mini_pad; - - if (glyph > 0xffff) - { - cols = 3; - g_snprintf (buf, sizeof(buf), "%06X", glyph); - } - else - { - cols = 2; - g_snprintf (buf, sizeof(buf), "%04X", glyph); - } - - draw_box (display, src_picture, dest_picture, draw, color, xfont, - xs[0], ys[0], - xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1), - xfont->mini_height * 2 + xfont->mini_pad * 5); - - FLUSH_GLYPHS (); - for (row = 0; row < 2; row++) - for (col = 0; col < cols; col++) - { - XftCharSpec *c = &chars[row * cols + col]; - c->ucs4 = buf[row * cols + col] & 0xff; - c->x = xs[col+1]; - c->y = ys[row+1]; - } - if (draw) - XftDrawCharSpec (draw, color, mini_xft, - chars, 2 * cols); - else - XftCharSpecRender (display, PictOpOver, src_picture, - mini_xft, dest_picture, 0, 0, - chars, 2 * cols); - } - else if (glyph) - { - if (n_xft_glyph == N_XFT_LOCAL) - FLUSH_GLYPHS (); - - xft_glyphs[n_xft_glyph].x = glyph_x; - xft_glyphs[n_xft_glyph].y = glyph_y; - xft_glyphs[n_xft_glyph].glyph = glyph; - n_xft_glyph++; - } - } - - x_off += glyphs->glyphs[i].geometry.width; - } - - FLUSH_GLYPHS (); - -#undef FLUSH_GLYPHS -} - -/** - * pango_xft_render: - * @draw: the <type>XftDraw</type> object. - * @color: the color in which to draw the string - * @font: the font in which to draw the string - * @glyphs: the glyph string to draw - * @x: the x position of start of string (in pixels) - * @y: the y position of baseline (in pixels) - * - * Renders a #PangoGlyphString onto an <type>XftDraw</type> object wrapping an X drawable. - */ -void -pango_xft_render (XftDraw *draw, - XftColor *color, - PangoFont *font, - PangoGlyphString *glyphs, - gint x, - gint y) -{ - g_return_if_fail (draw != NULL); - g_return_if_fail (color != NULL); - g_return_if_fail (PANGO_XFT_IS_FONT (font)); - g_return_if_fail (glyphs != NULL); - - pango_xft_real_render (NULL, None, None, draw, color, font, glyphs, x, y); -} - -/** - * pango_xft_picture_render: - * @display: an X display - * @src_picture: the source picture to draw the string with - * @dest_picture: the destination picture to draw the strign onto - * @font: the font in which to draw the string - * @glyphs: the glyph string to draw - * @x: the x position of start of string (in pixels) - * @y: the y position of baseline (in pixels) - * - * Renders a #PangoGlyphString onto an Xrender <type>Picture</type> object. - */ -void -pango_xft_picture_render (Display *display, - Picture src_picture, - Picture dest_picture, - PangoFont *font, - PangoGlyphString *glyphs, - gint x, - gint y) -{ - g_return_if_fail (display != NULL); - g_return_if_fail (src_picture != None); - g_return_if_fail (dest_picture != None); - g_return_if_fail (PANGO_XFT_IS_FONT (font)); - g_return_if_fail (glyphs != NULL); - - pango_xft_real_render (display, src_picture, dest_picture, NULL, NULL, font, glyphs, x, y); -} - -static void pango_xft_font_finalize (GObject *object) { PangoXftFont *xfont = (PangoXftFont *)object; @@ -427,7 +192,7 @@ get_glyph_extents_missing (PangoXftFont *xfont, gint cols = (glyph & ~PANGO_XFT_UNKNOWN_FLAG) > 0xffff ? 3 : 2; - get_mini_font (font); + _pango_xft_font_get_mini_font (xfont); if (ink_rect) { diff --git a/pango/pangoxft-fontmap.c b/pango/pangoxft-fontmap.c index 6d91ea6b..cc3f62b5 100644 --- a/pango/pangoxft-fontmap.c +++ b/pango/pangoxft-fontmap.c @@ -49,6 +49,8 @@ struct _PangoXftFontMap PangoXftSubstituteFunc substitute_func; gpointer substitute_data; GDestroyNotify substitute_destroy; + + PangoRenderer *renderer; }; struct _PangoXftFontMapClass @@ -87,6 +89,9 @@ pango_xft_font_map_finalize (GObject *object) { PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (object); + if (xftfontmap->renderer) + g_object_unref (xftfontmap->renderer); + fontmaps = g_slist_remove (fontmaps, object); if (xftfontmap->substitute_destroy) @@ -323,6 +328,24 @@ pango_xft_get_context (Display *display, return pango_fc_font_map_create_context (PANGO_FC_FONT_MAP (fontmap)); } +/** + * _pango_xft_font_map_get_renderer: + * @fontmap: a #PangoXftFontmap + * + * Gets the singleton PangoXFTRenderer for this fontmap. + * + * Return value: + **/ +PangoRenderer * +_pango_xft_font_map_get_renderer (PangoXftFontMap *xftfontmap) +{ + if (!xftfontmap->renderer) + xftfontmap->renderer = pango_xft_renderer_new (xftfontmap->display, + xftfontmap->screen); + + return xftfontmap->renderer; +} + static void pango_xft_font_map_default_substitute (PangoFcFontMap *fcfontmap, FcPattern *pattern) diff --git a/pango/pangoxft-private.h b/pango/pangoxft-private.h index cfd0b3fb..6a8a08af 100644 --- a/pango/pangoxft-private.h +++ b/pango/pangoxft-private.h @@ -22,13 +22,12 @@ #ifndef __PANGOXFT_PRIVATE_H__ #define __PANGOXFT_PRIVATE_H__ -#include <pangoxft.h> -#include <pango-ot.h> +#include "pangoxft.h" +#include "pango-renderer.h" G_BEGIN_DECLS -typedef struct _PangoXftFont PangoXftFont; -typedef struct _PangoXftFontMap PangoXftFontMap; +#define PANGO_XFT_UNKNOWN_FLAG 0x10000000 struct _PangoXftFont { @@ -49,10 +48,15 @@ struct _PangoXftFont PangoXftFont *_pango_xft_font_new (PangoXftFontMap *xftfontmap, FcPattern *pattern); + void _pango_xft_font_map_get_info (PangoFontMap *fontmap, Display **display, int *screen); +PangoRenderer *_pango_xft_font_map_get_renderer (PangoXftFontMap *xftfontmap); + +PangoFont *_pango_xft_font_get_mini_font (PangoXftFont *xfont); + G_END_DECLS #endif /* __PANGOXFT_PRIVATE_H__ */ diff --git a/pango/pangoxft-render.c b/pango/pangoxft-render.c new file mode 100644 index 00000000..145b6f59 --- /dev/null +++ b/pango/pangoxft-render.c @@ -0,0 +1,836 @@ +/* Pango + * pangoxft-render.c: Rendering routines for the Xft library + * + * Copyright (C) 2004 Red Hat Software + * + * 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 <math.h> + +#include "pangoxft-render.h" +#include "pangoxft-private.h" + +enum { + PROP_0, + PROP_DISPLAY, + PROP_SCREEN +}; + +struct _PangoXftRendererPrivate +{ + PangoColor default_color; + + Picture src_picture; + Picture dest_picture; + + XRenderPictFormat *mask_format; + + GArray *trapezoids; + PangoRenderPart trapezoid_part; + + GArray *glyphs; + PangoFont *glyph_font; +}; + +static void pango_xft_renderer_finalize (GObject *object); +static void pango_xft_renderer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +static void pango_xft_renderer_real_composite_trapezoids (PangoXftRenderer *xftrenderer, + PangoRenderPart part, + XTrapezoid *trapezoids, + int n_trapezoids); +static void pango_xft_renderer_real_composite_glyphs (PangoXftRenderer *xftrenderer, + XftFont *xft_font, + XftGlyphSpec *glyphs, + int n_glyphs); + +static void pango_xft_renderer_draw_glyphs (PangoRenderer *renderer, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y); +static void pango_xft_renderer_draw_glyph (PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y); +static void pango_xft_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22); +static void pango_xft_renderer_part_changed (PangoRenderer *renderer, + PangoRenderPart part); +static void pango_xft_renderer_end (PangoRenderer *renderer); + +static void flush_trapezoids (PangoXftRenderer *xftrenderer); +static void flush_glyphs (PangoXftRenderer *xftrenderer); + +G_DEFINE_TYPE (PangoXftRenderer, pango_xft_renderer, PANGO_TYPE_RENDERER) + +static void +pango_xft_renderer_init (PangoXftRenderer *xftrenderer) +{ + xftrenderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (xftrenderer, + PANGO_TYPE_XFT_RENDERER, + PangoXftRendererPrivate); +} + +static void +pango_xft_renderer_class_init (PangoXftRendererClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); + + klass->composite_glyphs = pango_xft_renderer_real_composite_glyphs; + klass->composite_trapezoids = pango_xft_renderer_real_composite_trapezoids; + + renderer_class->draw_glyphs = pango_xft_renderer_draw_glyphs; + renderer_class->draw_glyph = pango_xft_renderer_draw_glyph; + renderer_class->draw_trapezoid = pango_xft_renderer_draw_trapezoid; + renderer_class->part_changed = pango_xft_renderer_part_changed; + renderer_class->end = pango_xft_renderer_end; + + object_class->finalize = pango_xft_renderer_finalize; + object_class->set_property = pango_xft_renderer_set_property; + + g_object_class_install_property (object_class, PROP_DISPLAY, + g_param_spec_pointer ("display", + "Display", + "The display being rendered to", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_SCREEN, + g_param_spec_int ("screen", + "Screen", + "The screen being rendered to", + 0, G_MAXINT, 0, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (object_class, sizeof (PangoXftRendererPrivate)); +} + +static void +pango_xft_renderer_finalize (GObject *object) +{ + PangoXftRenderer *renderer = PANGO_XFT_RENDERER (object); + + if (renderer->priv->glyphs) + g_array_free (renderer->priv->glyphs, TRUE); + if (renderer->priv->trapezoids) + g_array_free (renderer->priv->trapezoids, TRUE); + + G_OBJECT_CLASS (pango_xft_renderer_parent_class)->finalize (object); +} + +static void +pango_xft_renderer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (object); + + switch (prop_id) + { + case PROP_DISPLAY: + xftrenderer->display = g_value_get_pointer (value); + /* We possibly should use ARGB format when subpixel-AA is turned + * on for the fontmap; we could discover that using the technique + * for FC_DPI in pango_fc_face_list_sizes. + */ + xftrenderer->priv->mask_format = XRenderFindStandardFormat (xftrenderer->display, + PictStandardA8); + break; + case PROP_SCREEN: + xftrenderer->screen = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pango_xft_renderer_set_pictures (PangoXftRenderer *renderer, + Picture src_picture, + Picture dest_picture) +{ + renderer->priv->src_picture = src_picture; + renderer->priv->dest_picture = dest_picture; +} + +static void +flush_glyphs (PangoXftRenderer *xftrenderer) +{ + XftFont *xft_font; + + if (!xftrenderer->priv->glyphs || + xftrenderer->priv->glyphs->len == 0) + return; + + xft_font = pango_xft_font_get_font (xftrenderer->priv->glyph_font); + + PANGO_XFT_RENDERER_GET_CLASS (xftrenderer)->composite_glyphs (xftrenderer, + xft_font, + (XftGlyphSpec *)xftrenderer->priv->glyphs->data, + xftrenderer->priv->glyphs->len); + + g_array_set_size (xftrenderer->priv->glyphs, 0); + g_object_unref (xftrenderer->priv->glyph_font); + xftrenderer->priv->glyph_font = NULL; +} + +#define MAX_GLYPHS 1024 + +static void +draw_glyph (PangoRenderer *renderer, + PangoFont *font, + FT_UInt glyph, + int x, + int y) +{ + PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer); + XftGlyphSpec gs; + int pixel_x, pixel_y; + + if (renderer->matrix) + { + pixel_x = floor (0.5 + (x * renderer->matrix->xx + y * renderer->matrix->xy) / PANGO_SCALE + renderer->matrix->x0); + pixel_y = floor (0.5 + (x * renderer->matrix->yx + y * renderer->matrix->yy) / PANGO_SCALE + renderer->matrix->y0); + } + else + { + pixel_x = PANGO_PIXELS (x); + pixel_y = PANGO_PIXELS (y); + } + + /* Clip glyphs into the X coordinate range; we really + * want to clip glyphs with an ink rect outside the + * [0,32767] x [0,32767] rectangle but looking up + * the ink rect here would be a noticeable speed hit. + * This is close enough. + */ + if (pixel_x < -32768 || pixel_x > 32767 || + pixel_y < -32768 || pixel_y > 32767) + return; + + flush_trapezoids (xftrenderer); + + if (!xftrenderer->priv->glyphs) + xftrenderer->priv->glyphs = g_array_new (FALSE, FALSE, + sizeof (XftGlyphSpec)); + + if (xftrenderer->priv->glyph_font != font) + { + flush_glyphs (xftrenderer); + + xftrenderer->priv->glyph_font = g_object_ref (font); + } + + if (xftrenderer->priv->glyphs->len == MAX_GLYPHS) + flush_glyphs (xftrenderer); + + gs.x = pixel_x; + gs.y = pixel_y; + gs.glyph = glyph; + + g_array_append_val (xftrenderer->priv->glyphs, gs); +} + +static gboolean +point_in_bounds (PangoRenderer *renderer, + gint x, + gint y) +{ + gdouble pixel_x = (x * renderer->matrix->xx + y * renderer->matrix->xy) / PANGO_SCALE + renderer->matrix->x0; + gdouble pixel_y = (x * renderer->matrix->yx + y * renderer->matrix->yy) / PANGO_SCALE + renderer->matrix->y0; + + return (pixel_x >= -32768. && pixel_x < 32768. && + pixel_y >= -32768. && pixel_y < 32768.); +} + +static gboolean +box_in_bounds (PangoRenderer *renderer, + gint x, + gint y, + gint width, + gint height) +{ + if (!renderer->matrix) + { +#define COORD_MIN (PANGO_SCALE * -16384 - PANGO_SCALE / 2) +#define COORD_MAX (PANGO_SCALE * -32767 + PANGO_SCALE / 2 - 1) + return (x >= COORD_MIN && x + width <= COORD_MAX && + y >= COORD_MIN && y + width <= COORD_MAX); +#undef COORD_MIN +#undef COORD_MAX + } + else + { + return (point_in_bounds (renderer, x, y) && + point_in_bounds (renderer, x + width, y) && + point_in_bounds (renderer, x + width, y + height) && + point_in_bounds (renderer, x, y + height)); + } +} + +static void +draw_box (PangoRenderer *renderer, + PangoXftFont *xfont, + gint x, + gint y, + gint width, + gint height) +{ + pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, + x, y, width, xfont->mini_pad); + pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, + x, y + xfont->mini_pad, xfont->mini_pad, height - xfont->mini_pad * 2); + pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, + x + width - xfont->mini_pad, y + xfont->mini_pad, xfont->mini_pad, height - xfont->mini_pad * 2); + pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, + x, y + height - xfont->mini_pad, width, xfont->mini_pad); +} + +static void +pango_xft_renderer_draw_glyphs (PangoRenderer *renderer, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + PangoXftFont *xfont = PANGO_XFT_FONT (font); + PangoFcFont *fcfont = PANGO_FC_FONT (font); + XftFont *xft_font = pango_xft_font_get_font (font); + int i; + int x_off = 0; + + if (!fcfont->fontmap) /* Display closed */ + return; + + for (i=0; i<glyphs->num_glyphs; i++) + { + PangoGlyph glyph = glyphs->glyphs[i].glyph; + int glyph_x = x + x_off + glyphs->glyphs[i].geometry.x_offset; + int glyph_y = y + glyphs->glyphs[i].geometry.y_offset; + + if (glyph) + { + if (glyph & PANGO_XFT_UNKNOWN_FLAG) + { + char buf[7]; + int ys[3]; + int xs[4]; + int row, col; + int cols; + + PangoFont *mini_font = _pango_xft_font_get_mini_font (xfont); + + glyph &= ~PANGO_XFT_UNKNOWN_FLAG; + + ys[0] = glyph_y - PANGO_SCALE * xft_font->ascent + (PANGO_SCALE * (xft_font->ascent + xft_font->descent) - xfont->mini_height * 2 - xfont->mini_pad * 5) / 2; + ys[1] = ys[0] + 2 * xfont->mini_pad + xfont->mini_height; + ys[2] = ys[1] + xfont->mini_height + xfont->mini_pad; + + xs[0] = glyph_x; + xs[1] = xs[0] + 2 * xfont->mini_pad; + xs[2] = xs[1] + xfont->mini_width + xfont->mini_pad; + xs[3] = xs[2] + xfont->mini_width + xfont->mini_pad; + + if (glyph > 0xffff) + { + cols = 3; + g_snprintf (buf, sizeof(buf), "%06X", glyph); + } + else + { + cols = 2; + g_snprintf (buf, sizeof(buf), "%04X", glyph); + } + + if (box_in_bounds (renderer, + xs[0], ys[0], + xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1), + xfont->mini_height * 2 + xfont->mini_pad * 5)) + { + draw_box (renderer, xfont, + xs[0], ys[0], + xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1), + xfont->mini_height * 2 + xfont->mini_pad * 5); + + for (row = 0; row < 2; row++) + for (col = 0; col < cols; col++) + { + draw_glyph (renderer, mini_font, + XftCharIndex (NULL, xft_font, + buf[row * cols + col] & 0xff), + xs[col+1], + ys[row+1]); + } + } + } + else if (glyph) + { + draw_glyph (renderer, font, + glyph, glyph_x, glyph_y); + } + } + + x_off += glyphs->glyphs[i].geometry.width; + } +} + +static void +pango_xft_renderer_draw_glyph (PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y) +{ + g_error ("pango_xft_renderer_draw_glyph(): should not be called\n"); +} + +static void +flush_trapezoids (PangoXftRenderer *xftrenderer) +{ + if (!xftrenderer->priv->trapezoids || + xftrenderer->priv->trapezoids->len == 0) + return; + + PANGO_XFT_RENDERER_GET_CLASS (xftrenderer)->composite_trapezoids (xftrenderer, + xftrenderer->priv->trapezoid_part, + (XTrapezoid *)xftrenderer->priv->trapezoids->data, + xftrenderer->priv->trapezoids->len); + + g_array_set_size (xftrenderer->priv->trapezoids, 0); +} + +static void +pango_xft_renderer_draw_trapezoid (PangoRenderer *renderer, + PangoRenderPart part, + double y1, + double x11, + double x21, + double y2, + double x12, + double x22) +{ + PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer); + XTrapezoid trap; + + flush_glyphs (xftrenderer); + + if (!xftrenderer->priv->trapezoids) + xftrenderer->priv->trapezoids = g_array_new (FALSE, FALSE, + sizeof (XTrapezoid)); + + if (xftrenderer->draw) + { + if (xftrenderer->priv->trapezoids->len > 0 && + xftrenderer->priv->trapezoid_part != part) + flush_trapezoids (xftrenderer); + + xftrenderer->priv->trapezoid_part = part; + } + + trap.top = XDoubleToFixed (y1); + trap.bottom = XDoubleToFixed (y2); + trap.left.p1.x = XDoubleToFixed (x11); + trap.left.p1.y = XDoubleToFixed (y1); + trap.left.p2.x = XDoubleToFixed (x12); + trap.left.p2.y = XDoubleToFixed (y2); + trap.right.p1.x = XDoubleToFixed (x21); + trap.right.p1.y = XDoubleToFixed (y1); + trap.right.p2.x = XDoubleToFixed (x22); + trap.right.p2.y = XDoubleToFixed (y2); + + g_array_append_val (xftrenderer->priv->trapezoids, trap); +} + +static void +pango_xft_renderer_part_changed (PangoRenderer *renderer, + PangoRenderPart part) +{ + PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer); + + if (part == PANGO_RENDER_PART_FOREGROUND) + flush_glyphs (xftrenderer); + + if (part == xftrenderer->priv->trapezoid_part) + flush_trapezoids (xftrenderer); +} + +static void +pango_xft_renderer_end (PangoRenderer *renderer) +{ + PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer); + + flush_glyphs (xftrenderer); + flush_trapezoids (xftrenderer); +} + +static void +pango_xft_renderer_real_composite_trapezoids (PangoXftRenderer *xftrenderer, + PangoRenderPart part, + XTrapezoid *trapezoids, + int n_trapezoids) +{ + Picture src_picture; + Picture dest_picture; + + if (!XftDefaultHasRender (xftrenderer->display)) + return; + + if (xftrenderer->priv->src_picture != None) + { + src_picture = xftrenderer->priv->src_picture; + dest_picture = xftrenderer->priv->dest_picture; + } + else + { + XftColor xft_color; + PangoColor *color = pango_renderer_get_color (PANGO_RENDERER (xftrenderer), + part); + if (!color) + color = &xftrenderer->priv->default_color; + + xft_color.color.red = color->red; + xft_color.color.green = color->green; + xft_color.color.blue = color->blue; + xft_color.color.alpha = 0xffff; + + src_picture = XftDrawSrcPicture (xftrenderer->draw, &xft_color); + dest_picture = XftDrawPicture (xftrenderer->draw); + } + + XRenderCompositeTrapezoids (xftrenderer->display, + PictOpOver, + src_picture, dest_picture, + xftrenderer->priv->mask_format, + 0, 0, + trapezoids, n_trapezoids); +} + +static void +pango_xft_renderer_real_composite_glyphs (PangoXftRenderer *xftrenderer, + XftFont *xft_font, + XftGlyphSpec *glyphs, + int n_glyphs) +{ + if (xftrenderer->priv->src_picture != None) + { + XftGlyphSpecRender (xftrenderer->display, PictOpOver, + xftrenderer->priv->src_picture, + xft_font, + xftrenderer->priv->dest_picture, 0, 0, + glyphs, n_glyphs); + } + else + { + XftColor xft_color; + PangoColor *color = pango_renderer_get_color (PANGO_RENDERER (xftrenderer), + PANGO_RENDER_PART_FOREGROUND); + if (!color) + color = &xftrenderer->priv->default_color; + + xft_color.color.red = color->red; + xft_color.color.green = color->green; + xft_color.color.blue = color->blue; + xft_color.color.alpha = 0xffff; + + XftDrawGlyphSpec (xftrenderer->draw, &xft_color, + xft_font, + glyphs, n_glyphs); + } +} + +static PangoRenderer * +get_renderer (PangoFontMap *fontmap, + XftDraw *draw, + XftColor *color) +{ + PangoRenderer *renderer; + PangoColor pango_color; + + renderer = _pango_xft_font_map_get_renderer (PANGO_XFT_FONT_MAP (fontmap)); + + pango_xft_renderer_set_draw (PANGO_XFT_RENDERER (renderer), draw); + + pango_color.red = color->color.red; + pango_color.green = color->color.green; + pango_color.blue = color->color.blue; + pango_xft_renderer_set_default_color (PANGO_XFT_RENDERER (renderer), &pango_color); + + return renderer; +} + +/** + * pango_xft_render_layout: + * @draw: an #XftDraw + * @color: the foreground color in which to draw the layout + * (may be overriden by color attributes) + * @layout: a #PangoLayout + * @x: the X position of the left of the layout (in Pango units) + * @y: the Y position of the top of the layout (in Pango units) + * + * Render a #PangoLayout onto a #XftDraw + * + * Since: 1.8 + */ +void +pango_xft_render_layout (XftDraw *draw, + XftColor *color, + PangoLayout *layout, + int x, + int y) +{ + PangoContext *context; + PangoFontMap *fontmap; + PangoRenderer *renderer; + + g_return_if_fail (draw != NULL); + g_return_if_fail (color != NULL); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); + + context = pango_layout_get_context (layout); + fontmap = pango_context_get_font_map (context); + renderer = get_renderer (fontmap, draw, color); + + pango_renderer_draw_layout (renderer, layout, x, y); +} + +/** + * pango_xft_render_layout_line: + * @draw: an #XftDraw + * @color: the foreground color in which to draw the layout line + * (may be overriden by color attributes) + * @line: a #PangoLayoutLine + * @x: the x position of start of string (in pango units) + * @y: the y position of baseline (in pango units) + * + * Render a #PangoLayoutLine onto a #XftDraw + * + * Since: 1.8 + */ +void +pango_xft_render_layout_line (XftDraw *draw, + XftColor *color, + PangoLayoutLine *line, + int x, + int y) +{ + PangoContext *context; + PangoFontMap *fontmap; + PangoRenderer *renderer; + + g_return_if_fail (draw != NULL); + g_return_if_fail (color != NULL); + g_return_if_fail (line != NULL); + + context = pango_layout_get_context (line->layout); + fontmap = pango_context_get_font_map (context); + renderer = get_renderer (fontmap, draw, color); + + pango_renderer_draw_layout_line (renderer, line, x, y); +} + +/** + * pango_xft_render_transformed: + * @draw: an #XftDraw + * @color: the color in which to draw the glyphs + * @font: the font in which to draw the string + * @matrix: a #PangoMatrix, or %NULL to use an identity transformation + * @glyphs: the glyph string to draw + * @x: the x position of the start of the string (in Pango + * units in user space coordinates) + * @y: the y position of the baseline (in Pango units + * in user space coordinates) + * + * Renders a #PangoGlyphString onto a #XftDraw, possibly + * transforming the layed-out coordinates through a transformation + * matrix. Note that the transformation matrix for @font is not + * changed, so to produce correct rendering results, the @font + * must have been loaded using a #PangoContext with an identical + * transformation matrix to that passed in to this function. + * + * Since: 1.8 + **/ +void +pango_xft_render_transformed (XftDraw *draw, + XftColor *color, + PangoMatrix *matrix, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y) +{ + PangoFontMap *fontmap; + PangoRenderer *renderer; + + g_return_if_fail (draw != NULL); + g_return_if_fail (color != NULL); + g_return_if_fail (PANGO_XFT_IS_FONT (font)); + g_return_if_fail (glyphs != NULL); + + fontmap = PANGO_FC_FONT (font)->fontmap; + renderer = get_renderer (fontmap, draw, color); + + pango_renderer_set_matrix (renderer, matrix); + + pango_renderer_draw_glyphs (renderer, font, glyphs, x, y); +} + +/** + * pango_xft_render: + * @draw: the <type>XftDraw</type> object. + * @color: the color in which to draw the string + * @font: the font in which to draw the string + * @glyphs: the glyph string to draw + * @x: the x position of start of string (in pixels) + * @y: the y position of baseline (in pixels) + * + * Renders a #PangoGlyphString onto an <type>XftDraw</type> object wrapping an X drawable. + */ +void +pango_xft_render (XftDraw *draw, + XftColor *color, + PangoFont *font, + PangoGlyphString *glyphs, + gint x, + gint y) +{ + g_return_if_fail (draw != NULL); + g_return_if_fail (color != NULL); + g_return_if_fail (PANGO_XFT_IS_FONT (font)); + g_return_if_fail (glyphs != NULL); + + pango_xft_render_transformed (draw, color, NULL, font, glyphs, + x * PANGO_SCALE, y * PANGO_SCALE); +} + +/** + * pango_xft_picture_render: + * @display: an X display + * @src_picture: the source picture to draw the string with + * @dest_picture: the destination picture to draw the strign onto + * @font: the font in which to draw the string + * @glyphs: the glyph string to draw + * @x: the x position of start of string (in pixels) + * @y: the y position of baseline (in pixels) + * + * Renders a #PangoGlyphString onto an Xrender <type>Picture</type> object. + */ +void +pango_xft_picture_render (Display *display, + Picture src_picture, + Picture dest_picture, + PangoFont *font, + PangoGlyphString *glyphs, + gint x, + gint y) +{ + PangoFontMap *fontmap; + PangoRenderer *renderer; + + g_return_if_fail (display != NULL); + g_return_if_fail (src_picture != None); + g_return_if_fail (dest_picture != None); + g_return_if_fail (PANGO_XFT_IS_FONT (font)); + g_return_if_fail (glyphs != NULL); + + fontmap = PANGO_FC_FONT (font)->fontmap; + renderer = _pango_xft_font_map_get_renderer (PANGO_XFT_FONT_MAP (fontmap)); + + pango_xft_renderer_set_pictures (PANGO_XFT_RENDERER (renderer), + src_picture, dest_picture); + pango_renderer_set_matrix (renderer, NULL); + + pango_renderer_draw_glyphs (renderer, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE); + + pango_xft_renderer_set_pictures (PANGO_XFT_RENDERER (renderer), + None, None); +} + +/** + * pango_xft_renderer_new: + * @display: an X display + * @screen: the index of the screen for @display to which rendering will be done + * + * Create a new #PangoXftRenderer to allow rendering Pango objects + * with the Xft library. + * + * Return value: the newly created #PangoXftRenderer object. Unref + * with g_object_unref() when you are finished with it. + * + * Since: 1.8 + **/ +PangoRenderer * +pango_xft_renderer_new (Display *display, + int screen) +{ + PangoXftRenderer *xftrenderer; + + xftrenderer = g_object_new (PANGO_TYPE_XFT_RENDERER, + "display", display, + "screen", screen, + NULL); + + return PANGO_RENDERER (xftrenderer); +} + +/** + * pango_xft_renderer_set_draw: + * @xftrenderer: a #PangoXftRenderer + * @draw: a #XftDraw + * + * Sets the #XftDraw object that the renderer is drawing to. + * The renderer must not be currently active. + * + * Since: 1.8 + **/ +void +pango_xft_renderer_set_draw (PangoXftRenderer *xftrenderer, + XftDraw *draw) +{ + g_return_if_fail (PANGO_IS_XFT_RENDERER (xftrenderer)); + + xftrenderer->draw = draw; +} + +/** + * pango_xft_renderer_set_default_color: + * @xftrenderer: a #XftRenderer + * @default_color: the default foreground color + * + * Sets the default foreground color for a #XftRenderer. + * + * Since: 1.8 + **/ +void +pango_xft_renderer_set_default_color (PangoXftRenderer *xftrenderer, + PangoColor *default_color) +{ + g_return_if_fail (PANGO_IS_XFT_RENDERER (xftrenderer)); + + xftrenderer->priv->default_color = *default_color; +} diff --git a/pango/pangoxft-render.h b/pango/pangoxft-render.h new file mode 100644 index 00000000..00390928 --- /dev/null +++ b/pango/pangoxft-render.h @@ -0,0 +1,142 @@ +/* Pango + * pangoxft-render.h: Rendering routines for the Xft library + * + * Copyright (C) 2004 Red Hat Software + * + * 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. + */ + +#ifndef __PANGOXFT_RENDER_H__ +#define __PANGOXFT_RENDER_H__ + +#include <pango/pango-renderer.h> + +G_BEGIN_DECLS + +#define _XFT_NO_COMPAT +#define _XFTCOMPAT_H_ +#include <X11/Xlib.h> +#include <X11/Xft/Xft.h> +#if defined(XftVersion) && XftVersion >= 20000 +#else +#error "must have Xft version 2 or newer" +#endif + +typedef struct _PangoXftRenderer PangoXftRenderer; +typedef struct _PangoXftRendererClass PangoXftRendererClass; +typedef struct _PangoXftRendererPrivate PangoXftRendererPrivate; + +#define PANGO_TYPE_XFT_RENDERER (pango_xft_renderer_get_type()) +#define PANGO_XFT_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_XFT_RENDERER, PangoXftRenderer)) +#define PANGO_IS_XFT_RENDERER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_XFT_RENDERER)) +#define PANGO_XFT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_XFT_RENDERER, PangoXftRendererClass)) +#define PANGO_IS_XFT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_XFT_RENDERER)) +#define PANGO_XFT_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_XFT_RENDERER, PangoXftRendererClass)) + +/** + * PangoXftRenderer + * + * #PangoXftRenderer is a subclass of #PangoRenderer used for rendering + * with Pango's Xft backend. It can be used directly, or it can be + * further subclassed to modify exactly how drawing of individual + * elements occurs. + * + * Since: 1.8 + */ +struct _PangoXftRenderer +{ + /*< private >*/ + PangoRenderer parent_instance; + + Display *display; + int screen; + XftDraw *draw; + + PangoXftRendererPrivate *priv; +}; + +/** + * PangoXftRendererClass + * @composite_trapezoids: draw the specified trapezoids using + * the current color and other attributes for @part + * @composite_glyphs: draw the specified glyphs using + * the current color and other attributes for @part + * + * #PangoXftRenderer is a subclass of #PangoRenderer used for rendering + * Renders a #PangoGlyphString onto an Xrender <type>Picture</type> object. + * + * Since: 1.8 + */ +struct _PangoXftRendererClass +{ + /*< private >*/ + PangoRendererClass parent_class; + + /*< public >*/ + 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); +}; + +GType pango_xft_renderer_get_type (void); + +PangoRenderer *pango_xft_renderer_new (Display *display, + int screen); +void pango_xft_renderer_set_draw (PangoXftRenderer *xftrenderer, + XftDraw *draw); +void pango_xft_renderer_set_default_color (PangoXftRenderer *xftrenderer, + PangoColor *default_color); + +void pango_xft_render (XftDraw *draw, + XftColor *color, + PangoFont *font, + PangoGlyphString *glyphs, + gint x, + gint y); +void pango_xft_picture_render (Display *display, + Picture src_picture, + Picture dest_picture, + PangoFont *font, + PangoGlyphString *glyphs, + gint x, + gint y); +void pango_xft_render_transformed (XftDraw *draw, + XftColor *color, + PangoMatrix *matrix, + PangoFont *font, + PangoGlyphString *glyphs, + int x, + int y); +void pango_xft_render_layout_line (XftDraw *draw, + XftColor *color, + PangoLayoutLine *line, + int x, + int y); +void pango_xft_render_layout (XftDraw *draw, + XftColor *color, + PangoLayout *layout, + int x, + int y); + +G_END_DECLS + +#endif /* __PANGOXFT_RENDER_H__ */ + diff --git a/pango/pangoxft.h b/pango/pangoxft.h index 3f6ecfd5..52c1d496 100644 --- a/pango/pangoxft.h +++ b/pango/pangoxft.h @@ -26,22 +26,23 @@ #include <pango/pango-context.h> #include <pango/pango-ot.h> #include <pango/pangofc-font.h> +#include <pango/pango-layout.h> +#include <pango/pangoxft-render.h> G_BEGIN_DECLS -#define _XFT_NO_COMPAT -#define _XFTCOMPAT_H_ -#include <X11/Xlib.h> -#include <X11/Xft/Xft.h> -#if defined(XftVersion) && XftVersion >= 20000 -#else -#error "must have Xft version 2 or newer" -#endif - #ifndef PANGO_DISABLE_DEPRECATED #define PANGO_RENDER_TYPE_XFT "PangoRenderXft" #endif +#define PANGO_TYPE_XFT_FONT_MAP (pango_xft_font_map_get_type ()) +#define PANGO_XFT_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_XFT_FONT_MAP, PangoXftFontMap)) +#define PANGO_XFT_IS_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_XFT_FONT_MAP)) + +typedef struct _PangoXftFontMap PangoXftFontMap; + +typedef struct _PangoXftFont PangoXftFont; + typedef void (*PangoXftSubstituteFunc) (FcPattern *pattern, gpointer data); @@ -54,20 +55,6 @@ PangoContext *pango_xft_get_context (Display *display, void pango_xft_shutdown_display (Display *display, int screen); -void pango_xft_render (XftDraw *draw, - XftColor *color, - PangoFont *font, - PangoGlyphString *glyphs, - gint x, - gint y); -void pango_xft_picture_render (Display *display, - Picture src_picture, - Picture dest_picture, - PangoFont *font, - PangoGlyphString *glyphs, - gint x, - gint y); - void pango_xft_set_default_substitute (Display *display, int screen, PangoXftSubstituteFunc func, @@ -76,6 +63,9 @@ void pango_xft_set_default_substitute (Display *display, void pango_xft_substitute_changed (Display *display, int screen); +GType pango_xft_font_map_get_type (void); + +#define PANGO_XFT_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_XFT_FONT, PangoXftFont)) #define PANGO_TYPE_XFT_FONT (pango_xft_font_get_type ()) #define PANGO_XFT_IS_FONT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_XFT_FONT)) |