diff options
author | Owen Taylor <otaylor@redhat.com> | 2002-12-03 06:21:49 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2002-12-03 06:21:49 +0000 |
commit | 891b984fc26e0f2422a6c5c13d5b310dc7c2f7e9 (patch) | |
tree | ef651ed3c746e47dd08fc1accf97d5649454d835 /pango | |
parent | bbdb12a9e6894109259286050464da44904d21d8 (diff) | |
download | pango-891b984fc26e0f2422a6c5c13d5b310dc7c2f7e9.tar.gz |
Rename PangoLayoutRun to PangoGlyphItem (with a typedef for compat), add
Sun Nov 17 23:28:26 2002 Owen Taylor <otaylor@redhat.com>
* pango/pango-glyph-item.[ch] pango/pango-layout.h:
Rename PangoLayoutRun to PangoGlyphItem (with a
typedef for compat), add pango_glyph_item_split(),
pango_glyph_item_apply_attrs().
* pango/pango-attributes.[ch]: Add
pango_attr_list_filter(), pango_attr_iterator_get_attrs().
* pango/pango-layout.c: Remove attributes that don't
affect shaping before shaping, shape and then add
them back. Fixes the infamous "underscores break
arabic shaping" bug (#83058)
* pango/pango-item.h: Remove an extraneous include.
* pango/pango-layout.c (imposed_shape): Fix bytes/chars
problem for glyph->log_clusters.
* pango/pango-layout.c (cluster_end_index)
* pango/pango-layout.c (pango_layout_iter_next_cluster): Fix
confusion between global indices and run-relative indices.
* docs/tmpl/glyphs.sgml: Improve docs for log_clusters.
* docs/*: Document new API and PangoOTRuleset
Diffstat (limited to 'pango')
-rw-r--r-- | pango/Makefile.am | 3 | ||||
-rw-r--r-- | pango/pango-attributes.c | 113 | ||||
-rw-r--r-- | pango/pango-attributes.h | 9 | ||||
-rw-r--r-- | pango/pango-glyph-item.c | 208 | ||||
-rw-r--r-- | pango/pango-glyph-item.h | 49 | ||||
-rw-r--r-- | pango/pango-item.h | 1 | ||||
-rw-r--r-- | pango/pango-layout.c | 99 | ||||
-rw-r--r-- | pango/pango-layout.h | 12 |
8 files changed, 463 insertions, 31 deletions
diff --git a/pango/Makefile.am b/pango/Makefile.am index 8a2635a6..cc7ef4ec 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -132,11 +132,13 @@ libpango_1_0_la_SOURCES = \ pango-coverage.c \ pango-fontmap.c \ pango-fontset.c \ + pango-glyph-item.c \ pango-intset.c \ pango-intset.h \ pango-item.c \ pango-layout.c \ pango-markup.c \ + pango-script-table.h \ pango-tabs.c \ pango-utils.c \ reorder-items.c \ @@ -227,6 +229,7 @@ pango_headers= \ pango-fontmap.h \ pango-fontset.h \ pango-glyph.h \ + pango-glyph-item.h \ pango-indic.h \ pango-item.h \ pango-layout.h \ diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 630c30b0..2b224eaa 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -1,7 +1,8 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ /* pango * pango-attributes.c: Attributed text * - * Copyright (C) 2000 Red Hat Software + * Copyright (C) 2000-2002 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 @@ -1500,3 +1501,113 @@ pango_attr_iterator_get_font (PangoAttrIterator *iterator, } } } + +/** + * pango_attr_list_filter: + * @list: a #PangoAttrList + * @func: callback function; returns %TRUE if an atttribute + * should be filtered out. + * @data: 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: a newly allocated %PangoAttrList or %NULL if + * no attributes of the given types were found. + **/ +PangoAttrList * +pango_attr_list_filter (PangoAttrList *list, + PangoAttrFilterFunc func, + gpointer data) + +{ + PangoAttrList *new = NULL; + GSList *tmp_list; + GSList *prev; + GSList *new_attrs; + + g_return_val_if_fail (list != NULL, NULL); + + tmp_list = list->attributes; + prev = NULL; + new_attrs = NULL; + while (tmp_list) + { + GSList *next = tmp_list->next; + PangoAttribute *tmp_attr = tmp_list->data; + + if ((*func) (tmp_attr, data)) + { + if (!tmp_list->next) + list->attributes_tail = prev; + + if (prev) + prev->next = tmp_list->next; + else + list->attributes = tmp_list->next; + + tmp_list->next = NULL; + + if (!new) + { + new = pango_attr_list_new (); + new->attributes = new->attributes_tail = tmp_list; + } + else + { + new->attributes_tail->next = tmp_list; + new->attributes_tail = tmp_list; + } + + goto next_attr; + } + + prev = tmp_list; + + next_attr: + tmp_list = next; + } + + return new; +} + +/** + * pango_attr_iterator_get_attrs: + * @iterator: a #PangAttrIterator + * + * Gets a list all attributes a the current position of the + * iterator. + * + * Return value: a list of all attributes for the current range. + * To free this value, call pango_attributes_destroy() on + * each value and g_slist_free() on the list. + **/ +GSList * +pango_attr_iterator_get_attrs (PangoAttrIterator *iterator) +{ + GSList *attrs = NULL; + GList *tmp_list; + + for (tmp_list = iterator->attribute_stack; tmp_list; tmp_list = tmp_list->next) + { + PangoAttribute *attr = tmp_list->data; + GSList *tmp_list2; + gboolean found = FALSE; + + for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next) + { + PangoAttribute *old_attr = tmp_list2->data; + if (attr->klass->type == old_attr->klass->type) + { + found = TRUE; + break; + } + } + + if (!found) + attrs = g_slist_prepend (attrs, pango_attribute_copy (attr)); + } + + return attrs; +} diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 78669bea..3860a6d9 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -97,6 +97,9 @@ struct _PangoAttribute guint end_index; }; +typedef gboolean (*PangoAttrFilterFunc) (PangoAttribute *attribute, + gpointer data); + struct _PangoAttrClass { PangoAttrType type; @@ -191,6 +194,11 @@ void pango_attr_list_splice (PangoAttrList *list, PangoAttrList *other, gint pos, gint len); + +PangoAttrList *pango_attr_list_filter (PangoAttrList *list, + PangoAttrFilterFunc func, + gpointer data); + PangoAttrIterator *pango_attr_list_get_iterator (PangoAttrList *list); void pango_attr_iterator_range (PangoAttrIterator *iterator, @@ -205,6 +213,7 @@ void pango_attr_iterator_get_font (PangoAttrIterator *iterator PangoFontDescription *desc, PangoLanguage **language, GSList **extra_attrs); +GSList * pango_attr_iterator_get_attrs (PangoAttrIterator *iterator); gboolean pango_parse_markup (const char *markup_text, diff --git a/pango/pango-glyph-item.c b/pango/pango-glyph-item.c new file mode 100644 index 00000000..0ea520ac --- /dev/null +++ b/pango/pango-glyph-item.c @@ -0,0 +1,208 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* Pango + * pango-glyph-item.c: Pair of PangoItem and a glyph string + * + * Copyright (C) 2002 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 <string.h> + +#include "pango-glyph-item.h" + +/** + * pango_glyph_item_split: + * @orig: a #PangoItem + * @text: text to which positions in @orig apply. + * @split_index: byte index of position to split item, relative to the start of the item + * + * Modifies @orig to cover only the text after @split_index, and + * returns a new item that covers the text before @split_index that + * used to be in @orig. You can think of @split_index as the length of + * the returned item. @split_index may not be 0, and it may not be + * greater than or equal to the length of @orig (that is, there must + * be at least one byte assigned to each item, you can't create a + * zero-length item). + * + * This function is similar in function to pango_item_split() (and uses + * it internally) + * + * Return value: new item representing text before @split_index + **/ +PangoGlyphItem * +pango_glyph_item_split (PangoGlyphItem *orig, + const char *text, + int split_index) +{ + PangoGlyphItem *new; + int i; + int num_glyphs; + int num_remaining; + int split_offset; + gboolean ltr = (orig->item->analysis.level % 2) == 0; + + g_return_val_if_fail (orig != NULL, NULL); + g_return_val_if_fail (orig->item->length > 0, NULL); + g_return_val_if_fail (split_index > 0, NULL); + g_return_val_if_fail (split_index < orig->item->length, NULL); + + if (ltr) + { + for (i = 0; i < orig->glyphs->num_glyphs; i++) + { + if (orig->glyphs->log_clusters[i] >= split_index) + break; + } + + if (i == orig->glyphs->num_glyphs) /* No splitting necessary */ + return NULL; + + split_index = orig->glyphs->log_clusters[i]; + num_glyphs = i; + } + else + { + for (i = orig->glyphs->num_glyphs - 1; i >= 0; i--) + { + if (orig->glyphs->log_clusters[i] >= split_index) + break; + } + + if (i < 0) /* No splitting necessary */ + return NULL; + + split_index = orig->glyphs->log_clusters[i]; + num_glyphs = orig->glyphs->num_glyphs - 1 - i; + } + + num_remaining = orig->glyphs->num_glyphs - num_glyphs; + + new = g_new (PangoGlyphItem, 1); + split_offset = g_utf8_pointer_to_offset (text + orig->item->offset, + text + orig->item->offset + split_index); + new->item = pango_item_split (orig->item, split_index, split_offset); + + new->glyphs = pango_glyph_string_new (); + pango_glyph_string_set_size (new->glyphs, num_glyphs); + + if (ltr) + { + memcpy (new->glyphs->glyphs, orig->glyphs->glyphs, num_glyphs * sizeof (PangoGlyphInfo)); + memcpy (new->glyphs->log_clusters, orig->glyphs->log_clusters, num_glyphs * sizeof (int)); + + memmove (orig->glyphs->glyphs, orig->glyphs->glyphs + num_glyphs, + num_remaining * sizeof (PangoGlyphInfo)); + for (i = num_glyphs; i < orig->glyphs->num_glyphs; i++) + orig->glyphs->log_clusters[i - num_glyphs] = orig->glyphs->log_clusters[i] - split_index; + } + else + { + memcpy (new->glyphs->glyphs, orig->glyphs->glyphs + num_remaining, num_glyphs * sizeof (PangoGlyphInfo)); + memcpy (new->glyphs->log_clusters, orig->glyphs->log_clusters + num_remaining, num_glyphs * sizeof (int)); + + for (i = 0; i < num_remaining; i++) + orig->glyphs->log_clusters[i] = orig->glyphs->log_clusters[i] - split_index; + } + + pango_glyph_string_set_size (orig->glyphs, orig->glyphs->num_glyphs - num_glyphs); + + return new; +} + +static void +append_attrs (PangoGlyphItem *glyph_item, + GSList *attrs) +{ + glyph_item->item->analysis.extra_attrs = + g_slist_concat (glyph_item->item->analysis.extra_attrs, attrs); +} + +/** + * pango_glyph_item_apply_attrs: + * @glyph_item: a shaped item + * @text: text that @list applies to + * @list: a #PangoAttrList + * + * Splits a shaped item (PangoGlyphItem) into multiple items based + * on an attribute list. The idea is that if you have attributes + * that don't affect shaping, such as color or underline, to avoid + * affecting shaping, you filter them out (pango_attr_list_filter()), + * apply the shaping process and then reapply them to the result using + * this function. + * + * This function takes ownership of @glyph_item; it will be reused + * as one of the elements in the list. + * + * Return value: a list of glyph items resulting from splitting + * @glyph_item. Free the elements using pango_glyph_item_free(), + * the list using g_slist_free(). + **/ +GSList * +pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item, + const char *text, + PangoAttrList *list) +{ + PangoAttrIterator *iter = pango_attr_list_get_iterator (list); + PangoGlyphItem *new; + GSList *result = NULL; + int start; + int end; + + gboolean ltr = (glyph_item->item->analysis.level % 2) == 0; + + while (TRUE) + { + pango_attr_iterator_range (iter, &start, &end); + + if (start > glyph_item->item->offset) + { + if (start >= glyph_item->item->offset + glyph_item->item->length) + break; + + new = pango_glyph_item_split (glyph_item, text, + start - glyph_item->item->offset); + + result = g_slist_prepend (result, new); + } + + if (end > glyph_item->item->offset) + { + if (end >= glyph_item->item->offset + glyph_item->item->length) + { + append_attrs (glyph_item, pango_attr_iterator_get_attrs (iter)); + break; + } + + new = pango_glyph_item_split (glyph_item, text, + end - glyph_item->item->offset); + + append_attrs (new, pango_attr_iterator_get_attrs (iter)); + + result = g_slist_prepend (result, new); + } + + if (!pango_attr_iterator_next (iter)) + break; + } + + result = g_slist_prepend (result, glyph_item); + + if (ltr) + result = g_slist_reverse (result); + + return result; +} diff --git a/pango/pango-glyph-item.h b/pango/pango-glyph-item.h new file mode 100644 index 00000000..c9849f47 --- /dev/null +++ b/pango/pango-glyph-item.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* Pango + * pango-glyph-item.h: Pair of PangoItem and a glyph string + * + * Copyright (C) 2002 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_GLYPH_ITEM_H__ +#define __PANGO_GLYPH_ITEM_H__ + +#include <pango/pango-attributes.h> +#include <pango/pango-item.h> +#include <pango/pango-glyph.h> + +G_BEGIN_DECLS + +typedef struct _PangoGlyphItem PangoGlyphItem; + +struct _PangoGlyphItem +{ + PangoItem *item; + PangoGlyphString *glyphs; +}; + +PangoGlyphItem *pango_glyph_item_split (PangoGlyphItem *orig, + const char *text, + int split_index); +GSList * pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item, + const char *text, + PangoAttrList *list); + +G_END_DECLS + +#endif /* __PANGO_GLYPH_ITEM_H__ */ diff --git a/pango/pango-item.h b/pango/pango-item.h index c16368a8..dd567c2a 100644 --- a/pango/pango-item.h +++ b/pango/pango-item.h @@ -23,7 +23,6 @@ #define __PANGO_ITEM_H__ #include <pango/pango-types.h> -#include <pango/pango-item.h> G_BEGIN_DECLS diff --git a/pango/pango-layout.c b/pango/pango-layout.c index f38465d5..d80f1f27 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -2128,16 +2128,18 @@ pango_layout_clear_lines (PangoLayout *layout) ************************************************/ static void -imposed_shape (gint n_chars, +imposed_shape (const char *text, + gint n_chars, PangoRectangle *shape_ink, PangoRectangle *shape_logical, PangoGlyphString *glyphs) { int i; + const char *p; pango_glyph_string_set_size (glyphs, n_chars); - for (i=0; i < n_chars; i++) + for (i=0, p = text; i < n_chars; i++, p = g_utf8_next_char (p)) { glyphs->glyphs[i].glyph = 0; glyphs->glyphs[i].geometry.x_offset = 0; @@ -2145,7 +2147,7 @@ imposed_shape (gint n_chars, glyphs->glyphs[i].geometry.width = shape_logical->width; glyphs->glyphs[i].attr.is_cluster_start = 1; - glyphs->log_clusters[i] = i; + glyphs->log_clusters[i] = p - text; } } @@ -2563,7 +2565,7 @@ process_item (PangoLayout *layout, &shape_set); if (shape_set) - imposed_shape (item->num_chars, &shape_ink, &shape_logical, state->glyphs); + imposed_shape (layout->text + item->offset, item->num_chars, &shape_ink, &shape_logical, state->glyphs); else if (layout->text[item->offset] == '\t') shape_tab (line, state->glyphs); else @@ -2838,16 +2840,7 @@ pango_layout_get_effective_attributes (PangoLayout *layout) PangoAttrList *attrs; if (layout->attrs) - { - /* If we were being clever, we'd try to catch the case here - * where the set font desc doesn't change the font for any - * characters. - */ - if (layout->font_desc) - attrs = pango_attr_list_copy (layout->attrs); - else - attrs = layout->attrs; - } + attrs = pango_attr_list_copy (layout->attrs); else attrs = pango_attr_list_new (); @@ -2863,6 +2856,64 @@ pango_layout_get_effective_attributes (PangoLayout *layout) return attrs; } +gboolean +no_shape_filter_func (PangoAttribute *attribute, + gpointer data) +{ + static PangoAttrType no_shape_types[] = { + PANGO_ATTR_FOREGROUND, + PANGO_ATTR_BACKGROUND, + PANGO_ATTR_UNDERLINE, + PANGO_ATTR_STRIKETHROUGH, + PANGO_ATTR_RISE + }; + + int i; + + for (i = 0; i < G_N_ELEMENTS (no_shape_types); i++) + if (attribute->klass->type == no_shape_types[i]) + return TRUE; + + return FALSE; +} + +static PangoAttrList * +filter_no_shape_attributes (PangoAttrList *attrs) +{ + return pango_attr_list_filter (attrs, + no_shape_filter_func, + NULL); +} + +static void +apply_no_shape_attributes (PangoLayout *layout, + PangoAttrList *no_shape_attrs) +{ + GSList *line_list; + + for (line_list = layout->lines; line_list; line_list = line_list->next) + { + PangoLayoutLine *line = line_list->data; + GSList *old_runs = g_slist_reverse (line->runs); + GSList *run_list; + + line->runs = NULL; + for (run_list = old_runs; run_list; run_list = run_list->next) + { + PangoGlyphItem *glyph_item = run_list->data; + GSList *new_runs; + + new_runs = pango_glyph_item_apply_attrs (glyph_item, + layout->text, + no_shape_attrs); + + line->runs = g_slist_concat (new_runs, line->runs); + } + + g_slist_free (old_runs); + } +} + static void pango_layout_check_lines (PangoLayout *layout) { @@ -2870,6 +2921,7 @@ pango_layout_check_lines (PangoLayout *layout) gboolean done = FALSE; int start_offset; PangoAttrList *attrs; + PangoAttrList *no_shape_attrs; PangoAttrIterator *iter; if (layout->lines) @@ -2884,6 +2936,7 @@ pango_layout_check_lines (PangoLayout *layout) pango_layout_set_text (layout, NULL, 0); attrs = pango_layout_get_effective_attributes (layout); + no_shape_attrs = filter_no_shape_attributes (attrs); iter = pango_attr_list_get_iterator (attrs); layout->log_attrs = g_new (PangoLogAttr, layout->n_chars + 1); @@ -2924,7 +2977,7 @@ pango_layout_check_lines (PangoLayout *layout) g_assert (start <= (layout->text + layout->length)); g_assert (delim_len < 4); /* PS is 3 bytes */ g_assert (delim_len >= 0); - + state.items = pango_itemize (layout->context, layout->text, start - layout->text, @@ -2967,10 +3020,14 @@ pango_layout_check_lines (PangoLayout *layout) while (!done); pango_attr_iterator_destroy (iter); - - if (attrs != layout->attrs) - pango_attr_list_unref (attrs); - + pango_attr_list_unref (attrs); + + if (no_shape_attrs) + { + apply_no_shape_attributes (layout, no_shape_attrs); + pango_attr_list_unref (no_shape_attrs); + } + layout->lines = g_slist_reverse (layout->lines); } @@ -3897,7 +3954,7 @@ cluster_end_index (PangoLayoutIter *iter) } else { - return gs->log_clusters[iter->next_cluster_start]; + return iter->run->item->offset + gs->log_clusters[iter->next_cluster_start]; } } @@ -4219,7 +4276,7 @@ pango_layout_iter_next_cluster (PangoLayoutIter *iter) iter->cluster_start = iter->next_cluster_start; iter->next_cluster_start = next_cluster_start (gs, iter->cluster_start); iter->cluster_index = gs->log_clusters[iter->cluster_start]; - iter->index = iter->cluster_index; + iter->index = iter->run->item->offset + iter->cluster_index; return TRUE; } } diff --git a/pango/pango-layout.h b/pango/pango-layout.h index e840de79..f3c8dfce 100644 --- a/pango/pango-layout.h +++ b/pango/pango-layout.h @@ -24,7 +24,7 @@ #include <pango/pango-attributes.h> #include <pango/pango-context.h> -#include <pango/pango-glyph.h> +#include <pango/pango-glyph-item.h> #include <pango/pango-tabs.h> G_BEGIN_DECLS @@ -32,7 +32,9 @@ G_BEGIN_DECLS typedef struct _PangoLayout PangoLayout; typedef struct _PangoLayoutClass PangoLayoutClass; typedef struct _PangoLayoutLine PangoLayoutLine; -typedef struct _PangoLayoutRun PangoLayoutRun; + +/* For backwards compatiblity */ +typedef PangoGlyphItem PangoLayoutRun; typedef enum { PANGO_ALIGN_LEFT, @@ -54,12 +56,6 @@ struct _PangoLayoutLine GSList *runs; }; -struct _PangoLayoutRun -{ - PangoItem *item; - PangoGlyphString *glyphs; -}; - #define PANGO_TYPE_LAYOUT (pango_layout_get_type ()) #define PANGO_LAYOUT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_LAYOUT, PangoLayout)) #define PANGO_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_LAYOUT, PangoLayoutClass)) |