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