1 | /* Pango |
2 | * pango-attributes.c: Attributed text |
3 | * |
4 | * Copyright (C) 2000-2002 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 <string.h> |
24 | |
25 | #include "pango-attributes.h" |
26 | #include "pango-attributes-private.h" |
27 | #include "pango-impl-utils.h" |
28 | |
29 | |
30 | /* {{{ Generic attribute code */ |
31 | |
32 | G_LOCK_DEFINE_STATIC (attr_type); |
33 | static GHashTable *name_map = NULL; /* MT-safe */ |
34 | |
35 | /** |
36 | * pango_attr_type_register: |
37 | * @name: an identifier for the type |
38 | * |
39 | * Allocate a new attribute type ID. |
40 | * |
41 | * The attribute type name can be accessed later |
42 | * by using [func@Pango.AttrType.get_name]. |
43 | * |
44 | * Return value: the new type ID. |
45 | */ |
46 | PangoAttrType |
47 | pango_attr_type_register (const gchar *name) |
48 | { |
49 | static guint current_type = 0x1000000; /* MT-safe */ |
50 | guint type; |
51 | |
52 | G_LOCK (attr_type); |
53 | |
54 | type = current_type++; |
55 | |
56 | if (name) |
57 | { |
58 | if (G_UNLIKELY (!name_map)) |
59 | name_map = g_hash_table_new (NULL, NULL); |
60 | |
61 | g_hash_table_insert (hash_table: name_map, GUINT_TO_POINTER (type), value: (gpointer) g_intern_string (string: name)); |
62 | } |
63 | |
64 | G_UNLOCK (attr_type); |
65 | |
66 | return type; |
67 | } |
68 | |
69 | /** |
70 | * pango_attr_type_get_name: |
71 | * @type: an attribute type ID to fetch the name for |
72 | * |
73 | * Fetches the attribute type name. |
74 | * |
75 | * The attribute type name is the string passed in |
76 | * when registering the type using |
77 | * [func@Pango.AttrType.register]. |
78 | * |
79 | * The returned value is an interned string (see |
80 | * g_intern_string() for what that means) that should |
81 | * not be modified or freed. |
82 | * |
83 | * Return value: (nullable): the type ID name (which |
84 | * may be %NULL), or %NULL if @type is a built-in Pango |
85 | * attribute type or invalid. |
86 | * |
87 | * Since: 1.22 |
88 | */ |
89 | const char * |
90 | pango_attr_type_get_name (PangoAttrType type) |
91 | { |
92 | const char *result = NULL; |
93 | |
94 | G_LOCK (attr_type); |
95 | |
96 | if (name_map) |
97 | result = g_hash_table_lookup (hash_table: name_map, GUINT_TO_POINTER ((guint) type)); |
98 | |
99 | G_UNLOCK (attr_type); |
100 | |
101 | return result; |
102 | } |
103 | |
104 | /** |
105 | * pango_attribute_init: |
106 | * @attr: a `PangoAttribute` |
107 | * @klass: a `PangoAttrClass` |
108 | * |
109 | * Initializes @attr's klass to @klass, it's start_index to |
110 | * %PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING and end_index to |
111 | * %PANGO_ATTR_INDEX_TO_TEXT_END such that the attribute applies |
112 | * to the entire text by default. |
113 | * |
114 | * Since: 1.20 |
115 | */ |
116 | void |
117 | pango_attribute_init (PangoAttribute *attr, |
118 | const PangoAttrClass *klass) |
119 | { |
120 | g_return_if_fail (attr != NULL); |
121 | g_return_if_fail (klass != NULL); |
122 | |
123 | attr->klass = klass; |
124 | attr->start_index = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING; |
125 | attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END; |
126 | } |
127 | |
128 | /** |
129 | * pango_attribute_copy: |
130 | * @attr: a `PangoAttribute` |
131 | * |
132 | * Make a copy of an attribute. |
133 | * |
134 | * Return value: (transfer full): the newly allocated |
135 | * `PangoAttribute`, which should be freed with |
136 | * [method@Pango.Attribute.destroy]. |
137 | */ |
138 | PangoAttribute * |
139 | pango_attribute_copy (const PangoAttribute *attr) |
140 | { |
141 | PangoAttribute *result; |
142 | |
143 | g_return_val_if_fail (attr != NULL, NULL); |
144 | |
145 | result = attr->klass->copy (attr); |
146 | result->start_index = attr->start_index; |
147 | result->end_index = attr->end_index; |
148 | |
149 | return result; |
150 | } |
151 | |
152 | /** |
153 | * pango_attribute_destroy: |
154 | * @attr: a `PangoAttribute`. |
155 | * |
156 | * Destroy a `PangoAttribute` and free all associated memory. |
157 | */ |
158 | void |
159 | pango_attribute_destroy (PangoAttribute *attr) |
160 | { |
161 | g_return_if_fail (attr != NULL); |
162 | |
163 | attr->klass->destroy (attr); |
164 | } |
165 | |
166 | G_DEFINE_BOXED_TYPE (PangoAttribute, pango_attribute, |
167 | pango_attribute_copy, |
168 | pango_attribute_destroy); |
169 | |
170 | /** |
171 | * pango_attribute_equal: |
172 | * @attr1: a `PangoAttribute` |
173 | * @attr2: another `PangoAttribute` |
174 | * |
175 | * Compare two attributes for equality. |
176 | * |
177 | * This compares only the actual value of the two |
178 | * attributes and not the ranges that the attributes |
179 | * apply to. |
180 | * |
181 | * Return value: %TRUE if the two attributes have the same value |
182 | */ |
183 | gboolean |
184 | pango_attribute_equal (const PangoAttribute *attr1, |
185 | const PangoAttribute *attr2) |
186 | { |
187 | g_return_val_if_fail (attr1 != NULL, FALSE); |
188 | g_return_val_if_fail (attr2 != NULL, FALSE); |
189 | |
190 | if (attr1->klass->type != attr2->klass->type) |
191 | return FALSE; |
192 | |
193 | return attr1->klass->equal (attr1, attr2); |
194 | } |
195 | |
196 | /* }}} */ |
197 | /* {{{ Attribute types */ |
198 | /* {{{ String attribute */ |
199 | static PangoAttribute *pango_attr_string_new (const PangoAttrClass *klass, |
200 | const char *str); |
201 | |
202 | static PangoAttribute * |
203 | pango_attr_string_copy (const PangoAttribute *attr) |
204 | { |
205 | return pango_attr_string_new (klass: attr->klass, str: ((PangoAttrString *)attr)->value); |
206 | } |
207 | |
208 | static void |
209 | pango_attr_string_destroy (PangoAttribute *attr) |
210 | { |
211 | PangoAttrString *sattr = (PangoAttrString *)attr; |
212 | |
213 | g_free (mem: sattr->value); |
214 | g_slice_free (PangoAttrString, sattr); |
215 | } |
216 | |
217 | static gboolean |
218 | pango_attr_string_equal (const PangoAttribute *attr1, |
219 | const PangoAttribute *attr2) |
220 | { |
221 | return strcmp (s1: ((PangoAttrString *)attr1)->value, s2: ((PangoAttrString *)attr2)->value) == 0; |
222 | } |
223 | |
224 | static PangoAttribute * |
225 | pango_attr_string_new (const PangoAttrClass *klass, |
226 | const char *str) |
227 | { |
228 | PangoAttrString *result = g_slice_new (PangoAttrString); |
229 | pango_attribute_init (attr: &result->attr, klass); |
230 | result->value = g_strdup (str); |
231 | |
232 | return (PangoAttribute *)result; |
233 | } |
234 | /* }}} */ |
235 | /* {{{ Language attribute */ |
236 | static PangoAttribute * |
237 | pango_attr_language_copy (const PangoAttribute *attr) |
238 | { |
239 | return pango_attr_language_new (language: ((PangoAttrLanguage *)attr)->value); |
240 | } |
241 | |
242 | static void |
243 | pango_attr_language_destroy (PangoAttribute *attr) |
244 | { |
245 | PangoAttrLanguage *lattr = (PangoAttrLanguage *)attr; |
246 | |
247 | g_slice_free (PangoAttrLanguage, lattr); |
248 | } |
249 | |
250 | static gboolean |
251 | pango_attr_language_equal (const PangoAttribute *attr1, |
252 | const PangoAttribute *attr2) |
253 | { |
254 | return ((PangoAttrLanguage *)attr1)->value == ((PangoAttrLanguage *)attr2)->value; |
255 | } |
256 | /* }}}} */ |
257 | /* {{{ Color attribute */ |
258 | static PangoAttribute *pango_attr_color_new (const PangoAttrClass *klass, |
259 | guint16 red, |
260 | guint16 green, |
261 | guint16 blue); |
262 | |
263 | static PangoAttribute * |
264 | pango_attr_color_copy (const PangoAttribute *attr) |
265 | { |
266 | const PangoAttrColor *color_attr = (PangoAttrColor *)attr; |
267 | |
268 | return pango_attr_color_new (klass: attr->klass, |
269 | red: color_attr->color.red, |
270 | green: color_attr->color.green, |
271 | blue: color_attr->color.blue); |
272 | } |
273 | |
274 | static void |
275 | pango_attr_color_destroy (PangoAttribute *attr) |
276 | { |
277 | PangoAttrColor *cattr = (PangoAttrColor *)attr; |
278 | |
279 | g_slice_free (PangoAttrColor, cattr); |
280 | } |
281 | |
282 | static gboolean |
283 | pango_attr_color_equal (const PangoAttribute *attr1, |
284 | const PangoAttribute *attr2) |
285 | { |
286 | const PangoAttrColor *color_attr1 = (const PangoAttrColor *)attr1; |
287 | const PangoAttrColor *color_attr2 = (const PangoAttrColor *)attr2; |
288 | |
289 | return (color_attr1->color.red == color_attr2->color.red && |
290 | color_attr1->color.blue == color_attr2->color.blue && |
291 | color_attr1->color.green == color_attr2->color.green); |
292 | } |
293 | |
294 | static PangoAttribute * |
295 | pango_attr_color_new (const PangoAttrClass *klass, |
296 | guint16 red, |
297 | guint16 green, |
298 | guint16 blue) |
299 | { |
300 | PangoAttrColor *result = g_slice_new (PangoAttrColor); |
301 | pango_attribute_init (attr: &result->attr, klass); |
302 | result->color.red = red; |
303 | result->color.green = green; |
304 | result->color.blue = blue; |
305 | |
306 | return (PangoAttribute *)result; |
307 | } |
308 | /* }}}} */ |
309 | /* {{{ Integer attribute */ |
310 | static PangoAttribute *pango_attr_int_new (const PangoAttrClass *klass, |
311 | int value); |
312 | |
313 | static PangoAttribute * |
314 | pango_attr_int_copy (const PangoAttribute *attr) |
315 | { |
316 | const PangoAttrInt *int_attr = (PangoAttrInt *)attr; |
317 | |
318 | return pango_attr_int_new (klass: attr->klass, value: int_attr->value); |
319 | } |
320 | |
321 | static void |
322 | pango_attr_int_destroy (PangoAttribute *attr) |
323 | { |
324 | PangoAttrInt *iattr = (PangoAttrInt *)attr; |
325 | |
326 | g_slice_free (PangoAttrInt, iattr); |
327 | } |
328 | |
329 | static gboolean |
330 | pango_attr_int_equal (const PangoAttribute *attr1, |
331 | const PangoAttribute *attr2) |
332 | { |
333 | const PangoAttrInt *int_attr1 = (const PangoAttrInt *)attr1; |
334 | const PangoAttrInt *int_attr2 = (const PangoAttrInt *)attr2; |
335 | |
336 | return (int_attr1->value == int_attr2->value); |
337 | } |
338 | |
339 | static PangoAttribute * |
340 | pango_attr_int_new (const PangoAttrClass *klass, |
341 | int value) |
342 | { |
343 | PangoAttrInt *result = g_slice_new (PangoAttrInt); |
344 | pango_attribute_init (attr: &result->attr, klass); |
345 | result->value = value; |
346 | |
347 | return (PangoAttribute *)result; |
348 | } |
349 | /* }}} */ |
350 | /* {{{ Float attribute */ |
351 | static PangoAttribute *pango_attr_float_new (const PangoAttrClass *klass, |
352 | double value); |
353 | |
354 | static PangoAttribute * |
355 | pango_attr_float_copy (const PangoAttribute *attr) |
356 | { |
357 | const PangoAttrFloat *float_attr = (PangoAttrFloat *)attr; |
358 | |
359 | return pango_attr_float_new (klass: attr->klass, value: float_attr->value); |
360 | } |
361 | |
362 | static void |
363 | pango_attr_float_destroy (PangoAttribute *attr) |
364 | { |
365 | PangoAttrFloat *fattr = (PangoAttrFloat *)attr; |
366 | |
367 | g_slice_free (PangoAttrFloat, fattr); |
368 | } |
369 | |
370 | static gboolean |
371 | pango_attr_float_equal (const PangoAttribute *attr1, |
372 | const PangoAttribute *attr2) |
373 | { |
374 | const PangoAttrFloat *float_attr1 = (const PangoAttrFloat *)attr1; |
375 | const PangoAttrFloat *float_attr2 = (const PangoAttrFloat *)attr2; |
376 | |
377 | return (float_attr1->value == float_attr2->value); |
378 | } |
379 | |
380 | static PangoAttribute * |
381 | pango_attr_float_new (const PangoAttrClass *klass, |
382 | double value) |
383 | { |
384 | PangoAttrFloat *result = g_slice_new (PangoAttrFloat); |
385 | pango_attribute_init (attr: &result->attr, klass); |
386 | result->value = value; |
387 | |
388 | return (PangoAttribute *)result; |
389 | } |
390 | /* }}} */ |
391 | /* {{{ Size attribute */ |
392 | static PangoAttribute *pango_attr_size_new_internal (int size, |
393 | gboolean absolute); |
394 | |
395 | static PangoAttribute * |
396 | pango_attr_size_copy (const PangoAttribute *attr) |
397 | { |
398 | const PangoAttrSize *size_attr = (PangoAttrSize *)attr; |
399 | |
400 | if (attr->klass->type == PANGO_ATTR_ABSOLUTE_SIZE) |
401 | return pango_attr_size_new_absolute (size: size_attr->size); |
402 | else |
403 | return pango_attr_size_new (size: size_attr->size); |
404 | } |
405 | |
406 | static void |
407 | pango_attr_size_destroy (PangoAttribute *attr) |
408 | { |
409 | PangoAttrSize *sattr = (PangoAttrSize *)attr; |
410 | |
411 | g_slice_free (PangoAttrSize, sattr); |
412 | } |
413 | |
414 | static gboolean |
415 | pango_attr_size_equal (const PangoAttribute *attr1, |
416 | const PangoAttribute *attr2) |
417 | { |
418 | const PangoAttrSize *size_attr1 = (const PangoAttrSize *)attr1; |
419 | const PangoAttrSize *size_attr2 = (const PangoAttrSize *)attr2; |
420 | |
421 | return size_attr1->size == size_attr2->size; |
422 | } |
423 | |
424 | static PangoAttribute * |
425 | pango_attr_size_new_internal (int size, |
426 | gboolean absolute) |
427 | { |
428 | PangoAttrSize *result; |
429 | |
430 | static const PangoAttrClass klass = { |
431 | PANGO_ATTR_SIZE, |
432 | pango_attr_size_copy, |
433 | pango_attr_size_destroy, |
434 | pango_attr_size_equal |
435 | }; |
436 | static const PangoAttrClass absolute_klass = { |
437 | PANGO_ATTR_ABSOLUTE_SIZE, |
438 | pango_attr_size_copy, |
439 | pango_attr_size_destroy, |
440 | pango_attr_size_equal |
441 | }; |
442 | |
443 | result = g_slice_new (PangoAttrSize); |
444 | pango_attribute_init (attr: &result->attr, klass: absolute ? &absolute_klass : &klass); |
445 | result->size = size; |
446 | result->absolute = absolute; |
447 | |
448 | return (PangoAttribute *)result; |
449 | } |
450 | /* }}} */ |
451 | /* {{{ Font description attribute */ |
452 | static PangoAttribute * |
453 | pango_attr_font_desc_copy (const PangoAttribute *attr) |
454 | { |
455 | const PangoAttrFontDesc *desc_attr = (const PangoAttrFontDesc *)attr; |
456 | |
457 | return pango_attr_font_desc_new (desc: desc_attr->desc); |
458 | } |
459 | |
460 | static void |
461 | pango_attr_font_desc_destroy (PangoAttribute *attr) |
462 | { |
463 | PangoAttrFontDesc *desc_attr = (PangoAttrFontDesc *)attr; |
464 | |
465 | pango_font_description_free (desc: desc_attr->desc); |
466 | g_slice_free (PangoAttrFontDesc, desc_attr); |
467 | } |
468 | |
469 | static gboolean |
470 | pango_attr_font_desc_equal (const PangoAttribute *attr1, |
471 | const PangoAttribute *attr2) |
472 | { |
473 | const PangoAttrFontDesc *desc_attr1 = (const PangoAttrFontDesc *)attr1; |
474 | const PangoAttrFontDesc *desc_attr2 = (const PangoAttrFontDesc *)attr2; |
475 | |
476 | return pango_font_description_get_set_fields (desc: desc_attr1->desc) == |
477 | pango_font_description_get_set_fields (desc: desc_attr2->desc) && |
478 | pango_font_description_equal (desc1: desc_attr1->desc, desc2: desc_attr2->desc); |
479 | } |
480 | /* }}} */ |
481 | /* {{{ Shape attribute */ |
482 | static PangoAttribute * |
483 | pango_attr_shape_copy (const PangoAttribute *attr) |
484 | { |
485 | const PangoAttrShape *shape_attr = (PangoAttrShape *)attr; |
486 | gpointer data; |
487 | |
488 | if (shape_attr->copy_func) |
489 | data = shape_attr->copy_func (shape_attr->data); |
490 | else |
491 | data = shape_attr->data; |
492 | |
493 | return pango_attr_shape_new_with_data (ink_rect: &shape_attr->ink_rect, logical_rect: &shape_attr->logical_rect, |
494 | data, copy_func: shape_attr->copy_func, destroy_func: shape_attr->destroy_func); |
495 | } |
496 | |
497 | static void |
498 | pango_attr_shape_destroy (PangoAttribute *attr) |
499 | { |
500 | PangoAttrShape *shape_attr = (PangoAttrShape *)attr; |
501 | |
502 | if (shape_attr->destroy_func) |
503 | shape_attr->destroy_func (shape_attr->data); |
504 | |
505 | g_slice_free (PangoAttrShape, shape_attr); |
506 | } |
507 | |
508 | static gboolean |
509 | pango_attr_shape_equal (const PangoAttribute *attr1, |
510 | const PangoAttribute *attr2) |
511 | { |
512 | const PangoAttrShape *shape_attr1 = (const PangoAttrShape *)attr1; |
513 | const PangoAttrShape *shape_attr2 = (const PangoAttrShape *)attr2; |
514 | |
515 | return (shape_attr1->logical_rect.x == shape_attr2->logical_rect.x && |
516 | shape_attr1->logical_rect.y == shape_attr2->logical_rect.y && |
517 | shape_attr1->logical_rect.width == shape_attr2->logical_rect.width && |
518 | shape_attr1->logical_rect.height == shape_attr2->logical_rect.height && |
519 | shape_attr1->ink_rect.x == shape_attr2->ink_rect.x && |
520 | shape_attr1->ink_rect.y == shape_attr2->ink_rect.y && |
521 | shape_attr1->ink_rect.width == shape_attr2->ink_rect.width && |
522 | shape_attr1->ink_rect.height == shape_attr2->ink_rect.height && |
523 | shape_attr1->data == shape_attr2->data); |
524 | } |
525 | /* }}} */ |
526 | /* }}} */ |
527 | /* {{{ Public API */ |
528 | |
529 | /** |
530 | * pango_attr_family_new: |
531 | * @family: the family or comma-separated list of families |
532 | * |
533 | * Create a new font family attribute. |
534 | * |
535 | * Return value: (transfer full): the newly allocated |
536 | * `PangoAttribute`, which should be freed with |
537 | * [method@Pango.Attribute.destroy] |
538 | */ |
539 | PangoAttribute * |
540 | pango_attr_family_new (const char *family) |
541 | { |
542 | static const PangoAttrClass klass = { |
543 | PANGO_ATTR_FAMILY, |
544 | pango_attr_string_copy, |
545 | pango_attr_string_destroy, |
546 | pango_attr_string_equal |
547 | }; |
548 | |
549 | g_return_val_if_fail (family != NULL, NULL); |
550 | |
551 | return pango_attr_string_new (klass: &klass, str: family); |
552 | } |
553 | |
554 | /** |
555 | * pango_attr_language_new: |
556 | * @language: language tag |
557 | * |
558 | * Create a new language tag attribute. |
559 | * |
560 | * Return value: (transfer full): the newly allocated |
561 | * `PangoAttribute`, which should be freed with |
562 | * [method@Pango.Attribute.destroy] |
563 | */ |
564 | PangoAttribute * |
565 | pango_attr_language_new (PangoLanguage *language) |
566 | { |
567 | PangoAttrLanguage *result; |
568 | |
569 | static const PangoAttrClass klass = { |
570 | PANGO_ATTR_LANGUAGE, |
571 | pango_attr_language_copy, |
572 | pango_attr_language_destroy, |
573 | pango_attr_language_equal |
574 | }; |
575 | |
576 | result = g_slice_new (PangoAttrLanguage); |
577 | pango_attribute_init (attr: &result->attr, klass: &klass); |
578 | result->value = language; |
579 | |
580 | return (PangoAttribute *)result; |
581 | } |
582 | |
583 | /** |
584 | * pango_attr_foreground_new: |
585 | * @red: the red value (ranging from 0 to 65535) |
586 | * @green: the green value |
587 | * @blue: the blue value |
588 | * |
589 | * Create a new foreground color attribute. |
590 | * |
591 | * Return value: (transfer full): the newly allocated |
592 | * `PangoAttribute`, which should be freed with |
593 | * [method@Pango.Attribute.destroy] |
594 | */ |
595 | PangoAttribute * |
596 | pango_attr_foreground_new (guint16 red, |
597 | guint16 green, |
598 | guint16 blue) |
599 | { |
600 | static const PangoAttrClass klass = { |
601 | PANGO_ATTR_FOREGROUND, |
602 | pango_attr_color_copy, |
603 | pango_attr_color_destroy, |
604 | pango_attr_color_equal |
605 | }; |
606 | |
607 | return pango_attr_color_new (klass: &klass, red, green, blue); |
608 | } |
609 | |
610 | /** |
611 | * pango_attr_background_new: |
612 | * @red: the red value (ranging from 0 to 65535) |
613 | * @green: the green value |
614 | * @blue: the blue value |
615 | * |
616 | * Create a new background color attribute. |
617 | * |
618 | * Return value: (transfer full): the newly allocated |
619 | * `PangoAttribute`, which should be freed with |
620 | * [method@Pango.Attribute.destroy] |
621 | */ |
622 | PangoAttribute * |
623 | pango_attr_background_new (guint16 red, |
624 | guint16 green, |
625 | guint16 blue) |
626 | { |
627 | static const PangoAttrClass klass = { |
628 | PANGO_ATTR_BACKGROUND, |
629 | pango_attr_color_copy, |
630 | pango_attr_color_destroy, |
631 | pango_attr_color_equal |
632 | }; |
633 | |
634 | return pango_attr_color_new (klass: &klass, red, green, blue); |
635 | } |
636 | |
637 | /** |
638 | * pango_attr_size_new: |
639 | * @size: the font size, in %PANGO_SCALE-ths of a point |
640 | * |
641 | * Create a new font-size attribute in fractional points. |
642 | * |
643 | * Return value: (transfer full): the newly allocated |
644 | * `PangoAttribute`, which should be freed with |
645 | * [method@Pango.Attribute.destroy] |
646 | */ |
647 | PangoAttribute * |
648 | pango_attr_size_new (int size) |
649 | { |
650 | return pango_attr_size_new_internal (size, FALSE); |
651 | } |
652 | |
653 | /** |
654 | * pango_attr_size_new_absolute: |
655 | * @size: the font size, in %PANGO_SCALE-ths of a device unit |
656 | * |
657 | * Create a new font-size attribute in device units. |
658 | * |
659 | * Return value: (transfer full): the newly allocated |
660 | * `PangoAttribute`, which should be freed with |
661 | * [method@Pango.Attribute.destroy] |
662 | * |
663 | * Since: 1.8 |
664 | */ |
665 | PangoAttribute * |
666 | pango_attr_size_new_absolute (int size) |
667 | { |
668 | return pango_attr_size_new_internal (size, TRUE); |
669 | } |
670 | |
671 | /** |
672 | * pango_attr_style_new: |
673 | * @style: the slant style |
674 | * |
675 | * Create a new font slant style attribute. |
676 | * |
677 | * Return value: (transfer full): the newly allocated |
678 | * `PangoAttribute`, which should be freed with |
679 | * [method@Pango.Attribute.destroy] |
680 | */ |
681 | PangoAttribute * |
682 | pango_attr_style_new (PangoStyle style) |
683 | { |
684 | static const PangoAttrClass klass = { |
685 | PANGO_ATTR_STYLE, |
686 | pango_attr_int_copy, |
687 | pango_attr_int_destroy, |
688 | pango_attr_int_equal |
689 | }; |
690 | |
691 | return pango_attr_int_new (klass: &klass, value: (int)style); |
692 | } |
693 | |
694 | /** |
695 | * pango_attr_weight_new: |
696 | * @weight: the weight |
697 | * |
698 | * Create a new font weight attribute. |
699 | * |
700 | * Return value: (transfer full): the newly allocated |
701 | * `PangoAttribute`, which should be freed with |
702 | * [method@Pango.Attribute.destroy] |
703 | */ |
704 | PangoAttribute * |
705 | pango_attr_weight_new (PangoWeight weight) |
706 | { |
707 | static const PangoAttrClass klass = { |
708 | PANGO_ATTR_WEIGHT, |
709 | pango_attr_int_copy, |
710 | pango_attr_int_destroy, |
711 | pango_attr_int_equal |
712 | }; |
713 | |
714 | return pango_attr_int_new (klass: &klass, value: (int)weight); |
715 | } |
716 | |
717 | /** |
718 | * pango_attr_variant_new: |
719 | * @variant: the variant |
720 | * |
721 | * Create a new font variant attribute (normal or small caps). |
722 | * |
723 | * Return value: (transfer full): the newly allocated `PangoAttribute`, |
724 | * which should be freed with [method@Pango.Attribute.destroy]. |
725 | */ |
726 | PangoAttribute * |
727 | pango_attr_variant_new (PangoVariant variant) |
728 | { |
729 | static const PangoAttrClass klass = { |
730 | PANGO_ATTR_VARIANT, |
731 | pango_attr_int_copy, |
732 | pango_attr_int_destroy, |
733 | pango_attr_int_equal |
734 | }; |
735 | |
736 | return pango_attr_int_new (klass: &klass, value: (int)variant); |
737 | } |
738 | |
739 | /** |
740 | * pango_attr_stretch_new: |
741 | * @stretch: the stretch |
742 | * |
743 | * Create a new font stretch attribute. |
744 | * |
745 | * Return value: (transfer full): the newly allocated |
746 | * `PangoAttribute`, which should be freed with |
747 | * [method@Pango.Attribute.destroy] |
748 | */ |
749 | PangoAttribute * |
750 | pango_attr_stretch_new (PangoStretch stretch) |
751 | { |
752 | static const PangoAttrClass klass = { |
753 | PANGO_ATTR_STRETCH, |
754 | pango_attr_int_copy, |
755 | pango_attr_int_destroy, |
756 | pango_attr_int_equal |
757 | }; |
758 | |
759 | return pango_attr_int_new (klass: &klass, value: (int)stretch); |
760 | } |
761 | |
762 | /** |
763 | * pango_attr_font_desc_new: |
764 | * @desc: the font description |
765 | * |
766 | * Create a new font description attribute. |
767 | * |
768 | * This attribute allows setting family, style, weight, variant, |
769 | * stretch, and size simultaneously. |
770 | * |
771 | * Return value: (transfer full): the newly allocated |
772 | * `PangoAttribute`, which should be freed with |
773 | * [method@Pango.Attribute.destroy] |
774 | */ |
775 | PangoAttribute * |
776 | pango_attr_font_desc_new (const PangoFontDescription *desc) |
777 | { |
778 | static const PangoAttrClass klass = { |
779 | PANGO_ATTR_FONT_DESC, |
780 | pango_attr_font_desc_copy, |
781 | pango_attr_font_desc_destroy, |
782 | pango_attr_font_desc_equal |
783 | }; |
784 | |
785 | PangoAttrFontDesc *result = g_slice_new (PangoAttrFontDesc); |
786 | pango_attribute_init (attr: &result->attr, klass: &klass); |
787 | result->desc = pango_font_description_copy (desc); |
788 | |
789 | return (PangoAttribute *)result; |
790 | } |
791 | |
792 | /** |
793 | * pango_attr_underline_new: |
794 | * @underline: the underline style |
795 | * |
796 | * Create a new underline-style attribute. |
797 | * |
798 | * Return value: (transfer full): the newly allocated |
799 | * `PangoAttribute`, which should be freed with |
800 | * [method@Pango.Attribute.destroy] |
801 | */ |
802 | PangoAttribute * |
803 | pango_attr_underline_new (PangoUnderline underline) |
804 | { |
805 | static const PangoAttrClass klass = { |
806 | PANGO_ATTR_UNDERLINE, |
807 | pango_attr_int_copy, |
808 | pango_attr_int_destroy, |
809 | pango_attr_int_equal |
810 | }; |
811 | |
812 | return pango_attr_int_new (klass: &klass, value: (int)underline); |
813 | } |
814 | |
815 | /** |
816 | * pango_attr_underline_color_new: |
817 | * @red: the red value (ranging from 0 to 65535) |
818 | * @green: the green value |
819 | * @blue: the blue value |
820 | * |
821 | * Create a new underline color attribute. |
822 | * |
823 | * This attribute modifies the color of underlines. |
824 | * If not set, underlines will use the foreground color. |
825 | * |
826 | * Return value: (transfer full): the newly allocated |
827 | * `PangoAttribute`, which should be freed with |
828 | * [method@Pango.Attribute.destroy] |
829 | * |
830 | * Since: 1.8 |
831 | */ |
832 | PangoAttribute * |
833 | pango_attr_underline_color_new (guint16 red, |
834 | guint16 green, |
835 | guint16 blue) |
836 | { |
837 | static const PangoAttrClass klass = { |
838 | PANGO_ATTR_UNDERLINE_COLOR, |
839 | pango_attr_color_copy, |
840 | pango_attr_color_destroy, |
841 | pango_attr_color_equal |
842 | }; |
843 | |
844 | return pango_attr_color_new (klass: &klass, red, green, blue); |
845 | } |
846 | |
847 | /** |
848 | * pango_attr_strikethrough_new: |
849 | * @strikethrough: %TRUE if the text should be struck-through |
850 | * |
851 | * Create a new strike-through attribute. |
852 | * |
853 | * Return value: (transfer full): the newly allocated |
854 | * `PangoAttribute`, which should be freed with |
855 | * [method@Pango.Attribute.destroy] |
856 | */ |
857 | PangoAttribute * |
858 | pango_attr_strikethrough_new (gboolean strikethrough) |
859 | { |
860 | static const PangoAttrClass klass = { |
861 | PANGO_ATTR_STRIKETHROUGH, |
862 | pango_attr_int_copy, |
863 | pango_attr_int_destroy, |
864 | pango_attr_int_equal |
865 | }; |
866 | |
867 | return pango_attr_int_new (klass: &klass, value: (int)strikethrough); |
868 | } |
869 | |
870 | /** |
871 | * pango_attr_strikethrough_color_new: |
872 | * @red: the red value (ranging from 0 to 65535) |
873 | * @green: the green value |
874 | * @blue: the blue value |
875 | * |
876 | * Create a new strikethrough color attribute. |
877 | * |
878 | * This attribute modifies the color of strikethrough lines. |
879 | * If not set, strikethrough lines will use the foreground color. |
880 | * |
881 | * Return value: (transfer full): the newly allocated |
882 | * `PangoAttribute`, which should be freed with |
883 | * [method@Pango.Attribute.destroy] |
884 | * |
885 | * Since: 1.8 |
886 | */ |
887 | PangoAttribute * |
888 | pango_attr_strikethrough_color_new (guint16 red, |
889 | guint16 green, |
890 | guint16 blue) |
891 | { |
892 | static const PangoAttrClass klass = { |
893 | PANGO_ATTR_STRIKETHROUGH_COLOR, |
894 | pango_attr_color_copy, |
895 | pango_attr_color_destroy, |
896 | pango_attr_color_equal |
897 | }; |
898 | |
899 | return pango_attr_color_new (klass: &klass, red, green, blue); |
900 | } |
901 | |
902 | /** |
903 | * pango_attr_rise_new: |
904 | * @rise: the amount that the text should be displaced vertically, |
905 | * in Pango units. Positive values displace the text upwards. |
906 | * |
907 | * Create a new baseline displacement attribute. |
908 | * |
909 | * Return value: (transfer full): the newly allocated |
910 | * `PangoAttribute`, which should be freed with |
911 | * [method@Pango.Attribute.destroy] |
912 | */ |
913 | PangoAttribute * |
914 | pango_attr_rise_new (int rise) |
915 | { |
916 | static const PangoAttrClass klass = { |
917 | PANGO_ATTR_RISE, |
918 | pango_attr_int_copy, |
919 | pango_attr_int_destroy, |
920 | pango_attr_int_equal |
921 | }; |
922 | |
923 | return pango_attr_int_new (klass: &klass, value: (int)rise); |
924 | } |
925 | |
926 | /** |
927 | * pango_attr_baseline_shift_new: |
928 | * @shift: either a `PangoBaselineShift` enumeration value or an absolute value (> 1024) |
929 | * in Pango units, relative to the baseline of the previous run. |
930 | * Positive values displace the text upwards. |
931 | * |
932 | * Create a new baseline displacement attribute. |
933 | * |
934 | * The effect of this attribute is to shift the baseline of a run, |
935 | * relative to the run of preceding run. |
936 | * |
937 | * <picture> |
938 | * <source srcset="baseline-shift-dark.png" media="(prefers-color-scheme: dark)"> |
939 | * <img alt="Baseline Shift" src="baseline-shift-light.png"> |
940 | * </picture> |
941 | |
942 | * Return value: (transfer full): the newly allocated |
943 | * `PangoAttribute`, which should be freed with |
944 | * [method@Pango.Attribute.destroy] |
945 | * |
946 | * Since: 1.50 |
947 | */ |
948 | PangoAttribute * |
949 | pango_attr_baseline_shift_new (int rise) |
950 | { |
951 | static const PangoAttrClass klass = { |
952 | PANGO_ATTR_BASELINE_SHIFT, |
953 | pango_attr_int_copy, |
954 | pango_attr_int_destroy, |
955 | pango_attr_int_equal |
956 | }; |
957 | |
958 | return pango_attr_int_new (klass: &klass, value: (int)rise); |
959 | } |
960 | |
961 | /** |
962 | * pango_attr_font_scale_new: |
963 | * @scale: a `PangoFontScale` value, which indicates font size change relative |
964 | * to the size of the previous run. |
965 | * |
966 | * |
967 | * Create a new font scale attribute. |
968 | * |
969 | * The effect of this attribute is to change the font size of a run, |
970 | * relative to the size of preceding run. |
971 | * |
972 | * Return value: (transfer full): the newly allocated |
973 | * `PangoAttribute`, which should be freed with |
974 | * [method@Pango.Attribute.destroy] |
975 | * |
976 | * Since: 1.50 |
977 | */ |
978 | PangoAttribute * |
979 | pango_attr_font_scale_new (PangoFontScale scale) |
980 | { |
981 | static const PangoAttrClass klass = { |
982 | PANGO_ATTR_FONT_SCALE, |
983 | pango_attr_int_copy, |
984 | pango_attr_int_destroy, |
985 | pango_attr_int_equal |
986 | }; |
987 | |
988 | return pango_attr_int_new (klass: &klass, value: (int)scale); |
989 | } |
990 | |
991 | /** |
992 | * pango_attr_scale_new: |
993 | * @scale_factor: factor to scale the font |
994 | * |
995 | * Create a new font size scale attribute. |
996 | * |
997 | * The base font for the affected text will have |
998 | * its size multiplied by @scale_factor. |
999 | * |
1000 | * Return value: (transfer full): the newly allocated |
1001 | * `PangoAttribute`, which should be freed with |
1002 | * [method@Pango.Attribute.destroy] |
1003 | */ |
1004 | PangoAttribute* |
1005 | pango_attr_scale_new (double scale_factor) |
1006 | { |
1007 | static const PangoAttrClass klass = { |
1008 | PANGO_ATTR_SCALE, |
1009 | pango_attr_float_copy, |
1010 | pango_attr_float_destroy, |
1011 | pango_attr_float_equal |
1012 | }; |
1013 | |
1014 | return pango_attr_float_new (klass: &klass, value: scale_factor); |
1015 | } |
1016 | |
1017 | /** |
1018 | * pango_attr_fallback_new: |
1019 | * @enable_fallback: %TRUE if we should fall back on other fonts |
1020 | * for characters the active font is missing |
1021 | * |
1022 | * Create a new font fallback attribute. |
1023 | * |
1024 | * If fallback is disabled, characters will only be |
1025 | * used from the closest matching font on the system. |
1026 | * No fallback will be done to other fonts on the system |
1027 | * that might contain the characters in the text. |
1028 | * |
1029 | * Return value: (transfer full): the newly allocated |
1030 | * `PangoAttribute`, which should be freed with |
1031 | * [method@Pango.Attribute.destroy] |
1032 | * |
1033 | * Since: 1.4 |
1034 | */ |
1035 | PangoAttribute * |
1036 | pango_attr_fallback_new (gboolean enable_fallback) |
1037 | { |
1038 | static const PangoAttrClass klass = { |
1039 | PANGO_ATTR_FALLBACK, |
1040 | pango_attr_int_copy, |
1041 | pango_attr_int_destroy, |
1042 | pango_attr_int_equal, |
1043 | }; |
1044 | |
1045 | return pango_attr_int_new (klass: &klass, value: (int)enable_fallback); |
1046 | } |
1047 | |
1048 | /** |
1049 | * pango_attr_letter_spacing_new: |
1050 | * @letter_spacing: amount of extra space to add between |
1051 | * graphemes of the text, in Pango units |
1052 | * |
1053 | * Create a new letter-spacing attribute. |
1054 | * |
1055 | * Return value: (transfer full): the newly allocated |
1056 | * `PangoAttribute`, which should be freed with |
1057 | * [method@Pango.Attribute.destroy] |
1058 | * |
1059 | * Since: 1.6 |
1060 | */ |
1061 | PangoAttribute * |
1062 | pango_attr_letter_spacing_new (int letter_spacing) |
1063 | { |
1064 | static const PangoAttrClass klass = { |
1065 | PANGO_ATTR_LETTER_SPACING, |
1066 | pango_attr_int_copy, |
1067 | pango_attr_int_destroy, |
1068 | pango_attr_int_equal |
1069 | }; |
1070 | |
1071 | return pango_attr_int_new (klass: &klass, value: letter_spacing); |
1072 | } |
1073 | |
1074 | /** |
1075 | * pango_attr_shape_new_with_data: |
1076 | * @ink_rect: ink rectangle to assign to each character |
1077 | * @logical_rect: logical rectangle to assign to each character |
1078 | * @data: user data pointer |
1079 | * @copy_func: (nullable): function to copy @data when the |
1080 | * attribute is copied. If %NULL, @data is simply copied |
1081 | * as a pointer |
1082 | * @destroy_func: (nullable): function to free @data when the |
1083 | * attribute is freed |
1084 | * |
1085 | * Creates a new shape attribute. |
1086 | * |
1087 | * Like [func@Pango.AttrShape.new], but a user data pointer |
1088 | * is also provided; this pointer can be accessed when later |
1089 | * rendering the glyph. |
1090 | * |
1091 | * Return value: (transfer full): the newly allocated |
1092 | * `PangoAttribute`, which should be freed with |
1093 | * [method@Pango.Attribute.destroy] |
1094 | * |
1095 | * Since: 1.8 |
1096 | */ |
1097 | PangoAttribute * |
1098 | pango_attr_shape_new_with_data (const PangoRectangle *ink_rect, |
1099 | const PangoRectangle *logical_rect, |
1100 | gpointer data, |
1101 | PangoAttrDataCopyFunc copy_func, |
1102 | GDestroyNotify destroy_func) |
1103 | { |
1104 | static const PangoAttrClass klass = { |
1105 | PANGO_ATTR_SHAPE, |
1106 | pango_attr_shape_copy, |
1107 | pango_attr_shape_destroy, |
1108 | pango_attr_shape_equal |
1109 | }; |
1110 | |
1111 | PangoAttrShape *result; |
1112 | |
1113 | g_return_val_if_fail (ink_rect != NULL, NULL); |
1114 | g_return_val_if_fail (logical_rect != NULL, NULL); |
1115 | |
1116 | result = g_slice_new (PangoAttrShape); |
1117 | pango_attribute_init (attr: &result->attr, klass: &klass); |
1118 | result->ink_rect = *ink_rect; |
1119 | result->logical_rect = *logical_rect; |
1120 | result->data = data; |
1121 | result->copy_func = copy_func; |
1122 | result->destroy_func = destroy_func; |
1123 | |
1124 | return (PangoAttribute *)result; |
1125 | } |
1126 | |
1127 | /** |
1128 | * pango_attr_shape_new: |
1129 | * @ink_rect: ink rectangle to assign to each character |
1130 | * @logical_rect: logical rectangle to assign to each character |
1131 | * |
1132 | * Create a new shape attribute. |
1133 | * |
1134 | * A shape is used to impose a particular ink and logical |
1135 | * rectangle on the result of shaping a particular glyph. |
1136 | * This might be used, for instance, for embedding a picture |
1137 | * or a widget inside a `PangoLayout`. |
1138 | * |
1139 | * Return value: (transfer full): the newly allocated |
1140 | * `PangoAttribute`, which should be freed with |
1141 | * [method@Pango.Attribute.destroy] |
1142 | */ |
1143 | PangoAttribute * |
1144 | pango_attr_shape_new (const PangoRectangle *ink_rect, |
1145 | const PangoRectangle *logical_rect) |
1146 | { |
1147 | g_return_val_if_fail (ink_rect != NULL, NULL); |
1148 | g_return_val_if_fail (logical_rect != NULL, NULL); |
1149 | |
1150 | return pango_attr_shape_new_with_data (ink_rect, logical_rect, |
1151 | NULL, NULL, NULL); |
1152 | } |
1153 | |
1154 | /** |
1155 | * pango_attr_gravity_new: |
1156 | * @gravity: the gravity value; should not be %PANGO_GRAVITY_AUTO |
1157 | * |
1158 | * Create a new gravity attribute. |
1159 | * |
1160 | * Return value: (transfer full): the newly allocated |
1161 | * `PangoAttribute`, which should be freed with |
1162 | * [method@Pango.Attribute.destroy] |
1163 | * |
1164 | * Since: 1.16 |
1165 | */ |
1166 | PangoAttribute * |
1167 | pango_attr_gravity_new (PangoGravity gravity) |
1168 | { |
1169 | static const PangoAttrClass klass = { |
1170 | PANGO_ATTR_GRAVITY, |
1171 | pango_attr_int_copy, |
1172 | pango_attr_int_destroy, |
1173 | pango_attr_int_equal |
1174 | }; |
1175 | |
1176 | g_return_val_if_fail (gravity != PANGO_GRAVITY_AUTO, NULL); |
1177 | |
1178 | return pango_attr_int_new (klass: &klass, value: (int)gravity); |
1179 | } |
1180 | |
1181 | /** |
1182 | * pango_attr_gravity_hint_new: |
1183 | * @hint: the gravity hint value |
1184 | * |
1185 | * Create a new gravity hint attribute. |
1186 | * |
1187 | * Return value: (transfer full): the newly allocated |
1188 | * `PangoAttribute`, which should be freed with |
1189 | * [method@Pango.Attribute.destroy] |
1190 | * |
1191 | * Since: 1.16 |
1192 | */ |
1193 | PangoAttribute * |
1194 | pango_attr_gravity_hint_new (PangoGravityHint hint) |
1195 | { |
1196 | static const PangoAttrClass klass = { |
1197 | PANGO_ATTR_GRAVITY_HINT, |
1198 | pango_attr_int_copy, |
1199 | pango_attr_int_destroy, |
1200 | pango_attr_int_equal |
1201 | }; |
1202 | |
1203 | return pango_attr_int_new (klass: &klass, value: (int)hint); |
1204 | } |
1205 | |
1206 | /** |
1207 | * pango_attr_font_features_new: |
1208 | * @features: a string with OpenType font features, with the syntax of the [CSS |
1209 | * font-feature-settings property](https://www.w3.org/TR/css-fonts-4/#font-rend-desc) |
1210 | * |
1211 | * Create a new font features tag attribute. |
1212 | * |
1213 | * You can use this attribute to select OpenType font features like small-caps, |
1214 | * alternative glyphs, ligatures, etc. for fonts that support them. |
1215 | * |
1216 | * Return value: (transfer full): the newly allocated |
1217 | * `PangoAttribute`, which should be freed with |
1218 | * [method@Pango.Attribute.destroy] |
1219 | * |
1220 | * Since: 1.38 |
1221 | */ |
1222 | PangoAttribute * |
1223 | pango_attr_font_features_new (const gchar *features) |
1224 | { |
1225 | static const PangoAttrClass klass = { |
1226 | PANGO_ATTR_FONT_FEATURES, |
1227 | pango_attr_string_copy, |
1228 | pango_attr_string_destroy, |
1229 | pango_attr_string_equal |
1230 | }; |
1231 | |
1232 | g_return_val_if_fail (features != NULL, NULL); |
1233 | |
1234 | return pango_attr_string_new (klass: &klass, str: features); |
1235 | } |
1236 | |
1237 | /** |
1238 | * pango_attr_foreground_alpha_new: |
1239 | * @alpha: the alpha value, between 1 and 65536 |
1240 | * |
1241 | * Create a new foreground alpha attribute. |
1242 | * |
1243 | * Return value: (transfer full): the newly allocated |
1244 | * `PangoAttribute`, which should be freed with |
1245 | * [method@Pango.Attribute.destroy] |
1246 | * |
1247 | * Since: 1.38 |
1248 | */ |
1249 | PangoAttribute * |
1250 | pango_attr_foreground_alpha_new (guint16 alpha) |
1251 | { |
1252 | static const PangoAttrClass klass = { |
1253 | PANGO_ATTR_FOREGROUND_ALPHA, |
1254 | pango_attr_int_copy, |
1255 | pango_attr_int_destroy, |
1256 | pango_attr_int_equal |
1257 | }; |
1258 | |
1259 | return pango_attr_int_new (klass: &klass, value: (int)alpha); |
1260 | } |
1261 | |
1262 | /** |
1263 | * pango_attr_background_alpha_new: |
1264 | * @alpha: the alpha value, between 1 and 65536 |
1265 | * |
1266 | * Create a new background alpha attribute. |
1267 | * |
1268 | * Return value: (transfer full): the newly allocated |
1269 | * `PangoAttribute`, which should be freed with |
1270 | * [method@Pango.Attribute.destroy] |
1271 | * |
1272 | * Since: 1.38 |
1273 | */ |
1274 | PangoAttribute * |
1275 | pango_attr_background_alpha_new (guint16 alpha) |
1276 | { |
1277 | static const PangoAttrClass klass = { |
1278 | PANGO_ATTR_BACKGROUND_ALPHA, |
1279 | pango_attr_int_copy, |
1280 | pango_attr_int_destroy, |
1281 | pango_attr_int_equal |
1282 | }; |
1283 | |
1284 | return pango_attr_int_new (klass: &klass, value: (int)alpha); |
1285 | } |
1286 | |
1287 | /** |
1288 | * pango_attr_allow_breaks_new: |
1289 | * @allow_breaks: %TRUE if we line breaks are allowed |
1290 | * |
1291 | * Create a new allow-breaks attribute. |
1292 | * |
1293 | * If breaks are disabled, the range will be kept in a |
1294 | * single run, as far as possible. |
1295 | * |
1296 | * Return value: (transfer full): the newly allocated |
1297 | * `PangoAttribute`, which should be freed with |
1298 | * [method@Pango.Attribute.destroy] |
1299 | * |
1300 | * Since: 1.44 |
1301 | */ |
1302 | PangoAttribute * |
1303 | pango_attr_allow_breaks_new (gboolean allow_breaks) |
1304 | { |
1305 | static const PangoAttrClass klass = { |
1306 | PANGO_ATTR_ALLOW_BREAKS, |
1307 | pango_attr_int_copy, |
1308 | pango_attr_int_destroy, |
1309 | pango_attr_int_equal, |
1310 | }; |
1311 | |
1312 | return pango_attr_int_new (klass: &klass, value: (int)allow_breaks); |
1313 | } |
1314 | |
1315 | /** |
1316 | * pango_attr_insert_hyphens_new: |
1317 | * @insert_hyphens: %TRUE if hyphens should be inserted |
1318 | * |
1319 | * Create a new insert-hyphens attribute. |
1320 | * |
1321 | * Pango will insert hyphens when breaking lines in |
1322 | * the middle of a word. This attribute can be used |
1323 | * to suppress the hyphen. |
1324 | * |
1325 | * Return value: (transfer full): the newly allocated |
1326 | * `PangoAttribute`, which should be freed with |
1327 | * [method@Pango.Attribute.destroy] |
1328 | * |
1329 | * Since: 1.44 |
1330 | */ |
1331 | PangoAttribute * |
1332 | pango_attr_insert_hyphens_new (gboolean insert_hyphens) |
1333 | { |
1334 | static const PangoAttrClass klass = { |
1335 | PANGO_ATTR_INSERT_HYPHENS, |
1336 | pango_attr_int_copy, |
1337 | pango_attr_int_destroy, |
1338 | pango_attr_int_equal, |
1339 | }; |
1340 | |
1341 | return pango_attr_int_new (klass: &klass, value: (int)insert_hyphens); |
1342 | } |
1343 | |
1344 | /** |
1345 | * pango_attr_show_new: |
1346 | * @flags: `PangoShowFlags` to apply |
1347 | * |
1348 | * Create a new attribute that influences how invisible |
1349 | * characters are rendered. |
1350 | * |
1351 | * Return value: (transfer full): the newly allocated |
1352 | * `PangoAttribute`, which should be freed with |
1353 | * [method@Pango.Attribute.destroy] |
1354 | * |
1355 | * Since: 1.44 |
1356 | **/ |
1357 | PangoAttribute * |
1358 | pango_attr_show_new (PangoShowFlags flags) |
1359 | { |
1360 | static const PangoAttrClass klass = { |
1361 | PANGO_ATTR_SHOW, |
1362 | pango_attr_int_copy, |
1363 | pango_attr_int_destroy, |
1364 | pango_attr_int_equal, |
1365 | }; |
1366 | |
1367 | return pango_attr_int_new (klass: &klass, value: (int)flags); |
1368 | } |
1369 | |
1370 | /** |
1371 | * pango_attr_word_new: |
1372 | * |
1373 | * Marks the range of the attribute as a single word. |
1374 | * |
1375 | * Note that this may require adjustments to word and |
1376 | * sentence classification around the range. |
1377 | * |
1378 | * Return value: (transfer full): the newly allocated |
1379 | * `PangoAttribute`, which should be freed with |
1380 | * [method@Pango.Attribute.destroy] |
1381 | * |
1382 | * Since: 1.50 |
1383 | */ |
1384 | PangoAttribute * |
1385 | pango_attr_word_new (void) |
1386 | { |
1387 | static const PangoAttrClass klass = { |
1388 | PANGO_ATTR_WORD, |
1389 | pango_attr_int_copy, |
1390 | pango_attr_int_destroy, |
1391 | pango_attr_int_equal, |
1392 | }; |
1393 | |
1394 | return pango_attr_int_new (klass: &klass, value: 1); |
1395 | } |
1396 | |
1397 | /** |
1398 | * pango_attr_sentence_new: |
1399 | * |
1400 | * Marks the range of the attribute as a single sentence. |
1401 | * |
1402 | * Note that this may require adjustments to word and |
1403 | * sentence classification around the range. |
1404 | * |
1405 | * Return value: (transfer full): the newly allocated |
1406 | * `PangoAttribute`, which should be freed with |
1407 | * [method@Pango.Attribute.destroy] |
1408 | * |
1409 | * Since: 1.50 |
1410 | */ |
1411 | PangoAttribute * |
1412 | pango_attr_sentence_new (void) |
1413 | { |
1414 | static const PangoAttrClass klass = { |
1415 | PANGO_ATTR_SENTENCE, |
1416 | pango_attr_int_copy, |
1417 | pango_attr_int_destroy, |
1418 | pango_attr_int_equal, |
1419 | }; |
1420 | |
1421 | return pango_attr_int_new (klass: &klass, value: 1); |
1422 | } |
1423 | |
1424 | /** |
1425 | * pango_attr_overline_new: |
1426 | * @overline: the overline style |
1427 | * |
1428 | * Create a new overline-style attribute. |
1429 | * |
1430 | * Return value: (transfer full): the newly allocated |
1431 | * `PangoAttribute`, which should be freed with |
1432 | * [method@Pango.Attribute.destroy] |
1433 | * |
1434 | * Since: 1.46 |
1435 | */ |
1436 | PangoAttribute * |
1437 | pango_attr_overline_new (PangoOverline overline) |
1438 | { |
1439 | static const PangoAttrClass klass = { |
1440 | PANGO_ATTR_OVERLINE, |
1441 | pango_attr_int_copy, |
1442 | pango_attr_int_destroy, |
1443 | pango_attr_int_equal |
1444 | }; |
1445 | |
1446 | return pango_attr_int_new (klass: &klass, value: (int)overline); |
1447 | } |
1448 | |
1449 | /** |
1450 | * pango_attr_overline_color_new: |
1451 | * @red: the red value (ranging from 0 to 65535) |
1452 | * @green: the green value |
1453 | * @blue: the blue value |
1454 | * |
1455 | * Create a new overline color attribute. |
1456 | * |
1457 | * This attribute modifies the color of overlines. |
1458 | * If not set, overlines will use the foreground color. |
1459 | * |
1460 | * Return value: (transfer full): the newly allocated |
1461 | * `PangoAttribute`, which should be freed with |
1462 | * [method@Pango.Attribute.destroy] |
1463 | * |
1464 | * Since: 1.46 |
1465 | */ |
1466 | PangoAttribute * |
1467 | pango_attr_overline_color_new (guint16 red, |
1468 | guint16 green, |
1469 | guint16 blue) |
1470 | { |
1471 | static const PangoAttrClass klass = { |
1472 | PANGO_ATTR_OVERLINE_COLOR, |
1473 | pango_attr_color_copy, |
1474 | pango_attr_color_destroy, |
1475 | pango_attr_color_equal |
1476 | }; |
1477 | |
1478 | return pango_attr_color_new (klass: &klass, red, green, blue); |
1479 | } |
1480 | |
1481 | /** |
1482 | * pango_attr_line_height_new: |
1483 | * @factor: the scaling factor to apply to the logical height |
1484 | * |
1485 | * Modify the height of logical line extents by a factor. |
1486 | * |
1487 | * This affects the values returned by |
1488 | * [method@Pango.LayoutLine.get_extents], |
1489 | * [method@Pango.LayoutLine.get_pixel_extents] and |
1490 | * [method@Pango.LayoutIter.get_line_extents]. |
1491 | * |
1492 | * |
1493 | * Since: 1.50 |
1494 | */ |
1495 | PangoAttribute * |
1496 | pango_attr_line_height_new (double factor) |
1497 | { |
1498 | static const PangoAttrClass klass = { |
1499 | PANGO_ATTR_LINE_HEIGHT, |
1500 | pango_attr_float_copy, |
1501 | pango_attr_float_destroy, |
1502 | pango_attr_float_equal |
1503 | }; |
1504 | |
1505 | return pango_attr_float_new (klass: &klass, value: factor); |
1506 | } |
1507 | |
1508 | /** |
1509 | * pango_attr_line_height_new_absolute: |
1510 | * @height: the line height, in %PANGO_SCALE-ths of a point |
1511 | * |
1512 | * Override the height of logical line extents to be @height. |
1513 | * |
1514 | * This affects the values returned by |
1515 | * [method@Pango.LayoutLine.get_extents], |
1516 | * [method@Pango.LayoutLine.get_pixel_extents] and |
1517 | * [method@Pango.LayoutIter.get_line_extents]. |
1518 | * |
1519 | * Since: 1.50 |
1520 | */ |
1521 | PangoAttribute * |
1522 | pango_attr_line_height_new_absolute (int height) |
1523 | { |
1524 | static const PangoAttrClass klass = { |
1525 | PANGO_ATTR_ABSOLUTE_LINE_HEIGHT, |
1526 | pango_attr_int_copy, |
1527 | pango_attr_int_destroy, |
1528 | pango_attr_int_equal |
1529 | }; |
1530 | |
1531 | return pango_attr_int_new (klass: &klass, value: height); |
1532 | } |
1533 | |
1534 | /** |
1535 | * pango_attr_text_transform_new: |
1536 | * @transform: `PangoTextTransform` to apply |
1537 | * |
1538 | * Create a new attribute that influences how characters |
1539 | * are transformed during shaping. |
1540 | * |
1541 | * Return value: (transfer full): the newly allocated |
1542 | * `PangoAttribute`, which should be freed with |
1543 | * [method@Pango.Attribute.destroy] |
1544 | * |
1545 | * Since: 1.50 |
1546 | */ |
1547 | PangoAttribute * |
1548 | pango_attr_text_transform_new (PangoTextTransform transform) |
1549 | { |
1550 | static const PangoAttrClass klass = { |
1551 | PANGO_ATTR_TEXT_TRANSFORM, |
1552 | pango_attr_int_copy, |
1553 | pango_attr_int_destroy, |
1554 | pango_attr_int_equal |
1555 | }; |
1556 | |
1557 | return pango_attr_int_new (klass: &klass, value: transform); |
1558 | } |
1559 | /* }}} */ |
1560 | /* {{{ Binding helpers */ |
1561 | |
1562 | /** |
1563 | * pango_attribute_as_int: |
1564 | * @attr: A `PangoAttribute` such as weight |
1565 | * |
1566 | * Returns the attribute cast to `PangoAttrInt`. |
1567 | * |
1568 | * This is mainly useful for language bindings. |
1569 | * |
1570 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrInt`, |
1571 | * or %NULL if it's not an integer attribute |
1572 | * |
1573 | * Since: 1.50 |
1574 | */ |
1575 | PangoAttrInt * |
1576 | pango_attribute_as_int (PangoAttribute *attr) |
1577 | { |
1578 | switch ((int)attr->klass->type) |
1579 | { |
1580 | case PANGO_ATTR_STYLE: |
1581 | case PANGO_ATTR_WEIGHT: |
1582 | case PANGO_ATTR_VARIANT: |
1583 | case PANGO_ATTR_STRETCH: |
1584 | case PANGO_ATTR_UNDERLINE: |
1585 | case PANGO_ATTR_STRIKETHROUGH: |
1586 | case PANGO_ATTR_RISE: |
1587 | case PANGO_ATTR_FALLBACK: |
1588 | case PANGO_ATTR_LETTER_SPACING: |
1589 | case PANGO_ATTR_GRAVITY: |
1590 | case PANGO_ATTR_GRAVITY_HINT: |
1591 | case PANGO_ATTR_FOREGROUND_ALPHA: |
1592 | case PANGO_ATTR_BACKGROUND_ALPHA: |
1593 | case PANGO_ATTR_ALLOW_BREAKS: |
1594 | case PANGO_ATTR_SHOW: |
1595 | case PANGO_ATTR_INSERT_HYPHENS: |
1596 | case PANGO_ATTR_OVERLINE: |
1597 | case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: |
1598 | case PANGO_ATTR_TEXT_TRANSFORM: |
1599 | case PANGO_ATTR_WORD: |
1600 | case PANGO_ATTR_SENTENCE: |
1601 | case PANGO_ATTR_BASELINE_SHIFT: |
1602 | case PANGO_ATTR_FONT_SCALE: |
1603 | return (PangoAttrInt *)attr; |
1604 | |
1605 | default: |
1606 | return NULL; |
1607 | } |
1608 | } |
1609 | |
1610 | /** |
1611 | * pango_attribute_as_float: |
1612 | * @attr: A `PangoAttribute` such as scale |
1613 | * |
1614 | * Returns the attribute cast to `PangoAttrFloat`. |
1615 | * |
1616 | * This is mainly useful for language bindings. |
1617 | * |
1618 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrFloat`, |
1619 | * or %NULL if it's not a floating point attribute |
1620 | * |
1621 | * Since: 1.50 |
1622 | */ |
1623 | PangoAttrFloat * |
1624 | pango_attribute_as_float (PangoAttribute *attr) |
1625 | { |
1626 | switch ((int)attr->klass->type) |
1627 | { |
1628 | case PANGO_ATTR_SCALE: |
1629 | case PANGO_ATTR_LINE_HEIGHT: |
1630 | return (PangoAttrFloat *)attr; |
1631 | |
1632 | default: |
1633 | return NULL; |
1634 | } |
1635 | } |
1636 | |
1637 | /** |
1638 | * pango_attribute_as_string: |
1639 | * @attr: A `PangoAttribute` such as family |
1640 | * |
1641 | * Returns the attribute cast to `PangoAttrString`. |
1642 | * |
1643 | * This is mainly useful for language bindings. |
1644 | * |
1645 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrString`, |
1646 | * or %NULL if it's not a string attribute |
1647 | * |
1648 | * Since: 1.50 |
1649 | */ |
1650 | PangoAttrString * |
1651 | pango_attribute_as_string (PangoAttribute *attr) |
1652 | { |
1653 | switch ((int)attr->klass->type) |
1654 | { |
1655 | case PANGO_ATTR_FAMILY: |
1656 | return (PangoAttrString *)attr; |
1657 | |
1658 | default: |
1659 | return NULL; |
1660 | } |
1661 | } |
1662 | |
1663 | /** |
1664 | * pango_attribute_as_size: |
1665 | * @attr: A `PangoAttribute` representing a size |
1666 | * |
1667 | * Returns the attribute cast to `PangoAttrSize`. |
1668 | * |
1669 | * This is mainly useful for language bindings. |
1670 | * |
1671 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrSize`, |
1672 | * or NULL if it's not a size attribute |
1673 | * |
1674 | * Since: 1.50 |
1675 | */ |
1676 | PangoAttrSize * |
1677 | pango_attribute_as_size (PangoAttribute *attr) |
1678 | { |
1679 | switch ((int)attr->klass->type) |
1680 | { |
1681 | case PANGO_ATTR_SIZE: |
1682 | case PANGO_ATTR_ABSOLUTE_SIZE: |
1683 | return (PangoAttrSize *)attr; |
1684 | |
1685 | default: |
1686 | return NULL; |
1687 | } |
1688 | } |
1689 | |
1690 | /** |
1691 | * pango_attribute_as_color: |
1692 | * @attr: A `PangoAttribute` such as foreground |
1693 | * |
1694 | * Returns the attribute cast to `PangoAttrColor`. |
1695 | * |
1696 | * This is mainly useful for language bindings. |
1697 | * |
1698 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrColor`, |
1699 | * or %NULL if it's not a color attribute |
1700 | * |
1701 | * Since: 1.50 |
1702 | */ |
1703 | PangoAttrColor * |
1704 | pango_attribute_as_color (PangoAttribute *attr) |
1705 | { |
1706 | switch ((int)attr->klass->type) |
1707 | { |
1708 | case PANGO_ATTR_FOREGROUND: |
1709 | case PANGO_ATTR_BACKGROUND: |
1710 | case PANGO_ATTR_UNDERLINE_COLOR: |
1711 | case PANGO_ATTR_STRIKETHROUGH_COLOR: |
1712 | case PANGO_ATTR_OVERLINE_COLOR: |
1713 | return (PangoAttrColor *)attr; |
1714 | |
1715 | default: |
1716 | return NULL; |
1717 | } |
1718 | } |
1719 | |
1720 | /** |
1721 | * pango_attribute_as_font_desc: |
1722 | * @attr: A `PangoAttribute` representing a font description |
1723 | * |
1724 | * Returns the attribute cast to `PangoAttrFontDesc`. |
1725 | * |
1726 | * This is mainly useful for language bindings. |
1727 | * |
1728 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrFontDesc`, |
1729 | * or %NULL if it's not a font description attribute |
1730 | * |
1731 | * Since: 1.50 |
1732 | */ |
1733 | PangoAttrFontDesc * |
1734 | pango_attribute_as_font_desc (PangoAttribute *attr) |
1735 | { |
1736 | switch ((int)attr->klass->type) |
1737 | { |
1738 | case PANGO_ATTR_FONT_DESC: |
1739 | return (PangoAttrFontDesc *)attr; |
1740 | |
1741 | default: |
1742 | return NULL; |
1743 | } |
1744 | } |
1745 | |
1746 | /** |
1747 | * pango_attribute_as_font_features: |
1748 | * @attr: A `PangoAttribute` representing font features |
1749 | * |
1750 | * Returns the attribute cast to `PangoAttrFontFeatures`. |
1751 | * |
1752 | * This is mainly useful for language bindings. |
1753 | * |
1754 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrFontFeatures`, |
1755 | * or %NULL if it's not a font features attribute |
1756 | * |
1757 | * Since: 1.50 |
1758 | */ |
1759 | PangoAttrFontFeatures * |
1760 | pango_attribute_as_font_features (PangoAttribute *attr) |
1761 | { |
1762 | switch ((int)attr->klass->type) |
1763 | { |
1764 | case PANGO_ATTR_FONT_FEATURES: |
1765 | return (PangoAttrFontFeatures *)attr; |
1766 | |
1767 | default: |
1768 | return NULL; |
1769 | } |
1770 | } |
1771 | |
1772 | /** |
1773 | * pango_attribute_as_language: |
1774 | * @attr: A `PangoAttribute` representing a language |
1775 | * |
1776 | * Returns the attribute cast to `PangoAttrLanguage`. |
1777 | * |
1778 | * This is mainly useful for language bindings. |
1779 | * |
1780 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrLanguage`, |
1781 | * or %NULL if it's not a language attribute |
1782 | * |
1783 | * Since: 1.50 |
1784 | */ |
1785 | PangoAttrLanguage * |
1786 | pango_attribute_as_language (PangoAttribute *attr) |
1787 | { |
1788 | switch ((int)attr->klass->type) |
1789 | { |
1790 | case PANGO_ATTR_LANGUAGE: |
1791 | return (PangoAttrLanguage *)attr; |
1792 | |
1793 | default: |
1794 | return NULL; |
1795 | } |
1796 | } |
1797 | |
1798 | /** |
1799 | * pango_attribute_as_shape: |
1800 | * @attr: A `PangoAttribute` representing a shape |
1801 | * |
1802 | * Returns the attribute cast to `PangoAttrShape`. |
1803 | * |
1804 | * This is mainly useful for language bindings. |
1805 | * |
1806 | * Returns: (nullable) (transfer none): The attribute as `PangoAttrShape`, |
1807 | * or %NULL if it's not a shape attribute |
1808 | * |
1809 | * Since: 1.50 |
1810 | */ |
1811 | PangoAttrShape * |
1812 | pango_attribute_as_shape (PangoAttribute *attr) |
1813 | { |
1814 | switch ((int)attr->klass->type) |
1815 | { |
1816 | case PANGO_ATTR_SHAPE: |
1817 | return (PangoAttrShape *)attr; |
1818 | |
1819 | default: |
1820 | return NULL; |
1821 | } |
1822 | } |
1823 | |
1824 | /* }}} */ |
1825 | /* {{{ Attribute List */ |
1826 | |
1827 | G_DEFINE_BOXED_TYPE (PangoAttrList, pango_attr_list, |
1828 | pango_attr_list_copy, |
1829 | pango_attr_list_unref); |
1830 | |
1831 | void |
1832 | _pango_attr_list_init (PangoAttrList *list) |
1833 | { |
1834 | list->ref_count = 1; |
1835 | list->attributes = NULL; |
1836 | } |
1837 | |
1838 | /** |
1839 | * pango_attr_list_new: |
1840 | * |
1841 | * Create a new empty attribute list with a reference |
1842 | * count of one. |
1843 | * |
1844 | * Return value: (transfer full): the newly allocated |
1845 | * `PangoAttrList`, which should be freed with |
1846 | * [method@Pango.AttrList.unref] |
1847 | */ |
1848 | PangoAttrList * |
1849 | pango_attr_list_new (void) |
1850 | { |
1851 | PangoAttrList *list = g_slice_new (PangoAttrList); |
1852 | |
1853 | _pango_attr_list_init (list); |
1854 | |
1855 | return list; |
1856 | } |
1857 | |
1858 | /** |
1859 | * pango_attr_list_ref: |
1860 | * @list: (nullable): a `PangoAttrList` |
1861 | * |
1862 | * Increase the reference count of the given attribute |
1863 | * list by one. |
1864 | * |
1865 | * Return value: The attribute list passed in |
1866 | * |
1867 | * Since: 1.10 |
1868 | */ |
1869 | PangoAttrList * |
1870 | pango_attr_list_ref (PangoAttrList *list) |
1871 | { |
1872 | if (list == NULL) |
1873 | return NULL; |
1874 | |
1875 | g_atomic_int_inc ((int *) &list->ref_count); |
1876 | |
1877 | return list; |
1878 | } |
1879 | |
1880 | void |
1881 | _pango_attr_list_destroy (PangoAttrList *list) |
1882 | { |
1883 | guint i, p; |
1884 | |
1885 | if (!list->attributes) |
1886 | return; |
1887 | |
1888 | for (i = 0, p = list->attributes->len; i < p; i++) |
1889 | { |
1890 | PangoAttribute *attr = g_ptr_array_index (list->attributes, i); |
1891 | |
1892 | attr->klass->destroy (attr); |
1893 | } |
1894 | |
1895 | g_ptr_array_free (array: list->attributes, TRUE); |
1896 | } |
1897 | |
1898 | /** |
1899 | * pango_attr_list_unref: |
1900 | * @list: (nullable): a `PangoAttrList` |
1901 | * |
1902 | * Decrease the reference count of the given attribute |
1903 | * list by one. |
1904 | * |
1905 | * If the result is zero, free the attribute list |
1906 | * and the attributes it contains. |
1907 | */ |
1908 | void |
1909 | pango_attr_list_unref (PangoAttrList *list) |
1910 | { |
1911 | if (list == NULL) |
1912 | return; |
1913 | |
1914 | g_return_if_fail (list->ref_count > 0); |
1915 | |
1916 | if (g_atomic_int_dec_and_test ((int *) &list->ref_count)) |
1917 | { |
1918 | _pango_attr_list_destroy (list); |
1919 | g_slice_free (PangoAttrList, list); |
1920 | } |
1921 | } |
1922 | |
1923 | /** |
1924 | * pango_attr_list_copy: |
1925 | * @list: (nullable): a `PangoAttrList` |
1926 | * |
1927 | * Copy @list and return an identical new list. |
1928 | * |
1929 | * Return value: (nullable): the newly allocated |
1930 | * `PangoAttrList`, with a reference count of one, |
1931 | * which should be freed with [method@Pango.AttrList.unref]. |
1932 | * Returns %NULL if @list was %NULL. |
1933 | */ |
1934 | PangoAttrList * |
1935 | pango_attr_list_copy (PangoAttrList *list) |
1936 | { |
1937 | PangoAttrList *new; |
1938 | |
1939 | if (list == NULL) |
1940 | return NULL; |
1941 | |
1942 | new = pango_attr_list_new (); |
1943 | if (!list->attributes || list->attributes->len == 0) |
1944 | return new; |
1945 | |
1946 | new->attributes = g_ptr_array_copy (array: list->attributes, func: (GCopyFunc)pango_attribute_copy, NULL); |
1947 | |
1948 | return new; |
1949 | } |
1950 | |
1951 | static void |
1952 | pango_attr_list_insert_internal (PangoAttrList *list, |
1953 | PangoAttribute *attr, |
1954 | gboolean before) |
1955 | { |
1956 | const guint start_index = attr->start_index; |
1957 | PangoAttribute *last_attr; |
1958 | |
1959 | if (G_UNLIKELY (!list->attributes)) |
1960 | list->attributes = g_ptr_array_new (); |
1961 | |
1962 | if (list->attributes->len == 0) |
1963 | { |
1964 | g_ptr_array_add (array: list->attributes, data: attr); |
1965 | return; |
1966 | } |
1967 | |
1968 | g_assert (list->attributes->len > 0); |
1969 | |
1970 | last_attr = g_ptr_array_index (list->attributes, list->attributes->len - 1); |
1971 | |
1972 | if (last_attr->start_index < start_index || |
1973 | (!before && last_attr->start_index == start_index)) |
1974 | { |
1975 | g_ptr_array_add (array: list->attributes, data: attr); |
1976 | } |
1977 | else |
1978 | { |
1979 | guint i, p; |
1980 | |
1981 | for (i = 0, p = list->attributes->len; i < p; i++) |
1982 | { |
1983 | PangoAttribute *cur = g_ptr_array_index (list->attributes, i); |
1984 | |
1985 | if (cur->start_index > start_index || |
1986 | (before && cur->start_index == start_index)) |
1987 | { |
1988 | g_ptr_array_insert (array: list->attributes, index_: i, data: attr); |
1989 | break; |
1990 | } |
1991 | } |
1992 | } |
1993 | } |
1994 | |
1995 | /** |
1996 | * pango_attr_list_insert: |
1997 | * @list: a `PangoAttrList` |
1998 | * @attr: (transfer full): the attribute to insert |
1999 | * |
2000 | * Insert the given attribute into the `PangoAttrList`. |
2001 | * |
2002 | * It will be inserted after all other attributes with a |
2003 | * matching @start_index. |
2004 | */ |
2005 | void |
2006 | pango_attr_list_insert (PangoAttrList *list, |
2007 | PangoAttribute *attr) |
2008 | { |
2009 | g_return_if_fail (list != NULL); |
2010 | g_return_if_fail (attr != NULL); |
2011 | |
2012 | pango_attr_list_insert_internal (list, attr, FALSE); |
2013 | } |
2014 | |
2015 | /** |
2016 | * pango_attr_list_insert_before: |
2017 | * @list: a `PangoAttrList` |
2018 | * @attr: (transfer full): the attribute to insert |
2019 | * |
2020 | * Insert the given attribute into the `PangoAttrList`. |
2021 | * |
2022 | * It will be inserted before all other attributes with a |
2023 | * matching @start_index. |
2024 | */ |
2025 | void |
2026 | pango_attr_list_insert_before (PangoAttrList *list, |
2027 | PangoAttribute *attr) |
2028 | { |
2029 | g_return_if_fail (list != NULL); |
2030 | g_return_if_fail (attr != NULL); |
2031 | |
2032 | pango_attr_list_insert_internal (list, attr, TRUE); |
2033 | } |
2034 | |
2035 | /** |
2036 | * pango_attr_list_change: |
2037 | * @list: a `PangoAttrList` |
2038 | * @attr: (transfer full): the attribute to insert |
2039 | * |
2040 | * Insert the given attribute into the `PangoAttrList`. |
2041 | * |
2042 | * It will replace any attributes of the same type |
2043 | * on that segment and be merged with any adjoining |
2044 | * attributes that are identical. |
2045 | * |
2046 | * This function is slower than [method@Pango.AttrList.insert] |
2047 | * for creating an attribute list in order (potentially |
2048 | * much slower for large lists). However, |
2049 | * [method@Pango.AttrList.insert] is not suitable for |
2050 | * continually changing a set of attributes since it |
2051 | * never removes or combines existing attributes. |
2052 | */ |
2053 | void |
2054 | pango_attr_list_change (PangoAttrList *list, |
2055 | PangoAttribute *attr) |
2056 | { |
2057 | guint i, p; |
2058 | guint start_index = attr->start_index; |
2059 | guint end_index = attr->end_index; |
2060 | gboolean inserted; |
2061 | |
2062 | g_return_if_fail (list != NULL); |
2063 | |
2064 | if (start_index == end_index) /* empty, nothing to do */ |
2065 | { |
2066 | pango_attribute_destroy (attr); |
2067 | return; |
2068 | } |
2069 | |
2070 | if (!list->attributes || list->attributes->len == 0) |
2071 | { |
2072 | pango_attr_list_insert (list, attr); |
2073 | return; |
2074 | } |
2075 | |
2076 | inserted = FALSE; |
2077 | for (i = 0, p = list->attributes->len; i < p; i++) |
2078 | { |
2079 | PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); |
2080 | |
2081 | if (tmp_attr->start_index > start_index) |
2082 | { |
2083 | g_ptr_array_insert (array: list->attributes, index_: i, data: attr); |
2084 | inserted = TRUE; |
2085 | break; |
2086 | } |
2087 | |
2088 | if (tmp_attr->klass->type != attr->klass->type) |
2089 | continue; |
2090 | |
2091 | if (tmp_attr->end_index < start_index) |
2092 | continue; /* This attr does not overlap with the new one */ |
2093 | |
2094 | g_assert (tmp_attr->start_index <= start_index); |
2095 | g_assert (tmp_attr->end_index >= start_index); |
2096 | |
2097 | if (pango_attribute_equal (attr1: tmp_attr, attr2: attr)) |
2098 | { |
2099 | /* We can merge the new attribute with this attribute |
2100 | */ |
2101 | if (tmp_attr->end_index >= end_index) |
2102 | { |
2103 | /* We are totally overlapping the previous attribute. |
2104 | * No action is needed. |
2105 | */ |
2106 | pango_attribute_destroy (attr); |
2107 | return; |
2108 | } |
2109 | |
2110 | tmp_attr->end_index = end_index; |
2111 | pango_attribute_destroy (attr); |
2112 | |
2113 | attr = tmp_attr; |
2114 | inserted = TRUE; |
2115 | break; |
2116 | } |
2117 | else |
2118 | { |
2119 | /* Split, truncate, or remove the old attribute |
2120 | */ |
2121 | if (tmp_attr->end_index > end_index) |
2122 | { |
2123 | PangoAttribute *end_attr = pango_attribute_copy (attr: tmp_attr); |
2124 | |
2125 | end_attr->start_index = end_index; |
2126 | pango_attr_list_insert (list, attr: end_attr); |
2127 | } |
2128 | |
2129 | if (tmp_attr->start_index == start_index) |
2130 | { |
2131 | pango_attribute_destroy (attr: tmp_attr); |
2132 | g_ptr_array_remove_index (array: list->attributes, index_: i); |
2133 | break; |
2134 | } |
2135 | else |
2136 | { |
2137 | tmp_attr->end_index = start_index; |
2138 | } |
2139 | } |
2140 | } |
2141 | |
2142 | if (!inserted) |
2143 | /* we didn't insert attr yet */ |
2144 | pango_attr_list_insert (list, attr); |
2145 | |
2146 | /* We now have the range inserted into the list one way or the |
2147 | * other. Fix up the remainder |
2148 | */ |
2149 | /* Attention: No i = 0 here. */ |
2150 | for (i = i + 1, p = list->attributes->len; i < p; i++) |
2151 | { |
2152 | PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); |
2153 | |
2154 | if (tmp_attr->start_index > end_index) |
2155 | break; |
2156 | |
2157 | if (tmp_attr->klass->type != attr->klass->type) |
2158 | continue; |
2159 | |
2160 | if (tmp_attr == attr) |
2161 | continue; |
2162 | |
2163 | if (tmp_attr->end_index <= attr->end_index || |
2164 | pango_attribute_equal (attr1: tmp_attr, attr2: attr)) |
2165 | { |
2166 | /* We can merge the new attribute with this attribute. */ |
2167 | attr->end_index = MAX (end_index, tmp_attr->end_index); |
2168 | pango_attribute_destroy (attr: tmp_attr); |
2169 | g_ptr_array_remove_index (array: list->attributes, index_: i); |
2170 | i--; |
2171 | p--; |
2172 | continue; |
2173 | } |
2174 | else |
2175 | { |
2176 | /* Trim the start of this attribute that it begins at the end |
2177 | * of the new attribute. This may involve moving it in the list |
2178 | * to maintain the required non-decreasing order of start indices. |
2179 | */ |
2180 | int k, m; |
2181 | |
2182 | tmp_attr->start_index = attr->end_index; |
2183 | |
2184 | for (k = i + 1, m = list->attributes->len; k < m; k++) |
2185 | { |
2186 | PangoAttribute *tmp_attr2 = g_ptr_array_index (list->attributes, k); |
2187 | |
2188 | if (tmp_attr2->start_index >= tmp_attr->start_index) |
2189 | break; |
2190 | |
2191 | g_ptr_array_index (list->attributes, k - 1) = tmp_attr2; |
2192 | g_ptr_array_index (list->attributes, k) = tmp_attr; |
2193 | } |
2194 | } |
2195 | } |
2196 | } |
2197 | |
2198 | /** |
2199 | * pango_attr_list_update: |
2200 | * @list: a `PangoAttrList` |
2201 | * @pos: the position of the change |
2202 | * @remove: the number of removed bytes |
2203 | * @add: the number of added bytes |
2204 | * |
2205 | * Update indices of attributes in @list for a change in the |
2206 | * text they refer to. |
2207 | * |
2208 | * The change that this function applies is removing @remove |
2209 | * bytes at position @pos and inserting @add bytes instead. |
2210 | * |
2211 | * Attributes that fall entirely in the (@pos, @pos + @remove) |
2212 | * range are removed. |
2213 | * |
2214 | * Attributes that start or end inside the (@pos, @pos + @remove) |
2215 | * range are shortened to reflect the removal. |
2216 | * |
2217 | * Attributes start and end positions are updated if they are |
2218 | * behind @pos + @remove. |
2219 | * |
2220 | * Since: 1.44 |
2221 | */ |
2222 | void |
2223 | pango_attr_list_update (PangoAttrList *list, |
2224 | int pos, |
2225 | int remove, |
2226 | int add) |
2227 | { |
2228 | guint i, p; |
2229 | |
2230 | g_return_if_fail (pos >= 0); |
2231 | g_return_if_fail (remove >= 0); |
2232 | g_return_if_fail (add >= 0); |
2233 | |
2234 | if (list->attributes) |
2235 | for (i = 0, p = list->attributes->len; i < p; i++) |
2236 | { |
2237 | PangoAttribute *attr = g_ptr_array_index (list->attributes, i); |
2238 | |
2239 | if (attr->start_index >= pos && |
2240 | attr->end_index < pos + remove) |
2241 | { |
2242 | pango_attribute_destroy (attr); |
2243 | g_ptr_array_remove_index (array: list->attributes, index_: i); |
2244 | i--; /* Look at this index again */ |
2245 | p--; |
2246 | continue; |
2247 | } |
2248 | |
2249 | if (attr->start_index != PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING) |
2250 | { |
2251 | if (attr->start_index >= pos && |
2252 | attr->start_index < pos + remove) |
2253 | { |
2254 | attr->start_index = pos + add; |
2255 | } |
2256 | else if (attr->start_index >= pos + remove) |
2257 | { |
2258 | attr->start_index += add - remove; |
2259 | } |
2260 | } |
2261 | |
2262 | if (attr->end_index != PANGO_ATTR_INDEX_TO_TEXT_END) |
2263 | { |
2264 | if (attr->end_index >= pos && |
2265 | attr->end_index < pos + remove) |
2266 | { |
2267 | attr->end_index = pos; |
2268 | } |
2269 | else if (attr->end_index >= pos + remove) |
2270 | { |
2271 | if (add > remove && |
2272 | G_MAXUINT - attr->end_index < add - remove) |
2273 | attr->end_index = G_MAXUINT; |
2274 | else |
2275 | attr->end_index += add - remove; |
2276 | } |
2277 | } |
2278 | } |
2279 | } |
2280 | |
2281 | /** |
2282 | * pango_attr_list_splice: |
2283 | * @list: a `PangoAttrList` |
2284 | * @other: another `PangoAttrList` |
2285 | * @pos: the position in @list at which to insert @other |
2286 | * @len: the length of the spliced segment. (Note that this |
2287 | * must be specified since the attributes in @other may only |
2288 | * be present at some subsection of this range) |
2289 | * |
2290 | * This function opens up a hole in @list, fills it |
2291 | * in with attributes from the left, and then merges |
2292 | * @other on top of the hole. |
2293 | * |
2294 | * This operation is equivalent to stretching every attribute |
2295 | * that applies at position @pos in @list by an amount @len, |
2296 | * and then calling [method@Pango.AttrList.change] with a copy |
2297 | * of each attribute in @other in sequence (offset in position |
2298 | * by @pos, and limited in length to @len). |
2299 | * |
2300 | * This operation proves useful for, for instance, inserting |
2301 | * a pre-edit string in the middle of an edit buffer. |
2302 | * |
2303 | * For backwards compatibility, the function behaves differently |
2304 | * when @len is 0. In this case, the attributes from @other are |
2305 | * not imited to @len, and are just overlayed on top of @list. |
2306 | * |
2307 | * This mode is useful for merging two lists of attributes together. |
2308 | */ |
2309 | void |
2310 | pango_attr_list_splice (PangoAttrList *list, |
2311 | PangoAttrList *other, |
2312 | gint pos, |
2313 | gint len) |
2314 | { |
2315 | guint i, p; |
2316 | guint upos, ulen; |
2317 | guint end; |
2318 | |
2319 | g_return_if_fail (list != NULL); |
2320 | g_return_if_fail (other != NULL); |
2321 | g_return_if_fail (pos >= 0); |
2322 | g_return_if_fail (len >= 0); |
2323 | |
2324 | upos = (guint)pos; |
2325 | ulen = (guint)len; |
2326 | |
2327 | /* This definition only works when a and b are unsigned; overflow |
2328 | * isn't defined in the C standard for signed integers |
2329 | */ |
2330 | #define CLAMP_ADD(a,b) (((a) + (b) < (a)) ? G_MAXUINT : (a) + (b)) |
2331 | |
2332 | end = CLAMP_ADD (upos, ulen); |
2333 | |
2334 | if (list->attributes) |
2335 | for (i = 0, p = list->attributes->len; i < p; i++) |
2336 | { |
2337 | PangoAttribute *attr = g_ptr_array_index (list->attributes, i);; |
2338 | |
2339 | if (attr->start_index <= upos) |
2340 | { |
2341 | if (attr->end_index > upos) |
2342 | attr->end_index = CLAMP_ADD (attr->end_index, ulen); |
2343 | } |
2344 | else |
2345 | { |
2346 | /* This could result in a zero length attribute if it |
2347 | * gets squashed up against G_MAXUINT, but deleting such |
2348 | * an element could (in theory) suprise the caller, so |
2349 | * we don't delete it. |
2350 | */ |
2351 | attr->start_index = CLAMP_ADD (attr->start_index, ulen); |
2352 | attr->end_index = CLAMP_ADD (attr->end_index, ulen); |
2353 | } |
2354 | } |
2355 | |
2356 | if (!other->attributes || other->attributes->len == 0) |
2357 | return; |
2358 | |
2359 | for (i = 0, p = other->attributes->len; i < p; i++) |
2360 | { |
2361 | PangoAttribute *attr = pango_attribute_copy (g_ptr_array_index (other->attributes, i)); |
2362 | if (ulen > 0) |
2363 | { |
2364 | attr->start_index = MIN (CLAMP_ADD (attr->start_index, upos), end); |
2365 | attr->end_index = MIN (CLAMP_ADD (attr->end_index, upos), end); |
2366 | } |
2367 | else |
2368 | { |
2369 | attr->start_index = CLAMP_ADD (attr->start_index, upos); |
2370 | attr->end_index = CLAMP_ADD (attr->end_index, upos); |
2371 | } |
2372 | |
2373 | /* Same as above, the attribute could be squashed to zero-length; here |
2374 | * pango_attr_list_change() will take care of deleting it. |
2375 | */ |
2376 | pango_attr_list_change (list, attr); |
2377 | } |
2378 | #undef CLAMP_ADD |
2379 | } |
2380 | |
2381 | /** |
2382 | * pango_attr_list_get_attributes: |
2383 | * @list: a `PangoAttrList` |
2384 | * |
2385 | * Gets a list of all attributes in @list. |
2386 | * |
2387 | * Return value: (element-type Pango.Attribute) (transfer full): |
2388 | * a list of all attributes in @list. To free this value, |
2389 | * call [method@Pango.Attribute.destroy] on each value and |
2390 | * g_slist_free() on the list. |
2391 | * |
2392 | * Since: 1.44 |
2393 | */ |
2394 | GSList * |
2395 | pango_attr_list_get_attributes (PangoAttrList *list) |
2396 | { |
2397 | GSList *result = NULL; |
2398 | guint i, p; |
2399 | |
2400 | g_return_val_if_fail (list != NULL, NULL); |
2401 | |
2402 | if (!list->attributes || list->attributes->len == 0) |
2403 | return NULL; |
2404 | |
2405 | for (i = 0, p = list->attributes->len; i < p; i++) |
2406 | { |
2407 | PangoAttribute *attr = g_ptr_array_index (list->attributes, i); |
2408 | |
2409 | result = g_slist_prepend (list: result, data: pango_attribute_copy (attr)); |
2410 | } |
2411 | |
2412 | return g_slist_reverse (list: result); |
2413 | } |
2414 | |
2415 | /** |
2416 | * pango_attr_list_equal: |
2417 | * @list: a `PangoAttrList` |
2418 | * @other_list: the other `PangoAttrList` |
2419 | * |
2420 | * Checks whether @list and @other_list contain the same |
2421 | * attributes and whether those attributes apply to the |
2422 | * same ranges. |
2423 | * |
2424 | * Beware that this will return wrong values if any list |
2425 | * contains duplicates. |
2426 | * |
2427 | * Return value: %TRUE if the lists are equal, %FALSE if |
2428 | * they aren't |
2429 | * |
2430 | * Since: 1.46 |
2431 | */ |
2432 | gboolean |
2433 | pango_attr_list_equal (PangoAttrList *list, |
2434 | PangoAttrList *other_list) |
2435 | { |
2436 | GPtrArray *attrs, *other_attrs; |
2437 | guint64 skip_bitmask = 0; |
2438 | guint i; |
2439 | |
2440 | if (list == other_list) |
2441 | return TRUE; |
2442 | |
2443 | if (list == NULL || other_list == NULL) |
2444 | return FALSE; |
2445 | |
2446 | if (list->attributes == NULL || other_list->attributes == NULL) |
2447 | return list->attributes == other_list->attributes; |
2448 | |
2449 | attrs = list->attributes; |
2450 | other_attrs = other_list->attributes; |
2451 | |
2452 | if (attrs->len != other_attrs->len) |
2453 | return FALSE; |
2454 | |
2455 | for (i = 0; i < attrs->len; i++) |
2456 | { |
2457 | PangoAttribute *attr = g_ptr_array_index (attrs, i); |
2458 | gboolean attr_equal = FALSE; |
2459 | guint other_attr_index; |
2460 | |
2461 | for (other_attr_index = 0; other_attr_index < other_attrs->len; other_attr_index++) |
2462 | { |
2463 | PangoAttribute *other_attr = g_ptr_array_index (other_attrs, other_attr_index); |
2464 | guint64 other_attr_bitmask = other_attr_index < 64 ? 1 << other_attr_index : 0; |
2465 | |
2466 | if ((skip_bitmask & other_attr_bitmask) != 0) |
2467 | continue; |
2468 | |
2469 | if (attr->start_index == other_attr->start_index && |
2470 | attr->end_index == other_attr->end_index && |
2471 | pango_attribute_equal (attr1: attr, attr2: other_attr)) |
2472 | { |
2473 | skip_bitmask |= other_attr_bitmask; |
2474 | attr_equal = TRUE; |
2475 | break; |
2476 | } |
2477 | |
2478 | } |
2479 | |
2480 | if (!attr_equal) |
2481 | return FALSE; |
2482 | } |
2483 | |
2484 | return TRUE; |
2485 | } |
2486 | |
2487 | gboolean |
2488 | _pango_attr_list_has_attributes (const PangoAttrList *list) |
2489 | { |
2490 | return list && list->attributes != NULL && list->attributes->len > 0; |
2491 | } |
2492 | |
2493 | /** |
2494 | * pango_attr_list_filter: |
2495 | * @list: a `PangoAttrList` |
2496 | * @func: (scope call) (closure data): callback function; |
2497 | * returns %TRUE if an attribute should be filtered out |
2498 | * @data: (closure): Data to be passed to @func |
2499 | * |
2500 | * Given a `PangoAttrList` and callback function, removes |
2501 | * any elements of @list for which @func returns %TRUE and |
2502 | * inserts them into a new list. |
2503 | * |
2504 | * Return value: (transfer full) (nullable): the new |
2505 | * `PangoAttrList` or %NULL if no attributes of the |
2506 | * given types were found |
2507 | * |
2508 | * Since: 1.2 |
2509 | */ |
2510 | PangoAttrList * |
2511 | pango_attr_list_filter (PangoAttrList *list, |
2512 | PangoAttrFilterFunc func, |
2513 | gpointer data) |
2514 | |
2515 | { |
2516 | PangoAttrList *new = NULL; |
2517 | guint i, p; |
2518 | |
2519 | g_return_val_if_fail (list != NULL, NULL); |
2520 | |
2521 | if (!list->attributes || list->attributes->len == 0) |
2522 | return NULL; |
2523 | |
2524 | for (i = 0, p = list->attributes->len; i < p; i++) |
2525 | { |
2526 | PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); |
2527 | |
2528 | if ((*func) (tmp_attr, data)) |
2529 | { |
2530 | g_ptr_array_remove_index (array: list->attributes, index_: i); |
2531 | i--; /* Need to look at this index again */ |
2532 | p--; |
2533 | |
2534 | if (G_UNLIKELY (!new)) |
2535 | { |
2536 | new = pango_attr_list_new (); |
2537 | new->attributes = g_ptr_array_new (); |
2538 | } |
2539 | |
2540 | g_ptr_array_add (array: new->attributes, data: tmp_attr); |
2541 | } |
2542 | } |
2543 | |
2544 | return new; |
2545 | } |
2546 | |
2547 | /* {{{ PangoAttrList serialization */ |
2548 | |
2549 | /* We serialize attribute lists to strings. The format |
2550 | * is a comma-separated list of the attributes in the order |
2551 | * in which they are in the list, with each attribute having |
2552 | * this format: |
2553 | * |
2554 | * START END NICK VALUE |
2555 | * |
2556 | * Values that can contain a comma, such as font descriptions |
2557 | * are quoted with "". |
2558 | */ |
2559 | |
2560 | static const char * |
2561 | get_attr_type_nick (PangoAttrType attr_type) |
2562 | { |
2563 | GEnumClass *enum_class; |
2564 | GEnumValue *enum_value; |
2565 | |
2566 | enum_class = g_type_class_ref (type: pango_attr_type_get_type ()); |
2567 | enum_value = g_enum_get_value (enum_class, value: attr_type); |
2568 | g_type_class_unref (g_class: enum_class); |
2569 | |
2570 | return enum_value->value_nick; |
2571 | } |
2572 | |
2573 | static GType |
2574 | get_attr_value_type (PangoAttrType type) |
2575 | { |
2576 | switch ((int)type) |
2577 | { |
2578 | case PANGO_ATTR_STYLE: return PANGO_TYPE_STYLE; |
2579 | case PANGO_ATTR_WEIGHT: return PANGO_TYPE_WEIGHT; |
2580 | case PANGO_ATTR_VARIANT: return PANGO_TYPE_VARIANT; |
2581 | case PANGO_ATTR_STRETCH: return PANGO_TYPE_STRETCH; |
2582 | case PANGO_ATTR_GRAVITY: return PANGO_TYPE_GRAVITY; |
2583 | case PANGO_ATTR_GRAVITY_HINT: return PANGO_TYPE_GRAVITY_HINT; |
2584 | case PANGO_ATTR_UNDERLINE: return PANGO_TYPE_UNDERLINE; |
2585 | case PANGO_ATTR_OVERLINE: return PANGO_TYPE_OVERLINE; |
2586 | case PANGO_ATTR_BASELINE_SHIFT: return PANGO_TYPE_BASELINE_SHIFT; |
2587 | case PANGO_ATTR_FONT_SCALE: return PANGO_TYPE_FONT_SCALE; |
2588 | case PANGO_ATTR_TEXT_TRANSFORM: return PANGO_TYPE_TEXT_TRANSFORM; |
2589 | default: return G_TYPE_INVALID; |
2590 | } |
2591 | } |
2592 | |
2593 | static void |
2594 | append_enum_value (GString *str, |
2595 | GType type, |
2596 | int value) |
2597 | { |
2598 | GEnumClass *enum_class; |
2599 | GEnumValue *enum_value; |
2600 | |
2601 | enum_class = g_type_class_ref (type); |
2602 | enum_value = g_enum_get_value (enum_class, value); |
2603 | g_type_class_unref (g_class: enum_class); |
2604 | |
2605 | if (enum_value) |
2606 | g_string_append_printf (string: str, format: " %s" , enum_value->value_nick); |
2607 | else |
2608 | g_string_append_printf (string: str, format: " %d" , value); |
2609 | } |
2610 | |
2611 | static void |
2612 | attr_print (GString *str, |
2613 | PangoAttribute *attr) |
2614 | { |
2615 | PangoAttrString *string; |
2616 | PangoAttrLanguage *lang; |
2617 | PangoAttrInt *integer; |
2618 | PangoAttrFloat *flt; |
2619 | PangoAttrFontDesc *font; |
2620 | PangoAttrColor *color; |
2621 | PangoAttrShape *shape; |
2622 | PangoAttrSize *size; |
2623 | PangoAttrFontFeatures *features; |
2624 | |
2625 | g_string_append_printf (string: str, format: "%u %u " , attr->start_index, attr->end_index); |
2626 | |
2627 | g_string_append (string: str, val: get_attr_type_nick (attr_type: attr->klass->type)); |
2628 | |
2629 | if (attr->klass->type == PANGO_ATTR_WEIGHT || |
2630 | attr->klass->type == PANGO_ATTR_STYLE || |
2631 | attr->klass->type == PANGO_ATTR_STRETCH || |
2632 | attr->klass->type == PANGO_ATTR_VARIANT || |
2633 | attr->klass->type == PANGO_ATTR_GRAVITY || |
2634 | attr->klass->type == PANGO_ATTR_GRAVITY_HINT || |
2635 | attr->klass->type == PANGO_ATTR_UNDERLINE || |
2636 | attr->klass->type == PANGO_ATTR_OVERLINE || |
2637 | attr->klass->type == PANGO_ATTR_BASELINE_SHIFT || |
2638 | attr->klass->type == PANGO_ATTR_FONT_SCALE || |
2639 | attr->klass->type == PANGO_ATTR_TEXT_TRANSFORM) |
2640 | append_enum_value (str, type: get_attr_value_type (type: attr->klass->type), value: ((PangoAttrInt *)attr)->value); |
2641 | else if (attr->klass->type == PANGO_ATTR_STRIKETHROUGH || |
2642 | attr->klass->type == PANGO_ATTR_ALLOW_BREAKS || |
2643 | attr->klass->type == PANGO_ATTR_INSERT_HYPHENS || |
2644 | attr->klass->type == PANGO_ATTR_FALLBACK) |
2645 | g_string_append (string: str, val: ((PangoAttrInt *)attr)->value ? " true" : " false" ); |
2646 | else if ((string = pango_attribute_as_string (attr)) != NULL) |
2647 | g_string_append_printf (string: str, format: " %s" , string->value); |
2648 | else if ((lang = pango_attribute_as_language (attr)) != NULL) |
2649 | g_string_append_printf (string: str, format: " %s" , pango_language_to_string (lang->value)); |
2650 | else if ((integer = pango_attribute_as_int (attr)) != NULL) |
2651 | g_string_append_printf (string: str, format: " %d" , integer->value); |
2652 | else if ((flt = pango_attribute_as_float (attr)) != NULL) |
2653 | { |
2654 | char buf[20]; |
2655 | g_ascii_formatd (buffer: buf, buf_len: 20, format: "%f" , d: flt->value); |
2656 | g_string_append_printf (string: str, format: " %s" , buf); |
2657 | } |
2658 | else if ((font = pango_attribute_as_font_desc (attr)) != NULL) |
2659 | { |
2660 | char *s = pango_font_description_to_string (desc: font->desc); |
2661 | g_string_append_printf (string: str, format: " \"%s\"" , s); |
2662 | g_free (mem: s); |
2663 | } |
2664 | else if ((color = pango_attribute_as_color (attr)) != NULL) |
2665 | { |
2666 | char *s = pango_color_to_string (color: &color->color); |
2667 | g_string_append_printf (string: str, format: " %s" , s); |
2668 | g_free (mem: s); |
2669 | } |
2670 | else if ((shape = pango_attribute_as_shape (attr)) != NULL) |
2671 | g_string_append (string: str, val: "shape" ); /* FIXME */ |
2672 | else if ((size = pango_attribute_as_size (attr)) != NULL) |
2673 | g_string_append_printf (string: str, format: " %d" , size->size); |
2674 | else if ((features = pango_attribute_as_font_features (attr)) != NULL) |
2675 | g_string_append_printf (string: str, format: " \"%s\"" , features->features); |
2676 | else |
2677 | g_assert_not_reached (); |
2678 | } |
2679 | |
2680 | /** |
2681 | * pango_attr_list_to_string: |
2682 | * @list: a `PangoAttrList` |
2683 | * |
2684 | * Serializes a `PangoAttrList` to a string. |
2685 | * |
2686 | * No guarantees are made about the format of the string, |
2687 | * it may change between Pango versions. |
2688 | * |
2689 | * The intended use of this function is testing and |
2690 | * debugging. The format is not meant as a permanent |
2691 | * storage format. |
2692 | * |
2693 | * Returns: (transfer full): a newly allocated string |
2694 | * Since: 1.50 |
2695 | */ |
2696 | char * |
2697 | pango_attr_list_to_string (PangoAttrList *list) |
2698 | { |
2699 | GString *s; |
2700 | |
2701 | s = g_string_new (init: "" ); |
2702 | |
2703 | if (list->attributes) |
2704 | for (int i = 0; i < list->attributes->len; i++) |
2705 | { |
2706 | PangoAttribute *attr = g_ptr_array_index (list->attributes, i); |
2707 | |
2708 | if (i > 0) |
2709 | g_string_append (string: s, val: "\n" ); |
2710 | attr_print (str: s, attr); |
2711 | } |
2712 | |
2713 | return g_string_free (string: s, FALSE); |
2714 | } |
2715 | |
2716 | static PangoAttrType |
2717 | get_attr_type_by_nick (const char *nick, |
2718 | int len) |
2719 | { |
2720 | GEnumClass *enum_class; |
2721 | |
2722 | enum_class = g_type_class_ref (type: pango_attr_type_get_type ()); |
2723 | for (GEnumValue *ev = enum_class->values; ev->value_name; ev++) |
2724 | { |
2725 | if (ev->value_nick && strncmp (s1: ev->value_nick, s2: nick, n: len) == 0) |
2726 | { |
2727 | g_type_class_unref (g_class: enum_class); |
2728 | return (PangoAttrType) ev->value; |
2729 | } |
2730 | } |
2731 | |
2732 | g_type_class_unref (g_class: enum_class); |
2733 | return PANGO_ATTR_INVALID; |
2734 | } |
2735 | |
2736 | static int |
2737 | get_attr_value (PangoAttrType type, |
2738 | const char *str, |
2739 | int len) |
2740 | { |
2741 | GEnumClass *enum_class; |
2742 | char *endp; |
2743 | int value; |
2744 | |
2745 | enum_class = g_type_class_ref (type: get_attr_value_type (type)); |
2746 | for (GEnumValue *ev = enum_class->values; ev->value_name; ev++) |
2747 | { |
2748 | if (ev->value_nick && strncmp (s1: ev->value_nick, s2: str, n: len) == 0) |
2749 | { |
2750 | g_type_class_unref (g_class: enum_class); |
2751 | return ev->value; |
2752 | } |
2753 | } |
2754 | g_type_class_unref (g_class: enum_class); |
2755 | |
2756 | value = g_ascii_strtoll (nptr: str, endptr: &endp, base: 10); |
2757 | if (endp - str == len) |
2758 | return value; |
2759 | |
2760 | return -1; |
2761 | } |
2762 | |
2763 | static gboolean |
2764 | is_valid_end_char (char c) |
2765 | { |
2766 | return c == ',' || c == '\n' || c == '\0'; |
2767 | } |
2768 | |
2769 | /** |
2770 | * pango_attr_list_from_string: |
2771 | * @text: a string |
2772 | * |
2773 | * Deserializes a `PangoAttrList` from a string. |
2774 | * |
2775 | * This is the counterpart to [method@Pango.AttrList.to_string]. |
2776 | * See that functions for details about the format. |
2777 | * |
2778 | * Returns: (transfer full) (nullable): a new `PangoAttrList` |
2779 | * Since: 1.50 |
2780 | */ |
2781 | PangoAttrList * |
2782 | pango_attr_list_from_string (const char *text) |
2783 | { |
2784 | PangoAttrList *list; |
2785 | const char *p; |
2786 | |
2787 | g_return_val_if_fail (text != NULL, NULL); |
2788 | |
2789 | list = pango_attr_list_new (); |
2790 | |
2791 | if (*text == '\0') |
2792 | return list; |
2793 | |
2794 | list->attributes = g_ptr_array_new (); |
2795 | |
2796 | p = text + strspn (s: text, accept: " \t\n" ); |
2797 | while (*p) |
2798 | { |
2799 | char *endp; |
2800 | gint64 start_index; |
2801 | gint64 end_index; |
2802 | char *str; |
2803 | PangoAttrType attr_type; |
2804 | PangoAttribute *attr; |
2805 | PangoLanguage *lang; |
2806 | gint64 integer; |
2807 | PangoFontDescription *desc; |
2808 | PangoColor color; |
2809 | double num; |
2810 | |
2811 | start_index = g_ascii_strtoll (nptr: p, endptr: &endp, base: 10); |
2812 | if (*endp != ' ') |
2813 | goto fail; |
2814 | |
2815 | p = endp + strspn (s: endp, accept: " " ); |
2816 | if (!*p) |
2817 | goto fail; |
2818 | |
2819 | end_index = g_ascii_strtoll (nptr: p, endptr: &endp, base: 10); |
2820 | if (*endp != ' ') |
2821 | goto fail; |
2822 | |
2823 | p = endp + strspn (s: endp, accept: " " ); |
2824 | |
2825 | endp = (char *)p + strcspn (s: p, reject: " " ); |
2826 | attr_type = get_attr_type_by_nick (nick: p, len: endp - p); |
2827 | |
2828 | p = endp + strspn (s: endp, accept: " " ); |
2829 | if (*p == '\0') |
2830 | goto fail; |
2831 | |
2832 | #define INT_ATTR(name,type) \ |
2833 | integer = g_ascii_strtoll (p, &endp, 10); \ |
2834 | if (!is_valid_end_char (*endp)) goto fail; \ |
2835 | attr = pango_attr_##name##_new ((type)integer); |
2836 | |
2837 | #define BOOLEAN_ATTR(name,type) \ |
2838 | if (strncmp (p, "true", strlen ("true")) == 0) \ |
2839 | { \ |
2840 | integer = 1; \ |
2841 | endp = (char *)(p + strlen ("true")); \ |
2842 | } \ |
2843 | else if (strncmp (p, "false", strlen ("false")) == 0) \ |
2844 | { \ |
2845 | integer = 0; \ |
2846 | endp = (char *)(p + strlen ("false")); \ |
2847 | } \ |
2848 | else \ |
2849 | integer = g_ascii_strtoll (p, &endp, 10); \ |
2850 | if (!is_valid_end_char (*endp)) goto fail; \ |
2851 | attr = pango_attr_##name##_new ((type)integer); |
2852 | |
2853 | #define ENUM_ATTR(name, type, min, max) \ |
2854 | endp = (char *)p + strcspn (p, ",\n"); \ |
2855 | integer = get_attr_value (attr_type, p, endp - p); \ |
2856 | attr = pango_attr_##name##_new ((type) CLAMP (integer, min, max)); |
2857 | |
2858 | #define FLOAT_ATTR(name) \ |
2859 | num = g_ascii_strtod (p, &endp); \ |
2860 | if (!is_valid_end_char (*endp)) goto fail; \ |
2861 | attr = pango_attr_##name##_new ((float)num); |
2862 | |
2863 | #define COLOR_ATTR(name) \ |
2864 | endp = (char *)p + strcspn (p, ",\n"); \ |
2865 | if (!is_valid_end_char (*endp)) goto fail; \ |
2866 | str = g_strndup (p, endp - p); \ |
2867 | if (!pango_color_parse (&color, str)) \ |
2868 | { \ |
2869 | g_free (str); \ |
2870 | goto fail; \ |
2871 | } \ |
2872 | attr = pango_attr_##name##_new (color.red, color.green, color.blue); \ |
2873 | g_free (str); |
2874 | |
2875 | switch (attr_type) |
2876 | { |
2877 | case PANGO_ATTR_INVALID: |
2878 | pango_attr_list_unref (list); |
2879 | return NULL; |
2880 | |
2881 | case PANGO_ATTR_LANGUAGE: |
2882 | endp = (char *)p + strcspn (s: p, reject: ",\n" ); |
2883 | if (!is_valid_end_char (c: *endp)) goto fail; |
2884 | str = g_strndup (str: p, n: endp - p); |
2885 | lang = pango_language_from_string (language: str); |
2886 | attr = pango_attr_language_new (language: lang); |
2887 | g_free (mem: str); |
2888 | break; |
2889 | |
2890 | case PANGO_ATTR_FAMILY: |
2891 | endp = (char *)p + strcspn (s: p, reject: ",\n" ); |
2892 | if (!is_valid_end_char (c: *endp)) goto fail; |
2893 | str = g_strndup (str: p, n: endp - p); |
2894 | attr = pango_attr_family_new (family: str); |
2895 | g_free (mem: str); |
2896 | break; |
2897 | |
2898 | case PANGO_ATTR_STYLE: |
2899 | ENUM_ATTR(style, PangoStyle, PANGO_STYLE_NORMAL, PANGO_STYLE_ITALIC); |
2900 | break; |
2901 | |
2902 | case PANGO_ATTR_WEIGHT: |
2903 | ENUM_ATTR(weight, PangoWeight, PANGO_WEIGHT_THIN, PANGO_WEIGHT_ULTRAHEAVY); |
2904 | break; |
2905 | |
2906 | case PANGO_ATTR_VARIANT: |
2907 | ENUM_ATTR(variant, PangoVariant, PANGO_VARIANT_NORMAL, PANGO_VARIANT_TITLE_CAPS); |
2908 | break; |
2909 | |
2910 | case PANGO_ATTR_STRETCH: |
2911 | ENUM_ATTR(stretch, PangoStretch, PANGO_STRETCH_ULTRA_CONDENSED, PANGO_STRETCH_ULTRA_EXPANDED); |
2912 | break; |
2913 | |
2914 | case PANGO_ATTR_SIZE: |
2915 | INT_ATTR(size, int); |
2916 | break; |
2917 | |
2918 | case PANGO_ATTR_FONT_DESC: |
2919 | p++; |
2920 | endp = strchr (s: p, c: '"'); |
2921 | if (!endp) goto fail; |
2922 | str = g_strndup (str: p, n: endp - p); |
2923 | desc = pango_font_description_from_string (str); |
2924 | attr = pango_attr_font_desc_new (desc); |
2925 | pango_font_description_free (desc); |
2926 | g_free (mem: str); |
2927 | endp++; |
2928 | if (!is_valid_end_char (c: *endp)) goto fail; |
2929 | break; |
2930 | |
2931 | case PANGO_ATTR_FOREGROUND: |
2932 | COLOR_ATTR(foreground); |
2933 | break; |
2934 | |
2935 | case PANGO_ATTR_BACKGROUND: |
2936 | COLOR_ATTR(background); |
2937 | break; |
2938 | |
2939 | case PANGO_ATTR_UNDERLINE: |
2940 | ENUM_ATTR(underline, PangoUnderline, PANGO_UNDERLINE_NONE, PANGO_UNDERLINE_ERROR_LINE); |
2941 | break; |
2942 | |
2943 | case PANGO_ATTR_STRIKETHROUGH: |
2944 | BOOLEAN_ATTR(strikethrough, gboolean); |
2945 | break; |
2946 | |
2947 | case PANGO_ATTR_RISE: |
2948 | INT_ATTR(rise, int); |
2949 | break; |
2950 | |
2951 | case PANGO_ATTR_SHAPE: |
2952 | endp = (char *)p + strcspn (s: p, reject: ",\n" ); |
2953 | continue; /* FIXME */ |
2954 | |
2955 | case PANGO_ATTR_SCALE: |
2956 | FLOAT_ATTR(scale); |
2957 | break; |
2958 | |
2959 | case PANGO_ATTR_FALLBACK: |
2960 | BOOLEAN_ATTR(fallback, gboolean); |
2961 | break; |
2962 | |
2963 | case PANGO_ATTR_LETTER_SPACING: |
2964 | INT_ATTR(letter_spacing, int); |
2965 | break; |
2966 | |
2967 | case PANGO_ATTR_UNDERLINE_COLOR: |
2968 | COLOR_ATTR(underline_color); |
2969 | break; |
2970 | |
2971 | case PANGO_ATTR_STRIKETHROUGH_COLOR: |
2972 | COLOR_ATTR(strikethrough_color); |
2973 | break; |
2974 | |
2975 | case PANGO_ATTR_ABSOLUTE_SIZE: |
2976 | integer = g_ascii_strtoll (nptr: p, endptr: &endp, base: 10); |
2977 | if (!is_valid_end_char (c: *endp)) goto fail; |
2978 | attr = pango_attr_size_new_absolute (size: integer); |
2979 | break; |
2980 | |
2981 | case PANGO_ATTR_GRAVITY: |
2982 | ENUM_ATTR(gravity, PangoGravity, PANGO_GRAVITY_SOUTH, PANGO_GRAVITY_WEST); |
2983 | break; |
2984 | |
2985 | case PANGO_ATTR_FONT_FEATURES: |
2986 | p++; |
2987 | endp = strchr (s: p, c: '"'); |
2988 | if (!endp) goto fail; |
2989 | str = g_strndup (str: p, n: endp - p); |
2990 | attr = pango_attr_font_features_new (features: str); |
2991 | g_free (mem: str); |
2992 | endp++; |
2993 | if (!is_valid_end_char (c: *endp)) goto fail; |
2994 | break; |
2995 | |
2996 | case PANGO_ATTR_GRAVITY_HINT: |
2997 | ENUM_ATTR(gravity_hint, PangoGravityHint, PANGO_GRAVITY_HINT_NATURAL, PANGO_GRAVITY_HINT_LINE); |
2998 | break; |
2999 | |
3000 | case PANGO_ATTR_FOREGROUND_ALPHA: |
3001 | INT_ATTR(foreground_alpha, int); |
3002 | break; |
3003 | |
3004 | case PANGO_ATTR_BACKGROUND_ALPHA: |
3005 | INT_ATTR(background_alpha, int); |
3006 | break; |
3007 | |
3008 | case PANGO_ATTR_ALLOW_BREAKS: |
3009 | BOOLEAN_ATTR(allow_breaks, gboolean); |
3010 | break; |
3011 | |
3012 | case PANGO_ATTR_SHOW: |
3013 | INT_ATTR(show, PangoShowFlags); |
3014 | break; |
3015 | |
3016 | case PANGO_ATTR_INSERT_HYPHENS: |
3017 | BOOLEAN_ATTR(insert_hyphens, gboolean); |
3018 | break; |
3019 | |
3020 | case PANGO_ATTR_OVERLINE: |
3021 | ENUM_ATTR(overline, PangoOverline, PANGO_OVERLINE_NONE, PANGO_OVERLINE_SINGLE); |
3022 | break; |
3023 | |
3024 | case PANGO_ATTR_OVERLINE_COLOR: |
3025 | COLOR_ATTR(overline_color); |
3026 | break; |
3027 | |
3028 | case PANGO_ATTR_LINE_HEIGHT: |
3029 | FLOAT_ATTR(line_height); |
3030 | break; |
3031 | |
3032 | case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: |
3033 | integer = g_ascii_strtoll (nptr: p, endptr: &endp, base: 10); |
3034 | if (!is_valid_end_char (c: *endp)) goto fail; |
3035 | attr = pango_attr_line_height_new_absolute (height: integer); |
3036 | break; |
3037 | |
3038 | case PANGO_ATTR_TEXT_TRANSFORM: |
3039 | ENUM_ATTR(text_transform, PangoTextTransform, PANGO_TEXT_TRANSFORM_NONE, PANGO_TEXT_TRANSFORM_CAPITALIZE); |
3040 | break; |
3041 | |
3042 | case PANGO_ATTR_WORD: |
3043 | integer = g_ascii_strtoll (nptr: p, endptr: &endp, base: 10); |
3044 | if (!is_valid_end_char (c: *endp)) goto fail; |
3045 | attr = pango_attr_word_new (); |
3046 | break; |
3047 | |
3048 | case PANGO_ATTR_SENTENCE: |
3049 | integer = g_ascii_strtoll (nptr: p, endptr: &endp, base: 10); |
3050 | if (!is_valid_end_char (c: *endp)) goto fail; |
3051 | attr = pango_attr_sentence_new (); |
3052 | break; |
3053 | |
3054 | case PANGO_ATTR_BASELINE_SHIFT: |
3055 | ENUM_ATTR(baseline_shift, PangoBaselineShift, 0, G_MAXINT); |
3056 | break; |
3057 | |
3058 | case PANGO_ATTR_FONT_SCALE: |
3059 | ENUM_ATTR(font_scale, PangoFontScale, PANGO_FONT_SCALE_NONE, PANGO_FONT_SCALE_SMALL_CAPS); |
3060 | break; |
3061 | |
3062 | default: |
3063 | g_assert_not_reached (); |
3064 | } |
3065 | |
3066 | attr->start_index = (guint)start_index; |
3067 | attr->end_index = (guint)end_index; |
3068 | g_ptr_array_add (array: list->attributes, data: attr); |
3069 | |
3070 | p = endp; |
3071 | if (*p) |
3072 | { |
3073 | if (*p == ',') |
3074 | p++; |
3075 | p += strspn (s: p, accept: " \n" ); |
3076 | } |
3077 | } |
3078 | |
3079 | goto success; |
3080 | |
3081 | fail: |
3082 | pango_attr_list_unref (list); |
3083 | list = NULL; |
3084 | |
3085 | success: |
3086 | return list; |
3087 | } |
3088 | |
3089 | /* }}} */ |
3090 | /* {{{ Attribute Iterator */ |
3091 | |
3092 | G_DEFINE_BOXED_TYPE (PangoAttrIterator, |
3093 | pango_attr_iterator, |
3094 | pango_attr_iterator_copy, |
3095 | pango_attr_iterator_destroy) |
3096 | |
3097 | void |
3098 | _pango_attr_list_get_iterator (PangoAttrList *list, |
3099 | PangoAttrIterator *iterator) |
3100 | { |
3101 | iterator->attribute_stack = NULL; |
3102 | iterator->attrs = list->attributes; |
3103 | iterator->n_attrs = iterator->attrs ? iterator->attrs->len : 0; |
3104 | |
3105 | iterator->attr_index = 0; |
3106 | iterator->start_index = 0; |
3107 | iterator->end_index = 0; |
3108 | |
3109 | if (!pango_attr_iterator_next (iterator)) |
3110 | iterator->end_index = G_MAXUINT; |
3111 | } |
3112 | |
3113 | /** |
3114 | * pango_attr_list_get_iterator: |
3115 | * @list: a `PangoAttrList` |
3116 | * |
3117 | * Create a iterator initialized to the beginning of the list. |
3118 | * |
3119 | * @list must not be modified until this iterator is freed. |
3120 | * |
3121 | * Return value: (transfer full): the newly allocated |
3122 | * `PangoAttrIterator`, which should be freed with |
3123 | * [method@Pango.AttrIterator.destroy] |
3124 | */ |
3125 | PangoAttrIterator * |
3126 | pango_attr_list_get_iterator (PangoAttrList *list) |
3127 | { |
3128 | PangoAttrIterator *iterator; |
3129 | |
3130 | g_return_val_if_fail (list != NULL, NULL); |
3131 | |
3132 | iterator = g_slice_new (PangoAttrIterator); |
3133 | _pango_attr_list_get_iterator (list, iterator); |
3134 | |
3135 | return iterator; |
3136 | } |
3137 | |
3138 | /** |
3139 | * pango_attr_iterator_range: |
3140 | * @iterator: a PangoAttrIterator |
3141 | * @start: (out): location to store the start of the range |
3142 | * @end: (out): location to store the end of the range |
3143 | * |
3144 | * Get the range of the current segment. |
3145 | * |
3146 | * Note that the stored return values are signed, not unsigned |
3147 | * like the values in `PangoAttribute`. To deal with this API |
3148 | * oversight, stored return values that wouldn't fit into |
3149 | * a signed integer are clamped to %G_MAXINT. |
3150 | */ |
3151 | void |
3152 | pango_attr_iterator_range (PangoAttrIterator *iterator, |
3153 | gint *start, |
3154 | gint *end) |
3155 | { |
3156 | g_return_if_fail (iterator != NULL); |
3157 | |
3158 | if (start) |
3159 | *start = MIN (iterator->start_index, G_MAXINT); |
3160 | if (end) |
3161 | *end = MIN (iterator->end_index, G_MAXINT); |
3162 | } |
3163 | |
3164 | /** |
3165 | * pango_attr_iterator_next: |
3166 | * @iterator: a `PangoAttrIterator` |
3167 | * |
3168 | * Advance the iterator until the next change of style. |
3169 | * |
3170 | * Return value: %FALSE if the iterator is at the end |
3171 | * of the list, otherwise %TRUE |
3172 | */ |
3173 | gboolean |
3174 | pango_attr_iterator_next (PangoAttrIterator *iterator) |
3175 | { |
3176 | int i; |
3177 | |
3178 | g_return_val_if_fail (iterator != NULL, FALSE); |
3179 | |
3180 | if (iterator->attr_index >= iterator->n_attrs && |
3181 | (!iterator->attribute_stack || iterator->attribute_stack->len == 0)) |
3182 | return FALSE; |
3183 | |
3184 | iterator->start_index = iterator->end_index; |
3185 | iterator->end_index = G_MAXUINT; |
3186 | |
3187 | if (iterator->attribute_stack) |
3188 | { |
3189 | for (i = iterator->attribute_stack->len - 1; i>= 0; i--) |
3190 | { |
3191 | const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); |
3192 | |
3193 | if (attr->end_index == iterator->start_index) |
3194 | g_ptr_array_remove_index (array: iterator->attribute_stack, index_: i); /* Can't use index_fast :( */ |
3195 | else |
3196 | iterator->end_index = MIN (iterator->end_index, attr->end_index); |
3197 | } |
3198 | } |
3199 | |
3200 | while (1) |
3201 | { |
3202 | PangoAttribute *attr; |
3203 | |
3204 | if (iterator->attr_index >= iterator->n_attrs) |
3205 | break; |
3206 | |
3207 | attr = g_ptr_array_index (iterator->attrs, iterator->attr_index); |
3208 | |
3209 | if (attr->start_index != iterator->start_index) |
3210 | break; |
3211 | |
3212 | if (attr->end_index > iterator->start_index) |
3213 | { |
3214 | if (G_UNLIKELY (!iterator->attribute_stack)) |
3215 | iterator->attribute_stack = g_ptr_array_new (); |
3216 | |
3217 | g_ptr_array_add (array: iterator->attribute_stack, data: attr); |
3218 | |
3219 | iterator->end_index = MIN (iterator->end_index, attr->end_index); |
3220 | } |
3221 | |
3222 | iterator->attr_index++; /* NEXT! */ |
3223 | } |
3224 | |
3225 | if (iterator->attr_index < iterator->n_attrs) |
3226 | { |
3227 | PangoAttribute *attr = g_ptr_array_index (iterator->attrs, iterator->attr_index); |
3228 | |
3229 | iterator->end_index = MIN (iterator->end_index, attr->start_index); |
3230 | } |
3231 | |
3232 | return TRUE; |
3233 | } |
3234 | |
3235 | /** |
3236 | * pango_attr_iterator_copy: |
3237 | * @iterator: a `PangoAttrIterator` |
3238 | * |
3239 | * Copy a `PangoAttrIterator`. |
3240 | * |
3241 | * Return value: (transfer full): the newly allocated |
3242 | * `PangoAttrIterator`, which should be freed with |
3243 | * [method@Pango.AttrIterator.destroy] |
3244 | */ |
3245 | PangoAttrIterator * |
3246 | pango_attr_iterator_copy (PangoAttrIterator *iterator) |
3247 | { |
3248 | PangoAttrIterator *copy; |
3249 | |
3250 | g_return_val_if_fail (iterator != NULL, NULL); |
3251 | |
3252 | copy = g_slice_new (PangoAttrIterator); |
3253 | |
3254 | *copy = *iterator; |
3255 | |
3256 | if (iterator->attribute_stack) |
3257 | copy->attribute_stack = g_ptr_array_copy (array: iterator->attribute_stack, NULL, NULL); |
3258 | else |
3259 | copy->attribute_stack = NULL; |
3260 | |
3261 | return copy; |
3262 | } |
3263 | |
3264 | void |
3265 | _pango_attr_iterator_destroy (PangoAttrIterator *iterator) |
3266 | { |
3267 | if (iterator->attribute_stack) |
3268 | g_ptr_array_free (array: iterator->attribute_stack, TRUE); |
3269 | } |
3270 | |
3271 | /** |
3272 | * pango_attr_iterator_destroy: |
3273 | * @iterator: a `PangoAttrIterator` |
3274 | * |
3275 | * Destroy a `PangoAttrIterator` and free all associated memory. |
3276 | */ |
3277 | void |
3278 | pango_attr_iterator_destroy (PangoAttrIterator *iterator) |
3279 | { |
3280 | g_return_if_fail (iterator != NULL); |
3281 | |
3282 | _pango_attr_iterator_destroy (iterator); |
3283 | g_slice_free (PangoAttrIterator, iterator); |
3284 | } |
3285 | |
3286 | /** |
3287 | * pango_attr_iterator_get: |
3288 | * @iterator: a `PangoAttrIterator` |
3289 | * @type: the type of attribute to find |
3290 | * |
3291 | * Find the current attribute of a particular type |
3292 | * at the iterator location. |
3293 | * |
3294 | * When multiple attributes of the same type overlap, |
3295 | * the attribute whose range starts closest to the |
3296 | * current location is used. |
3297 | * |
3298 | * Return value: (nullable) (transfer none): the current |
3299 | * attribute of the given type, or %NULL if no attribute |
3300 | * of that type applies to the current location. |
3301 | */ |
3302 | PangoAttribute * |
3303 | pango_attr_iterator_get (PangoAttrIterator *iterator, |
3304 | PangoAttrType type) |
3305 | { |
3306 | int i; |
3307 | |
3308 | g_return_val_if_fail (iterator != NULL, NULL); |
3309 | |
3310 | if (!iterator->attribute_stack) |
3311 | return NULL; |
3312 | |
3313 | for (i = iterator->attribute_stack->len - 1; i>= 0; i--) |
3314 | { |
3315 | PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); |
3316 | |
3317 | if (attr->klass->type == type) |
3318 | return attr; |
3319 | } |
3320 | |
3321 | return NULL; |
3322 | } |
3323 | |
3324 | /** |
3325 | * pango_attr_iterator_get_font: |
3326 | * @iterator: a `PangoAttrIterator` |
3327 | * @desc: a `PangoFontDescription` to fill in with the current |
3328 | * values. The family name in this structure will be set using |
3329 | * [method@Pango.FontDescription.set_family_static] using |
3330 | * values from an attribute in the `PangoAttrList` associated |
3331 | * with the iterator, so if you plan to keep it around, you |
3332 | * must call: |
3333 | * `pango_font_description_set_family (desc, pango_font_description_get_family (desc))`. |
3334 | * @language: (out) (optional): location to store language tag |
3335 | * for item, or %NULL if none is found. |
3336 | * @extra_attrs: (out) (optional) (element-type Pango.Attribute) (transfer full): |
3337 | * location in which to store a list of non-font attributes |
3338 | * at the the current position; only the highest priority |
3339 | * value of each attribute will be added to this list. In |
3340 | * order to free this value, you must call |
3341 | * [method@Pango.Attribute.destroy] on each member. |
3342 | * |
3343 | * Get the font and other attributes at the current |
3344 | * iterator position. |
3345 | */ |
3346 | void |
3347 | pango_attr_iterator_get_font (PangoAttrIterator *iterator, |
3348 | PangoFontDescription *desc, |
3349 | PangoLanguage **language, |
3350 | GSList **) |
3351 | { |
3352 | PangoFontMask mask = 0; |
3353 | gboolean have_language = FALSE; |
3354 | gdouble scale = 0; |
3355 | gboolean have_scale = FALSE; |
3356 | int i; |
3357 | |
3358 | g_return_if_fail (iterator != NULL); |
3359 | g_return_if_fail (desc != NULL); |
3360 | |
3361 | if (language) |
3362 | *language = NULL; |
3363 | |
3364 | if (extra_attrs) |
3365 | *extra_attrs = NULL; |
3366 | |
3367 | if (!iterator->attribute_stack) |
3368 | return; |
3369 | |
3370 | for (i = iterator->attribute_stack->len - 1; i >= 0; i--) |
3371 | { |
3372 | const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); |
3373 | |
3374 | switch ((int) attr->klass->type) |
3375 | { |
3376 | case PANGO_ATTR_FONT_DESC: |
3377 | { |
3378 | PangoFontMask new_mask = pango_font_description_get_set_fields (desc: ((PangoAttrFontDesc *)attr)->desc) & ~mask; |
3379 | mask |= new_mask; |
3380 | pango_font_description_unset_fields (desc, to_unset: new_mask); |
3381 | pango_font_description_merge_static (desc, desc_to_merge: ((PangoAttrFontDesc *)attr)->desc, FALSE); |
3382 | |
3383 | break; |
3384 | } |
3385 | case PANGO_ATTR_FAMILY: |
3386 | if (!(mask & PANGO_FONT_MASK_FAMILY)) |
3387 | { |
3388 | mask |= PANGO_FONT_MASK_FAMILY; |
3389 | pango_font_description_set_family (desc, family: ((PangoAttrString *)attr)->value); |
3390 | } |
3391 | break; |
3392 | case PANGO_ATTR_STYLE: |
3393 | if (!(mask & PANGO_FONT_MASK_STYLE)) |
3394 | { |
3395 | mask |= PANGO_FONT_MASK_STYLE; |
3396 | pango_font_description_set_style (desc, style: ((PangoAttrInt *)attr)->value); |
3397 | } |
3398 | break; |
3399 | case PANGO_ATTR_VARIANT: |
3400 | if (!(mask & PANGO_FONT_MASK_VARIANT)) |
3401 | { |
3402 | mask |= PANGO_FONT_MASK_VARIANT; |
3403 | pango_font_description_set_variant (desc, variant: ((PangoAttrInt *)attr)->value); |
3404 | } |
3405 | break; |
3406 | case PANGO_ATTR_WEIGHT: |
3407 | if (!(mask & PANGO_FONT_MASK_WEIGHT)) |
3408 | { |
3409 | mask |= PANGO_FONT_MASK_WEIGHT; |
3410 | pango_font_description_set_weight (desc, weight: ((PangoAttrInt *)attr)->value); |
3411 | } |
3412 | break; |
3413 | case PANGO_ATTR_STRETCH: |
3414 | if (!(mask & PANGO_FONT_MASK_STRETCH)) |
3415 | { |
3416 | mask |= PANGO_FONT_MASK_STRETCH; |
3417 | pango_font_description_set_stretch (desc, stretch: ((PangoAttrInt *)attr)->value); |
3418 | } |
3419 | break; |
3420 | case PANGO_ATTR_SIZE: |
3421 | if (!(mask & PANGO_FONT_MASK_SIZE)) |
3422 | { |
3423 | mask |= PANGO_FONT_MASK_SIZE; |
3424 | pango_font_description_set_size (desc, size: ((PangoAttrSize *)attr)->size); |
3425 | } |
3426 | break; |
3427 | case PANGO_ATTR_ABSOLUTE_SIZE: |
3428 | if (!(mask & PANGO_FONT_MASK_SIZE)) |
3429 | { |
3430 | mask |= PANGO_FONT_MASK_SIZE; |
3431 | pango_font_description_set_absolute_size (desc, size: ((PangoAttrSize *)attr)->size); |
3432 | } |
3433 | break; |
3434 | case PANGO_ATTR_SCALE: |
3435 | if (!have_scale) |
3436 | { |
3437 | have_scale = TRUE; |
3438 | scale = ((PangoAttrFloat *)attr)->value; |
3439 | } |
3440 | break; |
3441 | case PANGO_ATTR_LANGUAGE: |
3442 | if (language) |
3443 | { |
3444 | if (!have_language) |
3445 | { |
3446 | have_language = TRUE; |
3447 | *language = ((PangoAttrLanguage *)attr)->value; |
3448 | } |
3449 | } |
3450 | break; |
3451 | default: |
3452 | if (extra_attrs) |
3453 | { |
3454 | gboolean found = FALSE; |
3455 | |
3456 | /* Hack: special-case FONT_FEATURES, BASELINE_SHIFT and FONT_SCALE. |
3457 | * We don't want these to accumulate, not override each other, |
3458 | * so we never merge them. |
3459 | * This needs to be handled more systematically. |
3460 | */ |
3461 | if (attr->klass->type != PANGO_ATTR_FONT_FEATURES && |
3462 | attr->klass->type != PANGO_ATTR_BASELINE_SHIFT && |
3463 | attr->klass->type != PANGO_ATTR_FONT_SCALE) |
3464 | { |
3465 | GSList *tmp_list = *extra_attrs; |
3466 | while (tmp_list) |
3467 | { |
3468 | PangoAttribute *old_attr = tmp_list->data; |
3469 | if (attr->klass->type == old_attr->klass->type) |
3470 | { |
3471 | found = TRUE; |
3472 | break; |
3473 | } |
3474 | |
3475 | tmp_list = tmp_list->next; |
3476 | } |
3477 | } |
3478 | |
3479 | if (!found) |
3480 | *extra_attrs = g_slist_prepend (list: *extra_attrs, data: pango_attribute_copy (attr)); |
3481 | } |
3482 | } |
3483 | } |
3484 | |
3485 | if (have_scale) |
3486 | { |
3487 | /* We need to use a local variable to ensure that the compiler won't |
3488 | * implicitly cast it to integer while the result is kept in registers, |
3489 | * leading to a wrong approximation in i386 (with 387 FPU) |
3490 | */ |
3491 | volatile double size = scale * pango_font_description_get_size (desc); |
3492 | |
3493 | if (pango_font_description_get_size_is_absolute (desc)) |
3494 | pango_font_description_set_absolute_size (desc, size); |
3495 | else |
3496 | pango_font_description_set_size (desc, size); |
3497 | } |
3498 | } |
3499 | |
3500 | /** |
3501 | * pango_attr_iterator_get_attrs: |
3502 | * @iterator: a `PangoAttrIterator` |
3503 | * |
3504 | * Gets a list of all attributes at the current position of the |
3505 | * iterator. |
3506 | * |
3507 | * Return value: (element-type Pango.Attribute) (transfer full): |
3508 | * a list of all attributes for the current range. To free |
3509 | * this value, call [method@Pango.Attribute.destroy] on each |
3510 | * value and g_slist_free() on the list. |
3511 | * |
3512 | * Since: 1.2 |
3513 | */ |
3514 | GSList * |
3515 | pango_attr_iterator_get_attrs (PangoAttrIterator *iterator) |
3516 | { |
3517 | GSList *attrs = NULL; |
3518 | int i; |
3519 | |
3520 | if (!iterator->attribute_stack || |
3521 | iterator->attribute_stack->len == 0) |
3522 | return NULL; |
3523 | |
3524 | for (i = iterator->attribute_stack->len - 1; i >= 0; i--) |
3525 | { |
3526 | PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); |
3527 | GSList *tmp_list2; |
3528 | gboolean found = FALSE; |
3529 | |
3530 | if (attr->klass->type != PANGO_ATTR_FONT_DESC && |
3531 | attr->klass->type != PANGO_ATTR_BASELINE_SHIFT && |
3532 | attr->klass->type != PANGO_ATTR_FONT_SCALE) |
3533 | for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next) |
3534 | { |
3535 | PangoAttribute *old_attr = tmp_list2->data; |
3536 | if (attr->klass->type == old_attr->klass->type) |
3537 | { |
3538 | found = TRUE; |
3539 | break; |
3540 | } |
3541 | } |
3542 | |
3543 | if (!found) |
3544 | attrs = g_slist_prepend (list: attrs, data: pango_attribute_copy (attr)); |
3545 | } |
3546 | |
3547 | return attrs; |
3548 | } |
3549 | |
3550 | gboolean |
3551 | pango_attr_iterator_advance (PangoAttrIterator *iterator, |
3552 | int index) |
3553 | { |
3554 | int start_range, end_range; |
3555 | |
3556 | pango_attr_iterator_range (iterator, start: &start_range, end: &end_range); |
3557 | |
3558 | while (index >= end_range) |
3559 | { |
3560 | if (!pango_attr_iterator_next (iterator)) |
3561 | return FALSE; |
3562 | pango_attr_iterator_range (iterator, start: &start_range, end: &end_range); |
3563 | } |
3564 | |
3565 | if (start_range > index) |
3566 | g_warning ("pango_attr_iterator_advance(): iterator had already " |
3567 | "moved beyond the index" ); |
3568 | |
3569 | return TRUE; |
3570 | } |
3571 | /* }}} */ |
3572 | |
3573 | /* vim:set foldmethod=marker expandtab: */ |
3574 | |