From d4cf0b1c8dcdef31644879d6fbae11002828b927 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 13 Feb 2022 13:19:45 -0600 Subject: wip: Add an api to select palettes for color glyphs This commit adds a light-background attribute that can be used to influence which palette will be used to render COLRv0 layered glyphs with color fonts that have multiple palettes. This needs a way for cairo to invalidate its glyph cache when the selected palette changes, which needs new freetype api. --- pango/pango-attributes.c | 14 ++++++++++++++ pango/pango-attributes.h | 3 +++ pango/pango-markup.c | 12 ++++++++++++ pango/pangocairo-fc-private.h | 6 ++++++ pango/pangocairo-fcfont.c | 43 +++++++++++++++++++++++++++++++++++++++++++ pango/pangocairo-font.c | 18 +++++++++++++++++- pango/pangocairo-private.h | 5 ++++- pango/pangocairo-render.c | 36 +++++++++++++++++++++++++++++++++--- 8 files changed, 132 insertions(+), 5 deletions(-) diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 60d14706..59966575 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -1556,6 +1556,20 @@ pango_attr_text_transform_new (PangoTextTransform transform) return pango_attr_int_new (&klass, transform); } + +PangoAttribute * +pango_attr_light_background_new (gboolean light_background) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_LIGHT_BACKGROUND, + pango_attr_int_copy, + pango_attr_int_destroy, + pango_attr_int_equal + }; + + return pango_attr_int_new (&klass, light_background); +} + /* }}} */ /* {{{ Binding helpers */ diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 69ff9e52..964e594a 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -129,6 +129,7 @@ typedef enum PANGO_ATTR_SENTENCE, /* PangoAttrInt */ PANGO_ATTR_BASELINE_SHIFT, /* PangoAttrSize */ PANGO_ATTR_FONT_SCALE, /* PangoAttrInt */ + PANGO_ATTR_LIGHT_BACKGROUND, /* PangoAttrInt */ } PangoAttrType; /** @@ -609,6 +610,8 @@ PANGO_AVAILABLE_IN_1_50 PangoAttribute * pango_attr_line_height_new_absolute (int height); PANGO_AVAILABLE_IN_1_50 PangoAttribute * pango_attr_text_transform_new (PangoTextTransform transform); +PANGO_AVAILABLE_IN_1_50 +PangoAttribute * pango_attr_light_background_new (gboolean light_background); PANGO_AVAILABLE_IN_1_50 PangoAttrString * pango_attribute_as_string (PangoAttribute *attr); diff --git a/pango/pango-markup.c b/pango/pango-markup.c index 9a3bde55..12b1533e 100644 --- a/pango/pango-markup.c +++ b/pango/pango-markup.c @@ -1233,6 +1233,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED, const char *text_transform = NULL; const char *segment = NULL; const char *font_scale = NULL; + const char *light_background = NULL; g_markup_parse_context_get_position (context, &line_number, &char_number); @@ -1318,6 +1319,7 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED, CHECK_ATTRIBUTE (lang); CHECK_ATTRIBUTE (letter_spacing); CHECK_ATTRIBUTE (line_height); + CHECK_ATTRIBUTE (light_background); break; case 'o': CHECK_ATTRIBUTE (overline); @@ -1784,6 +1786,16 @@ span_parse_func (MarkupData *md G_GNUC_UNUSED, } } + if (G_UNLIKELY (light_background)) + { + gboolean b = FALSE; + + if (!span_parse_boolean ("light_background", light_background, &b, line_number, error)) + goto error; + + add_attribute (tag, pango_attr_light_background_new (b)); + } + return TRUE; error: diff --git a/pango/pangocairo-fc-private.h b/pango/pangocairo-fc-private.h index 370ecbea..78404ce1 100644 --- a/pango/pangocairo-fc-private.h +++ b/pango/pangocairo-fc-private.h @@ -39,6 +39,12 @@ struct _PangoCairoFcFontMap PangoFcFont *_pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap, PangoFcFontKey *key); +void pango_cairo_fc_font_install (PangoFcFont *font, + cairo_t *cr, + gboolean has_light_background); +void pango_cairo_fc_font_uninstall (PangoFcFont *font, + cairo_t *cr); + G_END_DECLS #endif /* __PANGOCAIRO_FC_PRIVATE_H__ */ diff --git a/pango/pangocairo-fcfont.c b/pango/pangocairo-fcfont.c index 4453b5ab..1e5b8c3e 100644 --- a/pango/pangocairo-fcfont.c +++ b/pango/pangocairo-fcfont.c @@ -35,6 +35,7 @@ #include #include +#include #define PANGO_TYPE_CAIRO_FC_FONT (pango_cairo_fc_font_get_type ()) #define PANGO_CAIRO_FC_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CAIRO_FC_FONT, PangoCairoFcFont)) @@ -275,3 +276,45 @@ _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap, return (PangoFcFont *) cffont; } + +void +pango_cairo_fc_font_install (PangoFcFont *font, + cairo_t *cr, + gboolean has_light_background) +{ + FT_Face face = pango_fc_font_lock_face (font); + FT_Palette_Data palettes; + int index = 0; + FT_Color *palette; + + FT_Palette_Data_Get (face, &palettes); + for (int i = 0; i < palettes.num_palettes; i++) + { + if (has_light_background) + { + if (palettes.palette_flags[i] & FT_PALETTE_FOR_LIGHT_BACKGROUND) + { + index = i; + break; + } + } + else + { + if (palettes.palette_flags[i] & FT_PALETTE_FOR_DARK_BACKGROUND) + { + index = i; + break; + } + } + } + + FT_Palette_Select (face, index, &palette); +} + +void +pango_cairo_fc_font_uninstall (PangoFcFont *font, + cairo_t *cr) +{ + pango_fc_font_unlock_face (font); +} + diff --git a/pango/pangocairo-font.c b/pango/pangocairo-font.c index 598065c0..9d1fca2e 100644 --- a/pango/pangocairo-font.c +++ b/pango/pangocairo-font.c @@ -26,6 +26,7 @@ #include "pangocairo.h" #include "pangocairo-private.h" +#include "pangocairo-fc-private.h" #include "pango-font-private.h" #include "pango-impl-utils.h" @@ -164,6 +165,7 @@ pango_cairo_font_get_scaled_font (PangoCairoFont *cfont) /** * _pango_cairo_font_install: * @font: a `PangoCairoFont` + * @renderer: a `PangoCairoRenderer` * @cr: a #cairo_t * * Makes @font the current font for rendering in the specified @@ -173,18 +175,32 @@ pango_cairo_font_get_scaled_font (PangoCairoFont *cfont) */ gboolean _pango_cairo_font_install (PangoFont *font, - cairo_t *cr) + cairo_t *cr, + gboolean has_light_background) { cairo_scaled_font_t *scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font); if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)) return FALSE; + if (PANGO_IS_FC_FONT (font)) + pango_cairo_fc_font_install (PANGO_FC_FONT (font), cr, has_light_background); + cairo_set_scaled_font (cr, scaled_font); return TRUE; } +gboolean +_pango_cairo_font_uninstall (PangoFont *font, + cairo_t *cr) +{ + if (PANGO_IS_FC_FONT (font)) + pango_cairo_fc_font_uninstall (PANGO_FC_FONT (font), cr); + + return TRUE; +} + static int max_glyph_width (PangoLayout *layout) diff --git a/pango/pangocairo-private.h b/pango/pangocairo-private.h index 704ae497..7c86d950 100644 --- a/pango/pangocairo-private.h +++ b/pango/pangocairo-private.h @@ -102,7 +102,10 @@ struct _PangoCairoFontIface }; gboolean _pango_cairo_font_install (PangoFont *font, - cairo_t *cr); + cairo_t *cr, + gboolean has_light_background); +gboolean _pango_cairo_font_uninstall (PangoFont *font, + cairo_t *cr); PangoFontMetrics * _pango_cairo_font_get_metrics (PangoFont *font, PangoLanguage *language); PangoCairoFontHexBoxInfo *_pango_cairo_font_get_hex_box_info (PangoCairoFont *cfont); diff --git a/pango/pangocairo-render.c b/pango/pangocairo-render.c index 2c552ba1..964d8a53 100644 --- a/pango/pangocairo-render.c +++ b/pango/pangocairo-render.c @@ -43,6 +43,8 @@ struct _PangoCairoRenderer gboolean has_show_text_glyphs; double x_offset, y_offset; + gboolean has_light_background; + /* house-keeping options */ gboolean is_cached_renderer; gboolean cr_had_current_point; @@ -250,10 +252,11 @@ _pango_cairo_renderer_draw_unknown_glyph (PangoCairoRenderer *crenderer, invalid_input = G_UNLIKELY (gi->glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF); hbi = _pango_cairo_font_get_hex_box_info ((PangoCairoFont *)font); - if (!hbi || !_pango_cairo_font_install ((PangoFont *)(hbi->font), crenderer->cr)) + if (!hbi || !_pango_cairo_font_install ((PangoFont *)(hbi->font), crenderer->cr, crenderer->has_light_background)) { _pango_cairo_renderer_draw_box_glyph (crenderer, gi, cx, cy, invalid_input); - goto done; + cairo_restore (crenderer->cr); + return; } if (G_UNLIKELY (invalid_input)) @@ -392,6 +395,7 @@ _pango_cairo_renderer_draw_unknown_glyph (PangoCairoRenderer *crenderer, } done: + _pango_cairo_font_uninstall ((PangoFont *)(hbi->font), crenderer->cr); cairo_restore (crenderer->cr); } @@ -426,7 +430,7 @@ pango_cairo_renderer_show_text_glyphs (PangoRenderer *renderer, if (!crenderer->do_path) set_color (crenderer, PANGO_RENDER_PART_FOREGROUND); - if (!_pango_cairo_font_install (font, crenderer->cr)) + if (!_pango_cairo_font_install (font, crenderer->cr, crenderer->has_light_background)) { for (i = 0; i < glyphs->num_glyphs; i++) { @@ -497,6 +501,8 @@ pango_cairo_renderer_show_text_glyphs (PangoRenderer *renderer, if (cairo_glyphs != stack_glyphs) g_free (cairo_glyphs); + _pango_cairo_font_uninstall (font, crenderer->cr); + done: cairo_restore (crenderer->cr); } @@ -813,11 +819,35 @@ pango_cairo_renderer_init (PangoCairoRenderer *renderer G_GNUC_UNUSED) { } +static void +pango_cairo_renderer_prepare_run (PangoRenderer *renderer, + PangoLayoutRun *run) +{ + PangoCairoRenderer *crenderer = (PangoCairoRenderer *) renderer; + + PANGO_RENDERER_CLASS (pango_cairo_renderer_parent_class)->prepare_run (renderer, run); + + for (GSList *l = run->item->analysis.extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + switch ((int) attr->klass->type) + { + case PANGO_ATTR_LIGHT_BACKGROUND: + crenderer->has_light_background = ((PangoAttrInt *)attr)->value; + break; + default: + break; + } + } +} + static void pango_cairo_renderer_class_init (PangoCairoRendererClass *klass) { PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass); + renderer_class->prepare_run = pango_cairo_renderer_prepare_run; renderer_class->draw_glyphs = pango_cairo_renderer_draw_glyphs; renderer_class->draw_glyph_item = pango_cairo_renderer_draw_glyph_item; renderer_class->draw_rectangle = pango_cairo_renderer_draw_rectangle; -- cgit v1.2.1