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 | |
43 | G_DEFINE_ABSTRACT_TYPE (GtkCssStyle, gtk_css_style, G_TYPE_OBJECT) |
44 | |
45 | static GtkCssSection * |
46 | gtk_css_style_real_get_section (GtkCssStyle *style, |
47 | guint id) |
48 | { |
49 | return NULL; |
50 | } |
51 | |
52 | static gboolean |
53 | gtk_css_style_real_is_static (GtkCssStyle *style) |
54 | { |
55 | return TRUE; |
56 | } |
57 | |
58 | |
59 | static void |
60 | gtk_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 | |
79 | static void |
80 | gtk_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 | |
90 | static void |
91 | gtk_css_style_init (GtkCssStyle *style) |
92 | { |
93 | } |
94 | |
95 | GtkCssValue * |
96 | gtk_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 | |
291 | GtkCssSection * |
292 | gtk_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 | |
300 | gboolean |
301 | gtk_css_style_is_static (GtkCssStyle *style) |
302 | { |
303 | return GTK_CSS_STYLE_GET_CLASS (style)->is_static (style); |
304 | } |
305 | |
306 | GtkCssStaticStyle * |
307 | gtk_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 | */ |
328 | gboolean |
329 | gtk_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 | |
374 | char * |
375 | gtk_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 | |
388 | static PangoUnderline |
389 | get_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 | |
405 | PangoTextTransform |
406 | gtk_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 | |
423 | static PangoOverline |
424 | get_pango_overline_from_style (GtkTextDecorationStyle style) |
425 | { |
426 | return PANGO_OVERLINE_SINGLE; |
427 | } |
428 | |
429 | static PangoAttrList * |
430 | add_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 | |
441 | static void |
442 | append_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 | |
454 | char * |
455 | gtk_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 | |
591 | PangoAttrList * |
592 | gtk_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 | |
701 | PangoFontDescription * |
702 | gtk_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 | |
755 | static 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 | |
775 | GtkCssValues *gtk_css_values_ref (GtkCssValues *values) |
776 | { |
777 | values->ref_count++; |
778 | |
779 | return values; |
780 | } |
781 | |
782 | static void |
783 | gtk_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 | |
797 | void 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 | |
808 | GtkCssValues * |
809 | gtk_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 | |
829 | GtkCssValues * |
830 | gtk_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 | |