1/*
2 * Copyright © 2012 Red Hat Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gtkprivate.h"
23#include "gtkcssstyleprivate.h"
24
25#include "gtkcssanimationprivate.h"
26#include "gtkcssarrayvalueprivate.h"
27#include "gtkcssenumvalueprivate.h"
28#include "gtkcssinheritvalueprivate.h"
29#include "gtkcssinitialvalueprivate.h"
30#include "gtkcssnumbervalueprivate.h"
31#include "gtkcsscolorvalueprivate.h"
32#include "gtkcssshorthandpropertyprivate.h"
33#include "gtkcssstringvalueprivate.h"
34#include "gtkcssfontvariationsvalueprivate.h"
35#include "gtkcssfontfeaturesvalueprivate.h"
36#include "gtkcsslineheightvalueprivate.h"
37#include "gtkcssstylepropertyprivate.h"
38#include "gtkcsstransitionprivate.h"
39#include "gtkstyleanimationprivate.h"
40#include "gtkstylepropertyprivate.h"
41#include "gtkstyleproviderprivate.h"
42
43G_DEFINE_ABSTRACT_TYPE (GtkCssStyle, gtk_css_style, G_TYPE_OBJECT)
44
45static GtkCssSection *
46gtk_css_style_real_get_section (GtkCssStyle *style,
47 guint id)
48{
49 return NULL;
50}
51
52static gboolean
53gtk_css_style_real_is_static (GtkCssStyle *style)
54{
55 return TRUE;
56}
57
58
59static void
60gtk_css_style_finalize (GObject *object)
61{
62 GtkCssStyle *style = GTK_CSS_STYLE (object);
63
64 gtk_css_values_unref (values: (GtkCssValues *)style->core);
65 gtk_css_values_unref (values: (GtkCssValues *)style->background);
66 gtk_css_values_unref (values: (GtkCssValues *)style->border);
67 gtk_css_values_unref (values: (GtkCssValues *)style->icon);
68 gtk_css_values_unref (values: (GtkCssValues *)style->outline);
69 gtk_css_values_unref (values: (GtkCssValues *)style->font);
70 gtk_css_values_unref (values: (GtkCssValues *)style->font_variant);
71 gtk_css_values_unref (values: (GtkCssValues *)style->animation);
72 gtk_css_values_unref (values: (GtkCssValues *)style->transition);
73 gtk_css_values_unref (values: (GtkCssValues *)style->size);
74 gtk_css_values_unref (values: (GtkCssValues *)style->other);
75
76 G_OBJECT_CLASS (gtk_css_style_parent_class)->finalize (object);
77}
78
79static void
80gtk_css_style_class_init (GtkCssStyleClass *klass)
81{
82 GObjectClass *object_class = G_OBJECT_CLASS (klass);
83
84 object_class->finalize = gtk_css_style_finalize;
85
86 klass->get_section = gtk_css_style_real_get_section;
87 klass->is_static = gtk_css_style_real_is_static;
88}
89
90static void
91gtk_css_style_init (GtkCssStyle *style)
92{
93}
94
95GtkCssValue *
96gtk_css_style_get_value (GtkCssStyle *style,
97 guint id)
98{
99 switch (id)
100 {
101 case GTK_CSS_PROPERTY_COLOR:
102 return style->core->color;
103 case GTK_CSS_PROPERTY_DPI:
104 return style->core->dpi;
105 case GTK_CSS_PROPERTY_FONT_SIZE:
106 return style->core->font_size;
107 case GTK_CSS_PROPERTY_ICON_PALETTE:
108 return style->core->icon_palette;
109 case GTK_CSS_PROPERTY_BACKGROUND_COLOR:
110 return style->background->background_color;
111 case GTK_CSS_PROPERTY_FONT_FAMILY:
112 return style->font->font_family;
113 case GTK_CSS_PROPERTY_FONT_STYLE:
114 return style->font->font_style;
115 case GTK_CSS_PROPERTY_FONT_WEIGHT:
116 return style->font->font_weight;
117 case GTK_CSS_PROPERTY_FONT_STRETCH:
118 return style->font->font_stretch;
119 case GTK_CSS_PROPERTY_LETTER_SPACING:
120 return style->font->letter_spacing;
121 case GTK_CSS_PROPERTY_LINE_HEIGHT:
122 return style->font->line_height;
123 case GTK_CSS_PROPERTY_TEXT_DECORATION_LINE:
124 return style->font_variant->text_decoration_line;
125 case GTK_CSS_PROPERTY_TEXT_DECORATION_COLOR:
126 return style->font_variant->text_decoration_color ? style->font_variant->text_decoration_color : style->core->color;
127 case GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE:
128 return style->font_variant->text_decoration_style;
129 case GTK_CSS_PROPERTY_TEXT_TRANSFORM:
130 return style->font_variant->text_transform;
131 case GTK_CSS_PROPERTY_FONT_KERNING:
132 return style->font_variant->font_kerning;
133 case GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES:
134 return style->font_variant->font_variant_ligatures;
135 case GTK_CSS_PROPERTY_FONT_VARIANT_POSITION:
136 return style->font_variant->font_variant_position;
137 case GTK_CSS_PROPERTY_FONT_VARIANT_CAPS:
138 return style->font_variant->font_variant_caps;
139 case GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC:
140 return style->font_variant->font_variant_numeric;
141 case GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES:
142 return style->font_variant->font_variant_alternates;
143 case GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN:
144 return style->font_variant->font_variant_east_asian;
145 case GTK_CSS_PROPERTY_TEXT_SHADOW:
146 return style->font->text_shadow;
147 case GTK_CSS_PROPERTY_BOX_SHADOW:
148 return style->background->box_shadow;
149 case GTK_CSS_PROPERTY_MARGIN_TOP:
150 return style->size->margin_top;
151 case GTK_CSS_PROPERTY_MARGIN_LEFT:
152 return style->size->margin_left;
153 case GTK_CSS_PROPERTY_MARGIN_BOTTOM:
154 return style->size->margin_bottom;
155 case GTK_CSS_PROPERTY_MARGIN_RIGHT:
156 return style->size->margin_right;
157 case GTK_CSS_PROPERTY_PADDING_TOP:
158 return style->size->padding_top;
159 case GTK_CSS_PROPERTY_PADDING_LEFT:
160 return style->size->padding_left;
161 case GTK_CSS_PROPERTY_PADDING_BOTTOM:
162 return style->size->padding_bottom;
163 case GTK_CSS_PROPERTY_PADDING_RIGHT:
164 return style->size->padding_right;
165 case GTK_CSS_PROPERTY_BORDER_TOP_STYLE:
166 return style->border->border_top_style;
167 case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH:
168 return style->border->border_top_width;
169 case GTK_CSS_PROPERTY_BORDER_LEFT_STYLE:
170 return style->border->border_left_style;
171 case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH:
172 return style->border->border_left_width;
173 case GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE:
174 return style->border->border_bottom_style;
175 case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
176 return style->border->border_bottom_width;
177 case GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE:
178 return style->border->border_right_style;
179 case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH:
180 return style->border->border_right_width;
181 case GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS:
182 return style->border->border_top_left_radius;
183 case GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS:
184 return style->border->border_top_right_radius;
185 case GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS:
186 return style->border->border_bottom_right_radius;
187 case GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS:
188 return style->border->border_bottom_left_radius;
189 case GTK_CSS_PROPERTY_OUTLINE_STYLE:
190 return style->outline->outline_style;
191 case GTK_CSS_PROPERTY_OUTLINE_WIDTH:
192 return style->outline->outline_width;
193 case GTK_CSS_PROPERTY_OUTLINE_OFFSET:
194 return style->outline->outline_offset;
195 case GTK_CSS_PROPERTY_BACKGROUND_CLIP:
196 return style->background->background_clip;
197 case GTK_CSS_PROPERTY_BACKGROUND_ORIGIN:
198 return style->background->background_origin;
199 case GTK_CSS_PROPERTY_BACKGROUND_SIZE:
200 return style->background->background_size;
201 case GTK_CSS_PROPERTY_BACKGROUND_POSITION:
202 return style->background->background_position;
203 case GTK_CSS_PROPERTY_BORDER_TOP_COLOR:
204 return style->border->border_top_color ? style->border->border_top_color : style->core->color;
205 case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR:
206 return style->border->border_right_color ? style->border->border_right_color : style->core->color;
207 case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR:
208 return style->border->border_bottom_color ? style->border->border_bottom_color : style->core->color;
209 case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR:
210 return style->border->border_left_color ? style->border->border_left_color: style->core->color;
211 case GTK_CSS_PROPERTY_OUTLINE_COLOR:
212 return style->outline->outline_color ? style->outline->outline_color : style->core->color;
213 case GTK_CSS_PROPERTY_BACKGROUND_REPEAT:
214 return style->background->background_repeat;
215 case GTK_CSS_PROPERTY_BACKGROUND_IMAGE:
216 return style->background->background_image;
217 case GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE:
218 return style->background->background_blend_mode;
219 case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE:
220 return style->border->border_image_source;
221 case GTK_CSS_PROPERTY_BORDER_IMAGE_REPEAT:
222 return style->border->border_image_repeat;
223 case GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE:
224 return style->border->border_image_slice;
225 case GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH:
226 return style->border->border_image_width;
227 case GTK_CSS_PROPERTY_ICON_SOURCE:
228 return style->other->icon_source;
229 case GTK_CSS_PROPERTY_ICON_SIZE:
230 return style->icon->icon_size;
231 case GTK_CSS_PROPERTY_ICON_SHADOW:
232 return style->icon->icon_shadow;
233 case GTK_CSS_PROPERTY_ICON_STYLE:
234 return style->icon->icon_style;
235 case GTK_CSS_PROPERTY_ICON_TRANSFORM:
236 return style->other->icon_transform;
237 case GTK_CSS_PROPERTY_ICON_FILTER:
238 return style->other->icon_filter;
239 case GTK_CSS_PROPERTY_BORDER_SPACING:
240 return style->size->border_spacing;
241 case GTK_CSS_PROPERTY_TRANSFORM:
242 return style->other->transform;
243 case GTK_CSS_PROPERTY_TRANSFORM_ORIGIN:
244 return style->other->transform_origin;
245 case GTK_CSS_PROPERTY_MIN_WIDTH:
246 return style->size->min_width;
247 case GTK_CSS_PROPERTY_MIN_HEIGHT:
248 return style->size->min_height;
249 case GTK_CSS_PROPERTY_TRANSITION_PROPERTY:
250 return style->transition->transition_property;
251 case GTK_CSS_PROPERTY_TRANSITION_DURATION:
252 return style->transition->transition_duration;
253 case GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION:
254 return style->transition->transition_timing_function;
255 case GTK_CSS_PROPERTY_TRANSITION_DELAY:
256 return style->transition->transition_delay;
257 case GTK_CSS_PROPERTY_ANIMATION_NAME:
258 return style->animation->animation_name;
259 case GTK_CSS_PROPERTY_ANIMATION_DURATION:
260 return style->animation->animation_duration;
261 case GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION:
262 return style->animation->animation_timing_function;
263 case GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT:
264 return style->animation->animation_iteration_count;
265 case GTK_CSS_PROPERTY_ANIMATION_DIRECTION:
266 return style->animation->animation_direction;
267 case GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE:
268 return style->animation->animation_play_state;
269 case GTK_CSS_PROPERTY_ANIMATION_DELAY:
270 return style->animation->animation_delay;
271 case GTK_CSS_PROPERTY_ANIMATION_FILL_MODE:
272 return style->animation->animation_fill_mode;
273 case GTK_CSS_PROPERTY_OPACITY:
274 return style->other->opacity;
275 case GTK_CSS_PROPERTY_FILTER:
276 return style->other->filter;
277 case GTK_CSS_PROPERTY_CARET_COLOR:
278 return style->font->caret_color ? style->font->caret_color : style->core->color;
279 case GTK_CSS_PROPERTY_SECONDARY_CARET_COLOR:
280 return style->font->secondary_caret_color ? style->font->secondary_caret_color : style->core->color;
281 case GTK_CSS_PROPERTY_FONT_FEATURE_SETTINGS:
282 return style->font->font_feature_settings;
283 case GTK_CSS_PROPERTY_FONT_VARIATION_SETTINGS:
284 return style->font->font_variation_settings;
285
286 default:
287 g_assert_not_reached ();
288 }
289}
290
291GtkCssSection *
292gtk_css_style_get_section (GtkCssStyle *style,
293 guint id)
294{
295 gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
296
297 return GTK_CSS_STYLE_GET_CLASS (style)->get_section (style, id);
298}
299
300gboolean
301gtk_css_style_is_static (GtkCssStyle *style)
302{
303 return GTK_CSS_STYLE_GET_CLASS (style)->is_static (style);
304}
305
306GtkCssStaticStyle *
307gtk_css_style_get_static_style (GtkCssStyle *style)
308{
309 gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
310
311 return GTK_CSS_STYLE_GET_CLASS (style)->get_static_style (style);
312}
313
314/*
315 * gtk_css_style_print:
316 * @style: a `GtkCssStyle`
317 * @string: the `GString` to print to
318 * @indent: level of indentation to use
319 * @skip_initial: %TRUE to skip properties that have their initial value
320 *
321 * Print the @style to @string, in CSS format. Every property is printed
322 * on a line by itself, indented by @indent spaces. If @skip_initial is
323 * %TRUE, properties are only printed if their value in @style is different
324 * from the initial value of the property.
325 *
326 * Returns: %TRUE is any properties have been printed
327 */
328gboolean
329gtk_css_style_print (GtkCssStyle *style,
330 GString *string,
331 guint indent,
332 gboolean skip_initial)
333{
334 guint i;
335 gboolean retval = FALSE;
336
337 g_return_val_if_fail (GTK_IS_CSS_STYLE (style), FALSE);
338 g_return_val_if_fail (string != NULL, FALSE);
339
340 for (i = 0; i < _gtk_css_style_property_get_n_properties (); i++)
341 {
342 GtkCssSection *section;
343 GtkCssStyleProperty *prop;
344 GtkCssValue *value;
345 const char *name;
346
347 section = gtk_css_style_get_section (style, id: i);
348 if (!section && skip_initial)
349 continue;
350
351 prop = _gtk_css_style_property_lookup_by_id (id: i);
352 name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop));
353 value = gtk_css_style_get_value (style, id: i);
354
355 g_string_append_printf (string, format: "%*s%s: ", indent, "", name);
356 _gtk_css_value_print (value, string);
357 g_string_append_c (string, ';');
358
359 if (section)
360 {
361 g_string_append (string, val: " /* ");
362 gtk_css_section_print (section, string);
363 g_string_append (string, val: " */");
364 }
365
366 g_string_append_c (string, '\n');
367
368 retval = TRUE;
369 }
370
371 return retval;
372}
373
374char *
375gtk_css_style_to_string (GtkCssStyle *style)
376{
377 GString *string;
378
379 g_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
380
381 string = g_string_new (init: "");
382
383 gtk_css_style_print (style, string, indent: 0, FALSE);
384
385 return g_string_free (string, FALSE);
386}
387
388static PangoUnderline
389get_pango_underline_from_style (GtkTextDecorationStyle style)
390{
391 switch (style)
392 {
393 case GTK_CSS_TEXT_DECORATION_STYLE_DOUBLE:
394 return PANGO_UNDERLINE_DOUBLE;
395 case GTK_CSS_TEXT_DECORATION_STYLE_WAVY:
396 return PANGO_UNDERLINE_ERROR;
397 case GTK_CSS_TEXT_DECORATION_STYLE_SOLID:
398 default:
399 return PANGO_UNDERLINE_SINGLE;
400 }
401
402 g_return_val_if_reached (PANGO_UNDERLINE_SINGLE);
403}
404
405PangoTextTransform
406gtk_css_style_get_pango_text_transform (GtkCssStyle *style)
407{
408 switch (_gtk_css_text_transform_value_get (value: style->font_variant->text_transform))
409 {
410 case GTK_CSS_TEXT_TRANSFORM_NONE:
411 return PANGO_TEXT_TRANSFORM_NONE;
412 case GTK_CSS_TEXT_TRANSFORM_LOWERCASE:
413 return PANGO_TEXT_TRANSFORM_LOWERCASE;
414 case GTK_CSS_TEXT_TRANSFORM_UPPERCASE:
415 return PANGO_TEXT_TRANSFORM_UPPERCASE;
416 case GTK_CSS_TEXT_TRANSFORM_CAPITALIZE:
417 return PANGO_TEXT_TRANSFORM_CAPITALIZE;
418 default:
419 return PANGO_TEXT_TRANSFORM_NONE;
420 }
421}
422
423static PangoOverline
424get_pango_overline_from_style (GtkTextDecorationStyle style)
425{
426 return PANGO_OVERLINE_SINGLE;
427}
428
429static PangoAttrList *
430add_pango_attr (PangoAttrList *attrs,
431 PangoAttribute *attr)
432{
433 if (attrs == NULL)
434 attrs = pango_attr_list_new ();
435
436 pango_attr_list_insert (list: attrs, attr);
437
438 return attrs;
439}
440
441static void
442append_separated (GString **s,
443 const char *text)
444{
445 if (G_UNLIKELY (!*s))
446 *s = g_string_new (NULL);
447
448 if ((*s)->len > 0)
449 g_string_append (string: *s, val: ", ");
450
451 g_string_append (string: *s, val: text);
452}
453
454char *
455gtk_css_style_compute_font_features (GtkCssStyle *style)
456{
457 GtkCssFontVariantLigature ligatures;
458 GtkCssFontVariantNumeric numeric;
459 GtkCssFontVariantEastAsian east_asian;
460 char *settings;
461 GString *s = NULL;
462
463 switch (_gtk_css_font_kerning_value_get (value: style->font_variant->font_kerning))
464 {
465 case GTK_CSS_FONT_KERNING_NORMAL:
466 append_separated (s: &s, text: "kern 1");
467 break;
468 case GTK_CSS_FONT_KERNING_NONE:
469 append_separated (s: &s, text: "kern 0");
470 break;
471 case GTK_CSS_FONT_KERNING_AUTO:
472 default:
473 break;
474 }
475
476 ligatures = _gtk_css_font_variant_ligature_value_get (value: style->font_variant->font_variant_ligatures);
477 if (ligatures == GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL)
478 {
479 /* all defaults */
480 }
481 else if (ligatures == GTK_CSS_FONT_VARIANT_LIGATURE_NONE)
482 append_separated (s: &s, text: "liga 0, clig 0, dlig 0, hlig 0, calt 0");
483 else
484 {
485 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES)
486 append_separated (s: &s, text: "liga 1, clig 1");
487 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES)
488 append_separated (s: &s, text: "liga 0, clig 0");
489 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES)
490 append_separated (s: &s, text: "dlig 1");
491 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES)
492 append_separated (s: &s, text: "dlig 0");
493 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES)
494 append_separated (s: &s, text: "hlig 1");
495 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES)
496 append_separated (s: &s, text: "hlig 0");
497 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL)
498 append_separated (s: &s, text: "calt 1");
499 if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL)
500 append_separated (s: &s, text: "calt 0");
501 }
502
503 switch (_gtk_css_font_variant_position_value_get (value: style->font_variant->font_variant_position))
504 {
505 case GTK_CSS_FONT_VARIANT_POSITION_SUB:
506 append_separated (s: &s, text: "subs 1");
507 break;
508 case GTK_CSS_FONT_VARIANT_POSITION_SUPER:
509 append_separated (s: &s, text: "sups 1");
510 break;
511 case GTK_CSS_FONT_VARIANT_POSITION_NORMAL:
512 default:
513 break;
514 }
515
516 numeric = _gtk_css_font_variant_numeric_value_get (value: style->font_variant->font_variant_numeric);
517 if (numeric == GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL)
518 {
519 /* all defaults */
520 }
521 else
522 {
523 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS)
524 append_separated (s: &s, text: "lnum 1");
525 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS)
526 append_separated (s: &s, text: "onum 1");
527 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS)
528 append_separated (s: &s, text: "pnum 1");
529 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS)
530 append_separated (s: &s, text: "tnum 1");
531 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS)
532 append_separated (s: &s, text: "frac 1");
533 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS)
534 append_separated (s: &s, text: "afrc 1");
535 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_ORDINAL)
536 append_separated (s: &s, text: "ordn 1");
537 if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO)
538 append_separated (s: &s, text: "zero 1");
539 }
540
541 switch (_gtk_css_font_variant_alternate_value_get (value: style->font_variant->font_variant_alternates))
542 {
543 case GTK_CSS_FONT_VARIANT_ALTERNATE_HISTORICAL_FORMS:
544 append_separated (s: &s, text: "hist 1");
545 break;
546 case GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL:
547 default:
548 break;
549 }
550
551 east_asian = _gtk_css_font_variant_east_asian_value_get (value: style->font_variant->font_variant_east_asian);
552 if (east_asian == GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL)
553 {
554 /* all defaults */
555 }
556 else
557 {
558 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78)
559 append_separated (s: &s, text: "jp78 1");
560 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83)
561 append_separated (s: &s, text: "jp83 1");
562 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90)
563 append_separated (s: &s, text: "jp90 1");
564 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04)
565 append_separated (s: &s, text: "jp04 1");
566 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED)
567 append_separated (s: &s, text: "smpl 1");
568 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL)
569 append_separated (s: &s, text: "trad 1");
570 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH)
571 append_separated (s: &s, text: "fwid 1");
572 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL)
573 append_separated (s: &s, text: "pwid 1");
574 if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_RUBY)
575 append_separated (s: &s, text: "ruby 1");
576 }
577
578 settings = gtk_css_font_features_value_get_features (value: style->font->font_feature_settings);
579 if (settings)
580 {
581 append_separated (s: &s, text: settings);
582 g_free (mem: settings);
583 }
584
585 if (s)
586 return g_string_free (string: s, FALSE);
587 else
588 return NULL;
589}
590
591PangoAttrList *
592gtk_css_style_get_pango_attributes (GtkCssStyle *style)
593{
594 PangoAttrList *attrs = NULL;
595 GtkTextDecorationLine decoration_line;
596 GtkTextDecorationStyle decoration_style;
597 const GdkRGBA *color;
598 const GdkRGBA *decoration_color;
599 int letter_spacing;
600
601 /* text-decoration */
602 decoration_line = _gtk_css_text_decoration_line_value_get (value: style->font_variant->text_decoration_line);
603 decoration_style = _gtk_css_text_decoration_style_value_get (value: style->font_variant->text_decoration_style);
604 color = gtk_css_color_value_get_rgba (color: style->core->color);
605 decoration_color = gtk_css_color_value_get_rgba (color: style->font_variant->text_decoration_color
606 ? style->font_variant->text_decoration_color
607 : style->core->color);
608
609 if (decoration_line & GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE)
610 {
611 attrs = add_pango_attr (attrs, attr: pango_attr_underline_new (underline: get_pango_underline_from_style (style: decoration_style)));
612 if (!gdk_rgba_equal (p1: color, p2: decoration_color))
613 attrs = add_pango_attr (attrs, attr: pango_attr_underline_color_new (red: decoration_color->red * 65535. + 0.5,
614 green: decoration_color->green * 65535. + 0.5,
615 blue: decoration_color->blue * 65535. + 0.5));
616 }
617 if (decoration_line & GTK_CSS_TEXT_DECORATION_LINE_OVERLINE)
618 {
619 attrs = add_pango_attr (attrs, attr: pango_attr_overline_new (overline: get_pango_overline_from_style (style: decoration_style)));
620 if (!gdk_rgba_equal (p1: color, p2: decoration_color))
621 attrs = add_pango_attr (attrs, attr: pango_attr_overline_color_new (red: decoration_color->red * 65535. + 0.5,
622 green: decoration_color->green * 65535. + 0.5,
623 blue: decoration_color->blue * 65535. + 0.5));
624 }
625 if (decoration_line & GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH)
626 {
627 attrs = add_pango_attr (attrs, attr: pango_attr_strikethrough_new (TRUE));
628 if (!gdk_rgba_equal (p1: color, p2: decoration_color))
629 attrs = add_pango_attr (attrs, attr: pango_attr_strikethrough_color_new (red: decoration_color->red * 65535. + 0.5,
630 green: decoration_color->green * 65535. + 0.5,
631 blue: decoration_color->blue * 65535. + 0.5));
632 }
633
634 /* letter-spacing */
635 letter_spacing = _gtk_css_number_value_get (number: style->font->letter_spacing, one_hundred_percent: 100);
636 if (letter_spacing != 0)
637 {
638 attrs = add_pango_attr (attrs, attr: pango_attr_letter_spacing_new (letter_spacing: letter_spacing * PANGO_SCALE));
639 }
640
641 /* line-height */
642 {
643 double height = gtk_css_line_height_value_get (value: style->font->line_height);
644 if (height != 0.0)
645 {
646 if (gtk_css_number_value_get_dimension (value: style->font->line_height) == GTK_CSS_DIMENSION_LENGTH)
647 attrs = add_pango_attr (attrs, attr: pango_attr_line_height_new_absolute (height: height * PANGO_SCALE));
648 else
649 attrs = add_pango_attr (attrs, attr: pango_attr_line_height_new (factor: height));
650 }
651 }
652
653 /* casing variants */
654 switch (_gtk_css_font_variant_caps_value_get (value: style->font_variant->font_variant_caps))
655 {
656 case GTK_CSS_FONT_VARIANT_CAPS_SMALL_CAPS:
657 attrs = add_pango_attr (attrs, attr: pango_attr_variant_new (variant: PANGO_VARIANT_SMALL_CAPS));
658 break;
659 case GTK_CSS_FONT_VARIANT_CAPS_ALL_SMALL_CAPS:
660 attrs = add_pango_attr (attrs, attr: pango_attr_variant_new (variant: PANGO_VARIANT_ALL_SMALL_CAPS));
661 break;
662 case GTK_CSS_FONT_VARIANT_CAPS_PETITE_CAPS:
663 attrs = add_pango_attr (attrs, attr: pango_attr_variant_new (variant: PANGO_VARIANT_PETITE_CAPS));
664 break;
665 case GTK_CSS_FONT_VARIANT_CAPS_ALL_PETITE_CAPS:
666 attrs = add_pango_attr (attrs, attr: pango_attr_variant_new (variant: PANGO_VARIANT_ALL_PETITE_CAPS));
667 break;
668 case GTK_CSS_FONT_VARIANT_CAPS_UNICASE:
669 attrs = add_pango_attr (attrs, attr: pango_attr_variant_new (variant: PANGO_VARIANT_UNICASE));
670 break;
671 case GTK_CSS_FONT_VARIANT_CAPS_TITLING_CAPS:
672 attrs = add_pango_attr (attrs, attr: pango_attr_variant_new (variant: PANGO_VARIANT_TITLE_CAPS));
673 break;
674 case GTK_CSS_FONT_VARIANT_CAPS_NORMAL:
675 default:
676 break;
677 }
678
679 /* OpenType features */
680 {
681 char *font_features = gtk_css_style_compute_font_features (style);
682
683 if (font_features)
684 {
685 attrs = add_pango_attr (attrs, attr: pango_attr_font_features_new (features: font_features));
686 g_free (mem: font_features);
687 }
688 }
689
690 /* text-transform */
691 {
692 PangoTextTransform transform = gtk_css_style_get_pango_text_transform (style);
693
694 if (transform != PANGO_TEXT_TRANSFORM_NONE)
695 attrs = add_pango_attr (attrs, attr: pango_attr_text_transform_new (transform));
696 }
697
698 return attrs;
699}
700
701PangoFontDescription *
702gtk_css_style_get_pango_font (GtkCssStyle *style)
703{
704 PangoFontDescription *description;
705 GtkCssValue *v;
706 char *str;
707
708 description = pango_font_description_new ();
709
710 v = style->font->font_family;
711 if (_gtk_css_array_value_get_n_values (value: v) > 1)
712 {
713 int i;
714 GString *s = g_string_new (init: "");
715
716 for (i = 0; i < _gtk_css_array_value_get_n_values (value: v); i++)
717 {
718 if (i > 0)
719 g_string_append (string: s, val: ",");
720 g_string_append (string: s, val: _gtk_css_string_value_get (string: _gtk_css_array_value_get_nth (value: v, i)));
721 }
722
723 pango_font_description_set_family (desc: description, family: s->str);
724 g_string_free (string: s, TRUE);
725 }
726 else
727 {
728 pango_font_description_set_family (desc: description,
729 family: _gtk_css_string_value_get (string: _gtk_css_array_value_get_nth (value: v, i: 0)));
730 }
731
732 v = style->core->font_size;
733 pango_font_description_set_absolute_size (desc: description, size: round (x: _gtk_css_number_value_get (number: v, one_hundred_percent: 100) * PANGO_SCALE));
734
735 v = style->font->font_style;
736 pango_font_description_set_style (desc: description, style: _gtk_css_font_style_value_get (value: v));
737
738 v = style->font->font_weight;
739 pango_font_description_set_weight (desc: description, weight: _gtk_css_number_value_get (number: v, one_hundred_percent: 100));
740
741 v = style->font->font_stretch;
742 pango_font_description_set_stretch (desc: description, stretch: _gtk_css_font_stretch_value_get (value: v));
743
744 v = style->font->font_variation_settings;
745 str = gtk_css_font_variations_value_get_variations (value: v);
746 if (str)
747 pango_font_description_set_variations (desc: description, variations: str);
748 g_free (mem: str);
749
750 return description;
751}
752
753/* Refcounted value structs */
754
755static const int values_size[] = {
756 sizeof (GtkCssCoreValues),
757 sizeof (GtkCssBackgroundValues),
758 sizeof (GtkCssBorderValues),
759 sizeof (GtkCssIconValues),
760 sizeof (GtkCssOutlineValues),
761 sizeof (GtkCssFontValues),
762 sizeof (GtkCssFontVariantValues),
763 sizeof (GtkCssAnimationValues),
764 sizeof (GtkCssTransitionValues),
765 sizeof (GtkCssSizeValues),
766 sizeof (GtkCssOtherValues)
767};
768
769#define TYPE_INDEX(type) ((type) - ((type) % 2))
770#define VALUES_SIZE(type) (values_size[(type) / 2])
771#define N_VALUES(type) ((VALUES_SIZE(type) - sizeof (GtkCssValues)) / sizeof (GtkCssValue *))
772
773#define GET_VALUES(v) (GtkCssValue **)((guint8 *)(v) + sizeof (GtkCssValues))
774
775GtkCssValues *gtk_css_values_ref (GtkCssValues *values)
776{
777 values->ref_count++;
778
779 return values;
780}
781
782static void
783gtk_css_values_free (GtkCssValues *values)
784{
785 int i;
786 GtkCssValue **v = GET_VALUES (values);
787
788 for (i = 0; i < N_VALUES (values->type); i++)
789 {
790 if (v[i])
791 gtk_css_value_unref (value: v[i]);
792 }
793
794 g_free (mem: values);
795}
796
797void gtk_css_values_unref (GtkCssValues *values)
798{
799 if (!values)
800 return;
801
802 values->ref_count--;
803
804 if (values->ref_count == 0)
805 gtk_css_values_free (values);
806}
807
808GtkCssValues *
809gtk_css_values_copy (GtkCssValues *values)
810{
811 GtkCssValues *copy;
812 GtkCssValue **v, **v2;
813 int i;
814
815 copy = gtk_css_values_new (TYPE_INDEX(values->type));
816
817 v = GET_VALUES (values);
818 v2 = GET_VALUES (copy);
819
820 for (i = 0; i < N_VALUES (values->type); i++)
821 {
822 if (v[i])
823 v2[i] = gtk_css_value_ref (value: v[i]);
824 }
825
826 return copy;
827}
828
829GtkCssValues *
830gtk_css_values_new (GtkCssValuesType type)
831{
832 GtkCssValues *values;
833
834 values = (GtkCssValues *)g_malloc0 (VALUES_SIZE(type));
835 values->ref_count = 1;
836 values->type = type;
837
838 return values;
839}
840

source code of gtk/gtk/gtkcssstyle.c