[pango/pango2-color-palette: 22/22] Support color palettes in fonts




commit 25d28eb376db22b7a296e58a53dd222e1ca80d8b
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jul 1 09:57:35 2022 -0400

    Support color palettes in fonts
    
    Add a pango_context_set_palette to select whether
    we prefer the default palette, the palette for light
    background, or the palette for dark background. Wire
    this through PangoFontSetCached and PangoFont, and
    apply in when we create a scaled font for cairo.
    
    Also add a palette field to PangoFontDescription,
    and treat it similarly.
    
    PangoHbFace gained a map from palette names
    to palette indices, which is used to find the
    palette to use.
    
    To try this, use the new --palette option of
    pango-view.
    
    The only font I've found with such color palettes
    is Amiri Quran Colored.

 pango2/meson.build                      |   2 +
 pango2/pango-color-palette-private.h    |  25 ++++
 pango2/pango-color-palette.c            | 131 +++++++++++++++++++++
 pango2/pango-color-palette.h            |  49 ++++++++
 pango2/pango-context-private.h          |   2 +
 pango2/pango-context.c                  |  76 +++++++++++-
 pango2/pango-context.h                  |   8 ++
 pango2/pango-font-description-private.h |   2 +
 pango2/pango-font-description.c         | 201 ++++++++++++++++++++++++--------
 pango2/pango-font-description.h         |   7 ++
 pango2/pango-font-private.h             |  14 ++-
 pango2/pango-fontmap.c                  |   7 +-
 pango2/pango-fontset-cached-private.h   |   1 +
 pango2/pango-fontset-cached.c           |  69 +++++------
 pango2/pango-hbface-private.h           |   6 +
 pango2/pango-hbface.c                   |  88 ++++++++++++++
 pango2/pango-hbface.h                   |   5 +
 pango2/pango-hbfont.c                   |   2 +-
 pango2/pango.h                          |   1 +
 pango2/pangocairo-font.c                |  23 +++-
 tests/test-font.c                       |  70 ++++++++++-
 utils/viewer-pangocairo.c               |   9 +-
 22 files changed, 694 insertions(+), 104 deletions(-)
---
diff --git a/pango2/meson.build b/pango2/meson.build
index 0a3e8d323..def139cd6 100644
--- a/pango2/meson.build
+++ b/pango2/meson.build
@@ -9,6 +9,7 @@ pango_sources = [
   'pango-attributes.c',
   'pango-bidi.c',
   'pango-color.c',
+  'pango-color-palette.c',
   'pango-context.c',
   'pango-emoji.c',
   'pango-font.c',
@@ -58,6 +59,7 @@ pango_headers = [
   'pango-attributes.h',
   'pango-break.h',
   'pango-color.h',
+  'pango-color-palette.h',
   'pango-context.h',
   'pango-direction.h',
   'pango-font.h',
diff --git a/pango2/pango-color-palette-private.h b/pango2/pango-color-palette-private.h
new file mode 100644
index 000000000..283c221d0
--- /dev/null
+++ b/pango2/pango-color-palette-private.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 Red Hat Software
+ *
+ * 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 "pango-color-palette.h"
+
+struct _Pango2ColorPalette {
+  GQuark name;
+  unsigned int index;
+};
diff --git a/pango2/pango-color-palette.c b/pango2/pango-color-palette.c
new file mode 100644
index 000000000..2df0907ed
--- /dev/null
+++ b/pango2/pango-color-palette.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 Red Hat Software
+ *
+ * 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-color-palette-private.h"
+
+/**
+ * Pango2ColorPalette:
+ *
+ * OpenType fonts can contain one or more color palettes
+ * for use with color glyphs. Since to order and position
+ * of these palettes is not standardized, they are difficult
+ * to use in a context you don't have tight control over the
+ * actual fonts that are used.
+ *
+ * `Pango2ColorPalette` objects are used to associate names
+ * with the palette indices of a font, to allow referring to
+ * the palettes with names that can be meaningful across
+ * different fonts.
+ *
+ * Note that Pango predefines the names "normal", "light"
+ * and "dark", and attempts to find suitable palettes for
+ * these ("light" and "dark" are intended to be palettes for
+ * use on light or dark background, respectively).
+ */
+
+/**
+ * PANGO2_COLOR_PALETTE_NORMAL:
+ *
+ * The name for the default color palette.
+ */
+
+/**
+ * PANGO2_COLOR_PALETTE_LIGHT:
+ *
+ * The name for a color palette suitable for use on
+ * a light background.
+ */
+
+/**
+ * PANGO2_COLOR_PALETTE_DARK:
+ *
+ * The name for a color palette suitable for use on
+ * a dark background.
+ */
+
+G_DEFINE_BOXED_TYPE (Pango2ColorPalette, pango2_color_palette,
+                     pango2_color_palette_copy,
+                     pango2_color_palette_free);
+
+/**
+ * pango2_color_palette_copy:
+ * @src: a `Pango2ColorPalette`
+ *
+ * Makes a copy of a `Pango2ColorPalette`
+ *
+ * Return value: (transfer full): a copy of @src
+ */
+Pango2ColorPalette *
+pango2_color_palette_copy (const Pango2ColorPalette *src)
+{
+  Pango2ColorPalette *ret;
+
+  if (src == NULL)
+    return NULL;
+
+  ret = g_slice_new (Pango2ColorPalette);
+
+  *ret = *src;
+
+  return ret;
+}
+
+/**
+ * pango2_color_palette_free:
+ * @palette: a `Pango2ColorPalette`
+ *
+ * Frees a `PangoColorPalette`.
+ */
+void
+pango2_color_palette_free (Pango2ColorPalette *palette)
+{
+  if (palette == NULL)
+    return;
+
+  g_slice_free (Pango2ColorPalette, palette);
+}
+
+/**
+ * pango2_color_palette_new:
+ * @name: the name to use for the palette
+ * @palette_index: the index for the palette
+ *
+ * Creates a new `Pango2ColorPalette` object.
+ *
+ * You can use `hb_ot_color_palette_get_count` to
+ * find out about the number of available palettes
+ * in a `hb_face_t`.
+ *
+ * Returns: (transfer full): a new `Pango2ColorPalette`
+ */
+Pango2ColorPalette *
+pango2_color_palette_new (const char   *name,
+                          unsigned int  palette_index)
+{
+  Pango2ColorPalette *ret;
+
+  ret = g_slice_new (Pango2ColorPalette);
+
+  ret->name = g_quark_from_string (name);
+  ret->index = palette_index;
+
+  return ret;
+}
diff --git a/pango2/pango-color-palette.h b/pango2/pango-color-palette.h
new file mode 100644
index 000000000..a4469198b
--- /dev/null
+++ b/pango2/pango-color-palette.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 Red Hat Software
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <pango2/pango-types.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _Pango2ColorPalette Pango2ColorPalette;
+
+#define PANGO2_TYPE_COLOR_PALETTE (pango2_color_palette_get_type ())
+
+PANGO2_AVAILABLE_IN_ALL
+GType                   pango2_color_palette_get_type   (void) G_GNUC_CONST;
+
+PANGO2_AVAILABLE_IN_ALL
+Pango2ColorPalette *    pango2_color_palette_new        (const char               *name,
+                                                         unsigned int              palette_index);
+
+PANGO2_AVAILABLE_IN_ALL
+Pango2ColorPalette *    pango2_color_palette_copy       (const Pango2ColorPalette *src);
+
+PANGO2_AVAILABLE_IN_ALL
+void                    pango2_color_palette_free       (Pango2ColorPalette       *palette);
+
+#define PANGO2_COLOR_PALETTE_NORMAL "normal"
+#define PANGO2_COLOR_PALETTE_LIGHT  "light"
+#define PANGO2_COLOR_PALETTE_DARK   "dark"
+
+G_END_DECLS
diff --git a/pango2/pango-context-private.h b/pango2/pango-context-private.h
index 07b4b506b..4ec65da6e 100644
--- a/pango2/pango-context-private.h
+++ b/pango2/pango-context-private.h
@@ -48,6 +48,8 @@ struct _Pango2Context
 
   gboolean round_glyph_positions;
 
+  GQuark palette;
+
 #ifdef HAVE_CAIRO
   gboolean set_options_explicit;
 
diff --git a/pango2/pango-context.c b/pango2/pango-context.c
index 371c8405f..8a69ffb89 100644
--- a/pango2/pango-context.c
+++ b/pango2/pango-context.c
@@ -69,6 +69,7 @@ enum {
   PROP_GRAVITY_HINT,
   PROP_MATRIX,
   PROP_ROUND_GLYPH_POSITIONS,
+  PROP_PALETTE,
   N_PROPERTIES
 };
 
@@ -88,6 +89,7 @@ pango2_context_init (Pango2Context *context)
   context->language = pango2_language_get_default ();
   context->font_map = NULL;
   context->round_glyph_positions = TRUE;
+  context->palette = g_quark_from_static_string (PANGO2_COLOR_PALETTE_NORMAL);
 
   context->font_desc = pango2_font_description_new ();
   pango2_font_description_set_family_static (context->font_desc, "serif");
@@ -140,6 +142,10 @@ pango2_context_set_property (GObject      *object,
       pango2_context_set_round_glyph_positions (context, g_value_get_boolean (value));
       break;
 
+    case PROP_PALETTE:
+      pango2_context_set_color_palette (context, g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -187,6 +193,10 @@ pango2_context_get_property (GObject    *object,
       g_value_set_boolean (value, pango2_context_get_round_glyph_positions (context));
       break;
 
+    case PROP_PALETTE:
+      g_value_set_string (value, pango2_context_get_color_palette (context));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -197,6 +207,10 @@ pango2_context_class_init (Pango2ContextClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  g_intern_static_string (PANGO2_COLOR_PALETTE_NORMAL);
+  g_intern_static_string (PANGO2_COLOR_PALETTE_LIGHT);
+  g_intern_static_string (PANGO2_COLOR_PALETTE_DARK);
+
   object_class->finalize = pango2_context_finalize;
   object_class->set_property = pango2_context_set_property;
   object_class->get_property = pango2_context_get_property;
@@ -303,15 +317,22 @@ pango2_context_class_init (Pango2ContextClass *klass)
     g_param_spec_boolean ("round-glyph-positions", NULL, NULL, TRUE,
                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * Pango2Context:palette: (attributes org.gtk.Property.get=pango2_context_get_palette 
org.gtk.Property.set=pango2_context_set_palette)
+   *
+   * The name of the palette to use for color fonts.
+   */
+  properties[PROP_PALETTE] =
+    g_param_spec_string ("palette", NULL, NULL, "normal",
+                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
 }
 
 static void
 pango2_context_finalize (GObject *object)
 {
-  Pango2Context *context;
-
-  context = PANGO2_CONTEXT (object);
+  Pango2Context *context = PANGO2_CONTEXT (object);
 
   if (context->font_map)
     g_object_unref (context->font_map);
@@ -1044,3 +1065,52 @@ pango2_context_get_round_glyph_positions (Pango2Context *context)
 {
   return context->round_glyph_positions;
 }
+
+/**
+ * pango2_context_set_color_palette:
+ * @context: a `Pango2Context`
+ * @palette: the name of the palette to use
+ *
+ * Sets the palette to use for color fonts.
+ *
+ * This can either be one of the predefined names
+ * "normal", "light" or "dark", or a custom name.
+ *
+ * Some color fonts include metadata that indicates
+ * the default palette, as well as palettes that work
+ * well on light or dark backgrounds. The predefined
+ * names select those.
+ */
+void
+pango2_context_set_color_palette (Pango2Context *context,
+                                  const char    *palette)
+{
+  GQuark quark;
+
+  g_return_if_fail (PANGO2_IS_CONTEXT (context));
+
+  quark = g_quark_from_string (palette);
+  if (context->palette == quark)
+    return;
+
+  context->palette = quark;
+  g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_PALETTE]);
+}
+
+/**
+ * pango2_context_get_color_palette:
+ * @context: a `Pango2Context`
+ *
+ * Returns the palette to use for color fonts.
+ *
+ * See [method@Pango2.Context.set_color_palette].
+ *
+ * Return value: (nullable): the palette name
+ */
+const char *
+pango2_context_get_color_palette (Pango2Context *context)
+{
+  g_return_val_if_fail (PANGO2_IS_CONTEXT (context), PANGO2_COLOR_PALETTE_NORMAL);
+
+  return g_quark_to_string (context->palette);
+}
diff --git a/pango2/pango-context.h b/pango2/pango-context.h
index 902e840dc..d9746d725 100644
--- a/pango2/pango-context.h
+++ b/pango2/pango-context.h
@@ -99,4 +99,12 @@ void                     pango2_context_set_round_glyph_positions (Pango2Context
 PANGO2_AVAILABLE_IN_ALL
 gboolean                 pango2_context_get_round_glyph_positions (Pango2Context                 *context);
 
+PANGO2_AVAILABLE_IN_ALL
+void                     pango2_context_set_color_palette         (Pango2Context                 *context,
+                                                                   const char                    *palette);
+PANGO2_AVAILABLE_IN_ALL
+const char *             pango2_context_get_color_palette         (Pango2Context                 *context);
+
+
+
 G_END_DECLS
diff --git a/pango2/pango-font-description-private.h b/pango2/pango-font-description-private.h
index 11b09d00d..231a28007 100644
--- a/pango2/pango-font-description-private.h
+++ b/pango2/pango-font-description-private.h
@@ -28,6 +28,8 @@ gboolean pango2_font_description_is_similar       (const Pango2FontDescription *
 int      pango2_font_description_compute_distance (const Pango2FontDescription *a,
                                                    const Pango2FontDescription *b);
 
+GQuark   pango2_font_description_get_palette_quark (const Pango2FontDescription *desc);
+
 gboolean pango2_parse_style              (const char    *str,
                                           Pango2Style   *style,
                                           gboolean       warn);
diff --git a/pango2/pango-font-description.c b/pango2/pango-font-description.c
index 20421c893..cc9aedab9 100644
--- a/pango2/pango-font-description.c
+++ b/pango2/pango-font-description.c
@@ -39,6 +39,8 @@ struct _Pango2FontDescription
   char *variations;
   char *faceid;
 
+  GQuark palette;
+
   guint16 mask;
   guint static_family : 1;
   guint static_variations : 1;
@@ -61,6 +63,7 @@ static const Pango2FontDescription pfd_defaults = {
   0,                    /* size */
   NULL,                 /* variations */
   NULL,                 /* faceid */
+  0,                    /* palette */
 
   0,                    /* mask */
   0,                    /* static_family */
@@ -733,6 +736,8 @@ pango2_font_description_merge_static (Pango2FontDescription       *desc,
     pango2_font_description_set_variations_static (desc, desc_to_merge->variations);
   if (new_mask & PANGO2_FONT_MASK_FACEID)
     pango2_font_description_set_faceid_static (desc, desc_to_merge->faceid);
+  if (new_mask & PANGO2_FONT_MASK_PALETTE)
+    desc->palette = desc_to_merge->palette;
 
   desc->mask |= new_mask;
 }
@@ -872,7 +877,8 @@ pango2_font_description_equal (const Pango2FontDescription *desc1,
          (desc1->family_name == desc2->family_name ||
           (desc1->family_name && desc2->family_name && g_ascii_strcasecmp (desc1->family_name, 
desc2->family_name) == 0)) &&
          (g_strcmp0 (desc1->variations, desc2->variations) == 0) &&
-         (g_strcmp0 (desc1->faceid, desc2->faceid) == 0);
+         (g_strcmp0 (desc1->faceid, desc2->faceid) == 0) &&
+         desc1->palette == desc2->palette;
 }
 
 #define TOLOWER(c) \
@@ -924,6 +930,7 @@ pango2_font_description_hash (const Pango2FontDescription *desc)
   hash ^= desc->weight << 16;
   hash ^= desc->stretch << 26;
   hash ^= desc->gravity << 28;
+  hash ^= desc->palette;
 
   return hash;
 }
@@ -1184,6 +1191,46 @@ parse_size (const char *word,
   return FALSE;
 }
 
+static gboolean
+parse_palette (const char  *word,
+               size_t       wordlen,
+               GQuark      *palette)
+{
+  const char *p, *q;
+  char *s;
+
+  if (!g_str_has_prefix (word, "@palette="))
+    return FALSE;
+
+  p = word + strlen ("@palette=");
+  q = word + wordlen;
+  s = g_strndup (p, q - p);
+
+  *palette = g_quark_from_string (s);
+
+  g_free (s);
+
+  return TRUE;
+}
+
+static gboolean
+parse_faceid (const char  *word,
+              size_t       wordlen,
+              char       **faceid)
+{
+  const char *p, *q;
+
+  if (!g_str_has_prefix (word, "@faceid="))
+    return FALSE;
+
+  p = word + strlen ("@faceid=");
+  q = word + wordlen;
+
+  *faceid = g_strndup (p, q - p);
+
+  return TRUE;
+}
+
 static gboolean
 parse_variations (const char  *word,
                   size_t       wordlen,
@@ -1201,40 +1248,6 @@ parse_variations (const char  *word,
   return TRUE;
 }
 
-static void
-faceid_from_variations (Pango2FontDescription *desc)
-{
-  const char *p, *q;
-
-  p = desc->variations;
-
-  if (g_str_has_prefix (p, "faceid="))
-    {
-      p += strlen ("faceid=");
-      q = strchr (p, ',');
-      if (q)
-        {
-          desc->faceid = g_strndup (p, q - p);
-          p = q + 1;
-        }
-      else
-        {
-          desc->faceid = g_strdup (p);
-          p = NULL;
-        }
-      desc->mask |= PANGO2_FONT_MASK_FACEID;
-    }
-
-  if (p != desc->variations)
-    {
-      char *variations = g_strdup (p);
-      g_free (desc->variations);
-      desc->variations = variations;
-      if (variations == NULL || *variations == '\0')
-        desc->mask &= ~PANGO2_FONT_MASK_VARIATIONS;
-    }
-}
-
 /**
  * pango2_font_description_from_string:
  * @str: string representation of a font description.
@@ -1243,15 +1256,30 @@ faceid_from_variations (Pango2FontDescription *desc)
  *
  * The string must have the form
  *
- *     "\[FAMILY-LIST] \[STYLE-OPTIONS] \[SIZE] \[VARIATIONS]",
+ *     "\[FAMILY-LIST] \[STYLE-OPTIONS] \[SIZE] \[VARIATIONS] \[FACEID] \[PALETTE]",
  *
  * where FAMILY-LIST is a comma-separated list of families optionally
  * terminated by a comma, STYLE_OPTIONS is a whitespace-separated list
  * of words where each word describes one of style, variant, weight,
  * stretch, or gravity, and SIZE is a decimal number (size in points)
  * or optionally followed by the unit modifier "px" for absolute size.
+ *
  * VARIATIONS is a comma-separated list of font variation
- * specifications of the form "\@axis=value" (the = sign is optional).
+ * specifications of the form "\@axis=value" (the = sign is optional),
+ * where "axis" is a 3-character name of an OpenType variation axis
+ * like "wght", "wdth" or "opsz".
+ *
+ * FACEID must have the form "\@faceid=string" with the literal string
+ * "faceid".
+ *
+ * PALETTE must have the form "\@palette=name" with the literal string
+ * "palette", and the name of a color palette. The name can either be
+ * one of the standard names "normal", "light" or "dark", or a custom
+ * name. See [method@Pango2.HbFace.new_synthetic] for information on
+ * how to associate custom names with palettes in the font.
+ *
+ * The VARIATION, FACEID and PALETTE parts can appear in any order,
+ * as long as they are at the end.
  *
  * The following words are understood as styles:
  * "Normal", "Roman", "Oblique", "Italic".
@@ -1304,18 +1332,39 @@ pango2_font_description_from_string (const char *str)
 
   len = strlen (str);
   last = str + len;
-  p = getword (str, last, &wordlen, "");
-  /* Look for variations at the end of the string */
-  if (wordlen != 0)
+
+  do
     {
-      if (parse_variations (p, wordlen, &desc->variations))
+      p = getword (str, last, &wordlen, "");
+
+      if (wordlen == 0 || p[0] != '@')
+        break;
+
+      /* Look for palettes, faceid and variations at the end of the string */
+      if (parse_palette (p, wordlen, &desc->palette))
+        {
+          desc->mask |= PANGO2_FONT_MASK_PALETTE;
+          last = p;
+        }
+      else if (parse_faceid (p, wordlen, &desc->faceid))
+        {
+          desc->mask |= PANGO2_FONT_MASK_FACEID;
+          last = p;
+        }
+      else if (parse_variations (p, wordlen, &desc->variations))
         {
           desc->mask |= PANGO2_FONT_MASK_VARIATIONS;
           last = p;
-
-          faceid_from_variations (desc);
         }
+      else
+        break;
     }
+  while ((desc->mask & (PANGO2_FONT_MASK_PALETTE |
+                        PANGO2_FONT_MASK_FACEID |
+                        PANGO2_FONT_MASK_VARIATIONS)) !=
+                       (PANGO2_FONT_MASK_PALETTE |
+                        PANGO2_FONT_MASK_FACEID |
+                        PANGO2_FONT_MASK_VARIATIONS));
 
   p = getword (str, last, &wordlen, ",");
   /* Look for a size */
@@ -1428,7 +1477,6 @@ char *
 pango2_font_description_to_string (const Pango2FontDescription *desc)
 {
   GString *result;
-  gboolean in_variations = FALSE;
 
   g_return_val_if_fail (desc != NULL, NULL);
 
@@ -1488,18 +1536,20 @@ pango2_font_description_to_string (const Pango2FontDescription *desc)
 
   if (desc->mask & PANGO2_FONT_MASK_FACEID)
     {
-      in_variations = TRUE;
       g_string_append (result, " @");
       g_string_append_printf (result, "faceid=%s", desc->faceid);
     }
 
+  if (desc->mask & PANGO2_FONT_MASK_PALETTE)
+    {
+      g_string_append (result, " @");
+      g_string_append_printf (result, "palette=%s", g_quark_to_string (desc->palette));
+    }
+
   if ((desc->variations && desc->mask & PANGO2_FONT_MASK_VARIATIONS) &&
       desc->variations[0] != '\0')
     {
-      if (!in_variations)
-        g_string_append (result, " @");
-      else
-        g_string_append (result, ",");
+      g_string_append (result, " @");
       g_string_append (result, desc->variations);
     }
 
@@ -1741,3 +1791,56 @@ pango2_font_description_get_faceid (const Pango2FontDescription *desc)
 
   return desc->faceid;
 }
+
+/**
+ * pango2_font_description_set_palette:
+ * @palette: the name of the palette
+ *
+ * Sets the palette field of a font description.
+ *
+ * Predefined palette names are "normal", "light" and "dark".
+ * Other names can be associated with palettes when constructing
+ * [class@Pango2.HbFace] objects.
+ */
+void
+pango2_font_description_set_palette (Pango2FontDescription *desc,
+                                     const char            *palette)
+{
+  g_return_if_fail (desc != NULL);
+
+  desc->palette = g_quark_from_string (palette);
+  desc->mask |= PANGO2_FONT_MASK_PALETTE;
+}
+
+/**
+ * pango2_font_description_get_palette:
+ * @desc: a `Pango2FontDescription`
+ *
+ * Gets the palette field of a font description.
+ *
+ * Return value: (nullable): the palette field of the font description
+ */
+const char *
+pango2_font_description_get_palette (const Pango2FontDescription *desc)
+{
+  g_return_val_if_fail (desc != NULL, NULL);
+
+  if (desc->palette)
+    return g_quark_to_string (desc->palette);
+
+  return NULL;
+}
+
+/*< private >
+ * pango2_font_description_get_palette_quark:
+ * @desc: a `Pango2FontDescription
+ *
+ * Gets the palette field as a `GQuark`.
+ *
+ * Return value: the palette field as a quark
+ */
+GQuark
+pango2_font_description_get_palette_quark (const Pango2FontDescription *desc)
+{
+  return desc->palette;
+}
diff --git a/pango2/pango-font-description.h b/pango2/pango-font-description.h
index 160ee50dc..a8fbcc458 100644
--- a/pango2/pango-font-description.h
+++ b/pango2/pango-font-description.h
@@ -171,6 +171,7 @@ typedef enum {
   PANGO2_FONT_MASK_GRAVITY    = 1 << 6,
   PANGO2_FONT_MASK_VARIATIONS = 1 << 7,
   PANGO2_FONT_MASK_FACEID     = 1 << 8,
+  PANGO2_FONT_MASK_PALETTE    = 1 << 9,
 } Pango2FontMask;
 
 /* CSS scale factors (1.2 factor between each size) */
@@ -298,6 +299,12 @@ void                    pango2_font_description_set_faceid_static (Pango2FontDes
 PANGO2_AVAILABLE_IN_ALL
 const char *            pango2_font_description_get_faceid        (const Pango2FontDescription *desc) 
G_GNUC_PURE;
 
+PANGO2_AVAILABLE_IN_ALL
+void                    pango2_font_description_set_palette       (Pango2FontDescription *desc,
+                                                                   const char            *palette);
+PANGO2_AVAILABLE_IN_ALL
+const char *            pango2_font_description_get_palette       (const Pango2FontDescription *desc) 
G_GNUC_PURE;
+
 PANGO2_AVAILABLE_IN_ALL
 Pango2FontMask          pango2_font_description_get_set_fields    (const Pango2FontDescription *desc) 
G_GNUC_PURE;
 PANGO2_AVAILABLE_IN_ALL
diff --git a/pango2/pango-font-private.h b/pango2/pango-font-private.h
index ca8d3a775..4278be5f5 100644
--- a/pango2/pango-font-private.h
+++ b/pango2/pango-font-private.h
@@ -42,6 +42,7 @@ struct _Pango2Font
   Pango2Gravity gravity;
   Pango2Matrix ctm;
 
+  GQuark palette;
 #ifdef HAVE_CAIRO
   cairo_font_options_t *options;
 #endif
@@ -107,6 +108,13 @@ pango2_font_set_ctm (Pango2Font         *font,
   font->ctm = ctm ? *ctm : matrix_init;
 }
 
+static inline void
+pango2_font_set_color_palette (Pango2Font *font,
+                               GQuark      palette)
+{
+  font->palette = palette;
+}
+
 gboolean pango2_font_is_hinted         (Pango2Font  *font);
 void     pango2_font_get_scale_factors (Pango2Font  *font,
                                         double      *x_scale,
@@ -114,12 +122,6 @@ void     pango2_font_get_scale_factors (Pango2Font  *font,
 void     pango2_font_get_transform     (Pango2Font  *font,
                                        Pango2Matrix *matrix);
 
-gboolean pango2_font_description_is_similar       (const Pango2FontDescription *a,
-                                                   const Pango2FontDescription *b);
-
-int      pango2_font_description_compute_distance (const Pango2FontDescription *a,
-                                                   const Pango2FontDescription *b);
-
 /* We use these values in a few places as a fallback size for an
  * unknown glyph, if we have no better information.
  */
diff --git a/pango2/pango-fontmap.c b/pango2/pango-fontmap.c
index 32dcd9286..b5fe3bcbb 100644
--- a/pango2/pango-fontmap.c
+++ b/pango2/pango-fontmap.c
@@ -34,7 +34,7 @@
 #include "pango-fontset.h"
 #include "pango-font-face-private.h"
 #include "pango-trace-private.h"
-#include "pango-context.h"
+#include "pango-context-private.h"
 
 #ifdef HAVE_CORE_TEXT
 #include "pangocoretext-fontmap.h"
@@ -167,6 +167,7 @@ pango2_fontset_cached_hash (const Pango2FontsetCached *fontset)
 
   return (hash ^
           GPOINTER_TO_UINT (fontset->language) ^
+          fontset->palette ^
 #ifdef HAVE_CAIRO
           cairo_font_options_hash (fontset->font_options) ^
 #endif
@@ -178,6 +179,7 @@ pango2_fontset_cached_equal (const Pango2FontsetCached *a,
                              const Pango2FontsetCached *b)
 {
   return a->language == b->language &&
+         a->palette == b->palette &&
 #ifdef HAVE_CAIRO
          cairo_font_options_equal (a->font_options, b->font_options) &&
 #endif
@@ -547,6 +549,8 @@ pango2_font_map_default_load_fontset (Pango2FontMap               *self,
   lookup.language = language;
   lookup.description = (Pango2FontDescription *)description;
   lookup.ctm = ctm;
+  lookup.palette = context->palette;
+
 #ifdef HAVE_CAIRO
   lookup.font_options = (cairo_font_options_t *)pango2_cairo_context_get_merged_font_options (context);
 #endif
@@ -556,6 +560,7 @@ pango2_font_map_default_load_fontset (Pango2FontMap               *self,
     goto done;
 
   fontset = pango2_fontset_cached_new (description, language, self->dpi, ctm);
+  fontset->palette = context->palette;
 #ifdef HAVE_CAIRO
   fontset->font_options = cairo_font_options_copy (pango2_cairo_context_get_merged_font_options (context));
 #endif
diff --git a/pango2/pango-fontset-cached-private.h b/pango2/pango-fontset-cached-private.h
index 95059a791..c1c74f5f0 100644
--- a/pango2/pango-fontset-cached-private.h
+++ b/pango2/pango-fontset-cached-private.h
@@ -44,6 +44,7 @@ struct _Pango2FontsetCached
   GList cache_link;
   GHashTable *cache;
 
+  GQuark palette;
 #ifdef HAVE_CAIRO
   cairo_font_options_t *font_options;
 #endif
diff --git a/pango2/pango-fontset-cached.c b/pango2/pango-fontset-cached.c
index 9feaca795..b9dd8c23c 100644
--- a/pango2/pango-fontset-cached.c
+++ b/pango2/pango-fontset-cached.c
@@ -26,7 +26,9 @@
 #include "pango-fontset-cached-private.h"
 #include "pango-font-private.h"
 #include "pango-font-face-private.h"
+#include "pango-font-description-private.h"
 #include "pango-generic-family-private.h"
+#include "pango-context.h"
 
 #ifdef HAVE_CAIRO
 #include "pangocairo-font.h"
@@ -40,6 +42,7 @@ pango2_fontset_cached_init (Pango2FontsetCached *fontset)
   fontset->items = g_ptr_array_new_with_free_func (g_object_unref);
   fontset->cache = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
   fontset->language = NULL;
+  fontset->palette = g_quark_from_static_string ("normal");
 #ifdef HAVE_CAIRO
   fontset->font_options = NULL;
 #endif
@@ -81,6 +84,27 @@ find_font_for_face (Pango2FontsetCached *self,
   return NULL;
 }
 
+static Pango2Font *
+create_font_for_face (Pango2FontsetCached *self,
+                      Pango2FontFace      *face)
+{
+  Pango2Font *font;
+
+  font = pango2_font_face_create_font (face,
+                                       self->description,
+                                       self->dpi,
+                                       self->ctm);
+  if (pango2_font_description_get_set_fields  (self->description) & PANGO2_FONT_MASK_PALETTE)
+    pango2_font_set_color_palette (font, pango2_font_description_get_palette_quark (self->description));
+  else
+    pango2_font_set_color_palette (font, self->palette);
+#ifdef HAVE_CAIRO
+  pango2_cairo_font_set_font_options (font, self->font_options);
+#endif
+
+  return font;
+}
+
 static Pango2Font *
 pango2_fontset_cached_get_font (Pango2Fontset *fontset,
                                 guint          wc)
@@ -129,19 +153,9 @@ pango2_fontset_cached_get_font (Pango2Fontset *fontset,
 
               font = find_font_for_face (self, face);
               if (font)
-                {
-                  retval = g_object_ref (font);
-                }
+                retval = g_object_ref (font);
               else
-                {
-                  retval = pango2_font_face_create_font (face,
-                                                         self->description,
-                                                         self->dpi,
-                                                         self->ctm);
-#ifdef HAVE_CAIRO
-                  pango2_cairo_font_set_font_options (retval, self->font_options);
-#endif
-                }
+                retval = create_font_for_face (self, face);
               break;
             }
         }
@@ -175,15 +189,7 @@ pango2_fontset_cached_get_first_font (Pango2FontsetCached *self)
       if (font)
         g_object_ref (font);
       else
-        {
-          font = pango2_font_face_create_font (face,
-                                               self->description,
-                                               self->dpi,
-                                               self->ctm);
-#ifdef HAVE_CAIRO
-          pango2_cairo_font_set_font_options (font, self->font_options);
-#endif
-        }
+        font = find_font_for_face (self, face);
 
       return font;
     }
@@ -249,15 +255,7 @@ pango2_fontset_cached_foreach (Pango2Fontset            *fontset,
           if (font)
             g_object_ref (font);
           else
-            {
-              font = pango2_font_face_create_font (face,
-                                                   self->description,
-                                                   self->dpi,
-                                                   self->ctm);
-#ifdef HAVE_CAIRO
-              pango2_cairo_font_set_font_options (font, self->font_options);
-#endif
-            }
+            font = create_font_for_face (self, face);
         }
 
       if ((*func) (fontset, font, data))
@@ -304,16 +302,7 @@ void
 pango2_fontset_cached_add_face (Pango2FontsetCached *self,
                                 Pango2FontFace      *face)
 {
-  Pango2Font *font;
-
-  font = pango2_font_face_create_font (face,
-                                       self->description,
-                                       self->dpi,
-                                       self->ctm);
-#ifdef HAVE_CAIRO
-  pango2_cairo_font_set_font_options (font, self->font_options);
-#endif
-  g_ptr_array_add (self->items, font);
+  g_ptr_array_add (self->items, create_font_for_face (self, face));
 }
 
 void
diff --git a/pango2/pango-hbface-private.h b/pango2/pango-hbface-private.h
index e29203887..703ab72cf 100644
--- a/pango2/pango-hbface-private.h
+++ b/pango2/pango-hbface-private.h
@@ -23,6 +23,7 @@
 #include "pango-font-face-private.h"
 #include "pango-fontmap.h"
 #include "pango-language-set-private.h"
+#include "pango-color-palette.h"
 #include <hb.h>
 
 struct _Pango2HbFace
@@ -41,6 +42,8 @@ struct _Pango2HbFace
   Pango2LanguageSet *languages;
   gboolean embolden;
   gboolean synthetic;
+  Pango2ColorPalette *palettes;
+  unsigned int n_palettes;
 };
 
 Pango2LanguageSet *     pango2_hb_face_get_language_set  (Pango2HbFace          *self);
@@ -50,3 +53,6 @@ void                    pango2_hb_face_set_language_set  (Pango2HbFace
 
 void                    pango2_hb_face_set_matrix        (Pango2HbFace          *self,
                                                           const Pango2Matrix    *matrix);
+
+unsigned int            pango2_hb_face_get_palette_index (Pango2HbFace          *self,
+                                                          GQuark                 palette);
diff --git a/pango2/pango-hbface.c b/pango2/pango-hbface.c
index dbe68e176..65dbb51e5 100644
--- a/pango2/pango-hbface.c
+++ b/pango2/pango-hbface.c
@@ -23,6 +23,7 @@
 #include "pango-font-private.h"
 #include "pango-hbface-private.h"
 #include "pango-hbfont.h"
+#include "pango-color-palette-private.h"
 
 #include "pango-language-set-simple-private.h"
 
@@ -48,6 +49,21 @@
 
  /* {{{ Utilities */
 
+static struct {
+  GQuark name;
+  hb_ot_color_palette_flags_t flag;
+} default_palettes[3];
+
+static void
+init_default_palettes (void)
+{
+  default_palettes[0].name = g_quark_from_static_string (PANGO2_COLOR_PALETTE_NORMAL);
+  default_palettes[0].flag = HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
+  default_palettes[1].name = g_quark_from_static_string (PANGO2_COLOR_PALETTE_LIGHT);
+  default_palettes[1].flag = HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND;
+  default_palettes[2].name = g_quark_from_static_string (PANGO2_COLOR_PALETTE_DARK);
+  default_palettes[2].flag = HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND;
+};
 static void
 get_name_from_hb_face (hb_face_t       *face,
                        hb_ot_name_id_t  name_id,
@@ -314,6 +330,7 @@ pango2_hb_face_finalize (GObject *object)
 {
   Pango2HbFace *self = PANGO2_HB_FACE (object);
 
+  g_free (self->palettes);
   g_free (self->faceid);
   if (self->face)
     hb_face_destroy (self->face);
@@ -483,6 +500,8 @@ pango2_hb_face_class_init (Pango2HbFaceClass *class)
   GObjectClass *object_class = G_OBJECT_CLASS (class);
   Pango2FontFaceClass *face_class = PANGO2_FONT_FACE_CLASS (class);
 
+  init_default_palettes ();
+
   object_class->finalize = pango2_hb_face_finalize;
   object_class->get_property = pango2_hb_face_get_property;
 
@@ -627,6 +646,44 @@ pango2_hb_face_set_matrix (Pango2HbFace       *self,
   pango2_matrix_scale (self->transform, 1./self->x_scale, 1./self->y_scale);
 }
 
+static unsigned int
+find_palette_index_by_flag (hb_face_t                   *hbface,
+                            hb_ot_color_palette_flags_t  flag)
+{
+  for (unsigned int i = 0; i < hb_ot_color_palette_get_count (hbface); i++)
+    {
+      if (hb_ot_color_palette_get_flags (hbface, i) & flag)
+        return i;
+    }
+
+  return 0;
+}
+
+unsigned int
+pango2_hb_face_get_palette_index (Pango2HbFace *self,
+                                  GQuark        palette)
+{
+
+  for (unsigned int i = 0; i < self->n_palettes; i++)
+    {
+      if (self->palettes[i].name == palette)
+        return self->palettes[i].index;
+    }
+
+  ensure_hb_face (self);
+
+  if (hb_ot_color_has_palettes (self->face))
+    {
+      for (unsigned int i = 0; i < G_N_ELEMENTS (default_palettes); i++)
+        {
+          if (palette == default_palettes[i].name)
+            return find_palette_index_by_flag (self->face, default_palettes[i].flag);
+        }
+    }
+
+  return 0;
+}
+
 /* }}} */
   /* {{{ Public API */
 
@@ -896,6 +953,8 @@ struct _Pango2HbFaceBuilder {
   unsigned int n_variations;
   char *name;
   Pango2FontDescription *description;
+  Pango2ColorPalette *palettes;
+  unsigned int n_palettes;
 };
 
 G_DEFINE_BOXED_TYPE (Pango2HbFaceBuilder, pango2_hb_face_builder,
@@ -917,6 +976,8 @@ face_builder_new (void)
   builder->n_variations = 0;
   builder->name = NULL;
   builder->description = NULL;
+  builder->palettes = NULL;
+  builder->n_palettes = 0;
 
   return builder;
 }
@@ -947,6 +1008,8 @@ pango2_hb_face_builder_copy (const Pango2HbFaceBuilder *src)
   builder->name = g_strdup (src->name);
   if (src->description)
     builder->description = pango2_font_description_copy_static (src->description);
+  builder->palettes = g_memdup2 (src->palettes, sizeof (Pango2ColorPalette) * src->n_palettes);
+  builder->n_palettes = src->n_palettes;
 
   return builder;
 }
@@ -969,6 +1032,7 @@ pango2_hb_face_builder_free (Pango2HbFaceBuilder *builder)
   g_free (builder->name);
   if (builder->description)
     pango2_font_description_free (builder->description);
+  g_free (builder->palettes);
 
   g_free (builder);
 }
@@ -1025,6 +1089,8 @@ pango2_hb_face_builder_new (Pango2HbFace *face)
   builder->n_variations = face->n_variations;
   builder->name = g_strdup (font_face->name);
   builder->description = pango2_font_description_copy_static (font_face->description);
+  builder->palettes = g_memdup2 (face->palettes, sizeof (Pango2ColorPalette) * face->n_palettes);
+  builder->n_palettes = face->n_palettes;
 
   return builder;
 }
@@ -1070,6 +1136,9 @@ pango2_hb_face_builder_get_face (Pango2HbFaceBuilder *builder)
 
   set_name_and_description (self, builder->name, builder->description);
 
+  self->palettes = g_memdup2 (builder->palettes, sizeof (Pango2ColorPalette) * builder->n_palettes);
+  self->n_palettes = builder->n_palettes;
+
   return self;
 }
 
@@ -1189,6 +1258,25 @@ pango2_hb_face_builder_set_variations (Pango2HbFaceBuilder  *builder,
   builder->n_variations = n_variations;
 }
 
+/**
+ * pango2_hb_face_builder_set_palettes:
+ * @builder: a `Pango2HbFaceBuilder`
+ * @palettes: (nullable) (array length=n_palettes): array of `Pango2ColorPalette`s to apply
+ * @n_palettes: length of @palettes
+ *
+ * Sets palettes to use for the face.
+ */
+void
+pango2_hb_face_builder_set_palettes (Pango2HbFaceBuilder *builder,
+                                     Pango2ColorPalette  *palettes[],
+                                     unsigned int         n_palettes)
+{
+  g_free (builder->palettes);
+  builder->palettes = g_new (Pango2ColorPalette, n_palettes);
+  for (int i = 0; i < n_palettes; i++)
+    builder->palettes[i] = *(palettes[i]);
+}
+
 /* }}} */
 
 /* vim:set foldmethod=marker expandtab: */
diff --git a/pango2/pango-hbface.h b/pango2/pango-hbface.h
index b110ff99e..072667028 100644
--- a/pango2/pango-hbface.h
+++ b/pango2/pango-hbface.h
@@ -21,6 +21,7 @@
 
 #include <pango2/pango-types.h>
 #include <pango2/pango-font-face.h>
+#include <pango2/pango-color-palette.h>
 
 #include <hb.h>
 
@@ -108,5 +109,9 @@ PANGO2_AVAILABLE_IN_ALL
 void                    pango2_hb_face_builder_set_variations   (Pango2HbFaceBuilder         *builder,
                                                                  const hb_variation_t        *variations,
                                                                  unsigned int                 n_variations);
+PANGO2_AVAILABLE_IN_ALL
+void                    pango2_hb_face_builder_set_palettes     (Pango2HbFaceBuilder         *builder,
+                                                                 Pango2ColorPalette          *palettes[],
+                                                                 unsigned int                 n_palettes);
 
 G_END_DECLS
diff --git a/pango2/pango-hbfont.c b/pango2/pango-hbfont.c
index a88762247..326c2def8 100644
--- a/pango2/pango-hbfont.c
+++ b/pango2/pango-hbfont.c
@@ -215,7 +215,7 @@ count_variations (const char *string)
 
   n = 1;
   p = string;
-  while ((p = strchr (p, ',')) != NULL)
+  while ((p = strchr (p + 1, ',')) != NULL)
     n++;
 
   return n;
diff --git a/pango2/pango.h b/pango2/pango.h
index f3486c4d8..a6dd892cc 100644
--- a/pango2/pango.h
+++ b/pango2/pango.h
@@ -25,6 +25,7 @@
 #include <pango2/pango-attributes.h>
 #include <pango2/pango-break.h>
 #include <pango2/pango-color.h>
+#include <pango2/pango-color-palette.h>
 #include <pango2/pango-context.h>
 #include <pango2/pango-direction.h>
 #include <pango2/pango-enum-types.h>
diff --git a/pango2/pangocairo-font.c b/pango2/pangocairo-font.c
index b9103d977..cb1dc83ca 100644
--- a/pango2/pangocairo-font.c
+++ b/pango2/pangocairo-font.c
@@ -24,6 +24,8 @@
 #include <math.h>
 #include <string.h>
 
+#include <hb-ot.h>
+
 #include "pangocairo.h"
 #include "pangocairo-private.h"
 #include "pango-font-private.h"
@@ -92,10 +94,22 @@ create_cairo_font_face (Pango2Font *font)
   return NULL;
 }
 
+static int
+find_palette_index_for_font (Pango2Font *font)
+{
+  Pango2FontFace *face = pango2_font_get_face (font);
+
+  if (PANGO2_IS_HB_FACE (face))
+    return pango2_hb_face_get_palette_index (PANGO2_HB_FACE (face), font->palette);
+
+  return CAIRO_COLOR_PALETTE_DEFAULT;
+}
+
 static cairo_scaled_font_t *
 _pango2_cairo_font_private_get_scaled_font (Pango2CairoFontPrivate *cf_priv)
 {
   cairo_font_face_t *font_face;
+  cairo_font_options_t *options;
 
   if (G_LIKELY (cf_priv->scaled_font))
     return cf_priv->scaled_font;
@@ -113,10 +127,17 @@ _pango2_cairo_font_private_get_scaled_font (Pango2CairoFontPrivate *cf_priv)
   if (G_UNLIKELY (font_face == NULL))
     goto done;
 
+  options = cairo_font_options_copy (cf_priv->data->options);
+  if (cairo_font_options_get_color_palette (options) == CAIRO_COLOR_PALETTE_DEFAULT)
+    cairo_font_options_set_color_palette (options,
+                                          find_palette_index_for_font (cf_priv->cfont));
+
   cf_priv->scaled_font = cairo_scaled_font_create (font_face,
                                                    &cf_priv->data->font_matrix,
                                                    &cf_priv->data->ctm,
-                                                   cf_priv->data->options);
+                                                   options);
+
+  cairo_font_options_destroy (options);
 
   cairo_font_face_destroy (font_face);
 
diff --git a/tests/test-font.c b/tests/test-font.c
index dd3ef1b54..19bebacf4 100644
--- a/tests/test-font.c
+++ b/tests/test-font.c
@@ -499,7 +499,7 @@ test_set_gravity (void)
 static void
 test_faceid (void)
 {
-  const char *test = "Cantarell Bold Italic 32 @faceid=Cantarell-Regular:0:-1:0,wght=600";
+  const char *test = "Cantarell Bold Italic 32 @faceid=Cantarell-Regular:0:-1:0 @wght=600";
   Pango2FontDescription *desc;
   char *s;
 
@@ -528,6 +528,72 @@ test_faceid (void)
   pango2_font_description_free (desc);
 }
 
+static void
+test_palette (void)
+{
+  const char *test = "Cantarell Bold Italic 32 @palette=light @wght=600";
+  Pango2FontDescription *desc;
+  char *s;
+
+  desc = pango2_font_description_from_string (test);
+  g_assert_cmpint (pango2_font_description_get_set_fields (desc), ==, PANGO2_FONT_MASK_FAMILY|
+                                                                     PANGO2_FONT_MASK_STYLE|
+                                                                     PANGO2_FONT_MASK_WEIGHT|
+                                                                     PANGO2_FONT_MASK_VARIANT|
+                                                                     PANGO2_FONT_MASK_STRETCH|
+                                                                     PANGO2_FONT_MASK_SIZE|
+                                                                     PANGO2_FONT_MASK_PALETTE|
+                                                                     PANGO2_FONT_MASK_VARIATIONS);
+  g_assert_cmpstr (pango2_font_description_get_family (desc), ==, "Cantarell");
+  g_assert_cmpint (pango2_font_description_get_size (desc), ==, 32 * PANGO2_SCALE);
+  g_assert_cmpint (pango2_font_description_get_style (desc), ==, PANGO2_STYLE_ITALIC);
+  g_assert_cmpint (pango2_font_description_get_variant (desc), ==, PANGO2_VARIANT_NORMAL);
+  g_assert_cmpint (pango2_font_description_get_weight (desc), ==, PANGO2_WEIGHT_BOLD);
+  g_assert_cmpint (pango2_font_description_get_stretch (desc), ==, PANGO2_STRETCH_NORMAL);
+  g_assert_cmpstr (pango2_font_description_get_palette (desc), ==, "light");
+  g_assert_cmpstr (pango2_font_description_get_variations (desc), ==, "wght=600");
+
+  s = pango2_font_description_to_string (desc);
+  g_assert_cmpstr (s, ==, test);
+  g_free (s);
+
+  pango2_font_description_free (desc);
+}
+
+static void
+test_all (void)
+{
+  const char *test = "Cantarell Bold Italic 32 @faceid=Cantarell-Regular:0:-1:0 @palette=dark @wght=600";
+  Pango2FontDescription *desc;
+  char *s;
+
+  desc = pango2_font_description_from_string (test);
+  g_assert_cmpint (pango2_font_description_get_set_fields (desc), ==, PANGO2_FONT_MASK_FAMILY|
+                                                                     PANGO2_FONT_MASK_STYLE|
+                                                                     PANGO2_FONT_MASK_WEIGHT|
+                                                                     PANGO2_FONT_MASK_VARIANT|
+                                                                     PANGO2_FONT_MASK_STRETCH|
+                                                                     PANGO2_FONT_MASK_SIZE|
+                                                                     PANGO2_FONT_MASK_PALETTE|
+                                                                     PANGO2_FONT_MASK_FACEID|
+                                                                     PANGO2_FONT_MASK_VARIATIONS);
+  g_assert_cmpstr (pango2_font_description_get_family (desc), ==, "Cantarell");
+  g_assert_cmpint (pango2_font_description_get_size (desc), ==, 32 * PANGO2_SCALE);
+  g_assert_cmpint (pango2_font_description_get_style (desc), ==, PANGO2_STYLE_ITALIC);
+  g_assert_cmpint (pango2_font_description_get_variant (desc), ==, PANGO2_VARIANT_NORMAL);
+  g_assert_cmpint (pango2_font_description_get_weight (desc), ==, PANGO2_WEIGHT_BOLD);
+  g_assert_cmpint (pango2_font_description_get_stretch (desc), ==, PANGO2_STRETCH_NORMAL);
+  g_assert_cmpstr (pango2_font_description_get_palette (desc), ==, "dark");
+  g_assert_cmpstr (pango2_font_description_get_faceid (desc), ==, "Cantarell-Regular:0:-1:0");
+  g_assert_cmpstr (pango2_font_description_get_variations (desc), ==, "wght=600");
+
+  s = pango2_font_description_to_string (desc);
+  g_assert_cmpstr (s, ==, test);
+  g_free (s);
+
+  pango2_font_description_free (desc);
+}
+
 static gboolean
 font_info_cb (Pango2UserFace     *face,
               int                size,
@@ -657,6 +723,8 @@ main (int argc, char *argv[])
   g_test_add_func ("/pango/fontdescription/empty-variations", test_empty_variations);
   g_test_add_func ("/pango/fontdescription/set-gravity", test_set_gravity);
   g_test_add_func ("/pango/fontdescription/faceid", test_faceid);
+  g_test_add_func ("/pango/fontdescription/palette", test_palette);
+  g_test_add_func ("/pango/fontdescription/all", test_all);
   g_test_add_func ("/pango/font/metrics", test_metrics);
   g_test_add_func ("/pango/font/extents", test_extents);
   g_test_add_func ("/pango/font/glyph-extents", test_glyph_extents);
diff --git a/utils/viewer-pangocairo.c b/utils/viewer-pangocairo.c
index d51b20552..e4b81ff6e 100644
--- a/utils/viewer-pangocairo.c
+++ b/utils/viewer-pangocairo.c
@@ -34,6 +34,7 @@
 static int opt_annotate = 0;
 static gboolean opt_userfont = 0;
 static char **opt_font_file = NULL;
+static char *opt_palette = NULL;
 
 typedef struct
 {
@@ -44,6 +45,7 @@ typedef struct
   Pango2FontMap *fontmap;
   cairo_font_options_t *font_options;
   gboolean subpixel_positions;
+  const char *palette;
 } CairoViewer;
 
 static gpointer
@@ -66,8 +68,8 @@ pangocairo_view_create (const Pango2Viewer *klass G_GNUC_UNUSED)
           Pango2FontFace *face;
 
           face = PANGO2_FONT_FACE (pango2_hb_face_new_from_file (opt_font_file[i],
-                                                               0, -1,
-                                                               NULL, NULL));
+                                                                 0, -1,
+                                                                 NULL, NULL));
 
           pango2_font_map_add_face (instance->fontmap, face);
 
@@ -119,6 +121,7 @@ pangocairo_view_create (const Pango2Viewer *klass G_GNUC_UNUSED)
     cairo_font_options_set_antialias (instance->font_options, (cairo_antialias_t)opt_antialias);
 
   instance->subpixel_positions = opt_subpixel_positions;
+  instance->palette = opt_palette;
 
   return instance;
 }
@@ -146,6 +149,7 @@ pangocairo_view_get_context (gpointer instance)
   context = pango2_context_new_with_font_map (c->fontmap);
   pango2_cairo_context_set_font_options (context, c->font_options);
   pango2_context_set_round_glyph_positions (context, !c->subpixel_positions);
+  pango2_context_set_color_palette (context, c->palette);
 
   return context;
 }
@@ -973,6 +977,7 @@ pangocairo_view_get_option_group (const Pango2Viewer *klass G_GNUC_UNUSED)
     {"annotate", 0, 0, G_OPTION_ARG_CALLBACK, parse_annotate_arg, annotate_arg_help, "FLAGS"},
     { "font-file", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_font_file, "Create a fontmap with this font", 
"FILE" },
     { "userfont", 0, 0, G_OPTION_ARG_NONE, &opt_userfont, "Add userfont" },
+    { "palette", 0, 0, G_OPTION_ARG_STRING, &opt_palette, "Preferred palette", "PALETTE" },
     {NULL}
   };
   GOptionGroup *group;


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