📄 pangowin32.c
字号:
/* Pango * pangowin32.c: Routines for handling Windows fonts * * Copyright (C) 1999 Red Hat Software * Copyright (C) 2000 Tor Lillqvist * Copyright (C) 2001 Alexander Larsson * * 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 <string.h>#include <stdlib.h>#include <glib.h>#include "pango-impl-utils.h"#include "pangowin32.h"#include "pangowin32-private.h"#define CH_IS_UNIHAN_BMP(ch) ((ch) >= 0x3400 && (ch) <= 0x9FFF)#define CH_IS_UNIHAN(ch) (CH_IS_UNIHAN_BMP (ch) || \ ((ch) >= 0x20000 && (ch) <= 0x2A6DF) || \ ((ch) >= 0x2F800 && (ch) <= 0x2FA1F))HDC pango_win32_hdc;OSVERSIONINFO pango_win32_os_version_info;gboolean pango_win32_debug = FALSE;static void pango_win32_font_dispose (GObject *object);static void pango_win32_font_finalize (GObject *object);static gboolean pango_win32_font_real_select_font (PangoFont *font, HDC hdc);static void pango_win32_font_real_done_font (PangoFont *font);static double pango_win32_font_real_get_metrics_factor (PangoFont *font);static PangoFontDescription *pango_win32_font_describe (PangoFont *font);static PangoFontDescription *pango_win32_font_describe_absolute (PangoFont *font);static PangoCoverage *pango_win32_font_get_coverage (PangoFont *font, PangoLanguage *lang);static void pango_win32_font_calc_coverage (PangoFont *font, PangoCoverage *coverage, PangoLanguage *lang);static PangoEngineShape *pango_win32_font_find_shaper (PangoFont *font, PangoLanguage *lang, guint32 ch);static void pango_win32_font_get_glyph_extents (PangoFont *font, PangoGlyph glyph, PangoRectangle *ink_rect, PangoRectangle *logical_rect);static PangoFontMetrics * pango_win32_font_get_metrics (PangoFont *font, PangoLanguage *lang);static PangoFontMap * pango_win32_font_get_font_map (PangoFont *font);static gboolean pango_win32_font_real_select_font (PangoFont *font, HDC hdc);static void pango_win32_font_real_done_font (PangoFont *font);static double pango_win32_font_real_get_metrics_factor (PangoFont *font);static HFONT pango_win32_get_hfont (PangoFont *font);static void pango_win32_get_item_properties (PangoItem *item, PangoUnderline *uline, PangoAttrColor *fg_color, gboolean *fg_set, PangoAttrColor *bg_color, gboolean *bg_set);static HFONTpango_win32_get_hfont (PangoFont *font){ PangoWin32Font *win32font = (PangoWin32Font *)font; PangoWin32FontCache *cache; TEXTMETRIC tm; if (!win32font) return NULL; if (!win32font->hfont) { cache = pango_win32_font_map_get_font_cache (win32font->fontmap); win32font->hfont = pango_win32_font_cache_load (cache, &win32font->logfont); if (!win32font->hfont) { gchar *face_utf8 = g_locale_to_utf8 (win32font->logfont.lfFaceName, -1, NULL, NULL, NULL); g_warning ("Cannot load font '%s\n", face_utf8); g_free (face_utf8); return NULL; } SelectObject (pango_win32_hdc, win32font->hfont); GetTextMetrics (pango_win32_hdc, &tm); win32font->tm_overhang = tm.tmOverhang; win32font->tm_descent = tm.tmDescent; win32font->tm_ascent = tm.tmAscent; } return win32font->hfont;}/** * pango_win32_get_context: * * Retrieves a #PangoContext appropriate for rendering with Windows fonts. * * Return value: the new #PangoContext **/PangoContext *pango_win32_get_context (void){ PangoContext *result; result = pango_context_new (); pango_context_set_font_map (result, pango_win32_font_map_for_display ()); return result;}G_DEFINE_TYPE (PangoWin32Font, pango_win32_font, PANGO_TYPE_FONT)static voidpango_win32_font_init (PangoWin32Font *win32font){ win32font->size = -1; win32font->metrics_by_lang = NULL; win32font->glyph_info = g_hash_table_new_full (NULL, NULL, NULL, g_free);}/** * pango_win32_get_dc: * * Obtains a handle to the Windows device context that is used by Pango. * * Return value: A handle to the Windows device context that is used by Pango. **/HDCpango_win32_get_dc (void){ if (pango_win32_hdc == NULL) { pango_win32_hdc = CreateDC ("DISPLAY", NULL, NULL, NULL); memset (&pango_win32_os_version_info, 0, sizeof (pango_win32_os_version_info)); pango_win32_os_version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx (&pango_win32_os_version_info); /* Also do some generic pangowin32 initialisations... this function * is a suitable place for those as it is called from a couple * of class_init functions. */#ifdef PANGO_WIN32_DEBUGGING if (getenv ("PANGO_WIN32_DEBUG") != NULL) pango_win32_debug = TRUE;#endif } return pango_win32_hdc;}/** * pango_win32_get_debug_flag: * * Returns whether debugging is turned on. * * Return value: %TRUE if debugging is turned on. * * Since: 1.2 */gbooleanpango_win32_get_debug_flag (void){ return pango_win32_debug;}static voidpango_win32_font_class_init (PangoWin32FontClass *class){ GObjectClass *object_class = G_OBJECT_CLASS (class); PangoFontClass *font_class = PANGO_FONT_CLASS (class); object_class->finalize = pango_win32_font_finalize; object_class->dispose = pango_win32_font_dispose; font_class->describe = pango_win32_font_describe; font_class->describe_absolute = pango_win32_font_describe_absolute; font_class->get_coverage = pango_win32_font_get_coverage; font_class->find_shaper = pango_win32_font_find_shaper; font_class->get_glyph_extents = pango_win32_font_get_glyph_extents; font_class->get_metrics = pango_win32_font_get_metrics; font_class->get_font_map = pango_win32_font_get_font_map; class->select_font = pango_win32_font_real_select_font; class->done_font = pango_win32_font_real_done_font; class->get_metrics_factor = pango_win32_font_real_get_metrics_factor; pango_win32_get_dc ();}PangoWin32Font *pango_win32_font_new (PangoFontMap *fontmap, const LOGFONT *lfp, int size){ PangoWin32Font *result; g_return_val_if_fail (fontmap != NULL, NULL); g_return_val_if_fail (lfp != NULL, NULL); result = (PangoWin32Font *)g_object_new (PANGO_TYPE_WIN32_FONT, NULL); result->fontmap = fontmap; g_object_ref (fontmap); result->size = size; pango_win32_make_matching_logfont (fontmap, lfp, size, &result->logfont); return result;}/** * pango_win32_render: * @hdc: the device context * @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) * * Render a #PangoGlyphString onto a Windows DC */voidpango_win32_render (HDC hdc, PangoFont *font, PangoGlyphString *glyphs, int x, int y){ HFONT hfont, old_hfont = NULL; int i, j, num_valid_glyphs; guint16 *glyph_indexes; gint *dX; gint this_x; PangoGlyphUnit start_x_offset, x_offset, next_x_offset, cur_y_offset; g_return_if_fail (glyphs != NULL);#ifdef PANGO_WIN32_DEBUGGING if (pango_win32_debug) { PING (("num_glyphs:%d", glyphs->num_glyphs)); for (i = 0; i < glyphs->num_glyphs; i++) { g_print (" %d:%d", glyphs->glyphs[i].glyph, glyphs->glyphs[i].geometry.width); if (glyphs->glyphs[i].geometry.x_offset != 0 || glyphs->glyphs[i].geometry.y_offset != 0) g_print (":%d,%d", glyphs->glyphs[i].geometry.x_offset, glyphs->glyphs[i].geometry.y_offset); } g_print ("\n"); }#endif if (glyphs->num_glyphs == 0) return; hfont = pango_win32_get_hfont (font); if (!hfont) return; old_hfont = SelectObject (hdc, hfont); glyph_indexes = g_new (guint16, glyphs->num_glyphs); dX = g_new (INT, glyphs->num_glyphs); /* Render glyphs using one ExtTextOutW() call for each run of glyphs * that have the same y offset. The big majoroty of glyphs will have * y offset of zero, so in general, the whole glyph string will be * rendered by one call to ExtTextOutW(). * * In order to minimize buildup of rounding errors, we keep track of * where the glyphs should be rendered in PangoGlyphUnits, and round * to pixels separately for each glyph, */ i = 0; /* Outer loop through all glyphs in string */ while (i < glyphs->num_glyphs) { cur_y_offset = glyphs->glyphs[i].geometry.y_offset; num_valid_glyphs = 0; x_offset = 0; start_x_offset = glyphs->glyphs[i].geometry.x_offset; this_x = PANGO_PIXELS (start_x_offset); /* Inner loop through glyphs with the same y offset, or code * point zero (just spacing). */ while (i < glyphs->num_glyphs && (glyphs->glyphs[i].glyph == PANGO_GLYPH_EMPTY || cur_y_offset == glyphs->glyphs[i].geometry.y_offset)) { if (glyphs->glyphs[i].glyph == PANGO_GLYPH_EMPTY) { /* PANGO_GLYPH_EMPTY glyphs should not be rendered, but their * indicated width (set up by PangoLayout) should be taken * into account. */ /* If the string starts with spacing, must shift the * starting point for the glyphs actually rendered. For * spacing in the middle of the glyph string, add to the dX * of the previous glyph to be rendered. */ if (num_valid_glyphs == 0) start_x_offset += glyphs->glyphs[i].geometry.width; else { x_offset += glyphs->glyphs[i].geometry.width; dX[num_valid_glyphs-1] = PANGO_PIXELS (x_offset) - this_x; } } else { if (glyphs->glyphs[i].glyph & PANGO_GLYPH_UNKNOWN_FLAG) { /* Glyph index is actually the char value that doesn't * have any glyph (ORed with the flag). We should really * do the same that pango_xft_real_render() does: render * a box with the char value in hex inside it in a tiny * font. Later. For now, use the TrueType invalid glyph * at 0. */ glyph_indexes[num_valid_glyphs] = 0; } else glyph_indexes[num_valid_glyphs] = glyphs->glyphs[i].glyph; x_offset += glyphs->glyphs[i].geometry.width; /* If the next glyph has an X offset, take that into consideration now */ if (i < glyphs->num_glyphs - 1) next_x_offset = glyphs->glyphs[i+1].geometry.x_offset; else next_x_offset = 0; dX[num_valid_glyphs] = PANGO_PIXELS (x_offset + next_x_offset) - this_x; /* Prepare for next glyph */ this_x += dX[num_valid_glyphs]; num_valid_glyphs++; } i++; }#ifdef PANGO_WIN32_DEBUGGING if (pango_win32_debug) { g_print ("ExtTextOutW at %d,%d deltas:", x + PANGO_PIXELS (start_x_offset), y + PANGO_PIXELS (cur_y_offset)); for (j = 0; j < num_valid_glyphs; j++) g_print (" %d", dX[j]); g_print ("\n"); }#endif ExtTextOutW (hdc, x + PANGO_PIXELS (start_x_offset), y + PANGO_PIXELS (cur_y_offset), ETO_GLYPH_INDEX, NULL, glyph_indexes, num_valid_glyphs, dX); x += this_x; } SelectObject (hdc, old_hfont); /* restore */ g_free (glyph_indexes); g_free (dX);}/** * pango_win32_render_transformed: * @hdc: a windows device context * @matrix: a #PangoMatrix, or %NULL to use an identity transformation * @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 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 windows DC, 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. **/voidpango_win32_render_transformed (HDC hdc, const PangoMatrix *matrix, PangoFont *font, PangoGlyphString *glyphs, int x, int y){ XFORM xForm; XFORM xFormPrev = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; int mode = GetGraphicsMode (hdc); if (!SetGraphicsMode (hdc, GM_ADVANCED)) g_warning ("SetGraphicsMode() failed"); else if (!GetWorldTransform (hdc, &xFormPrev)) g_warning ("GetWorldTransform() failed"); else if (matrix) { xForm.eM11 = matrix->xx; xForm.eM12 = matrix->yx; xForm.eM21 = matrix->xy; xForm.eM22 = matrix->yy; xForm.eDx = matrix->x0; xForm.eDy = matrix->y0; if (!SetWorldTransform (hdc, &xForm)) g_warning ("GetWorldTransform() failed"); } pango_win32_render (hdc, font, glyphs, x/PANGO_SCALE, y/PANGO_SCALE); /* restore */ SetWorldTransform (hdc, &xFormPrev); SetGraphicsMode (hdc, mode);}static voidpango_win32_font_get_glyph_extents (PangoFont *font, PangoGlyph glyph, PangoRectangle *ink_rect, PangoRectangle *logical_rect){ PangoWin32Font *win32font = (PangoWin32Font *)font; guint16 glyph_index = glyph; GLYPHMETRICS gm; guint32 res; HFONT hfont; MAT2 m = {{0,1}, {0,0}, {0,0}, {0,1}}; PangoWin32GlyphInfo *info; if (glyph == PANGO_GLYPH_EMPTY) { if (ink_rect) ink_rect->x = ink_rect->width = ink_rect->y = ink_rect->height = 0; if (logical_rect) logical_rect->x = logical_rect->width = logical_rect->y = logical_rect->height = 0; return; } if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) glyph_index = glyph = 0; info = g_hash_table_lookup (win32font->glyph_info, GUINT_TO_POINTER (glyph)); if (!info) { info = g_new0 (PangoWin32GlyphInfo, 1); memset (&gm, 0, sizeof (gm)); hfont = pango_win32_get_hfont (font); SelectObject (pango_win32_hdc, hfont); /* FIXME: (Alex) This constant reuse of pango_win32_hdc is not thread-safe */ res = GetGlyphOutlineA (pango_win32_hdc, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &m); if (res == GDI_ERROR) { gchar *error = g_win32_error_message (GetLastError ()); g_warning ("GetGlyphOutline(%04X) failed: %s\n", glyph_index, error); g_free (error); /* Don't just return now, use the still zeroed out gm */ } info->ink_rect.x = PANGO_SCALE * gm.gmptGlyphOrigin.x; info->ink_rect.width = PANGO_SCALE * gm.gmBlackBoxX; info->ink_rect.y = - PANGO_SCALE * gm.gmptGlyphOrigin.y; info->ink_rect.height = PANGO_SCALE * gm.gmBlackBoxY; info->logical_rect.x = 0; info->logical_rect.width = PANGO_SCALE * gm.gmCellIncX; info->logical_rect.y = - PANGO_SCALE * win32font->tm_ascent; info->logical_rect.height = PANGO_SCALE * (win32font->tm_ascent + win32font->tm_descent); g_hash_table_insert (win32font->glyph_info, GUINT_TO_POINTER(glyph), info); } if (ink_rect) *ink_rect = info->ink_rect; if (logical_rect) *logical_rect = info->logical_rect;}static intmax_glyph_width (PangoLayout *layout){ int max_width = 0; GSList *l, *r; for (l = pango_layout_get_lines_readonly (layout); l; l = l->next) { PangoLayoutLine *line = l->data; for (r = line->runs; r; r = r->next) { PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs; int i; for (i = 0; i < glyphs->num_glyphs; i++) if (glyphs->glyphs[i].geometry.width > max_width) max_width = glyphs->glyphs[i].geometry.width; } } return max_width;}static PangoFontMetrics *pango_win32_font_get_metrics (PangoFont *font, PangoLanguage *language){ PangoWin32MetricsInfo *info = NULL; /* Quiet gcc */ PangoWin32Font *win32font = (PangoWin32Font *)font; GSList *tmp_list; const char *sample_str = pango_language_get_sample_string (language); tmp_list = win32font->metrics_by_lang; while (tmp_list) { info = tmp_list->data; if (info->sample_str == sample_str) /* We _don't_ need strcmp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -