[pango/small-caps: 11/11] itemize: Emulate other casing variants
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/small-caps: 11/11] itemize: Emulate other casing variants
- Date: Sun, 7 Nov 2021 03:56:16 +0000 (UTC)
commit 3a2221375542e1f9a0e388a4d3efda20ae440586
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Nov 6 23:53:51 2021 -0400
itemize: Emulate other casing variants
When we detect that one of the other casing variants
is requested, but not available via OpenType font
features, emulate it by splitting the item into
lowercase and uppercase runs and apply a suitable
font scale and text transform to the runs to get
the desired effect.
Still to do: resolve conflics with preexisting
text transform attributes.
pango/itemize.c | 195 +++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 131 insertions(+), 64 deletions(-)
---
diff --git a/pango/itemize.c b/pango/itemize.c
index f115abdf..373d8488 100644
--- a/pango/itemize.c
+++ b/pango/itemize.c
@@ -1197,29 +1197,14 @@ apply_font_scale (PangoContext *context,
}
/* }}} */
-/* {{{ Handling Small Caps */
+/* {{{ Handling Casing variants */
static gboolean
-feature_is_requested (hb_feature_t *features,
- guint num_features,
- hb_tag_t tag)
-{
- for (guint i = 0; i < num_features; i++)
- {
- if (features[i].tag == tag)
- return features[i].value != 0;
- }
-
- return FALSE;
-}
-
-
-static gboolean
-feature_is_supported (hb_font_t *font,
- const PangoAnalysis *analysis,
- hb_tag_t table,
- hb_tag_t feature)
+all_features_supported (PangoItem *item,
+ hb_tag_t *features,
+ guint n_features)
{
+ hb_font_t *font = pango_font_get_hb_font (item->analysis.font);
hb_face_t *face = hb_font_get_face (font);
hb_script_t script;
hb_language_t language;
@@ -1229,57 +1214,116 @@ feature_is_supported (hb_font_t *font,
guint language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
guint script_index, language_index;
- guint feature_index;
+ guint index;
- script = g_unicode_script_to_iso15924 (analysis->script);
- language = hb_language_from_string (pango_language_to_string (analysis->language), -1);
+ script = g_unicode_script_to_iso15924 (item->analysis.script);
+ language = hb_language_from_string (pango_language_to_string (item->analysis.language), -1);
hb_ot_tags_from_script_and_language (script, language,
&script_count, script_tags,
&language_count, language_tags);
- hb_ot_layout_table_select_script (face, table,
+ hb_ot_layout_table_select_script (face, HB_OT_TAG_GSUB,
script_count, script_tags,
&script_index,
&chosen_script);
- hb_ot_layout_script_select_language (face, table,
+ hb_ot_layout_script_select_language (face, HB_OT_TAG_GSUB,
script_index,
language_count, language_tags,
&language_index);
- return hb_ot_layout_language_find_feature (face, table,
- script_index, language_index,
- feature,
- &feature_index);
+ for (int i = 0; i < n_features; i++)
+ {
+ if (!hb_ot_layout_language_find_feature (face, HB_OT_TAG_GSUB,
+ script_index, language_index,
+ features[i],
+ &index))
+ return FALSE;
+ }
+
+ return TRUE;
}
static gboolean
-small_caps_is_requested (PangoItem *item)
+variant_supported (PangoItem *item,
+ PangoVariant variant)
{
- hb_feature_t features[32];
- unsigned int num_features = 0;
+ hb_tag_t features[2];
+ guint num_features = 0;
- pango_analysis_collect_features (&item->analysis,
- features, G_N_ELEMENTS (features),
- &num_features);
+ switch (variant)
+ {
+ case PANGO_VARIANT_NORMAL:
+ case PANGO_VARIANT_UNICASE: /* Can't really emulate these */
+ case PANGO_VARIANT_TITLE_CAPS:
+ return TRUE;
+ case PANGO_VARIANT_SMALL_CAPS:
+ features[num_features++] = HB_TAG ('s', 'm', 'c', 'p');
+ break;
+ case PANGO_VARIANT_ALL_SMALL_CAPS:
+ features[num_features++] = HB_TAG ('s', 'm', 'c', 'p');
+ features[num_features++] = HB_TAG ('c', '2', 's', 'c');
+ break;
+ case PANGO_VARIANT_PETITE_CAPS:
+ features[num_features++] = HB_TAG ('p', 'c', 'a', 'p');
+ break;
+ case PANGO_VARIANT_ALL_PETITE_CAPS:
+ features[num_features++] = HB_TAG ('p', 'c', 'a', 'p');
+ features[num_features++] = HB_TAG ('c', '2', 'p', 'c');
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- return feature_is_requested (features, num_features, HB_TAG ('s', 'm', 'c', 'p'));
+ return all_features_supported (item, features, num_features);
}
-static gboolean
-small_caps_is_supported (PangoItem *item)
+static PangoVariant
+get_font_variant (PangoItem *item)
{
- hb_font_t *font = pango_font_get_hb_font (item->analysis.font);
+ PangoFontDescription *desc;
+ PangoVariant variant;
+
+ desc = pango_font_describe (item->analysis.font);
+ variant = pango_font_description_get_variant (desc);
+ pango_font_description_free (desc);
- return feature_is_supported (font, &item->analysis, HB_OT_TAG_GSUB, HB_TAG ('s', 'm', 'c', 'p'));
+ return variant;
}
static void
-split_item_for_small_caps (const char *text,
- GList *list_item)
+split_item_for_variant (const char *text,
+ GList *list_item,
+ PangoVariant variant)
{
PangoItem *item = list_item->data;
const char *start, *end;
const char *p, *p0;
+ PangoTextTransform transform = PANGO_TEXT_TRANSFORM_NONE;
+ PangoFontScale lowercase_scale = PANGO_FONT_SCALE_NONE;
+ PangoFontScale uppercase_scale = PANGO_FONT_SCALE_NONE;
+
+ switch (variant)
+ {
+ case PANGO_VARIANT_ALL_SMALL_CAPS:
+ uppercase_scale = PANGO_FONT_SCALE_SMALL_CAPS;
+ G_GNUC_FALLTHROUGH;
+ case PANGO_VARIANT_SMALL_CAPS:
+ transform = PANGO_TEXT_TRANSFORM_UPPERCASE;
+ lowercase_scale = PANGO_FONT_SCALE_SMALL_CAPS;
+ break;
+ case PANGO_VARIANT_ALL_PETITE_CAPS:
+ uppercase_scale = PANGO_FONT_SCALE_PETITE_CAPS;
+ G_GNUC_FALLTHROUGH;
+ case PANGO_VARIANT_PETITE_CAPS:
+ transform = PANGO_TEXT_TRANSFORM_UPPERCASE;
+ lowercase_scale = PANGO_FONT_SCALE_PETITE_CAPS;
+ break;
+ case PANGO_VARIANT_NORMAL:
+ case PANGO_VARIANT_UNICASE:
+ case PANGO_VARIANT_TITLE_CAPS:
+ default:
+ g_assert_not_reached ();
+ }
start = text + item->offset;
end = start + item->length;
@@ -1312,55 +1356,78 @@ split_item_for_small_caps (const char *text,
new_item = item;
}
- attr = pango_attr_text_transform_new (PANGO_TEXT_TRANSFORM_UPPERCASE);
- attr->start_index = new_item->offset;
- attr->end_index = new_item->offset + new_item->length;
- new_item->analysis.extra_attrs = g_slist_prepend (new_item->analysis.extra_attrs, attr);
+ if (transform != PANGO_TEXT_TRANSFORM_NONE)
+ {
+ attr = pango_attr_text_transform_new (transform);
+ attr->start_index = new_item->offset;
+ attr->end_index = new_item->offset + new_item->length;
+ new_item->analysis.extra_attrs = g_slist_prepend (new_item->analysis.extra_attrs, attr);
+ }
- attr = pango_attr_font_scale_new (PANGO_FONT_SCALE_SMALL_CAPS);
- attr->start_index = new_item->offset;
- attr->end_index = new_item->offset + new_item->length;
- new_item->analysis.extra_attrs = g_slist_prepend (new_item->analysis.extra_attrs, attr);
+ if (lowercase_scale != PANGO_FONT_SCALE_NONE)
+ {
+ attr = pango_attr_font_scale_new (lowercase_scale);
+ attr->start_index = new_item->offset;
+ attr->end_index = new_item->offset + new_item->length;
+ new_item->analysis.extra_attrs = g_slist_prepend (new_item->analysis.extra_attrs, attr);
+ }
}
p0 = p;
while (p < end && !g_unichar_islower (g_utf8_get_char (p)))
p = g_utf8_next_char (p);
- if (p0 < p && p < end)
+ if (p0 < p)
{
PangoItem *new_item;
+ PangoAttribute *attr;
/* p0 .. p is a uppercase segment */
- new_item = pango_item_split (item, p - p0, g_utf8_strlen (p, p - p0));
- list_item->data = new_item;
- list_item = g_list_insert_before (list_item, list_item->next, item);
- list_item = list_item->next;
+ if (p < end)
+ {
+ new_item = pango_item_split (item, p - p0, g_utf8_strlen (p, p - p0));
+ list_item->data = new_item;
+ list_item = g_list_insert_before (list_item, list_item->next, item);
+ list_item = list_item->next;
+ }
+ else
+ {
+ new_item = item;
+ }
+
+ if (uppercase_scale != PANGO_FONT_SCALE_NONE)
+ {
+ attr = pango_attr_font_scale_new (uppercase_scale);
+ attr->start_index = new_item->offset;
+ attr->end_index = new_item->offset + new_item->length;
+ new_item->analysis.extra_attrs = g_slist_prepend (new_item->analysis.extra_attrs, attr);
+ }
}
}
}
static void
-handle_small_caps_for_item (const char *text,
- GList *l)
+handle_variants_for_item (const char *text,
+ GList *l)
{
PangoItem *item = l->data;
+ PangoVariant variant;
- if (small_caps_is_requested (item) &&
- !small_caps_is_supported (item))
- split_item_for_small_caps (text, l);
+ variant = get_font_variant (item);
+ if (!variant_supported (item, variant))
+ split_item_for_variant (text, l, variant);
}
static void
-handle_small_caps (const char *text,
- GList *items)
+handle_variants (const char *text,
+ GList *items)
{
GList *next;
for (GList *l = items; l; l = next)
{
next = l->next;
- handle_small_caps_for_item (text, l);
+ handle_variants_for_item (text, l);
}
}
@@ -1384,7 +1451,7 @@ post_process_items (PangoContext *context,
}
}
- handle_small_caps (text, items);
+ handle_variants (text, items);
/* apply font-scale */
apply_font_scale (context, items);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]