diff options
Diffstat (limited to 'pango/pango-userfont.c')
-rw-r--r-- | pango/pango-userfont.c | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/pango/pango-userfont.c b/pango/pango-userfont.c new file mode 100644 index 00000000..d0860cca --- /dev/null +++ b/pango/pango-userfont.c @@ -0,0 +1,483 @@ +/* Pango + * + * Copyright (C) 2021 Matthias Clasen + * + * 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 "pango-userfont-private.h" + +#include "pango-font-private.h" +#include "pango-coverage-private.h" +#include "pango-userface-private.h" +#include "pango-hbfamily-private.h" +#include "pango-impl-utils.h" +#include "pango-language-set-private.h" + +#include <hb-ot.h> + +/** + * PangoUserFont: + * + * `PangoUserFont` is a `PangoFont` implementation that uses callbacks. + */ + +/* {{{ PangoFont implementation */ + +struct _PangoUserFontClass +{ + PangoFontClass parent_class; +}; + +G_DEFINE_TYPE (PangoUserFont, pango_user_font, PANGO_TYPE_FONT) + +static void +pango_user_font_init (PangoUserFont *self) +{ + self->gravity = PANGO_GRAVITY_AUTO; + self->matrix = (PangoMatrix) PANGO_MATRIX_INIT; +} + +static void +pango_user_font_finalize (GObject *object) +{ + PangoUserFont *self = PANGO_USER_FONT (object); + + g_object_unref (self->face); + + G_OBJECT_CLASS (pango_user_font_parent_class)->finalize (object); +} + +static PangoFontDescription * +pango_user_font_describe (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + PangoFontDescription *desc; + + desc = pango_font_face_describe (PANGO_FONT_FACE (self->face)); + pango_font_description_set_gravity (desc, self->gravity); + pango_font_description_set_size (desc, self->size); + + return desc; +} + +static PangoFontDescription * +pango_user_font_describe_absolute (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + PangoFontDescription *desc; + + desc = pango_user_font_describe (font); + pango_font_description_set_absolute_size (desc, self->size * self->dpi / 72.); + + return desc; +} + +static PangoCoverage * +pango_user_font_get_coverage (PangoFont *font, + PangoLanguage *language G_GNUC_UNUSED) +{ + /* FIXME */ + return pango_coverage_new (); +} + +static void +pango_user_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + hb_font_t *hb_font = pango_font_get_hb_font (font); + hb_glyph_extents_t extents; + hb_direction_t direction; + hb_font_extents_t font_extents; + + direction = PANGO_GRAVITY_IS_VERTICAL (self->gravity) + ? HB_DIRECTION_TTB + : HB_DIRECTION_LTR; + + hb_font_get_extents_for_direction (hb_font, direction, &font_extents); + + if (glyph == PANGO_GLYPH_EMPTY || (glyph & PANGO_GLYPH_UNKNOWN_FLAG)) + { + if (ink_rect) + ink_rect->x = ink_rect->y = ink_rect->width = ink_rect->height = 0; + + if (logical_rect) + { + logical_rect->x = logical_rect->width = 0; + logical_rect->y = - font_extents.ascender; + logical_rect->height = font_extents.ascender - font_extents.descender; + } + + return; + } + + hb_font_get_glyph_extents (hb_font, glyph, &extents); + + if (ink_rect) + { + PangoRectangle r; + + r.x = extents.x_bearing; + r.y = - extents.y_bearing; + r.width = extents.width; + r.height = - extents.height; + + switch (self->gravity) + { + case PANGO_GRAVITY_AUTO: + case PANGO_GRAVITY_SOUTH: + ink_rect->x = r.x; + ink_rect->y = r.y; + ink_rect->width = r.width; + ink_rect->height = r.height; + break; + case PANGO_GRAVITY_NORTH: + ink_rect->x = - r.x; + ink_rect->y = - r.y; + ink_rect->width = - r.width; + ink_rect->height = - r.height; + break; + case PANGO_GRAVITY_EAST: + ink_rect->x = r.y; + ink_rect->y = - r.x - r.width; + ink_rect->width = r.height; + ink_rect->height = r.width; + break; + case PANGO_GRAVITY_WEST: + ink_rect->x = - r.y - r.height; + ink_rect->y = r.x; + ink_rect->width = r.height; + ink_rect->height = r.width; + break; + default: + g_assert_not_reached (); + } + + if (PANGO_GRAVITY_IS_IMPROPER (self->gravity)) + { + PangoMatrix matrix = (PangoMatrix) PANGO_MATRIX_INIT; + pango_matrix_scale (&matrix, -1, -1); + pango_matrix_transform_rectangle (&matrix, ink_rect); + } + } + + if (logical_rect) + { + hb_position_t h_advance; + hb_font_extents_t extents; + + h_advance = hb_font_get_glyph_h_advance (hb_font, glyph); + hb_font_get_h_extents (hb_font, &extents); + + logical_rect->x = 0; + logical_rect->y = - extents.ascender; + + switch (self->gravity) + { + case PANGO_GRAVITY_AUTO: + case PANGO_GRAVITY_SOUTH: + logical_rect->y = - extents.ascender; + logical_rect->width = h_advance; + break; + case PANGO_GRAVITY_NORTH: + logical_rect->y = extents.descender; + logical_rect->width = h_advance; + break; + case PANGO_GRAVITY_EAST: + logical_rect->y = - logical_rect->height / 2; + logical_rect->width = logical_rect->height; + break; + case PANGO_GRAVITY_WEST: + logical_rect->y = - logical_rect->height / 2; + logical_rect->width = - logical_rect->height; + break; + default: + g_assert_not_reached (); + } + + if (PANGO_GRAVITY_IS_IMPROPER (self->gravity)) + { + logical_rect->height = - logical_rect->height; + logical_rect->y = - logical_rect->y; + } + } +} + +static PangoFontMetrics * +pango_user_font_get_metrics (PangoFont *font, + PangoLanguage *language) +{ + hb_font_t *hb_font = pango_font_get_hb_font (font); + PangoFontMetrics *metrics; + hb_font_extents_t extents; + + metrics = pango_font_metrics_new (); + + hb_font_get_extents_for_direction (hb_font, HB_DIRECTION_LTR, &extents); + + metrics->descent = - extents.descender; + metrics->ascent = extents.ascender; + metrics->height = extents.ascender - extents.descender + extents.line_gap; + + metrics->underline_thickness = PANGO_SCALE; + metrics->underline_position = - PANGO_SCALE; + metrics->strikethrough_thickness = PANGO_SCALE; + metrics->strikethrough_position = metrics->ascent / 2; + metrics->approximate_char_width = 0; /* FIXME */ + metrics->approximate_digit_width = 0; + + return metrics; +} + +static PangoFontMap * +pango_user_font_get_font_map (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + PangoHbFamily *family = PANGO_HB_FAMILY (self->face->family); + + return family->map; +} + +static hb_bool_t +nominal_glyph_func (hb_font_t *font, void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + void *user_data) +{ + PangoUserFont *self = font_data; + + return self->face->glyph_func (self->face, unicode, glyph, self->face->user_data); +} + +static hb_position_t +glyph_h_advance_func (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + void *user_data) +{ + PangoUserFont *self = font_data; + int size = self->size * self->dpi / 72.; + hb_position_t h_advance, v_advance; + hb_glyph_extents_t glyph_extents; + gboolean is_color; + + self->face->glyph_info_func (self->face, size, glyph, + &glyph_extents, + &h_advance, &v_advance, + &is_color, + self->face->user_data); + + return h_advance; +} + +static hb_bool_t +glyph_extents_func (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data) +{ + PangoUserFont *self = font_data; + int size = self->size * self->dpi / 72.; + hb_position_t h_advance, v_advance; + gboolean is_color; + + return self->face->glyph_info_func (self->face, size, glyph, + extents, + &h_advance, &v_advance, + &is_color, + self->face->user_data); +} + +static hb_bool_t +font_extents_func (hb_font_t *font, void *font_data, + hb_font_extents_t *extents, + void *user_data) +{ + PangoUserFont *self = font_data; + int size = self->size * self->dpi / 72.; + + return self->face->font_info_func (self->face, size, extents, self->face->user_data); +} + +static hb_font_t * +pango_user_font_create_hb_font (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + hb_font_t *hb_font; + double x_scale, y_scale; + int size; + hb_blob_t *blob; + hb_face_t *face; + hb_font_funcs_t *funcs; + + blob = hb_blob_create ("", 0, HB_MEMORY_MODE_READONLY, NULL, NULL); + face = hb_face_create (blob, 0); + hb_font = hb_font_create (face); + + funcs = hb_font_funcs_create (); + + hb_font_funcs_set_nominal_glyph_func (funcs, nominal_glyph_func, NULL, NULL); + hb_font_funcs_set_glyph_h_advance_func (funcs, glyph_h_advance_func, NULL, NULL); + hb_font_funcs_set_glyph_extents_func (funcs, glyph_extents_func, NULL, NULL); + hb_font_funcs_set_font_h_extents_func (funcs, font_extents_func, NULL, NULL); + + hb_font_set_funcs (hb_font, funcs, self, NULL); + + hb_font_funcs_destroy (funcs); + hb_face_destroy (face); + hb_blob_destroy (blob); + + size = self->size * self->dpi / 72.f; + x_scale = y_scale = 1; + + if (PANGO_GRAVITY_IS_IMPROPER (self->gravity)) + { + x_scale = - x_scale; + y_scale = - y_scale; + } + + hb_font_set_scale (hb_font, size * x_scale, size * y_scale); + hb_font_set_ptem (hb_font, self->size / PANGO_SCALE); + + return hb_font; +} + +static gboolean +pango_user_font_has_char (PangoFont *font, + gunichar wc) +{ + hb_font_t *user_font = pango_font_get_hb_font (font); + hb_codepoint_t glyph; + + return hb_font_get_nominal_glyph (user_font, wc, &glyph); +} + +static PangoFontFace * +pango_user_font_get_face (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + + return PANGO_FONT_FACE (self->face); +} + +static void +pango_user_font_class_init (PangoUserFontClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontClass *font_class = PANGO_FONT_CLASS (class); + PangoFontClassPrivate *pclass; + + object_class->finalize = pango_user_font_finalize; + + font_class->describe = pango_user_font_describe; + font_class->describe_absolute = pango_user_font_describe_absolute; + font_class->get_coverage = pango_user_font_get_coverage; + font_class->get_glyph_extents = pango_user_font_get_glyph_extents; + font_class->get_metrics = pango_user_font_get_metrics; + font_class->get_font_map = pango_user_font_get_font_map; + font_class->create_hb_font = pango_user_font_create_hb_font; + + pclass = g_type_class_get_private ((GTypeClass *) class, PANGO_TYPE_FONT); + + pclass->has_char = pango_user_font_has_char; + pclass->get_face = pango_user_font_get_face; +} + +/* }}} */ + /* {{{ Public API */ + +/** + * pango_user_font_new: + * @face: the `PangoUserFace` to use + * @size: the desired size in points, scaled by `PANGO_SCALE` + * @gravity: the gravity to use when rendering + * @dpi: the dpi used when rendering + * @matrix: (nullable): transformation matrix to use when rendering + * + * Creates a new `PangoUserFont`. + * + * Returns: a newly created `PangoUserFont` + * + * Since: 1.52 + */ +PangoUserFont * +pango_user_font_new (PangoUserFace *face, + int size, + PangoGravity gravity, + float dpi, + const PangoMatrix *matrix) +{ + PangoUserFont *self; + + self = g_object_new (PANGO_TYPE_USER_FONT, NULL); + + self->face = g_object_ref (face); + + self->size = size; + self->dpi = dpi; + if (gravity != PANGO_GRAVITY_AUTO) + self->gravity = gravity; + if (matrix) + self->matrix = *matrix; + + return self; +} + +/** + * pango_user_font_new_for_description: + * @face: the `PangoUserFace` to use + * @description: a `PangoFontDescription` + * @dpi: the dpi used when rendering + * @matrix: (nullable): transformation matrix to use when rendering + * + * Creates a new `PangoUserFont` with size and gravity taken + * from a font description. + * + * Returns: a newly created `PangoHbFont` + * + * Since: 1.52 + */ + +PangoUserFont * +pango_user_font_new_for_description (PangoUserFace *face, + const PangoFontDescription *description, + float dpi, + const PangoMatrix *matrix) +{ + int size; + PangoGravity gravity; + + if (pango_font_description_get_size_is_absolute (description)) + size = pango_font_description_get_size (description) * 72. / dpi; + else + size = pango_font_description_get_size (description); + + if ((pango_font_description_get_set_fields (description) & PANGO_FONT_MASK_GRAVITY) != 0 && + pango_font_description_get_gravity (description) != PANGO_GRAVITY_SOUTH) + gravity = pango_font_description_get_gravity (description); + else + gravity = PANGO_GRAVITY_AUTO; + + return pango_user_font_new (face, size, gravity, dpi, matrix); +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ |