css: Support background-position property

This commit is contained in:
Alexander Larsson 2012-03-16 22:13:39 +01:00 committed by Benjamin Otte
parent b874e6c3cf
commit e65a2709a3
2 changed files with 192 additions and 2 deletions

View File

@ -682,6 +682,181 @@ background_size_compute (GtkCssStyleProperty *property,
return _gtk_css_value_ref (specified);
}
static gboolean
background_position_parse (GtkCssStyleProperty *property,
GValue *value,
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 FALSE;
}
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 FALSE;
}
if (!_gtk_css_parser_read_number (parser,
missing,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH))
return FALSE;
}
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 FALSE;
}
}
g_value_set_boxed (value, &pos);
return TRUE;
}
static void
background_position_print (GtkCssStyleProperty *property,
const GValue *value,
GString *string)
{
GtkCssBackgroundPosition *pos = g_value_get_boxed (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);
}
}
static GtkCssValue *
background_position_compute (GtkCssStyleProperty *property,
GtkStyleContext *context,
GtkCssValue *specified)
{
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);
}
/*** REGISTRATION ***/
static GtkSymbolicColor *
@ -702,6 +877,7 @@ _gtk_css_style_property_init_properties (void)
GtkCssNumber number;
GtkSymbolicColor *symbolic;
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)};
GtkCssBorderCornerRadius no_corner_radius = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX) };
GtkBorder border_of_ones = { 1, 1, 1, 1 };
GtkCssBorderImageRepeat border_image_repeat = { GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH };
@ -1054,6 +1230,15 @@ _gtk_css_style_property_init_properties (void)
background_size_print,
background_size_compute,
&default_background_size);
gtk_css_style_property_register ("background-position",
GTK_TYPE_CSS_BACKGROUND_POSITION,
GTK_TYPE_CSS_BACKGROUND_POSITION,
G_TYPE_NONE,
0,
background_position_parse,
background_position_print,
background_position_compute,
&default_background_position);
gtk_css_style_property_register ("border-top-color",
GTK_TYPE_SYMBOLIC_COLOR,

View File

@ -162,10 +162,12 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
{
GtkCssBackgroundRepeat hrepeat, vrepeat;
GtkCssBackgroundSize *size;
GtkCssBackgroundPosition *pos;
double image_width, image_height;
double width, height;
size = _gtk_css_value_get_background_size (_gtk_style_context_peek_property (bg->context, "background-size"));
pos = _gtk_css_value_get_background_position (_gtk_style_context_peek_property (bg->context, "background-position"));
gtk_style_context_get (bg->context, bg->flags,
"background-repeat", &hrepeat,
NULL);
@ -199,6 +201,9 @@ _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));
/* shortcut for normal case */
_gtk_css_image_draw (bg->image, cr, image_width, image_height);
}
@ -276,8 +281,8 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
cairo_destroy (cr2);
cairo_set_source_surface (cr, surface,
/* background-position goes here */
0, 0);
_gtk_css_number_get (&pos->x, bg->image_rect.width - image_width),
_gtk_css_number_get (&pos->y, bg->image_rect.height - image_height));
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
cairo_surface_destroy (surface);