[pango/simple-fontmap: 8/22] Add PangoHbFamily




commit 0d9adcee07123aa6239a47ef8a1a0cc54a691473
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Oct 29 19:05:34 2021 -0400

    Add PangoHbFamily
    
    This is a straightforward implementation of
    PangoFontFamily for use with PangoHbFace.

 pango/meson.build              |   1 +
 pango/pango-hbfamily-private.h |  53 ++++++++
 pango/pango-hbfamily.c         | 274 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 328 insertions(+)
---
diff --git a/pango/meson.build b/pango/meson.build
index c12aa1bf..2b42c944 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -35,6 +35,7 @@ pango_sources = [
   'json/gtkjsonparser.c',
   'json/gtkjsonprinter.c',
   'pango-hbface.c',
+  'pango-hbfamily.c',
 ]
 
 pango_headers = [
diff --git a/pango/pango-hbfamily-private.h b/pango/pango-hbfamily-private.h
new file mode 100644
index 00000000..4129eb01
--- /dev/null
+++ b/pango/pango-hbfamily-private.h
@@ -0,0 +1,53 @@
+/* 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-font.h"
+#include "pango-hbface.h"
+
+#define PANGO_TYPE_HB_FAMILY (pango_hb_family_get_type ())
+
+PANGO_AVAILABLE_IN_1_52
+G_DECLARE_FINAL_TYPE (PangoHbFamily, pango_hb_family, PANGO, HB_FAMILY, PangoFontFamily)
+
+struct _PangoHbFamily
+{
+  PangoFontFamily parent_instance;
+
+  PangoFontMap *map;
+
+  char *name;
+  GPtrArray *faces;
+  gboolean monospace;
+  gboolean variable;
+};
+
+PANGO_AVAILABLE_IN_1_52
+PangoHbFamily *         pango_hb_family_new             (PangoFontMap           *map,
+                                                         const char             *name);
+
+PANGO_AVAILABLE_IN_1_52
+void                    pango_hb_family_add_face        (PangoHbFamily          *self,
+                                                         PangoHbFace            *face);
+
+PangoHbFace *           pango_hb_family_find_face       (PangoHbFamily          *self,
+                                                         PangoFontDescription   *description,
+                                                         PangoLanguage          *language);
diff --git a/pango/pango-hbfamily.c b/pango/pango-hbfamily.c
new file mode 100644
index 00000000..fd0e1189
--- /dev/null
+++ b/pango/pango-hbfamily.c
@@ -0,0 +1,274 @@
+/* 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 <gio/gio.h>
+
+#include "pango-hbfamily-private.h"
+#include "pango-impl-utils.h"
+#include "pango-hbface-private.h"
+#include "pango-font-private.h"
+
+/* {{{ GListModel implementation */
+
+static GType
+pango_hb_family_get_item_type (GListModel *list)
+{
+  return PANGO_TYPE_FONT_FACE;
+}
+
+static guint
+pango_hb_family_get_n_items (GListModel *list)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (list);
+
+  return self->faces->len;
+}
+
+static gpointer
+pango_hb_family_get_item (GListModel *list,
+                              guint       position)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (list);
+
+  if (position < self->faces->len)
+    return g_object_ref (g_ptr_array_index (self->faces, position));
+
+  return NULL;
+}
+
+static void
+pango_hb_family_list_model_init (GListModelInterface *iface)
+{
+  iface->get_item_type = pango_hb_family_get_item_type;
+  iface->get_n_items = pango_hb_family_get_n_items;
+  iface->get_item = pango_hb_family_get_item;
+}
+
+/* }}} */
+/* {{{ PangoFontFamily implementation */
+
+struct _PangoHbFamilyClass
+{
+  PangoFontFamilyClass parent_class;
+};
+
+G_DEFINE_TYPE_WITH_CODE (PangoHbFamily, pango_hb_family, PANGO_TYPE_FONT_FAMILY,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, pango_hb_family_list_model_init))
+
+static void
+pango_hb_family_init (PangoHbFamily *self)
+{
+  self->faces = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+static void
+pango_hb_family_finalize (GObject *object)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (object);
+
+  g_free (self->name);
+  g_ptr_array_unref (self->faces);
+
+  G_OBJECT_CLASS (pango_hb_family_parent_class)->finalize (object);
+}
+
+static const char *
+pango_hb_family_get_name (PangoFontFamily *family)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (family);
+
+  return self->name;
+}
+
+static void
+pango_hb_family_list_faces (PangoFontFamily   *family,
+                            PangoFontFace   ***faces,
+                            int               *n_faces)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (family);
+
+  if (faces)
+    *faces = g_memdup2 (self->faces->pdata, self->faces->len * sizeof (PangoFontFace *));
+
+  if (n_faces)
+    *n_faces = self->faces->len;
+}
+
+static PangoFontFace *
+pango_hb_family_get_face (PangoFontFamily *family,
+                          const char      *name)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (family);
+
+  for (int i = 0; i < self->faces->len; i++)
+    {
+      PangoFontFace *face = g_ptr_array_index (self->faces, i);
+
+        if (name == NULL || strcmp (name, pango_font_face_get_face_name (face)) == 0)
+          return face;
+    }
+
+  return NULL;
+}
+
+static gboolean
+pango_hb_family_is_monospace (PangoFontFamily *family)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (family);
+
+  return self->monospace;
+}
+
+static gboolean
+pango_hb_family_is_variable (PangoFontFamily *family)
+{
+  PangoHbFamily *self = PANGO_HB_FAMILY (family);
+
+  return self->variable;
+}
+
+static void
+pango_hb_family_class_init (PangoHbFamilyClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  PangoFontFamilyClass *family_class = PANGO_FONT_FAMILY_CLASS (class);
+
+  object_class->finalize = pango_hb_family_finalize;
+
+  family_class->list_faces = pango_hb_family_list_faces;
+  family_class->get_name = pango_hb_family_get_name;
+  family_class->get_face = pango_hb_family_get_face;
+  family_class->is_monospace = pango_hb_family_is_monospace;
+  family_class->is_variable = pango_hb_family_is_variable;
+}
+
+/* }}} */
+/* {{{ Private API */
+
+/*< private >
+ * pango_hb_family_new:
+ * @map: the font map
+ * @name: the family name
+ *
+ * Creates a new `PangoHbFamily`.
+ *
+ * Returns: a newly created `PangoHbFamily`
+ */
+PangoHbFamily *
+pango_hb_family_new (PangoFontMap *map,
+                     const char   *name)
+{
+  PangoHbFamily *self;
+
+  self = g_object_new (PANGO_TYPE_HB_FAMILY, NULL);
+
+  self->name = g_strdup (name);
+
+  self->map = map;
+  g_object_add_weak_pointer (G_OBJECT (map), (gpointer *)&self->map);
+
+  return self;
+}
+
+/*< private >
+ * pango_hb_family_add_face:
+ * @self: a `PangoHbFamily`
+ * @face: a `PangoFontFace` to add
+ *
+ * Adds a `PangoFontFace` to a `PangoHbFamily`.
+ *
+ * It is an error to call this function more than
+ * once for the same face.
+ */
+void
+pango_hb_family_add_face (PangoHbFamily *self,
+                          PangoHbFace   *face)
+{
+  self->monospace |= pango_font_face_is_monospace (PANGO_FONT_FACE (face));
+  self->variable |= pango_font_face_is_variable (PANGO_FONT_FACE (face));
+
+  g_ptr_array_add (self->faces, g_object_ref (face));
+  pango_hb_face_set_family (face, PANGO_FONT_FAMILY (self));
+}
+
+/*< private >
+ * pango_hb_family_find_face:
+ * @family: a `PangoHbFamily`
+ * @description: `PangoFontDescription` to match
+ * @language: (nullable): `PangoLanguage` to support
+ *
+ * Finds the face in @family that best matches
+ * the font description while also supporting
+ * the language.
+ *
+ * Amongst equally matching faces, a variable
+ * face is preferred over a non-variable one.
+ */
+PangoHbFace *
+pango_hb_family_find_face (PangoHbFamily        *family,
+                           PangoFontDescription *description,
+                           PangoLanguage        *language)
+{
+  PangoHbFace *face = NULL;
+  int best_distance = G_MAXINT;
+  gboolean best_supports_language = FALSE;
+  gboolean best_is_variable = FALSE;
+
+  for (int i = 0; i < family->faces->len; i++)
+    {
+      PangoHbFace *face2 = g_ptr_array_index (family->faces, i);
+      int distance;
+      gboolean supports_language;
+      gboolean is_variable;
+
+      if (!pango_font_description_is_similar (description, face2->description))
+        continue;
+
+      distance = pango_font_description_compute_distance (description, face2->description);
+
+      if (language)
+        supports_language = pango_hb_face_supports_language (face2, language);
+      else
+        supports_language = TRUE;
+
+      is_variable = pango_font_face_is_variable (PANGO_FONT_FACE (face2));
+
+      if ((supports_language && !best_supports_language) ||
+            (supports_language >= best_supports_language && (distance < best_distance ||
+               (distance == best_distance && is_variable && !best_is_variable))))
+        {
+          face = face2;
+          best_distance = distance;
+          best_supports_language = supports_language;
+          best_is_variable = is_variable;
+        }
+    }
+
+  if (!best_supports_language)
+    face = NULL;
+
+  return face;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]