📄 cairo-ft-font.c
字号:
if (unscaled == NULL) return; if (unscaled->from_face) { /* See comments in _ft_font_face_destroy about the "zombie" state * for a _ft_font_face. */ if (unscaled->faces && !unscaled->faces->unscaled) cairo_font_face_destroy (&unscaled->faces->base); } else { cairo_ft_unscaled_font_map_t *font_map; font_map = _cairo_ft_unscaled_font_map_lock (); /* All created objects must have been mapped in the font map. */ assert (font_map != NULL); _cairo_hash_table_remove (font_map->hash_table, &unscaled->base.hash_entry); _font_map_release_face_lock_held (font_map, unscaled); _cairo_ft_unscaled_font_fini (unscaled); _cairo_ft_unscaled_font_map_unlock (); }}static cairo_bool_t_has_unlocked_face (void *entry){ cairo_ft_unscaled_font_t *unscaled = entry; return (unscaled->lock == 0 && unscaled->face);}/* Ensures that an unscaled font has a face object. If we exceed * MAX_OPEN_FACES, try to close some. * * This differs from _cairo_ft_scaled_font_lock_face in that it doesn't * set the scale on the face, but just returns it at the last scale. */FT_Face_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled){ cairo_ft_unscaled_font_map_t *font_map; FT_Face face = NULL; if (unscaled->face) { unscaled->lock++; return unscaled->face; } /* If this unscaled font was created from an FT_Face then we just * returned it above. */ assert (!unscaled->from_face); font_map = _cairo_ft_unscaled_font_map_lock (); assert (font_map != NULL); while (font_map->num_open_faces >= MAX_OPEN_FACES) { cairo_ft_unscaled_font_t *entry; entry = _cairo_hash_table_random_entry (font_map->hash_table, _has_unlocked_face); if (entry == NULL) break; _font_map_release_face_lock_held (font_map, entry); } if (FT_New_Face (font_map->ft_library, unscaled->filename, unscaled->id, &face) != FT_Err_Ok) goto FAIL; unscaled->face = face; unscaled->lock++; font_map->num_open_faces++; FAIL: _cairo_ft_unscaled_font_map_unlock (); return face;}/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face */void_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled){ assert (unscaled->lock > 0); unscaled->lock--;}static void_compute_transform (cairo_ft_font_transform_t *sf, cairo_matrix_t *scale){ cairo_matrix_t normalized = *scale; double tx, ty; /* The font matrix has x and y "scale" components which we extract and * use as character scale values. These influence the way freetype * chooses hints, as well as selecting different bitmaps in * hand-rendered fonts. We also copy the normalized matrix to * freetype's transformation. */ _cairo_matrix_compute_scale_factors (&normalized, &sf->x_scale, &sf->y_scale, /* XXX */ 1); if (sf->x_scale != 0 && sf->y_scale != 0) { cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); _cairo_matrix_get_affine (&normalized, &sf->shape[0][0], &sf->shape[0][1], &sf->shape[1][0], &sf->shape[1][1], &tx, &ty); } else { sf->shape[0][0] = sf->shape[1][1] = 1.0; sf->shape[0][1] = sf->shape[1][0] = 0.0; }}/* Temporarily scales an unscaled font to the give scale. We catch * scaling to the same size, since changing a FT_Face is expensive. */static void_cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, cairo_matrix_t *scale){ cairo_ft_font_transform_t sf; FT_Matrix mat; FT_UInt pixel_width, pixel_height; FT_Error error; assert (unscaled->face != NULL); if (unscaled->have_scale && scale->xx == unscaled->current_scale.xx && scale->yx == unscaled->current_scale.yx && scale->xy == unscaled->current_scale.xy && scale->yy == unscaled->current_scale.yy) return; unscaled->have_scale = TRUE; unscaled->current_scale = *scale; _compute_transform (&sf, scale); unscaled->x_scale = sf.x_scale; unscaled->y_scale = sf.y_scale; mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]); mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]); mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); unscaled->have_shape = (mat.xx != 0x10000 || mat.yx != 0x00000 || mat.xy != 0x00000 || mat.yy != 0x10000); cairo_matrix_init (&unscaled->current_shape, sf.shape[0][0], sf.shape[0][1], sf.shape[1][0], sf.shape[1][1], 0.0, 0.0); FT_Set_Transform(unscaled->face, &mat, NULL); if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) { pixel_width = sf.x_scale; pixel_height = sf.y_scale; error = FT_Set_Char_Size (unscaled->face, sf.x_scale * 64.0, sf.y_scale * 64.0, 0, 0); } else { double min_distance = DBL_MAX; int i; int best_i = 0; pixel_width = pixel_height = 0; for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {#if HAVE_FT_BITMAP_SIZE_Y_PPEM double size = unscaled->face->available_sizes[i].y_ppem / 64.;#else double size = unscaled->face->available_sizes[i].height;#endif double distance = fabs (size - sf.y_scale); if (distance <= min_distance) { min_distance = distance; best_i = i; } }#if HAVE_FT_BITMAP_SIZE_Y_PPEM error = FT_Set_Char_Size (unscaled->face, unscaled->face->available_sizes[best_i].x_ppem, unscaled->face->available_sizes[best_i].y_ppem, 0, 0); if (error)#endif error = FT_Set_Pixel_Sizes (unscaled->face, unscaled->face->available_sizes[best_i].width, unscaled->face->available_sizes[best_i].height); } assert (error == 0);}/* Empirically-derived subpixel filtering values thanks to Keith * Packard and libXft. */static const int filters[3][3] = { /* red */#if 0 { 65538*4/7,65538*2/7,65538*1/7 }, /* green */ { 65536*1/4, 65536*2/4, 65537*1/4 }, /* blue */ { 65538*1/7,65538*2/7,65538*4/7 },#endif { 65538*9/13,65538*3/13,65538*1/13 }, /* green */ { 65538*1/6, 65538*4/6, 65538*1/6 }, /* blue */ { 65538*1/13,65538*3/13,65538*9/13 },};/* Fills in val->image with an image surface created from @bitmap */static cairo_status_t_get_bitmap_surface (FT_Bitmap *bitmap, cairo_bool_t own_buffer, cairo_font_options_t *font_options, cairo_image_surface_t **surface){ int width, height, stride; unsigned char *data; int format = CAIRO_FORMAT_A8; cairo_bool_t subpixel = FALSE; width = bitmap->width; height = bitmap->rows; switch (bitmap->pixel_mode) { case FT_PIXEL_MODE_MONO: stride = (((width + 31) & ~31) >> 3); if (own_buffer) { data = bitmap->buffer; assert (stride == bitmap->pitch); } else { data = malloc (stride * height); if (!data) return CAIRO_STATUS_NO_MEMORY; if (stride == bitmap->pitch) { memcpy (data, bitmap->buffer, stride * height); } else { int i; unsigned char *source, *dest; source = bitmap->buffer; dest = data; for (i = height; i; i--) { memcpy (dest, source, bitmap->pitch); memset (dest + bitmap->pitch, '\0', stride - bitmap->pitch); source += bitmap->pitch; dest += stride; } } }#ifndef WORDS_BIGENDIAN { unsigned char *d = data; int count = stride * height; while (count--) { *d = CAIRO_BITSWAP8 (*d); d++; } }#endif format = CAIRO_FORMAT_A1; break; case FT_PIXEL_MODE_LCD: case FT_PIXEL_MODE_LCD_V: case FT_PIXEL_MODE_GRAY: switch (font_options->antialias) { case CAIRO_ANTIALIAS_DEFAULT: case CAIRO_ANTIALIAS_GRAY: case CAIRO_ANTIALIAS_NONE: default: stride = bitmap->pitch; if (own_buffer) { data = bitmap->buffer; } else { data = malloc (stride * height); if (!data) return CAIRO_STATUS_NO_MEMORY; memcpy (data, bitmap->buffer, stride * height); } format = CAIRO_FORMAT_A8; break; case CAIRO_ANTIALIAS_SUBPIXEL: { int x, y; unsigned char *in_line, *out_line, *in; unsigned int *out; unsigned int red, green, blue; int rf, gf, bf; int s; int o, os; unsigned char *data_rgba; unsigned int width_rgba, stride_rgba; int vmul = 1; int hmul = 1; switch (font_options->subpixel_order) { case CAIRO_SUBPIXEL_ORDER_DEFAULT: case CAIRO_SUBPIXEL_ORDER_RGB: case CAIRO_SUBPIXEL_ORDER_BGR: default: width /= 3; hmul = 3; break; case CAIRO_SUBPIXEL_ORDER_VRGB: case CAIRO_SUBPIXEL_ORDER_VBGR: vmul = 3; height /= 3; break; } /* * Filter the glyph to soften the color fringes */ width_rgba = width; stride = bitmap->pitch; stride_rgba = (width_rgba * 4 + 3) & ~3; data_rgba = calloc (1, stride_rgba * height); os = 1; switch (font_options->subpixel_order) { case CAIRO_SUBPIXEL_ORDER_VRGB: os = stride; case CAIRO_SUBPIXEL_ORDER_DEFAULT: case CAIRO_SUBPIXEL_ORDER_RGB: default: rf = 0; gf = 1; bf = 2; break; case CAIRO_SUBPIXEL_ORDER_VBGR: os = stride; case CAIRO_SUBPIXEL_ORDER_BGR: bf = 0; gf = 1; rf = 2; break; } in_line = bitmap->buffer; out_line = data_rgba; for (y = 0; y < height; y++) { in = in_line; out = (unsigned int *) out_line; in_line += stride * vmul; out_line += stride_rgba; for (x = 0; x < width * hmul; x += hmul) { red = green = blue = 0; o = 0; for (s = 0; s < 3; s++) { red += filters[rf][s]*in[x+o]; green += filters[gf][s]*in[x+o]; blue += filters[bf][s]*in[x+o]; o += os; } red = red / 65536; green = green / 65536; blue = blue / 65536; *out++ = (green << 24) | (red << 16) | (green << 8) | blue; } } /* Images here are stored in native format. The * backend must convert to its own format as needed */ if (own_buffer) free (bitmap->buffer); data = data_rgba; stride = stride_rgba; format = CAIRO_FORMAT_ARGB32; subpixel = TRUE; break; } } break; case FT_PIXEL_MODE_GRAY2: case FT_PIXEL_MODE_GRAY4: /* These could be triggered by very rare types of TrueType fonts */ default: return CAIRO_STATUS_NO_MEMORY; } *surface = (cairo_image_surface_t *) cairo_image_surface_create_for_data (data, format, width, height, stride); if ((*surface)->base.status) { free (data); return CAIRO_STATUS_NO_MEMORY; } if (subpixel) pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE); _cairo_image_surface_assume_ownership_of_data ((*surface)); return CAIRO_STATUS_SUCCESS;}/* Converts an outline FT_GlyphSlot into an image * * This could go through _render_glyph_bitmap as well, letting * FreeType convert the outline to a bitmap, but doing it ourselves * has two minor advantages: first, we save a copy of the bitmap * buffer: we can directly use the buffer that FreeType renders * into. * * Second, it may help when we add support for subpixel * rendering: the Xft code does it this way. (Keith thinks that * it may also be possible to get the subpixel rendering with * FT_Render_Glyph: something worth looking into in more detail * when we add subpixel support. If so, we may want to eliminate * this version of the code path entirely. */static cairo_status_t_render_glyph_outline (FT_Face face, cairo_font_options_t *font_options, cairo_image_surface_t **surface){ FT_GlyphSlot glyphslot = face->glyph; FT_Outline *outline = &glyphslot->outline; FT_Bitmap bitmap; FT_BBox cbox; FT_Matrix matrix; int hmul = 1; int vmul = 1; unsigned int width, height, stride; cairo_bool_t subpixel = FALSE; cairo_status_t status; FT_Outline_Get_CBox (outline, &cbox); cbox.xMin &= -64; cbox.yMin &= -64; cbox.xMax = (cbox.xMax + 63) & -64;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -