📄 pango-markup.c
字号:
/* set next range_start to include this char */ range_start = p; } /* reset range_end */ range_end = NULL; } else if (c == md->accel_marker) { range_end = p; } p = g_utf8_next_char (p); } if (range_end) { g_string_append_len (md->text, range_start, range_end - range_start); md->index += range_end - range_start; } else { g_string_append_len (md->text, range_start, end - range_start); md->index += end - range_start; } if (md->attr_list != NULL && uline_index >= 0) { /* Add the underline indicating the accelerator */ PangoAttribute *attr; attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW); attr->start_index = uline_index; attr->end_index = uline_index + uline_len; pango_attr_list_change (md->attr_list, attr); } }}static gbooleanxml_isspace (char c){ return c == ' ' || c == '\t' || c == '\n' || c == '\r';}static const GMarkupParser pango_markup_parser = { start_element_handler, end_element_handler, text_handler, NULL, NULL};/** * pango_parse_markup: * @markup_text: markup to parse (see <link linkend="PangoMarkupFormat">markup format</link>) * @length: length of @markup_text, or -1 if nul-terminated * @accel_marker: character that precedes an accelerator, or 0 for none * @attr_list: address of return location for a #PangoAttrList, or %NULL * @text: address of return location for text with tags stripped, or %NULL * @accel_char: address of return location for accelerator char, or %NULL * @error: address of return location for errors, or %NULL * * * Parses marked-up text (see * <link linkend="PangoMarkupFormat">markup format</link>) to create * a plain-text string and an attribute list. * * If @accel_marker is nonzero, the given character will mark the * character following it as an accelerator. For example, @accel_marker * might be an ampersand or underscore. All characters marked * as an accelerator will receive a %PANGO_UNDERLINE_LOW attribute, * and the first character so marked will be returned in @accel_char. * Two @accel_marker characters following each other produce a single * literal @accel_marker character. * * Return value: %FALSE if @error is set, otherwise %TRUE **/gbooleanpango_parse_markup (const char *markup_text, int length, gunichar accel_marker, PangoAttrList **attr_list, char **text, gunichar *accel_char, GError **error){ GMarkupParseContext *context = NULL; MarkupData *md = NULL; gboolean needs_root = TRUE; GSList *tmp_list; const char *p; const char *end; g_return_val_if_fail (markup_text != NULL, FALSE); md = g_slice_new (MarkupData); /* Don't bother creating these if they weren't requested; * might be useful e.g. if you just want to validate * some markup. */ if (attr_list) md->attr_list = pango_attr_list_new (); else md->attr_list = NULL; md->text = g_string_new (NULL); if (accel_char) *accel_char = 0; md->accel_marker = accel_marker; md->accel_char = 0; md->index = 0; md->tag_stack = NULL; md->to_apply = NULL; context = g_markup_parse_context_new (&pango_markup_parser, 0, md, NULL); if (length < 0) length = strlen (markup_text); p = markup_text; end = markup_text + length; while (p != end && xml_isspace (*p)) ++p; if (end - p >= 8 && strncmp (p, "<markup>", 8) == 0) needs_root = FALSE; if (needs_root) if (!g_markup_parse_context_parse (context, "<markup>", -1, error)) goto error; if (!g_markup_parse_context_parse (context, markup_text, length, error)) goto error; if (needs_root) if (!g_markup_parse_context_parse (context, "</markup>", -1, error)) goto error; if (!g_markup_parse_context_end_parse (context, error)) goto error; g_markup_parse_context_free (context); if (md->attr_list) { /* The apply list has the most-recently-closed tags first; * we want to apply the least-recently-closed tag last. */ tmp_list = md->to_apply; while (tmp_list != NULL) { PangoAttribute *attr = tmp_list->data; /* Innermost tags before outermost */ pango_attr_list_change (md->attr_list, attr); tmp_list = g_slist_next (tmp_list); } g_slist_free (md->to_apply); md->to_apply = NULL; } if (attr_list) *attr_list = md->attr_list; if (text) *text = g_string_free (md->text, FALSE); else g_string_free (md->text, TRUE); if (accel_char) *accel_char = md->accel_char; g_assert (md->tag_stack == NULL); g_slice_free (MarkupData, md); return TRUE; error: g_slist_foreach (md->tag_stack, (GFunc) open_tag_free, NULL); g_slist_free (md->tag_stack); g_slist_foreach (md->to_apply, (GFunc) pango_attribute_destroy, NULL); g_slist_free (md->to_apply); g_string_free (md->text, TRUE); if (md->attr_list) pango_attr_list_unref (md->attr_list); g_slice_free (MarkupData, md); if (context) g_markup_parse_context_free (context); return FALSE;}static voidset_bad_attribute (GError **error, GMarkupParseContext *context, const char *element_name, const char *attribute_name){ gint line_number, char_number; g_markup_parse_context_get_position (context, &line_number, &char_number); g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Tag '%s' does not support attribute '%s' on line %d char %d"), element_name, attribute_name, line_number, char_number);}static voidadd_attribute (OpenTag *ot, PangoAttribute *attr){ if (ot == NULL) pango_attribute_destroy (attr); else ot->attrs = g_slist_prepend (ot->attrs, attr);}#define CHECK_NO_ATTRS(elem) G_STMT_START { \ if (*names != NULL) { \ set_bad_attribute (error, context, (elem), *names); \ return FALSE; \ } }G_STMT_ENDstatic gbooleanb_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error){ CHECK_NO_ATTRS("b"); add_attribute (tag, pango_attr_weight_new (PANGO_WEIGHT_BOLD)); return TRUE;}static gbooleanbig_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error){ CHECK_NO_ATTRS("big"); /* Grow text one level */ if (tag) { tag->scale_level_delta += 1; tag->scale_level += 1; } return TRUE;}static gbooleanparse_absolute_size (OpenTag *tag, const char *size){ SizeLevel level = Medium; double factor; if (strcmp (size, "xx-small") == 0) level = XXSmall; else if (strcmp (size, "x-small") == 0) level = XSmall; else if (strcmp (size, "small") == 0) level = Small; else if (strcmp (size, "medium") == 0) level = Medium; else if (strcmp (size, "large") == 0) level = Large; else if (strcmp (size, "x-large") == 0) level = XLarge; else if (strcmp (size, "xx-large") == 0) level = XXLarge; else return FALSE; /* This is "absolute" in that it's relative to the base font, * but not to sizes created by any other tags */ factor = scale_factor (level, 1.0); add_attribute (tag, pango_attr_scale_new (factor)); if (tag) open_tag_set_absolute_font_scale (tag, factor); return TRUE;}/* a string compare func that ignores '-' vs '_' differences */static gintattr_strcmp (gconstpointer pa, gconstpointer pb){ const char *a = pa; const char *b = pb; int ca; int cb; while (*a && *b) { ca = *a++; cb = *b++; if (ca == cb) continue; ca = ca == '_' ? '-' : ca; cb = cb == '_' ? '-' : cb; if (ca != cb) return cb - ca; } ca = *a; cb = *b; return cb - ca;}static gbooleanspan_parse_int (const char *attr_name, const char *attr_val, int *val, int line_number, GError **error){ const char *end = attr_val; if (!pango_scan_int (&end, val) || *end != '\0') { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Value of '%s' attribute on <span> tag " "on line %d could not be parsed; " "should be an integer, not '%s'"), attr_name, line_number, attr_val); return FALSE; } return TRUE;}static gbooleanspan_parse_boolean (const char *attr_name, const char *attr_val, gboolean *val, int line_number, GError **error){ const char *end = attr_val; if (strcmp (attr_val, "true") == 0 || strcmp (attr_val, "yes") == 0 || strcmp (attr_val, "t") == 0 || strcmp (attr_val, "y") == 0) *val = TRUE; else if (strcmp (attr_val, "false") == 0 || strcmp (attr_val, "no") == 0 || strcmp (attr_val, "f") == 0 || strcmp (attr_val, "n") == 0) *val = FALSE; else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Value of '%s' attribute on <span> tag " "line %d should have one of " "'true/yes/t/y' or 'false/no/f/n': '%s' is not valid"), attr_name, line_number, attr_val); return FALSE; } return TRUE;}static gbooleanspan_parse_color (const char *attr_name, const char *attr_val, PangoColor *color, int line_number, GError **error){ if (!pango_color_parse (color, attr_val)) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Value of '%s' attribute on <span> tag " "on line %d could not be parsed; " "should be a color specification, not '%s'"), attr_name, line_number, attr_val); return FALSE; } return TRUE;}static gbooleanspan_parse_enum (const char *attr_name, const char *attr_val, GType type, int *val, int line_number, GError **error){ char *possible_values = NULL; if (!pango_parse_enum (type, attr_val, val, FALSE, &possible_values)) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("'%s' is not a valid value for the '%s' " "attribute on <span> tag, line %d; valid " "values are %s"), attr_val, attr_name, line_number, possible_values); g_free (possible_values); return FALSE; } return TRUE;}static gbooleanspan_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error){ int line_number, char_number; int i; const char *family = NULL; const char *size = NULL; const char *style = NULL; const char *weight = NULL; const char *variant = NULL; const char *stretch = NULL; const char *desc = NULL; const char *foreground = NULL; const char *background = NULL; const char *underline = NULL; const char *underline_color = NULL; const char *strikethrough = NULL; const char *strikethrough_color = NULL; const char *rise = NULL; const char *letter_spacing = NULL; const char *lang = NULL; const char *fallback = NULL; const char *gravity = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -