/*
* Copyright © 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Benjamin Otte
*/
#include "config.h"
#include "gtkcsskeyframeruleprivate.h"
#include "gtkcssstylesheetprivate.h"
typedef struct _GtkCssKeyframeRulePrivate GtkCssKeyframeRulePrivate;
struct _GtkCssKeyframeRulePrivate {
double *offsets;
gsize n_offsets;
GtkCssStyleDeclaration *style;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssKeyframeRule, gtk_css_keyframe_rule, GTK_TYPE_CSS_RULE)
static void
gtk_css_keyframe_rule_finalize (GObject *object)
{
GtkCssKeyframeRule *keyframe_rule = GTK_CSS_KEYFRAME_RULE (object);
GtkCssKeyframeRulePrivate *priv = gtk_css_keyframe_rule_get_instance_private (keyframe_rule);
g_free (priv->offsets);
g_object_unref (priv->style);
G_OBJECT_CLASS (gtk_css_keyframe_rule_parent_class)->finalize (object);
}
static void
gtk_css_keyframe_rule_class_init (GtkCssKeyframeRuleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_keyframe_rule_finalize;
}
static void
gtk_css_keyframe_rule_init (GtkCssKeyframeRule *keyframe_rule)
{
GtkCssKeyframeRulePrivate *priv = gtk_css_keyframe_rule_get_instance_private (keyframe_rule);
priv->style = gtk_css_style_declaration_new (GTK_CSS_RULE (keyframe_rule));
}
static GtkCssRule *
gtk_css_keyframe_rule_new (GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
return g_object_new (GTK_TYPE_CSS_KEYFRAME_RULE,
"parent-rule", parent_rule,
"parent-stylesheet", parent_style_sheet,
NULL);
}
GtkCssRule *
gtk_css_keyframe_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
GtkCssKeyframeRulePrivate *priv;
GtkCssTokenSource *style_source;
const GtkCssToken *token;
GtkCssRule *rule;
GArray *offsets;
g_return_val_if_fail (source != NULL, NULL);
g_return_val_if_fail (parent_rule == NULL || GTK_IS_CSS_RULE (parent_rule), NULL);
g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (parent_style_sheet), NULL);
rule = gtk_css_keyframe_rule_new (parent_rule, parent_style_sheet);
priv = gtk_css_keyframe_rule_get_instance_private (GTK_CSS_KEYFRAME_RULE (rule));
gtk_css_token_source_set_consumer (source, G_OBJECT (rule));
offsets = g_array_new (FALSE, FALSE, sizeof (double));
while (TRUE)
{
double offset;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "from"))
offset = 0;
else if (gtk_css_token_is_ident (token, "to"))
offset = 100;
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
offset = token->number.number;
else
{
gtk_css_token_source_error (source, "Expected percentage");
gtk_css_token_source_consume_all (source);
g_array_free (offsets, TRUE);
g_object_unref (rule);
return NULL;
}
g_array_append_val (offsets, offset);
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COMMA))
break;
gtk_css_token_source_consume_token (source);
}
priv->n_offsets = offsets->len;
priv->offsets = (double *) g_array_free (offsets, FALSE);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_OPEN_CURLY))
{
gtk_css_token_source_error (source, "Expected percentage");
gtk_css_token_source_consume_all (source);
g_object_unref (rule);
return NULL;
}
gtk_css_token_source_consume_token (source);
style_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_CLOSE_CURLY);
gtk_css_style_declaration_parse (priv->style, style_source);
gtk_css_token_source_unref (style_source);
gtk_css_token_source_consume_token (source);
return rule;
}
gsize
gtk_css_keyframe_rule_get_n_offsets (GtkCssKeyframeRule *rule)
{
GtkCssKeyframeRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_KEYFRAME_RULE (rule), 0);
priv = gtk_css_keyframe_rule_get_instance_private (rule);
return priv->n_offsets;
}
double
gtk_css_keyframe_rule_get_offset (GtkCssKeyframeRule *rule,
gsize id)
{
GtkCssKeyframeRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_KEYFRAME_RULE (rule), 0.0);
priv = gtk_css_keyframe_rule_get_instance_private (rule);
g_return_val_if_fail (id < priv->n_offsets, 0.0);
return priv->offsets[id];
}
GtkCssStyleDeclaration *
gtk_css_keyframe_rule_get_style (GtkCssKeyframeRule *rule)
{
GtkCssKeyframeRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_KEYFRAME_RULE (rule), 0);
priv = gtk_css_keyframe_rule_get_instance_private (rule);
return priv->style;
}