📄 cairo-win32-font.c
字号:
if (!GetOutlineTextMetrics (hdc, otm_size, otm)) { _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics"); free (otm); return NULL; } scaled_font->em_square = otm->otmEMSquare; free (otm); logfont = scaled_font->logfont; logfont.lfHeight = -scaled_font->em_square; logfont.lfWidth = 0; logfont.lfEscapement = 0; logfont.lfOrientation = 0; logfont.lfQuality = scaled_font->quality; scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont); if (!scaled_font->unscaled_hfont) { _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:CreateIndirect"); return NULL; } } return scaled_font->unscaled_hfont;}static cairo_status_t_cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font, HDC hdc){ cairo_status_t status; HFONT hfont; HFONT old_hfont = NULL; hfont = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc); if (!hfont) return CAIRO_STATUS_NO_MEMORY; old_hfont = SelectObject (hdc, hfont); if (!old_hfont) return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font"); status = _win32_scaled_font_set_identity_transform (hdc); if (status) { SelectObject (hdc, old_hfont); return status; } SetMapMode (hdc, MM_TEXT); return CAIRO_STATUS_SUCCESS;}static void_cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font){}/* implement the font backend interface */static cairo_status_t_cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, const cairo_font_options_t *options, cairo_scaled_font_t **scaled_font_out){ LOGFONTW logfont; cairo_scaled_font_t *scaled_font; uint16_t *face_name; int face_name_len; cairo_status_t status; status = _cairo_utf8_to_utf16 (toy_face->family, -1, &face_name, &face_name_len); if (status) return status; if (face_name_len > LF_FACESIZE - 1) { free (face_name); return CAIRO_STATUS_INVALID_STRING; } memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1)); free (face_name); logfont.lfHeight = 0; /* filled in later */ logfont.lfWidth = 0; /* filled in later */ logfont.lfEscapement = 0; /* filled in later */ logfont.lfOrientation = 0; /* filled in later */ switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_NORMAL: default: logfont.lfWeight = FW_NORMAL; break; case CAIRO_FONT_WEIGHT_BOLD: logfont.lfWeight = FW_BOLD; break; } switch (toy_face->slant) { case CAIRO_FONT_SLANT_NORMAL: default: logfont.lfItalic = FALSE; break; case CAIRO_FONT_SLANT_ITALIC: case CAIRO_FONT_SLANT_OBLIQUE: logfont.lfItalic = TRUE; break; } logfont.lfUnderline = FALSE; logfont.lfStrikeOut = FALSE; /* The docs for LOGFONT discourage using this, since the * interpretation is locale-specific, but it's not clear what * would be a better alternative. */ logfont.lfCharSet = DEFAULT_CHARSET; logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */ logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; if (!logfont.lfFaceName) return CAIRO_STATUS_NO_MEMORY; scaled_font = _win32_scaled_font_create (&logfont, NULL, &toy_face->base, font_matrix, ctm, options); if (!scaled_font) return CAIRO_STATUS_NO_MEMORY; *scaled_font_out = scaled_font; return CAIRO_STATUS_SUCCESS;}static void_cairo_win32_scaled_font_fini (void *abstract_font){ cairo_win32_scaled_font_t *scaled_font = abstract_font; if (scaled_font == NULL) return; if (scaled_font->scaled_hfont && scaled_font->delete_scaled_hfont) DeleteObject (scaled_font->scaled_hfont); if (scaled_font->unscaled_hfont) DeleteObject (scaled_font->unscaled_hfont);}static cairo_int_status_t_cairo_win32_scaled_font_text_to_glyphs (void *abstract_font, double x, double y, const char *utf8, cairo_glyph_t **glyphs, int *num_glyphs){ cairo_win32_scaled_font_t *scaled_font = abstract_font; uint16_t *utf16; int n16; GCP_RESULTSW gcp_results; unsigned int buffer_size, i; WCHAR *glyph_indices = NULL; int *dx = NULL; cairo_status_t status = CAIRO_STATUS_SUCCESS; double x_pos, y_pos; double x_incr, y_incr; HDC hdc = NULL; /* Compute a vector in user space along the baseline of length one logical space unit */ x_incr = 1; y_incr = 0; cairo_matrix_transform_distance (&scaled_font->base.font_matrix, &x_incr, &y_incr); x_incr /= scaled_font->logical_scale; y_incr /= scaled_font->logical_scale; status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16); if (status) return status; gcp_results.lStructSize = sizeof (GCP_RESULTS); gcp_results.lpOutString = NULL; gcp_results.lpOrder = NULL; gcp_results.lpCaretPos = NULL; gcp_results.lpClass = NULL; buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */ if (buffer_size > INT_MAX) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL1; } hdc = _get_global_font_dc (); if (!hdc) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL1; } status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); if (status) goto FAIL1; while (TRUE) { if (glyph_indices) { free (glyph_indices); glyph_indices = NULL; } if (dx) { free (dx); dx = NULL; } glyph_indices = malloc (sizeof (WCHAR) * buffer_size); dx = malloc (sizeof (int) * buffer_size); if (!glyph_indices || !dx) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL2; } gcp_results.nGlyphs = buffer_size; gcp_results.lpDx = dx; gcp_results.lpGlyphs = glyph_indices; if (!GetCharacterPlacementW (hdc, utf16, n16, 0, &gcp_results, GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) { status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_text_to_glyphs"); goto FAIL2; } if (gcp_results.lpDx && gcp_results.lpGlyphs) break; /* Too small a buffer, try again */ buffer_size *= 1.5; if (buffer_size > INT_MAX) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL2; } } *num_glyphs = gcp_results.nGlyphs; *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs); if (!*glyphs) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL2; } x_pos = x; y_pos = y; for (i = 0; i < gcp_results.nGlyphs; i++) { (*glyphs)[i].index = glyph_indices[i]; (*glyphs)[i].x = x_pos ; (*glyphs)[i].y = y_pos; x_pos += x_incr * dx[i]; y_pos += y_incr * dx[i]; } FAIL2: if (glyph_indices) free (glyph_indices); if (dx) free (dx); cairo_win32_scaled_font_done_font (&scaled_font->base); FAIL1: free (utf16); return status;}static cairo_status_t_cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font){ cairo_status_t status; cairo_font_extents_t extents; TEXTMETRIC metrics; HDC hdc; hdc = _get_global_font_dc (); if (!hdc) return CAIRO_STATUS_NO_MEMORY; if (scaled_font->preserve_axes) { /* For 90-degree rotations (including 0), we get the metrics * from the GDI in logical space, then convert back to font space */ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); if (status) return status; GetTextMetrics (hdc, &metrics); cairo_win32_scaled_font_done_font (&scaled_font->base); extents.ascent = metrics.tmAscent / scaled_font->logical_scale; extents.descent = metrics.tmDescent / scaled_font->logical_scale; extents.height = (metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->logical_scale; extents.max_x_advance = metrics.tmMaxCharWidth / scaled_font->logical_scale; extents.max_y_advance = 0; } else { /* For all other transformations, we use the design metrics * of the font. The GDI results from GetTextMetrics() on a * transformed font are inexplicably large and we want to * avoid them. */ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); if (status) return status; GetTextMetrics (hdc, &metrics); _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); extents.ascent = (double)metrics.tmAscent / scaled_font->em_square; extents.descent = metrics.tmDescent * scaled_font->em_square; extents.height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square; extents.max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square; extents.max_y_advance = 0; } _cairo_scaled_font_set_metrics (&scaled_font->base, &extents); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph){ static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; GLYPHMETRICS metrics; cairo_status_t status; cairo_text_extents_t extents; HDC hdc; hdc = _get_global_font_dc (); if (!hdc) return CAIRO_STATUS_NO_MEMORY; if (scaled_font->preserve_axes) { /* If we aren't rotating / skewing the axes, then we get the metrics * from the GDI in device space and convert to font space. */ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); if (status) return status; if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph), GGO_METRICS | GGO_GLYPH_INDEX, &metrics, 0, NULL, &matrix) == GDI_ERROR) { status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW"); memset (&metrics, 0, sizeof (GLYPHMETRICS)); } cairo_win32_scaled_font_done_font (&scaled_font->base); if (scaled_font->swap_axes) { extents.x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale; extents.y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale; extents.width = metrics.gmBlackBoxY / scaled_font->y_scale; extents.height = metrics.gmBlackBoxX / scaled_font->x_scale; extents.x_advance = metrics.gmCellIncY / scaled_font->x_scale; extents.y_advance = metrics.gmCellIncX / scaled_font->y_scale; } else { extents.x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale; extents.y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale; extents.width = metrics.gmBlackBoxX / scaled_font->x_scale; extents.height = metrics.gmBlackBoxY / scaled_font->y_scale; extents.x_advance = metrics.gmCellIncX / scaled_font->x_scale; extents.y_advance = metrics.gmCellIncY / scaled_font->y_scale; } if (scaled_font->swap_x) { extents.x_bearing = (- extents.x_bearing - extents.width); extents.x_advance = - extents.x_advance; } if (scaled_font->swap_y) { extents.y_bearing = (- extents.y_bearing - extents.height); extents.y_advance = - extents.y_advance; } } else { /* For all other transformations, we use the design metrics
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -