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