[pango/simple-fontmap: 17/31] Add PangoHbFace
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/simple-fontmap: 17/31] Add PangoHbFace
- Date: Sun, 26 Dec 2021 18:03:15 +0000 (UTC)
commit 0d342a14ac469fd80f672c9edc959a3561bd38e6
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Oct 29 19:18:27 2021 -0400
Add PangoHbFace
PangoHbFace is a simple wrapper around hb_face_t.
This is an attempt to make a font backend that does
not depend on platform specifics and can be used in
tests.
pango/meson.build | 2 +
pango/pango-hbface-private.h | 42 +++
pango/pango-hbface.c | 595 +++++++++++++++++++++++++++++++++++++++++++
pango/pango-hbface.h | 63 +++++
pango/pango.h | 1 +
5 files changed, 703 insertions(+)
---
diff --git a/pango/meson.build b/pango/meson.build
index c8713582..c12aa1bf 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -34,6 +34,7 @@ pango_sources = [
'serializer.c',
'json/gtkjsonparser.c',
'json/gtkjsonprinter.c',
+ 'pango-hbface.c',
]
pango_headers = [
@@ -64,6 +65,7 @@ pango_headers = [
'pango-tabs.h',
'pango-types.h',
'pango-utils.h',
+ 'pango-hbface.h',
]
pango_installed_headers = pango_headers + [ 'pango-version-macros.h' ]
diff --git a/pango/pango-hbface-private.h b/pango/pango-hbface-private.h
new file mode 100644
index 00000000..4fc8fc1a
--- /dev/null
+++ b/pango/pango-hbface-private.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "pango-hbface.h"
+#include "pango-fontmap.h"
+#include "pango-language-set-private.h"
+#include <hb.h>
+
+struct _PangoHbFace
+{
+ PangoFontFace parent_instance;
+
+ unsigned int index;
+ int instance_id;
+ char *file;
+ PangoHbFace *orig;
+
+ hb_face_t *face;
+ char *name;
+ PangoFontFamily *family;
+ PangoFontDescription *description;
+ PangoMatrix matrix;
+ double x_scale, y_scale;
+ PangoLanguageSet *languages;
+ gboolean embolden;
+ gboolean synthetic;
+};
+
+void pango_hb_face_set_family (PangoHbFace *self,
+ PangoFontFamily *family);
+
+gboolean pango_hb_face_supports_language (PangoHbFace *self,
+ PangoLanguage *language);
+
+PangoLanguageSet * pango_hb_face_get_languages (PangoHbFace *self);
+
+PANGO_AVAILABLE_IN_1_52
+void pango_hb_face_set_languages (PangoHbFace *self,
+ PangoLanguageSet *languages);
+
+PANGO_AVAILABLE_IN_1_52
+void pango_hb_face_set_matrix (PangoHbFace *self,
+ const PangoMatrix *matrix);
diff --git a/pango/pango-hbface.c b/pango/pango-hbface.c
new file mode 100644
index 00000000..0699d55e
--- /dev/null
+++ b/pango/pango-hbface.c
@@ -0,0 +1,595 @@
+/* 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-hbface-private.h"
+
+#include "pango-language-set-simple-private.h"
+
+#include <hb-ot.h>
+
+/**
+ * PangoHbFace:
+ *
+ * `PangoHbFace` is a `PangoFontFace` implementation that wraps
+ * a `hb_face_t` object and implements all of the `PangoFontFace`
+ * functionality using HarfBuzz.
+ *
+ * In addition to making a `hb_face_t` available for rendering
+ * glyphs with Pango, `PangoHbFace` allows some tweaks to the
+ * rendering, such as artificial slant (using a transformation
+ * matrix) or artificial emboldening.
+ */
+
+/* {{{ PangoFontFace implementation */
+
+struct _PangoHbFaceClass
+{
+ PangoFontFaceClass parent_class;
+};
+
+G_DEFINE_TYPE (PangoHbFace, pango_hb_face, PANGO_TYPE_FONT_FACE)
+
+static void
+pango_hb_face_init (PangoHbFace *self)
+{
+ self->matrix = (PangoMatrix) PANGO_MATRIX_INIT;
+ self->x_scale = self->y_scale = 1.;
+ self->languages = PANGO_LANGUAGE_SET (pango_language_set_simple_new ());
+}
+
+static void
+pango_hb_face_finalize (GObject *object)
+{
+ PangoHbFace *self = PANGO_HB_FACE (object);
+
+ hb_face_destroy (self->face);
+ pango_font_description_free (self->description);
+ g_free (self->name);
+ g_free (self->file);
+ if (self->orig)
+ g_object_unref (self->orig);
+ g_object_unref (self->languages);
+
+ G_OBJECT_CLASS (pango_hb_face_parent_class)->finalize (object);
+}
+
+static const char *
+pango_hb_face_get_face_name (PangoFontFace *face)
+{
+ PangoHbFace *self = PANGO_HB_FACE (face);
+
+ return self->name;
+}
+
+static PangoFontDescription *
+pango_hb_face_describe (PangoFontFace *face)
+{
+ PangoHbFace *self = PANGO_HB_FACE (face);
+
+ return pango_font_description_copy (self->description);
+}
+
+static PangoFontFamily *
+pango_hb_face_get_family (PangoFontFace *face)
+{
+ PangoHbFace *self = PANGO_HB_FACE (face);
+
+ return self->family;
+}
+
+static gboolean
+pango_hb_face_is_synthesized (PangoFontFace *face)
+{
+ PangoHbFace *self = PANGO_HB_FACE (face);
+
+ return self->synthetic;
+}
+
+static void
+pango_hb_face_class_init (PangoHbFaceClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ PangoFontFaceClass *face_class = PANGO_FONT_FACE_CLASS (class);
+
+ object_class->finalize = pango_hb_face_finalize;
+
+ face_class->get_face_name = pango_hb_face_get_face_name;
+ face_class->describe = pango_hb_face_describe;
+ face_class->list_sizes = NULL;
+ face_class->is_synthesized = pango_hb_face_is_synthesized;
+ face_class->get_family = pango_hb_face_get_family;
+}
+
+/* }}} */
+/* {{{ Utilities */
+
+static char *
+font_description_to_style (PangoFontDescription *orig)
+{
+ PangoFontDescription *desc;
+ char *name;
+
+ desc = pango_font_description_copy_static (orig);
+ pango_font_description_unset_fields (desc, PANGO_FONT_MASK_FAMILY);
+ name = pango_font_description_to_string (desc);
+ if (strcmp (name, "Normal") == 0)
+ {
+ g_free (name);
+ name = g_strdup ("Regular");
+ }
+ pango_font_description_free (desc);
+
+ return name;
+}
+
+static char *
+get_name_from_hb_face (hb_face_t *face,
+ hb_ot_name_id_t name_id,
+ hb_ot_name_id_t fallback_id)
+{
+ char buf[256];
+ unsigned int len;
+ hb_language_t language;
+
+ language = hb_language_from_string ("en", -1);
+
+ len = sizeof (buf);
+ if (hb_ot_name_get_utf8 (face, name_id, language, &len, buf) > 0)
+ return g_strdup (buf);
+
+ if (fallback_id != HB_OT_NAME_ID_INVALID)
+ {
+ len = sizeof (buf);
+ if (hb_ot_name_get_utf8 (face, fallback_id, language, &len, buf) > 0)
+ return g_strdup (buf);
+ }
+
+ return g_strdup ("Unnamed");
+}
+
+static void
+ensure_hb_face (PangoHbFace *self)
+{
+ if (self->face)
+ return;
+
+ if (self->orig)
+ {
+ self->face = hb_face_reference (pango_hb_face_get_hb_face (self->orig));
+ }
+ else if (self->file)
+ {
+ hb_blob_t *blob = hb_blob_create_from_file (self->file);
+
+ if (blob == hb_blob_get_empty ())
+ g_warning ("Failed to load %s", self->file);
+
+ self->face = hb_face_create (blob, self->index);
+ hb_blob_destroy (blob);
+ hb_face_make_immutable (self->face);
+ }
+ else
+ g_assert_not_reached ();
+}
+
+static void
+set_name_and_description (PangoHbFace *self,
+ int instance_id,
+ const char *name,
+ PangoFontDescription *description)
+{
+ if (name)
+ {
+ self->name = g_strdup (name);
+ }
+ else
+ {
+ hb_ot_name_id_t name_id;
+
+ ensure_hb_face (self);
+
+ if (instance_id != -1)
+ name_id = hb_ot_var_named_instance_get_subfamily_name_id (self->face, instance_id);
+ else
+ name_id = HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY;
+
+ self->name = get_name_from_hb_face (self->face, name_id, HB_OT_NAME_ID_FONT_SUBFAMILY);
+ }
+
+ if (description)
+ {
+ self->description = pango_font_description_copy (description);
+ }
+ else
+ {
+ char *family;
+ char *fullname;
+
+ ensure_hb_face (self);
+
+ family = get_name_from_hb_face (self->face,
+ HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY,
+ HB_OT_NAME_ID_FONT_FAMILY);
+ fullname = g_strconcat (family, " ", self->name, NULL);
+
+ self->description = pango_font_description_from_string (fullname);
+ pango_font_description_unset_fields (self->description,
+ PANGO_FONT_MASK_VARIANT |
+ PANGO_FONT_MASK_GRAVITY |
+ PANGO_FONT_MASK_VARIATIONS);
+
+ g_free (fullname);
+ g_free (family);
+ }
+}
+
+/* }}} */
+/* {{{ Private API */
+
+/*< private >
+ * pango_hb_face_set_family:
+ * @self: a `PangoHbFace`
+ * @family: a `PangoFontFamily`
+ *
+ * Sets the font family of a `PangoHbFace`.
+ *
+ * This should only be called by fontmap implementations.
+ */
+void
+pango_hb_face_set_family (PangoHbFace *self,
+ PangoFontFamily *family)
+{
+ g_return_if_fail (self->family == NULL);
+ self->family = family;
+}
+
+/*< private >
+ * pango_hb_face_supports_language:
+ * @face: a `PangoHbFace`
+ * @language: a `PangoLanguage`
+ *
+ * Returns whether @face supports the language.
+ *
+ * Returns: `TRUE` if @face can be used for @language
+ */
+gboolean
+pango_hb_face_supports_language (PangoHbFace *face,
+ PangoLanguage *language)
+{
+ PangoLanguageSet *languages = pango_hb_face_get_languages (face);
+
+ return pango_language_set_matches_language (languages, language);
+}
+
+/*< private >
+ * pango_hb_face_get_languages:
+ * @face: a `PangoHbFace`
+ *
+ * Returns the languages supported by @face.
+ *
+ * Returns: (transfer none): a `PangoLanguageSet`
+ */
+PangoLanguageSet *
+pango_hb_face_get_languages (PangoHbFace *face)
+{
+ if (face->orig)
+ return pango_hb_face_get_languages (face->orig);
+
+ return face->languages;
+}
+
+/*< private >
+ * pango_hb_face_set_languages:
+ * @self: a `PangoHbFace`
+ * @languages: a `PangoLanguageSet`
+ *
+ * Sets the languages that are supported by @face.
+ *
+ * This should only be called by fontmap implementations.
+ */
+void
+pango_hb_face_set_languages (PangoHbFace *self,
+ PangoLanguageSet *languages)
+{
+ if (self->languages == languages)
+ return;
+
+ g_object_unref (self->languages);
+ self->languages = g_object_ref (languages);
+}
+
+/*< private >
+ * pango_hb_face_set_matrix:
+ * @self: a `PangoHbFace`
+ * @matrix: the `PangoMatrix`
+ *
+ * Sets the font matrix for @self.
+ *
+ * This should only be called by fontmap implementations.
+ */
+void
+pango_hb_face_set_matrix (PangoHbFace *self,
+ const PangoMatrix *matrix)
+{
+ if (self->orig)
+ self->matrix = self->orig->matrix;
+
+ pango_matrix_concat (&self->matrix, matrix);
+ pango_matrix_get_font_scale_factors (&self->matrix, &self->x_scale, &self->y_scale);
+ pango_matrix_scale (&self->matrix, 1./self->x_scale, 1./self->y_scale);
+}
+
+/* }}} */
+ /* {{{ Public API */
+
+/**
+ * pango_hb_face_new_from_bytes:
+ * @bytes: a `GBytes` containing font data
+ * @index: face index
+ * @instance_id: named instance id, or -1
+ * @name: (nullable): name for the face
+ * @description: (nullable): `PangoFontDescription` for the font
+ *
+ * Creates a new `PangoHbFace` from font data in memory.
+ *
+ * The @index can be used to pick one of the available
+ * faces in a .ttc file. See hb_face_count() to learn
+ * about the number of available faces.
+ *
+ * The @instance_id can be used to pick one of the
+ * available named instances in a variable font. See
+ * hb_ot_var_get_named_instance_count() to learn about
+ * the number of available named instances.
+ *
+ * If @name is provided, it is used as the name for the
+ * face. Otherwise, Pango will use the named instance
+ * subfamily name or `HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY`.
+ *
+ * If @description is provided, it is used as the font
+ * description for the face. Otherwise, Pango creates
+ * a description using HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY
+ * and the name of the face.
+ *
+ * If @desc and @name are provided, then the returned `PangoHbFace`
+ * object will be lazily initialized as needed.
+ *
+ * Returns: a newly created `PangoHbFace`
+ *
+ * Since: 1.52
+ */
+PangoHbFace *
+pango_hb_face_new_from_bytes (GBytes *bytes,
+ unsigned int index,
+ int instance_id,
+ const char *name,
+ PangoFontDescription *description)
+{
+ PangoHbFace *self;
+ hb_blob_t *blob;
+
+ self = g_object_new (PANGO_TYPE_HB_FACE, NULL);
+
+ blob = hb_blob_create (g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
+ HB_MEMORY_MODE_READONLY,
+ g_bytes_ref (bytes),
+ (hb_destroy_func_t) g_bytes_unref);
+
+ self->face = hb_face_create (blob, index);
+
+ hb_blob_destroy (blob);
+
+ self->index = index;
+ self->instance_id = instance_id;
+
+ set_name_and_description (self, instance_id, name, description);
+
+ return self;
+}
+
+/**
+ * pango_hb_face_new_from_file:
+ * @file: font filename
+ * @index: face index
+ * @instance_id: named instance id, or -1
+ * @name: (nullable): name for the face
+ * @description: (nullable): `PangoFontDescription` for the font
+ *
+ * Creates a new `PangoHbFace` from a font file.
+ *
+ * See [ctor@Pango.HbFace.new_from_bytes] for details.
+ *
+ * Returns: a newly created `PangoHbFace`
+ *
+ * Since: 1.52
+ */
+PangoHbFace *
+pango_hb_face_new_from_file (const char *file,
+ unsigned int index,
+ int instance_id,
+ const char *name,
+ PangoFontDescription *description)
+{
+ PangoHbFace *self;
+
+ self = g_object_new (PANGO_TYPE_HB_FACE, NULL);
+
+ self->file = g_strdup (file);
+ self->index = index;
+ self->instance_id = instance_id;
+
+ set_name_and_description (self, instance_id, name, description);
+
+ return self;
+}
+
+/**
+ * pango_hb_face_new_variant:
+ * @face: a `PangoHbFace`
+ * @transform: (nullable): the transform to apply
+ * @embolden: `TRUE` to render the font bolder
+ * @description: a `PangoFontDescription` to override fields from @face's description
+ *
+ * Creates a new `PangoHbFace` that is a variant of @face.
+ *
+ * The main possibilities for variations are:
+ * - Set a font matrix with @transformation, to create a slanted,
+ * condensed or expanded version of the @face
+ * - Render the glyphs of @face bolder, using @embolden
+ * - Provide an alternative family name in @description. This can
+ * be used to create generic aliases such as 'sans' or 'monospace'
+ *
+ * Note that only the following fields in @description should be set:
+ * - style or stretch, to indicate a transformed style
+ * - weight, to indicate a bolder weight
+ * - family, to provide an alternative family name
+ *
+ * Returns: (transfer full): a newly created `PangoHbFace`
+ *
+ * Since: 1.52
+ */
+PangoHbFace *
+pango_hb_face_new_variant (PangoHbFace *face,
+ const PangoMatrix *transform,
+ gboolean embolden,
+ PangoFontDescription *description)
+{
+ PangoHbFace *self;
+
+ g_return_val_if_fail (PANGO_IS_HB_FACE (face), NULL);
+ g_return_val_if_fail (description != NULL, NULL);
+ g_return_val_if_fail ((pango_font_description_get_set_fields (description) &
+ ~(PANGO_FONT_MASK_FAMILY |
+ PANGO_FONT_MASK_STYLE |
+ PANGO_FONT_MASK_WEIGHT |
+ PANGO_FONT_MASK_STRETCH)) == 0, NULL);
+
+ self = g_object_new (PANGO_TYPE_HB_FACE, NULL);
+
+ self->orig = g_object_ref (face);
+ self->index = face->index;
+ self->instance_id = face->instance_id;
+ if (transform)
+ pango_hb_face_set_matrix (self, transform);
+ self->embolden = embolden;
+ self->synthetic = TRUE;
+
+ self->description = pango_font_description_copy (face->description);
+ pango_font_description_merge (self->description, description, TRUE);
+ self->name = font_description_to_style (self->description);
+
+ return self;
+}
+
+typedef struct {
+ guint16 major;
+ guint16 minor;
+ gint32 italicAngle;
+ gint16 underlinePosition;
+ gint16 underlineThickness;
+ guint8 isFixedPitch[4];
+} PostTable;
+
+/**
+ * pango_hb_face_is_monospace:
+ * @self: a `PangoHbFace`
+ *
+ * Returns whether @self should be considered monospace.
+ *
+ * Returns: `TRUE` if @face is monospace
+ *
+ * Since: 1.52
+ */
+gboolean
+pango_hb_face_is_monospace (PangoHbFace *self)
+{
+ hb_blob_t *post_blob;
+ guint8 *raw_post;
+ unsigned int post_len;
+ gboolean res = FALSE;
+
+ ensure_hb_face (self);
+
+ post_blob = hb_face_reference_table (self->face, HB_TAG ('p', 'o', 's', 't'));
+ raw_post = (guint8 *) hb_blob_get_data (post_blob, &post_len);
+
+ if (post_len >= sizeof (PostTable))
+ {
+ PostTable *post = (PostTable *)raw_post;
+
+ res = post->isFixedPitch[0] != 0 ||
+ post->isFixedPitch[1] != 0 ||
+ post->isFixedPitch[2] != 0 ||
+ post->isFixedPitch[3] != 0;
+ }
+
+ hb_blob_destroy (post_blob);
+
+ return res;
+}
+
+/**
+ * pango_hb_face_is_variable:
+ * @self: a `PangoHbFace`
+ *
+ * Returns whether @self has OpenType variation axes.
+ *
+ * See hb_ot_var_get_axis_infos() to obtain
+ * more information about the axes of the face.
+ *
+ * Returns: `TRUE` if @face is variable
+ *
+ * Since: 1.52
+ */
+gboolean
+pango_hb_face_is_variable (PangoHbFace *self)
+{
+ ensure_hb_face (self);
+
+ return hb_ot_var_get_axis_count (self->face) > 0;
+}
+
+/**
+ * pango_hb_face_get_hb_face:
+ * @self: a `PangoHbFace`
+ *
+ * Gets the `hb_face_t` object backing this face.
+ *
+ * Note that the objects returned by this function are cached
+ * and immutable.
+ *
+ * Returns: (transfer none): the `hb_face_t` object
+ * backing the face
+ *
+ * Since: 1.52
+ */
+hb_face_t *
+pango_hb_face_get_hb_face (PangoHbFace *self)
+{
+ ensure_hb_face (self);
+
+ return self->face;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */
diff --git a/pango/pango-hbface.h b/pango/pango-hbface.h
new file mode 100644
index 00000000..a720e88e
--- /dev/null
+++ b/pango/pango-hbface.h
@@ -0,0 +1,63 @@
+/* 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.
+ */
+
+#pragma once
+
+#include <pango/pango-font.h>
+
+#include <hb.h>
+
+G_BEGIN_DECLS
+
+#define PANGO_TYPE_HB_FACE (pango_hb_face_get_type ())
+
+PANGO_AVAILABLE_IN_1_52
+G_DECLARE_FINAL_TYPE (PangoHbFace, pango_hb_face, PANGO, HB_FACE, PangoFontFace)
+
+PANGO_AVAILABLE_IN_1_52
+PangoHbFace * pango_hb_face_new_from_bytes (GBytes *bytes,
+ unsigned int index,
+ int instance_id,
+ const char *name,
+ PangoFontDescription *description);
+
+PANGO_AVAILABLE_IN_1_52
+PangoHbFace * pango_hb_face_new_from_file (const char *file,
+ unsigned int index,
+ int instance_id,
+ const char *name,
+ PangoFontDescription *description);
+
+PANGO_AVAILABLE_IN_1_52
+PangoHbFace * pango_hb_face_new_variant (PangoHbFace *face,
+ const PangoMatrix *transform,
+ gboolean embolden,
+ PangoFontDescription *description);
+
+PANGO_AVAILABLE_IN_1_52
+gboolean pango_hb_face_is_monospace (PangoHbFace *self);
+
+PANGO_AVAILABLE_IN_1_52
+gboolean pango_hb_face_is_variable (PangoHbFace *self);
+
+PANGO_AVAILABLE_IN_1_52
+hb_face_t * pango_hb_face_get_hb_face (PangoHbFace *self);
+
+G_END_DECLS
diff --git a/pango/pango.h b/pango/pango.h
index eca66265..917f9ffd 100644
--- a/pango/pango.h
+++ b/pango/pango.h
@@ -39,6 +39,7 @@
#include <pango/pango-glyph.h>
#include <pango/pango-glyph-item.h>
#include <pango/pango-gravity.h>
+#include <pango/pango-hbface.h>
#include <pango/pango-item.h>
#include <pango/pango-language.h>
#include <pango/pango-layout.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]