1 | /* gtktextattributes.c - text attributes |
2 | * |
3 | * Copyright (c) 1992-1994 The Regents of the University of California. |
4 | * Copyright (c) 1994-1997 Sun Microsystems, Inc. |
5 | * Copyright (c) 2000 Red Hat, Inc. |
6 | * Tk -> Gtk port by Havoc Pennington <hp@redhat.com> |
7 | * |
8 | * This software is copyrighted by the Regents of the University of |
9 | * California, Sun Microsystems, Inc., and other parties. The |
10 | * following terms apply to all files associated with the software |
11 | * unless explicitly disclaimed in individual files. |
12 | * |
13 | * The authors hereby grant permission to use, copy, modify, |
14 | * distribute, and license this software and its documentation for any |
15 | * purpose, provided that existing copyright notices are retained in |
16 | * all copies and that this notice is included verbatim in any |
17 | * distributions. No written agreement, license, or royalty fee is |
18 | * required for any of the authorized uses. Modifications to this |
19 | * software may be copyrighted by their authors and need not follow |
20 | * the licensing terms described here, provided that the new terms are |
21 | * clearly indicated on the first page of each file where they apply. |
22 | * |
23 | * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY |
24 | * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL |
25 | * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, |
26 | * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED |
27 | * OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | * |
29 | * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, |
30 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
31 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND |
32 | * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, |
33 | * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE |
34 | * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
35 | * |
36 | * GOVERNMENT USE: If you are acquiring this software on behalf of the |
37 | * U.S. government, the Government shall have only "Restricted Rights" |
38 | * in the software and related documentation as defined in the Federal |
39 | * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you |
40 | * are acquiring the software on behalf of the Department of Defense, |
41 | * the software shall be classified as "Commercial Computer Software" |
42 | * and the Government shall have only "Restricted Rights" as defined |
43 | * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the |
44 | * foregoing, the authors grant the U.S. Government and others acting |
45 | * in its behalf permission to use and distribute the software in |
46 | * accordance with the terms specified in this license. |
47 | * |
48 | */ |
49 | |
50 | #include "config.h" |
51 | |
52 | #include "gtktextattributes.h" |
53 | #include "gtktexttagprivate.h" |
54 | |
55 | /** |
56 | * gtk_text_attributes_new: |
57 | * |
58 | * Creates a `GtkTextAttributes`, which describes |
59 | * a set of properties on some text. |
60 | * |
61 | * Returns: a new `GtkTextAttributes`, |
62 | * free with gtk_text_attributes_unref(). |
63 | */ |
64 | GtkTextAttributes* |
65 | gtk_text_attributes_new (void) |
66 | { |
67 | GtkTextAttributes *values; |
68 | |
69 | values = g_slice_new0 (GtkTextAttributes); |
70 | |
71 | /* 0 is a valid value for most of the struct */ |
72 | values->refcount = 1; |
73 | |
74 | values->language = gtk_get_default_language (); |
75 | |
76 | values->font_scale = 1.0; |
77 | |
78 | values->editable = TRUE; |
79 | |
80 | return values; |
81 | } |
82 | |
83 | /** |
84 | * gtk_text_attributes_copy: |
85 | * @src: a `GtkTextAttributes` to be copied |
86 | * |
87 | * Copies @src and returns a new `GtkTextAttributes`. |
88 | * |
89 | * Returns: a copy of @src, |
90 | * free with gtk_text_attributes_unref() |
91 | */ |
92 | GtkTextAttributes* |
93 | gtk_text_attributes_copy (GtkTextAttributes *src) |
94 | { |
95 | GtkTextAttributes *dest; |
96 | |
97 | dest = gtk_text_attributes_new (); |
98 | gtk_text_attributes_copy_values (src, dest); |
99 | |
100 | return dest; |
101 | } |
102 | |
103 | /** |
104 | * gtk_text_attributes_copy_values: |
105 | * @src: a `GtkTextAttributes` |
106 | * @dest: another `GtkTextAttributes` |
107 | * |
108 | * Copies the values from @src to @dest so that @dest has |
109 | * the same values as @src. Frees existing values in @dest. |
110 | */ |
111 | void |
112 | gtk_text_attributes_copy_values (GtkTextAttributes *src, |
113 | GtkTextAttributes *dest) |
114 | { |
115 | guint orig_refcount; |
116 | |
117 | if (src == dest) |
118 | return; |
119 | |
120 | /* Remove refs */ |
121 | if (dest->tabs) |
122 | pango_tab_array_free (tab_array: dest->tabs); |
123 | |
124 | if (dest->font) |
125 | pango_font_description_free (desc: dest->font); |
126 | |
127 | if (dest->pg_bg_rgba) |
128 | gdk_rgba_free (rgba: dest->pg_bg_rgba); |
129 | |
130 | if (dest->appearance.fg_rgba) |
131 | gdk_rgba_free (rgba: dest->appearance.fg_rgba); |
132 | |
133 | if (dest->appearance.bg_rgba) |
134 | gdk_rgba_free (rgba: dest->appearance.bg_rgba); |
135 | |
136 | if (dest->appearance.underline_rgba) |
137 | gdk_rgba_free (rgba: dest->appearance.underline_rgba); |
138 | |
139 | if (dest->appearance.overline_rgba) |
140 | gdk_rgba_free (rgba: dest->appearance.overline_rgba); |
141 | |
142 | if (dest->appearance.strikethrough_rgba) |
143 | gdk_rgba_free (rgba: dest->appearance.strikethrough_rgba); |
144 | |
145 | if (dest->font_features) |
146 | g_free (mem: dest->font_features); |
147 | |
148 | /* Copy */ |
149 | orig_refcount = dest->refcount; |
150 | |
151 | *dest = *src; |
152 | |
153 | if (src->tabs) |
154 | dest->tabs = pango_tab_array_copy (src: src->tabs); |
155 | |
156 | dest->language = src->language; |
157 | |
158 | if (src->font) |
159 | dest->font = pango_font_description_copy (desc: src->font); |
160 | |
161 | if (src->pg_bg_rgba) |
162 | dest->pg_bg_rgba = gdk_rgba_copy (rgba: src->pg_bg_rgba); |
163 | |
164 | if (src->appearance.fg_rgba) |
165 | dest->appearance.fg_rgba = gdk_rgba_copy (rgba: src->appearance.fg_rgba); |
166 | |
167 | if (src->appearance.bg_rgba) |
168 | dest->appearance.bg_rgba = gdk_rgba_copy (rgba: src->appearance.bg_rgba); |
169 | |
170 | if (src->appearance.underline_rgba) |
171 | dest->appearance.underline_rgba = gdk_rgba_copy (rgba: src->appearance.underline_rgba); |
172 | |
173 | if (src->appearance.overline_rgba) |
174 | dest->appearance.overline_rgba = gdk_rgba_copy (rgba: src->appearance.overline_rgba); |
175 | |
176 | if (src->appearance.strikethrough_rgba) |
177 | dest->appearance.strikethrough_rgba = gdk_rgba_copy (rgba: src->appearance.strikethrough_rgba); |
178 | |
179 | if (src->font_features) |
180 | dest->font_features = g_strdup (str: src->font_features); |
181 | |
182 | dest->refcount = orig_refcount; |
183 | } |
184 | |
185 | /** |
186 | * gtk_text_attributes_ref: |
187 | * @values: a `GtkTextAttributes` |
188 | * |
189 | * Increments the reference count on @values. |
190 | * |
191 | * Returns: the `GtkTextAttributes` that were passed in |
192 | **/ |
193 | GtkTextAttributes * |
194 | gtk_text_attributes_ref (GtkTextAttributes *values) |
195 | { |
196 | g_return_val_if_fail (values != NULL, NULL); |
197 | |
198 | values->refcount += 1; |
199 | |
200 | return values; |
201 | } |
202 | |
203 | /** |
204 | * gtk_text_attributes_unref: |
205 | * @values: a `GtkTextAttributes` |
206 | * |
207 | * Decrements the reference count on @values, freeing the structure |
208 | * if the reference count reaches 0. |
209 | **/ |
210 | void |
211 | gtk_text_attributes_unref (GtkTextAttributes *values) |
212 | { |
213 | g_return_if_fail (values != NULL); |
214 | g_return_if_fail (values->refcount > 0); |
215 | |
216 | values->refcount -= 1; |
217 | |
218 | if (values->refcount == 0) |
219 | { |
220 | if (values->tabs) |
221 | pango_tab_array_free (tab_array: values->tabs); |
222 | |
223 | if (values->font) |
224 | pango_font_description_free (desc: values->font); |
225 | |
226 | if (values->pg_bg_rgba) |
227 | gdk_rgba_free (rgba: values->pg_bg_rgba); |
228 | |
229 | if (values->appearance.fg_rgba) |
230 | gdk_rgba_free (rgba: values->appearance.fg_rgba); |
231 | |
232 | if (values->appearance.bg_rgba) |
233 | gdk_rgba_free (rgba: values->appearance.bg_rgba); |
234 | |
235 | if (values->appearance.underline_rgba) |
236 | gdk_rgba_free (rgba: values->appearance.underline_rgba); |
237 | |
238 | if (values->appearance.overline_rgba) |
239 | gdk_rgba_free (rgba: values->appearance.underline_rgba); |
240 | |
241 | if (values->appearance.strikethrough_rgba) |
242 | gdk_rgba_free (rgba: values->appearance.strikethrough_rgba); |
243 | |
244 | if (values->font_features) |
245 | g_free (mem: values->font_features); |
246 | |
247 | g_slice_free (GtkTextAttributes, values); |
248 | } |
249 | } |
250 | |
251 | void |
252 | _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest, |
253 | GPtrArray *tags) |
254 | { |
255 | guint left_margin_accumulative = 0; |
256 | guint right_margin_accumulative = 0; |
257 | |
258 | for (guint n = 0; n < tags->len; n++) |
259 | { |
260 | GtkTextTag *tag = g_ptr_array_index (tags, n); |
261 | GtkTextAttributes *vals = tag->priv->values; |
262 | |
263 | g_assert (tag->priv->table != NULL); |
264 | if (n > 0) |
265 | g_assert (((GtkTextTag*)g_ptr_array_index (tags, n))->priv->priority > ((GtkTextTag *)g_ptr_array_index (tags, n - 1))->priv->priority); |
266 | |
267 | if (tag->priv->bg_color_set) |
268 | { |
269 | if (dest->appearance.bg_rgba) |
270 | { |
271 | gdk_rgba_free (rgba: dest->appearance.bg_rgba); |
272 | dest->appearance.bg_rgba = NULL; |
273 | } |
274 | |
275 | if (vals->appearance.bg_rgba) |
276 | dest->appearance.bg_rgba = gdk_rgba_copy (rgba: vals->appearance.bg_rgba); |
277 | |
278 | dest->appearance.draw_bg = TRUE; |
279 | } |
280 | |
281 | if (tag->priv->fg_color_set) |
282 | { |
283 | if (dest->appearance.fg_rgba) |
284 | { |
285 | gdk_rgba_free (rgba: dest->appearance.fg_rgba); |
286 | dest->appearance.fg_rgba = NULL; |
287 | } |
288 | |
289 | if (vals->appearance.fg_rgba) |
290 | dest->appearance.fg_rgba = gdk_rgba_copy (rgba: vals->appearance.fg_rgba); |
291 | } |
292 | |
293 | if (tag->priv->underline_rgba_set) |
294 | { |
295 | if (dest->appearance.underline_rgba) |
296 | { |
297 | gdk_rgba_free (rgba: dest->appearance.underline_rgba); |
298 | dest->appearance.underline_rgba = NULL; |
299 | } |
300 | |
301 | if (vals->appearance.underline_rgba) |
302 | dest->appearance.underline_rgba = gdk_rgba_copy (rgba: vals->appearance.underline_rgba); |
303 | } |
304 | |
305 | if (tag->priv->overline_rgba_set) |
306 | { |
307 | if (dest->appearance.overline_rgba) |
308 | { |
309 | gdk_rgba_free (rgba: dest->appearance.overline_rgba); |
310 | dest->appearance.overline_rgba = NULL; |
311 | } |
312 | |
313 | if (vals->appearance.overline_rgba) |
314 | dest->appearance.overline_rgba = gdk_rgba_copy (rgba: vals->appearance.overline_rgba); |
315 | } |
316 | |
317 | if (tag->priv->strikethrough_rgba_set) |
318 | { |
319 | if (dest->appearance.strikethrough_rgba) |
320 | { |
321 | gdk_rgba_free (rgba: dest->appearance.strikethrough_rgba); |
322 | dest->appearance.strikethrough_rgba = NULL; |
323 | } |
324 | |
325 | if (vals->appearance.strikethrough_rgba) |
326 | dest->appearance.strikethrough_rgba = gdk_rgba_copy (rgba: vals->appearance.strikethrough_rgba); |
327 | } |
328 | |
329 | if (tag->priv->pg_bg_color_set) |
330 | { |
331 | if (dest->pg_bg_rgba) |
332 | { |
333 | gdk_rgba_free (rgba: dest->pg_bg_rgba); |
334 | dest->pg_bg_rgba = NULL; |
335 | } |
336 | |
337 | if (vals->pg_bg_rgba) |
338 | dest->pg_bg_rgba = gdk_rgba_copy (rgba: vals->pg_bg_rgba); |
339 | } |
340 | |
341 | if (vals->font) |
342 | { |
343 | if (dest->font) |
344 | pango_font_description_merge (desc: dest->font, desc_to_merge: vals->font, TRUE); |
345 | else |
346 | dest->font = pango_font_description_copy (desc: vals->font); |
347 | } |
348 | |
349 | /* multiply all the scales together to get a composite */ |
350 | if (tag->priv->scale_set) |
351 | dest->font_scale *= vals->font_scale; |
352 | |
353 | if (tag->priv->justification_set) |
354 | dest->justification = vals->justification; |
355 | |
356 | if (vals->direction != GTK_TEXT_DIR_NONE) |
357 | dest->direction = vals->direction; |
358 | |
359 | if (tag->priv->left_margin_set) |
360 | { |
361 | if (tag->priv->accumulative_margin) |
362 | left_margin_accumulative += vals->left_margin; |
363 | else |
364 | dest->left_margin = vals->left_margin; |
365 | } |
366 | |
367 | if (tag->priv->indent_set) |
368 | dest->indent = vals->indent; |
369 | |
370 | if (tag->priv->rise_set) |
371 | dest->appearance.rise = vals->appearance.rise; |
372 | |
373 | if (tag->priv->right_margin_set) |
374 | { |
375 | if (tag->priv->accumulative_margin) |
376 | right_margin_accumulative += vals->right_margin; |
377 | else |
378 | dest->right_margin = vals->right_margin; |
379 | } |
380 | |
381 | if (tag->priv->pixels_above_lines_set) |
382 | dest->pixels_above_lines = vals->pixels_above_lines; |
383 | |
384 | if (tag->priv->pixels_below_lines_set) |
385 | dest->pixels_below_lines = vals->pixels_below_lines; |
386 | |
387 | if (tag->priv->pixels_inside_wrap_set) |
388 | dest->pixels_inside_wrap = vals->pixels_inside_wrap; |
389 | |
390 | if (tag->priv->line_height_set) |
391 | dest->line_height = vals->line_height; |
392 | |
393 | if (tag->priv->tabs_set) |
394 | { |
395 | if (dest->tabs) |
396 | pango_tab_array_free (tab_array: dest->tabs); |
397 | dest->tabs = pango_tab_array_copy (src: vals->tabs); |
398 | } |
399 | |
400 | if (tag->priv->wrap_mode_set) |
401 | dest->wrap_mode = vals->wrap_mode; |
402 | |
403 | if (tag->priv->underline_set) |
404 | dest->appearance.underline = vals->appearance.underline; |
405 | |
406 | if (tag->priv->overline_set) |
407 | dest->appearance.overline = vals->appearance.overline; |
408 | |
409 | if (tag->priv->strikethrough_set) |
410 | dest->appearance.strikethrough = vals->appearance.strikethrough; |
411 | |
412 | if (tag->priv->invisible_set) |
413 | dest->invisible = vals->invisible; |
414 | |
415 | if (tag->priv->editable_set) |
416 | dest->editable = vals->editable; |
417 | |
418 | if (tag->priv->bg_full_height_set) |
419 | dest->bg_full_height = vals->bg_full_height; |
420 | |
421 | if (tag->priv->language_set) |
422 | dest->language = vals->language; |
423 | |
424 | if (tag->priv->fallback_set) |
425 | dest->no_fallback = vals->no_fallback; |
426 | |
427 | if (tag->priv->letter_spacing_set) |
428 | dest->letter_spacing = vals->letter_spacing; |
429 | |
430 | if (tag->priv->font_features_set) |
431 | dest->font_features = g_strdup (str: vals->font_features); |
432 | |
433 | if (tag->priv->allow_breaks_set) |
434 | dest->no_breaks = vals->no_breaks; |
435 | |
436 | if (tag->priv->show_spaces_set) |
437 | dest->show_spaces = vals->show_spaces; |
438 | |
439 | if (tag->priv->insert_hyphens_set) |
440 | dest->no_hyphens = vals->no_hyphens; |
441 | |
442 | if (tag->priv->text_transform_set) |
443 | dest->text_transform = vals->text_transform; |
444 | |
445 | if (tag->priv->word_set) |
446 | dest->word = vals->word; |
447 | |
448 | if (tag->priv->sentence_set) |
449 | dest->sentence = vals->sentence; |
450 | } |
451 | |
452 | dest->left_margin += left_margin_accumulative; |
453 | dest->right_margin += right_margin_accumulative; |
454 | } |
455 | |
456 | gboolean |
457 | _gtk_text_tag_affects_size (GtkTextTag *tag) |
458 | { |
459 | GtkTextTagPrivate *priv = tag->priv; |
460 | |
461 | return |
462 | (priv->values->font && pango_font_description_get_set_fields (desc: priv->values->font) != 0) || |
463 | priv->scale_set || |
464 | priv->justification_set || |
465 | priv->left_margin_set || |
466 | priv->indent_set || |
467 | priv->rise_set || |
468 | priv->right_margin_set || |
469 | priv->pixels_above_lines_set || |
470 | priv->pixels_below_lines_set || |
471 | priv->pixels_inside_wrap_set || |
472 | priv->line_height_set || |
473 | priv->tabs_set || |
474 | priv->underline_set || |
475 | priv->overline_set || |
476 | priv->wrap_mode_set || |
477 | priv->invisible_set || |
478 | priv->font_features_set || |
479 | priv->letter_spacing_set || |
480 | priv->text_transform_set; |
481 | } |
482 | |
483 | gboolean |
484 | _gtk_text_tag_affects_nonsize_appearance (GtkTextTag *tag) |
485 | { |
486 | GtkTextTagPrivate *priv = tag->priv; |
487 | |
488 | return |
489 | priv->bg_color_set || |
490 | priv->fg_color_set || |
491 | priv->strikethrough_set || |
492 | priv->bg_full_height_set || |
493 | priv->pg_bg_color_set || |
494 | priv->fallback_set || |
495 | priv->underline_rgba_set || |
496 | priv->overline_rgba_set || |
497 | priv->strikethrough_rgba_set || |
498 | priv->show_spaces_set; |
499 | } |
500 | |