diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-08-20 17:35:41 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-08-20 17:35:41 +0000 |
commit | e756543935d415939e358d6d7cec094f7cd310a7 (patch) | |
tree | 6ca739b4439047fe0de0c16d38c6627a6d4feeee | |
parent | df6d8df3242d3e139df99dcccecf7ca9bbeed95d (diff) | |
parent | 5d36fc27baad02cf773ff9af1fb46cdc97c7788b (diff) | |
download | pango-e756543935d415939e358d6d7cec094f7cd310a7.tar.gz |
Merge branch 'code-reorg' into 'main'
Cosmetics: Clean up pango-context.h
See merge request GNOME/pango!418
-rw-r--r-- | pango/break.c | 105 | ||||
-rw-r--r-- | pango/itemize.c | 1151 | ||||
-rw-r--r-- | pango/meson.build | 4 | ||||
-rw-r--r-- | pango/pango-attributes-private.h | 2 | ||||
-rw-r--r-- | pango/pango-attributes.c | 1041 | ||||
-rw-r--r-- | pango/pango-attributes.h | 500 | ||||
-rw-r--r-- | pango/pango-break.h | 57 | ||||
-rw-r--r-- | pango/pango-color.h | 75 | ||||
-rw-r--r-- | pango/pango-context-private.h | 63 | ||||
-rw-r--r-- | pango/pango-context.c | 1153 | ||||
-rw-r--r-- | pango/pango-context.h | 108 | ||||
-rw-r--r-- | pango/pango-fontmap.h | 2 | ||||
-rw-r--r-- | pango/pango-glyph.h | 129 | ||||
-rw-r--r-- | pango/pango-item.h | 45 | ||||
-rw-r--r-- | pango/pango-language.h | 41 | ||||
-rw-r--r-- | pango/pango-markup.c | 2 | ||||
-rw-r--r-- | pango/pango-markup.h | 52 | ||||
-rw-r--r-- | pango/pango-types.h | 2 | ||||
-rw-r--r-- | pango/pango-utils.c | 102 | ||||
-rw-r--r-- | pango/pango-utils.h | 6 | ||||
-rw-r--r-- | pango/pango.h | 3 | ||||
-rw-r--r-- | pango/pangofc-shape.c | 425 | ||||
-rw-r--r-- | pango/reorder-items.c | 11 | ||||
-rw-r--r-- | pango/shape.c | 577 |
24 files changed, 2911 insertions, 2745 deletions
diff --git a/pango/break.c b/pango/break.c index 9690d510..9eb4a291 100644 --- a/pango/break.c +++ b/pango/break.c @@ -30,7 +30,6 @@ #include <string.h> #define PARAGRAPH_SEPARATOR 0x2029 -#define PARAGRAPH_SEPARATOR_STRING "\xE2\x80\xA9" /* See http://www.unicode.org/unicode/reports/tr14/ if you hope * to understand the line breaking code. @@ -1655,110 +1654,6 @@ pango_break (const gchar *text, } /** - * pango_find_paragraph_boundary: - * @text: UTF-8 text - * @length: length of @text in bytes, or -1 if nul-terminated - * @paragraph_delimiter_index: (out): return location for index of - * delimiter - * @next_paragraph_start: (out): return location for start of next - * paragraph - * - * Locates a paragraph boundary in @text. - * - * A boundary is caused by delimiter characters, such as - * a newline, carriage return, carriage return-newline pair, - * or Unicode paragraph separator character. - * - * The index of the run of delimiters is returned in - * @paragraph_delimiter_index. The index of the start - * of the paragrap (index after all delimiters) is stored - * in @next_paragraph_start. - * - * If no delimiters are found, both @paragraph_delimiter_index - * and @next_paragraph_start are filled with the length of @text - * (an index one off the end). - */ -void -pango_find_paragraph_boundary (const gchar *text, - gint length, - gint *paragraph_delimiter_index, - gint *next_paragraph_start) -{ - const gchar *p = text; - const gchar *end; - const gchar *start = NULL; - const gchar *delimiter = NULL; - - /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in - * Unicode 5.0; update the following code if that changes. - */ - - /* prev_sep is the first byte of the previous separator. Since - * the valid separators are \r, \n, and PARAGRAPH_SEPARATOR, the - * first byte is enough to identify it. - */ - gchar prev_sep; - - - if (length < 0) - length = strlen (text); - - end = text + length; - - if (paragraph_delimiter_index) - *paragraph_delimiter_index = length; - - if (next_paragraph_start) - *next_paragraph_start = length; - - if (length == 0) - return; - - prev_sep = 0; - - while (p < end) - { - if (prev_sep == '\n' || - prev_sep == PARAGRAPH_SEPARATOR_STRING[0]) - { - g_assert (delimiter); - start = p; - break; - } - else if (prev_sep == '\r') - { - /* don't break between \r and \n */ - if (*p != '\n') - { - g_assert (delimiter); - start = p; - break; - } - } - - if (*p == '\n' || - *p == '\r' || - !strncmp(p, PARAGRAPH_SEPARATOR_STRING, - strlen(PARAGRAPH_SEPARATOR_STRING))) - { - if (delimiter == NULL) - delimiter = p; - prev_sep = *p; - } - else - prev_sep = 0; - - p = g_utf8_next_char (p); - } - - if (delimiter && paragraph_delimiter_index) - *paragraph_delimiter_index = delimiter - text; - - if (start && next_paragraph_start) - *next_paragraph_start = start - text; -} - -/** * pango_tailor_break: * @text: text to process. Must be valid UTF-8 * @length: length in bytes of @text diff --git a/pango/itemize.c b/pango/itemize.c new file mode 100644 index 00000000..27a9865d --- /dev/null +++ b/pango/itemize.c @@ -0,0 +1,1151 @@ +/* Pango + * itemize.c: Turning text into items + * + * Copyright (C) 2000, 2006 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 "pango-context-private.h" +#include "pango-impl-utils.h" + +#include "pango-font-private.h" +#include "pango-fontset-private.h" +#include "pango-fontmap-private.h" +#include "pango-script-private.h" +#include "pango-emoji-private.h" +#include "pango-attributes-private.h" + + +/* {{{ Font cache */ + +/* + * We cache the results of character,fontset => font in a hash table + */ + +typedef struct { + GHashTable *hash; +} FontCache; + +typedef struct { + PangoFont *font; + int position; /* position of the font in the fontset */ +} FontElement; + +static void +font_cache_destroy (FontCache *cache) +{ + g_hash_table_destroy (cache->hash); + g_slice_free (FontCache, cache); +} + +static void +font_element_destroy (FontElement *element) +{ + if (element->font) + g_object_unref (element->font); + g_slice_free (FontElement, element); +} + +static FontCache * +get_font_cache (PangoFontset *fontset) +{ + FontCache *cache; + + static GQuark cache_quark = 0; /* MT-safe */ + if (G_UNLIKELY (!cache_quark)) + cache_quark = g_quark_from_static_string ("pango-font-cache"); + +retry: + cache = g_object_get_qdata (G_OBJECT (fontset), cache_quark); + if (G_UNLIKELY (!cache)) + { + cache = g_slice_new (FontCache); + cache->hash = g_hash_table_new_full (g_direct_hash, NULL, + NULL, (GDestroyNotify)font_element_destroy); + if (!g_object_replace_qdata (G_OBJECT (fontset), cache_quark, NULL, + cache, (GDestroyNotify)font_cache_destroy, + NULL)) + { + font_cache_destroy (cache); + goto retry; + } + } + + return cache; +} + +static gboolean +font_cache_get (FontCache *cache, + gunichar wc, + PangoFont **font, + int *position) +{ + FontElement *element; + + element = g_hash_table_lookup (cache->hash, GUINT_TO_POINTER (wc)); + if (element) + { + *font = element->font; + *position = element->position; + return TRUE; + } + else + return FALSE; +} + +static void +font_cache_insert (FontCache *cache, + gunichar wc, + PangoFont *font, + int position) +{ + FontElement *element = g_slice_new (FontElement); + element->font = font ? g_object_ref (font) : NULL; + element->position = position; + + g_hash_table_insert (cache->hash, GUINT_TO_POINTER (wc), element); +} + +/* }}} */ +/* {{{ Width Iter */ + +typedef struct _PangoWidthIter PangoWidthIter; + +struct _PangoWidthIter +{ + const gchar *text_start; + const gchar *text_end; + const gchar *start; + const gchar *end; + gboolean upright; +}; + +static gboolean +width_iter_is_upright (gunichar ch) +{ + /* https://www.unicode.org/Public/11.0.0/ucd/VerticalOrientation.txt + * VO=U or Tu table generated by tools/gen-vertical-orientation-U-table.py. + * + * FIXME: In the future, If GLib supports VerticalOrientation, please use it. + */ + static const gunichar upright[][2] = { + {0x00A7, 0x00A7}, {0x00A9, 0x00A9}, {0x00AE, 0x00AE}, {0x00B1, 0x00B1}, + {0x00BC, 0x00BE}, {0x00D7, 0x00D7}, {0x00F7, 0x00F7}, {0x02EA, 0x02EB}, + {0x1100, 0x11FF}, {0x1401, 0x167F}, {0x18B0, 0x18FF}, {0x2016, 0x2016}, + {0x2020, 0x2021}, {0x2030, 0x2031}, {0x203B, 0x203C}, {0x2042, 0x2042}, + {0x2047, 0x2049}, {0x2051, 0x2051}, {0x2065, 0x2065}, {0x20DD, 0x20E0}, + {0x20E2, 0x20E4}, {0x2100, 0x2101}, {0x2103, 0x2109}, {0x210F, 0x210F}, + {0x2113, 0x2114}, {0x2116, 0x2117}, {0x211E, 0x2123}, {0x2125, 0x2125}, + {0x2127, 0x2127}, {0x2129, 0x2129}, {0x212E, 0x212E}, {0x2135, 0x213F}, + {0x2145, 0x214A}, {0x214C, 0x214D}, {0x214F, 0x2189}, {0x218C, 0x218F}, + {0x221E, 0x221E}, {0x2234, 0x2235}, {0x2300, 0x2307}, {0x230C, 0x231F}, + {0x2324, 0x2328}, {0x232B, 0x232B}, {0x237D, 0x239A}, {0x23BE, 0x23CD}, + {0x23CF, 0x23CF}, {0x23D1, 0x23DB}, {0x23E2, 0x2422}, {0x2424, 0x24FF}, + {0x25A0, 0x2619}, {0x2620, 0x2767}, {0x2776, 0x2793}, {0x2B12, 0x2B2F}, + {0x2B50, 0x2B59}, {0x2BB8, 0x2BD1}, {0x2BD3, 0x2BEB}, {0x2BF0, 0x2BFF}, + {0x2E80, 0x3007}, {0x3012, 0x3013}, {0x3020, 0x302F}, {0x3031, 0x309F}, + {0x30A1, 0x30FB}, {0x30FD, 0xA4CF}, {0xA960, 0xA97F}, {0xAC00, 0xD7FF}, + {0xE000, 0xFAFF}, {0xFE10, 0xFE1F}, {0xFE30, 0xFE48}, {0xFE50, 0xFE57}, + {0xFE5F, 0xFE62}, {0xFE67, 0xFE6F}, {0xFF01, 0xFF07}, {0xFF0A, 0xFF0C}, + {0xFF0E, 0xFF19}, {0xFF1F, 0xFF3A}, {0xFF3C, 0xFF3C}, {0xFF3E, 0xFF3E}, + {0xFF40, 0xFF5A}, {0xFFE0, 0xFFE2}, {0xFFE4, 0xFFE7}, {0xFFF0, 0xFFF8}, + {0xFFFC, 0xFFFD}, {0x10980, 0x1099F}, {0x11580, 0x115FF}, {0x11A00, 0x11AAF}, + {0x13000, 0x1342F}, {0x14400, 0x1467F}, {0x16FE0, 0x18AFF}, {0x1B000, 0x1B12F}, + {0x1B170, 0x1B2FF}, {0x1D000, 0x1D1FF}, {0x1D2E0, 0x1D37F}, {0x1D800, 0x1DAAF}, + {0x1F000, 0x1F7FF}, {0x1F900, 0x1FA6F}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}, + {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD} + }; + static const int max = sizeof(upright) / sizeof(upright[0]); + int st = 0; + int ed = max; + + if (ch < upright[0][0]) + return FALSE; + + while (st <= ed) + { + int mid = (st + ed) / 2; + if (upright[mid][0] <= ch && ch <= upright[mid][1]) + return TRUE; + else + if (upright[mid][0] <= ch) + st = mid + 1; + else + ed = mid - 1; + } + + return FALSE; +} + +static void +width_iter_next (PangoWidthIter *iter) +{ + gboolean met_joiner = FALSE; + iter->start = iter->end; + + if (iter->end < iter->text_end) + { + gunichar ch = g_utf8_get_char (iter->end); + iter->upright = width_iter_is_upright (ch); + } + + while (iter->end < iter->text_end) + { + gunichar ch = g_utf8_get_char (iter->end); + + /* for zero width joiner */ + if (ch == 0x200D) + { + iter->end = g_utf8_next_char (iter->end); + met_joiner = TRUE; + continue; + } + + /* ignore the upright check if met joiner */ + if (met_joiner) + { + iter->end = g_utf8_next_char (iter->end); + met_joiner = FALSE; + continue; + } + + /* for variation selector, tag and emoji modifier. */ + if (G_UNLIKELY (ch == 0xFE0EU || ch == 0xFE0FU || + (ch >= 0xE0020 && ch <= 0xE007F) || + (ch >= 0x1F3FB && ch <= 0x1F3FF))) + { + iter->end = g_utf8_next_char (iter->end); + continue; + } + + if (width_iter_is_upright (ch) != iter->upright) + break; + + iter->end = g_utf8_next_char (iter->end); + } +} + +static void +width_iter_init (PangoWidthIter *iter, + const char *text, + int length) +{ + iter->text_start = text; + iter->text_end = text + length; + iter->start = iter->end = text; + + width_iter_next (iter); +} + +static void +width_iter_fini (PangoWidthIter *iter) +{ +} + +/* }}} */ +/* {{{ Itemization */ + +typedef struct _ItemizeState ItemizeState; + + +typedef enum { + EMBEDDING_CHANGED = 1 << 0, + SCRIPT_CHANGED = 1 << 1, + LANG_CHANGED = 1 << 2, + FONT_CHANGED = 1 << 3, + DERIVED_LANG_CHANGED = 1 << 4, + WIDTH_CHANGED = 1 << 5, + EMOJI_CHANGED = 1 << 6, +} ChangedFlags; + + +struct _ItemizeState +{ + PangoContext *context; + const char *text; + const char *end; + + const char *run_start; + const char *run_end; + + GList *result; + PangoItem *item; + + guint8 *embedding_levels; + int embedding_end_offset; + const char *embedding_end; + guint8 embedding; + + PangoGravity gravity; + PangoGravityHint gravity_hint; + PangoGravity resolved_gravity; + PangoGravity font_desc_gravity; + gboolean centered_baseline; + + PangoAttrIterator *attr_iter; + gboolean free_attr_iter; + const char *attr_end; + PangoFontDescription *font_desc; + PangoFontDescription *emoji_font_desc; + PangoLanguage *lang; + GSList *extra_attrs; + gboolean copy_extra_attrs; + + ChangedFlags changed; + + PangoScriptIter script_iter; + const char *script_end; + PangoScript script; + + PangoWidthIter width_iter; + PangoEmojiIter emoji_iter; + + PangoLanguage *derived_lang; + + PangoFontset *current_fonts; + FontCache *cache; + PangoFont *base_font; + gboolean enable_fallback; + + const char *first_space; /* first of a sequence of spaces we've seen */ + int font_position; /* position of the current font in the fontset */ +}; + +static void +update_embedding_end (ItemizeState *state) +{ + state->embedding = state->embedding_levels[state->embedding_end_offset]; + while (state->embedding_end < state->end && + state->embedding_levels[state->embedding_end_offset] == state->embedding) + { + state->embedding_end_offset++; + state->embedding_end = g_utf8_next_char (state->embedding_end); + } + + state->changed |= EMBEDDING_CHANGED; +} + +static PangoAttribute * +find_attribute (GSList *attr_list, + PangoAttrType type) +{ + GSList *node; + + for (node = attr_list; node; node = node->next) + if (((PangoAttribute *) node->data)->klass->type == type) + return (PangoAttribute *) node->data; + + return NULL; +} + +static void +update_attr_iterator (ItemizeState *state) +{ + PangoLanguage *old_lang; + PangoAttribute *attr; + int end_index; + + pango_attr_iterator_range (state->attr_iter, NULL, &end_index); + if (end_index < state->end - state->text) + state->attr_end = state->text + end_index; + else + state->attr_end = state->end; + + if (state->emoji_font_desc) + { + pango_font_description_free (state->emoji_font_desc); + state->emoji_font_desc = NULL; + } + + old_lang = state->lang; + if (state->font_desc) + pango_font_description_free (state->font_desc); + state->font_desc = pango_font_description_copy_static (state->context->font_desc); + pango_attr_iterator_get_font (state->attr_iter, state->font_desc, + &state->lang, &state->extra_attrs); + if (pango_font_description_get_set_fields (state->font_desc) & PANGO_FONT_MASK_GRAVITY) + state->font_desc_gravity = pango_font_description_get_gravity (state->font_desc); + else + state->font_desc_gravity = PANGO_GRAVITY_AUTO; + + state->copy_extra_attrs = FALSE; + + if (!state->lang) + state->lang = state->context->language; + + attr = find_attribute (state->extra_attrs, PANGO_ATTR_FALLBACK); + state->enable_fallback = (attr == NULL || ((PangoAttrInt *)attr)->value); + + attr = find_attribute (state->extra_attrs, PANGO_ATTR_GRAVITY); + state->gravity = attr == NULL ? PANGO_GRAVITY_AUTO : ((PangoAttrInt *)attr)->value; + + attr = find_attribute (state->extra_attrs, PANGO_ATTR_GRAVITY_HINT); + state->gravity_hint = attr == NULL ? state->context->gravity_hint : (PangoGravityHint)((PangoAttrInt *)attr)->value; + + state->changed |= FONT_CHANGED; + if (state->lang != old_lang) + state->changed |= LANG_CHANGED; +} + +static void +update_end (ItemizeState *state) +{ + state->run_end = state->embedding_end; + if (state->attr_end < state->run_end) + state->run_end = state->attr_end; + if (state->script_end < state->run_end) + state->run_end = state->script_end; + if (state->width_iter.end < state->run_end) + state->run_end = state->width_iter.end; + if (state->emoji_iter.end < state->run_end) + state->run_end = state->emoji_iter.end; +} + + +static void +itemize_state_init (ItemizeState *state, + PangoContext *context, + const char *text, + PangoDirection base_dir, + int start_index, + int length, + PangoAttrList *attrs, + PangoAttrIterator *cached_iter, + const PangoFontDescription *desc) +{ + state->context = context; + state->text = text; + state->end = text + start_index + length; + + state->result = NULL; + state->item = NULL; + + state->run_start = text + start_index; + state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | + FONT_CHANGED | WIDTH_CHANGED | EMOJI_CHANGED; + + /* First, apply the bidirectional algorithm to break + * the text into directional runs. + */ + state->embedding_levels = pango_log2vis_get_embedding_levels (text + start_index, length, &base_dir); + + state->embedding_end_offset = 0; + state->embedding_end = text + start_index; + update_embedding_end (state); + + state->gravity = PANGO_GRAVITY_AUTO; + state->centered_baseline = PANGO_GRAVITY_IS_VERTICAL (state->context->resolved_gravity); + state->gravity_hint = state->context->gravity_hint; + state->resolved_gravity = PANGO_GRAVITY_AUTO; + + /* Initialize the attribute iterator + */ + if (cached_iter) + { + state->attr_iter = cached_iter; + state->free_attr_iter = FALSE; + } + else if (attrs) + { + state->attr_iter = pango_attr_list_get_iterator (attrs); + state->free_attr_iter = TRUE; + } + else + { + state->attr_iter = NULL; + state->free_attr_iter = FALSE; + } + + state->emoji_font_desc = NULL; + if (state->attr_iter) + { + state->font_desc = NULL; + state->lang = NULL; + + pango_attr_iterator_advance (state->attr_iter, start_index); + update_attr_iterator (state); + } + else + { + state->font_desc = pango_font_description_copy_static (desc ? desc : state->context->font_desc); + state->lang = state->context->language; + state->extra_attrs = NULL; + state->copy_extra_attrs = FALSE; + + state->attr_end = state->end; + state->enable_fallback = TRUE; + } + + /* Initialize the script iterator + */ + _pango_script_iter_init (&state->script_iter, text + start_index, length); + pango_script_iter_get_range (&state->script_iter, NULL, + &state->script_end, &state->script); + + width_iter_init (&state->width_iter, text + start_index, length); + _pango_emoji_iter_init (&state->emoji_iter, text + start_index, length); + + if (!PANGO_GRAVITY_IS_VERTICAL (state->context->resolved_gravity)) + state->width_iter.end = state->end; + else + if (state->emoji_iter.is_emoji) + state->width_iter.end = MAX (state->width_iter.end, state->emoji_iter.end); + + update_end (state); + + if (pango_font_description_get_set_fields (state->font_desc) & PANGO_FONT_MASK_GRAVITY) + state->font_desc_gravity = pango_font_description_get_gravity (state->font_desc); + else + state->font_desc_gravity = PANGO_GRAVITY_AUTO; + + state->derived_lang = NULL; + state->current_fonts = NULL; + state->cache = NULL; + state->base_font = NULL; + state->first_space = NULL; + state->font_position = 0xffff; +} + +static gboolean +itemize_state_next (ItemizeState *state) +{ + if (state->run_end == state->end) + return FALSE; + + state->changed = 0; + + state->run_start = state->run_end; + + if (state->run_end == state->embedding_end) + { + update_embedding_end (state); + } + + if (state->run_end == state->attr_end) + { + pango_attr_iterator_next (state->attr_iter); + update_attr_iterator (state); + } + + if (state->run_end == state->script_end) + { + pango_script_iter_next (&state->script_iter); + pango_script_iter_get_range (&state->script_iter, NULL, + &state->script_end, &state->script); + state->changed |= SCRIPT_CHANGED; + } + if (state->run_end == state->emoji_iter.end) + { + _pango_emoji_iter_next (&state->emoji_iter); + state->changed |= EMOJI_CHANGED; + + if (state->emoji_iter.is_emoji) + state->width_iter.end = MAX (state->width_iter.end, state->emoji_iter.end); + } + if (state->run_end == state->width_iter.end) + { + width_iter_next (&state->width_iter); + state->changed |= WIDTH_CHANGED; + } + + update_end (state); + + return TRUE; +} + +static GSList * +copy_attr_slist (GSList *attr_slist) +{ + GSList *new_list = NULL; + GSList *l; + + for (l = attr_slist; l; l = l->next) + new_list = g_slist_prepend (new_list, pango_attribute_copy (l->data)); + + return g_slist_reverse (new_list); +} + +static void +itemize_state_fill_font (ItemizeState *state, + PangoFont *font) +{ + GList *l; + + for (l = state->result; l; l = l->next) + { + PangoItem *item = l->data; + if (item->analysis.font) + break; + if (font) + item->analysis.font = g_object_ref (font); + } +} + +static void +itemize_state_add_character (ItemizeState *state, + PangoFont *font, + int font_position, + gboolean force_break, + const char *pos, + gboolean is_space) +{ + const char *first_space = state->first_space; + int n_spaces = 0; + + if (is_space) + { + if (state->first_space == NULL) + state->first_space = pos; + } + else + state->first_space = NULL; + + if (state->item) + { + if (!state->item->analysis.font && font) + { + itemize_state_fill_font (state, font); + state->font_position = font_position; + } + else if (state->item->analysis.font && !font) + { + font = state->item->analysis.font; + font_position = state->font_position; + } + + if (!force_break && + state->item->analysis.font == font) + { + state->item->num_chars++; + return; + } + + /* Font is changing, we are about to end the current item. + * If it ended in a sequence of spaces (but wasn't only spaces), + * check if we should move those spaces to the new item (since + * the font is less "fallback". + * + * See https://gitlab.gnome.org/GNOME/pango/-/issues/249 + */ + if (state->text + state->item->offset < first_space && + font_position < state->font_position) + { + n_spaces = g_utf8_strlen (first_space, pos - first_space); + state->item->num_chars -= n_spaces; + pos = first_space; + } + + state->item->length = (pos - state->text) - state->item->offset; + } + + state->item = pango_item_new (); + state->item->offset = pos - state->text; + state->item->length = 0; + state->item->num_chars = n_spaces + 1; + + if (font) + g_object_ref (font); + state->item->analysis.font = font; + state->font_position = font_position; + + state->item->analysis.level = state->embedding; + state->item->analysis.gravity = state->resolved_gravity; + + /* The level vs. gravity dance: + * - If gravity is SOUTH, leave level untouched. + * - If gravity is NORTH, step level one up, to + * not get mirrored upside-down text. + * - If gravity is EAST, step up to an even level, as + * it's a clockwise-rotated layout, so the rotated + * top is unrotated left. + * - If gravity is WEST, step up to an odd level, as + * it's a counter-clockwise-rotated layout, so the rotated + * top is unrotated right. + * + * A similar dance is performed in pango-layout.c: + * line_set_resolved_dir(). Keep in synch. + */ + switch (state->item->analysis.gravity) + { + case PANGO_GRAVITY_SOUTH: + default: + break; + case PANGO_GRAVITY_NORTH: + state->item->analysis.level++; + break; + case PANGO_GRAVITY_EAST: + state->item->analysis.level += 1; + state->item->analysis.level &= ~1; + break; + case PANGO_GRAVITY_WEST: + state->item->analysis.level |= 1; + break; + } + + state->item->analysis.flags = state->centered_baseline ? PANGO_ANALYSIS_FLAG_CENTERED_BASELINE : 0; + + state->item->analysis.script = state->script; + state->item->analysis.language = state->derived_lang; + + if (state->copy_extra_attrs) + { + state->item->analysis.extra_attrs = copy_attr_slist (state->extra_attrs); + } + else + { + state->item->analysis.extra_attrs = state->extra_attrs; + state->copy_extra_attrs = TRUE; + } + + state->result = g_list_prepend (state->result, state->item); +} + +typedef struct { + PangoLanguage *lang; + gunichar wc; + PangoFont *font; + int position; +} GetFontInfo; + +static gboolean +get_font_foreach (PangoFontset *fontset, + PangoFont *font, + gpointer data) +{ + GetFontInfo *info = data; + + if (G_UNLIKELY (!font)) + return FALSE; + + if (pango_font_has_char (font, info->wc)) + { + info->font = font; + return TRUE; + } + + if (!fontset) + { + info->font = font; + return TRUE; + } + + info->position++; + + return FALSE; +} + +static PangoFont * +get_base_font (ItemizeState *state) +{ + if (!state->base_font) + state->base_font = pango_font_map_load_font (state->context->font_map, + state->context, + state->font_desc); + return state->base_font; +} + +static gboolean +get_font (ItemizeState *state, + gunichar wc, + PangoFont **font, + int *position) +{ + GetFontInfo info; + + /* We'd need a separate cache when fallback is disabled, but since lookup + * with fallback disabled is faster anyways, we just skip caching */ + if (state->enable_fallback && font_cache_get (state->cache, wc, font, position)) + return TRUE; + + info.lang = state->derived_lang; + info.wc = wc; + info.font = NULL; + info.position = 0; + + if (state->enable_fallback) + pango_fontset_foreach (state->current_fonts, get_font_foreach, &info); + else + get_font_foreach (NULL, get_base_font (state), &info); + + *font = info.font; + *position = info.position; + + /* skip caching if fallback disabled (see above) */ + if (state->enable_fallback) + font_cache_insert (state->cache, wc, *font, *position); + + return TRUE; +} + +static PangoLanguage * +compute_derived_language (PangoLanguage *lang, + PangoScript script) +{ + PangoLanguage *derived_lang; + + /* Make sure the language tag is consistent with the derived + * script. There is no point in marking up a section of + * Arabic text with the "en" language tag. + */ + if (lang && pango_language_includes_script (lang, script)) + derived_lang = lang; + else + { + derived_lang = pango_script_get_sample_language (script); + /* If we don't find a sample language for the script, we + * use a language tag that shouldn't actually be used + * anywhere. This keeps fontconfig (for the PangoFc* + * backend) from using the language tag to affect the + * sort order. I don't have a reference for 'xx' being + * safe here, though Keith Packard claims it is. + */ + if (!derived_lang) + derived_lang = pango_language_from_string ("xx"); + } + + return derived_lang; +} + +static void +itemize_state_update_for_new_run (ItemizeState *state) +{ + /* This block should be moved to update_attr_iterator, but I'm too lazy to + * do it right now */ + if (state->changed & (FONT_CHANGED | SCRIPT_CHANGED | WIDTH_CHANGED)) + { + /* Font-desc gravity overrides everything */ + if (state->font_desc_gravity != PANGO_GRAVITY_AUTO) + { + state->resolved_gravity = state->font_desc_gravity; + } + else + { + PangoGravity gravity = state->gravity; + PangoGravityHint gravity_hint = state->gravity_hint; + + if (G_LIKELY (gravity == PANGO_GRAVITY_AUTO)) + gravity = state->context->resolved_gravity; + + state->resolved_gravity = pango_gravity_get_for_script_and_width (state->script, + state->width_iter.upright, + gravity, + gravity_hint); + } + + if (state->font_desc_gravity != state->resolved_gravity) + { + pango_font_description_set_gravity (state->font_desc, state->resolved_gravity); + state->changed |= FONT_CHANGED; + } + } + + if (state->changed & (SCRIPT_CHANGED | LANG_CHANGED)) + { + PangoLanguage *old_derived_lang = state->derived_lang; + state->derived_lang = compute_derived_language (state->lang, state->script); + if (old_derived_lang != state->derived_lang) + state->changed |= DERIVED_LANG_CHANGED; + } + + if (state->changed & (EMOJI_CHANGED)) + { + state->changed |= FONT_CHANGED; + } + + if (state->changed & (FONT_CHANGED | DERIVED_LANG_CHANGED) && + state->current_fonts) + { + g_object_unref (state->current_fonts); + state->current_fonts = NULL; + state->cache = NULL; + } + + if (!state->current_fonts) + { + gboolean is_emoji = state->emoji_iter.is_emoji; + if (is_emoji && !state->emoji_font_desc) + { + state->emoji_font_desc = pango_font_description_copy_static (state->font_desc); + pango_font_description_set_family_static (state->emoji_font_desc, "emoji"); + } + state->current_fonts = pango_font_map_load_fontset (state->context->font_map, + state->context, + is_emoji ? state->emoji_font_desc : state->font_desc, + state->derived_lang); + state->cache = get_font_cache (state->current_fonts); + } + + if ((state->changed & FONT_CHANGED) && state->base_font) + { + g_object_unref (state->base_font); + state->base_font = NULL; + } +} + +static void +itemize_state_process_run (ItemizeState *state) +{ + const char *p; + gboolean last_was_forced_break = FALSE; + gboolean is_space; + + /* Only one character has type G_UNICODE_LINE_SEPARATOR in Unicode 4.0; + * update this if that changes. */ +#define LINE_SEPARATOR 0x2028 + + itemize_state_update_for_new_run (state); + + /* We should never get an empty run */ + g_assert (state->run_end != state->run_start); + + for (p = state->run_start; + p < state->run_end; + p = g_utf8_next_char (p)) + { + gunichar wc = g_utf8_get_char (p); + 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))) + { + font = NULL; + font_position = 0xffff; + is_space = TRUE; + } + else + { + get_font (state, wc, &font, &font_position); + is_space = FALSE; + } + + itemize_state_add_character (state, font, font_position, + is_forced_break || last_was_forced_break, + p, + is_space); + + last_was_forced_break = is_forced_break; + } + + /* Finish the final item from the current segment */ + state->item->length = (p - state->text) - state->item->offset; + if (!state->item->analysis.font) + { + PangoFont *font; + int position; + + if (G_UNLIKELY (!get_font (state, ' ', &font, &position))) + { + /* If no font was found, warn once per fontmap/script pair */ + PangoFontMap *fontmap = state->context->font_map; + char *script_tag = g_strdup_printf ("g-unicode-script-%d", state->script); + + if (!g_object_get_data (G_OBJECT (fontmap), script_tag)) + { + g_warning ("failed to choose a font, expect ugly output. script='%d'", + state->script); + + g_object_set_data_full (G_OBJECT (fontmap), script_tag, + GINT_TO_POINTER (1), NULL); + } + + g_free (script_tag); + + font = NULL; + } + itemize_state_fill_font (state, font); + } + state->item = NULL; +} + +static void +itemize_state_finish (ItemizeState *state) +{ + g_free (state->embedding_levels); + if (state->free_attr_iter) + pango_attr_iterator_destroy (state->attr_iter); + _pango_script_iter_fini (&state->script_iter); + pango_font_description_free (state->font_desc); + pango_font_description_free (state->emoji_font_desc); + width_iter_fini (&state->width_iter); + _pango_emoji_iter_fini (&state->emoji_iter); + + if (state->current_fonts) + g_object_unref (state->current_fonts); + if (state->base_font) + g_object_unref (state->base_font); +} +/* }}} */ +/* {{{ Public API */ + +/* Like pango_itemize, but takes a font description */ +GList * +pango_itemize_with_font (PangoContext *context, + const char *text, + int start_index, + int length, + const PangoFontDescription *desc) +{ + ItemizeState state; + + if (length == 0) + return NULL; + + itemize_state_init (&state, context, text, context->base_dir, start_index, length, + NULL, NULL, desc); + + do + itemize_state_process_run (&state); + while (itemize_state_next (&state)); + + itemize_state_finish (&state); + + return g_list_reverse (state.result); +} + +/** + * pango_itemize_with_base_dir: + * @context: a structure holding information that affects + * the itemization process. + * @base_dir: base direction to use for bidirectional processing + * @text: the text to itemize. + * @start_index: first byte in @text to process + * @length: the number of bytes (not characters) to process + * after @start_index. This must be >= 0. + * @attrs: the set of attributes that apply to @text. + * @cached_iter: (nullable): Cached attribute iterator + * + * Like `pango_itemize()`, but with an explicitly specified base direction. + * + * The base direction is used when computing bidirectional levels. + * (see [method@Pango.Context.set_base_dir]). [func@itemize] gets the + * base direction from the `PangoContext`. + * + * Return value: (transfer full) (element-type Pango.Item): a `GList` of + * [struct@Pango.Item] structures. The items should be freed using + * [method@Pango.Item.free] probably in combination with g_list_free_full(). + * + * Since: 1.4 + */ +GList * +pango_itemize_with_base_dir (PangoContext *context, + PangoDirection base_dir, + const char *text, + int start_index, + int length, + PangoAttrList *attrs, + PangoAttrIterator *cached_iter) +{ + ItemizeState state; + + 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); + + if (length == 0 || g_utf8_get_char (text + start_index) == '\0') + return NULL; + + itemize_state_init (&state, context, text, base_dir, start_index, length, + attrs, cached_iter, NULL); + + do + itemize_state_process_run (&state); + while (itemize_state_next (&state)); + + itemize_state_finish (&state); + + return g_list_reverse (state.result); +} + +/** + * pango_itemize: + * @context: a structure holding information that affects + * the itemization process. + * @text: the text to itemize. Must be valid UTF-8 + * @start_index: first byte in @text to process + * @length: the number of bytes (not characters) to process + * after @start_index. This must be >= 0. + * @attrs: the set of attributes that apply to @text. + * @cached_iter: (nullable): Cached attribute iterator + * + * Breaks a piece of text into segments with consistent directional + * level and font. + * + * Each byte of @text will be contained in exactly one of the items in the + * returned list; the generated list of items will be in logical order (the + * start offsets of the items are ascending). + * + * @cached_iter should be an iterator over @attrs currently positioned + * at a range before or containing @start_index; @cached_iter will be + * advanced to the range covering the position just after + * @start_index + @length. (i.e. if itemizing in a loop, just keep passing + * in the same @cached_iter). + * + * Return value: (transfer full) (element-type Pango.Item): a `GList` of + * [struct@Pango.Item] structures. The items should be freed using + * [method@Pango.Item.free] probably in combination with g_list_free_full(). + */ +GList * +pango_itemize (PangoContext *context, + const char *text, + int start_index, + int length, + PangoAttrList *attrs, + PangoAttrIterator *cached_iter) +{ + 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_base_dir (context, context->base_dir, + text, start_index, length, attrs, cached_iter); +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ diff --git a/pango/meson.build b/pango/meson.build index e5121bd8..084de229 100644 --- a/pango/meson.build +++ b/pango/meson.build @@ -3,6 +3,7 @@ pango_sources = [ 'ellipsize.c', 'fonts.c', 'glyphstring.c', + 'itemize.c', 'modules.c', 'pango-attributes.c', 'pango-bidi-type.c', @@ -26,7 +27,6 @@ pango_sources = [ 'pango-utils.c', 'reorder-items.c', 'shape.c', - 'pangofc-shape.c', ] pango_headers = [ @@ -34,6 +34,7 @@ pango_headers = [ 'pango-attributes.h', 'pango-bidi-type.h', 'pango-break.h', + 'pango-color.h', 'pango-context.h', 'pango-coverage.h', 'pango-direction.h', @@ -48,6 +49,7 @@ pango_headers = [ 'pango-language.h', 'pango-layout.h', 'pango-matrix.h', + 'pango-markup.h', 'pango-modules.h', 'pango-renderer.h', 'pango-script.h', diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h index f7384fd0..4c427695 100644 --- a/pango/pango-attributes-private.h +++ b/pango/pango-attributes-private.h @@ -46,6 +46,8 @@ void _pango_attr_list_get_iterator (PangoAttrList *list, PangoAttrIterator *iterator); void _pango_attr_iterator_destroy (PangoAttrIterator *iterator); +gboolean pango_attr_iterator_advance (PangoAttrIterator *iterator, + int index); #endif diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index fdb37f56..5690aeaa 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -26,19 +26,8 @@ #include "pango-attributes-private.h" #include "pango-impl-utils.h" -static PangoAttribute *pango_attr_color_new (const PangoAttrClass *klass, - guint16 red, - guint16 green, - guint16 blue); -static PangoAttribute *pango_attr_string_new (const PangoAttrClass *klass, - const char *str); -static PangoAttribute *pango_attr_int_new (const PangoAttrClass *klass, - int value); -static PangoAttribute *pango_attr_float_new (const PangoAttrClass *klass, - double value); -static PangoAttribute *pango_attr_size_new_internal (int size, - gboolean absolute); +/* {{{ Generic attribute code */ G_LOCK_DEFINE_STATIC (attr_type); static GHashTable *name_map = NULL; /* MT-safe */ @@ -204,6 +193,12 @@ pango_attribute_equal (const PangoAttribute *attr1, return attr1->klass->equal (attr1, attr2); } +/* }}} */ +/* {{{ Attribute types */ +/* {{{ String attribute */ +static PangoAttribute *pango_attr_string_new (const PangoAttrClass *klass, + const char *str); + static PangoAttribute * pango_attr_string_copy (const PangoAttribute *attr) { @@ -236,32 +231,8 @@ pango_attr_string_new (const PangoAttrClass *klass, return (PangoAttribute *)result; } - -/** - * pango_attr_family_new: - * @family: the family or comma-separated list of families - * - * Create a new font family attribute. - * - * Return value: (transfer full): the newly allocated - * `PangoAttribute`, which should be freed with - * [method@Pango.Attribute.destroy] - */ -PangoAttribute * -pango_attr_family_new (const char *family) -{ - static const PangoAttrClass klass = { - PANGO_ATTR_FAMILY, - pango_attr_string_copy, - pango_attr_string_destroy, - pango_attr_string_equal - }; - - g_return_val_if_fail (family != NULL, NULL); - - return pango_attr_string_new (&klass, family); -} - + /* }}} */ +/* {{{ Language attribute */ static PangoAttribute * pango_attr_language_copy (const PangoAttribute *attr) { @@ -282,35 +253,12 @@ pango_attr_language_equal (const PangoAttribute *attr1, { return ((PangoAttrLanguage *)attr1)->value == ((PangoAttrLanguage *)attr2)->value; } - -/** - * pango_attr_language_new: - * @language: language tag - * - * Create a new language tag attribute. - * - * Return value: (transfer full): the newly allocated - * `PangoAttribute`, which should be freed with - * [method@Pango.Attribute.destroy] - */ -PangoAttribute * -pango_attr_language_new (PangoLanguage *language) -{ - PangoAttrLanguage *result; - - static const PangoAttrClass klass = { - PANGO_ATTR_LANGUAGE, - pango_attr_language_copy, - pango_attr_language_destroy, - pango_attr_language_equal - }; - - result = g_slice_new (PangoAttrLanguage); - pango_attribute_init (&result->attr, &klass); - result->value = language; - - return (PangoAttribute *)result; -} +/* }}}} */ +/* {{{ Color attribute */ +static PangoAttribute *pango_attr_color_new (const PangoAttrClass *klass, + guint16 red, + guint16 green, + guint16 blue); static PangoAttribute * pango_attr_color_copy (const PangoAttribute *attr) @@ -357,60 +305,10 @@ pango_attr_color_new (const PangoAttrClass *klass, return (PangoAttribute *)result; } - -/** - * pango_attr_foreground_new: - * @red: the red value (ranging from 0 to 65535) - * @green: the green value - * @blue: the blue value - * - * Create a new foreground color attribute. - * - * Return value: (transfer full): the newly allocated - * `PangoAttribute`, which should be freed with - * [method@Pango.Attribute.destroy] - */ -PangoAttribute * -pango_attr_foreground_new (guint16 red, - guint16 green, - guint16 blue) -{ - static const PangoAttrClass klass = { - PANGO_ATTR_FOREGROUND, - pango_attr_color_copy, - pango_attr_color_destroy, - pango_attr_color_equal - }; - - return pango_attr_color_new (&klass, red, green, blue); -} - -/** - * pango_attr_background_new: - * @red: the red value (ranging from 0 to 65535) - * @green: the green value - * @blue: the blue value - * - * Create a new background color attribute. - * - * Return value: (transfer full): the newly allocated - * `PangoAttribute`, which should be freed with - * [method@Pango.Attribute.destroy] - */ -PangoAttribute * -pango_attr_background_new (guint16 red, - guint16 green, - guint16 blue) -{ - static const PangoAttrClass klass = { - PANGO_ATTR_BACKGROUND, - pango_attr_color_copy, - pango_attr_color_destroy, - pango_attr_color_equal - }; - - return pango_attr_color_new (&klass, red, green, blue); -} +/* }}}} */ +/* {{{ Integer attribute */ +static PangoAttribute *pango_attr_int_new (const PangoAttrClass *klass, + int value); static PangoAttribute * pango_attr_int_copy (const PangoAttribute *attr) @@ -448,6 +346,10 @@ pango_attr_int_new (const PangoAttrClass *klass, return (PangoAttribute *)result; } +/* }}} */ +/* {{{ Float attribute */ +static PangoAttribute *pango_attr_float_new (const PangoAttrClass *klass, + double value); static PangoAttribute * pango_attr_float_copy (const PangoAttribute *attr) @@ -475,7 +377,7 @@ pango_attr_float_equal (const PangoAttribute *attr1, return (float_attr1->value == float_attr2->value); } -static PangoAttribute* +static PangoAttribute * pango_attr_float_new (const PangoAttrClass *klass, double value) { @@ -485,6 +387,10 @@ pango_attr_float_new (const PangoAttrClass *klass, return (PangoAttribute *)result; } +/* }}} */ +/* {{{ Size attribute */ +static PangoAttribute *pango_attr_size_new_internal (int size, + gboolean absolute); static PangoAttribute * pango_attr_size_copy (const PangoAttribute *attr) @@ -541,6 +447,192 @@ pango_attr_size_new_internal (int size, return (PangoAttribute *)result; } +/* }}} */ +/* {{{ Font description attribute */ +static PangoAttribute * +pango_attr_font_desc_copy (const PangoAttribute *attr) +{ + const PangoAttrFontDesc *desc_attr = (const PangoAttrFontDesc *)attr; + + return pango_attr_font_desc_new (desc_attr->desc); +} + +static void +pango_attr_font_desc_destroy (PangoAttribute *attr) +{ + PangoAttrFontDesc *desc_attr = (PangoAttrFontDesc *)attr; + + pango_font_description_free (desc_attr->desc); + g_slice_free (PangoAttrFontDesc, desc_attr); +} + +static gboolean +pango_attr_font_desc_equal (const PangoAttribute *attr1, + const PangoAttribute *attr2) +{ + const PangoAttrFontDesc *desc_attr1 = (const PangoAttrFontDesc *)attr1; + const PangoAttrFontDesc *desc_attr2 = (const PangoAttrFontDesc *)attr2; + + return pango_font_description_get_set_fields (desc_attr1->desc) == + pango_font_description_get_set_fields (desc_attr2->desc) && + pango_font_description_equal (desc_attr1->desc, desc_attr2->desc); +} +/* }}} */ +/* {{{ Shape attribute */ +static PangoAttribute * +pango_attr_shape_copy (const PangoAttribute *attr) +{ + const PangoAttrShape *shape_attr = (PangoAttrShape *)attr; + gpointer data; + + if (shape_attr->copy_func) + data = shape_attr->copy_func (shape_attr->data); + else + data = shape_attr->data; + + return pango_attr_shape_new_with_data (&shape_attr->ink_rect, &shape_attr->logical_rect, + data, shape_attr->copy_func, shape_attr->destroy_func); +} + +static void +pango_attr_shape_destroy (PangoAttribute *attr) +{ + PangoAttrShape *shape_attr = (PangoAttrShape *)attr; + + if (shape_attr->destroy_func) + shape_attr->destroy_func (shape_attr->data); + + g_slice_free (PangoAttrShape, shape_attr); +} + +static gboolean +pango_attr_shape_equal (const PangoAttribute *attr1, + const PangoAttribute *attr2) +{ + const PangoAttrShape *shape_attr1 = (const PangoAttrShape *)attr1; + const PangoAttrShape *shape_attr2 = (const PangoAttrShape *)attr2; + + return (shape_attr1->logical_rect.x == shape_attr2->logical_rect.x && + shape_attr1->logical_rect.y == shape_attr2->logical_rect.y && + shape_attr1->logical_rect.width == shape_attr2->logical_rect.width && + shape_attr1->logical_rect.height == shape_attr2->logical_rect.height && + shape_attr1->ink_rect.x == shape_attr2->ink_rect.x && + shape_attr1->ink_rect.y == shape_attr2->ink_rect.y && + shape_attr1->ink_rect.width == shape_attr2->ink_rect.width && + shape_attr1->ink_rect.height == shape_attr2->ink_rect.height && + shape_attr1->data == shape_attr2->data); +} +/* }}} */ +/* }}} */ +/* {{{ Public API */ + +/** + * pango_attr_family_new: + * @family: the family or comma-separated list of families + * + * Create a new font family attribute. + * + * Return value: (transfer full): the newly allocated + * `PangoAttribute`, which should be freed with + * [method@Pango.Attribute.destroy] + */ +PangoAttribute * +pango_attr_family_new (const char *family) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_FAMILY, + pango_attr_string_copy, + pango_attr_string_destroy, + pango_attr_string_equal + }; + + g_return_val_if_fail (family != NULL, NULL); + + return pango_attr_string_new (&klass, family); +} + +/** + * pango_attr_language_new: + * @language: language tag + * + * Create a new language tag attribute. + * + * Return value: (transfer full): the newly allocated + * `PangoAttribute`, which should be freed with + * [method@Pango.Attribute.destroy] + */ +PangoAttribute * +pango_attr_language_new (PangoLanguage *language) +{ + PangoAttrLanguage *result; + + static const PangoAttrClass klass = { + PANGO_ATTR_LANGUAGE, + pango_attr_language_copy, + pango_attr_language_destroy, + pango_attr_language_equal + }; + + result = g_slice_new (PangoAttrLanguage); + pango_attribute_init (&result->attr, &klass); + result->value = language; + + return (PangoAttribute *)result; +} + +/** + * pango_attr_foreground_new: + * @red: the red value (ranging from 0 to 65535) + * @green: the green value + * @blue: the blue value + * + * Create a new foreground color attribute. + * + * Return value: (transfer full): the newly allocated + * `PangoAttribute`, which should be freed with + * [method@Pango.Attribute.destroy] + */ +PangoAttribute * +pango_attr_foreground_new (guint16 red, + guint16 green, + guint16 blue) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_FOREGROUND, + pango_attr_color_copy, + pango_attr_color_destroy, + pango_attr_color_equal + }; + + return pango_attr_color_new (&klass, red, green, blue); +} + +/** + * pango_attr_background_new: + * @red: the red value (ranging from 0 to 65535) + * @green: the green value + * @blue: the blue value + * + * Create a new background color attribute. + * + * Return value: (transfer full): the newly allocated + * `PangoAttribute`, which should be freed with + * [method@Pango.Attribute.destroy] + */ +PangoAttribute * +pango_attr_background_new (guint16 red, + guint16 green, + guint16 blue) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_BACKGROUND, + pango_attr_color_copy, + pango_attr_color_destroy, + pango_attr_color_equal + }; + + return pango_attr_color_new (&klass, red, green, blue); +} /** * pango_attr_size_new: @@ -667,35 +759,6 @@ pango_attr_stretch_new (PangoStretch stretch) return pango_attr_int_new (&klass, (int)stretch); } -static PangoAttribute * -pango_attr_font_desc_copy (const PangoAttribute *attr) -{ - const PangoAttrFontDesc *desc_attr = (const PangoAttrFontDesc *)attr; - - return pango_attr_font_desc_new (desc_attr->desc); -} - -static void -pango_attr_font_desc_destroy (PangoAttribute *attr) -{ - PangoAttrFontDesc *desc_attr = (PangoAttrFontDesc *)attr; - - pango_font_description_free (desc_attr->desc); - g_slice_free (PangoAttrFontDesc, desc_attr); -} - -static gboolean -pango_attr_font_desc_equal (const PangoAttribute *attr1, - const PangoAttribute *attr2) -{ - const PangoAttrFontDesc *desc_attr1 = (const PangoAttrFontDesc *)attr1; - const PangoAttrFontDesc *desc_attr2 = (const PangoAttrFontDesc *)attr2; - - return pango_font_description_get_set_fields (desc_attr1->desc) == - pango_font_description_get_set_fields (desc_attr2->desc) && - pango_font_description_equal (desc_attr1->desc, desc_attr2->desc); -} - /** * pango_attr_font_desc_new: * @desc: the font description @@ -726,7 +789,6 @@ pango_attr_font_desc_new (const PangoFontDescription *desc) return (PangoAttribute *)result; } - /** * pango_attr_underline_new: * @underline: the underline style @@ -944,50 +1006,6 @@ pango_attr_letter_spacing_new (int letter_spacing) return pango_attr_int_new (&klass, letter_spacing); } -static PangoAttribute * -pango_attr_shape_copy (const PangoAttribute *attr) -{ - const PangoAttrShape *shape_attr = (PangoAttrShape *)attr; - gpointer data; - - if (shape_attr->copy_func) - data = shape_attr->copy_func (shape_attr->data); - else - data = shape_attr->data; - - return pango_attr_shape_new_with_data (&shape_attr->ink_rect, &shape_attr->logical_rect, - data, shape_attr->copy_func, shape_attr->destroy_func); -} - -static void -pango_attr_shape_destroy (PangoAttribute *attr) -{ - PangoAttrShape *shape_attr = (PangoAttrShape *)attr; - - if (shape_attr->destroy_func) - shape_attr->destroy_func (shape_attr->data); - - g_slice_free (PangoAttrShape, shape_attr); -} - -static gboolean -pango_attr_shape_equal (const PangoAttribute *attr1, - const PangoAttribute *attr2) -{ - const PangoAttrShape *shape_attr1 = (const PangoAttrShape *)attr1; - const PangoAttrShape *shape_attr2 = (const PangoAttrShape *)attr2; - - return (shape_attr1->logical_rect.x == shape_attr2->logical_rect.x && - shape_attr1->logical_rect.y == shape_attr2->logical_rect.y && - shape_attr1->logical_rect.width == shape_attr2->logical_rect.width && - shape_attr1->logical_rect.height == shape_attr2->logical_rect.height && - shape_attr1->ink_rect.x == shape_attr2->ink_rect.x && - shape_attr1->ink_rect.y == shape_attr2->ink_rect.y && - shape_attr1->ink_rect.width == shape_attr2->ink_rect.width && - shape_attr1->ink_rect.height == shape_attr2->ink_rect.height && - shape_attr1->data == shape_attr2->data); -} - /** * pango_attr_shape_new_with_data: * @ink_rect: ink rectangle to assign to each character @@ -1393,9 +1411,265 @@ pango_attr_line_height_new_absolute (int height) return pango_attr_int_new (&klass, height); } -/* - * Attribute List +/* }}} */ +/* {{{ Binding helpers */ + +/** + * pango_attribute_as_int: + * @attr: A `PangoAttribute` such as weight + * + * Returns the attribute cast to `PangoAttrInt`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrInt`, + * or %NULL if it's not an integer attribute + * + * Since: 1.50 + */ +PangoAttrInt * +pango_attribute_as_int (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_STYLE: + case PANGO_ATTR_WEIGHT: + case PANGO_ATTR_VARIANT: + case PANGO_ATTR_STRETCH: + case PANGO_ATTR_UNDERLINE: + case PANGO_ATTR_STRIKETHROUGH: + case PANGO_ATTR_RISE: + case PANGO_ATTR_FALLBACK: + case PANGO_ATTR_LETTER_SPACING: + case PANGO_ATTR_GRAVITY: + case PANGO_ATTR_GRAVITY_HINT: + case PANGO_ATTR_FOREGROUND_ALPHA: + case PANGO_ATTR_BACKGROUND_ALPHA: + case PANGO_ATTR_ALLOW_BREAKS: + case PANGO_ATTR_SHOW: + case PANGO_ATTR_INSERT_HYPHENS: + case PANGO_ATTR_OVERLINE: + return (PangoAttrInt *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_float: + * @attr: A `PangoAttribute` such as scale + * + * Returns the attribute cast to `PangoAttrFloat`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrFloat`, + * or %NULL if it's not a floating point attribute + * + * Since: 1.50 + */ +PangoAttrFloat * +pango_attribute_as_float (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_SCALE: + case PANGO_ATTR_LINE_HEIGHT: + return (PangoAttrFloat *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_string: + * @attr: A `PangoAttribute` such as family + * + * Returns the attribute cast to `PangoAttrString`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrString`, + * or %NULL if it's not a string attribute */ +PangoAttrString * +pango_attribute_as_string (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_FAMILY: + return (PangoAttrString *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_size: + * @attr: A `PangoAttribute` representing a size + * + * Returns the attribute cast to `PangoAttrSize`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrSize`, + * or NULL if it's not a size attribute + * + * Since: 1.50 + */ +PangoAttrSize * +pango_attribute_as_size (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_SIZE: + case PANGO_ATTR_ABSOLUTE_SIZE: + return (PangoAttrSize *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_color: + * @attr: A `PangoAttribute` such as foreground + * + * Returns the attribute cast to `PangoAttrColor`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrColor`, + * or %NULL if it's not a color attribute + * + * Since: 1.50 + */ +PangoAttrColor * +pango_attribute_as_color (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_FOREGROUND: + case PANGO_ATTR_BACKGROUND: + case PANGO_ATTR_UNDERLINE_COLOR: + case PANGO_ATTR_STRIKETHROUGH_COLOR: + case PANGO_ATTR_OVERLINE_COLOR: + return (PangoAttrColor *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_font_desc: + * @attr: A `PangoAttribute` representing a font description + * + * Returns the attribute cast to `PangoAttrFontDesc`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrFontDesc`, + * or %NULL if it's not a font description attribute + * + * Since: 1.50 + */ +PangoAttrFontDesc * +pango_attribute_as_font_desc (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_FONT_DESC: + return (PangoAttrFontDesc *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_font_features: + * @attr: A `PangoAttribute` representing font features + * + * Returns the attribute cast to `PangoAttrFontFeatures`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrFontFeatures`, + * or %NULL if it's not a font features attribute + * + * Since: 1.50 + */ +PangoAttrFontFeatures * +pango_attribute_as_font_features (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_FONT_FEATURES: + return (PangoAttrFontFeatures *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_language: + * @attr: A `PangoAttribute` representing a language + * + * Returns the attribute cast to `PangoAttrLanguage`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrLanguage`, + * or %NULL if it's not a language attribute + * + * Since: 1.50 + */ +PangoAttrLanguage * +pango_attribute_as_language (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_LANGUAGE: + return (PangoAttrLanguage *)attr; + + default: + return NULL; + } +} + +/** + * pango_attribute_as_shape: + * @attr: A `PangoAttribute` representing a shape + * + * Returns the attribute cast to `PangoAttrShape`. + * + * This is mainly useful for language bindings. + * + * Returns: (nullable) (transfer none): The attribute as `PangoAttrShape`, + * or %NULL if it's not a shape attribute + * + * Since: 1.50 + */ +PangoAttrShape * +pango_attribute_as_shape (PangoAttribute *attr) +{ + switch (attr->klass->type) + { + case PANGO_ATTR_SHAPE: + return (PangoAttrShape *)attr; + + default: + return NULL; + } +} + +/* }}} */ +/* {{{ Attribute List */ G_DEFINE_BOXED_TYPE (PangoAttrList, pango_attr_list, pango_attr_list_copy, @@ -2043,6 +2317,63 @@ _pango_attr_list_has_attributes (const PangoAttrList *list) return list && list->attributes != NULL && list->attributes->len > 0; } +/** + * pango_attr_list_filter: + * @list: a `PangoAttrList` + * @func: (scope call) (closure data): callback function; + * returns %TRUE if an attribute should be filtered out + * @data: (closure): Data to be passed to @func + * + * Given a `PangoAttrList` and callback function, removes + * any elements of @list for which @func returns %TRUE and + * inserts them into a new list. + * + * Return value: (transfer full) (nullable): the new + * `PangoAttrList` or %NULL if no attributes of the + * given types were found + * + * Since: 1.2 + */ +PangoAttrList * +pango_attr_list_filter (PangoAttrList *list, + PangoAttrFilterFunc func, + gpointer data) + +{ + PangoAttrList *new = NULL; + guint i, p; + + g_return_val_if_fail (list != NULL, NULL); + + if (!list->attributes || list->attributes->len == 0) + return NULL; + + for (i = 0, p = list->attributes->len; i < p; i++) + { + PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); + + if ((*func) (tmp_attr, data)) + { + g_ptr_array_remove_index (list->attributes, i); + i--; /* Need to look at this index again */ + p--; + + if (G_UNLIKELY (!new)) + { + new = pango_attr_list_new (); + new->attributes = g_ptr_array_new (); + } + + g_ptr_array_add (new->attributes, tmp_attr); + } + } + + return new; +} + +/* }}} */ +/* {{{ Attribute Iterator */ + G_DEFINE_BOXED_TYPE (PangoAttrIterator, pango_attr_iterator, pango_attr_iterator_copy, @@ -2448,60 +2779,6 @@ pango_attr_iterator_get_font (PangoAttrIterator *iterator, } /** - * pango_attr_list_filter: - * @list: a `PangoAttrList` - * @func: (scope call) (closure data): callback function; - * returns %TRUE if an attribute should be filtered out - * @data: (closure): Data to be passed to @func - * - * Given a `PangoAttrList` and callback function, removes - * any elements of @list for which @func returns %TRUE and - * inserts them into a new list. - * - * Return value: (transfer full) (nullable): the new - * `PangoAttrList` or %NULL if no attributes of the - * given types were found - * - * Since: 1.2 - */ -PangoAttrList * -pango_attr_list_filter (PangoAttrList *list, - PangoAttrFilterFunc func, - gpointer data) - -{ - PangoAttrList *new = NULL; - guint i, p; - - g_return_val_if_fail (list != NULL, NULL); - - if (!list->attributes || list->attributes->len == 0) - return NULL; - - for (i = 0, p = list->attributes->len; i < p; i++) - { - PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); - - if ((*func) (tmp_attr, data)) - { - g_ptr_array_remove_index (list->attributes, i); - i--; /* Need to look at this index again */ - p--; - - if (G_UNLIKELY (!new)) - { - new = pango_attr_list_new (); - new->attributes = g_ptr_array_new (); - } - - g_ptr_array_add (new->attributes, tmp_attr); - } - } - - return new; -} - -/** * pango_attr_iterator_get_attrs: * @iterator: a `PangoAttrIterator` * @@ -2549,257 +2826,27 @@ pango_attr_iterator_get_attrs (PangoAttrIterator *iterator) return attrs; } - -/** - * pango_attribute_as_int: - * @attr: A `PangoAttribute` such as weight - * - * Returns the attribute cast to `PangoAttrInt`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrInt`, - * or %NULL if it's not an integer attribute - * - * Since: 1.50 - */ -PangoAttrInt * -pango_attribute_as_int (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_STYLE: - case PANGO_ATTR_WEIGHT: - case PANGO_ATTR_VARIANT: - case PANGO_ATTR_STRETCH: - case PANGO_ATTR_UNDERLINE: - case PANGO_ATTR_STRIKETHROUGH: - case PANGO_ATTR_RISE: - case PANGO_ATTR_FALLBACK: - case PANGO_ATTR_LETTER_SPACING: - case PANGO_ATTR_GRAVITY: - case PANGO_ATTR_GRAVITY_HINT: - case PANGO_ATTR_FOREGROUND_ALPHA: - case PANGO_ATTR_BACKGROUND_ALPHA: - case PANGO_ATTR_ALLOW_BREAKS: - case PANGO_ATTR_SHOW: - case PANGO_ATTR_INSERT_HYPHENS: - case PANGO_ATTR_OVERLINE: - return (PangoAttrInt *)attr; - - default: - return NULL; - } -} - -/** - * pango_attribute_as_float: - * @attr: A `PangoAttribute` such as scale - * - * Returns the attribute cast to `PangoAttrFloat`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrFloat`, - * or %NULL if it's not a floating point attribute - * - * Since: 1.50 - */ -PangoAttrFloat * -pango_attribute_as_float (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_SCALE: - case PANGO_ATTR_LINE_HEIGHT: - return (PangoAttrFloat *)attr; - - default: - return NULL; - } -} - -/** - * pango_attribute_as_string: - * @attr: A `PangoAttribute` such as family - * - * Returns the attribute cast to `PangoAttrString`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrString`, - * or %NULL if it's not a string attribute - */ -PangoAttrString * -pango_attribute_as_string (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_FAMILY: - return (PangoAttrString *)attr; - - default: - return NULL; - } -} - -/** - * pango_attribute_as_size: - * @attr: A `PangoAttribute` representing a size - * - * Returns the attribute cast to `PangoAttrSize`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrSize`, - * or NULL if it's not a size attribute - * - * Since: 1.50 - */ -PangoAttrSize * -pango_attribute_as_size (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_SIZE: - case PANGO_ATTR_ABSOLUTE_SIZE: - return (PangoAttrSize *)attr; - - default: - return NULL; - } -} - -/** - * pango_attribute_as_color: - * @attr: A `PangoAttribute` such as foreground - * - * Returns the attribute cast to `PangoAttrColor`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrColor`, - * or %NULL if it's not a color attribute - * - * Since: 1.50 - */ -PangoAttrColor * -pango_attribute_as_color (PangoAttribute *attr) +gboolean +pango_attr_iterator_advance (PangoAttrIterator *iterator, + int index) { - switch (attr->klass->type) - { - case PANGO_ATTR_FOREGROUND: - case PANGO_ATTR_BACKGROUND: - case PANGO_ATTR_UNDERLINE_COLOR: - case PANGO_ATTR_STRIKETHROUGH_COLOR: - case PANGO_ATTR_OVERLINE_COLOR: - return (PangoAttrColor *)attr; + int start_range, end_range; - default: - return NULL; - } -} + pango_attr_iterator_range (iterator, &start_range, &end_range); -/** - * pango_attribute_as_font_desc: - * @attr: A `PangoAttribute` representing a font description - * - * Returns the attribute cast to `PangoAttrFontDesc`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrFontDesc`, - * or %NULL if it's not a font description attribute - * - * Since: 1.50 - */ -PangoAttrFontDesc * -pango_attribute_as_font_desc (PangoAttribute *attr) -{ - switch (attr->klass->type) + while (index >= end_range) { - case PANGO_ATTR_FONT_DESC: - return (PangoAttrFontDesc *)attr; - - default: - return NULL; - } -} - -/** - * pango_attribute_as_font_features: - * @attr: A `PangoAttribute` representing font features - * - * Returns the attribute cast to `PangoAttrFontFeatures`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrFontFeatures`, - * or %NULL if it's not a font features attribute - * - * Since: 1.50 - */ -PangoAttrFontFeatures * -pango_attribute_as_font_features (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_FONT_FEATURES: - return (PangoAttrFontFeatures *)attr; - - default: - return NULL; + if (!pango_attr_iterator_next (iterator)) + return FALSE; + pango_attr_iterator_range (iterator, &start_range, &end_range); } -} -/** - * pango_attribute_as_language: - * @attr: A `PangoAttribute` representing a language - * - * Returns the attribute cast to `PangoAttrLanguage`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrLanguage`, - * or %NULL if it's not a language attribute - * - * Since: 1.50 - */ -PangoAttrLanguage * -pango_attribute_as_language (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_LANGUAGE: - return (PangoAttrLanguage *)attr; + if (start_range > index) + g_warning ("pango_attr_iterator_advance(): iterator had already " + "moved beyond the index"); - default: - return NULL; - } + return TRUE; } +/* }}} */ -/** - * pango_attribute_as_shape: - * @attr: A `PangoAttribute` representing a shape - * - * Returns the attribute cast to `PangoAttrShape`. - * - * This is mainly useful for language bindings. - * - * Returns: (nullable) (transfer none): The attribute as `PangoAttrShape`, - * or %NULL if it's not a shape attribute - * - * Since: 1.50 - */ -PangoAttrShape * -pango_attribute_as_shape (PangoAttribute *attr) -{ - switch (attr->klass->type) - { - case PANGO_ATTR_SHAPE: - return (PangoAttrShape *)attr; - - default: - return NULL; - } -} +/* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 35615bf3..e3012008 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -23,111 +23,26 @@ #define __PANGO_ATTRIBUTES_H__ #include <pango/pango-font.h> +#include <pango/pango-color.h> #include <glib-object.h> G_BEGIN_DECLS -/* PangoColor */ -typedef struct _PangoColor PangoColor; +typedef struct _PangoAttribute PangoAttribute; +typedef struct _PangoAttrClass PangoAttrClass; -/** - * PangoColor: - * @red: value of red component - * @green: value of green component - * @blue: value of blue component - * - * The `PangoColor` structure is used to - * represent a color in an uncalibrated RGB color-space. - */ -struct _PangoColor -{ - guint16 red; - guint16 green; - guint16 blue; -}; - -/** - * PANGO_TYPE_COLOR: - * - * The `GObject` type for `PangoColor`. - */ -#define PANGO_TYPE_COLOR pango_color_get_type () -PANGO_AVAILABLE_IN_ALL -GType pango_color_get_type (void) G_GNUC_CONST; - -PANGO_AVAILABLE_IN_ALL -GType pango_attribute_get_type (void) G_GNUC_CONST; - -PANGO_AVAILABLE_IN_ALL -PangoColor *pango_color_copy (const PangoColor *src); -PANGO_AVAILABLE_IN_ALL -void pango_color_free (PangoColor *color); -PANGO_AVAILABLE_IN_ALL -gboolean pango_color_parse (PangoColor *color, - const char *spec); -PANGO_AVAILABLE_IN_1_46 -gboolean pango_color_parse_with_alpha - (PangoColor *color, - guint16 *alpha, - const char *spec); -PANGO_AVAILABLE_IN_1_16 -gchar *pango_color_to_string(const PangoColor *color); - - -/* Attributes */ - -typedef struct _PangoAttribute PangoAttribute; -typedef struct _PangoAttrClass PangoAttrClass; - -typedef struct _PangoAttrString PangoAttrString; -typedef struct _PangoAttrLanguage PangoAttrLanguage; -typedef struct _PangoAttrInt PangoAttrInt; -typedef struct _PangoAttrSize PangoAttrSize; -typedef struct _PangoAttrFloat PangoAttrFloat; -typedef struct _PangoAttrColor PangoAttrColor; -typedef struct _PangoAttrFontDesc PangoAttrFontDesc; -typedef struct _PangoAttrShape PangoAttrShape; +typedef struct _PangoAttrString PangoAttrString; +typedef struct _PangoAttrLanguage PangoAttrLanguage; +typedef struct _PangoAttrInt PangoAttrInt; +typedef struct _PangoAttrSize PangoAttrSize; +typedef struct _PangoAttrFloat PangoAttrFloat; +typedef struct _PangoAttrColor PangoAttrColor; +typedef struct _PangoAttrFontDesc PangoAttrFontDesc; +typedef struct _PangoAttrShape PangoAttrShape; typedef struct _PangoAttrFontFeatures PangoAttrFontFeatures; /** - * PANGO_TYPE_ATTR_LIST: - * - * The `GObject` type for `PangoAttrList`. - */ -#define PANGO_TYPE_ATTR_LIST pango_attr_list_get_type () - -/** - * PangoAttrIterator: - * - * A `PangoAttrIterator` is used to iterate through a `PangoAttrList`. - * - * A new iterator is created with [method@Pango.AttrList.get_iterator]. - * Once the iterator is created, it can be advanced through the style - * changes in the text using [method@Pango.AttrIterator.next]. At each - * style change, the range of the current style segment and the attributes - * currently in effect can be queried. - */ - -/** - * PangoAttrList: - * - * A `PangoAttrList` represents a list of attributes that apply to a section - * of text. - * - * The attributes in a `PangoAttrList` are, in general, allowed to overlap in - * an arbitrary fashion. However, if the attributes are manipulated only through - * [method@Pango.AttrList.change], the overlap between properties will meet - * stricter criteria. - * - * Since the `PangoAttrList` structure is stored as a linear list, it is not - * suitable for storing attributes for large amounts of text. In general, you - * should not use a single `PangoAttrList` for more than one paragraph of text. - */ -typedef struct _PangoAttrList PangoAttrList; -typedef struct _PangoAttrIterator PangoAttrIterator; - -/** * PangoAttrType: * @PANGO_ATTR_INVALID: does not happen * @PANGO_ATTR_LANGUAGE: language ([struct@Pango.AttrLanguage]) @@ -173,37 +88,37 @@ typedef struct _PangoAttrIterator PangoAttrIterator; typedef enum { PANGO_ATTR_INVALID, /* 0 is an invalid attribute type */ - PANGO_ATTR_LANGUAGE, /* PangoAttrLanguage */ - PANGO_ATTR_FAMILY, /* PangoAttrString */ - PANGO_ATTR_STYLE, /* PangoAttrInt */ - PANGO_ATTR_WEIGHT, /* PangoAttrInt */ - PANGO_ATTR_VARIANT, /* PangoAttrInt */ - PANGO_ATTR_STRETCH, /* PangoAttrInt */ - PANGO_ATTR_SIZE, /* PangoAttrSize */ - PANGO_ATTR_FONT_DESC, /* PangoAttrFontDesc */ - PANGO_ATTR_FOREGROUND, /* PangoAttrColor */ - PANGO_ATTR_BACKGROUND, /* PangoAttrColor */ - PANGO_ATTR_UNDERLINE, /* PangoAttrInt */ - PANGO_ATTR_STRIKETHROUGH, /* PangoAttrInt */ - PANGO_ATTR_RISE, /* PangoAttrInt */ - PANGO_ATTR_SHAPE, /* PangoAttrShape */ + PANGO_ATTR_LANGUAGE, /* PangoAttrLanguage */ + PANGO_ATTR_FAMILY, /* PangoAttrString */ + PANGO_ATTR_STYLE, /* PangoAttrInt */ + PANGO_ATTR_WEIGHT, /* PangoAttrInt */ + PANGO_ATTR_VARIANT, /* PangoAttrInt */ + PANGO_ATTR_STRETCH, /* PangoAttrInt */ + PANGO_ATTR_SIZE, /* PangoAttrSize */ + PANGO_ATTR_FONT_DESC, /* PangoAttrFontDesc */ + PANGO_ATTR_FOREGROUND, /* PangoAttrColor */ + PANGO_ATTR_BACKGROUND, /* PangoAttrColor */ + PANGO_ATTR_UNDERLINE, /* PangoAttrInt */ + PANGO_ATTR_STRIKETHROUGH, /* PangoAttrInt */ + PANGO_ATTR_RISE, /* PangoAttrInt */ + PANGO_ATTR_SHAPE, /* PangoAttrShape */ PANGO_ATTR_SCALE, /* PangoAttrFloat */ PANGO_ATTR_FALLBACK, /* PangoAttrInt */ PANGO_ATTR_LETTER_SPACING, /* PangoAttrInt */ - PANGO_ATTR_UNDERLINE_COLOR, /* PangoAttrColor */ + PANGO_ATTR_UNDERLINE_COLOR, /* PangoAttrColor */ PANGO_ATTR_STRIKETHROUGH_COLOR,/* PangoAttrColor */ - PANGO_ATTR_ABSOLUTE_SIZE, /* PangoAttrSize */ - PANGO_ATTR_GRAVITY, /* PangoAttrInt */ - PANGO_ATTR_GRAVITY_HINT, /* PangoAttrInt */ - PANGO_ATTR_FONT_FEATURES, /* PangoAttrString */ - PANGO_ATTR_FOREGROUND_ALPHA, /* PangoAttrInt */ - PANGO_ATTR_BACKGROUND_ALPHA, /* PangoAttrInt */ - PANGO_ATTR_ALLOW_BREAKS, /* PangoAttrInt */ - PANGO_ATTR_SHOW, /* PangoAttrInt */ - PANGO_ATTR_INSERT_HYPHENS, /* PangoAttrInt */ - PANGO_ATTR_OVERLINE, /* PangoAttrInt */ - PANGO_ATTR_OVERLINE_COLOR, /* PangoAttrColor */ - PANGO_ATTR_LINE_HEIGHT, /* PangoAttrFloat */ + PANGO_ATTR_ABSOLUTE_SIZE, /* PangoAttrSize */ + PANGO_ATTR_GRAVITY, /* PangoAttrInt */ + PANGO_ATTR_GRAVITY_HINT, /* PangoAttrInt */ + PANGO_ATTR_FONT_FEATURES, /* PangoAttrString */ + PANGO_ATTR_FOREGROUND_ALPHA, /* PangoAttrInt */ + PANGO_ATTR_BACKGROUND_ALPHA, /* PangoAttrInt */ + PANGO_ATTR_ALLOW_BREAKS, /* PangoAttrInt */ + PANGO_ATTR_SHOW, /* PangoAttrInt */ + PANGO_ATTR_INSERT_HYPHENS, /* PangoAttrInt */ + PANGO_ATTR_OVERLINE, /* PangoAttrInt */ + PANGO_ATTR_OVERLINE_COLOR, /* PangoAttrColor */ + PANGO_ATTR_LINE_HEIGHT, /* PangoAttrFloat */ PANGO_ATTR_ABSOLUTE_LINE_HEIGHT, /* PangoAttrInt */ } PangoAttrType; @@ -268,6 +183,26 @@ typedef enum { } PangoOverline; /** + * PangoShowFlags: + * @PANGO_SHOW_NONE: No special treatment for invisible characters + * @PANGO_SHOW_SPACES: Render spaces, tabs and newlines visibly + * @PANGO_SHOW_LINE_BREAKS: Render line breaks visibly + * @PANGO_SHOW_IGNORABLES: Render default-ignorable Unicode + * characters visibly + * + * These flags affect how Pango treats characters that are normally + * not visible in the output. + * + * Since: 1.44 + */ +typedef enum { + PANGO_SHOW_NONE = 0, + PANGO_SHOW_SPACES = 1 << 0, + PANGO_SHOW_LINE_BREAKS = 1 << 1, + PANGO_SHOW_IGNORABLES = 1 << 2 +} PangoShowFlags; + +/** * PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING: * * Value for @start_index in `PangoAttribute` that indicates @@ -292,7 +227,7 @@ typedef enum { * @klass: the class structure holding information about the type of the attribute * @start_index: the start index of the range (in bytes). * @end_index: end index of the range (in bytes). The character at this index - * is not included in the range. + * is not included in the range. * * The `PangoAttribute` structure represents the common portions of all * attributes. @@ -306,8 +241,8 @@ typedef enum { struct _PangoAttribute { const PangoAttrClass *klass; - guint start_index; /* in bytes */ - guint end_index; /* in bytes. The character at this index is not included */ + guint start_index; + guint end_index; }; /** @@ -321,7 +256,7 @@ struct _PangoAttribute * filtering, %FALSE otherwise. */ typedef gboolean (*PangoAttrFilterFunc) (PangoAttribute *attribute, - gpointer user_data); + gpointer user_data); /** * PangoAttrDataCopyFunc: @@ -498,234 +433,229 @@ struct _PangoAttrFontFeatures }; PANGO_AVAILABLE_IN_ALL -PangoAttrType pango_attr_type_register (const gchar *name); -PANGO_AVAILABLE_IN_1_22 -const char * pango_attr_type_get_name (PangoAttrType type) G_GNUC_CONST; +GType pango_attribute_get_type (void) G_GNUC_CONST; +PANGO_AVAILABLE_IN_ALL +PangoAttrType pango_attr_type_register (const char *name); +PANGO_AVAILABLE_IN_1_22 +const char * pango_attr_type_get_name (PangoAttrType type) G_GNUC_CONST; PANGO_AVAILABLE_IN_1_20 -void pango_attribute_init (PangoAttribute *attr, - const PangoAttrClass *klass); +void pango_attribute_init (PangoAttribute *attr, + const PangoAttrClass *klass); PANGO_AVAILABLE_IN_ALL -PangoAttribute * pango_attribute_copy (const PangoAttribute *attr); +PangoAttribute * pango_attribute_copy (const PangoAttribute *attr); PANGO_AVAILABLE_IN_ALL -void pango_attribute_destroy (PangoAttribute *attr); +void pango_attribute_destroy (PangoAttribute *attr); PANGO_AVAILABLE_IN_ALL -gboolean pango_attribute_equal (const PangoAttribute *attr1, - const PangoAttribute *attr2) G_GNUC_PURE; +gboolean pango_attribute_equal (const PangoAttribute *attr1, + const PangoAttribute *attr2) G_GNUC_PURE; PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_language_new (PangoLanguage *language); +PangoAttribute * pango_attr_language_new (PangoLanguage *language); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_family_new (const char *family); +PangoAttribute * pango_attr_family_new (const char *family); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_foreground_new (guint16 red, - guint16 green, - guint16 blue); +PangoAttribute * pango_attr_foreground_new (guint16 red, + guint16 green, + guint16 blue); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_background_new (guint16 red, - guint16 green, - guint16 blue); +PangoAttribute * pango_attr_background_new (guint16 red, + guint16 green, + guint16 blue); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_size_new (int size); +PangoAttribute * pango_attr_size_new (int size); PANGO_AVAILABLE_IN_1_8 -PangoAttribute *pango_attr_size_new_absolute (int size); +PangoAttribute * pango_attr_size_new_absolute (int size); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_style_new (PangoStyle style); +PangoAttribute * pango_attr_style_new (PangoStyle style); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_weight_new (PangoWeight weight); +PangoAttribute * pango_attr_weight_new (PangoWeight weight); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_variant_new (PangoVariant variant); +PangoAttribute * pango_attr_variant_new (PangoVariant variant); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_stretch_new (PangoStretch stretch); +PangoAttribute * pango_attr_stretch_new (PangoStretch stretch); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_font_desc_new (const PangoFontDescription *desc); +PangoAttribute * pango_attr_font_desc_new (const PangoFontDescription *desc); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_underline_new (PangoUnderline underline); +PangoAttribute * pango_attr_underline_new (PangoUnderline underline); PANGO_AVAILABLE_IN_1_8 -PangoAttribute *pango_attr_underline_color_new (guint16 red, - guint16 green, - guint16 blue); +PangoAttribute * pango_attr_underline_color_new (guint16 red, + guint16 green, + guint16 blue); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_strikethrough_new (gboolean strikethrough); +PangoAttribute * pango_attr_strikethrough_new (gboolean strikethrough); PANGO_AVAILABLE_IN_1_8 -PangoAttribute *pango_attr_strikethrough_color_new (guint16 red, - guint16 green, - guint16 blue); - +PangoAttribute * pango_attr_strikethrough_color_new (guint16 red, + guint16 green, + guint16 blue); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_rise_new (int rise); +PangoAttribute * pango_attr_rise_new (int rise); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_scale_new (double scale_factor); +PangoAttribute * pango_attr_scale_new (double scale_factor); PANGO_AVAILABLE_IN_1_4 -PangoAttribute *pango_attr_fallback_new (gboolean enable_fallback); +PangoAttribute * pango_attr_fallback_new (gboolean enable_fallback); PANGO_AVAILABLE_IN_1_6 -PangoAttribute *pango_attr_letter_spacing_new (int letter_spacing); - +PangoAttribute * pango_attr_letter_spacing_new (int letter_spacing); PANGO_AVAILABLE_IN_ALL -PangoAttribute *pango_attr_shape_new (const PangoRectangle *ink_rect, - const PangoRectangle *logical_rect); +PangoAttribute * pango_attr_shape_new (const PangoRectangle *ink_rect, + const PangoRectangle *logical_rect); PANGO_AVAILABLE_IN_1_8 -PangoAttribute *pango_attr_shape_new_with_data (const PangoRectangle *ink_rect, - const PangoRectangle *logical_rect, - gpointer data, - PangoAttrDataCopyFunc copy_func, - GDestroyNotify destroy_func); - +PangoAttribute * pango_attr_shape_new_with_data (const PangoRectangle *ink_rect, + const PangoRectangle *logical_rect, + gpointer data, + PangoAttrDataCopyFunc copy_func, + GDestroyNotify destroy_func); PANGO_AVAILABLE_IN_1_16 -PangoAttribute *pango_attr_gravity_new (PangoGravity gravity); +PangoAttribute * pango_attr_gravity_new (PangoGravity gravity); PANGO_AVAILABLE_IN_1_16 -PangoAttribute *pango_attr_gravity_hint_new (PangoGravityHint hint); +PangoAttribute * pango_attr_gravity_hint_new (PangoGravityHint hint); PANGO_AVAILABLE_IN_1_38 -PangoAttribute *pango_attr_font_features_new (const gchar *features); +PangoAttribute * pango_attr_font_features_new (const char *features); PANGO_AVAILABLE_IN_1_38 -PangoAttribute *pango_attr_foreground_alpha_new (guint16 alpha); +PangoAttribute * pango_attr_foreground_alpha_new (guint16 alpha); PANGO_AVAILABLE_IN_1_38 -PangoAttribute *pango_attr_background_alpha_new (guint16 alpha); +PangoAttribute * pango_attr_background_alpha_new (guint16 alpha); PANGO_AVAILABLE_IN_1_44 -PangoAttribute *pango_attr_allow_breaks_new (gboolean allow_breaks); +PangoAttribute * pango_attr_allow_breaks_new (gboolean allow_breaks); PANGO_AVAILABLE_IN_1_44 -PangoAttribute *pango_attr_insert_hyphens_new (gboolean insert_hyphens); - +PangoAttribute * pango_attr_insert_hyphens_new (gboolean insert_hyphens); PANGO_AVAILABLE_IN_1_46 -PangoAttribute *pango_attr_overline_new (PangoOverline overline); +PangoAttribute * pango_attr_overline_new (PangoOverline overline); PANGO_AVAILABLE_IN_1_46 -PangoAttribute *pango_attr_overline_color_new (guint16 red, - guint16 green, - guint16 blue); +PangoAttribute * pango_attr_overline_color_new (guint16 red, + guint16 green, + guint16 blue); +PANGO_AVAILABLE_IN_1_44 +PangoAttribute * pango_attr_show_new (PangoShowFlags flags); +PANGO_AVAILABLE_IN_1_50 +PangoAttribute * pango_attr_line_height_new (double factor); +PANGO_AVAILABLE_IN_1_50 +PangoAttribute * pango_attr_line_height_new_absolute (int height); + +PANGO_AVAILABLE_IN_1_50 +PangoAttrString * pango_attribute_as_string (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrLanguage * pango_attribute_as_language (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrInt * pango_attribute_as_int (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrSize * pango_attribute_as_size (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrFloat * pango_attribute_as_float (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrColor * pango_attribute_as_color (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrFontDesc * pango_attribute_as_font_desc (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrShape * pango_attribute_as_shape (PangoAttribute *attr); +PANGO_AVAILABLE_IN_1_50 +PangoAttrFontFeatures * pango_attribute_as_font_features (PangoAttribute *attr); + +/* Attribute lists */ + +typedef struct _PangoAttrList PangoAttrList; +typedef struct _PangoAttrIterator PangoAttrIterator; + +#define PANGO_TYPE_ATTR_LIST pango_attr_list_get_type () /** - * PangoShowFlags: - * @PANGO_SHOW_NONE: No special treatment for invisible characters - * @PANGO_SHOW_SPACES: Render spaces, tabs and newlines visibly - * @PANGO_SHOW_LINE_BREAKS: Render line breaks visibly - * @PANGO_SHOW_IGNORABLES: Render default-ignorable Unicode - * characters visibly + * PangoAttrIterator: * - * These flags affect how Pango treats characters that are normally - * not visible in the output. + * A `PangoAttrIterator` is used to iterate through a `PangoAttrList`. + * + * A new iterator is created with [method@Pango.AttrList.get_iterator]. + * Once the iterator is created, it can be advanced through the style + * changes in the text using [method@Pango.AttrIterator.next]. At each + * style change, the range of the current style segment and the attributes + * currently in effect can be queried. */ -typedef enum { - PANGO_SHOW_NONE = 0, - PANGO_SHOW_SPACES = 1 << 0, - PANGO_SHOW_LINE_BREAKS = 1 << 1, - PANGO_SHOW_IGNORABLES = 1 << 2 -} PangoShowFlags; -PANGO_AVAILABLE_IN_1_44 -PangoAttribute *pango_attr_show_new (PangoShowFlags flags); - -PANGO_AVAILABLE_IN_1_50 -PangoAttribute *pango_attr_line_height_new (double factor); -PANGO_AVAILABLE_IN_1_50 -PangoAttribute *pango_attr_line_height_new_absolute (int height); +/** + * PangoAttrList: + * + * A `PangoAttrList` represents a list of attributes that apply to a section + * of text. + * + * The attributes in a `PangoAttrList` are, in general, allowed to overlap in + * an arbitrary fashion. However, if the attributes are manipulated only through + * [method@Pango.AttrList.change], the overlap between properties will meet + * stricter criteria. + * + * Since the `PangoAttrList` structure is stored as a linear list, it is not + * suitable for storing attributes for large amounts of text. In general, you + * should not use a single `PangoAttrList` for more than one paragraph of text. + */ PANGO_AVAILABLE_IN_ALL -GType pango_attr_list_get_type (void) G_GNUC_CONST; +GType pango_attr_list_get_type (void) G_GNUC_CONST; + PANGO_AVAILABLE_IN_ALL -PangoAttrList * pango_attr_list_new (void); +PangoAttrList * pango_attr_list_new (void); PANGO_AVAILABLE_IN_1_10 -PangoAttrList * pango_attr_list_ref (PangoAttrList *list); +PangoAttrList * pango_attr_list_ref (PangoAttrList *list); PANGO_AVAILABLE_IN_ALL -void pango_attr_list_unref (PangoAttrList *list); +void pango_attr_list_unref (PangoAttrList *list); PANGO_AVAILABLE_IN_ALL -PangoAttrList * pango_attr_list_copy (PangoAttrList *list); +PangoAttrList * pango_attr_list_copy (PangoAttrList *list); PANGO_AVAILABLE_IN_ALL -void pango_attr_list_insert (PangoAttrList *list, - PangoAttribute *attr); +void pango_attr_list_insert (PangoAttrList *list, + PangoAttribute *attr); PANGO_AVAILABLE_IN_ALL -void pango_attr_list_insert_before (PangoAttrList *list, - PangoAttribute *attr); +void pango_attr_list_insert_before (PangoAttrList *list, + PangoAttribute *attr); PANGO_AVAILABLE_IN_ALL -void pango_attr_list_change (PangoAttrList *list, - PangoAttribute *attr); +void pango_attr_list_change (PangoAttrList *list, + PangoAttribute *attr); PANGO_AVAILABLE_IN_ALL -void pango_attr_list_splice (PangoAttrList *list, - PangoAttrList *other, - gint pos, - gint len); +void pango_attr_list_splice (PangoAttrList *list, + PangoAttrList *other, + int pos, + int len); PANGO_AVAILABLE_IN_1_44 -void pango_attr_list_update (PangoAttrList *list, - int pos, - int remove, - int add); +void pango_attr_list_update (PangoAttrList *list, + int pos, + int remove, + int add); PANGO_AVAILABLE_IN_1_2 -PangoAttrList *pango_attr_list_filter (PangoAttrList *list, - PangoAttrFilterFunc func, - gpointer data); +PangoAttrList * pango_attr_list_filter (PangoAttrList *list, + PangoAttrFilterFunc func, + gpointer data); PANGO_AVAILABLE_IN_1_44 -GSList *pango_attr_list_get_attributes (PangoAttrList *list); +GSList * pango_attr_list_get_attributes (PangoAttrList *list); PANGO_AVAILABLE_IN_1_46 -gboolean pango_attr_list_equal (PangoAttrList *list, - PangoAttrList *other_list); +gboolean pango_attr_list_equal (PangoAttrList *list, + PangoAttrList *other_list); PANGO_AVAILABLE_IN_1_44 -GType pango_attr_iterator_get_type (void) G_GNUC_CONST; +GType pango_attr_iterator_get_type (void) G_GNUC_CONST; PANGO_AVAILABLE_IN_ALL -PangoAttrIterator *pango_attr_list_get_iterator (PangoAttrList *list); +PangoAttrIterator * pango_attr_list_get_iterator (PangoAttrList *list); PANGO_AVAILABLE_IN_ALL -void pango_attr_iterator_range (PangoAttrIterator *iterator, - gint *start, - gint *end); +void pango_attr_iterator_range (PangoAttrIterator *iterator, + int *start, + int *end); PANGO_AVAILABLE_IN_ALL -gboolean pango_attr_iterator_next (PangoAttrIterator *iterator); +gboolean pango_attr_iterator_next (PangoAttrIterator *iterator); PANGO_AVAILABLE_IN_ALL -PangoAttrIterator *pango_attr_iterator_copy (PangoAttrIterator *iterator); +PangoAttrIterator * pango_attr_iterator_copy (PangoAttrIterator *iterator); PANGO_AVAILABLE_IN_ALL -void pango_attr_iterator_destroy (PangoAttrIterator *iterator); +void pango_attr_iterator_destroy (PangoAttrIterator *iterator); PANGO_AVAILABLE_IN_ALL -PangoAttribute * pango_attr_iterator_get (PangoAttrIterator *iterator, - PangoAttrType type); +PangoAttribute * pango_attr_iterator_get (PangoAttrIterator *iterator, + PangoAttrType type); PANGO_AVAILABLE_IN_ALL -void pango_attr_iterator_get_font (PangoAttrIterator *iterator, - PangoFontDescription *desc, - PangoLanguage **language, - GSList **extra_attrs); +void pango_attr_iterator_get_font (PangoAttrIterator *iterator, + PangoFontDescription *desc, + PangoLanguage **language, + GSList **extra_attrs); PANGO_AVAILABLE_IN_1_2 -GSList * pango_attr_iterator_get_attrs (PangoAttrIterator *iterator); - - -PANGO_AVAILABLE_IN_ALL -gboolean pango_parse_markup (const char *markup_text, - int length, - gunichar accel_marker, - PangoAttrList **attr_list, - char **text, - gunichar *accel_char, - GError **error); - -PANGO_AVAILABLE_IN_1_32 -GMarkupParseContext * pango_markup_parser_new (gunichar accel_marker); -PANGO_AVAILABLE_IN_1_32 -gboolean pango_markup_parser_finish (GMarkupParseContext *context, - PangoAttrList **attr_list, - char **text, - gunichar *accel_char, - GError **error); - -PANGO_AVAILABLE_IN_1_50 -PangoAttrString *pango_attribute_as_string (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrLanguage *pango_attribute_as_language (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrInt *pango_attribute_as_int (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrSize *pango_attribute_as_size (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrFloat *pango_attribute_as_float (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrColor *pango_attribute_as_color (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrFontDesc *pango_attribute_as_font_desc (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrShape *pango_attribute_as_shape (PangoAttribute *attr); -PANGO_AVAILABLE_IN_1_50 -PangoAttrFontFeatures *pango_attribute_as_font_features (PangoAttribute *attr); +GSList * pango_attr_iterator_get_attrs (PangoAttrIterator *iterator); G_END_DECLS diff --git a/pango/pango-break.h b/pango/pango-break.h index 16f3918c..81526e9a 100644 --- a/pango/pango-break.h +++ b/pango/pango-break.h @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -94,45 +94,34 @@ struct _PangoLogAttr }; PANGO_DEPRECATED_IN_1_44 -void pango_break (const gchar *text, - int length, - PangoAnalysis *analysis, - PangoLogAttr *attrs, - int attrs_len); +void pango_break (const char *text, + int length, + PangoAnalysis *analysis, + PangoLogAttr *attrs, + int attrs_len); PANGO_AVAILABLE_IN_ALL -void pango_find_paragraph_boundary (const gchar *text, - gint length, - gint *paragraph_delimiter_index, - gint *next_paragraph_start); +void pango_get_log_attrs (const char *text, + int length, + int level, + PangoLanguage *language, + PangoLogAttr *log_attrs, + int attrs_len); PANGO_AVAILABLE_IN_ALL -void pango_get_log_attrs (const char *text, - int length, - int level, - PangoLanguage *language, - PangoLogAttr *log_attrs, - int attrs_len); - -/* This is the default break algorithm, used if no language - * engine overrides it. Normally you should use pango_break() - * instead; this function is mostly useful for chaining up - * from a language engine override. - */ -PANGO_AVAILABLE_IN_ALL -void pango_default_break (const gchar *text, - int length, - PangoAnalysis *analysis, - PangoLogAttr *attrs, - int attrs_len); +void pango_default_break (const char *text, + int length, + PangoAnalysis *analysis, + PangoLogAttr *attrs, + int attrs_len); PANGO_AVAILABLE_IN_1_44 -void pango_tailor_break (const char *text, - int length, - PangoAnalysis *analysis, - int offset, - PangoLogAttr *log_attrs, - int log_attrs_len); +void pango_tailor_break (const char *text, + int length, + PangoAnalysis *analysis, + int offset, + PangoLogAttr *log_attrs, + int log_attrs_len); G_END_DECLS diff --git a/pango/pango-color.h b/pango/pango-color.h new file mode 100644 index 00000000..675d8e82 --- /dev/null +++ b/pango/pango-color.h @@ -0,0 +1,75 @@ +/* Pango + * pango-color.h: A color struct + * + * 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. + */ + +#ifndef __PANGO_COLOR_H__ +#define __PANGO_COLOR_H__ + +#include <pango/pango-types.h> +#include <glib-object.h> + +G_BEGIN_DECLS + + +typedef struct _PangoColor PangoColor; + +/** + * PangoColor: + * @red: value of red component + * @green: value of green component + * @blue: value of blue component + * + * The `PangoColor` structure is used to + * represent a color in an uncalibrated RGB color-space. + */ +struct _PangoColor +{ + guint16 red; + guint16 green; + guint16 blue; +}; + +#define PANGO_TYPE_COLOR (pango_color_get_type ()) + +PANGO_AVAILABLE_IN_ALL +GType pango_color_get_type (void) G_GNUC_CONST; + +PANGO_AVAILABLE_IN_ALL +PangoColor *pango_color_copy (const PangoColor *src); + +PANGO_AVAILABLE_IN_ALL +void pango_color_free (PangoColor *color); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_color_parse (PangoColor *color, + const char *spec); + +PANGO_AVAILABLE_IN_1_46 +gboolean pango_color_parse_with_alpha (PangoColor *color, + guint16 *alpha, + const char *spec); + +PANGO_AVAILABLE_IN_1_16 +char *pango_color_to_string (const PangoColor *color); + + +G_END_DECLS + +#endif /* __PANGO_COLOR_H__ */ diff --git a/pango/pango-context-private.h b/pango/pango-context-private.h new file mode 100644 index 00000000..240c07d4 --- /dev/null +++ b/pango/pango-context-private.h @@ -0,0 +1,63 @@ +/* Pango + * pango-context-private.h: Internal structures of PangoContext + * + * Copyright (C) 2004 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. + */ + +#ifndef __PANGO_CONTEXT_PRIVATE_H__ +#define __PANGO_CONTEXT_PRIVATE_H__ + +#include <pango/pango-context.h> + +G_BEGIN_DECLS + +struct _PangoContext +{ + GObject parent_instance; + guint serial; + guint fontmap_serial; + + PangoLanguage *set_language; + PangoLanguage *language; + PangoDirection base_dir; + PangoGravity base_gravity; + PangoGravity resolved_gravity; + PangoGravityHint gravity_hint; + + PangoFontDescription *font_desc; + + PangoMatrix *matrix; + + PangoFontMap *font_map; + + PangoFontMetrics *metrics; + + gboolean round_glyph_positions; +}; + +GList * pango_itemize_with_font (PangoContext *context, + const char *text, + int start_index, + int length, + const PangoFontDescription *desc); + + +G_END_DECLS + +#endif /* __PANGO_CONTEXT_PRIVATE_H__ */ + diff --git a/pango/pango-context.c b/pango/pango-context.c index 2cb3304c..d76b0ae2 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "pango-context.h" +#include "pango-context-private.h" #include "pango-impl-utils.h" #include "pango-font-private.h" @@ -44,29 +45,6 @@ * * To obtain a `PangoContext`, use [method@Pango.FontMap.create_context]. */ -struct _PangoContext -{ - GObject parent_instance; - guint serial; - guint fontmap_serial; - - PangoLanguage *set_language; - PangoLanguage *language; - PangoDirection base_dir; - PangoGravity base_gravity; - PangoGravity resolved_gravity; - PangoGravityHint gravity_hint; - - PangoFontDescription *font_desc; - - PangoMatrix *matrix; - - PangoFontMap *font_map; - - PangoFontMetrics *metrics; - - gboolean round_glyph_positions; -}; struct _PangoContextClass { @@ -595,1133 +573,6 @@ pango_context_get_gravity_hint (PangoContext *context) return context->gravity_hint; } -/**********************************************************************/ - -static gboolean -advance_attr_iterator_to (PangoAttrIterator *iterator, - int start_index) -{ - int start_range, end_range; - - pango_attr_iterator_range (iterator, &start_range, &end_range); - - while (start_index >= end_range) - { - if (!pango_attr_iterator_next (iterator)) - return FALSE; - pango_attr_iterator_range (iterator, &start_range, &end_range); - } - - if (start_range > start_index) - g_warning ("In pango_itemize(), the cached iterator passed in " - "had already moved beyond the start_index"); - - return TRUE; -} - -/*************************************************************************** - * We cache the results of character,fontset => font in a hash table - ***************************************************************************/ - -typedef struct { - GHashTable *hash; -} FontCache; - -typedef struct { - PangoFont *font; - int position; /* position of the font in the fontset */ -} FontElement; - -static void -font_cache_destroy (FontCache *cache) -{ - g_hash_table_destroy (cache->hash); - g_slice_free (FontCache, cache); -} - -static void -font_element_destroy (FontElement *element) -{ - if (element->font) - g_object_unref (element->font); - g_slice_free (FontElement, element); -} - -static FontCache * -get_font_cache (PangoFontset *fontset) -{ - FontCache *cache; - - static GQuark cache_quark = 0; /* MT-safe */ - if (G_UNLIKELY (!cache_quark)) - cache_quark = g_quark_from_static_string ("pango-font-cache"); - -retry: - cache = g_object_get_qdata (G_OBJECT (fontset), cache_quark); - if (G_UNLIKELY (!cache)) - { - cache = g_slice_new (FontCache); - cache->hash = g_hash_table_new_full (g_direct_hash, NULL, - NULL, (GDestroyNotify)font_element_destroy); - if (!g_object_replace_qdata (G_OBJECT (fontset), cache_quark, NULL, - cache, (GDestroyNotify)font_cache_destroy, - NULL)) - { - font_cache_destroy (cache); - goto retry; - } - } - - return cache; -} - -static gboolean -font_cache_get (FontCache *cache, - gunichar wc, - PangoFont **font, - int *position) -{ - FontElement *element; - - element = g_hash_table_lookup (cache->hash, GUINT_TO_POINTER (wc)); - if (element) - { - *font = element->font; - *position = element->position; - return TRUE; - } - else - return FALSE; -} - -static void -font_cache_insert (FontCache *cache, - gunichar wc, - PangoFont *font, - int position) -{ - FontElement *element = g_slice_new (FontElement); - element->font = font ? g_object_ref (font) : NULL; - element->position = position; - - g_hash_table_insert (cache->hash, GUINT_TO_POINTER (wc), element); -} - -/**********************************************************************/ - -typedef enum { - EMBEDDING_CHANGED = 1 << 0, - SCRIPT_CHANGED = 1 << 1, - LANG_CHANGED = 1 << 2, - FONT_CHANGED = 1 << 3, - DERIVED_LANG_CHANGED = 1 << 4, - WIDTH_CHANGED = 1 << 5, - EMOJI_CHANGED = 1 << 6, -} ChangedFlags; - - - -typedef struct _PangoWidthIter PangoWidthIter; - -struct _PangoWidthIter -{ - const gchar *text_start; - const gchar *text_end; - const gchar *start; - const gchar *end; - gboolean upright; -}; - -typedef struct _ItemizeState ItemizeState; - - - -struct _ItemizeState -{ - PangoContext *context; - const char *text; - const char *end; - - const char *run_start; - const char *run_end; - - GList *result; - PangoItem *item; - - guint8 *embedding_levels; - int embedding_end_offset; - const char *embedding_end; - guint8 embedding; - - PangoGravity gravity; - PangoGravityHint gravity_hint; - PangoGravity resolved_gravity; - PangoGravity font_desc_gravity; - gboolean centered_baseline; - - PangoAttrIterator *attr_iter; - gboolean free_attr_iter; - const char *attr_end; - PangoFontDescription *font_desc; - PangoFontDescription *emoji_font_desc; - PangoLanguage *lang; - GSList *extra_attrs; - gboolean copy_extra_attrs; - - ChangedFlags changed; - - PangoScriptIter script_iter; - const char *script_end; - PangoScript script; - - PangoWidthIter width_iter; - PangoEmojiIter emoji_iter; - - PangoLanguage *derived_lang; - - PangoFontset *current_fonts; - FontCache *cache; - PangoFont *base_font; - gboolean enable_fallback; - - const char *first_space; /* first of a sequence of spaces we've seen */ - int font_position; /* position of the current font in the fontset */ -}; - -static void -update_embedding_end (ItemizeState *state) -{ - state->embedding = state->embedding_levels[state->embedding_end_offset]; - while (state->embedding_end < state->end && - state->embedding_levels[state->embedding_end_offset] == state->embedding) - { - state->embedding_end_offset++; - state->embedding_end = g_utf8_next_char (state->embedding_end); - } - - state->changed |= EMBEDDING_CHANGED; -} - -static PangoAttribute * -find_attribute (GSList *attr_list, - PangoAttrType type) -{ - GSList *node; - - for (node = attr_list; node; node = node->next) - if (((PangoAttribute *) node->data)->klass->type == type) - return (PangoAttribute *) node->data; - - return NULL; -} - -static void -update_attr_iterator (ItemizeState *state) -{ - PangoLanguage *old_lang; - PangoAttribute *attr; - int end_index; - - pango_attr_iterator_range (state->attr_iter, NULL, &end_index); - if (end_index < state->end - state->text) - state->attr_end = state->text + end_index; - else - state->attr_end = state->end; - - if (state->emoji_font_desc) - { - pango_font_description_free (state->emoji_font_desc); - state->emoji_font_desc = NULL; - } - - old_lang = state->lang; - if (state->font_desc) - pango_font_description_free (state->font_desc); - state->font_desc = pango_font_description_copy_static (state->context->font_desc); - pango_attr_iterator_get_font (state->attr_iter, state->font_desc, - &state->lang, &state->extra_attrs); - if (pango_font_description_get_set_fields (state->font_desc) & PANGO_FONT_MASK_GRAVITY) - state->font_desc_gravity = pango_font_description_get_gravity (state->font_desc); - else - state->font_desc_gravity = PANGO_GRAVITY_AUTO; - - state->copy_extra_attrs = FALSE; - - if (!state->lang) - state->lang = state->context->language; - - attr = find_attribute (state->extra_attrs, PANGO_ATTR_FALLBACK); - state->enable_fallback = (attr == NULL || ((PangoAttrInt *)attr)->value); - - attr = find_attribute (state->extra_attrs, PANGO_ATTR_GRAVITY); - state->gravity = attr == NULL ? PANGO_GRAVITY_AUTO : ((PangoAttrInt *)attr)->value; - - attr = find_attribute (state->extra_attrs, PANGO_ATTR_GRAVITY_HINT); - state->gravity_hint = attr == NULL ? state->context->gravity_hint : (PangoGravityHint)((PangoAttrInt *)attr)->value; - - state->changed |= FONT_CHANGED; - if (state->lang != old_lang) - state->changed |= LANG_CHANGED; -} - -static void -update_end (ItemizeState *state) -{ - state->run_end = state->embedding_end; - if (state->attr_end < state->run_end) - state->run_end = state->attr_end; - if (state->script_end < state->run_end) - state->run_end = state->script_end; - if (state->width_iter.end < state->run_end) - state->run_end = state->width_iter.end; - if (state->emoji_iter.end < state->run_end) - state->run_end = state->emoji_iter.end; -} - -static gboolean -width_iter_is_upright (gunichar ch) -{ - /* https://www.unicode.org/Public/11.0.0/ucd/VerticalOrientation.txt - * VO=U or Tu table generated by tools/gen-vertical-orientation-U-table.py. - * - * FIXME: In the future, If GLib supports VerticalOrientation, please use it. - */ - static const gunichar upright[][2] = { - {0x00A7, 0x00A7}, {0x00A9, 0x00A9}, {0x00AE, 0x00AE}, {0x00B1, 0x00B1}, - {0x00BC, 0x00BE}, {0x00D7, 0x00D7}, {0x00F7, 0x00F7}, {0x02EA, 0x02EB}, - {0x1100, 0x11FF}, {0x1401, 0x167F}, {0x18B0, 0x18FF}, {0x2016, 0x2016}, - {0x2020, 0x2021}, {0x2030, 0x2031}, {0x203B, 0x203C}, {0x2042, 0x2042}, - {0x2047, 0x2049}, {0x2051, 0x2051}, {0x2065, 0x2065}, {0x20DD, 0x20E0}, - {0x20E2, 0x20E4}, {0x2100, 0x2101}, {0x2103, 0x2109}, {0x210F, 0x210F}, - {0x2113, 0x2114}, {0x2116, 0x2117}, {0x211E, 0x2123}, {0x2125, 0x2125}, - {0x2127, 0x2127}, {0x2129, 0x2129}, {0x212E, 0x212E}, {0x2135, 0x213F}, - {0x2145, 0x214A}, {0x214C, 0x214D}, {0x214F, 0x2189}, {0x218C, 0x218F}, - {0x221E, 0x221E}, {0x2234, 0x2235}, {0x2300, 0x2307}, {0x230C, 0x231F}, - {0x2324, 0x2328}, {0x232B, 0x232B}, {0x237D, 0x239A}, {0x23BE, 0x23CD}, - {0x23CF, 0x23CF}, {0x23D1, 0x23DB}, {0x23E2, 0x2422}, {0x2424, 0x24FF}, - {0x25A0, 0x2619}, {0x2620, 0x2767}, {0x2776, 0x2793}, {0x2B12, 0x2B2F}, - {0x2B50, 0x2B59}, {0x2BB8, 0x2BD1}, {0x2BD3, 0x2BEB}, {0x2BF0, 0x2BFF}, - {0x2E80, 0x3007}, {0x3012, 0x3013}, {0x3020, 0x302F}, {0x3031, 0x309F}, - {0x30A1, 0x30FB}, {0x30FD, 0xA4CF}, {0xA960, 0xA97F}, {0xAC00, 0xD7FF}, - {0xE000, 0xFAFF}, {0xFE10, 0xFE1F}, {0xFE30, 0xFE48}, {0xFE50, 0xFE57}, - {0xFE5F, 0xFE62}, {0xFE67, 0xFE6F}, {0xFF01, 0xFF07}, {0xFF0A, 0xFF0C}, - {0xFF0E, 0xFF19}, {0xFF1F, 0xFF3A}, {0xFF3C, 0xFF3C}, {0xFF3E, 0xFF3E}, - {0xFF40, 0xFF5A}, {0xFFE0, 0xFFE2}, {0xFFE4, 0xFFE7}, {0xFFF0, 0xFFF8}, - {0xFFFC, 0xFFFD}, {0x10980, 0x1099F}, {0x11580, 0x115FF}, {0x11A00, 0x11AAF}, - {0x13000, 0x1342F}, {0x14400, 0x1467F}, {0x16FE0, 0x18AFF}, {0x1B000, 0x1B12F}, - {0x1B170, 0x1B2FF}, {0x1D000, 0x1D1FF}, {0x1D2E0, 0x1D37F}, {0x1D800, 0x1DAAF}, - {0x1F000, 0x1F7FF}, {0x1F900, 0x1FA6F}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}, - {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD} - }; - static const int max = sizeof(upright) / sizeof(upright[0]); - int st = 0; - int ed = max; - - if (ch < upright[0][0]) - return FALSE; - - while (st <= ed) - { - int mid = (st + ed) / 2; - if (upright[mid][0] <= ch && ch <= upright[mid][1]) - return TRUE; - else - if (upright[mid][0] <= ch) - st = mid + 1; - else - ed = mid - 1; - } - - return FALSE; -} - -static void -width_iter_next (PangoWidthIter *iter) -{ - gboolean met_joiner = FALSE; - iter->start = iter->end; - - if (iter->end < iter->text_end) - { - gunichar ch = g_utf8_get_char (iter->end); - iter->upright = width_iter_is_upright (ch); - } - - while (iter->end < iter->text_end) - { - gunichar ch = g_utf8_get_char (iter->end); - - /* for zero width joiner */ - if (ch == 0x200D) - { - iter->end = g_utf8_next_char (iter->end); - met_joiner = TRUE; - continue; - } - - /* ignore the upright check if met joiner */ - if (met_joiner) - { - iter->end = g_utf8_next_char (iter->end); - met_joiner = FALSE; - continue; - } - - /* for variation selector, tag and emoji modifier. */ - if (G_UNLIKELY (ch == 0xFE0EU || ch == 0xFE0FU || - (ch >= 0xE0020 && ch <= 0xE007F) || - (ch >= 0x1F3FB && ch <= 0x1F3FF))) - { - iter->end = g_utf8_next_char (iter->end); - continue; - } - - if (width_iter_is_upright (ch) != iter->upright) - break; - - iter->end = g_utf8_next_char (iter->end); - } -} - -static void -width_iter_init (PangoWidthIter *iter, - const char *text, - int length) -{ - iter->text_start = text; - iter->text_end = text + length; - iter->start = iter->end = text; - - width_iter_next (iter); -} - -static void -width_iter_fini (PangoWidthIter* iter) -{ -} - -static void -itemize_state_init (ItemizeState *state, - PangoContext *context, - const char *text, - PangoDirection base_dir, - int start_index, - int length, - PangoAttrList *attrs, - PangoAttrIterator *cached_iter, - const PangoFontDescription *desc) -{ - state->context = context; - state->text = text; - state->end = text + start_index + length; - - state->result = NULL; - state->item = NULL; - - state->run_start = text + start_index; - state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | - FONT_CHANGED | WIDTH_CHANGED | EMOJI_CHANGED; - - /* First, apply the bidirectional algorithm to break - * the text into directional runs. - */ - state->embedding_levels = pango_log2vis_get_embedding_levels (text + start_index, length, &base_dir); - - state->embedding_end_offset = 0; - state->embedding_end = text + start_index; - update_embedding_end (state); - - state->gravity = PANGO_GRAVITY_AUTO; - state->centered_baseline = PANGO_GRAVITY_IS_VERTICAL (state->context->resolved_gravity); - state->gravity_hint = state->context->gravity_hint; - state->resolved_gravity = PANGO_GRAVITY_AUTO; - - /* Initialize the attribute iterator - */ - if (cached_iter) - { - state->attr_iter = cached_iter; - state->free_attr_iter = FALSE; - } - else if (attrs) - { - state->attr_iter = pango_attr_list_get_iterator (attrs); - state->free_attr_iter = TRUE; - } - else - { - state->attr_iter = NULL; - state->free_attr_iter = FALSE; - } - - state->emoji_font_desc = NULL; - if (state->attr_iter) - { - state->font_desc = NULL; - state->lang = NULL; - - advance_attr_iterator_to (state->attr_iter, start_index); - update_attr_iterator (state); - } - else - { - state->font_desc = pango_font_description_copy_static (desc ? desc : state->context->font_desc); - state->lang = state->context->language; - state->extra_attrs = NULL; - state->copy_extra_attrs = FALSE; - - state->attr_end = state->end; - state->enable_fallback = TRUE; - } - - /* Initialize the script iterator - */ - _pango_script_iter_init (&state->script_iter, text + start_index, length); - pango_script_iter_get_range (&state->script_iter, NULL, - &state->script_end, &state->script); - - width_iter_init (&state->width_iter, text + start_index, length); - _pango_emoji_iter_init (&state->emoji_iter, text + start_index, length); - - if (!PANGO_GRAVITY_IS_VERTICAL (state->context->resolved_gravity)) - state->width_iter.end = state->end; - else - if (state->emoji_iter.is_emoji) - state->width_iter.end = MAX (state->width_iter.end, state->emoji_iter.end); - - update_end (state); - - if (pango_font_description_get_set_fields (state->font_desc) & PANGO_FONT_MASK_GRAVITY) - state->font_desc_gravity = pango_font_description_get_gravity (state->font_desc); - else - state->font_desc_gravity = PANGO_GRAVITY_AUTO; - - state->derived_lang = NULL; - state->current_fonts = NULL; - state->cache = NULL; - state->base_font = NULL; - state->first_space = NULL; - state->font_position = 0xffff; -} - -static gboolean -itemize_state_next (ItemizeState *state) -{ - if (state->run_end == state->end) - return FALSE; - - state->changed = 0; - - state->run_start = state->run_end; - - if (state->run_end == state->embedding_end) - { - update_embedding_end (state); - } - - if (state->run_end == state->attr_end) - { - pango_attr_iterator_next (state->attr_iter); - update_attr_iterator (state); - } - - if (state->run_end == state->script_end) - { - pango_script_iter_next (&state->script_iter); - pango_script_iter_get_range (&state->script_iter, NULL, - &state->script_end, &state->script); - state->changed |= SCRIPT_CHANGED; - } - if (state->run_end == state->emoji_iter.end) - { - _pango_emoji_iter_next (&state->emoji_iter); - state->changed |= EMOJI_CHANGED; - - if (state->emoji_iter.is_emoji) - state->width_iter.end = MAX (state->width_iter.end, state->emoji_iter.end); - } - if (state->run_end == state->width_iter.end) - { - width_iter_next (&state->width_iter); - state->changed |= WIDTH_CHANGED; - } - - update_end (state); - - return TRUE; -} - -static GSList * -copy_attr_slist (GSList *attr_slist) -{ - GSList *new_list = NULL; - GSList *l; - - for (l = attr_slist; l; l = l->next) - new_list = g_slist_prepend (new_list, pango_attribute_copy (l->data)); - - return g_slist_reverse (new_list); -} - -static void -itemize_state_fill_font (ItemizeState *state, - PangoFont *font) -{ - GList *l; - - for (l = state->result; l; l = l->next) - { - PangoItem *item = l->data; - if (item->analysis.font) - break; - if (font) - item->analysis.font = g_object_ref (font); - } -} - -static void -itemize_state_add_character (ItemizeState *state, - PangoFont *font, - int font_position, - gboolean force_break, - const char *pos, - gboolean is_space) -{ - const char *first_space = state->first_space; - int n_spaces = 0; - - if (is_space) - { - if (state->first_space == NULL) - state->first_space = pos; - } - else - state->first_space = NULL; - - if (state->item) - { - if (!state->item->analysis.font && font) - { - itemize_state_fill_font (state, font); - state->font_position = font_position; - } - else if (state->item->analysis.font && !font) - { - font = state->item->analysis.font; - font_position = state->font_position; - } - - if (!force_break && - state->item->analysis.font == font) - { - state->item->num_chars++; - return; - } - - /* Font is changing, we are about to end the current item. - * If it ended in a sequence of spaces (but wasn't only spaces), - * check if we should move those spaces to the new item (since - * the font is less "fallback". - * - * See https://gitlab.gnome.org/GNOME/pango/-/issues/249 - */ - if (state->text + state->item->offset < first_space && - font_position < state->font_position) - { - n_spaces = g_utf8_strlen (first_space, pos - first_space); - state->item->num_chars -= n_spaces; - pos = first_space; - } - - state->item->length = (pos - state->text) - state->item->offset; - } - - state->item = pango_item_new (); - state->item->offset = pos - state->text; - state->item->length = 0; - state->item->num_chars = n_spaces + 1; - - if (font) - g_object_ref (font); - state->item->analysis.font = font; - state->font_position = font_position; - - state->item->analysis.level = state->embedding; - state->item->analysis.gravity = state->resolved_gravity; - - /* The level vs. gravity dance: - * - If gravity is SOUTH, leave level untouched. - * - If gravity is NORTH, step level one up, to - * not get mirrored upside-down text. - * - If gravity is EAST, step up to an even level, as - * it's a clockwise-rotated layout, so the rotated - * top is unrotated left. - * - If gravity is WEST, step up to an odd level, as - * it's a counter-clockwise-rotated layout, so the rotated - * top is unrotated right. - * - * A similar dance is performed in pango-layout.c: - * line_set_resolved_dir(). Keep in synch. - */ - switch (state->item->analysis.gravity) - { - case PANGO_GRAVITY_SOUTH: - default: - break; - case PANGO_GRAVITY_NORTH: - state->item->analysis.level++; - break; - case PANGO_GRAVITY_EAST: - state->item->analysis.level += 1; - state->item->analysis.level &= ~1; - break; - case PANGO_GRAVITY_WEST: - state->item->analysis.level |= 1; - break; - } - - state->item->analysis.flags = state->centered_baseline ? PANGO_ANALYSIS_FLAG_CENTERED_BASELINE : 0; - - state->item->analysis.script = state->script; - state->item->analysis.language = state->derived_lang; - - if (state->copy_extra_attrs) - { - state->item->analysis.extra_attrs = copy_attr_slist (state->extra_attrs); - } - else - { - state->item->analysis.extra_attrs = state->extra_attrs; - state->copy_extra_attrs = TRUE; - } - - state->result = g_list_prepend (state->result, state->item); -} - -typedef struct { - PangoLanguage *lang; - gunichar wc; - PangoFont *font; - int position; -} GetFontInfo; - -static gboolean -get_font_foreach (PangoFontset *fontset, - PangoFont *font, - gpointer data) -{ - GetFontInfo *info = data; - - if (G_UNLIKELY (!font)) - return FALSE; - - if (pango_font_has_char (font, info->wc)) - { - info->font = font; - return TRUE; - } - - if (!fontset) - { - info->font = font; - return TRUE; - } - - info->position++; - - return FALSE; -} - -static PangoFont * -get_base_font (ItemizeState *state) -{ - if (!state->base_font) - state->base_font = pango_font_map_load_font (state->context->font_map, - state->context, - state->font_desc); - return state->base_font; -} - -static gboolean -get_font (ItemizeState *state, - gunichar wc, - PangoFont **font, - int *position) -{ - GetFontInfo info; - - /* We'd need a separate cache when fallback is disabled, but since lookup - * with fallback disabled is faster anyways, we just skip caching */ - if (state->enable_fallback && font_cache_get (state->cache, wc, font, position)) - return TRUE; - - info.lang = state->derived_lang; - info.wc = wc; - info.font = NULL; - info.position = 0; - - if (state->enable_fallback) - pango_fontset_foreach (state->current_fonts, get_font_foreach, &info); - else - get_font_foreach (NULL, get_base_font (state), &info); - - *font = info.font; - *position = info.position; - - /* skip caching if fallback disabled (see above) */ - if (state->enable_fallback) - font_cache_insert (state->cache, wc, *font, *position); - - return TRUE; -} - -static PangoLanguage * -compute_derived_language (PangoLanguage *lang, - PangoScript script) -{ - PangoLanguage *derived_lang; - - /* Make sure the language tag is consistent with the derived - * script. There is no point in marking up a section of - * Arabic text with the "en" language tag. - */ - if (lang && pango_language_includes_script (lang, script)) - derived_lang = lang; - else - { - derived_lang = pango_script_get_sample_language (script); - /* If we don't find a sample language for the script, we - * use a language tag that shouldn't actually be used - * anywhere. This keeps fontconfig (for the PangoFc* - * backend) from using the language tag to affect the - * sort order. I don't have a reference for 'xx' being - * safe here, though Keith Packard claims it is. - */ - if (!derived_lang) - derived_lang = pango_language_from_string ("xx"); - } - - return derived_lang; -} - -static void -itemize_state_update_for_new_run (ItemizeState *state) -{ - /* This block should be moved to update_attr_iterator, but I'm too lazy to - * do it right now */ - if (state->changed & (FONT_CHANGED | SCRIPT_CHANGED | WIDTH_CHANGED)) - { - /* Font-desc gravity overrides everything */ - if (state->font_desc_gravity != PANGO_GRAVITY_AUTO) - { - state->resolved_gravity = state->font_desc_gravity; - } - else - { - PangoGravity gravity = state->gravity; - PangoGravityHint gravity_hint = state->gravity_hint; - - if (G_LIKELY (gravity == PANGO_GRAVITY_AUTO)) - gravity = state->context->resolved_gravity; - - state->resolved_gravity = pango_gravity_get_for_script_and_width (state->script, - state->width_iter.upright, - gravity, - gravity_hint); - } - - if (state->font_desc_gravity != state->resolved_gravity) - { - pango_font_description_set_gravity (state->font_desc, state->resolved_gravity); - state->changed |= FONT_CHANGED; - } - } - - if (state->changed & (SCRIPT_CHANGED | LANG_CHANGED)) - { - PangoLanguage *old_derived_lang = state->derived_lang; - state->derived_lang = compute_derived_language (state->lang, state->script); - if (old_derived_lang != state->derived_lang) - state->changed |= DERIVED_LANG_CHANGED; - } - - if (state->changed & (EMOJI_CHANGED)) - { - state->changed |= FONT_CHANGED; - } - - if (state->changed & (FONT_CHANGED | DERIVED_LANG_CHANGED) && - state->current_fonts) - { - g_object_unref (state->current_fonts); - state->current_fonts = NULL; - state->cache = NULL; - } - - if (!state->current_fonts) - { - gboolean is_emoji = state->emoji_iter.is_emoji; - if (is_emoji && !state->emoji_font_desc) - { - state->emoji_font_desc = pango_font_description_copy_static (state->font_desc); - pango_font_description_set_family_static (state->emoji_font_desc, "emoji"); - } - state->current_fonts = pango_font_map_load_fontset (state->context->font_map, - state->context, - is_emoji ? state->emoji_font_desc : state->font_desc, - state->derived_lang); - state->cache = get_font_cache (state->current_fonts); - } - - if ((state->changed & FONT_CHANGED) && state->base_font) - { - g_object_unref (state->base_font); - state->base_font = NULL; - } -} - -static void -itemize_state_process_run (ItemizeState *state) -{ - const char *p; - gboolean last_was_forced_break = FALSE; - gboolean is_space; - - /* Only one character has type G_UNICODE_LINE_SEPARATOR in Unicode 4.0; - * update this if that changes. */ -#define LINE_SEPARATOR 0x2028 - - itemize_state_update_for_new_run (state); - - /* We should never get an empty run */ - g_assert (state->run_end != state->run_start); - - for (p = state->run_start; - p < state->run_end; - p = g_utf8_next_char (p)) - { - gunichar wc = g_utf8_get_char (p); - 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))) - { - font = NULL; - font_position = 0xffff; - is_space = TRUE; - } - else - { - get_font (state, wc, &font, &font_position); - is_space = FALSE; - } - - itemize_state_add_character (state, font, font_position, - is_forced_break || last_was_forced_break, - p, - is_space); - - last_was_forced_break = is_forced_break; - } - - /* Finish the final item from the current segment */ - state->item->length = (p - state->text) - state->item->offset; - if (!state->item->analysis.font) - { - PangoFont *font; - int position; - - if (G_UNLIKELY (!get_font (state, ' ', &font, &position))) - { - /* If no font was found, warn once per fontmap/script pair */ - PangoFontMap *fontmap = state->context->font_map; - char *script_tag = g_strdup_printf ("g-unicode-script-%d", state->script); - - if (!g_object_get_data (G_OBJECT (fontmap), script_tag)) - { - g_warning ("failed to choose a font, expect ugly output. script='%d'", - state->script); - - g_object_set_data_full (G_OBJECT (fontmap), script_tag, - GINT_TO_POINTER (1), NULL); - } - - g_free (script_tag); - - font = NULL; - } - itemize_state_fill_font (state, font); - } - state->item = NULL; -} - -static void -itemize_state_finish (ItemizeState *state) -{ - g_free (state->embedding_levels); - if (state->free_attr_iter) - pango_attr_iterator_destroy (state->attr_iter); - _pango_script_iter_fini (&state->script_iter); - pango_font_description_free (state->font_desc); - pango_font_description_free (state->emoji_font_desc); - width_iter_fini (&state->width_iter); - _pango_emoji_iter_fini (&state->emoji_iter); - - if (state->current_fonts) - g_object_unref (state->current_fonts); - if (state->base_font) - g_object_unref (state->base_font); -} - -/** - * pango_itemize_with_base_dir: - * @context: a structure holding information that affects - * the itemization process. - * @base_dir: base direction to use for bidirectional processing - * @text: the text to itemize. - * @start_index: first byte in @text to process - * @length: the number of bytes (not characters) to process - * after @start_index. This must be >= 0. - * @attrs: the set of attributes that apply to @text. - * @cached_iter: (nullable): Cached attribute iterator - * - * Like `pango_itemize()`, but with an explicitly specified base direction. - * - * The base direction is used when computing bidirectional levels. - * (see [method@Pango.Context.set_base_dir]). [func@itemize] gets the - * base direction from the `PangoContext`. - * - * Return value: (transfer full) (element-type Pango.Item): a `GList` of - * [struct@Pango.Item] structures. The items should be freed using - * [method@Pango.Item.free] probably in combination with g_list_free_full(). - * - * Since: 1.4 - */ -GList * -pango_itemize_with_base_dir (PangoContext *context, - PangoDirection base_dir, - const char *text, - int start_index, - int length, - PangoAttrList *attrs, - PangoAttrIterator *cached_iter) -{ - ItemizeState state; - - 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); - - if (length == 0 || g_utf8_get_char (text + start_index) == '\0') - return NULL; - - itemize_state_init (&state, context, text, base_dir, start_index, length, - attrs, cached_iter, NULL); - - do - itemize_state_process_run (&state); - while (itemize_state_next (&state)); - - itemize_state_finish (&state); - - return g_list_reverse (state.result); -} - -static GList * -itemize_with_font (PangoContext *context, - const char *text, - int start_index, - int length, - const PangoFontDescription *desc) -{ - ItemizeState state; - - if (length == 0) - return NULL; - - itemize_state_init (&state, context, text, context->base_dir, start_index, length, - NULL, NULL, desc); - - do - itemize_state_process_run (&state); - while (itemize_state_next (&state)); - - itemize_state_finish (&state); - - return g_list_reverse (state.result); -} - -/** - * pango_itemize: - * @context: a structure holding information that affects - * the itemization process. - * @text: the text to itemize. Must be valid UTF-8 - * @start_index: first byte in @text to process - * @length: the number of bytes (not characters) to process - * after @start_index. This must be >= 0. - * @attrs: the set of attributes that apply to @text. - * @cached_iter: (nullable): Cached attribute iterator - * - * Breaks a piece of text into segments with consistent directional - * level and font. - * - * Each byte of @text will be contained in exactly one of the items in the - * returned list; the generated list of items will be in logical order (the - * start offsets of the items are ascending). - * - * @cached_iter should be an iterator over @attrs currently positioned - * at a range before or containing @start_index; @cached_iter will be - * advanced to the range covering the position just after - * @start_index + @length. (i.e. if itemizing in a loop, just keep passing - * in the same @cached_iter). - * - * Return value: (transfer full) (element-type Pango.Item): a `GList` of - * [struct@Pango.Item] structures. The items should be freed using - * [method@Pango.Item.free] probably in combination with g_list_free_full(). - */ -GList * -pango_itemize (PangoContext *context, - const char *text, - int start_index, - int length, - PangoAttrList *attrs, - PangoAttrIterator *cached_iter) -{ - 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_base_dir (context, context->base_dir, - text, start_index, length, attrs, cached_iter); -} static gboolean get_first_metrics_foreach (PangoFontset *fontset, @@ -1861,7 +712,7 @@ pango_context_get_metrics (PangoContext *context, sample_str = pango_language_get_sample_string (language); text_len = strlen (sample_str); - items = itemize_with_font (context, sample_str, 0, text_len, desc); + items = pango_itemize_with_font (context, sample_str, 0, text_len, desc); update_metrics_from_items (metrics, language, sample_str, text_len, items); diff --git a/pango/pango-context.h b/pango/pango-context.h index b44bd623..3ad63f80 100644 --- a/pango/pango-context.h +++ b/pango/pango-context.h @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -22,6 +22,7 @@ #ifndef __PANGO_CONTEXT_H__ #define __PANGO_CONTEXT_H__ +#include <pango/pango-types.h> #include <pango/pango-font.h> #include <pango/pango-fontmap.h> #include <pango/pango-attributes.h> @@ -29,11 +30,6 @@ G_BEGIN_DECLS -/* Sort of like a GC - application set information about how - * to handle scripts - */ - -/* PangoContext typedefed in pango-fontmap.h */ typedef struct _PangoContextClass PangoContextClass; #define PANGO_TYPE_CONTEXT (pango_context_get_type ()) @@ -44,96 +40,76 @@ typedef struct _PangoContextClass PangoContextClass; #define PANGO_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_CONTEXT, PangoContextClass)) -/* The PangoContext and PangoContextClass structs are private; if you - * need to create a subclass of these, file a bug. - */ - PANGO_AVAILABLE_IN_ALL -GType pango_context_get_type (void) G_GNUC_CONST; +GType pango_context_get_type (void) G_GNUC_CONST; PANGO_AVAILABLE_IN_ALL -PangoContext *pango_context_new (void); +PangoContext * pango_context_new (void); PANGO_AVAILABLE_IN_1_32 -void pango_context_changed (PangoContext *context); +void pango_context_changed (PangoContext *context); PANGO_AVAILABLE_IN_ALL -void pango_context_set_font_map (PangoContext *context, - PangoFontMap *font_map); +void pango_context_set_font_map (PangoContext *context, + PangoFontMap *font_map); PANGO_AVAILABLE_IN_1_6 -PangoFontMap *pango_context_get_font_map (PangoContext *context); +PangoFontMap * pango_context_get_font_map (PangoContext *context); PANGO_AVAILABLE_IN_1_32 -guint pango_context_get_serial (PangoContext *context); +guint pango_context_get_serial (PangoContext *context); PANGO_AVAILABLE_IN_ALL -void pango_context_list_families (PangoContext *context, - PangoFontFamily ***families, - int *n_families); +void pango_context_list_families (PangoContext *context, + PangoFontFamily ***families, + int *n_families); PANGO_AVAILABLE_IN_ALL -PangoFont * pango_context_load_font (PangoContext *context, - const PangoFontDescription *desc); +PangoFont * pango_context_load_font (PangoContext *context, + const PangoFontDescription *desc); PANGO_AVAILABLE_IN_ALL -PangoFontset *pango_context_load_fontset (PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language); +PangoFontset * pango_context_load_fontset (PangoContext *context, + const PangoFontDescription *desc, + PangoLanguage *language); PANGO_AVAILABLE_IN_ALL -PangoFontMetrics *pango_context_get_metrics (PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language); +PangoFontMetrics * pango_context_get_metrics (PangoContext *context, + const PangoFontDescription *desc, + PangoLanguage *language); PANGO_AVAILABLE_IN_ALL -void pango_context_set_font_description (PangoContext *context, - const PangoFontDescription *desc); +void pango_context_set_font_description (PangoContext *context, + const PangoFontDescription *desc); PANGO_AVAILABLE_IN_ALL -PangoFontDescription * pango_context_get_font_description (PangoContext *context); +PangoFontDescription * pango_context_get_font_description (PangoContext *context); PANGO_AVAILABLE_IN_ALL -PangoLanguage *pango_context_get_language (PangoContext *context); +PangoLanguage * pango_context_get_language (PangoContext *context); PANGO_AVAILABLE_IN_ALL -void pango_context_set_language (PangoContext *context, - PangoLanguage *language); +void pango_context_set_language (PangoContext *context, + PangoLanguage *language); PANGO_AVAILABLE_IN_ALL -void pango_context_set_base_dir (PangoContext *context, - PangoDirection direction); +void pango_context_set_base_dir (PangoContext *context, + PangoDirection direction); PANGO_AVAILABLE_IN_ALL -PangoDirection pango_context_get_base_dir (PangoContext *context); +PangoDirection pango_context_get_base_dir (PangoContext *context); PANGO_AVAILABLE_IN_1_16 -void pango_context_set_base_gravity (PangoContext *context, - PangoGravity gravity); +void pango_context_set_base_gravity (PangoContext *context, + PangoGravity gravity); PANGO_AVAILABLE_IN_1_16 -PangoGravity pango_context_get_base_gravity (PangoContext *context); +PangoGravity pango_context_get_base_gravity (PangoContext *context); PANGO_AVAILABLE_IN_1_16 -PangoGravity pango_context_get_gravity (PangoContext *context); +PangoGravity pango_context_get_gravity (PangoContext *context); PANGO_AVAILABLE_IN_1_16 -void pango_context_set_gravity_hint (PangoContext *context, - PangoGravityHint hint); +void pango_context_set_gravity_hint (PangoContext *context, + PangoGravityHint hint); PANGO_AVAILABLE_IN_1_16 -PangoGravityHint pango_context_get_gravity_hint (PangoContext *context); +PangoGravityHint pango_context_get_gravity_hint (PangoContext *context); PANGO_AVAILABLE_IN_1_6 -void pango_context_set_matrix (PangoContext *context, - const PangoMatrix *matrix); +void pango_context_set_matrix (PangoContext *context, + const PangoMatrix *matrix); PANGO_AVAILABLE_IN_1_6 -const PangoMatrix * pango_context_get_matrix (PangoContext *context); +const PangoMatrix * pango_context_get_matrix (PangoContext *context); PANGO_AVAILABLE_IN_1_44 -void pango_context_set_round_glyph_positions (PangoContext *context, - gboolean round_positions); +void pango_context_set_round_glyph_positions (PangoContext *context, + gboolean round_positions); PANGO_AVAILABLE_IN_1_44 -gboolean pango_context_get_round_glyph_positions (PangoContext *context); - -PANGO_AVAILABLE_IN_ALL -GList *pango_itemize (PangoContext *context, - const char *text, - int start_index, - int length, - PangoAttrList *attrs, - PangoAttrIterator *cached_iter); -PANGO_AVAILABLE_IN_1_4 -GList *pango_itemize_with_base_dir (PangoContext *context, - PangoDirection base_dir, - const char *text, - int start_index, - int length, - PangoAttrList *attrs, - PangoAttrIterator *cached_iter); +gboolean pango_context_get_round_glyph_positions (PangoContext *context); G_END_DECLS diff --git a/pango/pango-fontmap.h b/pango/pango-fontmap.h index aec18eeb..0e0edd43 100644 --- a/pango/pango-fontmap.h +++ b/pango/pango-fontmap.h @@ -22,6 +22,7 @@ #ifndef __PANGO_FONTMAP_H__ #define __PANGO_FONTMAP_H__ +#include <pango/pango-types.h> #include <pango/pango-font.h> #include <pango/pango-fontset.h> @@ -35,7 +36,6 @@ G_BEGIN_DECLS #define PANGO_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FONT_MAP, PangoFontMapClass)) typedef struct _PangoFontMapClass PangoFontMapClass; -typedef struct _PangoContext PangoContext; /** * PangoFontMap: diff --git a/pango/pango-glyph.h b/pango/pango-glyph.h index 67302bfd..ae1f5fd7 100644 --- a/pango/pango-glyph.h +++ b/pango/pango-glyph.h @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -120,83 +120,72 @@ struct _PangoGlyphInfo * which simplifies memory management. */ struct _PangoGlyphString { - gint num_glyphs; + int num_glyphs; PangoGlyphInfo *glyphs; - gint *log_clusters; + int *log_clusters; /*< private >*/ - gint space; + int space; }; #define PANGO_TYPE_GLYPH_STRING (pango_glyph_string_get_type ()) PANGO_AVAILABLE_IN_ALL -PangoGlyphString *pango_glyph_string_new (void); +GType pango_glyph_string_get_type (void) G_GNUC_CONST; + PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_set_size (PangoGlyphString *string, - gint new_len); +PangoGlyphString * pango_glyph_string_new (void); PANGO_AVAILABLE_IN_ALL -GType pango_glyph_string_get_type (void) G_GNUC_CONST; +void pango_glyph_string_set_size (PangoGlyphString *string, + int new_len); + PANGO_AVAILABLE_IN_ALL -PangoGlyphString *pango_glyph_string_copy (PangoGlyphString *string); +PangoGlyphString * pango_glyph_string_copy (PangoGlyphString *string); PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_free (PangoGlyphString *string); +void pango_glyph_string_free (PangoGlyphString *string); + PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_extents (PangoGlyphString *glyphs, - PangoFont *font, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); +void pango_glyph_string_extents (PangoGlyphString *glyphs, + PangoFont *font, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); PANGO_AVAILABLE_IN_1_14 -int pango_glyph_string_get_width(PangoGlyphString *glyphs); +int pango_glyph_string_get_width (PangoGlyphString *glyphs); PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_extents_range (PangoGlyphString *glyphs, - int start, - int end, - PangoFont *font, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); +void pango_glyph_string_extents_range (PangoGlyphString *glyphs, + int start, + int end, + PangoFont *font, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_get_logical_widths (PangoGlyphString *glyphs, - const char *text, - int length, - int embedding_level, - int *logical_widths); +void pango_glyph_string_get_logical_widths (PangoGlyphString *glyphs, + const char *text, + int length, + int embedding_level, + int *logical_widths); PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_index_to_x (PangoGlyphString *glyphs, - const char *text, - int length, - PangoAnalysis *analysis, - int index_, - gboolean trailing, - int *x_pos); +void pango_glyph_string_index_to_x (PangoGlyphString *glyphs, + const char *text, + int length, + PangoAnalysis *analysis, + int index_, + gboolean trailing, + int *x_pos); PANGO_AVAILABLE_IN_ALL -void pango_glyph_string_x_to_index (PangoGlyphString *glyphs, - const char *text, - int length, - PangoAnalysis *analysis, - int x_pos, - int *index_, - int *trailing); - -/* Turn a string of characters into a string of glyphs - */ -PANGO_AVAILABLE_IN_ALL -void pango_shape (const char *text, - int length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs); +void pango_glyph_string_x_to_index (PangoGlyphString *glyphs, + const char *text, + int length, + PangoAnalysis *analysis, + int x_pos, + int *index_, + int *trailing); -PANGO_AVAILABLE_IN_1_32 -void pango_shape_full (const char *item_text, - int item_length, - const char *paragraph_text, - int paragraph_length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs); +/* Shaping */ /** * PangoShapeFlags: @@ -215,17 +204,29 @@ typedef enum { PANGO_SHAPE_ROUND_POSITIONS = 1 << 0, } PangoShapeFlags; +PANGO_AVAILABLE_IN_ALL +void pango_shape (const char *text, + int length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs); + +PANGO_AVAILABLE_IN_1_32 +void pango_shape_full (const char *item_text, + int item_length, + const char *paragraph_text, + int paragraph_length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs); + PANGO_AVAILABLE_IN_1_44 -void pango_shape_with_flags (const char *item_text, - int item_length, - const char *paragraph_text, - int paragraph_length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs, - PangoShapeFlags flags); +void pango_shape_with_flags (const char *item_text, + int item_length, + const char *paragraph_text, + int paragraph_length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs, + PangoShapeFlags flags); -PANGO_AVAILABLE_IN_ALL -GList *pango_reorder_items (GList *logical_items); G_END_DECLS diff --git a/pango/pango-item.h b/pango/pango-item.h index a1e95086..9e0596f2 100644 --- a/pango/pango-item.h +++ b/pango/pango-item.h @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -118,21 +118,46 @@ struct _PangoItem #define PANGO_TYPE_ITEM (pango_item_get_type ()) PANGO_AVAILABLE_IN_ALL -GType pango_item_get_type (void) G_GNUC_CONST; +GType pango_item_get_type (void) G_GNUC_CONST; PANGO_AVAILABLE_IN_ALL -PangoItem *pango_item_new (void); +PangoItem * pango_item_new (void); PANGO_AVAILABLE_IN_ALL -PangoItem *pango_item_copy (PangoItem *item); +PangoItem * pango_item_copy (PangoItem *item); PANGO_AVAILABLE_IN_ALL -void pango_item_free (PangoItem *item); +void pango_item_free (PangoItem *item); + PANGO_AVAILABLE_IN_ALL -PangoItem *pango_item_split (PangoItem *orig, - int split_index, - int split_offset); +PangoItem * pango_item_split (PangoItem *orig, + int split_index, + int split_offset); + PANGO_AVAILABLE_IN_1_44 -void pango_item_apply_attrs (PangoItem *item, - PangoAttrIterator *iter); +void pango_item_apply_attrs (PangoItem *item, + PangoAttrIterator *iter); + +PANGO_AVAILABLE_IN_ALL +GList * pango_reorder_items (GList *items); + +/* Itemization */ + +PANGO_AVAILABLE_IN_ALL +GList * pango_itemize (PangoContext *context, + const char *text, + int start_index, + int length, + PangoAttrList *attrs, + PangoAttrIterator *cached_iter); + +PANGO_AVAILABLE_IN_1_4 +GList * pango_itemize_with_base_dir (PangoContext *context, + PangoDirection base_dir, + const char *text, + int start_index, + int length, + PangoAttrList *attrs, + PangoAttrIterator *cached_iter); + G_END_DECLS diff --git a/pango/pango-language.h b/pango/pango-language.h index b000c5b8..a71316dd 100644 --- a/pango/pango-language.h +++ b/pango/pango-language.h @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -25,44 +25,45 @@ #include <glib.h> #include <glib-object.h> +#include <pango/pango-types.h> #include <pango/pango-version-macros.h> +#include <pango/pango-script.h> G_BEGIN_DECLS -typedef struct _PangoLanguage PangoLanguage; - #define PANGO_TYPE_LANGUAGE (pango_language_get_type ()) PANGO_AVAILABLE_IN_ALL -GType pango_language_get_type (void) G_GNUC_CONST; +GType pango_language_get_type (void) G_GNUC_CONST; + +PANGO_AVAILABLE_IN_1_16 +PangoLanguage * pango_language_get_default (void) G_GNUC_CONST; + +PANGO_AVAILABLE_IN_1_48 +PangoLanguage ** pango_language_get_preferred (void) G_GNUC_CONST; + PANGO_AVAILABLE_IN_ALL -PangoLanguage *pango_language_from_string (const char *language); +PangoLanguage * pango_language_from_string (const char *language); PANGO_AVAILABLE_IN_ALL -const char *pango_language_to_string (PangoLanguage *language) G_GNUC_CONST; +const char * pango_language_to_string (PangoLanguage *language) G_GNUC_CONST; + /* For back compat. Will have to keep indefinitely. */ #define pango_language_to_string(language) ((const char *)language) PANGO_AVAILABLE_IN_ALL -const char *pango_language_get_sample_string (PangoLanguage *language) G_GNUC_CONST; -PANGO_AVAILABLE_IN_1_16 -PangoLanguage *pango_language_get_default (void) G_GNUC_CONST; - -PANGO_AVAILABLE_IN_1_48 -PangoLanguage **pango_language_get_preferred (void) G_GNUC_CONST; +const char * pango_language_get_sample_string (PangoLanguage *language) G_GNUC_CONST; PANGO_AVAILABLE_IN_ALL -gboolean pango_language_matches (PangoLanguage *language, - const char *range_list) G_GNUC_PURE; - -#include <pango/pango-script.h> +gboolean pango_language_matches (PangoLanguage *language, + const char *range_list) G_GNUC_PURE; PANGO_AVAILABLE_IN_1_4 -gboolean pango_language_includes_script (PangoLanguage *language, - PangoScript script) G_GNUC_PURE; +gboolean pango_language_includes_script (PangoLanguage *language, + PangoScript script) G_GNUC_PURE; PANGO_AVAILABLE_IN_1_22 -const PangoScript *pango_language_get_scripts (PangoLanguage *language, - int *num_scripts); +const PangoScript * pango_language_get_scripts (PangoLanguage *language, + int *num_scripts); G_END_DECLS diff --git a/pango/pango-markup.c b/pango/pango-markup.c index d4421711..a897a52d 100644 --- a/pango/pango-markup.c +++ b/pango/pango-markup.c @@ -24,6 +24,8 @@ #include <stdlib.h> #include <errno.h> +#include "pango-markup.h" + #include "pango-attributes.h" #include "pango-font.h" #include "pango-enum-types.h" diff --git a/pango/pango-markup.h b/pango/pango-markup.h new file mode 100644 index 00000000..92ac509d --- /dev/null +++ b/pango/pango-markup.h @@ -0,0 +1,52 @@ +/* Pango + * pango-markup.h: Parser for 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. + */ + +#ifndef __PANGO_MARKUP_H__ +#define __PANGO_MARKUP_H__ + +#include <pango-attributes.h> + +G_BEGIN_DECLS + + +PANGO_AVAILABLE_IN_1_32 +GMarkupParseContext * pango_markup_parser_new (gunichar accel_marker); + +PANGO_AVAILABLE_IN_1_32 +gboolean pango_markup_parser_finish (GMarkupParseContext *context, + PangoAttrList **attr_list, + char **text, + gunichar *accel_char, + GError **error); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_parse_markup (const char *markup_text, + int length, + gunichar accel_marker, + PangoAttrList **attr_list, + char **text, + gunichar *accel_char, + GError **error); + + +G_END_DECLS + +#endif /* __PANGO_MARKUP_H__ */ diff --git a/pango/pango-types.h b/pango/pango-types.h index a7bcd747..f18225ba 100644 --- a/pango/pango-types.h +++ b/pango/pango-types.h @@ -41,7 +41,9 @@ typedef struct _PangoFontMap PangoFontMap; typedef struct _PangoRectangle PangoRectangle; +typedef struct _PangoContext PangoContext; +typedef struct _PangoLanguage PangoLanguage; /* A index of a glyph into a font. Rendering system dependent */ /** diff --git a/pango/pango-utils.c b/pango/pango-utils.c index 894935e7..412f417a 100644 --- a/pango/pango-utils.c +++ b/pango/pango-utils.c @@ -1154,3 +1154,105 @@ _pango_shape_get_extents (gint n_chars, } } +/** + * pango_find_paragraph_boundary: + * @text: UTF-8 text + * @length: length of @text in bytes, or -1 if nul-terminated + * @paragraph_delimiter_index: (out): return location for index of + * delimiter + * @next_paragraph_start: (out): return location for start of next + * paragraph + * + * Locates a paragraph boundary in @text. + * + * A boundary is caused by delimiter characters, such as + * a newline, carriage return, carriage return-newline pair, + * or Unicode paragraph separator character. + * + * The index of the run of delimiters is returned in + * @paragraph_delimiter_index. The index of the start + * of the paragrap (index after all delimiters) is stored + * in @next_paragraph_start. + * + * If no delimiters are found, both @paragraph_delimiter_index + * and @next_paragraph_start are filled with the length of @text + * (an index one off the end). + */ +void +pango_find_paragraph_boundary (const char *text, + int length, + int *paragraph_delimiter_index, + int *next_paragraph_start) +{ + const char *p = text; + const char *end; + const char *start = NULL; + const char *delimiter = NULL; + + /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in + * Unicode 5.0; update the following code if that changes. + */ + + /* prev_sep is the first byte of the previous separator. Since + * the valid separators are \r, \n, and PARAGRAPH_SEPARATOR, the + * first byte is enough to identify it. + */ + char prev_sep; + +#define PARAGRAPH_SEPARATOR_STRING "\xE2\x80\xA9" + + if (length < 0) + length = strlen (text); + + end = text + length; + + if (paragraph_delimiter_index) + *paragraph_delimiter_index = length; + + if (next_paragraph_start) + *next_paragraph_start = length; + + if (length == 0) + return; + + prev_sep = 0; + while (p < end) + { + if (prev_sep == '\n' || + prev_sep == PARAGRAPH_SEPARATOR_STRING[0]) + { + g_assert (delimiter); + start = p; + break; + } + else if (prev_sep == '\r') + { + /* don't break between \r and \n */ + if (*p != '\n') + { + g_assert (delimiter); + start = p; + break; + } + } + + if (*p == '\n' || + *p == '\r' || + !strncmp(p, PARAGRAPH_SEPARATOR_STRING, strlen (PARAGRAPH_SEPARATOR_STRING))) + { + if (delimiter == NULL) + delimiter = p; + prev_sep = *p; + } + else + prev_sep = 0; + + p = g_utf8_next_char (p); + } + + if (delimiter && paragraph_delimiter_index) + *paragraph_delimiter_index = delimiter - text; + + if (start && next_paragraph_start) + *next_paragraph_start = start - text; +} diff --git a/pango/pango-utils.h b/pango/pango-utils.h index 04452eb4..49566cf8 100644 --- a/pango/pango-utils.h +++ b/pango/pango-utils.h @@ -99,6 +99,12 @@ guint8 * pango_log2vis_get_embedding_levels (const gchar *text, PANGO_AVAILABLE_IN_1_10 gboolean pango_is_zero_width (gunichar ch) G_GNUC_CONST; +PANGO_AVAILABLE_IN_ALL +void pango_find_paragraph_boundary (const char *text, + int length, + int *paragraph_delimiter_index, + int *next_paragraph_start); + /* Pango version checking */ /* Encode a Pango version as an integer */ diff --git a/pango/pango.h b/pango/pango.h index 7a00f925..8dc86b13 100644 --- a/pango/pango.h +++ b/pango/pango.h @@ -25,6 +25,7 @@ #include <pango/pango-attributes.h> #include <pango/pango-bidi-type.h> #include <pango/pango-break.h> +#include <pango/pango-color.h> #include <pango/pango-context.h> #include <pango/pango-coverage.h> #include <pango/pango-direction.h> @@ -38,8 +39,10 @@ #include <pango/pango-glyph-item.h> #include <pango/pango-gravity.h> #include <pango/pango-item.h> +#include <pango/pango-language.h> #include <pango/pango-layout.h> #include <pango/pango-matrix.h> +#include <pango/pango-markup.h> #include <pango/pango-renderer.h> #include <pango/pango-script.h> #include <pango/pango-tabs.h> diff --git a/pango/pangofc-shape.c b/pango/pangofc-shape.c deleted file mode 100644 index 0a5ce7f9..00000000 --- a/pango/pangofc-shape.c +++ /dev/null @@ -1,425 +0,0 @@ -/* Pango - * pangofc-shape.c: Basic shaper for FreeType-based backends - * - * Copyright (C) 2000, 2007, 2009 Red Hat Software - * Authors: - * Owen Taylor <otaylor@redhat.com> - * Behdad Esfahbod <behdad@behdad.org> - * - * 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 <math.h> - -#include "pangohb-private.h" -#include "pango-impl-utils.h" - -#include <glib.h> - -/* cache a single hb_buffer_t */ -static hb_buffer_t *cached_buffer = NULL; /* MT-safe */ -G_LOCK_DEFINE_STATIC (cached_buffer); - -static hb_buffer_t * -acquire_buffer (gboolean *free_buffer) -{ - hb_buffer_t *buffer; - - if (G_LIKELY (G_TRYLOCK (cached_buffer))) - { - if (G_UNLIKELY (!cached_buffer)) - cached_buffer = hb_buffer_create (); - - buffer = cached_buffer; - *free_buffer = FALSE; - } - else - { - buffer = hb_buffer_create (); - *free_buffer = TRUE; - } - - return buffer; -} - -static void -release_buffer (hb_buffer_t *buffer, gboolean free_buffer) -{ - if (G_LIKELY (!free_buffer)) - { - hb_buffer_reset (buffer); - G_UNLOCK (cached_buffer); - } - else - hb_buffer_destroy (buffer); -} - -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)++; - } - } - } -} - -typedef struct -{ - PangoFont *font; - hb_font_t *parent; - PangoShowFlags show_flags; -} PangoHbShapeContext; - -static hb_bool_t -pango_hb_font_get_nominal_glyph (hb_font_t *font, - void *font_data, - hb_codepoint_t unicode, - hb_codepoint_t *glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; - - if (context->show_flags != 0) - { - if ((context->show_flags & PANGO_SHOW_SPACES) != 0 && - g_unichar_type (unicode) == G_UNICODE_SPACE_SEPARATOR) - { - /* Replace 0x20 by visible space, since we - * don't draw a hex box for 0x20 - */ - if (unicode == 0x20) - *glyph = PANGO_GET_UNKNOWN_GLYPH (0x2423); - else - *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); - return TRUE; - } - - if ((context->show_flags & PANGO_SHOW_IGNORABLES) != 0 && - pango_get_ignorable (unicode)) - { - *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); - return TRUE; - } - - if ((context->show_flags & PANGO_SHOW_LINE_BREAKS) != 0 && - unicode == 0x2028) - { - /* Always mark LS as unknown. If it ends up - * at the line end, PangoLayout takes care of - * hiding them, and if they end up in the middle - * of a line, we are in single paragraph mode - * and want to show the LS - */ - *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); - return TRUE; - } - } - - if (hb_font_get_nominal_glyph (context->parent, unicode, glyph)) - return TRUE; - - *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); - - /* We draw our own invalid-Unicode shape, so prevent HarfBuzz - * from using REPLACEMENT CHARACTER. */ - if (unicode > 0x10FFFF) - return TRUE; - - return FALSE; -} - -static hb_position_t -pango_hb_font_get_glyph_h_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; - - if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) - { - PangoRectangle logical; - - pango_font_get_glyph_extents (context->font, glyph, NULL, &logical); - return logical.width; - } - - return hb_font_get_glyph_h_advance (context->parent, glyph); -} - -static hb_position_t -pango_hb_font_get_glyph_v_advance (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; - - if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) - { - PangoRectangle logical; - - pango_font_get_glyph_extents (context->font, glyph, NULL, &logical); - return logical.height; - } - - return hb_font_get_glyph_v_advance (context->parent, glyph); -} - -static hb_bool_t -pango_hb_font_get_glyph_extents (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - hb_glyph_extents_t *extents, - void *user_data G_GNUC_UNUSED) -{ - PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; - - if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) - { - PangoRectangle ink; - - pango_font_get_glyph_extents (context->font, glyph, &ink, NULL); - - extents->x_bearing = ink.x; - extents->y_bearing = ink.y; - extents->width = ink.width; - extents->height = ink.height; - - return TRUE; - } - - return hb_font_get_glyph_extents (context->parent, glyph, extents); -} - -static hb_font_t * -pango_font_get_hb_font_for_context (PangoFont *font, - PangoHbShapeContext *context) -{ - hb_font_t *hb_font; - static hb_font_funcs_t *funcs; - - hb_font = pango_font_get_hb_font (font); - - if (G_UNLIKELY (!funcs)) - { - funcs = hb_font_funcs_create (); - - hb_font_funcs_set_nominal_glyph_func (funcs, pango_hb_font_get_nominal_glyph, NULL, NULL); - hb_font_funcs_set_glyph_h_advance_func (funcs, pango_hb_font_get_glyph_h_advance, NULL, NULL); - hb_font_funcs_set_glyph_v_advance_func (funcs, pango_hb_font_get_glyph_v_advance, NULL, NULL); - hb_font_funcs_set_glyph_extents_func (funcs, pango_hb_font_get_glyph_extents, NULL, NULL); - - hb_font_funcs_make_immutable (funcs); - } - - context->font = font; - context->parent = hb_font; - - hb_font = hb_font_create_sub_font (hb_font); - hb_font_set_funcs (hb_font, funcs, context, NULL); - - return hb_font; -} - -static PangoShowFlags -find_show_flags (const PangoAnalysis *analysis) -{ - GSList *l; - PangoShowFlags flags = 0; - - for (l = analysis->extra_attrs; l; l = l->next) - { - PangoAttribute *attr = l->data; - - if (attr->klass->type == PANGO_ATTR_SHOW) - flags |= ((PangoAttrInt*)attr)->value; - } - - return flags; -} - -void -pango_hb_shape (PangoFont *font, - const char *item_text, - unsigned int item_length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs, - const char *paragraph_text, - unsigned int paragraph_length) -{ - PangoHbShapeContext context = { 0, }; - hb_buffer_flags_t hb_buffer_flags; - hb_font_t *hb_font; - hb_buffer_t *hb_buffer; - hb_direction_t hb_direction; - gboolean free_buffer; - hb_glyph_info_t *hb_glyph; - hb_glyph_position_t *hb_position; - int last_cluster; - guint i, num_glyphs; - unsigned int item_offset = item_text - paragraph_text; - hb_feature_t features[32]; - unsigned int num_features = 0; - PangoGlyphInfo *infos; - - g_return_if_fail (font != NULL); - g_return_if_fail (analysis != NULL); - - context.show_flags = find_show_flags (analysis); - hb_font = pango_font_get_hb_font_for_context (font, &context); - hb_buffer = acquire_buffer (&free_buffer); - - hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR; - if (analysis->level % 2) - hb_direction = HB_DIRECTION_REVERSE (hb_direction); - if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity)) - hb_direction = HB_DIRECTION_REVERSE (hb_direction); - - hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT; - - if (context.show_flags & PANGO_SHOW_IGNORABLES) - hb_buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES; - - /* setup buffer */ - - hb_buffer_set_direction (hb_buffer, hb_direction); - hb_buffer_set_script (hb_buffer, (hb_script_t) g_unicode_script_to_iso15924 (analysis->script)); - hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language), -1)); - hb_buffer_set_cluster_level (hb_buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); - hb_buffer_set_flags (hb_buffer, hb_buffer_flags); - hb_buffer_set_invisible_glyph (hb_buffer, PANGO_GLYPH_EMPTY); - - hb_buffer_add_utf8 (hb_buffer, paragraph_text, paragraph_length, item_offset, item_length); - if (analysis->flags & PANGO_ANALYSIS_FLAG_NEED_HYPHEN) - { - /* Insert either a Unicode or ASCII hyphen. We may - * want to look for script-specific hyphens here. - */ - const char *p = paragraph_text + item_offset + item_length; - int last_char_len = p - g_utf8_prev_char (p); - hb_codepoint_t glyph; - - if (hb_font_get_nominal_glyph (hb_font, 0x2010, &glyph)) - hb_buffer_add (hb_buffer, 0x2010, item_offset + item_length - last_char_len); - else if (hb_font_get_nominal_glyph (hb_font, '-', &glyph)) - hb_buffer_add (hb_buffer, '-', item_offset + item_length - last_char_len); - } - - pango_font_get_features (font, features, G_N_ELEMENTS (features), &num_features); - apply_extra_attributes (analysis->extra_attrs, features, G_N_ELEMENTS (features), &num_features); - - hb_shape (hb_font, hb_buffer, features, num_features); - - if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity)) - hb_buffer_reverse (hb_buffer); - - /* buffer output */ - num_glyphs = hb_buffer_get_length (hb_buffer); - hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL); - pango_glyph_string_set_size (glyphs, num_glyphs); - infos = glyphs->glyphs; - last_cluster = -1; - for (i = 0; i < num_glyphs; i++) - { - infos[i].glyph = hb_glyph->codepoint; - glyphs->log_clusters[i] = hb_glyph->cluster - item_offset; - infos[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster; - hb_glyph++; - last_cluster = glyphs->log_clusters[i]; - } - - hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL); - if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity)) - for (i = 0; i < num_glyphs; i++) - { - /* 90 degrees rotation counter-clockwise. */ - infos[i].geometry.width = - hb_position->y_advance; - infos[i].geometry.x_offset = - hb_position->y_offset; - infos[i].geometry.y_offset = - hb_position->x_offset; - hb_position++; - } - else /* horizontal */ - for (i = 0; i < num_glyphs; i++) - { - infos[i].geometry.width = hb_position->x_advance; - infos[i].geometry.x_offset = hb_position->x_offset; - infos[i].geometry.y_offset = - hb_position->y_offset; - hb_position++; - } - - release_buffer (hb_buffer, free_buffer); - hb_font_destroy (hb_font); -} diff --git a/pango/reorder-items.c b/pango/reorder-items.c index e5ceeb6f..c30d003b 100644 --- a/pango/reorder-items.c +++ b/pango/reorder-items.c @@ -20,7 +20,7 @@ */ #include "config.h" -#include "pango-glyph.h" +#include "pango-item.h" /* * NB: The contents of the file implement the exact same algorithm @@ -31,7 +31,7 @@ static GList *reorder_items_recurse (GList *items, int n_items); /** * pango_reorder_items: - * @logical_items: (element-type Pango.Item): a `GList` of `PangoItem` + * @items: (element-type Pango.Item): a `GList` of `PangoItem` * in logical order. * * Reorder items from logical order to visual order. @@ -47,13 +47,14 @@ static GList *reorder_items_recurse (GList *items, int n_items); * of `PangoItem` structures in visual order. */ GList * -pango_reorder_items (GList *logical_items) +pango_reorder_items (GList *items) { - return reorder_items_recurse (logical_items, g_list_length (logical_items)); + return reorder_items_recurse (items, g_list_length (items)); } static GList * -reorder_items_recurse (GList *items, int n_items) +reorder_items_recurse (GList *items, + int n_items) { GList *tmp_list, *level_start_node; int i, level_start_i; diff --git a/pango/shape.c b/pango/shape.c index afb1db0d..f10bd5c9 100644 --- a/pango/shape.c +++ b/pango/shape.c @@ -10,7 +10,7 @@ * * 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 + * 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 @@ -21,13 +21,473 @@ #include "config.h" +#include <string.h> +#include <math.h> +#include <glib.h> + #include "pango-impl-utils.h" #include "pango-glyph.h" #include "pangohb-private.h" #include "pango-font-private.h" -#include <string.h> +/* {{{ Harfbuzz shaping */ + +/* {{{{ Buffer handling */ +static hb_buffer_t *cached_buffer = NULL; /* MT-safe */ +G_LOCK_DEFINE_STATIC (cached_buffer); + +static hb_buffer_t * +acquire_buffer (gboolean *free_buffer) +{ + hb_buffer_t *buffer; + + if (G_LIKELY (G_TRYLOCK (cached_buffer))) + { + if (G_UNLIKELY (!cached_buffer)) + cached_buffer = hb_buffer_create (); + + buffer = cached_buffer; + *free_buffer = FALSE; + } + else + { + buffer = hb_buffer_create (); + *free_buffer = TRUE; + } + + return buffer; +} + +static void +release_buffer (hb_buffer_t *buffer, + gboolean free_buffer) +{ + if (G_LIKELY (!free_buffer)) + { + hb_buffer_reset (buffer); + G_UNLOCK (cached_buffer); + } + else + hb_buffer_destroy (buffer); +} +/* }}}} */ +/* {{{{ Use PangoFont with Harfbuzz */ + +typedef struct +{ + PangoFont *font; + hb_font_t *parent; + PangoShowFlags show_flags; +} PangoHbShapeContext; + +static hb_bool_t +pango_hb_font_get_nominal_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + void *user_data G_GNUC_UNUSED) +{ + PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; + + if (context->show_flags != 0) + { + if ((context->show_flags & PANGO_SHOW_SPACES) != 0 && + g_unichar_type (unicode) == G_UNICODE_SPACE_SEPARATOR) + { + /* Replace 0x20 by visible space, since we + * don't draw a hex box for 0x20 + */ + if (unicode == 0x20) + *glyph = PANGO_GET_UNKNOWN_GLYPH (0x2423); + else + *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); + return TRUE; + } + + if ((context->show_flags & PANGO_SHOW_IGNORABLES) != 0 && + pango_get_ignorable (unicode)) + { + *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); + return TRUE; + } + + if ((context->show_flags & PANGO_SHOW_LINE_BREAKS) != 0 && + unicode == 0x2028) + { + /* Always mark LS as unknown. If it ends up + * at the line end, PangoLayout takes care of + * hiding them, and if they end up in the middle + * of a line, we are in single paragraph mode + * and want to show the LS + */ + *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); + return TRUE; + } + } + + if (hb_font_get_nominal_glyph (context->parent, unicode, glyph)) + return TRUE; + + *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); + + /* We draw our own invalid-Unicode shape, so prevent HarfBuzz + * from using REPLACEMENT CHARACTER. */ + if (unicode > 0x10FFFF) + return TRUE; + + return FALSE; +} + +static hb_position_t +pango_hb_font_get_glyph_h_advance (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + void *user_data G_GNUC_UNUSED) +{ + PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; + + if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) + { + PangoRectangle logical; + + pango_font_get_glyph_extents (context->font, glyph, NULL, &logical); + return logical.width; + } + + return hb_font_get_glyph_h_advance (context->parent, glyph); +} + +static hb_position_t +pango_hb_font_get_glyph_v_advance (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + void *user_data G_GNUC_UNUSED) +{ + PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; + + if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) + { + PangoRectangle logical; + + pango_font_get_glyph_extents (context->font, glyph, NULL, &logical); + return logical.height; + } + + return hb_font_get_glyph_v_advance (context->parent, glyph); +} + +static hb_bool_t +pango_hb_font_get_glyph_extents (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data G_GNUC_UNUSED) +{ + PangoHbShapeContext *context = (PangoHbShapeContext *) font_data; + + if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) + { + PangoRectangle ink; + + pango_font_get_glyph_extents (context->font, glyph, &ink, NULL); + + extents->x_bearing = ink.x; + extents->y_bearing = ink.y; + extents->width = ink.width; + extents->height = ink.height; + + return TRUE; + } + + return hb_font_get_glyph_extents (context->parent, glyph, extents); +} + +static hb_font_t * +pango_font_get_hb_font_for_context (PangoFont *font, + PangoHbShapeContext *context) +{ + hb_font_t *hb_font; + static hb_font_funcs_t *funcs; + + hb_font = pango_font_get_hb_font (font); + + if (G_UNLIKELY (!funcs)) + { + funcs = hb_font_funcs_create (); + + hb_font_funcs_set_nominal_glyph_func (funcs, pango_hb_font_get_nominal_glyph, NULL, NULL); + hb_font_funcs_set_glyph_h_advance_func (funcs, pango_hb_font_get_glyph_h_advance, NULL, NULL); + hb_font_funcs_set_glyph_v_advance_func (funcs, pango_hb_font_get_glyph_v_advance, NULL, NULL); + hb_font_funcs_set_glyph_extents_func (funcs, pango_hb_font_get_glyph_extents, NULL, NULL); + + hb_font_funcs_make_immutable (funcs); + } + + context->font = font; + context->parent = hb_font; + + hb_font = hb_font_create_sub_font (hb_font); + hb_font_set_funcs (hb_font, funcs, context, NULL); + + return hb_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) +{ + GSList *l; + PangoShowFlags flags = 0; + + for (l = analysis->extra_attrs; l; l = l->next) + { + PangoAttribute *attr = l->data; + + if (attr->klass->type == PANGO_ATTR_SHOW) + flags |= ((PangoAttrInt*)attr)->value; + } + + return flags; +} + +/* }}}} */ +void +pango_hb_shape (PangoFont *font, + const char *item_text, + unsigned int item_length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs, + const char *paragraph_text, + unsigned int paragraph_length) +{ + PangoHbShapeContext context = { 0, }; + hb_buffer_flags_t hb_buffer_flags; + hb_font_t *hb_font; + hb_buffer_t *hb_buffer; + hb_direction_t hb_direction; + gboolean free_buffer; + hb_glyph_info_t *hb_glyph; + hb_glyph_position_t *hb_position; + int last_cluster; + guint i, num_glyphs; + unsigned int item_offset = item_text - paragraph_text; + hb_feature_t features[32]; + unsigned int num_features = 0; + PangoGlyphInfo *infos; + + g_return_if_fail (font != NULL); + g_return_if_fail (analysis != NULL); + + context.show_flags = find_show_flags (analysis); + hb_font = pango_font_get_hb_font_for_context (font, &context); + hb_buffer = acquire_buffer (&free_buffer); + + hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR; + if (analysis->level % 2) + hb_direction = HB_DIRECTION_REVERSE (hb_direction); + if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity)) + hb_direction = HB_DIRECTION_REVERSE (hb_direction); + + hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT; + + if (context.show_flags & PANGO_SHOW_IGNORABLES) + hb_buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES; + + /* setup buffer */ + + hb_buffer_set_direction (hb_buffer, hb_direction); + hb_buffer_set_script (hb_buffer, (hb_script_t) g_unicode_script_to_iso15924 (analysis->script)); + hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language), -1)); + hb_buffer_set_cluster_level (hb_buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); + hb_buffer_set_flags (hb_buffer, hb_buffer_flags); + hb_buffer_set_invisible_glyph (hb_buffer, PANGO_GLYPH_EMPTY); + + hb_buffer_add_utf8 (hb_buffer, paragraph_text, paragraph_length, item_offset, item_length); + if (analysis->flags & PANGO_ANALYSIS_FLAG_NEED_HYPHEN) + { + /* Insert either a Unicode or ASCII hyphen. We may + * want to look for script-specific hyphens here. + */ + const char *p = paragraph_text + item_offset + item_length; + int last_char_len = p - g_utf8_prev_char (p); + hb_codepoint_t glyph; + + if (hb_font_get_nominal_glyph (hb_font, 0x2010, &glyph)) + hb_buffer_add (hb_buffer, 0x2010, item_offset + item_length - last_char_len); + else if (hb_font_get_nominal_glyph (hb_font, '-', &glyph)) + hb_buffer_add (hb_buffer, '-', item_offset + item_length - last_char_len); + } + + pango_font_get_features (font, features, G_N_ELEMENTS (features), &num_features); + apply_extra_attributes (analysis->extra_attrs, features, G_N_ELEMENTS (features), &num_features); + + hb_shape (hb_font, hb_buffer, features, num_features); + + if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity)) + hb_buffer_reverse (hb_buffer); + + /* buffer output */ + num_glyphs = hb_buffer_get_length (hb_buffer); + hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL); + pango_glyph_string_set_size (glyphs, num_glyphs); + infos = glyphs->glyphs; + last_cluster = -1; + for (i = 0; i < num_glyphs; i++) + { + infos[i].glyph = hb_glyph->codepoint; + glyphs->log_clusters[i] = hb_glyph->cluster - item_offset; + infos[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster; + hb_glyph++; + last_cluster = glyphs->log_clusters[i]; + } + + hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL); + if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity)) + for (i = 0; i < num_glyphs; i++) + { + /* 90 degrees rotation counter-clockwise. */ + infos[i].geometry.width = - hb_position->y_advance; + infos[i].geometry.x_offset = - hb_position->y_offset; + infos[i].geometry.y_offset = - hb_position->x_offset; + hb_position++; + } + else /* horizontal */ + for (i = 0; i < num_glyphs; i++) + { + infos[i].geometry.width = hb_position->x_advance; + infos[i].geometry.x_offset = hb_position->x_offset; + infos[i].geometry.y_offset = - hb_position->y_offset; + hb_position++; + } + + release_buffer (hb_buffer, free_buffer); + hb_font_destroy (hb_font); +} + +/* }}} */ +/* {{{ Fallback shaping */ + +/* This is not meant to produce reasonable results */ + +static void +fallback_shape (const char *text, + unsigned int length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs) +{ + int n_chars; + const char *p; + int cluster = 0; + int i; + + n_chars = text ? pango_utf8_strlen (text, length) : 0; + + pango_glyph_string_set_size (glyphs, n_chars); + + p = text; + for (i = 0; i < n_chars; i++) + { + gunichar wc; + PangoGlyph glyph; + PangoRectangle logical_rect; + + wc = g_utf8_get_char (p); + + if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) + cluster = p - text; + + if (pango_is_zero_width (wc)) + glyph = PANGO_GLYPH_EMPTY; + else + glyph = PANGO_GET_UNKNOWN_GLYPH (wc); + + pango_font_get_glyph_extents (analysis->font, glyph, NULL, &logical_rect); + + glyphs->glyphs[i].glyph = glyph; + + glyphs->glyphs[i].geometry.x_offset = 0; + glyphs->glyphs[i].geometry.y_offset = 0; + glyphs->glyphs[i].geometry.width = logical_rect.width; + + glyphs->log_clusters[i] = cluster; + + p = g_utf8_next_char (p); + } + + if (analysis->level & 1) + pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs); +} + +/* }}} */ +/* {{{ Public API */ /** * pango_shape: @@ -52,10 +512,10 @@ * calling [func@shape]. */ void -pango_shape (const gchar *text, - gint length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs) +pango_shape (const char *text, + int length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs) { pango_shape_full (text, length, text, length, analysis, glyphs); } @@ -103,55 +563,6 @@ pango_shape_full (const char *item_text, PANGO_SHAPE_NONE); } -static void -fallback_shape (const char *text, - unsigned int length, - const PangoAnalysis *analysis, - PangoGlyphString *glyphs) -{ - int n_chars; - const char *p; - int cluster = 0; - int i; - - n_chars = text ? pango_utf8_strlen (text, length) : 0; - - pango_glyph_string_set_size (glyphs, n_chars); - - p = text; - for (i = 0; i < n_chars; i++) - { - gunichar wc; - PangoGlyph glyph; - PangoRectangle logical_rect; - - wc = g_utf8_get_char (p); - - if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) - cluster = p - text; - - if (pango_is_zero_width (wc)) - glyph = PANGO_GLYPH_EMPTY; - else - glyph = PANGO_GET_UNKNOWN_GLYPH (wc); - - pango_font_get_glyph_extents (analysis->font, glyph, NULL, &logical_rect); - - glyphs->glyphs[i].glyph = glyph; - - glyphs->glyphs[i].geometry.x_offset = 0; - glyphs->glyphs[i].geometry.y_offset = 0; - glyphs->glyphs[i].geometry.width = logical_rect.width; - - glyphs->log_clusters[i] = cluster; - - p = g_utf8_next_char (p); - } - - if (analysis->level & 1) - pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs); -} - /** * pango_shape_with_flags: * @item_text: valid UTF-8 text to shape @@ -183,10 +594,10 @@ fallback_shape (const char *text, * Since: 1.44 */ void -pango_shape_with_flags (const gchar *item_text, - gint item_length, - const gchar *paragraph_text, - gint paragraph_length, +pango_shape_with_flags (const char *item_text, + int item_length, + const char *paragraph_text, + int paragraph_length, const PangoAnalysis *analysis, PangoGlyphString *glyphs, PangoShapeFlags flags) @@ -218,19 +629,19 @@ pango_shape_with_flags (const gchar *item_text, paragraph_text, paragraph_length); if (G_UNLIKELY (glyphs->num_glyphs == 0)) - { - /* If a font has been correctly chosen, but no glyphs are output, - * there's probably something wrong with the font. - * - * Trying to be informative, we print out the font description, - * and the text, but to not flood the terminal with - * zillions of the message, we set a flag to only err once per - * font. - */ + { + /* If a font has been correctly chosen, but no glyphs are output, + * there's probably something wrong with the font. + * + * Trying to be informative, we print out the font description, + * and the text, but to not flood the terminal with + * zillions of the message, we set a flag to only err once per + * font. + */ GQuark warned_quark = g_quark_from_static_string ("pango-shape-fail-warned"); - if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark)) - { + if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark)) + { PangoFontDescription *desc; char *font_name; @@ -246,7 +657,7 @@ pango_shape_with_flags (const gchar *item_text, g_object_set_qdata (G_OBJECT (analysis->font), warned_quark, GINT_TO_POINTER (1)); } - } + } } else glyphs->num_glyphs = 0; @@ -264,12 +675,12 @@ pango_shape_with_flags (const gchar *item_text, { /* Set glyphs[i].attr.is_cluster_start based on log_clusters[] */ if (glyphs->log_clusters[i] != last_cluster) - { - glyphs->glyphs[i].attr.is_cluster_start = TRUE; - last_cluster = glyphs->log_clusters[i]; - } + { + glyphs->glyphs[i].attr.is_cluster_start = TRUE; + last_cluster = glyphs->log_clusters[i]; + } else - glyphs->glyphs[i].attr.is_cluster_start = FALSE; + glyphs->glyphs[i].attr.is_cluster_start = FALSE; /* Shift glyph if width is negative, and negate width. @@ -277,15 +688,15 @@ pango_shape_with_flags (const gchar *item_text, * harm in normal cases. */ if (glyphs->glyphs[i].geometry.width < 0) - { - glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width; - glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width; - } + { + glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width; + glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width; + } } /* Make sure glyphstring direction conforms to analysis->level */ if (G_UNLIKELY ((analysis->level & 1) && - glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1])) + glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1])) { g_warning ("Expected RTL run but got LTR. Fixing."); @@ -355,3 +766,7 @@ pango_shape_with_flags (const gchar *item_text, } } } + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ |