cssvalue: Add a value for background-position

This commit is contained in:
Benjamin Otte 2012-04-03 22:21:16 +02:00
parent aed7600425
commit 5377169ef3
9 changed files with 350 additions and 198 deletions

View File

@ -443,6 +443,7 @@ gtk_private_h_sources = \
gtkcssmatcherprivate.h \
gtkcssnumbervalueprivate.h \
gtkcssparserprivate.h \
gtkcsspositionvalueprivate.h \
gtkcssproviderprivate.h \
gtkcssrgbavalueprivate.h \
gtkcsssectionprivate.h \
@ -653,6 +654,7 @@ gtk_base_c_sources = \
gtkcssmatcher.c \
gtkcssnumbervalue.c \
gtkcssparser.c \
gtkcsspositionvalue.c \
gtkcssprovider.c \
gtkcssrgbavalue.c \
gtkcsssection.c \

292
gtk/gtkcsspositionvalue.c Normal file
View File

@ -0,0 +1,292 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 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 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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkcssnumbervalueprivate.h"
struct _GtkCssValue {
GTK_CSS_VALUE_BASE
GtkCssValue *x;
GtkCssValue *y;
};
static void
gtk_css_value_position_free (GtkCssValue *value)
{
_gtk_css_value_unref (value->x);
_gtk_css_value_unref (value->y);
g_slice_free (GtkCssValue, value);
}
static gboolean
gtk_css_value_position_equal (const GtkCssValue *position1,
const GtkCssValue *position2)
{
return _gtk_css_value_equal (position1->x, position2->x)
&& _gtk_css_value_equal (position1->y, position2->y);
}
static GtkCssValue *
gtk_css_value_position_transition (GtkCssValue *start,
GtkCssValue *end,
double progress)
{
GtkCssValue *x, *y;
x = _gtk_css_value_transition (start->x, end->x, progress);
if (x == NULL)
return NULL;
y = _gtk_css_value_transition (start->y, end->y, progress);
if (y == NULL)
{
_gtk_css_value_unref (x);
return NULL;
}
return _gtk_css_position_value_new (x, y);
}
static void
gtk_css_value_position_print (const GtkCssValue *position,
GString *string)
{
struct {
const char *x_name;
const char *y_name;
GtkCssValue *number;
} values[] = {
{ "left", "top", _gtk_css_number_value_new (0, GTK_CSS_PERCENT) },
{ "right", "bottom", _gtk_css_number_value_new (100, GTK_CSS_PERCENT) }
};
GtkCssValue *center = _gtk_css_number_value_new (50, GTK_CSS_PERCENT);
guint i;
if (_gtk_css_value_equal (position->x, center))
{
if (_gtk_css_value_equal (position->y, center))
{
g_string_append (string, "center");
goto done;
}
}
else
{
for (i = 0; i < G_N_ELEMENTS (values); i++)
{
if (_gtk_css_value_equal (position->x, values[i].number))
{
g_string_append (string, values[i].x_name);
break;
}
}
if (i == G_N_ELEMENTS (values))
_gtk_css_value_print (position->x, string);
if (_gtk_css_value_equal (position->y, center))
goto done;
g_string_append_c (string, ' ');
}
for (i = 0; i < G_N_ELEMENTS (values); i++)
{
if (_gtk_css_value_equal (position->y, values[i].number))
{
g_string_append (string, values[i].y_name);
goto done;
}
}
if (i == G_N_ELEMENTS (values))
{
if (_gtk_css_value_equal (position->x, center))
g_string_append (string, "center ");
_gtk_css_value_print (position->y, string);
}
_gtk_css_value_print (position->x, string);
if (!_gtk_css_value_equal (position->x, position->y))
{
g_string_append_c (string, ' ');
_gtk_css_value_print (position->y, string);
}
done:
for (i = 0; i < G_N_ELEMENTS (values); i++)
_gtk_css_value_unref (values[i].number);
_gtk_css_value_unref (center);
}
static const GtkCssValueClass GTK_CSS_VALUE_POSITION = {
gtk_css_value_position_free,
gtk_css_value_position_equal,
gtk_css_value_position_transition,
gtk_css_value_position_print
};
GtkCssValue *
_gtk_css_position_value_new (GtkCssValue *x,
GtkCssValue *y)
{
GtkCssValue *result;
result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_POSITION);
result->x = x;
result->y = y;
return result;
}
GtkCssValue *
_gtk_css_position_value_parse (GtkCssParser *parser)
{
static const struct {
const char *name;
guint percentage;
gboolean horizontal;
gboolean vertical;
} names[] = {
{ "left", 0, TRUE, FALSE },
{ "right", 100, TRUE, FALSE },
{ "center", 50, TRUE, TRUE },
{ "top", 0, FALSE, TRUE },
{ "bottom", 100, FALSE, TRUE },
{ NULL , 0, TRUE, FALSE }, /* used for numbers */
{ NULL , 50, TRUE, TRUE } /* used for no value */
};
GtkCssValue *x, *y;
GtkCssValue **missing;
guint first, second;
for (first = 0; names[first].name != NULL; first++)
{
if (_gtk_css_parser_try (parser, names[first].name, TRUE))
{
if (names[first].horizontal)
{
x = _gtk_css_number_value_new (names[first].percentage, GTK_CSS_PERCENT);
missing = &y;
}
else
{
y = _gtk_css_number_value_new (names[first].percentage, GTK_CSS_PERCENT);
missing = &x;
}
break;
}
}
if (names[first].name == NULL)
{
missing = &y;
x = _gtk_css_number_value_parse (parser,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH);
if (x == NULL)
return NULL;
}
for (second = 0; names[second].name != NULL; second++)
{
if (_gtk_css_parser_try (parser, names[second].name, TRUE))
{
*missing = _gtk_css_number_value_new (names[second].percentage, GTK_CSS_PERCENT);
break;
}
}
if (names[second].name == NULL)
{
if (_gtk_css_parser_has_number (parser))
{
if (missing != &y)
{
_gtk_css_parser_error (parser, "Invalid combination of values");
_gtk_css_value_unref (y);
return NULL;
}
y = _gtk_css_number_value_parse (parser,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH);
if (y == NULL)
{
_gtk_css_value_unref (x);
return NULL;
}
}
else
{
second++;
*missing = _gtk_css_number_value_new (50, GTK_CSS_PERCENT);
}
}
else
{
if ((names[first].horizontal && !names[second].vertical) ||
(!names[first].horizontal && !names[second].horizontal))
{
_gtk_css_parser_error (parser, "Invalid combination of values");
_gtk_css_value_unref (x);
_gtk_css_value_unref (y);
return NULL;
}
}
return _gtk_css_position_value_new (x, y);
}
double
_gtk_css_position_value_get_x (const GtkCssValue *position,
double one_hundred_percent)
{
g_return_val_if_fail (position != NULL, 0.0);
g_return_val_if_fail (position->class == &GTK_CSS_VALUE_POSITION, 0.0);
return _gtk_css_number_value_get (position->x, one_hundred_percent);
}
double
_gtk_css_position_value_get_y (const GtkCssValue *position,
double one_hundred_percent)
{
g_return_val_if_fail (position != NULL, 0.0);
g_return_val_if_fail (position->class == &GTK_CSS_VALUE_POSITION, 0.0);
return _gtk_css_number_value_get (position->y, one_hundred_percent);
}
GtkCssValue *
_gtk_css_position_value_compute (GtkCssValue *position,
GtkStyleContext *context)
{
GtkCssValue *x, *y;
g_return_val_if_fail (position->class == &GTK_CSS_VALUE_POSITION, NULL);
x = _gtk_css_number_value_compute (position->x, context);
y = _gtk_css_number_value_compute (position->y, context);
if (x == position->x && y == position->y)
{
_gtk_css_value_unref (x);
_gtk_css_value_unref (y);
return _gtk_css_value_ref (position);
}
return _gtk_css_position_value_new (x, y);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright © 2012 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 <http://www.gnu.org/licenses/>.
*
* Authors: Alexander Larsson <alexl@gnome.org>
*/
#ifndef __GTK_CSS_POSITION_VALUE_PRIVATE_H__
#define __GTK_CSS_POSITION_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
GtkCssValue * _gtk_css_position_value_new (GtkCssValue *x,
GtkCssValue *y);
GtkCssValue * _gtk_css_position_value_parse (GtkCssParser *parser);
double _gtk_css_position_value_get_x (const GtkCssValue *position,
double one_hundred_percent);
double _gtk_css_position_value_get_y (const GtkCssValue *position,
double one_hundred_percent);
GtkCssValue * _gtk_css_position_value_compute (GtkCssValue *position,
GtkStyleContext *context);
G_END_DECLS
#endif /* __GTK_CSS_POSITION_VALUE_PRIVATE_H__ */

View File

@ -49,6 +49,7 @@
#include "gtkcssimagevalueprivate.h"
#include "gtkcssenumvalueprivate.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkcssrgbavalueprivate.h"
#include "gtkcssshadowsvalueprivate.h"
#include "gtkcssstringvalueprivate.h"
@ -1037,152 +1038,7 @@ background_position_parse (GtkCssStyleProperty *property,
GtkCssParser *parser,
GFile *base)
{
static const struct {
const char *name;
guint percentage;
gboolean horizontal;
gboolean vertical;
} names[] = {
{ "left", 0, TRUE, FALSE },
{ "right", 100, TRUE, FALSE },
{ "center", 50, TRUE, TRUE },
{ "top", 0, FALSE, TRUE },
{ "bottom", 100, FALSE, TRUE },
{ NULL , 0, TRUE, FALSE }, /* used for numbers */
{ NULL , 50, TRUE, TRUE } /* used for no value */
};
GtkCssBackgroundPosition pos;
GtkCssNumber *missing;
guint first, second;
for (first = 0; names[first].name != NULL; first++)
{
if (_gtk_css_parser_try (parser, names[first].name, TRUE))
{
if (names[first].horizontal)
{
_gtk_css_number_init (&pos.x, names[first].percentage, GTK_CSS_PERCENT);
missing = &pos.y;
}
else
{
_gtk_css_number_init (&pos.y, names[first].percentage, GTK_CSS_PERCENT);
missing = &pos.x;
}
break;
}
}
if (names[first].name == NULL)
{
missing = &pos.y;
if (!_gtk_css_parser_read_number (parser,
&pos.x,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH))
return NULL;
}
for (second = 0; names[second].name != NULL; second++)
{
if (_gtk_css_parser_try (parser, names[second].name, TRUE))
{
_gtk_css_number_init (missing, names[second].percentage, GTK_CSS_PERCENT);
break;
}
}
if (names[second].name == NULL)
{
if (_gtk_css_parser_has_number (parser))
{
if (missing != &pos.y)
{
_gtk_css_parser_error (parser, "Invalid combination of values");
return NULL;
}
if (!_gtk_css_parser_read_number (parser,
missing,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH))
return NULL;
}
else
{
second++;
_gtk_css_number_init (missing, 50, GTK_CSS_PERCENT);
}
}
else
{
if ((names[first].horizontal && !names[second].vertical) ||
(!names[first].horizontal && !names[second].horizontal))
{
_gtk_css_parser_error (parser, "Invalid combination of values");
return NULL;
}
}
return _gtk_css_value_new_from_background_position (&pos);
}
static void
background_position_print (GtkCssStyleProperty *property,
const GtkCssValue *value,
GString *string)
{
const GtkCssBackgroundPosition *pos = _gtk_css_value_get_background_position (value);
static const GtkCssNumber center = GTK_CSS_NUMBER_INIT (50, GTK_CSS_PERCENT);
static const struct {
const char *x_name;
const char *y_name;
GtkCssNumber number;
} values[] = {
{ "left", "top", GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT) },
{ "right", "bottom", GTK_CSS_NUMBER_INIT (100, GTK_CSS_PERCENT) }
};
guint i;
if (_gtk_css_number_equal (&pos->x, &center))
{
if (_gtk_css_number_equal (&pos->y, &center))
{
g_string_append (string, "center");
return;
}
}
else
{
for (i = 0; i < G_N_ELEMENTS (values); i++)
{
if (_gtk_css_number_equal (&pos->x, &values[i].number))
{
g_string_append (string, values[i].x_name);
break;
}
}
if (i == G_N_ELEMENTS (values))
_gtk_css_number_print (&pos->x, string);
if (_gtk_css_number_equal (&pos->y, &center))
return;
g_string_append_c (string, ' ');
}
for (i = 0; i < G_N_ELEMENTS (values); i++)
{
if (_gtk_css_number_equal (&pos->y, &values[i].number))
{
g_string_append (string, values[i].y_name);
break;
}
}
if (i == G_N_ELEMENTS (values))
{
if (_gtk_css_number_equal (&pos->x, &center))
g_string_append (string, "center ");
_gtk_css_number_print (&pos->y, string);
}
return _gtk_css_position_value_parse (parser);
}
static GtkCssValue *
@ -1190,19 +1046,7 @@ background_position_compute (GtkCssStyleProperty *property,
GtkStyleContext *context,
GtkCssValue *specified)
{
const GtkCssBackgroundPosition *spos = _gtk_css_value_get_background_position (specified);
GtkCssBackgroundPosition cpos;
gboolean changed;
changed = _gtk_css_number_compute (&cpos.x,
&spos->x,
context);
changed |= _gtk_css_number_compute (&cpos.y,
&spos->y,
context);
if (changed)
return _gtk_css_value_new_from_background_position (&cpos);
return _gtk_css_value_ref (specified);
return _gtk_css_position_value_compute (specified, context);
}
/*** REGISTRATION ***/
@ -1222,7 +1066,6 @@ void
_gtk_css_style_property_init_properties (void)
{
GtkCssBackgroundSize default_background_size = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), FALSE, FALSE };
GtkCssBackgroundPosition default_background_position = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT)};
GtkBorder border_of_ones = { 1, 1, 1, 1 };
GtkCssBorderImageRepeat border_image_repeat = { GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH };
@ -1650,14 +1493,15 @@ _gtk_css_style_property_init_properties (void)
gtk_css_style_property_register ("background-position",
GTK_CSS_PROPERTY_BACKGROUND_POSITION,
G_TYPE_NONE,
0,
GTK_STYLE_PROPERTY_ANIMATED,
background_position_parse,
background_position_print,
NULL,
background_position_compute,
NULL,
NULL,
NULL,
_gtk_css_value_new_from_background_position (&default_background_position));
_gtk_css_position_value_new (_gtk_css_number_value_new (0, GTK_CSS_PERCENT),
_gtk_css_number_value_new (0, GTK_CSS_PERCENT)));
gtk_css_style_property_register ("border-top-color",
GTK_CSS_PROPERTY_BORDER_TOP_COLOR,

View File

@ -33,7 +33,6 @@ type_name ## _copy (const TypeName *foo) \
G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name ## _copy, g_free)
DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBackgroundSize, _gtk_css_background_size)
DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBackgroundPosition, _gtk_css_background_position)
DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderImageRepeat, _gtk_css_border_image_repeat)
typedef struct _GtkCssChangeTranslation GtkCssChangeTranslation;

View File

@ -188,7 +188,6 @@ typedef enum /*< skip >*/ {
typedef struct _GtkCssNumber GtkCssNumber;
typedef struct _GtkCssBackgroundSize GtkCssBackgroundSize;
typedef struct _GtkCssBackgroundPosition GtkCssBackgroundPosition;
typedef struct _GtkCssBorderImageRepeat GtkCssBorderImageRepeat;
struct _GtkCssNumber {
@ -203,22 +202,15 @@ struct _GtkCssBackgroundSize {
guint contain :1;
};
struct _GtkCssBackgroundPosition {
GtkCssNumber x;
GtkCssNumber y;
};
struct _GtkCssBorderImageRepeat {
GtkCssBorderRepeatStyle vrepeat;
GtkCssBorderRepeatStyle hrepeat;
};
#define GTK_TYPE_CSS_BACKGROUND_SIZE _gtk_css_background_size_get_type ()
#define GTK_TYPE_CSS_BACKGROUND_POSITION _gtk_css_background_position_get_type ()
#define GTK_TYPE_CSS_BORDER_IMAGE_REPEAT _gtk_css_border_image_repeat_get_type ()
GType _gtk_css_background_size_get_type (void);
GType _gtk_css_background_position_get_type (void);
GType _gtk_css_border_image_repeat_get_type (void);
GtkCssChange _gtk_css_change_for_sibling (GtkCssChange match);

View File

@ -289,17 +289,6 @@ _gtk_css_value_new_from_background_size (const GtkCssBackgroundSize *v)
return value;
}
GtkCssValue *
_gtk_css_value_new_from_background_position (const GtkCssBackgroundPosition *v)
{
GtkCssValue *value;
value = gtk_css_value_new (GTK_TYPE_CSS_BACKGROUND_POSITION);
value->u.ptr = g_boxed_copy0 (GTK_TYPE_CSS_BACKGROUND_POSITION, v);
return value;
}
GtkCssValue *
_gtk_css_value_new_from_border_image_repeat (const GtkCssBorderImageRepeat *v)
{
@ -543,13 +532,6 @@ _gtk_css_value_get_background_size (const GtkCssValue *value)
return value->u.ptr;
}
const GtkCssBackgroundPosition *
_gtk_css_value_get_background_position (const GtkCssValue *value)
{
g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BACKGROUND_POSITION), NULL);
return value->u.ptr;
}
const GtkCssBorderImageRepeat *
_gtk_css_value_get_border_image_repeat (const GtkCssValue *value)
{

View File

@ -89,7 +89,6 @@ GtkCssValue *_gtk_css_value_new_take_symbolic_color (GtkSymbolicColor
GtkCssValue *_gtk_css_value_new_take_pattern (cairo_pattern_t *v);
GtkCssValue *_gtk_css_value_new_take_binding_sets (GPtrArray *array);
GtkCssValue *_gtk_css_value_new_from_background_size (const GtkCssBackgroundSize *v);
GtkCssValue *_gtk_css_value_new_from_background_position (const GtkCssBackgroundPosition *v);
GtkCssValue *_gtk_css_value_new_from_border_image_repeat (const GtkCssBorderImageRepeat *v);
void _gtk_css_value_init_gvalue (const GtkCssValue *value,
GValue *g_value);
@ -102,7 +101,6 @@ gpointer _gtk_css_value_get_boxed (const
const char ** _gtk_css_value_get_strv (const GtkCssValue *value);
GtkSymbolicColor *_gtk_css_value_get_symbolic_color (const GtkCssValue *value);
const GtkCssBackgroundSize *_gtk_css_value_get_background_size (const GtkCssValue *value);
const GtkCssBackgroundPosition *_gtk_css_value_get_background_position (const GtkCssValue *value);
const GtkCssBorderImageRepeat *_gtk_css_value_get_border_image_repeat (const GtkCssValue *value);
GtkGradient *_gtk_css_value_get_gradient (const GtkCssValue *value);

View File

@ -27,6 +27,7 @@
#include "gtkcssenumvalueprivate.h"
#include "gtkcssimagevalueprivate.h"
#include "gtkcssshadowsvalueprivate.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkthemingengineprivate.h"
@ -161,12 +162,12 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
{
GtkCssBackgroundRepeat hrepeat, vrepeat;
const GtkCssBackgroundSize *size;
const GtkCssBackgroundPosition *pos;
const GtkCssValue *pos;
double image_width, image_height;
double width, height;
size = _gtk_css_value_get_background_size (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_SIZE));
pos = _gtk_css_value_get_background_position (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_POSITION));
pos = _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_POSITION);
gtk_style_context_get (bg->context, bg->flags,
"background-repeat", &hrepeat,
NULL);
@ -201,8 +202,8 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
if (hrepeat == GTK_CSS_BACKGROUND_NO_REPEAT && vrepeat == GTK_CSS_BACKGROUND_NO_REPEAT)
{
cairo_translate (cr,
_gtk_css_number_get (&pos->x, bg->image_rect.width - image_width),
_gtk_css_number_get (&pos->y, bg->image_rect.height - image_height));
_gtk_css_position_value_get_x (pos, width - image_width),
_gtk_css_position_value_get_y (pos, height - image_height));
/* shortcut for normal case */
_gtk_css_image_draw (bg->image, cr, image_width, image_height);
}
@ -280,8 +281,8 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
cairo_destroy (cr2);
cairo_set_source_surface (cr, surface,
_gtk_css_number_get (&pos->x, bg->image_rect.width - image_width),
_gtk_css_number_get (&pos->y, bg->image_rect.height - image_height));
_gtk_css_position_value_get_x (pos, width - image_width),
_gtk_css_position_value_get_y (pos, height - image_height));
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
cairo_surface_destroy (surface);