summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-07-01 09:57:35 -0400
committerMatthias Clasen <mclasen@redhat.com>2022-07-04 11:24:16 -0400
commit8ee5fe2707db5013dc53084ec1ac44e91b863f6d (patch)
tree1535b516d1df78b14be71ee84315a3318687d25c
parent9954891c66a241338cc48d2c2236b12dd2368572 (diff)
downloadpango-8ee5fe2707db5013dc53084ec1ac44e91b863f6d.tar.gz
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. Also add a palette attribute that can be used to override this. Make the cairo renderer pick up the palette, and apply it when installing the font for a run. Predefined palette names are "default", "light", "dark", "palette0", "palette1", ... Additionally, PangoHbFace can associate custom names with palette indices. To try this, use the new --palette option of pango-view. Fonts to try this with are Amiri Quran Colored or the Bungee Color family.
-rw-r--r--docs/pango_markup.md3
-rw-r--r--pango2/pango-attr-iterator.c3
-rw-r--r--pango2/pango-attr-list.c11
-rw-r--r--pango2/pango-attributes.c23
-rw-r--r--pango2/pango-attributes.h4
-rw-r--r--pango2/pango-color-palette-private.h25
-rw-r--r--pango2/pango-context-private.h2
-rw-r--r--pango2/pango-context.c81
-rw-r--r--pango2/pango-context.h8
-rw-r--r--pango2/pango-font-description-private.h2
-rw-r--r--pango2/pango-font-description.c117
-rw-r--r--pango2/pango-font-private.h6
-rw-r--r--pango2/pango-fontmap.c3
-rw-r--r--pango2/pango-fontset-cached.c64
-rw-r--r--pango2/pango-hbface-private.h9
-rw-r--r--pango2/pango-hbface.c180
-rw-r--r--pango2/pango-hbface.h7
-rw-r--r--pango2/pango-hbfont.c2
-rw-r--r--pango2/pango-markup.c10
-rw-r--r--pango2/pango-types.h23
-rw-r--r--pango2/pangocairo-font.c84
-rw-r--r--pango2/pangocairo-private.h25
-rw-r--r--pango2/pangocairo-render.c77
-rw-r--r--pango2/pangocairo-render.h5
-rw-r--r--pango2/serializer.c6
-rw-r--r--tests/test-font.c35
-rw-r--r--utils/viewer-pangocairo.c9
27 files changed, 680 insertions, 144 deletions
diff --git a/docs/pango_markup.md b/docs/pango_markup.md
index 587c4352..a33c04d6 100644
--- a/docs/pango_markup.md
+++ b/docs/pango_markup.md
@@ -108,6 +108,9 @@ font_features
: A comma-separated list of OpenType font feature settings, in the same syntax as
accepted by CSS. E.g: `font_features='dlig=1, -kern, afrc on'`.
+palette
+: The name of a palette to use.
+
foreground
fgcolor
color
diff --git a/pango2/pango-attr-iterator.c b/pango2/pango-attr-iterator.c
index 59bb1255..72a23c24 100644
--- a/pango2/pango-attr-iterator.c
+++ b/pango2/pango-attr-iterator.c
@@ -306,8 +306,7 @@ pango2_attr_iterator_get (Pango2AttrIterator *iterator,
* order to free this value, you must call
* [method@Pango2.Attribute.destroy] on each member.
*
- * Get the font and other attributes at the current
- * iterator position.
+ * Get the font and other attributes at the current iterator position.
*/
void
pango2_attr_iterator_get_font (Pango2AttrIterator *iterator,
diff --git a/pango2/pango-attr-list.c b/pango2/pango-attr-list.c
index fb0d2471..eae66d87 100644
--- a/pango2/pango-attr-list.c
+++ b/pango2/pango-attr-list.c
@@ -1253,6 +1253,17 @@ pango2_attr_list_from_string (const char *text)
INT_ATTR(line_spacing, int);
break;
+ case PANGO2_ATTR_PALETTE:
+ p++;
+ endp = strchr (p, '"');
+ if (!endp) goto fail;
+ str = g_strndup (p, endp - p);
+ attr = pango2_attr_palette_new (str);
+ g_free (str);
+ endp++;
+ if (!is_valid_end_char (*endp)) goto fail;
+ break;
+
case PANGO2_ATTR_SHAPE:
default:
g_assert_not_reached ();
diff --git a/pango2/pango-attributes.c b/pango2/pango-attributes.c
index 1318451f..2c72c9c0 100644
--- a/pango2/pango-attributes.c
+++ b/pango2/pango-attributes.c
@@ -564,7 +564,7 @@ pango2_attr_gravity_hint_new (Pango2GravityHint hint)
/**
* pango2_attr_font_features_new:
* @features: a string with OpenType font features, with the syntax of the [CSS
- * font-feature-settings property](https://www.w3.org/TR/css-fonts-4/#font-rend-desc)
+ * font-feature-settings property](https://www.w3.org/TR/css-fonts-4/#font-rend-desc)
*
* Create a new font features tag attribute.
*
@@ -584,6 +584,27 @@ pango2_attr_font_features_new (const char *features)
}
/**
+ * pango2_attr_palette_new:
+ * @palette : name of palette to use
+ *
+ * Create a new palette attribute.
+ *
+ * You can use this attribute to select font color palettes
+ * by name, like "light", "dark" or "palette3".
+ *
+ * Return value: (transfer full): the newly allocated
+ * `Pango2Attribute`, which should be freed with
+ * [method@Pango2.Attribute.destroy]
+ */
+Pango2Attribute *
+pango2_attr_palette_new (const char *palette)
+{
+ g_return_val_if_fail (palette != NULL, NULL);
+
+ return pango2_attr_string_new (PANGO2_ATTR_PALETTE, palette);
+}
+
+/**
* pango2_attr_allow_breaks_new:
* @allow_breaks: %TRUE if we line breaks are allowed
*
diff --git a/pango2/pango-attributes.h b/pango2/pango-attributes.h
index d7c7661c..990d90e1 100644
--- a/pango2/pango-attributes.h
+++ b/pango2/pango-attributes.h
@@ -57,6 +57,7 @@ G_BEGIN_DECLS
* @PANGO2_ATTR_GRAVITY: base text gravity
* @PANGO2_ATTR_GRAVITY_HINT: gravity hint
* @PANGO2_ATTR_FONT_FEATURES: OpenType font features
+ * @PANGO2_ATTR_PALETTE: Color palette name
* @PANGO2_ATTR_ALLOW_BREAKS: whether line breaks are allowed
* @PANGO2_ATTR_SHOW: how to render invisible characters
* @PANGO2_ATTR_INSERT_HYPHENS: whether to insert hyphens at intra-word line breaks
@@ -105,6 +106,7 @@ typedef enum
PANGO2_ATTR_GRAVITY = PANGO2_ATTR_TYPE (INT, ITEMIZATION, OVERRIDES),
PANGO2_ATTR_GRAVITY_HINT = PANGO2_ATTR_TYPE (INT, ITEMIZATION, OVERRIDES),
PANGO2_ATTR_FONT_FEATURES = PANGO2_ATTR_TYPE (STRING, SHAPING, ACCUMULATES),
+ PANGO2_ATTR_PALETTE = PANGO2_ATTR_TYPE (STRING, ITEMIZATION, OVERRIDES),
PANGO2_ATTR_ALLOW_BREAKS = PANGO2_ATTR_TYPE (BOOLEAN, BREAKING, OVERRIDES),
PANGO2_ATTR_SHOW = PANGO2_ATTR_TYPE (INT, SHAPING, OVERRIDES),
PANGO2_ATTR_INSERT_HYPHENS = PANGO2_ATTR_TYPE (BOOLEAN, SHAPING, OVERRIDES),
@@ -245,6 +247,8 @@ Pango2Attribute * pango2_attr_gravity_hint_new (Pango2Gravity
PANGO2_AVAILABLE_IN_ALL
Pango2Attribute * pango2_attr_font_features_new (const char *features);
PANGO2_AVAILABLE_IN_ALL
+Pango2Attribute * pango2_attr_palette_new (const char *palette);
+PANGO2_AVAILABLE_IN_ALL
Pango2Attribute * pango2_attr_allow_breaks_new (gboolean allow_breaks);
PANGO2_AVAILABLE_IN_ALL
Pango2Attribute * pango2_attr_word_new (void);
diff --git a/pango2/pango-color-palette-private.h b/pango2/pango-color-palette-private.h
new file mode 100644
index 00000000..283c221d
--- /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-context-private.h b/pango2/pango-context-private.h
index 07b4b506..4ec65da6 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 371c8405..a6b6ee24 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_DEFAULT);
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_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_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_DEFAULT);
+ 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 color palette to use for color fonts.
+ */
+ properties[PROP_PALETTE] =
+ g_param_spec_string ("palette", NULL, NULL, "default",
+ 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,57 @@ pango2_context_get_round_glyph_positions (Pango2Context *context)
{
return context->round_glyph_positions;
}
+
+/**
+ * pango2_context_set_palette:
+ * @context: a `Pango2Context`
+ * @palette: the name of the palette to use
+ *
+ * Sets the default palette to use for color fonts.
+ *
+ * This can either be one of the predefined names
+ * "default", "light" or "dark", a name referring
+ * to a palette by index ("palette0", "palette1", …),
+ * 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.
+ *
+ * To associate custom names with palettes in fonts,
+ * use [method@Pango2.HbFace.set_palette_name].
+ */
+void
+pango2_context_set_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_palette:
+ * @context: a `Pango2Context`
+ *
+ * Returns the default palette to use for color fonts.
+ *
+ * See [method@Pango2.Context.set_palette].
+ *
+ * Return value: (nullable): the palette name
+ */
+const char *
+pango2_context_get_palette (Pango2Context *context)
+{
+ g_return_val_if_fail (PANGO2_IS_CONTEXT (context), PANGO2_COLOR_PALETTE_DEFAULT);
+
+ return g_quark_to_string (context->palette);
+}
diff --git a/pango2/pango-context.h b/pango2/pango-context.h
index 902e840d..21901498 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_palette (Pango2Context *context,
+ const char *palette);
+PANGO2_AVAILABLE_IN_ALL
+const char * pango2_context_get_palette (Pango2Context *context);
+
+
+
G_END_DECLS
diff --git a/pango2/pango-font-description-private.h b/pango2/pango-font-description-private.h
index 11b09d00..231a2800 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 20421c89..9eeab8ae 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 */
@@ -872,7 +875,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 +928,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;
}
@@ -1185,6 +1190,24 @@ parse_size (const char *word,
}
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,
char **variations)
@@ -1201,40 +1224,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 +1232,24 @@ faceid_from_variations (Pango2FontDescription *desc)
*
* The string must have the form
*
- * "\[FAMILY-LIST] \[STYLE-OPTIONS] \[SIZE] \[VARIATIONS]",
+ * "\[FAMILY-LIST] \[STYLE-OPTIONS] \[SIZE] \[VARIATIONS] \[FACEID]",
*
* 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".
+ *
+ * The VARIATION, FACEID 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 +1302,30 @@ 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 faceid and variations at the end of the string */
+ 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_FACEID | PANGO2_FONT_MASK_VARIATIONS)) !=
+ (PANGO2_FONT_MASK_FACEID | PANGO2_FONT_MASK_VARIATIONS));
p = getword (str, last, &wordlen, ",");
/* Look for a size */
@@ -1428,7 +1438,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,7 +1497,6 @@ 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);
}
@@ -1496,10 +1504,7 @@ pango2_font_description_to_string (const Pango2FontDescription *desc)
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 +1746,17 @@ pango2_font_description_get_faceid (const Pango2FontDescription *desc)
return desc->faceid;
}
+
+/*< 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-private.h b/pango2/pango-font-private.h
index ca8d3a77..7789e6be 100644
--- a/pango2/pango-font-private.h
+++ b/pango2/pango-font-private.h
@@ -114,12 +114,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 20cf8193..5ae9b69b 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"
@@ -558,6 +558,7 @@ pango2_font_map_default_load_fontset (Pango2FontMap *self,
lookup.language = language;
lookup.description = (Pango2FontDescription *)description;
lookup.ctm = ctm;
+
#ifdef HAVE_CAIRO
lookup.font_options = (cairo_font_options_t *)pango2_cairo_context_get_merged_font_options (context);
#endif
diff --git a/pango2/pango-fontset-cached.c b/pango2/pango-fontset-cached.c
index 9feaca79..37b80687 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"
@@ -82,6 +84,23 @@ find_font_for_face (Pango2FontsetCached *self,
}
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);
+#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 +148,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 +184,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 = create_font_for_face (self, face);
return font;
}
@@ -249,15 +250,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 +297,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 e2920388..8fbf6bf3 100644
--- a/pango2/pango-hbface-private.h
+++ b/pango2/pango-hbface-private.h
@@ -25,6 +25,11 @@
#include "pango-language-set-private.h"
#include <hb.h>
+typedef struct {
+ GQuark name;
+ unsigned int index;
+} PaletteMapEntry;
+
struct _Pango2HbFace
{
Pango2FontFace parent_instance;
@@ -41,6 +46,7 @@ struct _Pango2HbFace
Pango2LanguageSet *languages;
gboolean embolden;
gboolean synthetic;
+ GArray *palettes;
};
Pango2LanguageSet * pango2_hb_face_get_language_set (Pango2HbFace *self);
@@ -50,3 +56,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 dbe68e17..61be8b38 100644
--- a/pango2/pango-hbface.c
+++ b/pango2/pango-hbface.c
@@ -48,6 +48,10 @@
/* {{{ Utilities */
+static GQuark quark_default_palette;
+static GQuark quark_light_palette;
+static GQuark quark_dark_palette;
+
static void
get_name_from_hb_face (hb_face_t *face,
hb_ot_name_id_t name_id,
@@ -314,6 +318,8 @@ pango2_hb_face_finalize (GObject *object)
{
Pango2HbFace *self = PANGO2_HB_FACE (object);
+ if (self->palettes)
+ g_array_unref (self->palettes);
g_free (self->faceid);
if (self->face)
hb_face_destroy (self->face);
@@ -483,6 +489,10 @@ pango2_hb_face_class_init (Pango2HbFaceClass *class)
GObjectClass *object_class = G_OBJECT_CLASS (class);
Pango2FontFaceClass *face_class = PANGO2_FONT_FACE_CLASS (class);
+ quark_default_palette = g_quark_from_static_string (PANGO2_COLOR_PALETTE_DEFAULT);
+ quark_light_palette = g_quark_from_static_string (PANGO2_COLOR_PALETTE_LIGHT);
+ quark_dark_palette = g_quark_from_static_string (PANGO2_COLOR_PALETTE_DARK);
+
object_class->finalize = pango2_hb_face_finalize;
object_class->get_property = pango2_hb_face_get_property;
@@ -627,6 +637,73 @@ 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)
+{
+ unsigned int n_palettes;
+
+ n_palettes = hb_ot_color_palette_get_count (hbface);
+ for (unsigned int i = 0; i < n_palettes; 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)
+{
+ const char *name;
+
+ if (palette == 0)
+ return 0;
+
+ if (self->palettes)
+ {
+ for (unsigned int i = 0; i < self->palettes->len; i++)
+ {
+ PaletteMapEntry *entry = &g_array_index (self->palettes, PaletteMapEntry, i);
+
+ if (entry->name == palette)
+ return entry->index;
+ }
+ }
+
+ if (palette == quark_default_palette)
+ return 0;
+
+ ensure_hb_face (self);
+
+ if (!hb_ot_color_has_palettes (self->face))
+ return 0;
+
+ /* look for a name of the form "paletteN" */
+ name = g_quark_to_string (palette);
+ if (g_str_has_prefix (name, "palette") && g_ascii_isdigit (name[strlen ("palette")]))
+ {
+ const char *p;
+ char *end;
+ unsigned int index;
+
+ p = name + strlen ("palette");
+ index = (unsigned int) g_ascii_strtoull (p, &end, 10);
+ if (*end == '\0')
+ return index;
+ }
+
+ /* look for "light", "dark" */
+ if (palette == quark_light_palette)
+ return find_palette_index_by_flag (self->face, HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND);
+ else if (palette == quark_dark_palette)
+ return find_palette_index_by_flag (self->face, HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND);
+
+ return 0;
+}
+
/* }}} */
/* {{{ Public API */
@@ -877,6 +954,104 @@ pango2_hb_face_get_transform (Pango2HbFace *self)
return self->transform;
}
+static gboolean
+name_is_valid (const char *name)
+{
+ if (!name)
+ return FALSE;
+
+ /* First character must be a letter. */
+ if ((name[0] < 'A' || name[0] > 'Z') &&
+ (name[0] < 'a' || name[0] > 'z'))
+ return FALSE;
+
+ for (const char *p = name; *p != 0; p++)
+ {
+ const char c = *p;
+
+ if (c != '-' && c != '_' &&
+ (c < '0' || c > '9') &&
+ (c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z'))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * pango2_hb_face_set_palette_name:
+ * @self: a `Pango2HbFace`
+ * @name: the palette name to set
+ * @index: index of the palette
+ *
+ * Sets up a palette name for one of the palettes of the `PangoHbFace`.
+ *
+ * After this call, using the name with a palette attribute
+ * or with [method@Pango2.Context.set_palette] will use the
+ * given palette index for @self.
+ */
+void
+pango2_hb_face_set_palette_name (Pango2HbFace *self,
+ const char *name,
+ unsigned int index)
+{
+ PaletteMapEntry add;
+
+ g_return_if_fail (PANGO2_IS_HB_FACE (self));
+ g_return_if_fail (name_is_valid (name));
+
+ add.name = g_quark_from_string (name);
+ add.index = index;
+
+ if (self->palettes == NULL)
+ self->palettes = g_array_new (FALSE, FALSE, sizeof (PaletteMapEntry));
+
+ for (int i = 0; i < self->palettes->len; i++)
+ {
+ PaletteMapEntry *entry = &g_array_index (self->palettes, PaletteMapEntry, i);
+ if (entry->index == add.index)
+ {
+ entry->name = add.name;
+ return;
+ }
+ }
+
+ g_array_append_val (self->palettes, add);
+}
+
+/**
+ * pango2_hb_face_get_palette_name:
+ * @self: a `PangoHbFace`
+ * @index: index of the palette
+ *
+ * Gets the name for the palette with the given index in @self.
+ *
+ * Note that this function only returns names that have been
+ * set up by a prior call of [method@Pang2.HbFace.set_palette_name].
+ * It does not return the predefined "paletteN" names.
+ *
+ * Returns: (nullable): the palette name
+ */
+const char *
+pango2_hb_face_get_palette_name (Pango2HbFace *self,
+ unsigned int index)
+{
+ g_return_val_if_fail (PANGO2_IS_HB_FACE (self), NULL);
+
+ if (self->palettes == NULL)
+ return NULL;
+
+ for (int i = 0; i < self->palettes->len; i++)
+ {
+ PaletteMapEntry *entry = &g_array_index (self->palettes, PaletteMapEntry, i);
+ if (entry->index == index)
+ return g_quark_to_string (entry->name);
+ }
+
+ return NULL;
+}
+
/* }}} */
/* {{{ Pango2HbFaceBuilder */
@@ -1025,6 +1200,7 @@ 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);
+ pango2_font_description_unset_fields (builder->description, PANGO2_FONT_MASK_FACEID);
return builder;
}
@@ -1043,6 +1219,7 @@ pango2_hb_face_builder_get_face (Pango2HbFaceBuilder *builder)
Pango2HbFace *self;
self = g_object_new (PANGO2_TYPE_HB_FACE, NULL);
+
if (builder->face)
{
self->file = g_strdup (builder->face->file);
@@ -1051,6 +1228,9 @@ pango2_hb_face_builder_get_face (Pango2HbFaceBuilder *builder)
if (builder->face->face)
self->face = hb_face_reference (builder->face->face);
pango2_hb_face_set_language_set (self, builder->face->languages);
+
+ if (builder->face->palettes)
+ self->palettes = g_array_copy (builder->face->palettes);
}
else if (builder->hb_face)
{
diff --git a/pango2/pango-hbface.h b/pango2/pango-hbface.h
index b110ff99..ef7c6b73 100644
--- a/pango2/pango-hbface.h
+++ b/pango2/pango-hbface.h
@@ -66,6 +66,13 @@ gboolean pango2_hb_face_get_embolden (Pango2HbFace
PANGO2_AVAILABLE_IN_ALL
const Pango2Matrix * pango2_hb_face_get_transform (Pango2HbFace *self);
+PANGO2_AVAILABLE_IN_ALL
+void pango2_hb_face_set_palette_name (Pango2HbFace *self,
+ const char *name,
+ unsigned int index);
+PANGO2_AVAILABLE_IN_ALL
+const char * pango2_hb_face_get_palette_name (Pango2HbFace *self,
+ unsigned int index);
typedef struct _Pango2HbFaceBuilder Pango2HbFaceBuilder;
diff --git a/pango2/pango-hbfont.c b/pango2/pango-hbfont.c
index 91f4a305..1bac38de 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-markup.c b/pango2/pango-markup.c
index 72d2d2e8..91c9aded 100644
--- a/pango2/pango-markup.c
+++ b/pango2/pango-markup.c
@@ -1341,6 +1341,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED,
const char *gravity = NULL;
const char *gravity_hint = NULL;
const char *font_features = NULL;
+ const char *palette = NULL;
const char *allow_breaks = NULL;
const char *insert_hyphens = NULL;
const char *show = NULL;
@@ -1406,6 +1407,10 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED,
CHECK_ATTRIBUTE (font_features);
break;
+ case 'p':
+ CHECK_ATTRIBUTE (palette);
+ break;
+
case 's':
CHECK_ATTRIBUTE (show);
CHECK_ATTRIBUTE (size);
@@ -1841,6 +1846,11 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED,
add_attribute (tag, pango2_attr_font_features_new (font_features));
}
+ if (G_UNLIKELY (palette))
+ {
+ add_attribute (tag, pango2_attr_palette_new (palette));
+ }
+
if (G_UNLIKELY (allow_breaks))
{
gboolean b = FALSE;
diff --git a/pango2/pango-types.h b/pango2/pango-types.h
index 56cf3dbf..fb045f14 100644
--- a/pango2/pango-types.h
+++ b/pango2/pango-types.h
@@ -319,6 +319,29 @@ typedef enum
*/
#define PANGO2_LEADING_TRIM_BOTH (PANGO2_LEADING_TRIM_START|PANGO2_LEADING_TRIM_END)
+/**
+ * PANGO2_COLOR_PALETTE_DEFAULT:
+ *
+ * The name for the default color palette.
+ */
+#define PANGO2_COLOR_PALETTE_DEFAULT "default"
+
+/**
+ * PANGO2_COLOR_PALETTE_LIGHT:
+ *
+ * The name for a color palette suitable for use on
+ * a light background.
+ */
+#define PANGO2_COLOR_PALETTE_LIGHT "light"
+
+/**
+ * PANGO2_COLOR_PALETTE_DARK:
+ *
+ * The name for a color palette suitable for use on
+ * a dark background.
+ */
+#define PANGO2_COLOR_PALETTE_DARK "dark"
+
/*
* PANGO2_DECLARE_INTERNAL_TYPE:
* @ModuleObjName: The name of the new type, in camel case (like GtkWidget)
diff --git a/pango2/pangocairo-font.c b/pango2/pangocairo-font.c
index b9103d97..72c06bdb 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"
@@ -36,7 +38,8 @@
#include "pango-font-private.h"
static Pango2CairoFontPrivate * _pango2_font_get_cairo_font_private (Pango2Font *font);
-static cairo_scaled_font_t * _pango2_font_get_scaled_font (Pango2Font *font);
+static cairo_scaled_font_t * _pango2_font_get_scaled_font (Pango2Font *font,
+ GQuark palette);
static void _pango2_cairo_font_private_initialize (Pango2CairoFontPrivate *cf_priv,
Pango2Font *font,
Pango2Gravity gravity,
@@ -92,32 +95,74 @@ create_cairo_font_face (Pango2Font *font)
return NULL;
}
+#ifdef CAIRO_COLOR_PALETTE_DEFAULT
+
+static int
+find_palette_index_for_font (Pango2Font *font,
+ GQuark palette)
+{
+ Pango2FontFace *face = pango2_font_get_face (font);
+
+ if (PANGO2_IS_HB_FACE (face))
+ return pango2_hb_face_get_palette_index (PANGO2_HB_FACE (face), palette);
+
+ return CAIRO_COLOR_PALETTE_DEFAULT;
+}
+
+#endif
+
static cairo_scaled_font_t *
-_pango2_cairo_font_private_get_scaled_font (Pango2CairoFontPrivate *cf_priv)
+_pango2_cairo_font_private_get_scaled_font (Pango2CairoFontPrivate *cf_priv,
+ GQuark palette)
{
cairo_font_face_t *font_face;
+ cairo_font_options_t *options;
+ cairo_matrix_t _font_matrix, *font_matrix;
+ cairo_matrix_t _ctm, *ctm;
- if (G_LIKELY (cf_priv->scaled_font))
+ if (G_LIKELY (cf_priv->palette == palette && cf_priv->scaled_font))
return cf_priv->scaled_font;
+ if (!cf_priv->data && !cf_priv->scaled_font)
+ return NULL;
+
/* need to create it */
- if (G_UNLIKELY (cf_priv->data == NULL))
+ if (cf_priv->scaled_font)
{
- /* we have tried to create and failed before */
- return NULL;
+ font_face = cairo_scaled_font_get_font_face (cf_priv->scaled_font);
+ cairo_font_face_reference (font_face);
+
+ options = cairo_font_options_create ();
+ cairo_scaled_font_get_font_options (cf_priv->scaled_font, options);
+ cairo_scaled_font_get_font_matrix (cf_priv->scaled_font, &_font_matrix);
+ font_matrix = &_font_matrix;
+ cairo_scaled_font_get_ctm (cf_priv->scaled_font, &_ctm);
+ ctm = &_ctm;
+
+ cairo_scaled_font_destroy (cf_priv->scaled_font);
+ cf_priv->scaled_font = NULL;
+ }
+ else
+ {
+ font_face = create_cairo_font_face (cf_priv->cfont);
+ options = cairo_font_options_copy (cf_priv->data->options);
+ font_matrix = &cf_priv->data->font_matrix;
+ ctm = &cf_priv->data->ctm;
}
-
- font_face = create_cairo_font_face (cf_priv->cfont);
if (G_UNLIKELY (font_face == NULL))
goto done;
- cf_priv->scaled_font = cairo_scaled_font_create (font_face,
- &cf_priv->data->font_matrix,
- &cf_priv->data->ctm,
- cf_priv->data->options);
+#ifdef CAIRO_COLOR_PALETTE_DEFAULT
+ cairo_font_options_set_color_palette (options,
+ find_palette_index_for_font (cf_priv->cfont, palette));
+#endif
+ cf_priv->palette = palette;
+ cf_priv->scaled_font = cairo_scaled_font_create (font_face, font_matrix, ctm, options);
+
+ cairo_font_options_destroy (options);
cairo_font_face_destroy (font_face);
done:
@@ -168,8 +213,9 @@ done:
return cf_priv->scaled_font;
}
-cairo_scaled_font_t *
-_pango2_font_get_scaled_font (Pango2Font *font)
+static cairo_scaled_font_t *
+_pango2_font_get_scaled_font (Pango2Font *font,
+ GQuark palette)
{
Pango2CairoFontPrivate *cf_priv;
@@ -178,12 +224,13 @@ _pango2_font_get_scaled_font (Pango2Font *font)
if (G_UNLIKELY (!cf_priv))
return NULL;
- return _pango2_cairo_font_private_get_scaled_font (cf_priv);
+ return _pango2_cairo_font_private_get_scaled_font (cf_priv, palette);
}
/**
* _pango2_cairo_font_install:
* @font: a `Pango2CairoFont`
+ * @palette: a palette
* @cr: a #cairo_t
*
* Makes @font the current font for rendering in the specified
@@ -193,11 +240,12 @@ _pango2_font_get_scaled_font (Pango2Font *font)
*/
gboolean
_pango2_cairo_font_install (Pango2Font *font,
+ GQuark palette,
cairo_t *cr)
{
cairo_scaled_font_t *scaled_font;
- scaled_font = _pango2_font_get_scaled_font (font);
+ scaled_font = _pango2_font_get_scaled_font (font, palette);
if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
return FALSE;
@@ -239,7 +287,7 @@ _pango2_cairo_font_private_get_hex_box_info (Pango2CairoFontPrivate *cf_priv)
if (cf_priv->hbi)
return cf_priv->hbi;
- scaled_font = _pango2_cairo_font_private_get_scaled_font (cf_priv);
+ scaled_font = _pango2_cairo_font_private_get_scaled_font (cf_priv, 0);
if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
return NULL;
@@ -352,7 +400,7 @@ _pango2_cairo_font_private_get_hex_box_info (Pango2CairoFontPrivate *cf_priv)
pango2_font_description_free (desc);
cairo_font_options_destroy (font_options);
- scaled_mini_font = _pango2_font_get_scaled_font (mini_font);
+ scaled_mini_font = _pango2_font_get_scaled_font (mini_font, 0);
if (G_UNLIKELY (scaled_mini_font == NULL || cairo_scaled_font_status (scaled_mini_font) != CAIRO_STATUS_SUCCESS))
return NULL;
diff --git a/pango2/pangocairo-private.h b/pango2/pangocairo-private.h
index be9fa8cf..0ff05b98 100644
--- a/pango2/pangocairo-private.h
+++ b/pango2/pangocairo-private.h
@@ -41,6 +41,7 @@ struct _Pango2CairoFontPrivate
Pango2CairoFontPrivateScaledFontData *data;
+ GQuark palette;
cairo_scaled_font_t *scaled_font;
Pango2CairoFontHexBoxInfo *hbi;
@@ -50,9 +51,11 @@ struct _Pango2CairoFontPrivate
Pango2Rectangle font_extents;
};
-gboolean _pango2_cairo_font_install (Pango2Font *font,
- cairo_t *cr);
-Pango2CairoFontHexBoxInfo *_pango2_cairo_font_get_hex_box_info (Pango2Font *font);
+gboolean _pango2_cairo_font_install (Pango2Font *font,
+ GQuark palette,
+ cairo_t *cr);
+Pango2CairoFontHexBoxInfo *
+ _pango2_cairo_font_get_hex_box_info (Pango2Font *font);
#define PANGO2_TYPE_CAIRO_RENDERER (pango2_cairo_renderer_get_type())
#define PANGO2_CAIRO_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO2_TYPE_CAIRO_RENDERER, Pango2CairoRenderer))
@@ -61,27 +64,23 @@ Pango2CairoFontHexBoxInfo *_pango2_cairo_font_get_hex_box_info (Pango2Font *font
typedef struct _Pango2CairoRenderer Pango2CairoRenderer;
_PANGO2_EXTERN
-GType pango2_cairo_renderer_get_type (void) G_GNUC_CONST;
+GType pango2_cairo_renderer_get_type (void) G_GNUC_CONST;
const cairo_font_options_t *
- pango2_cairo_context_get_merged_font_options (Pango2Context *context);
+ pango2_cairo_context_get_merged_font_options (Pango2Context *context);
-cairo_font_face_t *
-create_cairo_user_font_face (Pango2Font *font);
+cairo_font_face_t * create_cairo_user_font_face (Pango2Font *font);
#ifdef CAIRO_HAS_FT_FONT
-cairo_font_face_t *
-create_cairo_ft_font_face (Pango2Font *font);
+cairo_font_face_t * create_cairo_ft_font_face (Pango2Font *font);
#endif
#ifdef HAVE_CORE_TEXT
-cairo_font_face_t *
-create_cairo_core_text_font_face (Pango2Font *font);
+cairo_font_face_t * create_cairo_core_text_font_face (Pango2Font *font);
#endif
#ifdef HAVE_DIRECT_WRITE
-cairo_font_face_t *
-create_cairo_dwrite_font_face (Pango2Font *font);
+cairo_font_face_t * create_cairo_dwrite_font_face (Pango2Font *font);
#endif
G_END_DECLS
diff --git a/pango2/pangocairo-render.c b/pango2/pangocairo-render.c
index e4cfefa1..fd046073 100644
--- a/pango2/pangocairo-render.c
+++ b/pango2/pangocairo-render.c
@@ -31,6 +31,9 @@
#include "pango-run-private.h"
#include "pango-impl-utils.h"
#include "pango-hbfont-private.h"
+#include "pango-attr-private.h"
+#include "pango-context-private.h"
+
typedef struct _Pango2CairoRendererClass Pango2CairoRendererClass;
@@ -46,6 +49,7 @@ struct _Pango2CairoRenderer
gboolean do_path;
gboolean has_show_text_glyphs;
double x_offset, y_offset;
+ GQuark palette;
/* house-keeping options */
gboolean is_cached_renderer;
@@ -253,7 +257,7 @@ _pango2_cairo_renderer_draw_unknown_glyph (Pango2CairoRenderer *crenderer,
hbi = PANGO2_HB_FONT (font)->hex_box_info;
else
hbi = _pango2_cairo_font_get_hex_box_info (font);
- if (!hbi || !_pango2_cairo_font_install ((Pango2Font *)(hbi->font), crenderer->cr))
+ if (!hbi || !_pango2_cairo_font_install ((Pango2Font *)(hbi->font), 0, crenderer->cr))
{
_pango2_cairo_renderer_draw_box_glyph (crenderer, gi, cx, cy, invalid_input);
goto done;
@@ -413,11 +417,11 @@ pango2_cairo_renderer_show_text_glyphs (Pango2Renderer *renderer,
int num_clusters,
gboolean backward,
Pango2Font *font,
+ GQuark palette,
int x,
int y)
{
Pango2CairoRenderer *crenderer = (Pango2CairoRenderer *) (renderer);
-
int i, count;
int x_position = 0;
cairo_glyph_t *cairo_glyphs;
@@ -429,7 +433,7 @@ pango2_cairo_renderer_show_text_glyphs (Pango2Renderer *renderer,
if (!crenderer->do_path)
set_color (crenderer, PANGO2_RENDER_PART_FOREGROUND);
- if (!_pango2_cairo_font_install (font, crenderer->cr))
+ if (!_pango2_cairo_font_install (font, palette, crenderer->cr))
{
for (i = 0; i < glyphs->num_glyphs; i++)
{
@@ -511,7 +515,8 @@ pango2_cairo_renderer_draw_glyphs (Pango2Renderer *renderer,
int x,
int y)
{
- pango2_cairo_renderer_show_text_glyphs (renderer, NULL, 0, glyphs, NULL, 0, FALSE, font, x, y);
+ Pango2CairoRenderer *crenderer = (Pango2CairoRenderer *) (renderer);
+ pango2_cairo_renderer_show_text_glyphs (renderer, NULL, 0, glyphs, NULL, 0, FALSE, font, crenderer->palette, x, y);
}
static void
@@ -534,7 +539,7 @@ pango2_cairo_renderer_draw_run (Pango2Renderer *renderer,
if (!crenderer->has_show_text_glyphs || crenderer->do_path)
{
- pango2_cairo_renderer_show_text_glyphs (renderer, NULL, 0, glyphs, NULL, 0, FALSE, font, x, y);
+ pango2_cairo_renderer_show_text_glyphs (renderer, NULL, 0, glyphs, NULL, 0, FALSE, font, crenderer->palette, x, y);
return;
}
@@ -581,6 +586,7 @@ pango2_cairo_renderer_draw_run (Pango2Renderer *renderer,
cairo_clusters, num_clusters,
backward,
font,
+ crenderer->palette,
x, y);
if (cairo_clusters != stack_clusters)
@@ -816,6 +822,35 @@ pango2_cairo_renderer_draw_styled_line (Pango2Renderer *renderer,
}
}
+static GQuark
+find_palette (Pango2Context *context,
+ Pango2Item *item)
+{
+ GSList *l;
+
+ for (l = item->analysis.extra_attrs; l; l = l->next)
+ {
+ Pango2Attribute *attr = l->data;
+
+ if (attr->type == PANGO2_ATTR_PALETTE)
+ return g_quark_from_string (attr->str_value);
+ }
+
+ return context->palette;
+}
+
+static void
+pango2_cairo_renderer_prepare_run (Pango2Renderer *renderer,
+ Pango2Run *run)
+{
+ Pango2CairoRenderer *crenderer = (Pango2CairoRenderer *) (renderer);
+
+ PANGO2_RENDERER_CLASS (pango2_cairo_renderer_parent_class)->prepare_run (renderer, run);
+
+ crenderer->palette = find_palette (pango2_renderer_get_context (renderer),
+ pango2_run_get_item (run));
+}
+
static void
pango2_cairo_renderer_init (Pango2CairoRenderer *renderer G_GNUC_UNUSED)
{
@@ -831,6 +866,7 @@ pango2_cairo_renderer_class_init (Pango2CairoRendererClass *klass)
renderer_class->draw_rectangle = pango2_cairo_renderer_draw_rectangle;
renderer_class->draw_styled_line = pango2_cairo_renderer_draw_styled_line;
renderer_class->draw_trapezoid = pango2_cairo_renderer_draw_trapezoid;
+ renderer_class->prepare_run = pango2_cairo_renderer_prepare_run;
}
static Pango2CairoRenderer *cached_renderer = NULL; /* MT-safe */
@@ -903,6 +939,7 @@ restore_current_point (Pango2CairoRenderer *renderer)
static void
_pango2_cairo_do_glyph_string (cairo_t *cr,
Pango2Font *font,
+ GQuark palette,
Pango2GlyphString *glyphs,
gboolean do_path)
{
@@ -911,6 +948,7 @@ _pango2_cairo_do_glyph_string (cairo_t *cr,
crenderer->cr = cr;
crenderer->do_path = do_path;
+ crenderer->palette = palette;
save_current_point (crenderer);
if (!do_path)
@@ -1057,7 +1095,32 @@ pango2_cairo_show_glyph_string (cairo_t *cr,
g_return_if_fail (cr != NULL);
g_return_if_fail (glyphs != NULL);
- _pango2_cairo_do_glyph_string (cr, font, glyphs, FALSE);
+ _pango2_cairo_do_glyph_string (cr, font, 0, glyphs, FALSE);
+}
+
+/**
+ * pango2_cairo_show_color_glyph_string:
+ * @cr: a Cairo context
+ * @font: a `Pango2Font` from a `Pango2CairoFontMap`
+ * @palette: a palette name, as quark
+ * @glyphs: a `Pango2GlyphString`
+ *
+ * Draws the glyphs in @glyphs in the specified cairo context,
+ * and with the given palette name.
+ *
+ * This is a variation of [func@Pango2.cairo_show_glyph_string]
+ * for use with fonts that have color palettes.
+ */
+void
+pango2_cairo_show_color_glyph_string (cairo_t *cr,
+ Pango2Font *font,
+ GQuark palette,
+ Pango2GlyphString *glyphs)
+{
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (glyphs != NULL);
+
+ _pango2_cairo_do_glyph_string (cr, font, palette, glyphs, FALSE);
}
/**
@@ -1169,7 +1232,7 @@ pango2_cairo_glyph_string_path (cairo_t *cr,
g_return_if_fail (cr != NULL);
g_return_if_fail (glyphs != NULL);
- _pango2_cairo_do_glyph_string (cr, font, glyphs, TRUE);
+ _pango2_cairo_do_glyph_string (cr, font, 0, glyphs, TRUE);
}
/**
diff --git a/pango2/pangocairo-render.h b/pango2/pangocairo-render.h
index fb40fba9..e36a4100 100644
--- a/pango2/pangocairo-render.h
+++ b/pango2/pangocairo-render.h
@@ -28,6 +28,11 @@ PANGO2_AVAILABLE_IN_ALL
void pango2_cairo_show_glyph_string (cairo_t *cr,
Pango2Font *font,
Pango2GlyphString *glyphs);
+PANGO2_AVAILABLE_IN_ALL
+void pango2_cairo_show_color_glyph_string (cairo_t *cr,
+ Pango2Font *font,
+ GQuark palette,
+ Pango2GlyphString *glyphs);
PANGO2_AVAILABLE_IN_ALL
void pango2_cairo_show_run (cairo_t *cr,
diff --git a/pango2/serializer.c b/pango2/serializer.c
index 7f719a06..03ffb4cd 100644
--- a/pango2/serializer.c
+++ b/pango2/serializer.c
@@ -1053,6 +1053,12 @@ attr_for_type (GtkJsonParser *parser,
g_free (str);
break;
+ case PANGO2_ATTR_PALETTE:
+ str = gtk_json_parser_get_string (parser);
+ attr = pango2_attr_palette_new (str);
+ g_free (str);
+ break;
+
case PANGO2_ATTR_ALLOW_BREAKS:
attr = pango2_attr_allow_breaks_new (gtk_json_parser_get_boolean (parser));
break;
diff --git a/tests/test-font.c b/tests/test-font.c
index dd3ef1b5..56a12046 100644
--- a/tests/test-font.c
+++ b/tests/test-font.c
@@ -499,7 +499,39 @@ 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;
+
+ 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_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_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 void
+test_all (void)
+{
+ const char *test = "Cantarell Bold Italic 32 @faceid=Cantarell-Regular:0:-1:0 @wght=600";
Pango2FontDescription *desc;
char *s;
@@ -657,6 +689,7 @@ 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/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 d51b2055..b6e906a8 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_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;