1 /* Pango
2 * pango-item.c: Single run handling
3 *
4 * Copyright (C) 2000 Red Hat Software
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #include "config.h"
23 #include "pango-attributes.h"
24 #include "pango-item.h"
25 #include "pango-impl-utils.h"
26
27 /**
28 * pango_item_new:
29 *
30 * Creates a new `PangoItem` structure initialized to default values.
31 *
32 * Return value: the newly allocated `PangoItem`, which should
33 * be freed with [method@Pango.Item.free].
34 */
35 PangoItem *
pango_item_new(void)36 pango_item_new (void)
37 {
38 PangoItem *result = g_slice_new0 (PangoItem);
39
40 return result;
41 }
42
43 /**
44 * pango_item_copy:
45 * @item: (nullable): a `PangoItem`
46 *
47 * Copy an existing `PangoItem` structure.
48 *
49 * Return value: (nullable): the newly allocated `PangoItem`
50 */
51 PangoItem *
pango_item_copy(PangoItem * item)52 pango_item_copy (PangoItem *item)
53 {
54 GSList *extra_attrs, *tmp_list;
55 PangoItem *result;
56
57 if (item == NULL)
58 return NULL;
59
60 result = g_slice_new (PangoItem);
61
62 result->offset = item->offset;
63 result->length = item->length;
64 result->num_chars = item->num_chars;
65
66 result->analysis = item->analysis;
67 if (result->analysis.font)
68 g_object_ref (result->analysis.font);
69
70 extra_attrs = NULL;
71 tmp_list = item->analysis.extra_attrs;
72 while (tmp_list)
73 {
74 extra_attrs = g_slist_prepend (extra_attrs, pango_attribute_copy (tmp_list->data));
75 tmp_list = tmp_list->next;
76 }
77
78 result->analysis.extra_attrs = g_slist_reverse (extra_attrs);
79
80 return result;
81 }
82
83 /**
84 * pango_item_free:
85 * @item: (nullable): a `PangoItem`, may be %NULL
86 *
87 * Free a `PangoItem` and all associated memory.
88 **/
89 void
pango_item_free(PangoItem * item)90 pango_item_free (PangoItem *item)
91 {
92 if (item == NULL)
93 return;
94
95 if (item->analysis.extra_attrs)
96 {
97 g_slist_foreach (item->analysis.extra_attrs, (GFunc)pango_attribute_destroy, NULL);
98 g_slist_free (item->analysis.extra_attrs);
99 }
100
101 if (item->analysis.font)
102 g_object_unref (item->analysis.font);
103
104 g_slice_free (PangoItem, item);
105 }
106
107 G_DEFINE_BOXED_TYPE (PangoItem, pango_item,
108 pango_item_copy,
109 pango_item_free);
110
111 /**
112 * pango_item_split:
113 * @orig: a `PangoItem`
114 * @split_index: byte index of position to split item, relative to the
115 * start of the item
116 * @split_offset: number of chars between start of @orig and @split_index
117 *
118 * Modifies @orig to cover only the text after @split_index, and
119 * returns a new item that covers the text before @split_index that
120 * used to be in @orig.
121 *
122 * You can think of @split_index as the length of the returned item.
123 * @split_index may not be 0, and it may not be greater than or equal
124 * to the length of @orig (that is, there must be at least one byte
125 * assigned to each item, you can't create a zero-length item).
126 * @split_offset is the length of the first item in chars, and must be
127 * provided because the text used to generate the item isn't available,
128 * so `pango_item_split()` can't count the char length of the split items
129 * itself.
130 *
131 * Return value: new item representing text before @split_index, which
132 * should be freed with [method@Pango.Item.free].
133 */
134 PangoItem*
pango_item_split(PangoItem * orig,int split_index,int split_offset)135 pango_item_split (PangoItem *orig,
136 int split_index,
137 int split_offset)
138 {
139 PangoItem *new_item;
140
141 g_return_val_if_fail (orig != NULL, NULL);
142 g_return_val_if_fail (split_index > 0, NULL);
143 g_return_val_if_fail (split_index < orig->length, NULL);
144 g_return_val_if_fail (split_offset > 0, NULL);
145 g_return_val_if_fail (split_offset < orig->num_chars, NULL);
146
147 new_item = pango_item_copy (orig);
148 new_item->length = split_index;
149 new_item->num_chars = split_offset;
150
151 orig->offset += split_index;
152 orig->length -= split_index;
153 orig->num_chars -= split_offset;
154
155 return new_item;
156 }
157
158 static int
compare_attr(gconstpointer p1,gconstpointer p2)159 compare_attr (gconstpointer p1, gconstpointer p2)
160 {
161 const PangoAttribute *a1 = p1;
162 const PangoAttribute *a2 = p2;
163 if (pango_attribute_equal (a1, a2) &&
164 a1->start_index == a2->start_index &&
165 a1->end_index == a2->end_index)
166 return 0;
167
168 return 1;
169 }
170
171 /**
172 * pango_item_apply_attrs:
173 * @item: a `PangoItem`
174 * @iter: a `PangoAttrIterator`
175 *
176 * Add attributes to a `PangoItem`.
177 *
178 * The idea is that you have attributes that don't affect itemization,
179 * such as font features, so you filter them out using
180 * [method@Pango.AttrList.filter], itemize your text, then reapply the
181 * attributes to the resulting items using this function.
182 *
183 * The @iter should be positioned before the range of the item,
184 * and will be advanced past it. This function is meant to be called
185 * in a loop over the items resulting from itemization, while passing
186 * the iter to each call.
187 *
188 * Since: 1.44
189 */
190 void
pango_item_apply_attrs(PangoItem * item,PangoAttrIterator * iter)191 pango_item_apply_attrs (PangoItem *item,
192 PangoAttrIterator *iter)
193 {
194 int start, end;
195 GSList *attrs = NULL;
196
197 do
198 {
199 pango_attr_iterator_range (iter, &start, &end);
200
201 if (start >= item->offset + item->length)
202 break;
203
204 if (end >= item->offset)
205 {
206 GSList *list, *l;
207
208 list = pango_attr_iterator_get_attrs (iter);
209 for (l = list; l; l = l->next)
210 {
211 if (!g_slist_find_custom (attrs, l->data, compare_attr))
212
213 attrs = g_slist_prepend (attrs, pango_attribute_copy (l->data));
214 }
215 g_slist_free_full (list, (GDestroyNotify)pango_attribute_destroy);
216 }
217
218 if (end >= item->offset + item->length)
219 break;
220 }
221 while (pango_attr_iterator_next (iter));
222
223 item->analysis.extra_attrs = g_slist_concat (item->analysis.extra_attrs, attrs);
224 }
225