📄 pango-markup.c
字号:
/* Pango * pango-markup.c: Parse markup into attributed text * * Copyright (C) 2000 Red Hat Software * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <config.h>#include <string.h>#include <stdlib.h>#include <errno.h>#include "pango-attributes.h"#include "pango-font.h"#include "pango-enum-types.h"#include "pango-impl-utils.h"/* FIXME */#define _(x) x/* CSS size levels */typedef enum{ XXSmall = -3, XSmall = -2, Small = -1, Medium = 0, Large = 1, XLarge = 2, XXLarge = 3} SizeLevel;typedef struct _MarkupData MarkupData;struct _MarkupData{ PangoAttrList *attr_list; GString *text; GSList *tag_stack; gsize index; GSList *to_apply; gunichar accel_marker; gunichar accel_char;};typedef struct _OpenTag OpenTag;struct _OpenTag{ GSList *attrs; gsize start_index; /* Current total scale level; reset whenever * an absolute size is set. * Each "larger" ups it 1, each "smaller" decrements it 1 */ gint scale_level; /* Our impact on scale_level, so we know whether we * need to create an attribute ourselves on close */ gint scale_level_delta; /* Base scale factor currently in effect * or size that this tag * forces, or parent's scale factor or size. */ double base_scale_factor; int base_font_size; guint has_base_font_size : 1;};typedef gboolean (*TagParseFunc) (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean b_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean big_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean span_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean i_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean markup_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean s_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean sub_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean sup_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean small_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean tt_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static gboolean u_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error);static doublescale_factor (int scale_level, double base){ double factor = base; int i; /* 1.2 is the CSS scale factor between sizes */ if (scale_level > 0) { i = 0; while (i < scale_level) { factor *= 1.2; ++i; } } else if (scale_level < 0) { i = scale_level; while (i < 0) { factor /= 1.2; ++i; } } return factor;}static voidopen_tag_free (OpenTag *ot){ g_slist_foreach (ot->attrs, (GFunc) pango_attribute_destroy, NULL); g_slist_free (ot->attrs); g_slice_free (OpenTag, ot);}static voidopen_tag_set_absolute_font_size (OpenTag *ot, int font_size){ ot->base_font_size = font_size; ot->has_base_font_size = TRUE; ot->scale_level = 0; ot->scale_level_delta = 0;}static voidopen_tag_set_absolute_font_scale (OpenTag *ot, double scale){ ot->base_scale_factor = scale; ot->has_base_font_size = FALSE; ot->scale_level = 0; ot->scale_level_delta = 0;}static OpenTag*markup_data_open_tag (MarkupData *md){ OpenTag *ot; OpenTag *parent = NULL; if (md->attr_list == NULL) return NULL; if (md->tag_stack) parent = md->tag_stack->data; ot = g_slice_new (OpenTag); ot->attrs = NULL; ot->start_index = md->index; ot->scale_level_delta = 0; if (parent == NULL) { ot->base_scale_factor = 1.0; ot->base_font_size = 0; ot->has_base_font_size = FALSE; ot->scale_level = 0; } else { ot->base_scale_factor = parent->base_scale_factor; ot->base_font_size = parent->base_font_size; ot->has_base_font_size = parent->has_base_font_size; ot->scale_level = parent->scale_level; } md->tag_stack = g_slist_prepend (md->tag_stack, ot); return ot;}static voidmarkup_data_close_tag (MarkupData *md){ OpenTag *ot; GSList *tmp_list; if (md->attr_list == NULL) return; /* pop the stack */ ot = md->tag_stack->data; md->tag_stack = g_slist_delete_link (md->tag_stack, md->tag_stack); /* Adjust end indexes, and push each attr onto the front of the * to_apply list. This means that outermost tags are on the front of * that list; if we apply the list in order, then the innermost * tags will "win" which is correct. */ tmp_list = ot->attrs; while (tmp_list != NULL) { PangoAttribute *a = tmp_list->data; a->start_index = ot->start_index; a->end_index = md->index; md->to_apply = g_slist_prepend (md->to_apply, a); tmp_list = g_slist_next (tmp_list); } if (ot->scale_level_delta != 0) { /* We affected relative font size; create an appropriate * attribute and reverse our effects on the current level */ PangoAttribute *a; if (ot->has_base_font_size) { /* Create a font using the absolute point size * as the base size to be scaled from */ a = pango_attr_size_new (scale_factor (ot->scale_level, 1.0) * ot->base_font_size); } else { /* Create a font using the current scale factor * as the base size to be scaled from */ a = pango_attr_scale_new (scale_factor (ot->scale_level, ot->base_scale_factor)); } a->start_index = ot->start_index; a->end_index = md->index; md->to_apply = g_slist_prepend (md->to_apply, a); } g_slist_free (ot->attrs); g_slice_free (OpenTag, ot);}static voidstart_element_handler (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error){ TagParseFunc parse_func = NULL; OpenTag *ot; switch (*element_name) { case 'b': if (strcmp ("b", element_name) == 0) parse_func = b_parse_func; else if (strcmp ("big", element_name) == 0) parse_func = big_parse_func; break; case 'i': if (strcmp ("i", element_name) == 0) parse_func = i_parse_func; break; case 'm': if (strcmp ("markup", element_name) == 0) parse_func = markup_parse_func; break; case 's': if (strcmp ("span", element_name) == 0) parse_func = span_parse_func; else if (strcmp ("s", element_name) == 0) parse_func = s_parse_func; else if (strcmp ("sub", element_name) == 0) parse_func = sub_parse_func; else if (strcmp ("sup", element_name) == 0) parse_func = sup_parse_func; else if (strcmp ("small", element_name) == 0) parse_func = small_parse_func; break; case 't': if (strcmp ("tt", element_name) == 0) parse_func = tt_parse_func; break; case 'u': if (strcmp ("u", element_name) == 0) parse_func = u_parse_func; break; } if (parse_func == NULL) { 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_ELEMENT, _("Unknown tag '%s' on line %d char %d"), element_name, line_number, char_number); return; } ot = markup_data_open_tag (user_data); /* note ot may be NULL if the user didn't want the attribute list */ if (!(*parse_func) (user_data, ot, attribute_names, attribute_values, context, error)) { /* there's nothing to do; we return an error, and end up * freeing ot off the tag stack later. */ }}static voidend_element_handler (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error){ markup_data_close_tag (user_data);}static voidtext_handler (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error){ MarkupData *md = user_data; if (md->accel_marker == 0) { /* Just append all the text */ md->index += text_len; g_string_append_len (md->text, text, text_len); } else { /* Parse the accelerator */ const gchar *p; const gchar *end; const gchar *range_start; const gchar *range_end; gssize uline_index = -1; gsize uline_len = 0; /* Quiet GCC */ range_end = NULL; range_start = text; p = text; end = text + text_len; while (p != end) { gunichar c; c = g_utf8_get_char (p); if (range_end) { if (c == md->accel_marker) { /* escaped accel marker; move range_end * past the accel marker that came before, * append the whole thing */ range_end = g_utf8_next_char (range_end); g_string_append_len (md->text, range_start, range_end - range_start); md->index += range_end - range_start; /* set next range_start, skipping accel marker */ range_start = g_utf8_next_char (p); } else { /* Don't append the accel marker (leave range_end * alone); set the accel char to c; record location for * underline attribute */ if (md->accel_char == 0) md->accel_char = c; g_string_append_len (md->text, range_start, range_end - range_start); md->index += range_end - range_start; /* The underline should go underneath the char * we're setting as the next range_start */ uline_index = md->index; uline_len = g_utf8_next_char (p) - p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -