diff options
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; |