summaryrefslogtreecommitdiff
path: root/pango/pango-userfont.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango/pango-userfont.c')
-rw-r--r--pango/pango-userfont.c483
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: */