diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-11-08 13:47:52 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-11-08 13:47:52 +0000 |
commit | 78d4efd6af8fc37b93b1dafb7c3b7101b389a565 (patch) | |
tree | 857deeac1c70f10038c2e967d0238f1845964533 /pango | |
parent | 9d389e936707ebcf84fbc64d07b8aa17cdf2ef04 (diff) | |
parent | 1790dbf9da8a4249528833ead1af32d232861b64 (diff) | |
download | pango-78d4efd6af8fc37b93b1dafb7c3b7101b389a565.tar.gz |
Merge branch 'small-caps' into 'main'
Emulate Small Caps if not available from the font
See merge request GNOME/pango!497
Diffstat (limited to 'pango')
-rw-r--r-- | pango/fonts.c | 7 | ||||
-rw-r--r-- | pango/itemize.c | 482 | ||||
-rw-r--r-- | pango/pango-attributes.h | 4 | ||||
-rw-r--r-- | pango/pango-context-private.h | 10 | ||||
-rw-r--r-- | pango/pango-context.c | 1 | ||||
-rw-r--r-- | pango/pango-font.h | 26 | ||||
-rw-r--r-- | pango/pango-item-private.h | 21 | ||||
-rw-r--r-- | pango/pango-item.c | 68 | ||||
-rw-r--r-- | pango/pango-layout.c | 20 | ||||
-rw-r--r-- | pango/pangofc-fontmap.c | 71 | ||||
-rw-r--r-- | pango/shape.c | 75 |
11 files changed, 619 insertions, 166 deletions
diff --git a/pango/fonts.c b/pango/fonts.c index fd98d91e..70a987e6 100644 --- a/pango/fonts.c +++ b/pango/fonts.c @@ -1019,7 +1019,12 @@ static const FieldMap style_map[] = { static const FieldMap variant_map[] = { { PANGO_VARIANT_NORMAL, "" }, - { PANGO_VARIANT_SMALL_CAPS, "Small-Caps" } + { PANGO_VARIANT_SMALL_CAPS, "Small-Caps" }, + { PANGO_VARIANT_ALL_SMALL_CAPS, "All-Small-Caps" }, + { PANGO_VARIANT_PETITE_CAPS, "Petite-Caps" }, + { PANGO_VARIANT_ALL_PETITE_CAPS, "All-Petite-Caps" }, + { PANGO_VARIANT_UNICASE, "Unicase" }, + { PANGO_VARIANT_TITLE_CAPS, "Title-Caps" } }; static const FieldMap weight_map[] = { diff --git a/pango/itemize.c b/pango/itemize.c index bd339633..82c737cc 100644 --- a/pango/itemize.c +++ b/pango/itemize.c @@ -902,6 +902,36 @@ itemize_state_update_for_new_run (ItemizeState *state) } } +/* We don't want space characters to affect font selection; in general, +* it's always wrong to select a font just to render a space. +* We assume that all fonts have the ASCII space, and for other space +* characters if they don't, HarfBuzz will compatibility-decompose them +* to ASCII space... +* See bugs #355987 and #701652. +* +* We don't want to change fonts just for variation selectors. +* See bug #781123. +* +* Finally, don't change fonts for line or paragraph separators. +* +* Note that we want spaces to use the 'better' font, comparing +* the font that is used before and after the space. This is handled +* in itemize_state_add_character(). +*/ +static gboolean +consider_as_space (gunichar wc) +{ + GUnicodeType type = g_unichar_type (wc); + return type == G_UNICODE_CONTROL || + type == G_UNICODE_FORMAT || + type == G_UNICODE_SURROGATE || + type == G_UNICODE_LINE_SEPARATOR || + type == G_UNICODE_PARAGRAPH_SEPARATOR || + (type == G_UNICODE_SPACE_SEPARATOR && wc != 0x1680u /* OGHAM SPACE MARK */) || + (wc >= 0xfe00u && wc <= 0xfe0fu) || + (wc >= 0xe0100u && wc <= 0xe01efu); +} + static void itemize_state_process_run (ItemizeState *state) { @@ -926,33 +956,8 @@ itemize_state_process_run (ItemizeState *state) gboolean is_forced_break = (wc == '\t' || wc == LINE_SEPARATOR); PangoFont *font; int font_position; - GUnicodeType type; - - /* We don't want space characters to affect font selection; in general, - * it's always wrong to select a font just to render a space. - * We assume that all fonts have the ASCII space, and for other space - * characters if they don't, HarfBuzz will compatibility-decompose them - * to ASCII space... - * See bugs #355987 and #701652. - * - * We don't want to change fonts just for variation selectors. - * See bug #781123. - * - * Finally, don't change fonts for line or paragraph separators. - * - * Note that we want spaces to use the 'better' font, comparing - * the font that is used before and after the space. This is handled - * in itemize_state_add_character(). - */ - type = g_unichar_type (wc); - if (G_UNLIKELY (type == G_UNICODE_CONTROL || - type == G_UNICODE_FORMAT || - type == G_UNICODE_SURROGATE || - type == G_UNICODE_LINE_SEPARATOR || - type == G_UNICODE_PARAGRAPH_SEPARATOR || - (type == G_UNICODE_SPACE_SEPARATOR && wc != 0x1680u /* OGHAM SPACE MARK */) || - (wc >= 0xfe00u && wc <= 0xfe0fu) || - (wc >= 0xe0100u && wc <= 0xe01efu))) + + if (consider_as_space (wc)) { font = NULL; font_position = 0xffff; @@ -1024,6 +1029,8 @@ itemize_state_finish (ItemizeState *state) /* }}} */ /* {{{ Post-processing */ + /* {{{ Handling font scale */ + typedef struct { PangoAttribute *attr; double scale; @@ -1048,43 +1055,61 @@ collect_font_scale (PangoContext *context, if (attr->start_index == item->offset) { ScaleItem *entry; - hb_font_t *hb_font; int y_scale; hb_position_t y_size; + hb_position_t cap_height; + hb_position_t x_height; entry = g_new (ScaleItem, 1); entry->attr = attr; *stack = g_list_prepend (*stack, entry); - if (prev) - { - hb_font = pango_font_get_hb_font (prev->analysis.font); - hb_font_get_scale (hb_font, NULL, &y_scale); - } - else - hb_font = NULL; - switch (((PangoAttrInt *)attr)->value) { case PANGO_FONT_SCALE_NONE: break; case PANGO_FONT_SCALE_SUPERSCRIPT: - if (hb_font && - hb_ot_metrics_get_position (hb_font, + if (prev && + hb_ot_metrics_get_position (pango_font_get_hb_font (prev->analysis.font), HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE, &y_size)) - entry->scale = y_size / (double) y_scale; + { + hb_font_get_scale (pango_font_get_hb_font (prev->analysis.font), NULL, &y_scale); + entry->scale = y_size / (double) y_scale; + } else - entry->scale = 1 / 1.2; + { + entry->scale = 1 / 1.2; + } break; case PANGO_FONT_SCALE_SUBSCRIPT: - if (hb_font && - hb_ot_metrics_get_position (hb_font, + if (prev && + hb_ot_metrics_get_position (pango_font_get_hb_font (prev->analysis.font), HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE, &y_size)) - entry->scale = y_size / (double) y_scale; + { + hb_font_get_scale (pango_font_get_hb_font (prev->analysis.font), NULL, &y_scale); + entry->scale = y_size / (double) y_scale; + } else - entry->scale = 1 / 1.2; + { + entry->scale = 1 / 1.2; + } + break; + case PANGO_FONT_SCALE_SMALL_CAPS: + if (hb_ot_metrics_get_position (pango_font_get_hb_font (item->analysis.font), + HB_OT_METRICS_TAG_CAP_HEIGHT, + &cap_height) && + hb_ot_metrics_get_position (pango_font_get_hb_font (item->analysis.font), + HB_OT_METRICS_TAG_X_HEIGHT, + &x_height)) + { + entry->scale = x_height / (double) cap_height; + } + else + { + entry->scale = 0.8; + } break; default: g_assert_not_reached (); @@ -1167,33 +1192,333 @@ apply_font_scale (PangoContext *context, } } +/* }}} */ +/* {{{ Handling Casing variants */ + +static gboolean +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; + guint script_count = HB_OT_MAX_TAGS_PER_SCRIPT; + hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT]; + hb_tag_t chosen_script; + 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 index; + + 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, HB_OT_TAG_GSUB, + script_count, script_tags, + &script_index, + &chosen_script); + hb_ot_layout_script_select_language (face, HB_OT_TAG_GSUB, + script_index, + language_count, language_tags, + &language_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 +variant_supported (PangoItem *item, + PangoVariant variant) +{ + hb_tag_t features[2]; + guint num_features = 0; + + switch (variant) + { + case PANGO_VARIANT_NORMAL: + 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; + case PANGO_VARIANT_UNICASE: + features[num_features++] = HB_TAG ('u', 'n', 'i', 'c'); + break; + default: + g_assert_not_reached (); + } + + return all_features_supported (item, features, num_features); +} + +static PangoVariant +get_font_variant (PangoItem *item) +{ + PangoFontDescription *desc; + PangoVariant variant; + + desc = pango_font_describe (item->analysis.font); + variant = pango_font_description_get_variant (desc); + pango_font_description_free (desc); + + return variant; +} + +static PangoTextTransform +find_text_transform (const PangoAnalysis *analysis) +{ + GSList *l; + PangoTextTransform transform = PANGO_TEXT_TRANSFORM_NONE; + + for (l = analysis->extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + if (attr->klass->type == PANGO_ATTR_TEXT_TRANSFORM) + transform = (PangoTextTransform) ((PangoAttrInt*)attr)->value; + } + + return transform; +} + +/* Split list_item into upper- and lowercase runs, and + * add font scale and text transform attributes to make + * them be appear according to variant. The log_attrs are + * needed for taking text transforms into account when + * determining the case of characters int he run. + */ +static void +split_item_for_variant (const char *text, + PangoLogAttr *log_attrs, + PangoVariant variant, + GList *list_item) +{ + PangoItem *item = list_item->data; + const char *start, *end; + const char *p, *p0; + gunichar wc; + PangoTextTransform transform = PANGO_TEXT_TRANSFORM_NONE; + PangoFontScale lowercase_scale = PANGO_FONT_SCALE_NONE; + PangoFontScale uppercase_scale = PANGO_FONT_SCALE_NONE; + PangoTextTransform item_transform; + gboolean is_word_start; + int offset; + + switch (variant) + { + case PANGO_VARIANT_ALL_SMALL_CAPS: + case PANGO_VARIANT_ALL_PETITE_CAPS: + uppercase_scale = PANGO_FONT_SCALE_SMALL_CAPS; + G_GNUC_FALLTHROUGH; + case PANGO_VARIANT_SMALL_CAPS: + case PANGO_VARIANT_PETITE_CAPS: + transform = PANGO_TEXT_TRANSFORM_UPPERCASE; + lowercase_scale = PANGO_FONT_SCALE_SMALL_CAPS; + break; + case PANGO_VARIANT_UNICASE: + uppercase_scale = PANGO_FONT_SCALE_SMALL_CAPS; + break; + case PANGO_VARIANT_NORMAL: + case PANGO_VARIANT_TITLE_CAPS: + default: + g_assert_not_reached (); + } + + item_transform = find_text_transform (&item->analysis); + + start = text + item->offset; + end = start + item->length; + offset = ((PangoItemPrivate *)item)->char_offset; + + p = start; + while (p < end) + { + p0 = p; + wc = g_utf8_get_char (p); + is_word_start = log_attrs && log_attrs[offset].is_word_start; + while (p < end && (item_transform == PANGO_TEXT_TRANSFORM_LOWERCASE || + consider_as_space (wc) || + (g_unichar_islower (wc) && + !(item_transform == PANGO_TEXT_TRANSFORM_UPPERCASE || + (item_transform == PANGO_TEXT_TRANSFORM_CAPITALIZE && is_word_start))))) + { + p = g_utf8_next_char (p); + wc = g_utf8_get_char (p); + offset++; + is_word_start = log_attrs && log_attrs[offset].is_word_start; + } + + if (p0 < p) + { + PangoItem *new_item; + PangoAttribute *attr; + + /* p0 .. p is a lowercase segment */ + 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 (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_append (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_append (new_item->analysis.extra_attrs, attr); + } + } + + p0 = p; + wc = g_utf8_get_char (p); + is_word_start = log_attrs && log_attrs[offset].is_word_start; + while (p < end && (item_transform == PANGO_TEXT_TRANSFORM_UPPERCASE || + consider_as_space (wc) || + !(item_transform == PANGO_TEXT_TRANSFORM_LOWERCASE || g_unichar_islower (wc)) || + (item_transform == PANGO_TEXT_TRANSFORM_CAPITALIZE && is_word_start))) + { + p = g_utf8_next_char (p); + wc = g_utf8_get_char (p); + offset++; + is_word_start = log_attrs && log_attrs[offset].is_word_start; + } + + if (p0 < p) + { + PangoItem *new_item; + PangoAttribute *attr; + + /* p0 .. p is a uppercase segment */ + 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_append (new_item->analysis.extra_attrs, attr); + } + } + } +} + +static void +handle_variants_for_item (const char *text, + PangoLogAttr *log_attrs, + GList *l) +{ + PangoItem *item = l->data; + PangoVariant variant; + + variant = get_font_variant (item); + if (!variant_supported (item, variant)) + split_item_for_variant (text, log_attrs, variant, l); +} + +static void +handle_variants (const char *text, + PangoLogAttr *log_attrs, + GList *items) +{ + GList *next; + + for (GList *l = items; l; l = next) + { + next = l->next; + handle_variants_for_item (text, log_attrs, l); + } +} + +/* }}} */ + static GList * -post_process_items (PangoContext *context, - GList *items) +reorder_items (PangoContext *context, + GList *items) { + int char_offset = 0; + items = g_list_reverse (items); - /* Compute the char offset for each item */ - { - int char_offset = 0; - for (GList *l = items; l; l = l->next) - { - PangoItemPrivate *item = l->data; - item->char_offset = char_offset; - char_offset += item->num_chars; - } - } - - /* apply font-scale */ + /* Also cmpute the char offset for each item here */ + for (GList *l = items; l; l = l->next) + { + PangoItemPrivate *item = l->data; + item->char_offset = char_offset; + char_offset += item->num_chars; + } + + return items; +} + +static GList * +post_process_items (PangoContext *context, + const char *text, + PangoLogAttr *log_attrs, + GList *items) +{ + handle_variants (text, log_attrs, items); apply_font_scale (context, items); return items; } /* }}} */ -/* {{{ Public API */ +/* {{{ Private API */ -/* Like pango_itemize_with_base_dir, but takes a font description */ +/* Like pango_itemize_with_base_dir, but takes a font description. + * In contrast to pango_itemize_with_base_dir, this function does + * not call pango_itemize_post_process_items, so you need to do that + * separately, after applying attributes that affect segmentation and + * computing the log attrs. + */ GList * pango_itemize_with_font (PangoContext *context, PangoDirection base_dir, @@ -1218,9 +1543,23 @@ pango_itemize_with_font (PangoContext *context, itemize_state_finish (&state); - return post_process_items (context, state.result); + return reorder_items (context, state.result); +} + +/* Apply post-processing steps that may require log attrs. + */ +GList * +pango_itemize_post_process_items (PangoContext *context, + const char *text, + PangoLogAttr *log_attrs, + GList *items) +{ + return post_process_items (context, text, log_attrs, items); } +/* }}} */ +/* {{{ Public API */ + /** * pango_itemize_with_base_dir: * @context: a structure holding information that affects @@ -1254,15 +1593,19 @@ pango_itemize_with_base_dir (PangoContext *context, PangoAttrList *attrs, PangoAttrIterator *cached_iter) { + GList *items; + g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (start_index >= 0, NULL); g_return_val_if_fail (length >= 0, NULL); g_return_val_if_fail (length == 0 || text != NULL, NULL); - return pango_itemize_with_font (context, base_dir, - text, start_index, length, - attrs, cached_iter, - NULL); + items = pango_itemize_with_font (context, base_dir, + text, start_index, length, + attrs, cached_iter, + NULL); + + return pango_itemize_post_process_items (context, text, NULL, items); } /** @@ -1306,12 +1649,11 @@ pango_itemize (PangoContext *context, g_return_val_if_fail (length >= 0, NULL); g_return_val_if_fail (length == 0 || text != NULL, NULL); - return pango_itemize_with_font (context, context->base_dir, - text, start_index, length, - attrs, cached_iter, - NULL); + return pango_itemize_with_base_dir (context, context->base_dir, + text, start_index, length, + attrs, cached_iter); } - /* }}} */ + /* }}} */ /* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 51b9b077..018417d5 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -253,9 +253,10 @@ typedef enum { * @PANGO_FONT_SCALE_NONE: Leave the font size unchanged * @PANGO_FONT_SCALE_SUPERSCRIPT: Change the font to a size suitable for superscripts * @PANGO_FONT_SCALE_SUBSCRIPT: Change the font to a size suitable for subscripts + * @PANGO_FONT_SCALE_SMALL_CAPS: Change the font to a size suitable for Small Caps. Since: 1.50 * * An enumeration that affects font sizes for superscript - * and subscript positioning. + * and subscript positioning and for (emulated) Small Caps. * * Since: 1.50 */ @@ -263,6 +264,7 @@ typedef enum { PANGO_FONT_SCALE_NONE, PANGO_FONT_SCALE_SUPERSCRIPT, PANGO_FONT_SCALE_SUBSCRIPT, + PANGO_FONT_SCALE_SMALL_CAPS, } PangoFontScale; /** diff --git a/pango/pango-context-private.h b/pango/pango-context-private.h index d65406e1..71f43b60 100644 --- a/pango/pango-context-private.h +++ b/pango/pango-context-private.h @@ -50,16 +50,6 @@ struct _PangoContext gboolean round_glyph_positions; }; -GList * pango_itemize_with_font (PangoContext *context, - PangoDirection base_dir, - const char *text, - int start_index, - int length, - PangoAttrList *attrs, - PangoAttrIterator *cached_iter, - const PangoFontDescription *desc); - - G_END_DECLS #endif /* __PANGO_CONTEXT_PRIVATE_H__ */ diff --git a/pango/pango-context.c b/pango/pango-context.c index 2301138f..d0166d94 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -28,6 +28,7 @@ #include "pango-impl-utils.h" #include "pango-font-private.h" +#include "pango-item-private.h" #include "pango-fontset-private.h" #include "pango-fontmap-private.h" #include "pango-script-private.h" diff --git a/pango/pango-font.h b/pango/pango-font.h index d4bded86..6f3284fa 100644 --- a/pango/pango-font.h +++ b/pango/pango-font.h @@ -81,13 +81,35 @@ typedef enum { * PangoVariant: * @PANGO_VARIANT_NORMAL: A normal font. * @PANGO_VARIANT_SMALL_CAPS: A font with the lower case characters - * replaced by smaller variants of the capital characters. + * replaced by smaller variants of the capital characters. + * @PANGO_VARIANT_ALL_SMALL_CAPS: A font with all characters + * replaced by smaller variants of the capital characters. + * Since: 1.50 + * @PANGO_VARIANT_PETITE_CAPS: A font with the lower case characters + * replaced by smaller variants of the capital characters. + * Petite Caps can be even smaller than Small Caps. + * Since: 1.50 + * @PANGO_VARIANT_ALL_PETITE_CAPS: A font with all characters + * replaced by smaller variants of the capital characters. + * Petite Caps can be even smaller than Small Caps. + * Since: 1.50 + * @PANGO_VARIANT_UNICASE: A font with the upper case characters + * replaced by smaller variants of the capital letters. + * Since: 1.50 + * @PANGO_VARIANT_TITLE_CAPS: A font with capital letters that + * are more suitable for all-uppercase titles. + * Since: 1.50 * * An enumeration specifying capitalization variant of the font. */ typedef enum { PANGO_VARIANT_NORMAL, - PANGO_VARIANT_SMALL_CAPS + PANGO_VARIANT_SMALL_CAPS, + PANGO_VARIANT_ALL_SMALL_CAPS, + PANGO_VARIANT_PETITE_CAPS, + PANGO_VARIANT_ALL_PETITE_CAPS, + PANGO_VARIANT_UNICASE, + PANGO_VARIANT_TITLE_CAPS } PangoVariant; /** diff --git a/pango/pango-item-private.h b/pango/pango-item-private.h index 8680fa4b..ef3e8ed0 100644 --- a/pango/pango-item-private.h +++ b/pango/pango-item-private.h @@ -22,6 +22,7 @@ #define __PANGO_ITEM_PRIVATE_H__ #include <pango/pango-item.h> +#include <pango/pango-break.h> G_BEGIN_DECLS @@ -68,6 +69,26 @@ G_STATIC_ASSERT (offsetof (PangoItem, length) == offsetof (PangoItemPrivate, len G_STATIC_ASSERT (offsetof (PangoItem, num_chars) == offsetof (PangoItemPrivate, num_chars)); G_STATIC_ASSERT (offsetof (PangoItem, analysis) == offsetof (PangoItemPrivate, analysis)); +void pango_analysis_collect_features (const PangoAnalysis *analysis, + hb_feature_t *features, + guint length, + guint *num_features); + +GList * pango_itemize_with_font (PangoContext *context, + PangoDirection base_dir, + const char *text, + int start_index, + int length, + PangoAttrList *attrs, + PangoAttrIterator *cached_iter, + const PangoFontDescription *desc); + +GList * pango_itemize_post_process_items (PangoContext *context, + const char *text, + PangoLogAttr *log_attrs, + GList *items); + + G_END_DECLS #endif /* __PANGO_ITEM_PRIVATE_H__ */ diff --git a/pango/pango-item.c b/pango/pango-item.c index 484d5f1f..4b02c277 100644 --- a/pango/pango-item.c +++ b/pango/pango-item.c @@ -231,3 +231,71 @@ pango_item_apply_attrs (PangoItem *item, item->analysis.extra_attrs = g_slist_concat (item->analysis.extra_attrs, attrs); } + +void +pango_analysis_collect_features (const PangoAnalysis *analysis, + hb_feature_t *features, + guint length, + guint *num_features) +{ + GSList *l; + + pango_font_get_features (analysis->font, features, length, num_features); + + for (l = analysis->extra_attrs; l && *num_features < length; l = l->next) + { + PangoAttribute *attr = l->data; + if (attr->klass->type == PANGO_ATTR_FONT_FEATURES) + { + PangoAttrFontFeatures *fattr = (PangoAttrFontFeatures *) attr; + const gchar *feat; + const gchar *end; + int len; + + feat = fattr->features; + + while (feat != NULL && *num_features < length) + { + end = strchr (feat, ','); + if (end) + len = end - feat; + else + len = -1; + if (hb_feature_from_string (feat, len, &features[*num_features])) + { + features[*num_features].start = attr->start_index; + features[*num_features].end = attr->end_index; + (*num_features)++; + } + + if (end == NULL) + break; + + feat = end + 1; + } + } + } + + /* Turn off ligatures when letterspacing */ + for (l = analysis->extra_attrs; l && *num_features < length; l = l->next) + { + PangoAttribute *attr = l->data; + if (attr->klass->type == PANGO_ATTR_LETTER_SPACING) + { + hb_tag_t tags[] = { + HB_TAG('l','i','g','a'), + HB_TAG('c','l','i','g'), + HB_TAG('d','l','i','g'), + }; + int i; + for (i = 0; i < G_N_ELEMENTS (tags); i++) + { + features[*num_features].tag = tags[i]; + features[*num_features].value = 0; + features[*num_features].start = attr->start_index; + features[*num_features].end = attr->end_index; + (*num_features)++; + } + } + } +} diff --git a/pango/pango-layout.c b/pango/pango-layout.c index ba81adf6..9e8ce248 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -4534,13 +4534,14 @@ pango_layout_check_lines (PangoLayout *layout) g_assert (delim_len >= 0); state.attrs = itemize_attrs; - state.items = pango_itemize_with_base_dir (layout->context, - base_dir, - layout->text, - start - layout->text, - end - start, - itemize_attrs, - itemize_attrs ? &iter : NULL); + state.items = pango_itemize_with_font (layout->context, + base_dir, + layout->text, + start - layout->text, + end - start, + itemize_attrs, + itemize_attrs ? &iter : NULL, + NULL); apply_attributes_to_items (state.items, shape_attrs); @@ -4553,6 +4554,11 @@ pango_layout_check_lines (PangoLayout *layout) layout->log_attrs + start_offset, layout->n_chars + 1 - start_offset); + state.items = pango_itemize_post_process_items (layout->context, + layout->text, + layout->log_attrs + start_offset, + state.items); + state.base_dir = base_dir; state.line_of_par = 1; state.start_offset = start_offset; diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c index 113142fd..076ca291 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -1915,8 +1915,33 @@ pango_fc_make_pattern (const PangoFontDescription *description, if (prgname) FcPatternAddString (pattern, PANGO_FC_PRGNAME, (FcChar8*) prgname); - if (variant == PANGO_VARIANT_SMALL_CAPS) - FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "smcp=1"); + switch (variant) + { + case PANGO_VARIANT_SMALL_CAPS: + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "smcp=1"); + break; + case PANGO_VARIANT_ALL_SMALL_CAPS: + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "smcp=1"); + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "c2sc=1"); + break; + case PANGO_VARIANT_PETITE_CAPS: + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "pcap=1"); + break; + case PANGO_VARIANT_ALL_PETITE_CAPS: + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "pcap=1"); + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "c2pc=1"); + break; + case PANGO_VARIANT_UNICASE: + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "unic=1"); + break; + case PANGO_VARIANT_TITLE_CAPS: + FcPatternAddString (pattern, PANGO_FC_FONT_FEATURES, (FcChar8*) "titl=1"); + break; + case PANGO_VARIANT_NORMAL: + break; + default: + g_assert_not_reached (); + } return pattern; } @@ -2756,6 +2781,8 @@ pango_fc_font_description_from_pattern (FcPattern *pattern, gboolean include_siz PangoStretch stretch; double size; PangoGravity gravity; + PangoVariant variant; + gboolean all_caps; FcChar8 *s; int i; @@ -2790,7 +2817,8 @@ pango_fc_font_description_from_pattern (FcPattern *pattern, gboolean include_siz pango_font_description_set_stretch (desc, stretch); - pango_font_description_set_variant (desc, PANGO_VARIANT_NORMAL); + variant = PANGO_VARIANT_NORMAL; + all_caps = FALSE; for (int i = 0; i < 32; i++) { @@ -2800,14 +2828,47 @@ pango_fc_font_description_from_pattern (FcPattern *pattern, gboolean include_siz { if (strcmp (s, "smcp=1") == 0) { - pango_font_description_set_variant (desc, PANGO_VARIANT_SMALL_CAPS); - break; + if (all_caps) + variant = PANGO_VARIANT_ALL_SMALL_CAPS; + else + variant = PANGO_VARIANT_SMALL_CAPS; + } + else if (strcmp (s, "c2sc=1") == 0) + { + if (variant == PANGO_VARIANT_SMALL_CAPS) + variant = PANGO_VARIANT_ALL_SMALL_CAPS; + else + all_caps = TRUE; + } + else if (strcmp (s, "pcap=1") == 0) + { + if (all_caps) + variant = PANGO_VARIANT_ALL_PETITE_CAPS; + else + variant = PANGO_VARIANT_PETITE_CAPS; + } + else if (strcmp (s, "c2pc=1") == 0) + { + if (variant == PANGO_VARIANT_PETITE_CAPS) + variant = PANGO_VARIANT_ALL_PETITE_CAPS; + else + all_caps = TRUE; + } + else if (strcmp (s, "unic=1") == 0) + { + variant = PANGO_VARIANT_UNICASE; + } + else if (strcmp (s, "titl=1") == 0) + { + variant = PANGO_VARIANT_TITLE_CAPS; } } else break; } + pango_font_description_set_variant (desc, variant); + if (include_size && FcPatternGetDouble (pattern, FC_SIZE, 0, &size) == FcResultMatch) { FcMatrix *fc_matrix; diff --git a/pango/shape.c b/pango/shape.c index 52a7aabb..02f0f059 100644 --- a/pango/shape.c +++ b/pango/shape.c @@ -28,6 +28,7 @@ #include "pango-impl-utils.h" #include "pango-glyph.h" +#include "pango-item-private.h" #include "pango-font-private.h" #include <hb-ot.h> @@ -222,72 +223,6 @@ pango_font_get_hb_font_for_context (PangoFont *font, /* }}} */ /* {{{ Utilities */ -static void -apply_extra_attributes (GSList *attrs, - hb_feature_t *features, - guint length, - guint *num_features) -{ - GSList *l; - - for (l = attrs; l && *num_features < length; l = l->next) - { - PangoAttribute *attr = l->data; - if (attr->klass->type == PANGO_ATTR_FONT_FEATURES) - { - PangoAttrFontFeatures *fattr = (PangoAttrFontFeatures *) attr; - const gchar *feat; - const gchar *end; - int len; - - feat = fattr->features; - - while (feat != NULL && *num_features < length) - { - end = strchr (feat, ','); - if (end) - len = end - feat; - else - len = -1; - if (hb_feature_from_string (feat, len, &features[*num_features])) - { - features[*num_features].start = attr->start_index; - features[*num_features].end = attr->end_index; - (*num_features)++; - } - - if (end == NULL) - break; - - feat = end + 1; - } - } - } - - /* Turn off ligatures when letterspacing */ - for (l = attrs; l && *num_features < length; l = l->next) - { - PangoAttribute *attr = l->data; - if (attr->klass->type == PANGO_ATTR_LETTER_SPACING) - { - hb_tag_t tags[] = { - HB_TAG('l','i','g','a'), - HB_TAG('c','l','i','g'), - HB_TAG('d','l','i','g'), - }; - int i; - for (i = 0; i < G_N_ELEMENTS (tags); i++) - { - features[*num_features].tag = tags[i]; - features[*num_features].value = 0; - features[*num_features].start = attr->start_index; - features[*num_features].end = attr->end_index; - (*num_features)++; - } - } - } -} - static PangoShowFlags find_show_flags (const PangoAnalysis *analysis) { @@ -309,16 +244,17 @@ static PangoTextTransform find_text_transform (const PangoAnalysis *analysis) { GSList *l; + PangoTextTransform transform = PANGO_TEXT_TRANSFORM_NONE; for (l = analysis->extra_attrs; l; l = l->next) { PangoAttribute *attr = l->data; if (attr->klass->type == PANGO_ATTR_TEXT_TRANSFORM) - return (PangoTextTransform) ((PangoAttrInt*)attr)->value; + transform = (PangoTextTransform) ((PangoAttrInt*)attr)->value; } - return PANGO_TEXT_TRANSFORM_NONE; + return transform; } static gboolean @@ -506,8 +442,7 @@ pango_hb_shape (const char *item_text, hb_buffer_add (hb_buffer, '-', hyphen_index); } - pango_font_get_features (analysis->font, features, G_N_ELEMENTS (features), &num_features); - apply_extra_attributes (analysis->extra_attrs, features, G_N_ELEMENTS (features), &num_features); + pango_analysis_collect_features (analysis, features, G_N_ELEMENTS (features), &num_features); hb_shape (hb_font, hb_buffer, features, num_features); |