📄 pangoxft-render.c
字号:
/* 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 <config.h>#include <math.h>#include "pangoxft-render.h"#include "pangoxft-private.h"enum { PROP_0, PROP_DISPLAY, PROP_SCREEN};struct _PangoXftRendererPrivate{ PangoColor default_color; guint16 alpha; 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_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 voidpango_xft_renderer_init (PangoXftRenderer *xftrenderer){ xftrenderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (xftrenderer, PANGO_TYPE_XFT_RENDERER, PangoXftRendererPrivate); xftrenderer->priv->alpha = 0xffff;}static voidpango_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_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 voidpango_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 voidpango_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 voidpango_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 voidflush_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 1024static voiddraw_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 || xftrenderer->priv->glyphs->len == MAX_GLYPHS) { flush_glyphs (xftrenderer); xftrenderer->priv->glyph_font = g_object_ref (font); } gs.x = pixel_x; gs.y = pixel_y; gs.glyph = glyph; g_array_append_val (xftrenderer->priv->glyphs, gs);}static gbooleanpoint_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 gbooleanbox_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 voiddraw_box (PangoRenderer *renderer, gint line_width, gint x, gint y, gint width, gint height){ pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, x, y, width, line_width); pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, x, y + line_width, line_width, height - line_width * 2); pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, x + width - line_width, y + line_width, line_width, height - line_width * 2); pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND, x, y + height - line_width, width, line_width);}static void_pango_xft_renderer_draw_box_glyph (PangoRenderer *renderer, PangoGlyphInfo *gi, int glyph_x, int glyph_y){ int x = glyph_x + PANGO_SCALE; int y = glyph_y - PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT - 1); int width = gi->geometry.width - PANGO_SCALE * 2; int height = PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT - 2); if (box_in_bounds (renderer, x, y, width, height)) draw_box (renderer, PANGO_SCALE, x, y, width, height);}static void_pango_xft_renderer_draw_unknown_glyph (PangoRenderer *renderer, PangoXftFont *xfont, XftFont *xft_font, PangoGlyphInfo *gi, int glyph_x, int glyph_y){ char buf[7]; int ys[3]; int xs[4]; int row, col; int cols; PangoGlyph glyph; PangoFont *mini_font = _pango_xft_font_get_mini_font (xfont); XftFont *mini_xft_font = pango_xft_font_get_font (mini_font); if (!mini_xft_font) { _pango_xft_renderer_draw_box_glyph (renderer, gi, glyph_x, glyph_y); return; } glyph = gi->glyph & ~PANGO_GLYPH_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 + PANGO_SCALE / 2) / PANGO_SCALE) / 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)) { if (xfont->mini_pad) draw_box (renderer, xfont->mini_pad, 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, mini_xft_font, buf[row * cols + col] & 0xff), xs[col+1], ys[row+1]); } }}static voidpango_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) { for (i=0; i<glyphs->num_glyphs; i++) { PangoGlyphInfo *gi = &glyphs->glyphs[i]; if (gi->glyph != PANGO_GLYPH_EMPTY) { int glyph_x = x + x_off + gi->geometry.x_offset; int glyph_y = y + gi->geometry.y_offset; _pango_xft_renderer_draw_box_glyph (renderer, gi, glyph_x, glyph_y); } x_off += gi->geometry.width; } return; } if (!fcfont->fontmap) /* Display closed */ return; for (i=0; i<glyphs->num_glyphs; i++) { PangoGlyphInfo *gi = &glyphs->glyphs[i]; if (gi->glyph != PANGO_GLYPH_EMPTY) { int glyph_x = x + x_off + gi->geometry.x_offset; int glyph_y = y + gi->geometry.y_offset; if (gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG) { _pango_xft_renderer_draw_unknown_glyph (renderer, xfont, xft_font, gi, glyph_x, glyph_y); } else { draw_glyph (renderer, font, gi->glyph, glyph_x, glyph_y); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -