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 "gtktextattributesprivate.h"
54 #include "gtktexttagprivate.h"
55
56 /**
57 * gtk_text_attributes_new:
58 *
59 * Creates a #GtkTextAttributes, which describes
60 * a set of properties on some text.
61 *
62 * Returns: a new #GtkTextAttributes,
63 * free with gtk_text_attributes_unref().
64 */
65 GtkTextAttributes*
gtk_text_attributes_new(void)66 gtk_text_attributes_new (void)
67 {
68 GtkTextAttributes *values;
69
70 values = g_slice_new0 (GtkTextAttributes);
71
72 /* 0 is a valid value for most of the struct */
73 values->refcount = 1;
74
75 values->language = gtk_get_default_language ();
76
77 values->font_scale = 1.0;
78
79 values->editable = TRUE;
80
81 return values;
82 }
83
84 /**
85 * gtk_text_attributes_copy:
86 * @src: a #GtkTextAttributes to be copied
87 *
88 * Copies @src and returns a new #GtkTextAttributes.
89 *
90 * Returns: a copy of @src,
91 * free with gtk_text_attributes_unref()
92 */
93 GtkTextAttributes*
gtk_text_attributes_copy(GtkTextAttributes * src)94 gtk_text_attributes_copy (GtkTextAttributes *src)
95 {
96 GtkTextAttributes *dest;
97
98 dest = gtk_text_attributes_new ();
99 gtk_text_attributes_copy_values (src, dest);
100
101 return dest;
102 }
103
G_DEFINE_BOXED_TYPE(GtkTextAttributes,gtk_text_attributes,gtk_text_attributes_ref,gtk_text_attributes_unref)104 G_DEFINE_BOXED_TYPE (GtkTextAttributes, gtk_text_attributes,
105 gtk_text_attributes_ref,
106 gtk_text_attributes_unref)
107
108 /**
109 * gtk_text_attributes_copy_values:
110 * @src: a #GtkTextAttributes
111 * @dest: another #GtkTextAttributes
112 *
113 * Copies the values from @src to @dest so that @dest has
114 * the same values as @src. Frees existing values in @dest.
115 */
116 void
117 gtk_text_attributes_copy_values (GtkTextAttributes *src,
118 GtkTextAttributes *dest)
119 {
120 guint orig_refcount;
121
122 if (src == dest)
123 return;
124
125 /* Remove refs */
126 if (dest->tabs)
127 pango_tab_array_free (dest->tabs);
128
129 if (dest->font)
130 pango_font_description_free (dest->font);
131
132 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
133 if (dest->pg_bg_color)
134 gdk_color_free (dest->pg_bg_color);
135 G_GNUC_END_IGNORE_DEPRECATIONS
136
137 if (dest->pg_bg_rgba)
138 gdk_rgba_free (dest->pg_bg_rgba);
139
140 if (dest->appearance.rgba[0])
141 gdk_rgba_free (dest->appearance.rgba[0]);
142
143 if (dest->appearance.rgba[1])
144 gdk_rgba_free (dest->appearance.rgba[1]);
145
146 if (dest->font_features)
147 g_free (dest->font_features);
148
149 /* Copy */
150 orig_refcount = dest->refcount;
151
152 *dest = *src;
153
154 if (src->tabs)
155 dest->tabs = pango_tab_array_copy (src->tabs);
156
157 dest->language = src->language;
158
159 if (src->font)
160 dest->font = pango_font_description_copy (src->font);
161
162 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
163 if (src->pg_bg_color)
164 dest->pg_bg_color = gdk_color_copy (src->pg_bg_color);
165 G_GNUC_END_IGNORE_DEPRECATIONS
166
167 if (src->pg_bg_rgba)
168 dest->pg_bg_rgba = gdk_rgba_copy (src->pg_bg_rgba);
169
170 if (src->appearance.rgba[0])
171 dest->appearance.rgba[0] = gdk_rgba_copy (src->appearance.rgba[0]);
172
173 if (src->appearance.rgba[1])
174 dest->appearance.rgba[1] = gdk_rgba_copy (src->appearance.rgba[1]);
175
176 if (src->font_features)
177 dest->font_features = g_strdup (src->font_features);
178
179 dest->refcount = orig_refcount;
180 }
181
182 /**
183 * gtk_text_attributes_ref:
184 * @values: a #GtkTextAttributes
185 *
186 * Increments the reference count on @values.
187 *
188 * Returns: the #GtkTextAttributes that were passed in
189 **/
190 GtkTextAttributes *
gtk_text_attributes_ref(GtkTextAttributes * values)191 gtk_text_attributes_ref (GtkTextAttributes *values)
192 {
193 g_return_val_if_fail (values != NULL, NULL);
194
195 values->refcount += 1;
196
197 return values;
198 }
199
200 /**
201 * gtk_text_attributes_unref:
202 * @values: a #GtkTextAttributes
203 *
204 * Decrements the reference count on @values, freeing the structure
205 * if the reference count reaches 0.
206 **/
207 void
gtk_text_attributes_unref(GtkTextAttributes * values)208 gtk_text_attributes_unref (GtkTextAttributes *values)
209 {
210 g_return_if_fail (values != NULL);
211 g_return_if_fail (values->refcount > 0);
212
213 values->refcount -= 1;
214
215 if (values->refcount == 0)
216 {
217 if (values->tabs)
218 pango_tab_array_free (values->tabs);
219
220 if (values->font)
221 pango_font_description_free (values->font);
222
223 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
224 if (values->pg_bg_color)
225 gdk_color_free (values->pg_bg_color);
226 G_GNUC_END_IGNORE_DEPRECATIONS
227
228 if (values->pg_bg_rgba)
229 gdk_rgba_free (values->pg_bg_rgba);
230
231 if (values->appearance.rgba[0])
232 gdk_rgba_free (values->appearance.rgba[0]);
233
234 if (values->appearance.rgba[1])
235 gdk_rgba_free (values->appearance.rgba[1]);
236
237 if (values->font_features)
238 g_free (values->font_features);
239
240 g_slice_free (GtkTextAttributes, values);
241 }
242 }
243
244 void
_gtk_text_attributes_fill_from_tags(GtkTextAttributes * dest,GtkTextTag ** tags,guint n_tags)245 _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
246 GtkTextTag** tags,
247 guint n_tags)
248 {
249 guint n = 0;
250
251 guint left_margin_accumulative = 0;
252 guint right_margin_accumulative = 0;
253
254 while (n < n_tags)
255 {
256 GtkTextTag *tag = tags[n];
257 GtkTextAttributes *vals = tag->priv->values;
258
259 g_assert (tag->priv->table != NULL);
260 if (n > 0)
261 g_assert (tags[n]->priv->priority > tags[n-1]->priv->priority);
262
263 if (tag->priv->bg_color_set)
264 {
265 if (dest->appearance.rgba[0])
266 {
267 gdk_rgba_free (dest->appearance.rgba[0]);
268 dest->appearance.rgba[0] = NULL;
269 }
270
271 if (vals->appearance.rgba[0])
272 dest->appearance.rgba[0] = gdk_rgba_copy (vals->appearance.rgba[0]);
273
274 dest->appearance.draw_bg = TRUE;
275 }
276
277 if (tag->priv->fg_color_set)
278 {
279 if (dest->appearance.rgba[1])
280 {
281 gdk_rgba_free (dest->appearance.rgba[1]);
282 dest->appearance.rgba[1] = NULL;
283 }
284
285 if (vals->appearance.rgba[1])
286 dest->appearance.rgba[1] = gdk_rgba_copy (vals->appearance.rgba[1]);
287 }
288
289 if (tag->priv->pg_bg_color_set)
290 {
291 if (dest->pg_bg_rgba)
292 {
293 gdk_rgba_free (dest->pg_bg_rgba);
294 dest->pg_bg_rgba = NULL;
295 }
296
297 if (dest->pg_bg_color)
298 {
299 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
300 gdk_color_free (dest->pg_bg_color);
301 dest->pg_bg_color = NULL;
302 G_GNUC_END_IGNORE_DEPRECATIONS
303 }
304
305 if (vals->pg_bg_rgba)
306 dest->pg_bg_rgba = gdk_rgba_copy (vals->pg_bg_rgba);
307
308 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
309 if (vals->pg_bg_color)
310 dest->pg_bg_color = gdk_color_copy (vals->pg_bg_color);
311 G_GNUC_END_IGNORE_DEPRECATIONS
312 }
313
314 if (vals->font)
315 {
316 if (dest->font)
317 pango_font_description_merge (dest->font, vals->font, TRUE);
318 else
319 dest->font = pango_font_description_copy (vals->font);
320 }
321
322 /* multiply all the scales together to get a composite */
323 if (tag->priv->scale_set)
324 dest->font_scale *= vals->font_scale;
325
326 if (tag->priv->justification_set)
327 dest->justification = vals->justification;
328
329 if (vals->direction != GTK_TEXT_DIR_NONE)
330 dest->direction = vals->direction;
331
332 if (tag->priv->left_margin_set)
333 {
334 if (tag->priv->accumulative_margin)
335 left_margin_accumulative += vals->left_margin;
336 else
337 dest->left_margin = vals->left_margin;
338 }
339
340 if (tag->priv->indent_set)
341 dest->indent = vals->indent;
342
343 if (tag->priv->rise_set)
344 dest->appearance.rise = vals->appearance.rise;
345
346 if (tag->priv->right_margin_set)
347 {
348 if (tag->priv->accumulative_margin)
349 right_margin_accumulative += vals->right_margin;
350 else
351 dest->right_margin = vals->right_margin;
352 }
353
354 if (tag->priv->pixels_above_lines_set)
355 dest->pixels_above_lines = vals->pixels_above_lines;
356
357 if (tag->priv->pixels_below_lines_set)
358 dest->pixels_below_lines = vals->pixels_below_lines;
359
360 if (tag->priv->pixels_inside_wrap_set)
361 dest->pixels_inside_wrap = vals->pixels_inside_wrap;
362
363 if (tag->priv->tabs_set)
364 {
365 if (dest->tabs)
366 pango_tab_array_free (dest->tabs);
367 dest->tabs = pango_tab_array_copy (vals->tabs);
368 }
369
370 if (tag->priv->wrap_mode_set)
371 dest->wrap_mode = vals->wrap_mode;
372
373 if (tag->priv->underline_set)
374 dest->appearance.underline = vals->appearance.underline;
375
376 if (GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA_SET (&vals->appearance))
377 {
378 GdkRGBA rgba;
379
380 GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA (&vals->appearance, &rgba);
381 GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA (&dest->appearance, &rgba);
382 GTK_TEXT_APPEARANCE_SET_UNDERLINE_RGBA_SET (&dest->appearance, TRUE);
383 }
384
385 if (tag->priv->strikethrough_set)
386 dest->appearance.strikethrough = vals->appearance.strikethrough;
387
388 if (GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA_SET (&vals->appearance))
389 {
390 GdkRGBA rgba;
391
392 GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA (&vals->appearance, &rgba);
393 GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA (&dest->appearance, &rgba);
394 GTK_TEXT_APPEARANCE_SET_STRIKETHROUGH_RGBA_SET (&dest->appearance, TRUE);
395 }
396
397 if (tag->priv->invisible_set)
398 dest->invisible = vals->invisible;
399
400 if (tag->priv->editable_set)
401 dest->editable = vals->editable;
402
403 if (tag->priv->bg_full_height_set)
404 dest->bg_full_height = vals->bg_full_height;
405
406 if (tag->priv->language_set)
407 dest->language = vals->language;
408
409 if (tag->priv->fallback_set)
410 dest->no_fallback = vals->no_fallback;
411
412 if (tag->priv->letter_spacing_set)
413 dest->letter_spacing = vals->letter_spacing;
414
415 if (tag->priv->font_features_set)
416 dest->font_features = g_strdup (vals->font_features);
417
418 ++n;
419 }
420
421 dest->left_margin += left_margin_accumulative;
422 dest->right_margin += right_margin_accumulative;
423 }
424
425 gboolean
_gtk_text_tag_affects_size(GtkTextTag * tag)426 _gtk_text_tag_affects_size (GtkTextTag *tag)
427 {
428 GtkTextTagPrivate *priv = tag->priv;
429
430 return
431 (priv->values->font && pango_font_description_get_set_fields (priv->values->font) != 0) ||
432 priv->scale_set ||
433 priv->justification_set ||
434 priv->left_margin_set ||
435 priv->indent_set ||
436 priv->rise_set ||
437 priv->right_margin_set ||
438 priv->pixels_above_lines_set ||
439 priv->pixels_below_lines_set ||
440 priv->pixels_inside_wrap_set ||
441 priv->tabs_set ||
442 priv->underline_set ||
443 priv->wrap_mode_set ||
444 priv->invisible_set ||
445 priv->font_features_set ||
446 priv->letter_spacing_set;
447 }
448
449 gboolean
_gtk_text_tag_affects_nonsize_appearance(GtkTextTag * tag)450 _gtk_text_tag_affects_nonsize_appearance (GtkTextTag *tag)
451 {
452 GtkTextTagPrivate *priv = tag->priv;
453
454 return
455 priv->bg_color_set ||
456 priv->fg_color_set ||
457 priv->strikethrough_set ||
458 priv->bg_full_height_set ||
459 priv->pg_bg_color_set ||
460 priv->fallback_set ||
461 GTK_TEXT_APPEARANCE_GET_UNDERLINE_RGBA_SET (&priv->values->appearance) ||
462 GTK_TEXT_APPEARANCE_GET_STRIKETHROUGH_RGBA_SET (&priv->values->appearance);
463 }
464