📄 cairo-win32-font.c
字号:
* of the font. */ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); 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_unscaled_font (&scaled_font->base); extents.x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square; extents.y_bearing = - (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square; extents.width = (double)metrics.gmBlackBoxX / scaled_font->em_square; extents.height = (double)metrics.gmBlackBoxY / scaled_font->em_square; extents.x_advance = (double)metrics.gmCellIncX / scaled_font->em_square; extents.y_advance = (double)metrics.gmCellIncY / scaled_font->em_square; } _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); return CAIRO_STATUS_SUCCESS;}/* Not currently used code, but may be useful in the future if we add * back the capability to the scaled font backend interface to get the * actual device space bbox rather than computing it from the * font-space metrics. */#if 0static cairo_status_t_cairo_win32_scaled_font_glyph_bbox (void *abstract_font, const cairo_glyph_t *glyphs, int num_glyphs, cairo_box_t *bbox){ static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; cairo_win32_scaled_font_t *scaled_font = abstract_font; int x1 = 0, x2 = 0, y1 = 0, y2 = 0; if (num_glyphs > 0) { HDC hdc = _get_global_font_dc (); GLYPHMETRICS metrics; cairo_status_t status; int i; if (!hdc) return CAIRO_STATUS_NO_MEMORY; status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); if (status) return status; for (i = 0; i < num_glyphs; i++) { int x = floor (0.5 + glyphs[i].x); int y = floor (0.5 + glyphs[i].y); GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX, &metrics, 0, NULL, &matrix); if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x) x1 = x + metrics.gmptGlyphOrigin.x; if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y) y1 = y - metrics.gmptGlyphOrigin.y; if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX) x2 = x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX; if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY) y2 = y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY; } cairo_win32_scaled_font_done_font (&scaled_font->base); } bbox->p1.x = _cairo_fixed_from_int (x1); bbox->p1.y = _cairo_fixed_from_int (y1); bbox->p2.x = _cairo_fixed_from_int (x2); bbox->p2.y = _cairo_fixed_from_int (y2); return CAIRO_STATUS_SUCCESS;}#endiftypedef struct { cairo_win32_scaled_font_t *scaled_font; HDC hdc; cairo_array_t glyphs; cairo_array_t dx; int start_x; int last_x; int last_y;} cairo_glyph_state_t;static void_start_glyphs (cairo_glyph_state_t *state, cairo_win32_scaled_font_t *scaled_font, HDC hdc){ state->hdc = hdc; state->scaled_font = scaled_font; _cairo_array_init (&state->glyphs, sizeof (WCHAR)); _cairo_array_init (&state->dx, sizeof (int));}static cairo_status_t_flush_glyphs (cairo_glyph_state_t *state){ cairo_status_t status; int dx = 0; WCHAR * elements; int * dx_elements; status = _cairo_array_append (&state->dx, &dx); if (status) return status; elements = _cairo_array_index (&state->glyphs, 0); dx_elements = _cairo_array_index (&state->dx, 0); if (!ExtTextOutW (state->hdc, state->start_x, state->last_y, ETO_GLYPH_INDEX, NULL, elements, state->glyphs.num_elements, dx_elements)) { return _cairo_win32_print_gdi_error ("_flush_glyphs"); } _cairo_array_truncate (&state->glyphs, 0); _cairo_array_truncate (&state->dx, 0); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_add_glyph (cairo_glyph_state_t *state, unsigned long index, double device_x, double device_y){ cairo_status_t status; double user_x = device_x; double user_y = device_y; WCHAR glyph_index = index; int logical_x, logical_y; cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y); logical_x = floor (user_x + 0.5); logical_y = floor (user_y + 0.5); if (state->glyphs.num_elements > 0) { int dx; if (logical_y != state->last_y) { status = _flush_glyphs (state); if (status) return status; state->start_x = logical_x; } dx = logical_x - state->last_x; status = _cairo_array_append (&state->dx, &dx); if (status) return status; } else { state->start_x = logical_x; } state->last_x = logical_x; state->last_y = logical_y; status = _cairo_array_append (&state->glyphs, &glyph_index); if (status) return status; return CAIRO_STATUS_SUCCESS;}static void_finish_glyphs (cairo_glyph_state_t *state){ _flush_glyphs (state); _cairo_array_fini (&state->glyphs); _cairo_array_fini (&state->dx);}static cairo_status_t_draw_glyphs_on_surface (cairo_win32_surface_t *surface, cairo_win32_scaled_font_t *scaled_font, COLORREF color, int x_offset, int y_offset, const cairo_glyph_t *glyphs, int num_glyphs){ cairo_glyph_state_t state; cairo_status_t status = CAIRO_STATUS_SUCCESS; int i; if (!SaveDC (surface->dc)) return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC"); status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc); if (status) goto FAIL1; SetTextColor (surface->dc, color); SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT); SetBkMode (surface->dc, TRANSPARENT); _start_glyphs (&state, scaled_font, surface->dc); for (i = 0; i < num_glyphs; i++) { status = _add_glyph (&state, glyphs[i].index, glyphs[i].x - x_offset, glyphs[i].y - y_offset); if (status) goto FAIL2; } FAIL2: _finish_glyphs (&state); cairo_win32_scaled_font_done_font (&scaled_font->base); FAIL1: RestoreDC (surface->dc, -1); return status;}/* Duplicate the green channel of a 4-channel mask in the alpha channel, then * invert the whole mask. */static void_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface){ cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image; int i, j; for (i = 0; i < image->height; i++) { uint32_t *p = (uint32_t *) (image->data + i * image->stride); for (j = 0; j < image->width; j++) { *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16)); p++; } }}/* Invert a mask */static void_invert_argb32_mask (cairo_win32_surface_t *mask_surface){ cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image; int i, j; for (i = 0; i < image->height; i++) { uint32_t *p = (uint32_t *) (image->data + i * image->stride); for (j = 0; j < image->width; j++) { *p = 0xffffffff ^ *p; p++; } }}/* Compute an alpha-mask from a monochrome RGB24 image */static cairo_surface_t *_compute_a8_mask (cairo_win32_surface_t *mask_surface){ cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image; cairo_image_surface_t *image8; int i, j; image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, image24->width, image24->height); if (image8->base.status) return NULL; for (i = 0; i < image24->height; i++) { uint32_t *p = (uint32_t *) (image24->data + i * image24->stride); unsigned char *q = (unsigned char *) (image8->data + i * image8->stride); for (j = 0; j < image24->width; j++) { *q = 255 - ((*p & 0x0000ff00) >> 8); p++; q++; } } return &image8->base;}static cairo_status_t_cairo_win32_scaled_font_glyph_init (void *abstract_font, cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_glyph_info_t info){ cairo_win32_scaled_font_t *scaled_font = abstract_font; cairo_status_t status; if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) { status = _cairo_win32_scaled_font_init_glyph_metrics (scaled_font, scaled_glyph); if (status) return status; } if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { ASSERT_NOT_REACHED; } if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) { status = _cairo_win32_scaled_font_init_glyph_path (scaled_font, scaled_glyph); if (status) return status; } return CAIRO_STATUS_SUCCESS;}static cairo_int_status_t_cairo_win32_scaled_font_show_glyphs (void *abstract_font, cairo_operator_t op, cairo_pattern_t *pattern, cairo_surface_t *generic_surface, int source_x, int source_y, int dest_x, int dest_y, unsigned int width, unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs){ cairo_win32_scaled_font_t *scaled_font = abstract_font; cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface; cairo_status_t status; if (width == 0 || height == 0) return CAIRO_STATUS_SUCCESS; if (_cairo_surface_is_win32 (generic_surface) && surface->format == CAIRO_FORMAT_RGB24 && op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (pattern)) { cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern; /* When compositing OVER on a GDI-understood surface, with a * solid opaque color, we can just call ExtTextOut directly. */ COLORREF new_color; new_color = RGB (((int)solid_pattern->color.red_short) >> 8, ((int)solid_pattern->color.green_short) >> 8, ((int)solid_pattern->color.blue_short) >> 8); status = _draw_glyphs_on_surface (surface, scaled_font, new_color, 0, 0, glyphs, num_glyphs); return status; } else { /* Otherwise, we need to draw using software fallbacks. We create a mask * surface by drawing the the glyphs onto a DIB, black-on-white then * inverting. GDI outputs gamma-corrected images so inverted black-on-white * is very different from white-on-black. We favor the more common * case where the final output is dark-on-light. */ cairo_win32_surface_t *tmp_surface; cairo_surface_t *mask_surface; cairo_surface_pattern_t mask; RECT r; tmp_surface = (cairo_win32_surface_t *)cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height); if (tmp_surface->base.status) return CAIRO_STATUS_NO_MEMORY; r.left = 0; r.top = 0; r.right = width; r.bottom = height; FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH)); _draw_glyphs_on_surface (tmp_surface, scaled_font, RGB (0, 0, 0), dest_x, dest_y, glyphs, num_glyphs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -