diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-11-13 18:33:00 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-11-14 01:55:07 -0500 |
commit | 1056a0aeed821d6250cdef426a767bf215431b75 (patch) | |
tree | ae6184f1ab014f660fa88769ced5d3f88104e970 /pango | |
parent | 8247bfeb9cb9e40e4af020e94f3a747e5c9aae2d (diff) | |
download | pango-1056a0aeed821d6250cdef426a767bf215431b75.tar.gz |
Add pango_attr_list_to/from_string
Add an api to serialize PangoAttrList.
This will be useful in testing and debugging.
Diffstat (limited to 'pango')
-rw-r--r-- | pango/pango-attributes.c | 472 | ||||
-rw-r--r-- | pango/pango-attributes.h | 5 |
2 files changed, 477 insertions, 0 deletions
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index c929a3d5..2f6b4eb2 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -2524,6 +2524,478 @@ pango_attr_list_filter (PangoAttrList *list, return new; } +/* {{{ PangoAttrList serialization */ + +/* We serialize attribute lists to strings. The format + * is a comma-separated list of the attributes in the order + * in which they are in the list, with each attribute having + * this format: + * + * START END NICK VALUE + * + * Values that can contain a comma, such as font descriptions + * are quoted with "". + */ + +static const char * +get_attr_value_nick (PangoAttrType attr_type) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + + enum_class = g_type_class_ref (pango_attr_type_get_type ()); + enum_value = g_enum_get_value (enum_class, attr_type); + g_type_class_unref (enum_class); + + return enum_value->value_nick; +} + +static void +attr_print (GString *str, + PangoAttribute *attr) +{ + PangoAttrString *string; + PangoAttrLanguage *lang; + PangoAttrInt *integer; + PangoAttrFloat *flt; + PangoAttrFontDesc *font; + PangoAttrColor *color; + PangoAttrShape *shape; + PangoAttrSize *size; + PangoAttrFontFeatures *features; + + g_string_append_printf (str, "%u %u ", attr->start_index, attr->end_index); + + g_string_append (str, get_attr_value_nick (attr->klass->type)); + + if ((string = pango_attribute_as_string (attr)) != NULL) + g_string_append_printf (str, " %s", string->value); + else if ((lang = pango_attribute_as_language (attr)) != NULL) + g_string_append_printf (str, " %s", pango_language_to_string (lang->value)); + else if ((integer = pango_attribute_as_int (attr)) != NULL) + g_string_append_printf (str, " %d", integer->value); + else if ((flt = pango_attribute_as_float (attr)) != NULL) + { + char buf[20]; + g_ascii_formatd (buf, 20, " %f", flt->value); + g_string_append_printf (str, " %s", buf); + } + else if ((font = pango_attribute_as_font_desc (attr)) != NULL) + { + char *s = pango_font_description_to_string (font->desc); + g_string_append_printf (str, " \"%s\"", s); + g_free (s); + } + else if ((color = pango_attribute_as_color (attr)) != NULL) + { + char *s = pango_color_to_string (&color->color); + g_string_append_printf (str, " %s", s); + g_free (s); + } + else if ((shape = pango_attribute_as_shape (attr)) != NULL) + g_string_append (str, "shape"); /* FIXME */ + else if ((size = pango_attribute_as_size (attr)) != NULL) + g_string_append_printf (str, " %d", size->size); + else if ((features = pango_attribute_as_font_features (attr)) != NULL) + g_string_append_printf (str, " \"%s\"", features->features); + else + g_assert_not_reached (); +} + +/* }}} */ + +/** + * pango_attr_list_to_string: + * @list: a `PangoAttrList` + * + * Serializes a `PangoAttrList` to a string. + * + * No guarantees are made about the format of the string, + * it may change between Pango versions. + * + * The intended use of this function is testing and + * debugging. The format is not meant as a permanent + * storage format. + * + * Returns: (transfer full): a newly allocated string + * Since: 1.50 + */ +char * +pango_attr_list_to_string (PangoAttrList *list) +{ + GString *s; + + s = g_string_new (""); + + if (list->attributes) + for (int i = 0; i < list->attributes->len; i++) + { + PangoAttribute *attr = g_ptr_array_index (list->attributes, i); + + if (i > 0) + g_string_append (s, ",\n"); + attr_print (s, attr); + } + + return g_string_free (s, FALSE); +} + +static PangoAttrType +get_attr_type_by_nick (const char *nick) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + + enum_class = g_type_class_ref (pango_attr_type_get_type ()); + enum_value = g_enum_get_value_by_nick (enum_class, nick); + g_type_class_unref (enum_class); + + if (enum_value) + return (PangoAttrType) enum_value->value; + + return PANGO_ATTR_INVALID; +} + +static const char * +skip_whitespace (const char *p) +{ + while (g_ascii_isspace (*p)) + p++; + return p; +} + +static const char * +next_whitespace (const char *p) +{ + while (*p && !g_ascii_isspace (*p)) + p++; + return p; +} + +static const char * +next_comma (const char *p) +{ + while (*p && *p != ',') + p++; + return p; +} + +static gboolean +is_valid_end_char (char c) +{ + return c == ',' || g_ascii_isspace (c) || c == '\0'; +} + +/** + * pango_attr_list_from_string: + * @text: a string + * + * Deserializes a `PangoAttrList` from a string. + * + * This is the counterpart to [func@Pango.AttrList.to_string]. + * See that functions for details about the format. + * + * Returns: (transfer full) (nullable): a new `PangoAttrList` + * Since: 1.50 + */ +PangoAttrList * +pango_attr_list_from_string (const char *text) +{ + PangoAttrList *list; + const char *p; + + g_return_val_if_fail (text != NULL, NULL); + + list = pango_attr_list_new (); + + if (*text == '\0') + return list; + + list->attributes = g_ptr_array_new (); + + p = skip_whitespace (text); + while (*p) + { + char *endp; + gint64 start_index; + gint64 end_index; + char *str; + PangoAttrType type; + PangoAttribute *attr; + PangoLanguage *lang; + gint64 integer; + PangoFontDescription *desc; + PangoColor color; + double num; + + start_index = g_ascii_strtoll (p, &endp, 10); + if (*endp != ' ') + goto fail; + + p = skip_whitespace (endp); + if (!*p) + goto fail; + + end_index = g_ascii_strtoll (p, &endp, 10); + if (*endp != ' ') + goto fail; + + p = skip_whitespace (endp); + + endp = (char *)next_whitespace (p); + str = g_strndup (p, endp - p); + type = get_attr_type_by_nick (str); + g_free (str); + + p = skip_whitespace (endp); + if (*p == '\0') + goto fail; + +#define INT_ATTR(name,type) \ + integer = g_ascii_strtoll (p, &endp, 10); \ + if (!is_valid_end_char (*endp)) goto fail; \ + attr = pango_attr_##name##_new ((type)integer); + +#define ENUM_ATTR(name,type, min, max) \ + integer = g_ascii_strtoll (p, &endp, 10); \ + if (!is_valid_end_char (*endp)) goto fail; \ + attr = pango_attr_##name##_new ((type)CLAMP(integer,min,max)); + +#define FLOAT_ATTR(name) \ + num = g_ascii_strtod (p, &endp); \ + if (!is_valid_end_char (*endp)) goto fail; \ + attr = pango_attr_##name##_new ((float)num); + +#define COLOR_ATTR(name) \ + endp = (char *)next_comma (p); \ + if (!is_valid_end_char (*endp)) goto fail; \ + str = g_strndup (p, endp - p); \ + if (!pango_color_parse (&color, str)) \ + { \ + g_free (str); \ + goto fail; \ + } \ + attr = pango_attr_##name##_new (color.red, color.green, color.blue); \ + g_free (str); + + switch (type) + { + case PANGO_ATTR_INVALID: + pango_attr_list_unref (list); + return NULL; + + case PANGO_ATTR_LANGUAGE: + endp = (char *)next_comma (p); + if (!is_valid_end_char (*endp)) goto fail; + str = g_strndup (p, endp - p); + lang = pango_language_from_string (str); + attr = pango_attr_language_new (lang); + g_free (str); + break; + + case PANGO_ATTR_FAMILY: + endp = (char *)next_comma (p); + if (!is_valid_end_char (*endp)) goto fail; + str = g_strndup (p, endp - p); + attr = pango_attr_family_new (str); + g_free (str); + break; + + case PANGO_ATTR_STYLE: + INT_ATTR(style, PangoStyle); + break; + + case PANGO_ATTR_WEIGHT: + INT_ATTR(weight, PangoWeight); + break; + + case PANGO_ATTR_VARIANT: + INT_ATTR(variant, PangoVariant); + break; + + case PANGO_ATTR_STRETCH: + INT_ATTR(stretch, PangoStretch); + break; + + case PANGO_ATTR_SIZE: + INT_ATTR(size, int); + break; + + case PANGO_ATTR_FONT_DESC: + p++; + endp = strchr (p, '"'); + if (!endp) goto fail; + str = g_strndup (p, endp - p); + desc = pango_font_description_from_string (str); + attr = pango_attr_font_desc_new (desc); + pango_font_description_free (desc); + g_free (str); + endp++; + break; + + case PANGO_ATTR_FOREGROUND: + COLOR_ATTR(foreground); + break; + + case PANGO_ATTR_BACKGROUND: + COLOR_ATTR(background); + break; + + case PANGO_ATTR_UNDERLINE: + ENUM_ATTR(underline, PangoUnderline, PANGO_UNDERLINE_NONE, PANGO_UNDERLINE_ERROR_LINE); + break; + + case PANGO_ATTR_STRIKETHROUGH: + INT_ATTR(strikethrough, gboolean); + break; + + case PANGO_ATTR_RISE: + INT_ATTR(rise, int); + break; + + case PANGO_ATTR_SHAPE: + endp = (char *)next_comma (p); + p = skip_whitespace (endp); + continue; /* FIXME */ + + case PANGO_ATTR_SCALE: + + FLOAT_ATTR(scale); + break; + + case PANGO_ATTR_FALLBACK: + INT_ATTR(fallback, gboolean); + break; + + case PANGO_ATTR_LETTER_SPACING: + INT_ATTR(letter_spacing, int); + break; + + case PANGO_ATTR_UNDERLINE_COLOR: + COLOR_ATTR(underline_color); + break; + + case PANGO_ATTR_STRIKETHROUGH_COLOR: + COLOR_ATTR(strikethrough_color); + break; + + case PANGO_ATTR_ABSOLUTE_SIZE: + integer = g_ascii_strtoll (p, &endp, 10); + if (!is_valid_end_char (*endp)) goto fail; + attr = pango_attr_size_new_absolute (integer); + break; + + case PANGO_ATTR_GRAVITY: + ENUM_ATTR(gravity, PangoGravity, PANGO_GRAVITY_SOUTH, PANGO_GRAVITY_WEST); + break; + + case PANGO_ATTR_FONT_FEATURES: + p++; + endp = strchr (p, '"'); + if (!endp) goto fail; + str = g_strndup (p, endp - p); + attr = pango_attr_font_features_new (str); + g_free (str); + endp++; + break; + + case PANGO_ATTR_GRAVITY_HINT: + ENUM_ATTR(gravity_hint, PangoGravityHint, PANGO_GRAVITY_HINT_NATURAL, PANGO_GRAVITY_HINT_LINE); + break; + + case PANGO_ATTR_FOREGROUND_ALPHA: + INT_ATTR(foreground_alpha, int); + break; + + case PANGO_ATTR_BACKGROUND_ALPHA: + INT_ATTR(background_alpha, int); + break; + + case PANGO_ATTR_ALLOW_BREAKS: + INT_ATTR(allow_breaks, gboolean); + break; + + case PANGO_ATTR_SHOW: + INT_ATTR(show, PangoShowFlags); + break; + + case PANGO_ATTR_INSERT_HYPHENS: + INT_ATTR(insert_hyphens, gboolean); + break; + + case PANGO_ATTR_OVERLINE: + ENUM_ATTR(overline, PangoOverline, PANGO_OVERLINE_NONE, PANGO_OVERLINE_SINGLE); + break; + + case PANGO_ATTR_OVERLINE_COLOR: + COLOR_ATTR(overline_color); + break; + + case PANGO_ATTR_LINE_HEIGHT: + FLOAT_ATTR(line_height); + break; + + case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: + integer = g_ascii_strtoll (p, &endp, 10); + if (!is_valid_end_char (*endp)) goto fail; + attr = pango_attr_line_height_new_absolute (integer); + break; + + case PANGO_ATTR_TEXT_TRANSFORM: + ENUM_ATTR(text_transform, PangoTextTransform, PANGO_TEXT_TRANSFORM_NONE, PANGO_TEXT_TRANSFORM_CAPITALIZE); + break; + + case PANGO_ATTR_WORD: + integer = g_ascii_strtoll (p, &endp, 10); + if (!is_valid_end_char (*endp)) goto fail; + attr = pango_attr_word_new (); + break; + + case PANGO_ATTR_SENTENCE: + integer = g_ascii_strtoll (p, &endp, 10); + if (!is_valid_end_char (*endp)) goto fail; + attr = pango_attr_sentence_new (); + break; + + case PANGO_ATTR_BASELINE_SHIFT: + INT_ATTR(baseline_shift, int); + break; + + case PANGO_ATTR_FONT_SCALE: + ENUM_ATTR(font_scale, PangoFontScale, PANGO_FONT_SCALE_NONE, PANGO_FONT_SCALE_SMALL_CAPS); + break; + + default: + g_assert_not_reached (); + } + + attr->start_index = start_index; + attr->end_index = end_index; + g_ptr_array_add (list->attributes, attr); + + p = endp; + if (*p) + { + gboolean had_comma = *p == ','; + + if (had_comma) + p++; + p = skip_whitespace (p); + if (*p == '\0' && had_comma) + goto fail; /* trailing comma */ + } + } + + goto success; + +fail: + pango_attr_list_unref (list); + list = NULL; + +success: + return list; +} + /* }}} */ /* {{{ Attribute Iterator */ diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 018417d5..5ea6bd9e 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -707,6 +707,11 @@ PANGO_AVAILABLE_IN_1_46 gboolean pango_attr_list_equal (PangoAttrList *list, PangoAttrList *other_list); +PANGO_AVAILABLE_IN_1_50 +char * pango_attr_list_to_string (PangoAttrList *list); +PANGO_AVAILABLE_IN_1_50 +PangoAttrList * pango_attr_list_from_string (const char *text); + PANGO_AVAILABLE_IN_1_44 GType pango_attr_iterator_get_type (void) G_GNUC_CONST; |