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 "gtkcssanimatedstyleprivate.h"
23
24#include "gtkcssanimationprivate.h"
25#include "gtkcssarrayvalueprivate.h"
26#include "gtkcssdynamicprivate.h"
27#include "gtkcssenumvalueprivate.h"
28#include "gtkcssinheritvalueprivate.h"
29#include "gtkcssinitialvalueprivate.h"
30#include "gtkcssnumbervalueprivate.h"
31#include "gtkcssshorthandpropertyprivate.h"
32#include "gtkcssstaticstyleprivate.h"
33#include "gtkcssstringvalueprivate.h"
34#include "gtkcssstylepropertyprivate.h"
35#include "gtkcsstransitionprivate.h"
36#include "gtkprivate.h"
37#include "gtkstyleanimationprivate.h"
38#include "gtkstylepropertyprivate.h"
39#include "gtkstyleproviderprivate.h"
40
41G_DEFINE_TYPE (GtkCssAnimatedStyle, gtk_css_animated_style, GTK_TYPE_CSS_STYLE)
42
43
44static GtkCssSection *
45gtk_css_animated_style_get_section (GtkCssStyle *style,
46 guint id)
47{
48 GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style);
49
50 return gtk_css_style_get_section (style: animated->style, id);
51}
52
53static gboolean
54gtk_css_animated_style_is_static (GtkCssStyle *style)
55{
56 GtkCssAnimatedStyle *animated = (GtkCssAnimatedStyle *)style;
57 guint i;
58
59 for (i = 0; i < animated->n_animations; i ++)
60 {
61 if (!_gtk_style_animation_is_static (animation: animated->animations[i]))
62 return FALSE;
63 }
64
65 return TRUE;
66}
67
68static GtkCssStaticStyle *
69gtk_css_animated_style_get_static_style (GtkCssStyle *style)
70{
71 /* This is called a lot, so we avoid a dynamic type check here */
72 GtkCssAnimatedStyle *animated = (GtkCssAnimatedStyle *) style;
73
74 return (GtkCssStaticStyle *)animated->style;
75}
76
77static void
78gtk_css_animated_style_dispose (GObject *object)
79{
80 GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object);
81 guint i;
82
83 for (i = 0; i < style->n_animations; i ++)
84 gtk_style_animation_unref (animation: style->animations[i]);
85
86 style->n_animations = 0;
87 g_free (mem: style->animations);
88 style->animations = NULL;
89
90 G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->dispose (object);
91}
92
93static void
94gtk_css_animated_style_finalize (GObject *object)
95{
96 GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object);
97
98 g_object_unref (object: style->style);
99
100 G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->finalize (object);
101}
102
103static void
104gtk_css_animated_style_class_init (GtkCssAnimatedStyleClass *klass)
105{
106 GObjectClass *object_class = G_OBJECT_CLASS (klass);
107 GtkCssStyleClass *style_class = GTK_CSS_STYLE_CLASS (klass);
108
109 object_class->dispose = gtk_css_animated_style_dispose;
110 object_class->finalize = gtk_css_animated_style_finalize;
111
112 style_class->get_section = gtk_css_animated_style_get_section;
113 style_class->is_static = gtk_css_animated_style_is_static;
114 style_class->get_static_style = gtk_css_animated_style_get_static_style;
115}
116
117static void
118gtk_css_animated_style_init (GtkCssAnimatedStyle *style)
119{
120}
121
122#define DEFINE_UNSHARE(TYPE, NAME) \
123static inline void \
124unshare_ ## NAME (GtkCssAnimatedStyle *animated) \
125{ \
126 GtkCssStyle *style = (GtkCssStyle *)animated; \
127 if (style->NAME == animated->style->NAME) \
128 { \
129 gtk_css_values_unref ((GtkCssValues *)style->NAME); \
130 style->NAME = (TYPE *)gtk_css_values_copy ((GtkCssValues *)animated->style->NAME); \
131 } \
132}
133
134DEFINE_UNSHARE (GtkCssCoreValues, core)
135DEFINE_UNSHARE (GtkCssBackgroundValues, background)
136DEFINE_UNSHARE (GtkCssBorderValues, border)
137DEFINE_UNSHARE (GtkCssIconValues, icon)
138DEFINE_UNSHARE (GtkCssOutlineValues, outline)
139DEFINE_UNSHARE (GtkCssFontValues, font)
140DEFINE_UNSHARE (GtkCssFontVariantValues, font_variant)
141DEFINE_UNSHARE (GtkCssAnimationValues, animation)
142DEFINE_UNSHARE (GtkCssTransitionValues, transition)
143DEFINE_UNSHARE (GtkCssSizeValues, size)
144DEFINE_UNSHARE (GtkCssOtherValues, other)
145
146static inline void
147gtk_css_take_value (GtkCssValue **variable,
148 GtkCssValue *value)
149{
150 if (*variable)
151 gtk_css_value_unref (value: *variable);
152 *variable = value;
153}
154
155void
156gtk_css_animated_style_set_animated_value (GtkCssAnimatedStyle *animated,
157 guint id,
158 GtkCssValue *value)
159{
160 GtkCssStyle *style = (GtkCssStyle *)animated;
161
162 gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
163 gtk_internal_return_if_fail (value != NULL);
164
165 switch (id)
166 {
167 case GTK_CSS_PROPERTY_COLOR:
168 unshare_core (animated);
169 gtk_css_take_value (variable: &style->core->color, value);
170 break;
171 case GTK_CSS_PROPERTY_DPI:
172 unshare_core (animated);
173 gtk_css_take_value (variable: &style->core->dpi, value);
174 break;
175 case GTK_CSS_PROPERTY_FONT_SIZE:
176 unshare_core (animated);
177 gtk_css_take_value (variable: &style->core->font_size, value);
178 break;
179 case GTK_CSS_PROPERTY_ICON_PALETTE:
180 unshare_core (animated);
181 gtk_css_take_value (variable: &style->core->icon_palette, value);
182 break;
183 case GTK_CSS_PROPERTY_BACKGROUND_COLOR:
184 unshare_background (animated);
185 gtk_css_take_value (variable: &style->background->background_color, value);
186 break;
187 case GTK_CSS_PROPERTY_FONT_FAMILY:
188 unshare_font (animated);
189 gtk_css_take_value (variable: &style->font->font_family, value);
190 break;
191 case GTK_CSS_PROPERTY_FONT_STYLE:
192 unshare_font (animated);
193 gtk_css_take_value (variable: &style->font->font_style, value);
194 break;
195 case GTK_CSS_PROPERTY_FONT_WEIGHT:
196 unshare_font (animated);
197 gtk_css_take_value (variable: &style->font->font_weight, value);
198 break;
199 case GTK_CSS_PROPERTY_FONT_STRETCH:
200 unshare_font (animated);
201 gtk_css_take_value (variable: &style->font->font_stretch, value);
202 break;
203 case GTK_CSS_PROPERTY_LETTER_SPACING:
204 unshare_font (animated);
205 gtk_css_take_value (variable: &style->font->letter_spacing, value);
206 break;
207 case GTK_CSS_PROPERTY_LINE_HEIGHT:
208 unshare_font (animated);
209 gtk_css_take_value (variable: &style->font->line_height, value);
210 break;
211 case GTK_CSS_PROPERTY_TEXT_DECORATION_LINE:
212 unshare_font_variant (animated);
213 gtk_css_take_value (variable: &style->font_variant->text_decoration_line, value);
214 break;
215 case GTK_CSS_PROPERTY_TEXT_DECORATION_COLOR:
216 unshare_font_variant (animated);
217 gtk_css_take_value (variable: &style->font_variant->text_decoration_color, value);
218 break;
219 case GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE:
220 unshare_font_variant (animated);
221 gtk_css_take_value (variable: &style->font_variant->text_decoration_style, value);
222 break;
223 case GTK_CSS_PROPERTY_TEXT_TRANSFORM:
224 unshare_font_variant (animated);
225 gtk_css_take_value (variable: &style->font_variant->text_transform, value);
226 break;
227 case GTK_CSS_PROPERTY_FONT_KERNING:
228 unshare_font_variant (animated);
229 gtk_css_take_value (variable: &style->font_variant->font_kerning, value);
230 break;
231 case GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES:
232 unshare_font_variant (animated);
233 gtk_css_take_value (variable: &style->font_variant->font_variant_ligatures, value);
234 break;
235 case GTK_CSS_PROPERTY_FONT_VARIANT_POSITION:
236 unshare_font_variant (animated);
237 gtk_css_take_value (variable: &style->font_variant->font_variant_position, value);
238 break;
239 case GTK_CSS_PROPERTY_FONT_VARIANT_CAPS:
240 unshare_font_variant (animated);
241 gtk_css_take_value (variable: &style->font_variant->font_variant_caps, value);
242 break;
243 case GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC:
244 unshare_font_variant (animated);
245 gtk_css_take_value (variable: &style->font_variant->font_variant_numeric, value);
246 break;
247 case GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES:
248 unshare_font_variant (animated);
249 gtk_css_take_value (variable: &style->font_variant->font_variant_alternates, value);
250 break;
251 case GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN:
252 unshare_font_variant (animated);
253 gtk_css_take_value (variable: &style->font_variant->font_variant_east_asian, value);
254 break;
255 case GTK_CSS_PROPERTY_TEXT_SHADOW:
256 unshare_font (animated);
257 gtk_css_take_value (variable: &style->font->text_shadow, value);
258 break;
259 case GTK_CSS_PROPERTY_BOX_SHADOW:
260 unshare_background (animated);
261 gtk_css_take_value (variable: &style->background->box_shadow, value);
262 break;
263 case GTK_CSS_PROPERTY_MARGIN_TOP:
264 unshare_size (animated);
265 gtk_css_take_value (variable: &style->size->margin_top, value);
266 break;
267 case GTK_CSS_PROPERTY_MARGIN_LEFT:
268 unshare_size (animated);
269 gtk_css_take_value (variable: &style->size->margin_left, value);
270 break;
271 case GTK_CSS_PROPERTY_MARGIN_BOTTOM:
272 unshare_size (animated);
273 gtk_css_take_value (variable: &style->size->margin_bottom, value);
274 break;
275 case GTK_CSS_PROPERTY_MARGIN_RIGHT:
276 unshare_size (animated);
277 gtk_css_take_value (variable: &style->size->margin_right, value);
278 break;
279 case GTK_CSS_PROPERTY_PADDING_TOP:
280 unshare_size (animated);
281 gtk_css_take_value (variable: &style->size->padding_top, value);
282 break;
283 case GTK_CSS_PROPERTY_PADDING_LEFT:
284 unshare_size (animated);
285 gtk_css_take_value (variable: &style->size->padding_left, value);
286 break;
287 case GTK_CSS_PROPERTY_PADDING_BOTTOM:
288 unshare_size (animated);
289 gtk_css_take_value (variable: &style->size->padding_bottom, value);
290 break;
291 case GTK_CSS_PROPERTY_PADDING_RIGHT:
292 unshare_size (animated);
293 gtk_css_take_value (variable: &style->size->padding_right, value);
294 break;
295 case GTK_CSS_PROPERTY_BORDER_TOP_STYLE:
296 unshare_border (animated);
297 gtk_css_take_value (variable: &style->border->border_top_style, value);
298 break;
299 case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH:
300 unshare_border (animated);
301 gtk_css_take_value (variable: &style->border->border_top_width, value);
302 break;
303 case GTK_CSS_PROPERTY_BORDER_LEFT_STYLE:
304 unshare_border (animated);
305 gtk_css_take_value (variable: &style->border->border_left_style, value);
306 break;
307 case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH:
308 unshare_border (animated);
309 gtk_css_take_value (variable: &style->border->border_left_width, value);
310 break;
311 case GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE:
312 unshare_border (animated);
313 gtk_css_take_value (variable: &style->border->border_bottom_style, value);
314 break;
315 case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
316 unshare_border (animated);
317 gtk_css_take_value (variable: &style->border->border_bottom_width, value);
318 break;
319 case GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE:
320 unshare_border (animated);
321 gtk_css_take_value (variable: &style->border->border_right_style, value);
322 break;
323 case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH:
324 unshare_border (animated);
325 gtk_css_take_value (variable: &style->border->border_right_width, value);
326 break;
327 case GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS:
328 unshare_border (animated);
329 gtk_css_take_value (variable: &style->border->border_top_left_radius, value);
330 break;
331 case GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS:
332 unshare_border (animated);
333 gtk_css_take_value (variable: &style->border->border_top_right_radius, value);
334 break;
335 case GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS:
336 unshare_border (animated);
337 gtk_css_take_value (variable: &style->border->border_bottom_right_radius, value);
338 break;
339 case GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS:
340 unshare_border (animated);
341 gtk_css_take_value (variable: &style->border->border_bottom_left_radius, value);
342 break;
343 case GTK_CSS_PROPERTY_OUTLINE_STYLE:
344 unshare_outline (animated);
345 gtk_css_take_value (variable: &style->outline->outline_style, value);
346 break;
347 case GTK_CSS_PROPERTY_OUTLINE_WIDTH:
348 unshare_outline (animated);
349 gtk_css_take_value (variable: &style->outline->outline_width, value);
350 break;
351 case GTK_CSS_PROPERTY_OUTLINE_OFFSET:
352 unshare_outline (animated);
353 gtk_css_take_value (variable: &style->outline->outline_offset, value);
354 break;
355 case GTK_CSS_PROPERTY_BACKGROUND_CLIP:
356 unshare_background (animated);
357 gtk_css_take_value (variable: &style->background->background_clip, value);
358 break;
359 case GTK_CSS_PROPERTY_BACKGROUND_ORIGIN:
360 unshare_background (animated);
361 gtk_css_take_value (variable: &style->background->background_origin, value);
362 break;
363 case GTK_CSS_PROPERTY_BACKGROUND_SIZE:
364 unshare_background (animated);
365 gtk_css_take_value (variable: &style->background->background_size, value);
366 break;
367 case GTK_CSS_PROPERTY_BACKGROUND_POSITION:
368 unshare_background (animated);
369 gtk_css_take_value (variable: &style->background->background_position, value);
370 break;
371 case GTK_CSS_PROPERTY_BORDER_TOP_COLOR:
372 unshare_border (animated);
373 gtk_css_take_value (variable: &style->border->border_top_color, value);
374 break;
375 case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR:
376 unshare_border (animated);
377 gtk_css_take_value (variable: &style->border->border_right_color, value);
378 break;
379 case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR:
380 unshare_border (animated);
381 gtk_css_take_value (variable: &style->border->border_bottom_color, value);
382 break;
383 case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR:
384 unshare_border (animated);
385 gtk_css_take_value (variable: &style->border->border_left_color, value);
386 break;
387 case GTK_CSS_PROPERTY_OUTLINE_COLOR:
388 unshare_outline (animated);
389 gtk_css_take_value (variable: &style->outline->outline_color, value);
390 break;
391 case GTK_CSS_PROPERTY_BACKGROUND_REPEAT:
392 unshare_background (animated);
393 gtk_css_take_value (variable: &style->background->background_repeat, value);
394 break;
395 case GTK_CSS_PROPERTY_BACKGROUND_IMAGE:
396 unshare_background (animated);
397 gtk_css_take_value (variable: &style->background->background_image, value);
398 break;
399 case GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE:
400 unshare_background (animated);
401 gtk_css_take_value (variable: &style->background->background_blend_mode, value);
402 break;
403 case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE:
404 unshare_border (animated);
405 gtk_css_take_value (variable: &style->border->border_image_source, value);
406 break;
407 case GTK_CSS_PROPERTY_BORDER_IMAGE_REPEAT:
408 unshare_border (animated);
409 gtk_css_take_value (variable: &style->border->border_image_repeat, value);
410 break;
411 case GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE:
412 unshare_border (animated);
413 gtk_css_take_value (variable: &style->border->border_image_slice, value);
414 break;
415 case GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH:
416 unshare_border (animated);
417 gtk_css_take_value (variable: &style->border->border_image_width, value);
418 break;
419 case GTK_CSS_PROPERTY_ICON_SOURCE:
420 unshare_other (animated);
421 gtk_css_take_value (variable: &style->other->icon_source, value);
422 break;
423 case GTK_CSS_PROPERTY_ICON_SIZE:
424 unshare_icon (animated);
425 gtk_css_take_value (variable: &style->icon->icon_size, value);
426 break;
427 case GTK_CSS_PROPERTY_ICON_SHADOW:
428 unshare_icon (animated);
429 gtk_css_take_value (variable: &style->icon->icon_shadow, value);
430 break;
431 case GTK_CSS_PROPERTY_ICON_STYLE:
432 unshare_icon (animated);
433 gtk_css_take_value (variable: &style->icon->icon_style, value);
434 break;
435 case GTK_CSS_PROPERTY_ICON_TRANSFORM:
436 unshare_other (animated);
437 gtk_css_take_value (variable: &style->other->icon_transform, value);
438 break;
439 case GTK_CSS_PROPERTY_ICON_FILTER:
440 unshare_other (animated);
441 gtk_css_take_value (variable: &style->other->icon_filter, value);
442 break;
443 case GTK_CSS_PROPERTY_BORDER_SPACING:
444 unshare_size (animated);
445 gtk_css_take_value (variable: &style->size->border_spacing, value);
446 break;
447 case GTK_CSS_PROPERTY_TRANSFORM:
448 unshare_other (animated);
449 gtk_css_take_value (variable: &style->other->transform, value);
450 break;
451 case GTK_CSS_PROPERTY_TRANSFORM_ORIGIN:
452 unshare_other (animated);
453 gtk_css_take_value (variable: &style->other->transform_origin, value);
454 break;
455 case GTK_CSS_PROPERTY_MIN_WIDTH:
456 unshare_size (animated);
457 gtk_css_take_value (variable: &style->size->min_width, value);
458 break;
459 case GTK_CSS_PROPERTY_MIN_HEIGHT:
460 unshare_size (animated);
461 gtk_css_take_value (variable: &style->size->min_height, value);
462 break;
463 case GTK_CSS_PROPERTY_TRANSITION_PROPERTY:
464 unshare_transition (animated);
465 gtk_css_take_value (variable: &style->transition->transition_property, value);
466 break;
467 case GTK_CSS_PROPERTY_TRANSITION_DURATION:
468 unshare_transition (animated);
469 gtk_css_take_value (variable: &style->transition->transition_duration, value);
470 break;
471 case GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION:
472 unshare_transition (animated);
473 gtk_css_take_value (variable: &style->transition->transition_timing_function, value);
474 break;
475 case GTK_CSS_PROPERTY_TRANSITION_DELAY:
476 unshare_transition (animated);
477 gtk_css_take_value (variable: &style->transition->transition_delay, value);
478 break;
479 case GTK_CSS_PROPERTY_ANIMATION_NAME:
480 unshare_animation (animated);
481 gtk_css_take_value (variable: &style->animation->animation_name, value);
482 break;
483 case GTK_CSS_PROPERTY_ANIMATION_DURATION:
484 unshare_animation (animated);
485 gtk_css_take_value (variable: &style->animation->animation_duration, value);
486 break;
487 case GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION:
488 unshare_animation (animated);
489 gtk_css_take_value (variable: &style->animation->animation_timing_function, value);
490 break;
491 case GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT:
492 unshare_animation (animated);
493 gtk_css_take_value (variable: &style->animation->animation_iteration_count, value);
494 break;
495 case GTK_CSS_PROPERTY_ANIMATION_DIRECTION:
496 unshare_animation (animated);
497 gtk_css_take_value (variable: &style->animation->animation_direction, value);
498 break;
499 case GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE:
500 unshare_animation (animated);
501 gtk_css_take_value (variable: &style->animation->animation_play_state, value);
502 break;
503 case GTK_CSS_PROPERTY_ANIMATION_DELAY:
504 unshare_animation (animated);
505 gtk_css_take_value (variable: &style->animation->animation_delay, value);
506 break;
507 case GTK_CSS_PROPERTY_ANIMATION_FILL_MODE:
508 unshare_animation (animated);
509 gtk_css_take_value (variable: &style->animation->animation_fill_mode, value);
510 break;
511 case GTK_CSS_PROPERTY_OPACITY:
512 unshare_other (animated);
513 gtk_css_take_value (variable: &style->other->opacity, value);
514 break;
515 case GTK_CSS_PROPERTY_FILTER:
516 unshare_other (animated);
517 gtk_css_take_value (variable: &style->other->filter, value);
518 break;
519 case GTK_CSS_PROPERTY_CARET_COLOR:
520 unshare_font (animated);
521 gtk_css_take_value (variable: &style->font->caret_color, value);
522 break;
523 case GTK_CSS_PROPERTY_SECONDARY_CARET_COLOR:
524 unshare_font (animated);
525 gtk_css_take_value (variable: &style->font->secondary_caret_color, value);
526 break;
527 case GTK_CSS_PROPERTY_FONT_FEATURE_SETTINGS:
528 unshare_font (animated);
529 gtk_css_take_value (variable: &style->font->font_feature_settings, value);
530 break;
531 case GTK_CSS_PROPERTY_FONT_VARIATION_SETTINGS:
532 unshare_font (animated);
533 gtk_css_take_value (variable: &style->font->font_variation_settings, value);
534 break;
535
536 default:
537 g_assert_not_reached ();
538 break;
539 }
540}
541
542GtkCssValue *
543gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style,
544 guint id)
545{
546 return gtk_css_style_get_value (style: style->style, id);
547}
548
549static GPtrArray *
550gtk_css_animated_style_create_dynamic (GPtrArray *animations,
551 GtkCssStyle *style,
552 gint64 timestamp)
553{
554 guint i;
555
556 /* XXX: Check animations if they have dynamic values */
557
558 for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++)
559 {
560 if (gtk_css_value_is_dynamic (value: gtk_css_style_get_value (style, id: i)))
561 {
562 if (!animations)
563 animations = g_ptr_array_new ();
564
565 g_ptr_array_insert (array: animations, index_: 0, data: gtk_css_dynamic_new (timestamp));
566 break;
567 }
568 }
569
570 return animations;
571}
572
573/* TRANSITIONS */
574
575typedef struct _TransitionInfo TransitionInfo;
576struct _TransitionInfo {
577 guint index; /* index into value arrays */
578 gboolean pending; /* TRUE if we still need to handle it */
579};
580
581static void
582transition_info_add (TransitionInfo infos[GTK_CSS_PROPERTY_N_PROPERTIES],
583 GtkStyleProperty *property,
584 guint index)
585{
586 if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
587 {
588 GtkCssShorthandProperty *shorthand = (GtkCssShorthandProperty *) property;
589 guint len = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
590 guint i;
591
592 for (i = 0; i < len; i++)
593 {
594 GtkCssStyleProperty *prop = _gtk_css_shorthand_property_get_subproperty (shorthand, property: i);
595 guint id;
596
597 if (!_gtk_css_style_property_is_animated (property: (GtkCssStyleProperty *) prop))
598 continue;
599
600 id = _gtk_css_style_property_get_id (property: (GtkCssStyleProperty *) prop);
601 infos[id].index = index;
602 infos[id].pending = TRUE;
603 }
604 }
605 else
606 {
607 guint id;
608
609 if (!_gtk_css_style_property_is_animated (property: (GtkCssStyleProperty *) property))
610 return;
611
612 id = _gtk_css_style_property_get_id (property: (GtkCssStyleProperty *) property);
613 g_assert (id < GTK_CSS_PROPERTY_N_PROPERTIES);
614 infos[id].index = index;
615 infos[id].pending = TRUE;
616 }
617}
618
619static void
620transition_infos_set (TransitionInfo infos[GTK_CSS_PROPERTY_N_PROPERTIES],
621 GtkCssValue *transitions)
622{
623 guint i;
624
625 for (i = 0; i < _gtk_css_array_value_get_n_values (value: transitions); i++)
626 {
627 GtkStyleProperty *property;
628 GtkCssValue *prop_value;
629
630 prop_value = _gtk_css_array_value_get_nth (value: transitions, i);
631 if (g_ascii_strcasecmp (s1: _gtk_css_ident_value_get (ident: prop_value), s2: "all") == 0)
632 {
633 const guint len = _gtk_css_style_property_get_n_properties ();
634 guint j;
635
636 for (j = 0; j < len; j++)
637 {
638 property = (GtkStyleProperty *)_gtk_css_style_property_lookup_by_id (id: j);
639 transition_info_add (infos, property, index: i);
640 }
641 }
642 else
643 {
644 property = _gtk_style_property_lookup (name: _gtk_css_ident_value_get (ident: prop_value));
645 if (property)
646 transition_info_add (infos, property, index: i);
647 }
648 }
649}
650
651static GtkStyleAnimation *
652gtk_css_animated_style_find_transition (GtkCssAnimatedStyle *style,
653 guint property_id)
654{
655 guint i;
656
657 for (i = 0; i < style->n_animations; i ++)
658 {
659 GtkStyleAnimation *animation = style->animations[i];
660
661 if (!_gtk_css_transition_is_transition (animation))
662 continue;
663
664 if (_gtk_css_transition_get_property (transition: (GtkCssTransition *)animation) == property_id)
665 return animation;
666 }
667
668 return NULL;
669}
670
671static GPtrArray *
672gtk_css_animated_style_create_css_transitions (GPtrArray *animations,
673 GtkCssStyle *base_style,
674 gint64 timestamp,
675 GtkCssStyle *source)
676{
677 TransitionInfo transitions[GTK_CSS_PROPERTY_N_PROPERTIES] = { { 0, } };
678 GtkCssValue *durations, *delays, *timing_functions;
679 gboolean source_is_animated;
680 guint i;
681
682 durations = base_style->transition->transition_duration;
683 delays = base_style->transition->transition_delay;
684 timing_functions = base_style->transition->transition_timing_function;
685
686 if (_gtk_css_array_value_get_n_values (value: durations) == 1 &&
687 _gtk_css_array_value_get_n_values (value: delays) == 1 &&
688 _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: durations, i: 0), one_hundred_percent: 100) +
689 _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: delays, i: 0), one_hundred_percent: 100) == 0)
690 return animations;
691
692 transition_infos_set (infos: transitions, transitions: base_style->transition->transition_property);
693
694 source_is_animated = GTK_IS_CSS_ANIMATED_STYLE (source);
695 for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++)
696 {
697 GtkStyleAnimation *animation;
698 GtkCssValue *start, *end;
699 double duration, delay;
700
701 if (!transitions[i].pending)
702 continue;
703
704 duration = _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: durations, i: transitions[i].index), one_hundred_percent: 100);
705 delay = _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: delays, i: transitions[i].index), one_hundred_percent: 100);
706 if (duration + delay == 0.0)
707 continue;
708
709 if (source_is_animated)
710 {
711 start = gtk_css_animated_style_get_intrinsic_value (style: (GtkCssAnimatedStyle *)source, id: i);
712 end = gtk_css_style_get_value (style: base_style, id: i);
713
714 if (_gtk_css_value_equal (value1: start, value2: end))
715 {
716 animation = gtk_css_animated_style_find_transition (style: (GtkCssAnimatedStyle *)source, property_id: i);
717 if (animation)
718 {
719 animation = _gtk_style_animation_advance (animation, timestamp);
720 if (!animations)
721 animations = g_ptr_array_new ();
722
723 g_ptr_array_add (array: animations, data: animation);
724 }
725
726 continue;
727 }
728 }
729
730 if (_gtk_css_value_equal (value1: gtk_css_style_get_value (style: source, id: i),
731 value2: gtk_css_style_get_value (style: base_style, id: i)))
732 continue;
733
734 animation = _gtk_css_transition_new (property: i,
735 start: gtk_css_style_get_value (style: source, id: i),
736 ease: _gtk_css_array_value_get_nth (value: timing_functions, i),
737 timestamp,
738 duration_us: duration * G_USEC_PER_SEC,
739 delay_us: delay * G_USEC_PER_SEC);
740 if (!animations)
741 animations = g_ptr_array_new ();
742
743 g_ptr_array_add (array: animations, data: animation);
744 }
745
746 return animations;
747}
748
749static GtkStyleAnimation *
750gtk_css_animated_style_find_animation (GtkStyleAnimation **animations,
751 guint n_animations,
752 const char *name)
753{
754 guint i;
755
756 for (i = 0; i < n_animations; i ++)
757 {
758 GtkStyleAnimation *animation = animations[i];
759
760 if (!_gtk_css_animation_is_animation (animation))
761 continue;
762
763 if (g_str_equal (v1: _gtk_css_animation_get_name (animation: (GtkCssAnimation *)animation), v2: name))
764 return animation;
765 }
766
767 return NULL;
768}
769
770static GPtrArray *
771gtk_css_animated_style_create_css_animations (GPtrArray *animations,
772 GtkCssStyle *base_style,
773 GtkCssStyle *parent_style,
774 gint64 timestamp,
775 GtkStyleProvider *provider,
776 GtkCssStyle *source)
777{
778 GtkCssValue *durations, *delays, *timing_functions, *animation_names;
779 GtkCssValue *iteration_counts, *directions, *play_states, *fill_modes;
780 gboolean source_is_animated;
781 guint i;
782
783 animation_names = base_style->animation->animation_name;
784
785 if (_gtk_css_array_value_get_n_values (value: animation_names) == 1)
786 {
787 const char *name = _gtk_css_ident_value_get (ident: _gtk_css_array_value_get_nth (value: animation_names, i: 0));
788
789 if (g_ascii_strcasecmp (s1: name, s2: "none") == 0)
790 return animations;
791 }
792
793 durations = base_style->animation->animation_duration;
794 delays = base_style->animation->animation_delay;
795 timing_functions = base_style->animation->animation_timing_function;
796 iteration_counts = base_style->animation->animation_iteration_count;
797 directions = base_style->animation->animation_direction;
798 play_states = base_style->animation->animation_play_state;
799 fill_modes = base_style->animation->animation_fill_mode;
800 source_is_animated = GTK_IS_CSS_ANIMATED_STYLE (source);
801
802 for (i = 0; i < _gtk_css_array_value_get_n_values (value: animation_names); i++)
803 {
804 GtkStyleAnimation *animation = NULL;
805 GtkCssKeyframes *keyframes;
806 const char *name;
807
808 name = _gtk_css_ident_value_get (ident: _gtk_css_array_value_get_nth (value: animation_names, i));
809 if (g_ascii_strcasecmp (s1: name, s2: "none") == 0)
810 continue;
811
812 if (animations)
813 animation = gtk_css_animated_style_find_animation (animations: (GtkStyleAnimation **)animations->pdata, n_animations: animations->len, name);
814
815 if (animation)
816 continue;
817
818 if (source_is_animated)
819 animation = gtk_css_animated_style_find_animation (animations: (GtkStyleAnimation **)GTK_CSS_ANIMATED_STYLE (source)->animations,
820 GTK_CSS_ANIMATED_STYLE (source)->n_animations,
821 name);
822
823 if (animation)
824 {
825 animation = _gtk_css_animation_advance_with_play_state (animation: (GtkCssAnimation *)animation,
826 timestamp,
827 play_state: _gtk_css_play_state_value_get (value: _gtk_css_array_value_get_nth (value: play_states, i)));
828 }
829 else
830 {
831 keyframes = gtk_style_provider_get_keyframes (provider, name);
832 if (keyframes == NULL)
833 continue;
834
835 keyframes = _gtk_css_keyframes_compute (keyframes, provider, style: base_style, parent_style);
836
837 animation = _gtk_css_animation_new (name,
838 keyframes,
839 timestamp,
840 delay_us: _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: delays, i), one_hundred_percent: 100) * G_USEC_PER_SEC,
841 duration_us: _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: durations, i), one_hundred_percent: 100) * G_USEC_PER_SEC,
842 ease: _gtk_css_array_value_get_nth (value: timing_functions, i),
843 direction: _gtk_css_direction_value_get (value: _gtk_css_array_value_get_nth (value: directions, i)),
844 play_state: _gtk_css_play_state_value_get (value: _gtk_css_array_value_get_nth (value: play_states, i)),
845 fill_mode: _gtk_css_fill_mode_value_get (value: _gtk_css_array_value_get_nth (value: fill_modes, i)),
846 iteration_count: _gtk_css_number_value_get (number: _gtk_css_array_value_get_nth (value: iteration_counts, i), one_hundred_percent: 100));
847 _gtk_css_keyframes_unref (keyframes);
848 }
849
850 if (!animations)
851 animations = g_ptr_array_sized_new (reserved_size: 16);
852
853 g_ptr_array_add (array: animations, data: animation);
854 }
855
856 return animations;
857}
858
859/* PUBLIC API */
860
861static void
862gtk_css_animated_style_apply_animations (GtkCssAnimatedStyle *style)
863{
864 guint i;
865
866 for (i = 0; i < style->n_animations; i ++)
867 {
868 GtkStyleAnimation *animation = style->animations[i];
869
870 _gtk_style_animation_apply_values (animation, style);
871 }
872}
873
874GtkCssStyle *
875gtk_css_animated_style_new (GtkCssStyle *base_style,
876 GtkCssStyle *parent_style,
877 gint64 timestamp,
878 GtkStyleProvider *provider,
879 GtkCssStyle *previous_style)
880{
881 GtkCssAnimatedStyle *result;
882 GtkCssStyle *style;
883 GPtrArray *animations = NULL;
884
885 gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (base_style), NULL);
886 gtk_internal_return_val_if_fail (parent_style == NULL || GTK_IS_CSS_STYLE (parent_style), NULL);
887 gtk_internal_return_val_if_fail (GTK_IS_STYLE_PROVIDER (provider), NULL);
888 gtk_internal_return_val_if_fail (previous_style == NULL || GTK_IS_CSS_STYLE (previous_style), NULL);
889
890 if (timestamp == 0)
891 return g_object_ref (base_style);
892
893 if (previous_style != NULL)
894 animations = gtk_css_animated_style_create_css_transitions (animations, base_style, timestamp, source: previous_style);
895
896 animations = gtk_css_animated_style_create_css_animations (animations, base_style, parent_style, timestamp, provider, source: previous_style);
897 animations = gtk_css_animated_style_create_dynamic (animations, style: base_style, timestamp);
898
899 if (animations == NULL)
900 return g_object_ref (base_style);
901
902 result = g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL);
903
904 result->style = g_object_ref (base_style);
905 result->current_time = timestamp;
906 result->n_animations = animations->len;
907 result->animations = g_ptr_array_free (array: animations, FALSE);
908
909 style = (GtkCssStyle *)result;
910 style->core = (GtkCssCoreValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->core);
911 style->background = (GtkCssBackgroundValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->background);
912 style->border = (GtkCssBorderValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->border);
913 style->icon = (GtkCssIconValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->icon);
914 style->outline = (GtkCssOutlineValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->outline);
915 style->font = (GtkCssFontValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font);
916 style->font_variant = (GtkCssFontVariantValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font_variant);
917 style->animation = (GtkCssAnimationValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->animation);
918 style->transition = (GtkCssTransitionValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->transition);
919 style->size = (GtkCssSizeValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->size);
920 style->other = (GtkCssOtherValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->other);
921
922 gtk_css_animated_style_apply_animations (style: result);
923
924 return GTK_CSS_STYLE (result);
925}
926
927GtkCssStyle *
928gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
929 GtkCssStyle *base_style,
930 gint64 timestamp)
931{
932 GtkCssAnimatedStyle *result;
933 GtkCssStyle *style;
934 GPtrArray *animations;
935 guint i;
936
937 gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (source), NULL);
938 gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (base_style), NULL);
939
940 if (timestamp == 0 || timestamp == source->current_time)
941 return g_object_ref (source->style);
942
943 gtk_internal_return_val_if_fail (timestamp > source->current_time, NULL);
944
945 animations = NULL;
946 for (i = 0; i < source->n_animations; i ++)
947 {
948 GtkStyleAnimation *animation = source->animations[i];
949
950 if (_gtk_style_animation_is_finished (animation))
951 continue;
952
953 if (!animations)
954 animations = g_ptr_array_sized_new (reserved_size: 16);
955
956 animation = _gtk_style_animation_advance (animation, timestamp);
957 g_ptr_array_add (array: animations, data: animation);
958 }
959
960 if (animations == NULL)
961 return g_object_ref (source->style);
962
963 result = g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL);
964
965 result->style = g_object_ref (base_style);
966 result->current_time = timestamp;
967 result->n_animations = animations->len;
968 result->animations = g_ptr_array_free (array: animations, FALSE);
969
970 style = (GtkCssStyle *)result;
971 style->core = (GtkCssCoreValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->core);
972 style->background = (GtkCssBackgroundValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->background);
973 style->border = (GtkCssBorderValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->border);
974 style->icon = (GtkCssIconValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->icon);
975 style->outline = (GtkCssOutlineValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->outline);
976 style->font = (GtkCssFontValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font);
977 style->font_variant = (GtkCssFontVariantValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->font_variant);
978 style->animation = (GtkCssAnimationValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->animation);
979 style->transition = (GtkCssTransitionValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->transition);
980 style->size = (GtkCssSizeValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->size);
981 style->other = (GtkCssOtherValues *)gtk_css_values_ref (values: (GtkCssValues *)base_style->other);
982
983 gtk_css_animated_style_apply_animations (style: result);
984
985 return GTK_CSS_STYLE (result);
986}
987

source code of gtk/gtk/gtkcssanimatedstyle.c