Compare commits

...

78 Commits

Author SHA1 Message Date
Benjamin Otte
be2d3321aa csstokenizer: Export the error location 2016-04-08 16:18:33 +02:00
Benjamin Otte
62b2f979e5 csstokenizer: Collect error, don't just emit it
This again is part of the quest to make it possible to "undo" reading
a token.
2016-04-08 16:18:32 +02:00
Benjamin Otte
c6951488f9 csstokenizer: Refactor to add GtkCssTokenReader
This new internal struct is now used to read the next token. This allows
keeping the current info in the tokenizer.

Technically, we could now reset a parse if we wanted to. So far we don't
want to.
2016-04-08 16:18:32 +02:00
Benjamin Otte
935141b915 csstokenizer: Export GtkCssLocation
And change the tokenizer API to return the location instead of having
multiple functions returning all of the members of the location struct.

And because surprisingly the new Location struct is exactly the same
struct as what is used in the CssEditor (how could that happen?!), use
it there, too.
2016-04-08 16:18:32 +02:00
Benjamin Otte
947f3ea5ec csstokenizer: Introduce GtkCssLocation 2016-04-08 16:18:32 +02:00
Benjamin Otte
7ca4ef7b0c cssease: Optimize with Newton's method
Idea stolen from Webkit's implementation.
2016-04-08 16:18:32 +02:00
Benjamin Otte
3659741414 cssease: Refactor code
Makes it a bit easier to read and prepares it for the next commit.
2016-04-08 16:18:32 +02:00
Benjamin Otte
02f31d7133 cssimage: Move fallback token parser to -gtk-gradient()
Every other image type has a real token parser now.
2016-04-08 16:18:32 +02:00
Benjamin Otte
58aa294970 cssimage: Make the win32 image parser have a token parser 2016-04-08 16:18:32 +02:00
Benjamin Otte
55e3a1927d css: Add gtk_css_token_source_consume_integer()
And make sure the integer parsing functions call it.
2016-04-08 16:18:32 +02:00
Benjamin Otte
b00e9f629c win32 theme: Fix functions to not have spaces
CSS doesn't allow that (although GTK's CSS parser did so far not
complain).
2016-04-08 16:18:32 +02:00
Benjamin Otte
f54cf9d9d4 cssimage: Add token parser for image() images 2016-04-08 16:18:32 +02:00
Benjamin Otte
e351cbc83f cssimage: Add token parser for cross-fade() 2016-04-08 16:18:32 +02:00
Benjamin Otte
f4fba248ad cssimage: Add token parser for -gtk-recolor() images 2016-04-08 16:18:32 +02:00
Benjamin Otte
27bbfe9d80 cssimage: Add a token parser for radial gradients 2016-04-08 16:18:32 +02:00
Benjamin Otte
63b1e50835 cssimage: Add token parser for builtin images 2016-04-08 16:18:32 +02:00
Benjamin Otte
87eeb1bdfb cssimage: Add token parser for linear-gradient
This requires refactoring of gtk_css_token_source_consume_function() to
allow a single call to the parse_args function to consume multiple
arguments.
Because the first argument to linear-gradient() is the optional
direction, we need to indicate that we skipped it. So the parse
function returns 2 in that case. This way we can set the minimum required
arguments to 3, while still allowing
  linear-gradient(red, blue);
which is equivalent to
  linear-gradient(to bottom, red, blue);
2016-04-08 16:18:31 +02:00
Benjamin Otte
fabc1f633d cssprovider: Add a way to load a provider from a stylesheet
Use that way in the CSS editor.
2016-04-08 16:18:31 +02:00
Benjamin Otte
01b320f563 css: Functions don't accept spaces before ( anymore
So fix the testcaes that use them.
And in particular, fix -gtk-gradient() using spaces everywhere.
2016-04-08 16:18:31 +02:00
Benjamin Otte
ca5075c26d css: Split integer tokens into ones with sign and ones without
And with that newfound power, fix the an+b parser.
I hate that part of the spec.
2016-04-08 16:18:31 +02:00
Benjamin Otte
9c12d01ba3 cssimportrule: Add recursion check 2016-04-08 16:18:31 +02:00
Benjamin Otte
9d07be0238 css: Parse widget styles with token parser 2016-04-08 16:18:31 +02:00
Benjamin Otte
f36217dda6 cssdeclaration: Propertify 2016-04-08 16:18:31 +02:00
Benjamin Otte
0f9526578a cssdeclaration: Turn into abstract base class
This is in preparation for allowing to parse style properties like
-GtkWidget-focus-width.
2016-04-08 16:18:31 +02:00
Benjamin Otte
afe70c4568 cssimportrule: Actually import the style sheet
Also add code to the inspector's ruleview to display rules of imported
style sheets.
2016-04-08 16:18:31 +02:00
Benjamin Otte
eb86a5fb3f stylesheet: Add properties
... and turn it into the API demanded by the CSSOM. That is, don't allow
reloading in the stylesheet, demand that new ones are created and the
token source be provided at construction.
2016-04-08 16:18:31 +02:00
Benjamin Otte
ca1c46c170 csskeyframes: Allow constructing from KeyframesRule
This requires a bunch of API being added to the rules.
2016-04-08 16:18:31 +02:00
Benjamin Otte
23c729459f menu: Clip children to view window
Don't overdraw the arrow allocations.

https://bugzilla.gnome.org/show_bug.cgi?id=764118
2016-04-08 16:18:31 +02:00
Benjamin Otte
7a36b5df90 cssdefinecolorrule: Rework parser
Actually store the values that get parsed. And change the parsing code
to construct the rule in advance so that it can be set as the consumer
while parsing.
2016-04-08 16:18:31 +02:00
Benjamin Otte
69506210a2 css: Add token parser for keyframes rule 2016-04-08 16:18:31 +02:00
Benjamin Otte
0fbdcc3cd1 inspector: Add a ruleview
This widget lists all the rules in the current CSS. For now it lives
next to the css editor widget.
2016-04-08 16:18:30 +02:00
Benjamin Otte
ff7f62b3ca cssstyledeclaration: Make declarations queryable 2016-04-08 16:18:30 +02:00
Benjamin Otte
b3ee232880 cssstylesheet: Store the file we loaded from 2016-04-08 16:18:30 +02:00
Benjamin Otte
768cdf8a55 cssrule: Add properties
... and actually store the style sheet and parent rule.
2016-04-08 16:18:30 +02:00
Benjamin Otte
b2c070551b cssdeclaration: Add API to query name + value 2016-04-08 16:18:30 +02:00
Benjamin Otte
e1444d0d35 inspector: Allow horizontal scrolling in the css editor
Otherwise, when pasting Adwaita's CSS into it, it expands to be larger
than my screen...
2016-04-08 16:18:30 +02:00
Benjamin Otte
33b2684c29 css: Add a token aprser for define-color 2016-04-08 16:18:30 +02:00
Benjamin Otte
16dff3909b css: Add token parser for @import 2016-04-08 16:18:30 +02:00
Benjamin Otte
920a88512b css: Move blocks handling to the token sources that need it
They need different ways of handling blocks, so they better do it
themselves instead of having a generic way that always gets it wrong.
2016-04-08 16:18:30 +02:00
Benjamin Otte
fcf65bf8a4 cssimage: Add token parser for -gtk-scaled 2016-04-08 16:18:30 +02:00
Benjamin Otte
a39d1a620f cssimage: Add a token parser for icontheme images 2016-04-08 16:18:30 +02:00
Benjamin Otte
ae248b3443 cssimage: Add token parser for url() images
This requires adding location information to GtkCssTokenSource, so that
we can resolve relative URLs.
2016-04-08 16:18:30 +02:00
Benjamin Otte
28babd269b css: Move fallback parser to GtkCssImage
Now that all CSS values can be parsed by the token parser, no fallback
parsing code is necessary anymore.
However, the images can't be parsed by the token parser yet, so the
fallback code moved there.

Also remove the property argiument from the token parsing vfunc in
GtkCssStyleProperty. It was unused and just caused a lot of casting.
2016-04-08 16:18:30 +02:00
Benjamin Otte
fef9fe68d0 css: Add a token parser for transform values 2016-04-08 16:18:30 +02:00
Benjamin Otte
945bddf120 css: Add gtk_css_token_source_consume_number()
This is totally so we can parse
  color: rgb(calc(255 * 0.3), calc(255 * 0.6), calc(255 * 0.3));
which Webkit totally can, but Firefox and IE totally can't.

And GTK has to be at least the 2nd best CSS engine in the world.
2016-04-08 16:18:30 +02:00
Benjamin Otte
87d3bb5799 css: Add a token parser for engine values 2016-04-08 16:18:29 +02:00
Benjamin Otte
19d88eca1f css: Add token parser for font-size property 2016-04-08 16:18:29 +02:00
Benjamin Otte
2e05b896de css: Add token parser for bgsize values 2016-04-08 16:18:29 +02:00
Benjamin Otte
c767617d54 css: Add token parse for position values
And implement that parser completely. Now that we have calc(), this
actually works.
2016-04-08 16:18:29 +02:00
Benjamin Otte
90e423b34d css: Consume whitespace tokens automatically
Exception: The selector parsing code uses the peek_token() vfunc to
actually get the real tokens, whitepsace included.
2016-04-08 16:18:27 +02:00
Benjamin Otte
d7c8885852 css: Add token parsers for shadows
This also introduces the new idea of check_token() functions. These
functions check if a given function might be the initial token in
parsing a certain value. Implementations for numbers and colors are
included.
2016-04-08 16:18:07 +02:00
Benjamin Otte
567d9887f7 css: A token parse func for repeat values 2016-04-08 16:18:07 +02:00
Benjamin Otte
32d671cfd7 inspector: Move errors on EOF token to last token
That's wrong, but it makes sure we don't lose any error messages.
2016-04-08 16:18:07 +02:00
Benjamin Otte
fae4a14177 css: Add token parser for ease values
Also add a parser for functions to the token source.
2016-04-08 16:18:07 +02:00
Benjamin Otte
c0ee099aa1 css: Add a token parser for border values 2016-04-08 16:18:07 +02:00
Benjamin Otte
ab402e2400 css: Add token parser for corner radius value 2016-04-08 16:18:07 +02:00
Benjamin Otte
c5d5825cf0 css: Add token parser for palettes 2016-04-08 16:18:07 +02:00
Benjamin Otte
6c72e9423f css: add token parser for icontheme values 2016-04-08 16:18:07 +02:00
Benjamin Otte
73d69e353b css: Add token parser for array values 2016-04-08 16:18:07 +02:00
Benjamin Otte
e9bc9082a4 css: Convert enums to token parsing 2016-04-08 16:18:07 +02:00
Benjamin Otte
b9c77aadec css: Add token parsing for number values
This includes calc() and the win32 number values.

CSS properties using just <length>, <angle>, <time>, <percentage> or
<number> have been converted.
2016-04-08 16:18:05 +02:00
Benjamin Otte
974ca283ef css: Change the way we token parse longhands
- Move the default parse func to gtkcssstylepropertyimpl.c and use it
  there.
- Change the arguments in the prototype of the parse func so that we
  don't use trampolines anymore.
- Stop using a trampoline for color parsing.
2016-04-08 16:17:22 +02:00
Benjamin Otte
0a11e4d36b css: Add token parsing for colors
... and add infrastructure to use it to longhand properties.
2016-04-08 16:17:22 +02:00
Benjamin Otte
662065bdb1 css: Allow the css editor to take a CSS node
Use that to hilight the selectors that match that node.
2016-04-08 16:17:22 +02:00
Benjamin Otte
9c02a600b2 css: Add gtk_style_property_token_parse()
Slowly move the token parser into CSS value parsing.
2016-04-08 16:17:22 +02:00
Benjamin Otte
257273c439 inspector: Add style sheet parsing to CSS editor
This way, we can now keep backlogs to the style sheet objects from the
tokens. A simple use of that is included via syntax hilighting of CSS
properties.

Also, we now take the errors from the style sheet parsing and not from
the loading of the CSS provider. This is a bit of a regression for now,
as the style sheet parser does not emit very many errors yet.
2016-04-08 16:17:22 +02:00
Benjamin Otte
348052064a cssdeclaration: Store the style property
That way, we can error if a property name isn't valid.
2016-04-08 16:17:22 +02:00
Benjamin Otte
14e7c42200 css: Add a consumer object to consume_token()
This is to allow backreferences from code analysis frameworks.
2016-04-08 16:17:22 +02:00
Benjamin Otte
e64a143ff7 tokenizer: Emit token in error vfunc 2016-04-08 16:17:22 +02:00
Benjamin Otte
840d347d59 css: Add code to parse declarations
We don't parse the values yet.
2016-04-08 16:17:22 +02:00
Benjamin Otte
674ca8ae1c css: Add skeleton for new parsing infrastructure
This infrastructure will be based around the CSSOM and return a
GtkCssStyleSheet object as its result.

The initial intended use for this is as a syntax tree while editing in
the inspector, but we might even want to look into exporting the CSSOM
parts as public API at some point.
2016-04-08 16:17:21 +02:00
Benjamin Otte
25b2e2f3e5 inspector: Implement rudimentary syntax hilighting
We hilight comments in blue and strings in red. Go us!
2016-04-08 16:17:21 +02:00
Benjamin Otte
48b241833a inspector: Don't clear all tags when getting text 2016-04-08 16:17:21 +02:00
Benjamin Otte
460ad90379 gtk: Add an RB tree implementation for use in CSS code
Some tests included
2016-04-08 16:17:21 +02:00
Benjamin Otte
adeec6656c rbtree: Remove unused typedef 2016-04-08 16:17:21 +02:00
Benjamin Otte
78fd100ade css: Add GtkCssTokenizer
So far, it's known to successfully tokenize Adwaita's CSS.
2016-04-08 16:17:21 +02:00
Benjamin Otte
b1a8537314 theme: linear-gradient() needs 2 color-stops
So make sure our _solid() function gives it two.
2016-04-08 16:17:21 +02:00
Benjamin Otte
7a69ea89ca theme: Add _solid() function
The function creates a solid color image. Currently this is done with
linear-gradient().
2016-04-08 16:17:14 +02:00
135 changed files with 13471 additions and 496 deletions

View File

@@ -397,6 +397,8 @@ gtk_private_h_sources = \
gtkcsscornervalueprivate.h \
gtkcsscustomgadgetprivate.h \
gtkcsscustompropertyprivate.h \
gtkcssdeclarationprivate.h \
gtkcssdefinecolorruleprivate.h \
gtkcssdimensionvalueprivate.h \
gtkcsseasevalueprivate.h \
gtkcssenginevalueprivate.h \
@@ -417,9 +419,13 @@ gtk_private_h_sources = \
gtkcssimagescaledprivate.h \
gtkcssimagevalueprivate.h \
gtkcssimagewin32private.h \
gtkcssimportruleprivate.h \
gtkcssinheritvalueprivate.h \
gtkcssinitialvalueprivate.h \
gtkcsskeyframeruleprivate.h \
gtkcsskeyframesprivate.h \
gtkcsskeyframesruleprivate.h \
gtkcsslonghanddeclarationprivate.h \
gtkcsslookupprivate.h \
gtkcssmatcherprivate.h \
gtkcssnodeprivate.h \
@@ -431,12 +437,16 @@ gtk_private_h_sources = \
gtkcsspathnodeprivate.h \
gtkcsspositionvalueprivate.h \
gtkcssproviderprivate.h \
gtkcssrbtreeprivate.h \
gtkcssrepeatvalueprivate.h \
gtkcssrgbavalueprivate.h \
gtkcssruleprivate.h \
gtkcssrulelistprivate.h \
gtkcsssectionprivate.h \
gtkcssselectorprivate.h \
gtkcssshadowsvalueprivate.h \
gtkcssshadowvalueprivate.h \
gtkcssshorthanddeclarationprivate.h \
gtkcssshorthandpropertyprivate.h \
gtkcssstaticstyleprivate.h \
gtkcssstringvalueprivate.h \
@@ -444,6 +454,11 @@ gtk_private_h_sources = \
gtkcssstylechangeprivate.h \
gtkcssstyleprivate.h \
gtkcssstylepropertyprivate.h \
gtkcssstyledeclarationprivate.h \
gtkcssstyleruleprivate.h \
gtkcssstylesheetprivate.h \
gtkcsstokenizerprivate.h \
gtkcsstokensourceprivate.h \
gtkcsstransformvalueprivate.h \
gtkcsstransientnodeprivate.h \
gtkcsstransitionprivate.h \
@@ -452,6 +467,7 @@ gtk_private_h_sources = \
gtkcssvalueprivate.h \
gtkcsswin32sizevalueprivate.h \
gtkcsswidgetnodeprivate.h \
gtkcsswidgetstyledeclarationprivate.h \
gtkcustompaperunixdialog.h \
gtkdialogprivate.h \
gtkdndprivate.h \
@@ -665,6 +681,8 @@ gtk_base_c_sources = \
gtkcsscornervalue.c \
gtkcsscustomgadget.c \
gtkcsscustomproperty.c \
gtkcssdeclaration.c \
gtkcssdefinecolorrule.c \
gtkcssdimensionvalue.c \
gtkcsseasevalue.c \
gtkcssenumvalue.c \
@@ -685,9 +703,13 @@ gtk_base_c_sources = \
gtkcssimagescaled.c \
gtkcssimagevalue.c \
gtkcssimagewin32.c \
gtkcssimportrule.c \
gtkcssinheritvalue.c \
gtkcssinitialvalue.c \
gtkcsskeyframerule.c \
gtkcsskeyframes.c \
gtkcsskeyframesrule.c \
gtkcsslonghanddeclaration.c \
gtkcsslookup.c \
gtkcssmatcher.c \
gtkcssnode.c \
@@ -699,21 +721,30 @@ gtk_base_c_sources = \
gtkcsspathnode.c \
gtkcsspositionvalue.c \
gtkcssprovider.c \
gtkcssrbtree.c \
gtkcssrepeatvalue.c \
gtkcssrgbavalue.c \
gtkcssrule.c \
gtkcssrulelist.c \
gtkcsssection.c \
gtkcssselector.c \
gtkcssstringvalue.c \
gtkcssstyle.c \
gtkcssstylechange.c \
gtkcssshadowsvalue.c \
gtkcssshadowvalue.c \
gtkcssshorthanddeclaration.c \
gtkcssshorthandproperty.c \
gtkcssshorthandpropertyimpl.c \
gtkcssstaticstyle.c \
gtkcssstyle.c \
gtkcssstylechange.c \
gtkcssstyledeclaration.c \
gtkcssstylefuncs.c \
gtkcssstyleproperty.c \
gtkcssstylepropertyimpl.c \
gtkcssstylerule.c \
gtkcssstylesheet.c \
gtkcsstokenizer.c \
gtkcsstokensource.c \
gtkcsstransformvalue.c \
gtkcsstransientnode.c \
gtkcsstransition.c \
@@ -722,6 +753,7 @@ gtk_base_c_sources = \
gtkcsstypes.c \
gtkcssvalue.c \
gtkcsswidgetnode.c \
gtkcsswidgetstyledeclaration.c \
gtkcsswin32sizevalue.c \
gtkdialog.c \
gtkdragsource.c \

View File

@@ -397,7 +397,7 @@ gtk_gradient_to_string (GtkGradient *gradient)
g_return_val_if_fail (gradient != NULL, NULL);
str = g_string_new ("-gtk-gradient (");
str = g_string_new ("-gtk-gradient(");
if (gradient->radius0 == 0 && gradient->radius1 == 0)
{

View File

@@ -379,6 +379,36 @@ _gtk_css_array_value_parse (GtkCssParser *parser,
return result;
}
GtkCssValue *
gtk_css_array_value_token_parse (GtkCssTokenSource *source,
GtkCssValue *(* parse_func) (GtkCssTokenSource *))
{
GtkCssValue *value, *result;
GPtrArray *values;
values = g_ptr_array_new ();
while (TRUE) {
value = parse_func (source);
if (value == NULL)
{
g_ptr_array_set_free_func (values, (GDestroyNotify) _gtk_css_value_unref);
g_ptr_array_free (values, TRUE);
return NULL;
}
g_ptr_array_add (values, value);
if (!gtk_css_token_is (gtk_css_token_source_get_token (source), GTK_CSS_TOKEN_COMMA))
break;
gtk_css_token_source_consume_token (source);
}
result = _gtk_css_array_value_new_from_array ((GtkCssValue **) values->pdata, values->len);
g_ptr_array_free (values, TRUE);
return result;
}
GtkCssValue *
_gtk_css_array_value_get_nth (const GtkCssValue *value,
guint i)

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_ARRAY_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtktypes.h"
@@ -31,6 +32,8 @@ GtkCssValue * _gtk_css_array_value_new_from_array (GtkCssValue **
guint n_values);
GtkCssValue * _gtk_css_array_value_parse (GtkCssParser *parser,
GtkCssValue * (* parse_func) (GtkCssParser *));
GtkCssValue * gtk_css_array_value_token_parse (GtkCssTokenSource *source,
GtkCssValue * (* parse_func) (GtkCssTokenSource *));
GtkCssValue * _gtk_css_array_value_get_nth (const GtkCssValue *value,
guint i);

View File

@@ -212,6 +212,65 @@ _gtk_css_bg_size_value_parse (GtkCssParser *parser)
return _gtk_css_bg_size_value_new (x, y);
}
GtkCssValue *
gtk_css_bg_size_value_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token;
GtkCssValue *x, *y;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "cover"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_value_ref (&cover_singleton);
}
if (gtk_css_token_is_ident (token, "contain"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_value_ref (&contain_singleton);
}
if (gtk_css_token_is_ident (token, "auto"))
{
gtk_css_token_source_consume_token (source);
x = NULL;
}
else
{
x = gtk_css_number_value_token_parse (source,
GTK_CSS_POSITIVE_ONLY
| GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH);
if (x == NULL)
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "auto"))
{
gtk_css_token_source_consume_token (source);
y = NULL;
}
else if (!gtk_css_number_value_check_token (token))
{
y = NULL;
}
else
{
y = gtk_css_number_value_token_parse (source,
GTK_CSS_POSITIVE_ONLY
| GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH);
if (y == NULL)
{
_gtk_css_value_unref (x);
return NULL;
}
}
return _gtk_css_bg_size_value_new (x, y);
}
static void
gtk_css_bg_size_compute_size_for_cover_contain (gboolean cover,
GtkCssImage *image,

View File

@@ -20,8 +20,9 @@
#ifndef __GTK_CSS_BG_SIZE_VALUE_PRIVATE_H__
#define __GTK_CSS_BG_SIZE_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcssimageprivate.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -29,6 +30,7 @@ G_BEGIN_DECLS
GtkCssValue * _gtk_css_bg_size_value_new (GtkCssValue *x,
GtkCssValue *y);
GtkCssValue * _gtk_css_bg_size_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_bg_size_value_token_parse (GtkCssTokenSource *source);
void _gtk_css_bg_size_value_compute_size (const GtkCssValue *bg_size,
GtkCssImage *image,

View File

@@ -204,6 +204,72 @@ _gtk_css_border_value_parse (GtkCssParser *parser,
return result;
}
GtkCssValue *
gtk_css_border_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags,
gboolean allow_auto,
gboolean allow_fill)
{
GtkCssValue *result;
const GtkCssToken *token;
int i;
result = _gtk_css_border_value_new (NULL, NULL, NULL, NULL);
token = gtk_css_token_source_get_token (source);
if (allow_fill && gtk_css_token_is_ident (token, "fill"))
{
result->fill = TRUE;
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
}
for (i = 0;
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
i++, token = gtk_css_token_source_get_token (source))
{
if (allow_fill && !result->fill && gtk_css_token_is_ident (token, "fill"))
{
result->fill = TRUE;
gtk_css_token_source_consume_token (source);
i--;
break;
}
if (allow_auto && gtk_css_token_is_ident (token, "auto"))
{
gtk_css_token_source_consume_token (source);
continue;
}
if (i == 4)
break;
result->values[i] = gtk_css_number_value_token_parse (source, flags);
if (result->values[i] == NULL)
{
_gtk_css_value_unref (result);
return NULL;
}
}
if (i <= 0)
{
gtk_css_token_source_error (source, "Expected a number");
gtk_css_token_source_consume_all (source);
_gtk_css_value_unref (result);
return NULL;
}
for (; i < 4; i++)
{
if (result->values[(i - 1) >> 1])
result->values[i] = _gtk_css_value_ref (result->values[(i - 1) >> 1]);
}
return result;
}
GtkCssValue *
_gtk_css_border_value_get_top (const GtkCssValue *value)
{

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_BORDER_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcssvalueprivate.h"
@@ -34,6 +35,10 @@ GtkCssValue * _gtk_css_border_value_parse (GtkCssParser *par
GtkCssNumberParseFlags flags,
gboolean allow_auto,
gboolean allow_fill);
GtkCssValue * gtk_css_border_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags,
gboolean allow_auto,
gboolean allow_fill);
GtkCssValue * _gtk_css_border_value_get_top (const GtkCssValue *value);
GtkCssValue * _gtk_css_border_value_get_right (const GtkCssValue *value);

View File

@@ -485,3 +485,208 @@ gtk_css_calc_value_parse (GtkCssParser *parser,
return value;
}
GtkCssValue * gtk_css_calc_value_token_parse_sum (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags);
GtkCssValue *
gtk_css_calc_value_token_parse_value (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
const GtkCssToken *token;
GtkCssValue *result;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_function (token, "calc"))
{
gtk_css_token_source_error (source, "Nested calc() expressions are not allowed.");
gtk_css_token_source_consume_all (source);
return NULL;
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_OPEN_PARENS))
{
gtk_css_token_source_consume_token (source);
result = gtk_css_calc_value_token_parse_sum (source, flags);
if (result == NULL)
return NULL;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Missing closing ')' in calc() subterm");
gtk_css_token_source_consume_all (source);
_gtk_css_value_unref (result);
return NULL;
}
gtk_css_token_source_consume_token (source);
return result;
}
else
{
result = gtk_css_number_value_token_parse (source, flags);
if (result == NULL)
return NULL;
}
return result;
}
GtkCssValue *
gtk_css_calc_value_token_parse_product (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
GtkCssValue *result, *value, *temp;
GtkCssNumberParseFlags actual_flags;
actual_flags = flags | GTK_CSS_PARSE_NUMBER;
result = gtk_css_calc_value_token_parse_value (source, actual_flags);
if (result == NULL)
return NULL;
while (TRUE)
{
const GtkCssToken *token = gtk_css_token_source_get_token (source);
if (actual_flags != GTK_CSS_PARSE_NUMBER && !is_number (result))
actual_flags = GTK_CSS_PARSE_NUMBER;
if (gtk_css_token_is_delim (token, '*'))
{
gtk_css_token_source_consume_token (source);
value = gtk_css_calc_value_token_parse_product (source, actual_flags);
if (value == NULL)
goto fail;
if (is_number (value))
temp = gtk_css_number_value_multiply (result, _gtk_css_number_value_get (value, 100));
else
temp = gtk_css_number_value_multiply (value, _gtk_css_number_value_get (result, 100));
_gtk_css_value_unref (value);
_gtk_css_value_unref (result);
result = temp;
}
else if (gtk_css_token_is_delim (token, '/'))
{
gtk_css_token_source_consume_token (source);
value = gtk_css_calc_value_token_parse_product (source, GTK_CSS_PARSE_NUMBER);
if (value == NULL)
goto fail;
temp = gtk_css_number_value_multiply (result, 1.0 / _gtk_css_number_value_get (value, 100));
_gtk_css_value_unref (value);
_gtk_css_value_unref (result);
result = temp;
}
else
{
break;
}
}
if (is_number (result) && !(flags & GTK_CSS_PARSE_NUMBER))
{
gtk_css_token_source_error (source, "calc() product term has no units");
gtk_css_token_source_consume_all (source);
goto fail;
}
return result;
fail:
_gtk_css_value_unref (result);
return NULL;
}
GtkCssValue *
gtk_css_calc_value_token_parse_sum (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
GtkCssValue *result;
const GtkCssToken *token;
result = gtk_css_calc_value_token_parse_product (source, flags);
if (result == NULL)
return NULL;
while (TRUE)
{
GtkCssValue *next, *temp;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_delim (token, '+'))
{
gtk_css_token_source_consume_token (source);
next = gtk_css_calc_value_token_parse_product (source, flags);
if (next == NULL)
goto fail;
}
else if (gtk_css_token_is_delim (token, '-'))
{
gtk_css_token_source_consume_token (source);
temp = gtk_css_calc_value_token_parse_product (source, flags);
if (temp == NULL)
goto fail;
next = gtk_css_number_value_multiply (temp, -1);
_gtk_css_value_unref (temp);
}
else
{
break;
}
temp = gtk_css_number_value_add (result, next);
_gtk_css_value_unref (result);
_gtk_css_value_unref (next);
result = temp;
}
return result;
fail:
_gtk_css_value_unref (result);
return NULL;
}
GtkCssValue *
gtk_css_calc_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
const GtkCssToken *token;
GtkCssValue *value;
/* This confuses '*' and '/' so we disallow backwards compat. */
flags &= ~GTK_CSS_NUMBER_AS_PIXELS;
/* This can only be handled at compute time, we allow negative numbers everywhere */
flags &= ~GTK_CSS_POSITIVE_ONLY;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "calc"))
{
gtk_css_token_source_error (source, "Expected 'calc('");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
value = gtk_css_calc_value_token_parse_sum (source, flags);
if (value == NULL)
return NULL;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
_gtk_css_value_unref (value);
gtk_css_token_source_error (source, "Expected ')' after calc() statement");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
return value;
}

View File

@@ -27,6 +27,8 @@ GtkCssValue * gtk_css_calc_value_new_sum (GtkCssValue *val
GtkCssValue * gtk_css_calc_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags);
GtkCssValue * gtk_css_calc_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags);
G_END_DECLS

View File

@@ -860,3 +860,333 @@ _gtk_css_color_value_parse (GtkCssParser *parser)
return NULL;
}
static gboolean
parse_comma (GtkCssTokenSource *source)
{
if (!gtk_css_token_is (gtk_css_token_source_get_token (source), GTK_CSS_TOKEN_COMMA))
{
gtk_css_token_source_error (source, "Expected ','");
gtk_css_token_source_consume_all (source);
return FALSE;
}
gtk_css_token_source_consume_token (source);
return TRUE;
}
static gboolean
parse_percentage (GtkCssTokenSource *source,
double *d)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
{
*d = token->number.number;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else
{
gtk_css_token_source_error (source, "Expected a percentage.");
gtk_css_token_source_consume_all (source);
return FALSE;
}
}
gboolean
gtk_css_color_value_check_token (const GtkCssToken *token)
{
GdkRGBA rgba;
return gtk_css_token_is_ident (token, "currentColor")
|| gtk_css_token_is_ident (token, "transparent")
|| gtk_css_token_is_function (token, "rgb")
|| gtk_css_token_is_function (token, "rgba")
|| gtk_css_token_is_function (token, "lighter")
|| gtk_css_token_is_function (token, "darker")
|| gtk_css_token_is_function (token, "shade")
|| gtk_css_token_is_function (token, "alpha")
|| gtk_css_token_is_function (token, "mix")
|| gtk_css_token_is_function (token, GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_AT_KEYWORD)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED)
|| (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) && gdk_rgba_parse (&rgba, token->string.string));
}
GtkCssValue *
gtk_css_color_value_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token;
GtkCssValue *value;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "currentColor"))
{
value = _gtk_css_color_value_new_current_color ();
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "transparent"))
{
GdkRGBA transparent = { 0, 0, 0, 0 };
value = _gtk_css_color_value_new_literal (&transparent);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_FUNCTION))
{
if (gtk_css_token_is_function (token, "rgb") ||
gtk_css_token_is_function (token, "rgba"))
{
gboolean has_alpha = gtk_css_token_is_function (token, "rgba");
GdkRGBA rgba;
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
{
if (!parse_percentage (source, &rgba.red) ||
!parse_comma (source) ||
!parse_percentage (source, &rgba.green) ||
!parse_comma (source) ||
!parse_percentage (source, &rgba.blue))
return NULL;
rgba.red = CLAMP (rgba.red, 0, 100.0) / 100.0;
rgba.green = CLAMP (rgba.green, 0, 100.0) / 100.0;
rgba.blue = CLAMP (rgba.blue, 0, 100.0) / 100.0;
}
else
{
if (!gtk_css_token_source_consume_number (source, &rgba.red) ||
!parse_comma (source) ||
!gtk_css_token_source_consume_number (source, &rgba.green) ||
!parse_comma (source) ||
!gtk_css_token_source_consume_number (source, &rgba.blue))
return NULL;
rgba.red = CLAMP (rgba.red, 0, 255.0) / 255.0;
rgba.green = CLAMP (rgba.green, 0, 255.0) / 255.0;
rgba.blue = CLAMP (rgba.blue, 0, 255.0) / 255.0;
}
if (has_alpha)
{
if (!parse_comma (source) ||
!gtk_css_token_source_consume_number (source, &rgba.alpha))
return NULL;
rgba.alpha = CLAMP (rgba.alpha, 0, 1.0);
}
else
rgba.alpha = 1.0;
value = _gtk_css_color_value_new_literal (&rgba);
}
else if (gtk_css_token_is_function (token, "lighter"))
{
GtkCssValue *child;
gtk_css_token_source_consume_token (source);
child = gtk_css_color_value_token_parse (source);
if (child == NULL)
return NULL;
value = _gtk_css_color_value_new_shade (child, 1.3);
_gtk_css_value_unref (child);
}
else if (gtk_css_token_is_function (token, "darker"))
{
GtkCssValue *child;
gtk_css_token_source_consume_token (source);
child = gtk_css_color_value_token_parse (source);
if (child == NULL)
return NULL;
value = _gtk_css_color_value_new_shade (child, 0.7);
_gtk_css_value_unref (child);
}
else if (gtk_css_token_is_function (token, "shade"))
{
GtkCssValue *child;
double d;
gtk_css_token_source_consume_token (source);
child = gtk_css_color_value_token_parse (source);
if (child == NULL)
return NULL;
if (!parse_comma (source) ||
!gtk_css_token_source_consume_number (source, &d))
{
_gtk_css_value_unref (child);
return NULL;
}
value = _gtk_css_color_value_new_shade (child, d);
_gtk_css_value_unref (child);
}
else if (gtk_css_token_is_function (token, "alpha"))
{
GtkCssValue *child;
double d;
gtk_css_token_source_consume_token (source);
child = gtk_css_color_value_token_parse (source);
if (child == NULL)
return NULL;
if (!parse_comma (source) ||
!gtk_css_token_source_consume_number (source, &d))
{
_gtk_css_value_unref (child);
return NULL;
}
value = _gtk_css_color_value_new_alpha (child, d);
_gtk_css_value_unref (child);
}
else if (gtk_css_token_is_function (token, "mix"))
{
GtkCssValue *child1, *child2;
double d;
gtk_css_token_source_consume_token (source);
child1 = gtk_css_color_value_token_parse (source);
if (child1 == NULL)
return NULL;
if (!parse_comma (source) ||
!(child2 = gtk_css_color_value_token_parse (source)))
{
_gtk_css_value_unref (child1);
return NULL;
}
if (!parse_comma (source) ||
!gtk_css_token_source_consume_number (source, &d))
{
_gtk_css_value_unref (child1);
_gtk_css_value_unref (child2);
return NULL;
}
value = _gtk_css_color_value_new_mix (child1, child2, d);
_gtk_css_value_unref (child1);
_gtk_css_value_unref (child2);
}
else if (gtk_css_token_is_function (token, GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME))
{
GtkWin32Theme *theme;
int id;
gtk_css_token_source_consume_token (source);
theme = gtk_win32_theme_token_parse (source);
if (theme == NULL)
return NULL;
if (!parse_comma (source))
{
gtk_win32_theme_unref (theme);
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
id = gtk_win32_get_sys_color_id_for_name (token->string.string);
if (id == -1)
{
gtk_css_token_source_error (source, "'%s' is not a win32 color name.", token->string.string);
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else if (!gtk_css_token_source_consume_integer (source, &id))
{
gtk_win32_theme_unref (theme);
return NULL;
}
value = gtk_css_color_value_new_win32_for_theme (theme, id);
gtk_win32_theme_unref (theme);
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "No closing ')' in color definition");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_AT_KEYWORD))
{
value = _gtk_css_color_value_new_name (token->string.string);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED))
{
GdkRGBA rgba;
const char *s = token->string.string;
if (g_ascii_isxdigit (s[0]) && g_ascii_isxdigit (s[1]) && g_ascii_isxdigit (s[2]) && s[3] == '\0')
{
rgba.red = g_ascii_xdigit_value(s[0]) / 15.0;
rgba.green = g_ascii_xdigit_value(s[1]) / 15.0;
rgba.blue = g_ascii_xdigit_value(s[2]) / 15.0;
rgba.alpha = 1.0;
}
else if (g_ascii_isxdigit (s[0]) && g_ascii_isxdigit (s[1]) && g_ascii_isxdigit (s[2]) &&
g_ascii_isxdigit (s[3]) && g_ascii_isxdigit (s[4]) && g_ascii_isxdigit (s[5]) &&
s[6] == '\0')
{
rgba.red = (g_ascii_xdigit_value(s[0]) * 16 + g_ascii_xdigit_value(s[1])) / 255.0;
rgba.green = (g_ascii_xdigit_value(s[2]) * 16 + g_ascii_xdigit_value(s[3])) / 255.0;
rgba.blue = (g_ascii_xdigit_value(s[4]) * 16 + g_ascii_xdigit_value(s[5])) / 255.0;
rgba.alpha = 1.0;
}
else
{
gtk_css_token_source_error (source, "Not a valid color value, needs to be #RGB or #RRGGBB");
gtk_css_token_source_consume_all (source);
return NULL;
}
value = _gtk_css_color_value_new_literal (&rgba);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
GdkRGBA rgba;
const char *name = token->string.string;
if (!gdk_rgba_parse (&rgba, name))
{
gtk_css_token_source_error (source, "'%s' is not a valid color name", name);
gtk_css_token_source_consume_all (source);
return NULL;
}
value = _gtk_css_color_value_new_literal (&rgba);
gtk_css_token_source_consume_token (source);
}
else
{
gtk_css_token_source_error (source, "Not a color definition");
gtk_css_token_source_consume_all (source);
return NULL;
}
return value;
return NULL;
}

View File

@@ -19,6 +19,7 @@
#define __GTK_CSS_COLOR_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -41,7 +42,9 @@ GtkCssValue * _gtk_css_color_value_new_win32 (const gchar *theme_c
gint id);
GtkCssValue * _gtk_css_color_value_new_current_color (void);
GtkCssValue * _gtk_css_color_value_parse (GtkCssParser *parser);
GtkCssValue * _gtk_css_color_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_color_value_token_parse (GtkCssTokenSource *source);
gboolean gtk_css_color_value_check_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_color_value_resolve (GtkCssValue *color,
GtkStyleProviderPrivate *provider,

View File

@@ -151,6 +151,38 @@ _gtk_css_corner_value_parse (GtkCssParser *parser)
return _gtk_css_corner_value_new (x, y);
}
GtkCssValue *
gtk_css_corner_value_token_parse (GtkCssTokenSource *source)
{
GtkCssValue *x, *y;
x = gtk_css_number_value_token_parse (source,
GTK_CSS_POSITIVE_ONLY
| GTK_CSS_PARSE_PERCENT
| GTK_CSS_NUMBER_AS_PIXELS
| GTK_CSS_PARSE_LENGTH);
if (x == NULL)
return NULL;
if (gtk_css_token_is (gtk_css_token_source_get_token (source), GTK_CSS_TOKEN_EOF))
y = _gtk_css_value_ref (x);
else
{
y = gtk_css_number_value_token_parse (source,
GTK_CSS_POSITIVE_ONLY
| GTK_CSS_PARSE_PERCENT
| GTK_CSS_NUMBER_AS_PIXELS
| GTK_CSS_PARSE_LENGTH);
if (y == NULL)
{
_gtk_css_value_unref (x);
return NULL;
}
}
return _gtk_css_corner_value_new (x, y);
}
double
_gtk_css_corner_value_get_x (const GtkCssValue *corner,
double one_hundred_percent)

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_CORNER_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -28,6 +29,7 @@ G_BEGIN_DECLS
GtkCssValue * _gtk_css_corner_value_new (GtkCssValue *x,
GtkCssValue *y);
GtkCssValue * _gtk_css_corner_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_corner_value_token_parse (GtkCssTokenSource *source);
double _gtk_css_corner_value_get_x (const GtkCssValue *corner,
double one_hundred_percent);

View File

@@ -43,6 +43,14 @@ gtk_css_custom_property_parse_value (GtkStyleProperty *property,
return NULL;
}
static GtkCssValue *
gtk_css_custom_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
gtk_css_token_source_unknown (source, "Custom CSS properties are no longer supported.");
return NULL;
}
static void
gtk_css_custom_property_query (GtkStyleProperty *property,
GValue *value,
@@ -81,6 +89,7 @@ _gtk_css_custom_property_class_init (GtkCssCustomPropertyClass *klass)
GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);
property_class->parse_value = gtk_css_custom_property_parse_value;
property_class->token_parse = gtk_css_custom_property_token_parse;
property_class->query = gtk_css_custom_property_query;
property_class->assign = gtk_css_custom_property_assign;
}

196
gtk/gtkcssdeclaration.c Normal file
View File

@@ -0,0 +1,196 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssdeclarationprivate.h"
#include "gtkcsslonghanddeclarationprivate.h"
#include "gtkcssshorthanddeclarationprivate.h"
#include "gtkcsswidgetstyledeclarationprivate.h"
#include "gtkstylepropertyprivate.h"
#include "gtkintl.h"
#include "gtkprivate.h"
enum {
PROP_0,
PROP_NAME,
PROP_PARENT_STYLE,
NUM_PROPERTIES
};
typedef struct _GtkCssDeclarationPrivate GtkCssDeclarationPrivate;
struct _GtkCssDeclarationPrivate {
GtkCssStyleDeclaration *parent_style;
};
static GParamSpec *declaration_props[NUM_PROPERTIES] = { NULL, };
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkCssDeclaration, gtk_css_declaration, G_TYPE_OBJECT)
static void
gtk_css_declaration_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkCssDeclaration *declaration = GTK_CSS_DECLARATION (gobject);
GtkCssDeclarationPrivate *priv = gtk_css_declaration_get_instance_private (declaration);
switch (prop_id)
{
case PROP_PARENT_STYLE:
priv->parent_style = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_css_declaration_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkCssDeclaration *declaration = GTK_CSS_DECLARATION (gobject);
GtkCssDeclarationPrivate *priv = gtk_css_declaration_get_instance_private (declaration);
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, gtk_css_declaration_get_name (declaration));
break;
case PROP_PARENT_STYLE:
g_value_set_object (value, priv->parent_style);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gtk_css_declaration_class_init (GtkCssDeclarationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = gtk_css_declaration_set_property;
object_class->get_property = gtk_css_declaration_get_property;
declaration_props[PROP_NAME] =
g_param_spec_string ("name",
P_("name"),
P_("Name this declaration defines a value for"),
NULL,
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
declaration_props[PROP_PARENT_STYLE] =
g_param_spec_object ("parent-style",
P_("parent style"),
P_("The parent style"),
GTK_TYPE_CSS_STYLE_DECLARATION,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, declaration_props);
}
static void
gtk_css_declaration_init (GtkCssDeclaration *declaration)
{
}
GtkCssDeclaration *
gtk_css_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
GtkStyleProperty *prop;
char *name;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected a property name");
gtk_css_token_source_consume_all (source);
return NULL;
}
name = g_utf8_strdown (token->string.string, -1);
prop = _gtk_style_property_lookup (name);
g_free (name);
if (GTK_IS_CSS_STYLE_PROPERTY (prop))
return gtk_css_longhand_declaration_new_parse (style, source);
else if (GTK_IS_CSS_SHORTHAND_PROPERTY (prop))
return gtk_css_shorthand_declaration_new_parse (style, source);
else if (gtk_css_widget_style_declaration_accepts_name (token->string.string))
return gtk_css_widget_style_declaration_new_parse (style, source);
else
{
gtk_css_token_source_unknown (source,
"Property name \"%s\" does not define a valid property",
token->string.string);
gtk_css_token_source_consume_all (source);
return NULL;
}
}
GtkCssStyleDeclaration *
gtk_css_declaration_get_parent_style (GtkCssDeclaration *decl)
{
GtkCssDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_DECLARATION (decl), NULL);
priv = gtk_css_declaration_get_instance_private (decl);
return priv->parent_style;
}
const char *
gtk_css_declaration_get_name (GtkCssDeclaration *decl)
{
g_return_val_if_fail (GTK_IS_CSS_DECLARATION (decl), NULL);
return GTK_CSS_DECLARATION_GET_CLASS (decl)->get_name (decl);
}
void
gtk_css_declaration_print_value (GtkCssDeclaration *decl,
GString *string)
{
g_return_if_fail (GTK_IS_CSS_DECLARATION (decl));
g_return_if_fail (string != NULL);
return GTK_CSS_DECLARATION_GET_CLASS (decl)->print_value (decl, string);
}
char *
gtk_css_declaration_get_value_string (GtkCssDeclaration *decl)
{
GString *string;
g_return_val_if_fail (GTK_IS_CSS_DECLARATION (decl), NULL);
string = g_string_new (NULL);
gtk_css_declaration_print_value (decl, string);
return g_string_free (string, FALSE);
}

View File

@@ -0,0 +1,68 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_DECLARATION_PRIVATE_H__
#define __GTK_CSS_DECLARATION_PRIVATE_H__
#include "gtk/gtkcssstyledeclarationprivate.h"
#include "gtk/gtkcssvalueprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_DECLARATION (gtk_css_declaration_get_type ())
#define GTK_CSS_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_DECLARATION, GtkCssDeclaration))
#define GTK_CSS_DECLARATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_DECLARATION, GtkCssDeclarationClass))
#define GTK_IS_CSS_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_DECLARATION))
#define GTK_IS_CSS_DECLARATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_DECLARATION))
#define GTK_CSS_DECLARATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_DECLARATION, GtkCssDeclarationClass))
/* typedef struct _GtkCssDeclaration GtkCssDeclaration; */
typedef struct _GtkCssDeclarationClass GtkCssDeclarationClass;
struct _GtkCssDeclaration
{
GObject parent;
};
struct _GtkCssDeclarationClass
{
GObjectClass parent_class;
const char * (* get_name) (GtkCssDeclaration *decl);
void (* print_value) (GtkCssDeclaration *decl,
GString *string);
};
GType gtk_css_declaration_get_type (void) G_GNUC_CONST;
GtkCssDeclaration * gtk_css_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source);
const char * gtk_css_declaration_get_name (GtkCssDeclaration *decl);
GtkCssStyleDeclaration *gtk_css_declaration_get_parent_style (GtkCssDeclaration *decl);
void gtk_css_declaration_print_value (GtkCssDeclaration *decl,
GString *string);
char * gtk_css_declaration_get_value_string (GtkCssDeclaration *decl);
G_END_DECLS
#endif /* __GTK_CSS_DECLARATION_PRIVATE_H__ */

152
gtk/gtkcssdefinecolorrule.c Normal file
View File

@@ -0,0 +1,152 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssdefinecolorruleprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssstylesheetprivate.h"
typedef struct _GtkCssDefineColorRulePrivate GtkCssDefineColorRulePrivate;
struct _GtkCssDefineColorRulePrivate {
char *name;
GtkCssValue *color;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssDefineColorRule, gtk_css_define_color_rule, GTK_TYPE_CSS_RULE)
static void
gtk_css_define_color_rule_finalize (GObject *object)
{
GtkCssDefineColorRule *define_color_rule = GTK_CSS_DEFINE_COLOR_RULE (object);
GtkCssDefineColorRulePrivate *priv = gtk_css_define_color_rule_get_instance_private (define_color_rule);
g_free (priv->name);
if (priv->color)
_gtk_css_value_unref (priv->color);
G_OBJECT_CLASS (gtk_css_define_color_rule_parent_class)->finalize (object);
}
static void
gtk_css_define_color_rule_class_init (GtkCssDefineColorRuleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_define_color_rule_finalize;
}
static void
gtk_css_define_color_rule_init (GtkCssDefineColorRule *define_color_rule)
{
}
static GtkCssRule *
gtk_css_define_color_rule_new (GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
return g_object_new (GTK_TYPE_CSS_DEFINE_COLOR_RULE,
"parent-rule", parent_rule,
"parent-stylesheet", parent_style_sheet,
NULL);
}
GtkCssRule *
gtk_css_define_color_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
GtkCssDefineColorRulePrivate *priv;
const GtkCssToken *token;
GtkCssRule *result;
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);
result = gtk_css_define_color_rule_new (parent_rule, parent_style_sheet);
priv = gtk_css_define_color_rule_get_instance_private (GTK_CSS_DEFINE_COLOR_RULE (result));
gtk_css_token_source_set_consumer (source, G_OBJECT (result));
token = gtk_css_token_source_get_token (source);
if (token->type != GTK_CSS_TOKEN_AT_KEYWORD ||
g_ascii_strcasecmp (token->string.string, "define-color") != 0)
{
gtk_css_token_source_error (source, "Expected '@define-color'");
gtk_css_token_source_consume_all (source);
g_object_unref (result);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected name of color");
gtk_css_token_source_consume_all (source);
g_object_unref (result);
return NULL;
}
priv->name = g_strdup (token->string.string);
gtk_css_token_source_consume_token (source);
priv->color = gtk_css_color_value_token_parse (source);
if (priv->color == NULL)
{
g_object_unref (result);
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_SEMICOLON))
{
gtk_css_token_source_error (source, "Expected ';' at end of @define-color");
gtk_css_token_source_consume_all (source);
g_object_unref (result);
return NULL;
}
gtk_css_token_source_consume_token (source);
return result;
}
const char *
gtk_css_define_color_rule_get_name (GtkCssDefineColorRule *rule)
{
GtkCssDefineColorRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_DEFINE_COLOR_RULE (rule), NULL);
priv = gtk_css_define_color_rule_get_instance_private (rule);
return priv->name;
}
GtkCssValue *
gtk_css_define_color_rule_get_value (GtkCssDefineColorRule *rule)
{
GtkCssDefineColorRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_DEFINE_COLOR_RULE (rule), NULL);
priv = gtk_css_define_color_rule_get_instance_private (rule);
return priv->color;
}

View File

@@ -0,0 +1,60 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_DEFINE_COLOR_RULE_PRIVATE_H__
#define __GTK_CSS_DEFINE_COLOR_RULE_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
#include "gtk/gtkcssvalueprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_DEFINE_COLOR_RULE (gtk_css_define_color_rule_get_type ())
#define GTK_CSS_DEFINE_COLOR_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_DEFINE_COLOR_RULE, GtkCssDefineColorRule))
#define GTK_CSS_DEFINE_COLOR_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_DEFINE_COLOR_RULE, GtkCssDefineColorRuleClass))
#define GTK_IS_CSS_DEFINE_COLOR_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_DEFINE_COLOR_RULE))
#define GTK_IS_CSS_DEFINE_COLOR_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_DEFINE_COLOR_RULE))
#define GTK_CSS_DEFINE_COLOR_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_DEFINE_COLOR_RULE, GtkCssDefineColorRuleClass))
typedef struct _GtkCssDefineColorRule GtkCssDefineColorRule;
typedef struct _GtkCssDefineColorRuleClass GtkCssDefineColorRuleClass;
struct _GtkCssDefineColorRule
{
GtkCssRule parent;
};
struct _GtkCssDefineColorRuleClass
{
GtkCssRuleClass parent_class;
};
GType gtk_css_define_color_rule_get_type (void) G_GNUC_CONST;
GtkCssRule * gtk_css_define_color_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
const char * gtk_css_define_color_rule_get_name (GtkCssDefineColorRule *rule);
GtkCssValue * gtk_css_define_color_rule_get_value (GtkCssDefineColorRule *rule);
G_END_DECLS
#endif /* __GTK_CSS_DEFINE_COLOR_RULE_PRIVATE_H__ */

View File

@@ -323,3 +323,115 @@ gtk_css_dimension_value_new (double value,
return result;
}
GtkCssValue *
gtk_css_dimension_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
const GtkCssToken *token = gtk_css_token_source_get_token (source);
double d;
GtkCssUnit unit;
if ((gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER)) &&
((flags & (GTK_CSS_PARSE_NUMBER | GTK_CSS_NUMBER_AS_PIXELS)) ||
(token->number.number == 0.0 && (flags & (GTK_CSS_PARSE_LENGTH | GTK_CSS_PARSE_ANGLE)))))
{
d = token->number.number;
if (flags & GTK_CSS_NUMBER_AS_PIXELS)
{
if (d != 0.0)
gtk_css_token_source_deprecated (source, "Not using units is deprecated. Assuming 'px'.");
unit = GTK_CSS_PX;
}
else
{
if (flags & GTK_CSS_PARSE_NUMBER)
unit = GTK_CSS_NUMBER;
else if (flags & GTK_CSS_PARSE_LENGTH)
unit = GTK_CSS_PX;
else if (flags & GTK_CSS_PARSE_ANGLE)
unit = GTK_CSS_DEG;
}
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE) &&
(flags & GTK_CSS_PARSE_PERCENT))
{
d = token->number.number;
unit = GTK_CSS_PERCENT;
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_DIMENSION))
{
static const struct {
const char *name;
GtkCssUnit unit;
GtkCssNumberParseFlags flag;
} units[] = {
{ "px", GTK_CSS_PX, GTK_CSS_PARSE_LENGTH },
{ "pt", GTK_CSS_PT, GTK_CSS_PARSE_LENGTH },
{ "em", GTK_CSS_EM, GTK_CSS_PARSE_LENGTH },
{ "ex", GTK_CSS_EX, GTK_CSS_PARSE_LENGTH },
{ "rem", GTK_CSS_REM, GTK_CSS_PARSE_LENGTH },
{ "pc", GTK_CSS_PC, GTK_CSS_PARSE_LENGTH },
{ "in", GTK_CSS_IN, GTK_CSS_PARSE_LENGTH },
{ "cm", GTK_CSS_CM, GTK_CSS_PARSE_LENGTH },
{ "mm", GTK_CSS_MM, GTK_CSS_PARSE_LENGTH },
{ "rad", GTK_CSS_RAD, GTK_CSS_PARSE_ANGLE },
{ "deg", GTK_CSS_DEG, GTK_CSS_PARSE_ANGLE },
{ "grad", GTK_CSS_GRAD, GTK_CSS_PARSE_ANGLE },
{ "turn", GTK_CSS_TURN, GTK_CSS_PARSE_ANGLE },
{ "s", GTK_CSS_S, GTK_CSS_PARSE_TIME },
{ "ms", GTK_CSS_MS, GTK_CSS_PARSE_TIME }
};
guint i;
for (i = 0; i < G_N_ELEMENTS (units); i++)
{
if ((flags & units[i].flag) == 0)
continue;
if (g_ascii_strcasecmp (units[i].name, token->dimension.dimension) == 0)
{
d = token->dimension.value;
unit = units[i].unit;
break;
}
}
if (i == G_N_ELEMENTS (units))
{
gtk_css_token_source_error (source, "'%s' is not a valid unit.", token->dimension.dimension);
gtk_css_token_source_consume_all (source);
return NULL;
}
}
else
{
if (flags & GTK_CSS_PARSE_LENGTH)
gtk_css_token_source_error (source, "Expected a length");
else if (flags & GTK_CSS_PARSE_ANGLE)
gtk_css_token_source_error (source, "Expected an angle");
else if (flags & GTK_CSS_PARSE_TIME)
gtk_css_token_source_error (source, "Expected a time");
else if (flags & GTK_CSS_PARSE_PERCENT)
gtk_css_token_source_error (source, "Expected a percentage");
else
gtk_css_token_source_error (source, "Expected a number");
gtk_css_token_source_consume_all (source);
return NULL;
}
if ((flags & GTK_CSS_POSITIVE_ONLY) && d < 0.0)
{
gtk_css_token_source_error (source, "Negative values are not allowed");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
return gtk_css_dimension_value_new (d, unit);
}

View File

@@ -30,6 +30,9 @@ GtkCssValue * gtk_css_dimension_value_new (double val
GtkCssValue * gtk_css_dimension_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags);
GtkCssValue * gtk_css_dimension_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags);
G_END_DECLS
#endif /* __GTK_CSS_DIMENSION_VALUE_PRIVATE_H__ */

View File

@@ -37,7 +37,7 @@ struct _GtkCssValue {
double y2;
} cubic;
struct {
guint steps;
int steps;
gboolean start;
} steps;
} u;
@@ -125,7 +125,7 @@ gtk_css_value_ease_print (const GtkCssValue *ease,
}
else
{
g_string_append_printf (string, "steps(%u%s)", ease->u.steps.steps, ease->u.steps.start ? ",start" : "");
g_string_append_printf (string, "steps(%d%s)", ease->u.steps.steps, ease->u.steps.start ? ",start" : "");
}
break;
default:
@@ -167,7 +167,7 @@ _gtk_css_ease_value_new_cubic_bezier (double x1,
}
static GtkCssValue *
_gtk_css_ease_value_new_steps (guint n_steps,
_gtk_css_ease_value_new_steps (gint n_steps,
gboolean start)
{
GtkCssValue *value;
@@ -327,6 +327,137 @@ _gtk_css_ease_value_parse (GtkCssParser *parser)
return NULL;
}
static guint
token_parse_cubic_bezier (GtkCssTokenSource *source,
guint n,
gpointer data)
{
double *numbers = data;
if (!gtk_css_token_source_consume_number (source, &numbers[n]))
return FALSE;
/* XXX: This error is too late */
if (n % 2 == 0 &&
(numbers[n] < 0 || numbers[n] > 1.0))
{
gtk_css_token_source_error (source, "Value %g out of range. Must be from 0.0 to 1.0", numbers[n]);
return 0;
}
return 1;
}
static guint
token_parse_steps (GtkCssTokenSource *source,
guint nth_argument,
gpointer data)
{
GtkCssValue *value = data;
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (nth_argument == 0)
{
if (!gtk_css_token_source_consume_integer (source, &value->u.steps.steps))
return 0;
if (value->u.steps.steps <= 0)
{
gtk_css_token_source_error (source, "Number of steps must be greater than 0");
gtk_css_token_source_consume_all (source);
return 0;
}
return 1;
}
else
{
if (gtk_css_token_is_ident (token, "start"))
value->u.steps.start = TRUE;
else if (gtk_css_token_is_ident (token, "end"))
value->u.steps.start = FALSE;
else
{
gtk_css_token_source_error (source, "Only allowed values are 'start' and 'end'");
gtk_css_token_source_consume_all (source);
return 0;
}
gtk_css_token_source_consume_token (source);
return 1;
}
}
GtkCssValue *
gtk_css_ease_value_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token;
guint i;
token = gtk_css_token_source_get_token (source);
for (i = 0; i < G_N_ELEMENTS (parser_values); i++)
{
if (parser_values[i].needs_custom)
continue;
if (gtk_css_token_is_ident (token, parser_values[i].name))
{
gtk_css_token_source_consume_token (source);
if (parser_values[i].is_bezier)
return _gtk_css_ease_value_new_cubic_bezier (parser_values[i].values[0],
parser_values[i].values[1],
parser_values[i].values[2],
parser_values[i].values[3]);
else
return _gtk_css_ease_value_new_steps (parser_values[i].values[0],
parser_values[i].values[1] != 0.0);
}
}
if (gtk_css_token_is_function (token, "cubic-bezier"))
{
double numbers[4];
if (!gtk_css_token_source_consume_function (source, 4, 4, token_parse_cubic_bezier, numbers))
{
gtk_css_token_source_consume_all (source);
return NULL;
}
return _gtk_css_ease_value_new_cubic_bezier (numbers[0], numbers[1], numbers[2], numbers[3]);
}
else if (gtk_css_token_is_function (token, "steps"))
{
GtkCssValue *value = _gtk_css_ease_value_new_steps (1, FALSE);
if (!gtk_css_token_source_consume_function (source, 1, 2, token_parse_steps, value))
{
_gtk_css_value_unref (value);
gtk_css_token_source_consume_all (source);
return NULL;
}
return value;
}
else
{
gtk_css_token_source_error (source, "Unknown ease value");
gtk_css_token_source_consume_all (source);
return NULL;
}
}
static inline double
cubic (double a, double b, double c, double t)
{
return ((a * t + b) * t + c) * t;
}
static inline double
cubic_deriv (double a, double b, double c, double t)
{
return (3 * a * t + 2 * b) * t + c;
}
double
_gtk_css_ease_value_transform (const GtkCssValue *ease,
double progress)
@@ -343,8 +474,36 @@ _gtk_css_ease_value_transform (const GtkCssValue *ease,
case GTK_CSS_EASE_CUBIC_BEZIER:
{
static const double epsilon = 0.00001;
double ax, bx, cx;
double ay, by, cy;
double tmin, t, tmax;
guint i;
cx = 3.0 * ease->u.cubic.x1;
bx = 3.0 * (ease->u.cubic.x2 - ease->u.cubic.x1) - cx;
ax = 1.0 - cx - bx;
cy = 3.0 * ease->u.cubic.y1;
by = 3.0 * (ease->u.cubic.y2 - ease->u.cubic.y1) - cy;
ay = 1.0 - cy - by;
/* Try with Newton's method first */
t = progress;
for (i = 0; i < 8; i++)
{
double sample, deriv;
sample = cubic (ax, bx, cx, t);
if (fabs (sample - t) < epsilon)
return cubic (ay, by, cy, t);
deriv = cubic_deriv (ax, bx, cx, t);
if (deriv < epsilon)
return cubic (ay, by, cy, t);
t = t - (sample - t) / deriv;
}
/* Fallback if Newton doesn't converge */
tmin = 0.0;
tmax = 1.0;
t = progress;
@@ -352,9 +511,7 @@ _gtk_css_ease_value_transform (const GtkCssValue *ease,
while (tmin < tmax)
{
double sample;
sample = (((1.0 + 3 * ease->u.cubic.x1 - 3 * ease->u.cubic.x2) * t
+ -6 * ease->u.cubic.x1 + 3 * ease->u.cubic.x2) * t
+ 3 * ease->u.cubic.x1 ) * t;
sample = cubic (ax, bx, cx, t);
if (fabs(sample - progress) < epsilon)
break;
@@ -365,9 +522,7 @@ _gtk_css_ease_value_transform (const GtkCssValue *ease,
t = (tmax + tmin) * .5;
}
return (((1.0 + 3 * ease->u.cubic.y1 - 3 * ease->u.cubic.y2) * t
+ -6 * ease->u.cubic.y1 + 3 * ease->u.cubic.y2) * t
+ 3 * ease->u.cubic.y1 ) * t;
return cubic (ay, by, cy, t);
}
case GTK_CSS_EASE_STEPS:
progress *= ease->u.steps.steps;

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_EASE_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -31,6 +32,7 @@ GtkCssValue * _gtk_css_ease_value_new_cubic_bezier (double x1,
double y2);
gboolean _gtk_css_ease_value_can_parse (GtkCssParser *parser);
GtkCssValue * _gtk_css_ease_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_ease_value_token_parse (GtkCssTokenSource *source);
double _gtk_css_ease_value_transform (const GtkCssValue *ease,
double progress);

View File

@@ -130,6 +130,40 @@ _gtk_css_engine_value_parse (GtkCssParser *parser)
return _gtk_css_engine_value_new (engine);
}
GtkCssValue *
gtk_css_engine_value_token_parse (GtkCssTokenSource *source)
{
GtkThemingEngine *engine;
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "none"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_engine_value_new (gtk_theming_engine_load (NULL));
}
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected a valid theme name");
gtk_css_token_source_consume_all (source);
return NULL;
}
engine = gtk_theming_engine_load (token->string.string);
if (engine == NULL)
{
gtk_css_token_source_error (source, "Theming engine '%s' not found", token->string.string);
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
return _gtk_css_engine_value_new (engine);
}
GtkThemingEngine *
_gtk_css_engine_value_get_engine (const GtkCssValue *value)
{

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_ENGINE_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
#include "deprecated/gtkthemingengine.h"
@@ -28,6 +29,7 @@ G_BEGIN_DECLS
GtkCssValue * _gtk_css_engine_value_new (GtkThemingEngine *engine);
GtkCssValue * _gtk_css_engine_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_engine_value_token_parse (GtkCssTokenSource *source);
GtkThemingEngine * _gtk_css_engine_value_get_engine (const GtkCssValue *engine);

View File

@@ -101,6 +101,23 @@ _gtk_css_border_style_value_new (GtkBorderStyle border_style)
return _gtk_css_value_ref (&border_style_values[border_style]);
}
GtkCssValue *
gtk_css_border_style_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (border_style_values); i++)
{
if (gtk_css_token_is_ident (token, border_style_values[i].name))
return _gtk_css_value_ref (&border_style_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_border_style_value_try_parse (GtkCssParser *parser)
{
@@ -243,6 +260,23 @@ _gtk_css_font_size_value_new (GtkCssFontSize font_size)
return _gtk_css_value_ref (&font_size_values[font_size]);
}
GtkCssValue *
gtk_css_font_size_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (font_size_values); i++)
{
if (gtk_css_token_is_ident (token, font_size_values[i].name))
return _gtk_css_value_ref (&font_size_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_font_size_value_try_parse (GtkCssParser *parser)
{
@@ -291,6 +325,23 @@ _gtk_css_font_style_value_new (PangoStyle font_style)
return _gtk_css_value_ref (&font_style_values[font_style]);
}
GtkCssValue *
gtk_css_font_style_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (font_style_values); i++)
{
if (gtk_css_token_is_ident (token, font_style_values[i].name))
return _gtk_css_value_ref (&font_style_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_font_style_value_try_parse (GtkCssParser *parser)
{
@@ -338,6 +389,23 @@ _gtk_css_font_variant_value_new (PangoVariant font_variant)
return _gtk_css_value_ref (&font_variant_values[font_variant]);
}
GtkCssValue *
gtk_css_font_variant_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (font_variant_values); i++)
{
if (gtk_css_token_is_ident (token, font_variant_values[i].name))
return _gtk_css_value_ref (&font_variant_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_font_variant_value_try_parse (GtkCssParser *parser)
{
@@ -467,6 +535,23 @@ _gtk_css_font_weight_value_new (PangoWeight font_weight)
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_font_weight_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (font_weight_values); i++)
{
if (gtk_css_token_is_ident (token, font_weight_values[i].name))
return _gtk_css_value_ref (&font_weight_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_font_weight_value_try_parse (GtkCssParser *parser)
{
@@ -529,6 +614,23 @@ _gtk_css_font_stretch_value_new (PangoStretch font_stretch)
return _gtk_css_value_ref (&font_stretch_values[font_stretch]);
}
GtkCssValue *
gtk_css_font_stretch_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (font_stretch_values); i++)
{
if (gtk_css_token_is_ident (token, font_stretch_values[i].name))
return _gtk_css_value_ref (&font_stretch_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_font_stretch_value_try_parse (GtkCssParser *parser)
{
@@ -577,6 +679,23 @@ _gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line)
return _gtk_css_value_ref (&text_decoration_line_values[line]);
}
GtkCssValue *
gtk_css_text_decoration_line_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (text_decoration_line_values); i++)
{
if (gtk_css_token_is_ident (token, text_decoration_line_values[i].name))
return _gtk_css_value_ref (&text_decoration_line_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_text_decoration_line_value_try_parse (GtkCssParser *parser)
{
@@ -625,6 +744,23 @@ _gtk_css_text_decoration_style_value_new (GtkTextDecorationStyle style)
return _gtk_css_value_ref (&text_decoration_style_values[style]);
}
GtkCssValue *
gtk_css_text_decoration_style_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (text_decoration_style_values); i++)
{
if (gtk_css_token_is_ident (token, text_decoration_style_values[i].name))
return _gtk_css_value_ref (&text_decoration_style_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_text_decoration_style_value_try_parse (GtkCssParser *parser)
{
@@ -679,6 +815,23 @@ _gtk_css_area_value_new (GtkCssArea area)
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_area_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (area_values); i++)
{
if (gtk_css_token_is_ident (token, area_values[i].name))
return _gtk_css_value_ref (&area_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_area_value_try_parse (GtkCssParser *parser)
{
@@ -734,6 +887,23 @@ _gtk_css_direction_value_new (GtkCssDirection direction)
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_direction_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (direction_values); i++)
{
if (gtk_css_token_is_ident (token, direction_values[i].name))
return _gtk_css_value_ref (&direction_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_direction_value_try_parse (GtkCssParser *parser)
{
@@ -790,6 +960,23 @@ _gtk_css_play_state_value_new (GtkCssPlayState play_state)
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_play_state_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
{
if (gtk_css_token_is_ident (token, play_state_values[i].name))
return _gtk_css_value_ref (&play_state_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_play_state_value_try_parse (GtkCssParser *parser)
{
@@ -845,6 +1032,23 @@ _gtk_css_fill_mode_value_new (GtkCssFillMode fill_mode)
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_fill_mode_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
{
if (gtk_css_token_is_ident (token, fill_mode_values[i].name))
return _gtk_css_value_ref (&fill_mode_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_fill_mode_value_try_parse (GtkCssParser *parser)
{
@@ -879,26 +1083,43 @@ static const GtkCssValueClass GTK_CSS_VALUE_ICON_EFFECT = {
gtk_css_value_enum_print
};
static GtkCssValue image_effect_values[] = {
static GtkCssValue icon_effect_values[] = {
{ &GTK_CSS_VALUE_ICON_EFFECT, 1, GTK_CSS_ICON_EFFECT_NONE, "none" },
{ &GTK_CSS_VALUE_ICON_EFFECT, 1, GTK_CSS_ICON_EFFECT_HIGHLIGHT, "highlight" },
{ &GTK_CSS_VALUE_ICON_EFFECT, 1, GTK_CSS_ICON_EFFECT_DIM, "dim" }
};
GtkCssValue *
_gtk_css_icon_effect_value_new (GtkCssIconEffect image_effect)
_gtk_css_icon_effect_value_new (GtkCssIconEffect icon_effect)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (image_effect_values); i++)
for (i = 0; i < G_N_ELEMENTS (icon_effect_values); i++)
{
if (image_effect_values[i].value == image_effect)
return _gtk_css_value_ref (&image_effect_values[i]);
if (icon_effect_values[i].value == icon_effect)
return _gtk_css_value_ref (&icon_effect_values[i]);
}
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_icon_effect_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (icon_effect_values); i++)
{
if (gtk_css_token_is_ident (token, icon_effect_values[i].name))
return _gtk_css_value_ref (&icon_effect_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_icon_effect_value_try_parse (GtkCssParser *parser)
{
@@ -906,10 +1127,10 @@ _gtk_css_icon_effect_value_try_parse (GtkCssParser *parser)
g_return_val_if_fail (parser != NULL, NULL);
for (i = 0; i < G_N_ELEMENTS (image_effect_values); i++)
for (i = 0; i < G_N_ELEMENTS (icon_effect_values); i++)
{
if (_gtk_css_parser_try (parser, image_effect_values[i].name, TRUE))
return _gtk_css_value_ref (&image_effect_values[i]);
if (_gtk_css_parser_try (parser, icon_effect_values[i].name, TRUE))
return _gtk_css_value_ref (&icon_effect_values[i]);
}
return NULL;
@@ -986,6 +1207,23 @@ _gtk_css_icon_style_value_new (GtkCssIconStyle icon_style)
g_return_val_if_reached (NULL);
}
GtkCssValue *
gtk_css_icon_style_value_from_token (const GtkCssToken *token)
{
guint i;
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
return NULL;
for (i = 0; i < G_N_ELEMENTS (icon_style_values); i++)
{
if (gtk_css_token_is_ident (token, icon_style_values[i].name))
return _gtk_css_value_ref (&icon_style_values[i]);
}
return NULL;
}
GtkCssValue *
_gtk_css_icon_style_value_try_parse (GtkCssParser *parser)
{

View File

@@ -22,67 +22,82 @@
#include "gtkenums.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
GtkCssValue * _gtk_css_border_style_value_new (GtkBorderStyle border_style);
GtkCssValue * gtk_css_border_style_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_border_style_value_try_parse (GtkCssParser *parser);
GtkBorderStyle _gtk_css_border_style_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_font_size_value_new (GtkCssFontSize size);
GtkCssValue * gtk_css_font_size_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_font_size_value_try_parse (GtkCssParser *parser);
GtkCssFontSize _gtk_css_font_size_value_get (const GtkCssValue *value);
double _gtk_css_font_size_get_default (GtkStyleProviderPrivate *provider);
GtkCssValue * _gtk_css_font_style_value_new (PangoStyle style);
GtkCssValue * gtk_css_font_style_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_font_style_value_try_parse (GtkCssParser *parser);
PangoStyle _gtk_css_font_style_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_font_variant_value_new (PangoVariant variant);
GtkCssValue * gtk_css_font_variant_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_font_variant_value_try_parse (GtkCssParser *parser);
PangoVariant _gtk_css_font_variant_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_font_weight_value_new (PangoWeight weight);
GtkCssValue * gtk_css_font_weight_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_font_weight_value_try_parse (GtkCssParser *parser);
PangoWeight _gtk_css_font_weight_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_font_stretch_value_new (PangoStretch stretch);
GtkCssValue * gtk_css_font_stretch_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_font_stretch_value_try_parse (GtkCssParser *parser);
PangoStretch _gtk_css_font_stretch_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line);
GtkCssValue * gtk_css_text_decoration_line_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_text_decoration_line_value_try_parse (GtkCssParser *parser);
GtkTextDecorationLine _gtk_css_text_decoration_line_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_text_decoration_style_value_new (GtkTextDecorationStyle style);
GtkCssValue * gtk_css_text_decoration_style_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_text_decoration_style_value_try_parse (GtkCssParser *parser);
GtkTextDecorationStyle _gtk_css_text_decoration_style_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_area_value_new (GtkCssArea area);
GtkCssValue * gtk_css_area_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_area_value_try_parse (GtkCssParser *parser);
GtkCssArea _gtk_css_area_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_direction_value_new (GtkCssDirection direction);
GtkCssValue * gtk_css_direction_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_direction_value_try_parse (GtkCssParser *parser);
GtkCssDirection _gtk_css_direction_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_play_state_value_new (GtkCssPlayState play_state);
GtkCssValue * gtk_css_play_state_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_play_state_value_try_parse (GtkCssParser *parser);
GtkCssPlayState _gtk_css_play_state_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_fill_mode_value_new (GtkCssFillMode fill_mode);
GtkCssValue * gtk_css_fill_mode_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_fill_mode_value_try_parse (GtkCssParser *parser);
GtkCssFillMode _gtk_css_fill_mode_value_get (const GtkCssValue *value);
GtkCssValue * _gtk_css_icon_effect_value_new (GtkCssIconEffect image_effect);
GtkCssValue * gtk_css_icon_effect_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_icon_effect_value_try_parse (GtkCssParser *parser);
GtkCssIconEffect _gtk_css_icon_effect_value_get (const GtkCssValue *value);
void gtk_css_icon_effect_apply (GtkCssIconEffect icon_effect,
cairo_surface_t *surface);
GtkCssValue * _gtk_css_icon_style_value_new (GtkCssIconStyle icon_style);
GtkCssValue * gtk_css_icon_style_value_from_token (const GtkCssToken *token);
GtkCssValue * _gtk_css_icon_style_value_try_parse (GtkCssParser *parser);
GtkCssIconStyle _gtk_css_icon_style_value_get (const GtkCssValue *value);

View File

@@ -162,6 +162,32 @@ gtk_css_icon_theme_value_parse (GtkCssParser *parser)
return result;
}
GtkCssValue *
gtk_css_icon_theme_value_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_STRING))
{
GtkIconTheme *icontheme;
GtkCssValue *value;
icontheme = gtk_icon_theme_new ();
gtk_icon_theme_set_custom_theme (icontheme, token->string.string);
value = gtk_css_icon_theme_value_new (icontheme);
g_object_unref (icontheme);
gtk_css_token_source_consume_token (source);
return value;
}
else
{
gtk_css_token_source_error (source, "Expected a string");
gtk_css_token_source_consume_all (source);
return NULL;
}
}
GtkIconTheme *
gtk_css_icon_theme_value_get_icon_theme (GtkCssValue *value)
{

View File

@@ -23,6 +23,7 @@
#include "gtkicontheme.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -30,6 +31,7 @@ G_BEGIN_DECLS
GtkCssValue * gtk_css_icon_theme_value_new (GtkIconTheme *icontheme);
GtkCssValue * gtk_css_icon_theme_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_icon_theme_value_token_parse (GtkCssTokenSource *source);
GtkIconTheme * gtk_css_icon_theme_value_get_icon_theme (GtkCssValue *value);

View File

@@ -410,26 +410,27 @@ _gtk_css_image_get_surface (GtkCssImage *image,
return result;
}
static const struct {
const char *prefix;
GType (* type_func) (void);
} image_types[] = {
{ "url", _gtk_css_image_url_get_type },
{ "-gtk-gradient", _gtk_css_image_gradient_get_type },
{ "-gtk-icontheme", _gtk_css_image_icon_theme_get_type },
{ "-gtk-scaled", _gtk_css_image_scaled_get_type },
{ "-gtk-recolor", _gtk_css_image_recolor_get_type },
{ "-gtk-win32-theme-part", _gtk_css_image_win32_get_type },
{ "linear-gradient", _gtk_css_image_linear_get_type },
{ "repeating-linear-gradient", _gtk_css_image_linear_get_type },
{ "radial-gradient", _gtk_css_image_radial_get_type },
{ "repeating-radial-gradient", _gtk_css_image_radial_get_type },
{ "cross-fade", _gtk_css_image_cross_fade_get_type },
{ "image", _gtk_css_image_fallback_get_type }
};
static GType
gtk_css_image_get_parser_type (GtkCssParser *parser)
{
static const struct {
const char *prefix;
GType (* type_func) (void);
} image_types[] = {
{ "url", _gtk_css_image_url_get_type },
{ "-gtk-gradient", _gtk_css_image_gradient_get_type },
{ "-gtk-icontheme", _gtk_css_image_icon_theme_get_type },
{ "-gtk-scaled", _gtk_css_image_scaled_get_type },
{ "-gtk-recolor", _gtk_css_image_recolor_get_type },
{ "-gtk-win32-theme-part", _gtk_css_image_win32_get_type },
{ "linear-gradient", _gtk_css_image_linear_get_type },
{ "repeating-linear-gradient", _gtk_css_image_linear_get_type },
{ "radial-gradient", _gtk_css_image_radial_get_type },
{ "repeating-radial-gradient", _gtk_css_image_radial_get_type },
{ "cross-fade", _gtk_css_image_cross_fade_get_type },
{ "image", _gtk_css_image_fallback_get_type }
};
guint i;
for (i = 0; i < G_N_ELEMENTS (image_types); i++)
@@ -486,3 +487,57 @@ _gtk_css_image_new_parse (GtkCssParser *parser)
return image;
}
static GType
gtk_css_image_get_type_from_token (const GtkCssToken *token)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (image_types); i++)
{
if (gtk_css_token_is_function (token, image_types[i].prefix))
return image_types[i].type_func ();
}
if (gtk_css_token_is (token, GTK_CSS_TOKEN_URL))
return _gtk_css_image_url_get_type ();
return G_TYPE_INVALID;
}
gboolean
gtk_css_image_check_token (const GtkCssToken *token)
{
return gtk_css_image_get_type_from_token (token) != G_TYPE_INVALID;
}
GtkCssImage *
gtk_css_image_new_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token;
GtkCssImageClass *klass;
GtkCssImage *image;
GType image_type;
g_return_val_if_fail (source != NULL, NULL);
token = gtk_css_token_source_get_token (source);
image_type = gtk_css_image_get_type_from_token (token);
if (image_type == G_TYPE_INVALID)
{
gtk_css_token_source_error (source, "Not a valid image");
gtk_css_token_source_consume_all (source);
return NULL;
}
image = g_object_new (image_type, NULL);
klass = GTK_CSS_IMAGE_GET_CLASS (image);
if (!klass->token_parse (image, source))
{
g_object_unref (image);
return NULL;
}
return image;
}

View File

@@ -794,6 +794,24 @@ gtk_css_image_builtin_parse (GtkCssImage *image,
return TRUE;
}
static gboolean
gtk_css_image_builtin_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_ident (token, "builtin"))
{
gtk_css_token_source_error (source, "Expected 'builtin'");
gtk_css_token_source_consume_all (source);
return FALSE;
}
gtk_css_token_source_consume_token (source);
return TRUE;
}
static void
gtk_css_image_builtin_print (GtkCssImage *image,
GString *string)
@@ -864,6 +882,7 @@ gtk_css_image_builtin_class_init (GtkCssImageBuiltinClass *klass)
image_class->draw = gtk_css_image_builtin_real_draw;
image_class->parse = gtk_css_image_builtin_parse;
image_class->token_parse = gtk_css_image_builtin_token_parse;
image_class->print = gtk_css_image_builtin_print;
image_class->compute = gtk_css_image_builtin_compute;
image_class->equal = gtk_css_image_builtin_equal;

View File

@@ -203,6 +203,101 @@ gtk_css_image_cross_fade_parse (GtkCssImage *image,
return TRUE;
}
static gboolean
gtk_css_image_cross_fade_parse_progress (GtkCssTokenSource *source,
gboolean *parsed_something,
double *progress)
{
const GtkCssToken *token;
GtkCssValue *value;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_number_value_check_token (token))
{
*parsed_something = FALSE;
return TRUE;
}
*parsed_something = TRUE;
value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_PERCENT | GTK_CSS_POSITIVE_ONLY);
if (value == NULL)
return FALSE;
*progress = _gtk_css_number_value_get (value, 1.0);
_gtk_css_value_unref (value);
if (*progress < 0.0 || *progress > 1.0)
{
gtk_css_token_source_error (source, "Percentage must be between 0%% and 100%%");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return TRUE;
}
static guint
gtk_css_image_cross_fade_token_parse_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageCrossFade *cross_fade = data;
if (arg == 0)
{
gboolean has_percentage = FALSE;
if (!gtk_css_image_cross_fade_parse_progress (source, &has_percentage, &cross_fade->progress))
return 0;
cross_fade->end = gtk_css_image_new_token_parse (source);
if (cross_fade->end == NULL)
return 0;
if (!has_percentage &&
!gtk_css_image_cross_fade_parse_progress (source, &has_percentage, &cross_fade->progress))
return 0;
if (!has_percentage)
cross_fade->progress = 0.5;
return 1;
}
else if (arg == 1)
{
/* XXX: allow parsing colors here */
cross_fade->start = gtk_css_image_new_token_parse (source);
if (cross_fade->start == NULL)
return 0;
return 1;
}
else
{
g_assert_not_reached ();
return 0;
}
}
static gboolean
gtk_css_image_cross_fade_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "cross-fade"))
{
gtk_css_token_source_error (source, "Expected 'cross-fade('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source,
2, 2,
gtk_css_image_cross_fade_token_parse_argument,
image);
}
static void
gtk_css_image_cross_fade_print (GtkCssImage *image,
GString *string)
@@ -249,6 +344,7 @@ _gtk_css_image_cross_fade_class_init (GtkCssImageCrossFadeClass *klass)
image_class->equal = gtk_css_image_cross_fade_equal;
image_class->draw = gtk_css_image_cross_fade_draw;
image_class->parse = gtk_css_image_cross_fade_parse;
image_class->token_parse = gtk_css_image_cross_fade_token_parse;
image_class->print = gtk_css_image_cross_fade_print;
object_class->dispose = gtk_css_image_cross_fade_dispose;

View File

@@ -231,6 +231,64 @@ gtk_css_image_fallback_parse (GtkCssImage *image,
return TRUE;
}
static guint
gtk_css_image_fallback_token_parse_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageFallback *fallback = GTK_CSS_IMAGE_FALLBACK (data);
const GtkCssToken *token;
if (fallback->color)
{
gtk_css_token_source_error (source, "Color argument must be last argument");
return 0;
}
token = gtk_css_token_source_get_token (source);
if (gtk_css_color_value_check_token (token))
{
fallback->color = gtk_css_color_value_token_parse (source);
if (fallback->color == NULL)
return 0;
return 1;
}
else
{
GtkCssImage *image;
image = gtk_css_image_new_token_parse (source);
if (image == NULL)
return 0;
fallback->images = g_realloc (fallback->images, (fallback->n_images + 1) * sizeof (GtkCssImage *));
fallback->images[fallback->n_images] = image;
fallback->n_images++;
return 1;
}
}
static gboolean
gtk_css_image_fallback_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "image"))
{
gtk_css_token_source_error (source, "Expected 'image('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source,
1, G_MAXUINT,
gtk_css_image_fallback_token_parse_argument,
image);
}
static void
_gtk_css_image_fallback_class_init (GtkCssImageFallbackClass *klass)
{
@@ -242,6 +300,7 @@ _gtk_css_image_fallback_class_init (GtkCssImageFallbackClass *klass)
image_class->get_aspect_ratio = gtk_css_image_fallback_get_aspect_ratio;
image_class->draw = gtk_css_image_fallback_draw;
image_class->parse = gtk_css_image_fallback_parse;
image_class->token_parse = gtk_css_image_fallback_token_parse;
image_class->compute = gtk_css_image_fallback_compute;
image_class->print = gtk_css_image_fallback_print;

View File

@@ -263,6 +263,17 @@ gtk_css_image_gradient_parse (GtkCssImage *image,
return gradient->gradient != NULL;
}
static gboolean
gtk_css_image_gradient_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
GtkCssImageGradient *gradient = GTK_CSS_IMAGE_GRADIENT (image);
gradient->gradient = gtk_gradient_token_parse (source);
return gradient->gradient != NULL;
}
static void
gtk_css_image_gradient_print (GtkCssImage *image,
GString *string)
@@ -304,6 +315,7 @@ _gtk_css_image_gradient_class_init (GtkCssImageGradientClass *klass)
image_class->transition = gtk_css_image_gradient_transition;
image_class->draw = gtk_css_image_gradient_draw;
image_class->parse = gtk_css_image_gradient_parse;
image_class->token_parse = gtk_css_image_gradient_token_parse;
image_class->print = gtk_css_image_gradient_print;
object_class->dispose = gtk_css_image_gradient_dispose;
@@ -505,3 +517,32 @@ _gtk_gradient_parse (GtkCssParser *parser)
return gradient;
}
static void
forward_error_to_source (GtkCssParser *parser,
const GError *error,
gpointer source)
{
/* XXX: This is bad because it doesn't emit the error on the right token */
gtk_css_token_source_emit_error (source, error);
}
GtkGradient *
gtk_gradient_token_parse (GtkCssTokenSource *source)
{
GtkCssParser *parser;
GtkGradient *gradient;
char *str;
str = gtk_css_token_source_consume_to_string (source);
parser = _gtk_css_parser_new (str,
NULL,
forward_error_to_source,
source);
gradient = _gtk_gradient_parse (parser);
_gtk_css_parser_free (parser);
g_free (str);
return gradient;
}

View File

@@ -52,7 +52,8 @@ struct _GtkCssImageGradientClass
GType _gtk_css_image_gradient_get_type (void) G_GNUC_CONST;
/* for lack of a better place to put it */
GtkGradient * _gtk_gradient_parse (GtkCssParser *parser);
GtkGradient * _gtk_gradient_parse (GtkCssParser *parser);
GtkGradient * gtk_gradient_token_parse (GtkCssTokenSource *source);
G_END_DECLS

View File

@@ -117,6 +117,45 @@ gtk_css_image_icon_theme_parse (GtkCssImage *image,
return TRUE;
}
static guint
token_parse_arg (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageIconTheme *icon_theme = data;
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_STRING))
{
gtk_css_token_source_error (source, "Expected a string for the icon name");
gtk_css_token_source_consume_all (source);
return 0;
}
icon_theme->name = g_strdup (token->string.string);
gtk_css_token_source_consume_token (source);
return 1;
}
static gboolean
gtk_css_image_icon_theme_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "-gtk-icontheme"))
{
gtk_css_token_source_error (source, "Expected '-gtk-icontheme('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source, 1, 1, token_parse_arg, image);
}
static void
gtk_css_image_icon_theme_print (GtkCssImage *image,
GString *string)
@@ -177,6 +216,7 @@ _gtk_css_image_icon_theme_class_init (GtkCssImageIconThemeClass *klass)
image_class->get_aspect_ratio = gtk_css_image_icon_theme_get_aspect_ratio;
image_class->draw = gtk_css_image_icon_theme_draw;
image_class->parse = gtk_css_image_icon_theme_parse;
image_class->token_parse = gtk_css_image_icon_theme_token_parse;
image_class->print = gtk_css_image_icon_theme_print;
image_class->compute = gtk_css_image_icon_theme_compute;
image_class->equal = gtk_css_image_icon_theme_equal;

View File

@@ -361,6 +361,130 @@ gtk_css_image_linear_parse (GtkCssImage *image,
return TRUE;
}
static guint
gtk_css_image_linear_token_parse_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageLinear *linear = data;
GtkCssImageLinearColorStop stop;
const GtkCssToken *token;
if (arg == 0)
{
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "to"))
{
static const struct {
const char *name;
guint value;
guint optional_index[2];
} sides[] = {
{ "top", 1 << GTK_CSS_TOP, { 2, 3 } },
{ "bottom", 1 << GTK_CSS_BOTTOM, { 2, 3 } },
{ "left", 1 << GTK_CSS_LEFT, { 0, 1 } },
{ "right", 1 << GTK_CSS_RIGHT, { 0, 1 } }
};
guint i, j;
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
for (i = 0; i < G_N_ELEMENTS (sides); i++)
{
if (!gtk_css_token_is_ident (token, sides[i].name))
continue;
linear->side = sides[i].value;
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
for (j = 0; j < G_N_ELEMENTS (sides[i].optional_index); j++)
{
guint idx = sides[i].optional_index[j];
if (!gtk_css_token_is_ident (token, sides[idx].name))
continue;
linear->side = sides[idx].value;
gtk_css_token_source_consume_token (source);
break;
}
return 1;
}
gtk_css_token_source_error (source, "Expected a direction");
gtk_css_token_source_consume_all (source);
return 0;
}
else if (!gtk_css_color_value_check_token (token))
{
/* We check for !color here so the error message is "expected angle"
* for nonsense values */
linear->angle = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE);
if (linear->angle == NULL)
return 0;
return 1;
}
linear->side = 1 << GTK_CSS_BOTTOM;
}
stop.color = gtk_css_color_value_token_parse (source);
if (stop.color == NULL)
return 0;
token = gtk_css_token_source_get_token (source);
if (gtk_css_number_value_check_token (token))
{
stop.offset = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH);
if (stop.offset == NULL)
{
_gtk_css_value_unref (stop.color);
return FALSE;
}
}
else
{
stop.offset = NULL;
}
g_array_append_val (linear->stops, stop);
/* We consume the optional side argument here, too. */
return arg == 0 ? 2 : 1;
}
static gboolean
gtk_css_image_linear_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_function (token, "linear-gradient"))
{
/* nothing to do here */
}
else if (gtk_css_token_is_function (token, "repeating-linear-gradient"))
{
linear->repeating = TRUE;
}
else
{
gtk_css_token_source_error (source, "Expected 'linear-gradient('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source,
3, G_MAXUINT,
gtk_css_image_linear_token_parse_argument,
image);
}
static void
gtk_css_image_linear_print (GtkCssImage *image,
GString *string)
@@ -598,6 +722,7 @@ _gtk_css_image_linear_class_init (GtkCssImageLinearClass *klass)
image_class->draw = gtk_css_image_linear_draw;
image_class->parse = gtk_css_image_linear_parse;
image_class->token_parse = gtk_css_image_linear_token_parse;
image_class->print = gtk_css_image_linear_print;
image_class->compute = gtk_css_image_linear_compute;
image_class->equal = gtk_css_image_linear_equal;

View File

@@ -24,6 +24,7 @@
#include <glib-object.h>
#include "gtk/gtkcssparserprivate.h"
#include "gtk/gtkcsstokensourceprivate.h"
#include "gtk/gtkcsstypesprivate.h"
G_BEGIN_DECLS
@@ -77,6 +78,9 @@ struct _GtkCssImageClass
/* parse CSS, return TRUE on success */
gboolean (* parse) (GtkCssImage *image,
GtkCssParser *parser);
/* parse CSS, return TRUE on success */
gboolean (* token_parse) (GtkCssImage *image,
GtkCssTokenSource *source);
/* print to CSS */
void (* print) (GtkCssImage *image,
GString *string);
@@ -86,6 +90,8 @@ GType _gtk_css_image_get_type (void) G_GNUC_CONST;
gboolean _gtk_css_image_can_parse (GtkCssParser *parser);
GtkCssImage * _gtk_css_image_new_parse (GtkCssParser *parser);
gboolean gtk_css_image_check_token (const GtkCssToken *token);
GtkCssImage * gtk_css_image_new_token_parse (GtkCssTokenSource *source);
int _gtk_css_image_get_width (GtkCssImage *image);
int _gtk_css_image_get_height (GtkCssImage *image);

View File

@@ -386,6 +386,210 @@ gtk_css_image_radial_parse (GtkCssImage *image,
return TRUE;
}
static gboolean
gtk_css_image_radial_token_parse_size (GtkCssImageRadial *radial,
GtkCssTokenSource *source,
gboolean *shape_is_known,
gboolean *has_size)
{
static const struct {
const char *name;
guint value;
} names[] = {
{ "closest-side", GTK_CSS_CLOSEST_SIDE },
{ "farthest-side", GTK_CSS_FARTHEST_SIDE },
{ "closest-corner", GTK_CSS_CLOSEST_CORNER },
{ "farthest-corner", GTK_CSS_FARTHEST_CORNER }
};
const GtkCssToken *token;
guint i;
token = gtk_css_token_source_get_token (source);
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
if (gtk_css_token_is_ident (token, names[i].name))
{
radial->size = names[i].value;
gtk_css_token_source_consume_token (source);
*has_size = TRUE;
return TRUE;
}
}
if (!gtk_css_number_value_check_token (token))
{
radial->size = GTK_CSS_FARTHEST_CORNER;
return TRUE;
}
*has_size = TRUE;
radial->sizes[0] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH |
(!*shape_is_known || !radial->circle ? GTK_CSS_PARSE_PERCENT : 0));
if (radial->sizes[0] == NULL)
return FALSE;
if (gtk_css_number_value_has_percent (radial->sizes[0]))
{
*shape_is_known = TRUE;
radial->circle = FALSE;
}
if (!*shape_is_known)
{
*shape_is_known = TRUE;
token = gtk_css_token_source_get_token (source);
radial->circle = !gtk_css_number_value_check_token (token);
}
if (radial->circle)
return TRUE;
radial->sizes[1] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH | GTK_CSS_PARSE_PERCENT);
if (radial->sizes[1] == NULL)
return FALSE;
return TRUE;
}
static guint
gtk_css_image_radial_token_parse_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageRadial *radial = data;
GtkCssImageRadialColorStop stop;
const GtkCssToken *token;
if (arg == 0)
{
gboolean has_shape = FALSE, shape_is_known = FALSE, has_size = FALSE;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "ellipse"))
{
shape_is_known = has_shape = TRUE;
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "circle"))
{
radial->circle = TRUE;
shape_is_known = has_shape = TRUE;
gtk_css_token_source_consume_token (source);
}
if (!gtk_css_image_radial_token_parse_size (radial, source, &shape_is_known, &has_size))
return 0;
if (!has_shape)
{
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "ellipse"))
{
if (shape_is_known && radial->circle)
{
gtk_css_token_source_error (source, "Specified size not allowed for ellipse");
gtk_css_token_source_consume_all (source);
return 0;
}
shape_is_known = TRUE;
has_shape = TRUE;
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "circle"))
{
if (shape_is_known && !radial->circle)
{
gtk_css_token_source_error (source, "Specified size not allowed for circle");
gtk_css_token_source_consume_all (source);
return 0;
}
radial->circle = TRUE;
shape_is_known = TRUE;
has_shape = TRUE;
gtk_css_token_source_consume_token (source);
}
}
if (!shape_is_known)
{
g_assert (radial->size != GTK_CSS_EXPLICIT_SIZE);
radial->circle = TRUE;
}
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "at"))
{
gtk_css_token_source_consume_token (source);
radial->position = gtk_css_position_value_token_parse (source);
if (radial->position == NULL)
return 0;
return 1;
}
else
{
radial->position = _gtk_css_position_value_new (_gtk_css_number_value_new (50, GTK_CSS_PERCENT),
_gtk_css_number_value_new (50, GTK_CSS_PERCENT));
}
if (has_shape || has_size)
return 1;
}
stop.color = gtk_css_color_value_token_parse (source);
if (stop.color == NULL)
return 0;
token = gtk_css_token_source_get_token (source);
if (gtk_css_number_value_check_token (token))
{
stop.offset = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_PERCENT
| GTK_CSS_PARSE_LENGTH);
if (stop.offset == NULL)
{
_gtk_css_value_unref (stop.color);
return FALSE;
}
}
else
{
stop.offset = NULL;
}
g_array_append_val (radial->stops, stop);
/* We consume the optional side argument here, too. */
return arg == 0 ? 2 : 1;
}
static gboolean
gtk_css_image_radial_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
GtkCssImageRadial *radial = GTK_CSS_IMAGE_RADIAL (image);
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_function (token, "radial-gradient"))
{
/* nothing to do here */
}
else if (gtk_css_token_is_function (token, "repeating-radial-gradient"))
{
radial->repeating = TRUE;
}
else
{
gtk_css_token_source_error (source, "Expected 'radial-gradient('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source,
3, G_MAXUINT,
gtk_css_image_radial_token_parse_argument,
image);
}
static void
gtk_css_image_radial_print (GtkCssImage *image,
GString *string)
@@ -662,6 +866,7 @@ _gtk_css_image_radial_class_init (GtkCssImageRadialClass *klass)
image_class->draw = gtk_css_image_radial_draw;
image_class->parse = gtk_css_image_radial_parse;
image_class->token_parse = gtk_css_image_radial_token_parse;
image_class->print = gtk_css_image_radial_print;
image_class->compute = gtk_css_image_radial_compute;
image_class->transition = gtk_css_image_radial_transition;

View File

@@ -227,6 +227,55 @@ gtk_css_image_recolor_parse (GtkCssImage *image,
return TRUE;
}
static guint
gtk_css_image_recolor_token_parse_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageRecolor *recolor = GTK_CSS_IMAGE_RECOLOR (data);
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (data);
if (arg == 0)
{
url->file = gtk_css_token_source_consume_url (source);
if (url->file == NULL)
return 0;
}
else if (arg == 1)
{
recolor->palette = gtk_css_palette_value_token_parse (source);
if (recolor->palette == NULL)
return 0;
}
else
{
g_assert_not_reached ();
return 0;
}
return 1;
}
static gboolean
gtk_css_image_recolor_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "-gtk-recolor"))
{
gtk_css_token_source_error (source, "Expected '-gtk-recolor('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source,
1, 2,
gtk_css_image_recolor_token_parse_argument,
image);
}
static void
_gtk_css_image_recolor_class_init (GtkCssImageRecolorClass *klass)
{
@@ -234,6 +283,7 @@ _gtk_css_image_recolor_class_init (GtkCssImageRecolorClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
image_class->parse = gtk_css_image_recolor_parse;
image_class->token_parse = gtk_css_image_recolor_token_parse;
image_class->compute = gtk_css_image_recolor_compute;
image_class->print = gtk_css_image_recolor_print;

View File

@@ -180,6 +180,53 @@ gtk_css_image_scaled_parse (GtkCssImage *image,
return TRUE;
}
static guint
token_parse_arg (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GPtrArray *images = data;
GtkCssImage *image;
image = gtk_css_image_new_token_parse (source);
if (image == NULL)
return 0;
g_ptr_array_add (images, image);
return 1;
}
static gboolean
gtk_css_image_scaled_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
const GtkCssToken *token;
GPtrArray *images;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "-gtk-scaled"))
{
gtk_css_token_source_error (source, "Expected '-gtk-scaled('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
images = g_ptr_array_new_with_free_func (g_object_unref);
if (!gtk_css_token_source_consume_function (source, 1, G_MAXUINT, token_parse_arg, images))
{
g_ptr_array_free (images, TRUE);
return FALSE;
}
scaled->n_images = images->len;
scaled->images = (GtkCssImage **) g_ptr_array_free (images, FALSE);
return TRUE;
}
static void
_gtk_css_image_scaled_class_init (GtkCssImageScaledClass *klass)
{
@@ -191,6 +238,7 @@ _gtk_css_image_scaled_class_init (GtkCssImageScaledClass *klass)
image_class->get_aspect_ratio = gtk_css_image_scaled_get_aspect_ratio;
image_class->draw = gtk_css_image_scaled_draw;
image_class->parse = gtk_css_image_scaled_parse;
image_class->token_parse = gtk_css_image_scaled_token_parse;
image_class->compute = gtk_css_image_scaled_compute;
image_class->print = gtk_css_image_scaled_print;

View File

@@ -163,6 +163,19 @@ gtk_css_image_url_parse (GtkCssImage *image,
return TRUE;
}
static gboolean
gtk_css_image_url_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
url->file = gtk_css_token_source_consume_url (source);
if (url->file == NULL)
return FALSE;
return TRUE;
}
static void
gtk_css_image_url_print (GtkCssImage *image,
GString *string)
@@ -195,6 +208,7 @@ _gtk_css_image_url_class_init (GtkCssImageUrlClass *klass)
image_class->compute = gtk_css_image_url_compute;
image_class->draw = gtk_css_image_url_draw;
image_class->parse = gtk_css_image_url_parse;
image_class->token_parse = gtk_css_image_url_token_parse;
image_class->print = gtk_css_image_url_print;
object_class->dispose = gtk_css_image_url_dispose;

View File

@@ -22,6 +22,7 @@
#include "gtkcssimagewin32private.h"
#include "gtkcssprovider.h"
#include "gtkcssnumbervalueprivate.h"
G_DEFINE_TYPE (GtkCssImageWin32, _gtk_css_image_win32, GTK_TYPE_CSS_IMAGE)
@@ -212,6 +213,134 @@ gtk_css_image_win32_parse (GtkCssImage *image,
return TRUE;
}
static guint
gtk_css_image_win32_token_parse_over_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (data);
if (arg == 0)
{
if (!gtk_css_token_source_consume_integer (source, &wimage->part2))
return 0;
return 1;
}
else if (arg == 1)
{
if (!gtk_css_token_source_consume_integer (source, &wimage->state2))
return 0;
return 1;
}
else if (arg == 2)
{
if (!gtk_css_token_source_consume_number (source, &wimage->over_alpha))
return 0;
return 1;
}
else
{
g_assert_not_reached ();
return 0;
}
}
static guint
gtk_css_image_win32_token_parse_margins_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (data);
guint i;
for (i = 0; i < 4; i++)
{
if (i > 0 && !gtk_css_number_value_check_token (gtk_css_token_source_get_token (source)))
break;
if (!gtk_css_token_source_consume_integer (source, &wimage->margins[i]))
return 0;
}
for (; i < 4; i++)
wimage->margins[i] = wimage->margins[i - 1];
return 1;
}
static guint
gtk_css_image_win32_token_parse_argument (GtkCssTokenSource *source,
guint arg,
gpointer data)
{
GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (data);
if (arg == 0)
{
wimage->theme = gtk_win32_theme_token_parse (source);
if (wimage->theme == NULL)
return 0;
return 1;
}
else if (arg == 1)
{
if (!gtk_css_token_source_consume_integer (source, &wimage->part))
return 0;
return 1;
}
else if (arg == 2)
{
if (!gtk_css_token_source_consume_integer (source, &wimage->state))
return 0;
return 1;
}
else
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_function (token, "over"))
{
return gtk_css_token_source_consume_function (source,
2, 3,
gtk_css_image_win32_token_parse_over_argument,
wimage) ? 1 : 0;
}
else if (gtk_css_token_is_function (token, "margins"))
{
return gtk_css_token_source_consume_function (source,
1, 1,
gtk_css_image_win32_token_parse_margins_argument,
wimage) ? 1 : 0;
}
else
{
gtk_css_token_source_error (source, "Expected over() or margins()");
return 0;
}
}
}
static gboolean
gtk_css_image_win32_token_parse (GtkCssImage *image,
GtkCssTokenSource *source)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is_function (token, "-gtk-win32-theme-part"))
{
gtk_css_token_source_error (source, "Expected '-gtk-win32-theme-part('");
gtk_css_token_source_consume_all (source);
return FALSE;
}
return gtk_css_token_source_consume_function (source,
3, G_MAXUINT,
gtk_css_image_win32_token_parse_argument,
image);
}
static void
gtk_css_image_win32_print (GtkCssImage *image,
GString *string)
@@ -244,6 +373,7 @@ _gtk_css_image_win32_class_init (GtkCssImageWin32Class *klass)
image_class->draw = gtk_css_image_win32_draw;
image_class->parse = gtk_css_image_win32_parse;
image_class->token_parse = gtk_css_image_win32_token_parse;
image_class->print = gtk_css_image_win32_print;
}

192
gtk/gtkcssimportrule.c Normal file
View File

@@ -0,0 +1,192 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssimportruleprivate.h"
#include "gtkcssstylesheetprivate.h"
typedef struct _GtkCssImportRulePrivate GtkCssImportRulePrivate;
struct _GtkCssImportRulePrivate {
GFile *file;
GtkCssStyleSheet *style_sheet;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssImportRule, gtk_css_import_rule, GTK_TYPE_CSS_RULE)
static void
gtk_css_import_rule_finalize (GObject *object)
{
GtkCssImportRule *import_rule = GTK_CSS_IMPORT_RULE (object);
GtkCssImportRulePrivate *priv = gtk_css_import_rule_get_instance_private (import_rule);
if (priv->file)
g_object_unref (priv->file);
if (priv->style_sheet)
g_object_unref (priv->style_sheet);
G_OBJECT_CLASS (gtk_css_import_rule_parent_class)->finalize (object);
}
static void
gtk_css_import_rule_class_init (GtkCssImportRuleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_import_rule_finalize;
}
static void
gtk_css_import_rule_init (GtkCssImportRule *import_rule)
{
}
static GtkCssRule *
gtk_css_import_rule_new (GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
return g_object_new (GTK_TYPE_CSS_IMPORT_RULE,
"parent-rule", parent_rule,
"parent-stylesheet", parent_style_sheet,
NULL);
}
static gboolean
gtk_css_import_rule_would_recurse (GtkCssImportRule *rule)
{
GtkCssImportRulePrivate *priv = gtk_css_import_rule_get_instance_private (GTK_CSS_IMPORT_RULE (rule));
GtkCssStyleSheet *sheet;
for (sheet = gtk_css_rule_get_parent_style_sheet (GTK_CSS_RULE (rule));
sheet != NULL;
sheet = gtk_css_style_sheet_get_parent_style_sheet (sheet))
{
GFile *sheet_file = gtk_css_style_sheet_get_file (sheet);
if (sheet_file && g_file_equal (sheet_file, priv->file))
return TRUE;
}
return FALSE;
}
GtkCssRule *
gtk_css_import_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
GtkCssImportRulePrivate *priv;
const GtkCssToken *token;
GtkCssRule *result;
GtkCssTokenizer *tokenizer;
GtkCssTokenSource *import_source;
GError *load_error = NULL;
GBytes *bytes;
char *data;
gsize size;
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);
result = gtk_css_import_rule_new (parent_rule, parent_style_sheet);
gtk_css_token_source_set_consumer (source, G_OBJECT (result));
priv = gtk_css_import_rule_get_instance_private (GTK_CSS_IMPORT_RULE (result));
token = gtk_css_token_source_get_token (source);
if (token->type != GTK_CSS_TOKEN_AT_KEYWORD ||
g_ascii_strcasecmp (token->string.string, "import") != 0)
{
gtk_css_token_source_error (source, "Expected '@import'");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_STRING))
{
priv->file = gtk_css_token_source_resolve_url (source, token->string.string);
gtk_css_token_source_consume_token (source);
}
else
{
priv->file = gtk_css_token_source_consume_url (source);
if (priv->file == NULL)
{
g_object_unref (result);
return NULL;
}
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_SEMICOLON))
{
gtk_css_token_source_error (source, "Expected ';' at end of @import");
gtk_css_token_source_consume_all (source);
g_object_unref (result);
return NULL;
}
if (gtk_css_import_rule_would_recurse (GTK_CSS_IMPORT_RULE (result)))
{
char *path = g_file_get_path (priv->file);
gtk_css_token_source_error (source,
"Loading '%s' would recurse",
path);
g_object_unref (result);
g_free (path);
bytes = g_bytes_new (NULL, 0);
}
else if (g_file_load_contents (priv->file, NULL,
&data, &size,
NULL, &load_error))
{
bytes = g_bytes_new_take (data, size);
}
else
{
gtk_css_token_source_emit_error (source, load_error);
bytes = g_bytes_new (NULL, 0);
g_error_free (load_error);
}
tokenizer = gtk_css_tokenizer_new (bytes, NULL, NULL, NULL);
import_source = gtk_css_token_source_new_for_tokenizer (tokenizer, priv->file);
priv->style_sheet = gtk_css_style_sheet_new_import (import_source, result);
gtk_css_token_source_unref (import_source);
gtk_css_tokenizer_unref (tokenizer);
gtk_css_token_source_consume_token (source);
return result;
}
GtkCssStyleSheet *
gtk_css_import_rule_get_style_sheet (GtkCssImportRule *rule)
{
GtkCssImportRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_IMPORT_RULE (rule), NULL);
priv = gtk_css_import_rule_get_instance_private (rule);
return priv->style_sheet;
}

View File

@@ -0,0 +1,57 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_IMPORT_RULE_PRIVATE_H__
#define __GTK_CSS_IMPORT_RULE_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_IMPORT_RULE (gtk_css_import_rule_get_type ())
#define GTK_CSS_IMPORT_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMPORT_RULE, GtkCssImportRule))
#define GTK_CSS_IMPORT_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMPORT_RULE, GtkCssImportRuleClass))
#define GTK_IS_CSS_IMPORT_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMPORT_RULE))
#define GTK_IS_CSS_IMPORT_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMPORT_RULE))
#define GTK_CSS_IMPORT_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMPORT_RULE, GtkCssImportRuleClass))
typedef struct _GtkCssImportRule GtkCssImportRule;
typedef struct _GtkCssImportRuleClass GtkCssImportRuleClass;
struct _GtkCssImportRule
{
GtkCssRule parent;
};
struct _GtkCssImportRuleClass
{
GtkCssRuleClass parent_class;
};
GType gtk_css_import_rule_get_type (void) G_GNUC_CONST;
GtkCssRule * gtk_css_import_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
GtkCssStyleSheet * gtk_css_import_rule_get_style_sheet (GtkCssImportRule *rule);
G_END_DECLS
#endif /* __GTK_CSS_IMPORT_RULE_PRIVATE_H__ */

176
gtk/gtkcsskeyframerule.c Normal file
View File

@@ -0,0 +1,176 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#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;
}

View File

@@ -0,0 +1,63 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_KEYFRAME_RULE_PRIVATE_H__
#define __GTK_CSS_KEYFRAME_RULE_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
#include "gtk/gtkcssstyledeclarationprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_KEYFRAME_RULE (gtk_css_keyframe_rule_get_type ())
#define GTK_CSS_KEYFRAME_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_KEYFRAME_RULE, GtkCssKeyframeRule))
#define GTK_CSS_KEYFRAME_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_KEYFRAME_RULE, GtkCssKeyframeRuleClass))
#define GTK_IS_CSS_KEYFRAME_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_KEYFRAME_RULE))
#define GTK_IS_CSS_KEYFRAME_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_KEYFRAME_RULE))
#define GTK_CSS_KEYFRAME_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_KEYFRAME_RULE, GtkCssKeyframeRuleClass))
typedef struct _GtkCssKeyframeRule GtkCssKeyframeRule;
typedef struct _GtkCssKeyframeRuleClass GtkCssKeyframeRuleClass;
struct _GtkCssKeyframeRule
{
GtkCssRule parent;
};
struct _GtkCssKeyframeRuleClass
{
GtkCssRuleClass parent_class;
};
GType gtk_css_keyframe_rule_get_type (void) G_GNUC_CONST;
GtkCssRule * gtk_css_keyframe_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
gsize gtk_css_keyframe_rule_get_n_offsets (GtkCssKeyframeRule *rule);
double gtk_css_keyframe_rule_get_offset (GtkCssKeyframeRule *rule,
gsize id);
GtkCssStyleDeclaration *gtk_css_keyframe_rule_get_style (GtkCssKeyframeRule *rule);
G_END_DECLS
#endif /* __GTK_CSS_KEYFRAME_RULE_PRIVATE_H__ */

View File

@@ -20,8 +20,10 @@
#include "gtkcsskeyframesprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcsskeyframeruleprivate.h"
#include "gtkcsslonghanddeclarationprivate.h"
#include "gtkcssshorthanddeclarationprivate.h"
#include "gtkcssshorthandpropertyprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkstylepropertyprivate.h"
#include <stdlib.h>
@@ -370,6 +372,67 @@ _gtk_css_keyframes_parse (GtkCssParser *parser)
return keyframes;
}
GtkCssKeyframes *
gtk_css_keyframes_new_from_rule (GtkCssKeyframesRule *rule)
{
GtkCssKeyframes *keyframes;
GtkCssRuleList *rules;
guint i, j, k, l;
keyframes = gtk_css_keyframes_new ();
rules = gtk_css_keyframes_rule_get_css_rules (rule);
for (i = 0; i < gtk_css_rule_list_get_length (rules); i++)
{
/* Don't do GTK_CSS_KEYFRAME_RULE() cast here. */
GtkCssKeyframeRule *keyframe = (GtkCssKeyframeRule *) gtk_css_rule_list_get_item (rules, i);
if (!GTK_IS_CSS_KEYFRAME_RULE (keyframe))
continue;
for (j = 0; j < gtk_css_keyframe_rule_get_n_offsets (keyframe); j++)
{
double offset = gtk_css_keyframe_rule_get_offset (keyframe, j) / 100;
GtkCssStyleDeclaration *style;
guint offset_idx;
if (offset < 0 || offset > 1)
continue;
offset_idx = gtk_css_keyframes_add_keyframe (keyframes, offset);
style = gtk_css_keyframe_rule_get_style (keyframe);
for (k = 0; k < gtk_css_style_declaration_get_length (style); k++)
{
GtkCssDeclaration *decl = gtk_css_style_declaration_get_declaration (style, k);
if (GTK_IS_CSS_LONGHAND_DECLARATION (decl))
{
GtkCssLonghandDeclaration *longhand = GTK_CSS_LONGHAND_DECLARATION (decl);
keyframes_set_value (keyframes,
offset_idx,
gtk_css_longhand_declaration_get_property (longhand),
_gtk_css_value_ref (gtk_css_longhand_declaration_get_value (longhand)));
}
else if (GTK_IS_CSS_SHORTHAND_DECLARATION (decl))
{
GtkCssShorthandDeclaration *shorthand = GTK_CSS_SHORTHAND_DECLARATION (decl);
for (l = 0; l < gtk_css_shorthand_declaration_get_length (shorthand); l++)
{
keyframes_set_value (keyframes,
offset_idx,
gtk_css_shorthand_declaration_get_subproperty (shorthand, l),
_gtk_css_value_ref (gtk_css_shorthand_declaration_get_value (shorthand, l)));
}
}
}
}
}
return keyframes;
}
static int
compare_property_by_name (gconstpointer a,
gconstpointer b,

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_KEYFRAMES_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsskeyframesruleprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtktypes.h"
@@ -29,6 +30,7 @@ G_BEGIN_DECLS
typedef struct _GtkCssKeyframes GtkCssKeyframes;
GtkCssKeyframes * _gtk_css_keyframes_parse (GtkCssParser *parser);
GtkCssKeyframes * gtk_css_keyframes_new_from_rule (GtkCssKeyframesRule *rule);
GtkCssKeyframes * _gtk_css_keyframes_ref (GtkCssKeyframes *keyframes);
void _gtk_css_keyframes_unref (GtkCssKeyframes *keyframes);

287
gtk/gtkcsskeyframesrule.c Normal file
View File

@@ -0,0 +1,287 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcsskeyframesruleprivate.h"
#include "gtkcsskeyframeruleprivate.h"
#include "gtkcssstylesheetprivate.h"
typedef struct _GtkCssKeyframesRulePrivate GtkCssKeyframesRulePrivate;
struct _GtkCssKeyframesRulePrivate {
char *name;
GtkCssRuleList *rules;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssKeyframesRule, gtk_css_keyframes_rule, GTK_TYPE_CSS_RULE)
typedef struct _GtkCssTokenSourceKeyframe GtkCssTokenSourceKeyframe;
struct _GtkCssTokenSourceKeyframe {
GtkCssTokenSource parent;
GtkCssTokenSource *source;
GSList *blocks;
gboolean done;
};
static void
gtk_css_token_source_keyframe_finalize (GtkCssTokenSource *source)
{
GtkCssTokenSourceKeyframe *keyframe = (GtkCssTokenSourceKeyframe *) source;
g_slist_free (keyframe->blocks);
gtk_css_token_source_unref (keyframe->source);
}
static void
gtk_css_token_source_keyframe_consume_token (GtkCssTokenSource *source,
GObject *consumer)
{
GtkCssTokenSourceKeyframe *keyframe = (GtkCssTokenSourceKeyframe *) source;
const GtkCssToken *token;
if (keyframe->done)
return;
token = gtk_css_token_source_peek_token (keyframe->source);
switch (token->type)
{
case GTK_CSS_TOKEN_FUNCTION:
case GTK_CSS_TOKEN_OPEN_PARENS:
keyframe->blocks = g_slist_prepend (keyframe->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_PARENS));
break;
case GTK_CSS_TOKEN_OPEN_SQUARE:
keyframe->blocks = g_slist_prepend (keyframe->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_SQUARE));
break;
case GTK_CSS_TOKEN_OPEN_CURLY:
keyframe->blocks = g_slist_prepend (keyframe->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_CURLY));
break;
case GTK_CSS_TOKEN_CLOSE_PARENS:
case GTK_CSS_TOKEN_CLOSE_SQUARE:
case GTK_CSS_TOKEN_CLOSE_CURLY:
if (keyframe->blocks && GPOINTER_TO_UINT (keyframe->blocks->data) == token->type)
keyframe->blocks = g_slist_remove (keyframe->blocks, keyframe->blocks->data);
if (token->type == GTK_CSS_TOKEN_CLOSE_CURLY && keyframe->blocks == NULL)
keyframe->done = TRUE;
break;
default:
break;
}
gtk_css_token_source_consume_token_as (keyframe->source, consumer);
}
const GtkCssToken *
gtk_css_token_source_keyframe_peek_token (GtkCssTokenSource *source)
{
GtkCssTokenSourceKeyframe *keyframe = (GtkCssTokenSourceKeyframe *) source;
static GtkCssToken eof_token = { GTK_CSS_TOKEN_EOF };
if (keyframe->done)
return &eof_token;
return gtk_css_token_source_peek_token (keyframe->source);
}
static void
gtk_css_token_source_keyframe_error (GtkCssTokenSource *source,
const GError *error)
{
GtkCssTokenSourceKeyframe *keyframe = (GtkCssTokenSourceKeyframe *) source;
gtk_css_token_source_emit_error (keyframe->source, error);
}
static GFile *
gtk_css_token_source_keyframe_get_location (GtkCssTokenSource *source)
{
GtkCssTokenSourceKeyframe *keyframe = (GtkCssTokenSourceKeyframe *) source;
return gtk_css_token_source_get_location (keyframe->source);
}
static const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_KEYFRAME = {
gtk_css_token_source_keyframe_finalize,
gtk_css_token_source_keyframe_consume_token,
gtk_css_token_source_keyframe_peek_token,
gtk_css_token_source_keyframe_error,
gtk_css_token_source_keyframe_get_location,
};
static GtkCssTokenSource *
gtk_css_token_source_new_keyframe (GtkCssTokenSource *source)
{
GtkCssTokenSourceKeyframe *keyframe = gtk_css_token_source_new (GtkCssTokenSourceKeyframe, &GTK_CSS_TOKEN_SOURCE_KEYFRAME);
keyframe->source = gtk_css_token_source_ref (source);
gtk_css_token_source_set_consumer (&keyframe->parent,
gtk_css_token_source_get_consumer (source));
return &keyframe->parent;
}
static void
gtk_css_keyframes_rule_finalize (GObject *object)
{
GtkCssKeyframesRule *keyframes_rule = GTK_CSS_KEYFRAMES_RULE (object);
GtkCssKeyframesRulePrivate *priv = gtk_css_keyframes_rule_get_instance_private (keyframes_rule);
g_free (priv->name);
g_object_unref (priv->rules);
G_OBJECT_CLASS (gtk_css_keyframes_rule_parent_class)->finalize (object);
}
static void
gtk_css_keyframes_rule_class_init (GtkCssKeyframesRuleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_keyframes_rule_finalize;
}
static void
gtk_css_keyframes_rule_init (GtkCssKeyframesRule *keyframes_rule)
{
GtkCssKeyframesRulePrivate *priv = gtk_css_keyframes_rule_get_instance_private (keyframes_rule);
priv->rules = gtk_css_rule_list_new ();
}
static void
gtk_css_keyframes_rule_set_name (GtkCssKeyframesRule *keyframes,
const char *name)
{
GtkCssKeyframesRulePrivate *priv;
priv = gtk_css_keyframes_rule_get_instance_private (keyframes);
g_free (priv->name);
priv->name = g_strdup (name);
}
static void
gtk_css_keyframes_rule_append (GtkCssKeyframesRule *keyframes,
GtkCssRule *rule)
{
GtkCssKeyframesRulePrivate *priv;
priv = gtk_css_keyframes_rule_get_instance_private (keyframes);
gtk_css_rule_list_append (priv->rules, rule);
}
static GtkCssRule *
gtk_css_keyframes_rule_new (GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
return g_object_new (GTK_TYPE_CSS_KEYFRAMES_RULE,
"parent-rule", parent_rule,
"parent-stylesheet", parent_style_sheet,
NULL);
}
GtkCssRule *
gtk_css_keyframes_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
const GtkCssToken *token;
GtkCssRule *rule;
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_keyframes_rule_new (parent_rule, parent_style_sheet);
gtk_css_token_source_set_consumer (source, G_OBJECT (rule));
token = gtk_css_token_source_get_token (source);
if (token->type != GTK_CSS_TOKEN_AT_KEYWORD ||
g_ascii_strcasecmp (token->string.string, "keyframes") != 0)
{
gtk_css_token_source_error (source, "Expected '@keyframes'");
gtk_css_token_source_consume_all (source);
g_object_unref (rule);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected name of keyframes");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_keyframes_rule_set_name (GTK_CSS_KEYFRAMES_RULE (rule), token->string.string);
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_OPEN_CURLY))
{
gtk_css_token_source_error (source, "Expected '{'");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
for (token = gtk_css_token_source_get_token (source);
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF) && !gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_CURLY);
token = gtk_css_token_source_get_token (source))
{
GtkCssTokenSource *keyframe_source = gtk_css_token_source_new_keyframe (source);
GtkCssRule *keyframe;
keyframe = gtk_css_keyframe_rule_new_parse (keyframe_source, rule, parent_style_sheet);
if (keyframe)
gtk_css_keyframes_rule_append (GTK_CSS_KEYFRAMES_RULE (rule), keyframe);
gtk_css_token_source_unref (keyframe_source);
}
gtk_css_token_source_consume_token (source);
return rule;
}
const char *
gtk_css_keyframes_rule_get_name (GtkCssKeyframesRule *rule)
{
GtkCssKeyframesRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_KEYFRAMES_RULE (rule), NULL);
priv = gtk_css_keyframes_rule_get_instance_private (rule);
return priv->name;
}
GtkCssRuleList *
gtk_css_keyframes_rule_get_css_rules (GtkCssKeyframesRule *rule)
{
GtkCssKeyframesRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_KEYFRAMES_RULE (rule), NULL);
priv = gtk_css_keyframes_rule_get_instance_private (rule);
return priv->rules;
}

View File

@@ -0,0 +1,59 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_KEYFRAMES_RULE_PRIVATE_H__
#define __GTK_CSS_KEYFRAMES_RULE_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
#include "gtk/gtkcssrulelistprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_KEYFRAMES_RULE (gtk_css_keyframes_rule_get_type ())
#define GTK_CSS_KEYFRAMES_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_KEYFRAMES_RULE, GtkCssKeyframesRule))
#define GTK_CSS_KEYFRAMES_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_KEYFRAMES_RULE, GtkCssKeyframesRuleClass))
#define GTK_IS_CSS_KEYFRAMES_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_KEYFRAMES_RULE))
#define GTK_IS_CSS_KEYFRAMES_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_KEYFRAMES_RULE))
#define GTK_CSS_KEYFRAMES_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_KEYFRAMES_RULE, GtkCssKeyframesRuleClass))
typedef struct _GtkCssKeyframesRule GtkCssKeyframesRule;
typedef struct _GtkCssKeyframesRuleClass GtkCssKeyframesRuleClass;
struct _GtkCssKeyframesRule
{
GtkCssRule parent;
};
struct _GtkCssKeyframesRuleClass
{
GtkCssRuleClass parent_class;
};
GType gtk_css_keyframes_rule_get_type (void) G_GNUC_CONST;
GtkCssRule * gtk_css_keyframes_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
const char * gtk_css_keyframes_rule_get_name (GtkCssKeyframesRule *rule);
GtkCssRuleList * gtk_css_keyframes_rule_get_css_rules (GtkCssKeyframesRule *rule);
G_END_DECLS
#endif /* __GTK_CSS_KEYFRAMES_RULE_PRIVATE_H__ */

View File

@@ -0,0 +1,178 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcsslonghanddeclarationprivate.h"
#include "gtkcssstylepropertyprivate.h"
typedef struct _GtkCssLonghandDeclarationPrivate GtkCssLonghandDeclarationPrivate;
struct _GtkCssLonghandDeclarationPrivate {
GtkCssStyleProperty *prop;
GtkCssValue *value;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssLonghandDeclaration, gtk_css_longhand_declaration, GTK_TYPE_CSS_DECLARATION)
static void
gtk_css_longhand_declaration_finalize (GObject *object)
{
GtkCssLonghandDeclaration *longhand_declaration = GTK_CSS_LONGHAND_DECLARATION (object);
GtkCssLonghandDeclarationPrivate *priv = gtk_css_longhand_declaration_get_instance_private (longhand_declaration);
if (priv->value)
_gtk_css_value_unref (priv->value);
G_OBJECT_CLASS (gtk_css_longhand_declaration_parent_class)->finalize (object);
}
static const char *
gtk_css_longhand_declaration_get_name (GtkCssDeclaration *decl)
{
GtkCssLonghandDeclaration *longhand_declaration = GTK_CSS_LONGHAND_DECLARATION (decl);
GtkCssLonghandDeclarationPrivate *priv = gtk_css_longhand_declaration_get_instance_private (longhand_declaration);
return _gtk_style_property_get_name (GTK_STYLE_PROPERTY (priv->prop));
}
static void
gtk_css_longhand_declaration_print_value (GtkCssDeclaration *decl,
GString *string)
{
GtkCssLonghandDeclaration *longhand_declaration = GTK_CSS_LONGHAND_DECLARATION (decl);
GtkCssLonghandDeclarationPrivate *priv = gtk_css_longhand_declaration_get_instance_private (longhand_declaration);
_gtk_css_value_print (priv->value, string);
}
static void
gtk_css_longhand_declaration_class_init (GtkCssLonghandDeclarationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCssDeclarationClass *decl_class = GTK_CSS_DECLARATION_CLASS (klass);
object_class->finalize = gtk_css_longhand_declaration_finalize;
decl_class->get_name = gtk_css_longhand_declaration_get_name;
decl_class->print_value = gtk_css_longhand_declaration_print_value;
}
static void
gtk_css_longhand_declaration_init (GtkCssLonghandDeclaration *longhand_declaration)
{
}
GtkCssDeclaration *
gtk_css_longhand_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source)
{
GtkCssLonghandDeclarationPrivate *priv;
const GtkCssToken *token;
GtkCssLonghandDeclaration *decl;
char *name;
decl = g_object_new (GTK_TYPE_CSS_LONGHAND_DECLARATION,
"parent-style", style,
NULL);
priv = gtk_css_longhand_declaration_get_instance_private (decl);
gtk_css_token_source_set_consumer (source, G_OBJECT (decl));
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected a property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
name = g_utf8_strdown (token->string.string, -1);
priv->prop = (GtkCssStyleProperty *) _gtk_style_property_lookup (name);
if (!GTK_IS_CSS_STYLE_PROPERTY (priv->prop))
{
gtk_css_token_source_unknown (source, "Property name '%s' is not a CSS property", token->string.string);
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
g_free (name);
return NULL;
}
else if (!g_str_equal (name, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (priv->prop))))
gtk_css_token_source_deprecated (source,
"The '%s' property has been renamed to '%s'",
name, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (priv->prop)));
gtk_css_token_source_consume_token (source);
g_free (name);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
gtk_css_token_source_error (source, "No colon following property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
gtk_css_token_source_consume_token (source);
priv->value = gtk_style_property_token_parse (GTK_STYLE_PROPERTY (priv->prop), source);
if (priv->value == NULL)
{
g_object_unref (decl);
return NULL;
}
return GTK_CSS_DECLARATION (decl);
}
guint
gtk_css_longhand_declaration_get_id (GtkCssLonghandDeclaration *decl)
{
GtkCssLonghandDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_LONGHAND_DECLARATION (decl), 0);
priv = gtk_css_longhand_declaration_get_instance_private (decl);
return _gtk_css_style_property_get_id (priv->prop);
}
GtkCssStyleProperty *
gtk_css_longhand_declaration_get_property (GtkCssLonghandDeclaration *decl)
{
GtkCssLonghandDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_LONGHAND_DECLARATION (decl), 0);
priv = gtk_css_longhand_declaration_get_instance_private (decl);
return priv->prop;
}
GtkCssValue *
gtk_css_longhand_declaration_get_value (GtkCssLonghandDeclaration *decl)
{
GtkCssLonghandDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_LONGHAND_DECLARATION (decl), NULL);
priv = gtk_css_longhand_declaration_get_instance_private (decl);
return priv->value;
}

View File

@@ -0,0 +1,62 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_LONGHAND_DECLARATION_PRIVATE_H__
#define __GTK_CSS_LONGHAND_DECLARATION_PRIVATE_H__
#include "gtk/gtkcssdeclarationprivate.h"
#include "gtk/gtkcssstylepropertyprivate.h"
#include "gtk/gtkcssvalueprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_LONGHAND_DECLARATION (gtk_css_longhand_declaration_get_type ())
#define GTK_CSS_LONGHAND_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_LONGHAND_DECLARATION, GtkCssLonghandDeclaration))
#define GTK_CSS_LONGHAND_DECLARATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_LONGHAND_DECLARATION, GtkCssLonghandDeclarationClass))
#define GTK_IS_CSS_LONGHAND_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_LONGHAND_DECLARATION))
#define GTK_IS_CSS_LONGHAND_DECLARATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_LONGHAND_DECLARATION))
#define GTK_CSS_LONGHAND_DECLARATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_LONGHAND_DECLARATION, GtkCssLonghandDeclarationClass))
typedef struct _GtkCssLonghandDeclaration GtkCssLonghandDeclaration;
typedef struct _GtkCssLonghandDeclarationClass GtkCssLonghandDeclarationClass;
struct _GtkCssLonghandDeclaration
{
GtkCssDeclaration parent;
};
struct _GtkCssLonghandDeclarationClass
{
GtkCssDeclarationClass parent_class;
};
GType gtk_css_longhand_declaration_get_type (void) G_GNUC_CONST;
GtkCssDeclaration * gtk_css_longhand_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source);
guint gtk_css_longhand_declaration_get_id (GtkCssLonghandDeclaration *decl);
GtkCssStyleProperty * gtk_css_longhand_declaration_get_property (GtkCssLonghandDeclaration *decl);
GtkCssValue * gtk_css_longhand_declaration_get_value (GtkCssLonghandDeclaration *decl);
G_END_DECLS
#endif /* __GTK_CSS_LONGHAND_DECLARATION_PRIVATE_H__ */

View File

@@ -158,6 +158,47 @@ _gtk_css_number_value_parse (GtkCssParser *parser,
return gtk_css_dimension_value_parse (parser, flags);
}
gboolean
gtk_css_number_value_check_token (const GtkCssToken *token)
{
return gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_DIMENSION)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)
|| gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE)
|| gtk_css_token_is_function (token, "calc")
|| gtk_css_token_is_function (token, "-gtk-win32-size")
|| gtk_css_token_is_function (token, "-gtk-win32-part-width")
|| gtk_css_token_is_function (token, "-gtk-win32-part-height")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-top")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-left")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-bottom")
|| gtk_css_token_is_function (token, "-gtk-win32-part-border-right");
}
GtkCssValue *
gtk_css_number_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
const GtkCssToken *token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_function (token, "calc"))
return gtk_css_calc_value_token_parse (source, flags);
else if (gtk_css_token_is_function (token, "-gtk-win32-size") ||
gtk_css_token_is_function (token, "-gtk-win32-part-width") ||
gtk_css_token_is_function (token, "-gtk-win32-part-height") ||
gtk_css_token_is_function (token, "-gtk-win32-part-border-top") ||
gtk_css_token_is_function (token, "-gtk-win32-part-border-left") ||
gtk_css_token_is_function (token, "-gtk-win32-part-border-bottom") ||
gtk_css_token_is_function (token, "-gtk-win32-part-border-right"))
return gtk_css_win32_size_value_token_parse (source, flags);
else
return gtk_css_dimension_value_token_parse (source, flags);
}
double
_gtk_css_number_value_get (const GtkCssValue *number,
double one_hundred_percent)

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_NUMBER_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkcssvalueprivate.h"
@@ -61,6 +62,9 @@ GtkCssValue * gtk_css_number_value_transition (GtkCssValue *sta
gboolean gtk_css_number_value_can_parse (GtkCssParser *parser);
GtkCssValue * _gtk_css_number_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags);
gboolean gtk_css_number_value_check_token (const GtkCssToken *token);
GtkCssValue * gtk_css_number_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags);
GtkCssDimension gtk_css_number_value_get_dimension (const GtkCssValue *value);
gboolean gtk_css_number_value_has_percent (const GtkCssValue *value);

View File

@@ -242,6 +242,55 @@ gtk_css_palette_value_parse (GtkCssParser *parser)
return result;
}
GtkCssValue *
gtk_css_palette_value_token_parse (GtkCssTokenSource *source)
{
GtkCssValue *result, *color;
const GtkCssToken *token;
char *ident;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "default"))
{
gtk_css_token_source_consume_token (source);
return gtk_css_palette_value_new_default ();
}
result = gtk_css_palette_value_new_empty ();
while (TRUE)
{
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected color name");
gtk_css_token_source_consume_all (source);
_gtk_css_value_unref (result);
return NULL;
}
ident = g_strdup (token->string.string);
gtk_css_token_source_consume_token (source);
color = gtk_css_color_value_token_parse (source);
if (color == NULL)
{
g_free (ident);
_gtk_css_value_unref (result);
return NULL;
}
gtk_css_palette_value_add_color (result, ident, color);
g_free (ident);
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);
}
return result;
}
const GdkRGBA *
gtk_css_palette_value_get_color (GtkCssValue *value,
const char *name)

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_PALETTE_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -28,6 +29,7 @@ G_BEGIN_DECLS
GtkCssValue * gtk_css_palette_value_new_default (void);
GtkCssValue * gtk_css_palette_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_palette_value_token_parse (GtkCssTokenSource *source);
const GdkRGBA * gtk_css_palette_value_get_color (GtkCssValue *value,
const char *color_name);

View File

@@ -20,6 +20,7 @@
#include "gtkcssparserprivate.h"
#include "gtkcssdimensionvalueprivate.h"
#include "gtkcsstokenizerprivate.h"
#include <errno.h>
#include <string.h>
@@ -46,6 +47,54 @@ struct _GtkCssParser
guint line;
};
#include "gtkcssstylesheetprivate.h"
static void
do_the_tokenizer (const char *data)
{
#if 0
GtkCssTokenizer *tokenizer;
GtkCssToken token;
GBytes *bytes;
bytes = g_bytes_new_static (data, strlen (data));
tokenizer = gtk_css_tokenizer_new (bytes, NULL, NULL, NULL);
g_bytes_unref (bytes);
for (gtk_css_tokenizer_read_token (tokenizer, &token);
token.type != GTK_CSS_TOKEN_EOF;
gtk_css_tokenizer_read_token (tokenizer, &token))
{
char *s = gtk_css_token_to_string (&token);
g_print ("%3zu:%02zu %2d %s\n",
gtk_css_tokenizer_get_line (tokenizer), gtk_css_tokenizer_get_line_char (tokenizer),
token.type, s);
g_free (s);
gtk_css_token_clear (&token);
}
gtk_css_tokenizer_unref (tokenizer);
#else
#if 0
GtkCssStyleSheet *sheet;
GtkCssTokenSource *source;
GtkCssTokenizer *tokenizer;
GBytes *bytes;
bytes = g_bytes_new_static (data, strlen (data));
tokenizer = gtk_css_tokenizer_new (bytes, NULL, NULL, NULL);
source = gtk_css_token_source_new_for_tokenizer (tokenizer);
sheet = gtk_css_style_sheet_new ();
gtk_css_style_sheet_parse (sheet, source);
g_object_unref (sheet);
gtk_css_token_source_unref (source);
gtk_css_tokenizer_unref (tokenizer);
g_bytes_unref (bytes);
#endif
#endif
}
GtkCssParser *
_gtk_css_parser_new (const char *data,
GFile *file,
@@ -57,6 +106,8 @@ _gtk_css_parser_new (const char *data,
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
do_the_tokenizer (data);
parser = g_slice_new0 (GtkCssParser);
parser->data = data;

View File

@@ -291,6 +291,262 @@ _gtk_css_position_value_try_parse (GtkCssParser *parser)
return position_value_parse (parser, TRUE);
}
gboolean
gtk_css_position_value_check_token (const GtkCssToken *token)
{
return gtk_css_token_is_ident (token, "center")
|| gtk_css_token_is_ident (token, "left")
|| gtk_css_token_is_ident (token, "right")
|| gtk_css_token_is_ident (token, "top")
|| gtk_css_token_is_ident (token, "bottom")
|| gtk_css_number_value_check_token (token);
}
typedef enum {
NONE = 0,
CENTER,
LEFT,
RIGHT,
TOP,
BOTTOM
} Keyword;
static Keyword
get_keyword (const GtkCssToken *token)
{
if (gtk_css_token_is_ident (token, "center"))
return CENTER;
else if (gtk_css_token_is_ident (token, "left"))
return LEFT;
else if (gtk_css_token_is_ident (token, "right"))
return RIGHT;
else if (gtk_css_token_is_ident (token, "top"))
return TOP;
else if (gtk_css_token_is_ident (token, "bottom"))
return BOTTOM;
else
return NONE;
}
static GtkCssValue *
value_from_keyword (Keyword keyword,
GtkCssValue *value)
{
switch (keyword)
{
default:
case NONE:
g_assert_not_reached ();
return NULL;
case CENTER:
g_assert (value == NULL);
return _gtk_css_number_value_new (50, GTK_CSS_PERCENT);
case LEFT:
case TOP:
if (value)
return value;
else
return _gtk_css_number_value_new (0, GTK_CSS_PERCENT);
case RIGHT:
case BOTTOM:
if (value == NULL)
return _gtk_css_number_value_new (100, GTK_CSS_PERCENT);
else
{
GtkCssValue *mult = gtk_css_number_value_multiply (value, -1);
GtkCssValue *hundred = _gtk_css_number_value_new (100, GTK_CSS_PERCENT);
GtkCssValue *sum = gtk_css_number_value_add (hundred, mult);
_gtk_css_value_unref (mult);
_gtk_css_value_unref (hundred);
_gtk_css_value_unref (value);
return sum;
}
}
}
static gboolean
keywords_compatible (Keyword a, Keyword b)
{
if ((a == LEFT || a == RIGHT) && (b == LEFT || b == RIGHT))
return FALSE;
if ((a == TOP || a == BOTTOM) && (b == TOP || b == BOTTOM))
return FALSE;
return TRUE;
}
static gboolean
keywords_need_swap (Keyword x, Keyword y)
{
/* NB: We assume the keywords are compatible here */
return x == TOP || x == BOTTOM
|| y == LEFT || y == RIGHT;
}
GtkCssValue *
gtk_css_position_value_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token;
GtkCssValue *x, *y;
Keyword keyword;
token = gtk_css_token_source_get_token (source);
keyword = get_keyword (token);
if (keyword == NONE)
{
/* NUMBER ... */
x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH);
if (x == NULL)
return NULL;
token = gtk_css_token_source_get_token (source);
keyword = get_keyword (token);
if (keyword == NONE)
{
if (gtk_css_number_value_check_token (token))
{
/* NUMBER NUMBER */
y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH);
if (y == NULL)
{
_gtk_css_value_unref (x);
return NULL;
}
}
else
{
/* NUMBER */
y = value_from_keyword (CENTER, NULL);
}
}
else if (keyword == LEFT || keyword == RIGHT)
{
gtk_css_token_source_error (source, "\"left\" and \"right\" may not follow a number");
gtk_css_token_source_consume_all (source);
_gtk_css_value_unref (x);
return NULL;
}
else
{
/* NUMBER KEYWORD */
y = value_from_keyword (keyword, NULL);
}
}
else
{
/* KEYWORD ... */
Keyword keyword2;
GtkCssValue *value;
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
keyword2 = get_keyword (token);
if (keyword2 != NONE)
{
/* KEYWORD KEYWORD ... */
if (!keywords_compatible (keyword, keyword2))
{
gtk_css_token_source_error (source, "Two keywords for same axis");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (keyword2 != CENTER && gtk_css_number_value_check_token (token))
{
/* KEYWORD KEYWORD NUMBER */
value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH);
if (value == NULL)
return NULL;
}
else
value = NULL;
if (keywords_need_swap (keyword, keyword2))
{
x = value_from_keyword (keyword2, value);
y = value_from_keyword (keyword, NULL);
}
else
{
x = value_from_keyword (keyword, NULL);
y = value_from_keyword (keyword2, value);
}
}
else
{
if (gtk_css_number_value_check_token (token))
{
/* KEYWORD NUMBER ... */
x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH);
if (x == NULL)
return NULL;
token = gtk_css_token_source_get_token (source);
keyword2 = get_keyword (token);
if (keyword2 == NONE)
{
/* KEYWORD NUMBER */
if (keyword == TOP || keyword == BOTTOM)
{
x = value_from_keyword (LEFT, x);
y = value_from_keyword (keyword, NULL);
}
else
{
y = value_from_keyword (LEFT, x);
x = value_from_keyword (keyword, NULL);
}
}
else
{
/* KEYWORD NUMBER KEYWORD ... */
if (!keywords_compatible (keyword, keyword2))
{
gtk_css_token_source_error (source, "Two keywords for same axis");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (keyword2 != CENTER && gtk_css_number_value_check_token (token))
{
/* KEYWORD NUMBER KEYWORD NUMBER */
y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH);
if (y == NULL)
return NULL;
}
else
y = NULL;
if (keywords_need_swap (keyword, keyword2))
{
value = value_from_keyword (keyword2, y);
y = value_from_keyword (keyword, x);
x = value;
}
else
{
x = value_from_keyword (keyword, x);
y = value_from_keyword (keyword, y);
}
}
}
else
{
/* KEYWORD */
x = value_from_keyword (keyword, NULL);
y = value_from_keyword (CENTER, NULL);
}
}
}
return _gtk_css_position_value_new (x, y);
}
double
_gtk_css_position_value_get_x (const GtkCssValue *position,
double one_hundred_percent)

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_POSITION_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -29,6 +30,8 @@ GtkCssValue * _gtk_css_position_value_new (GtkCssValue *x
GtkCssValue *y);
GtkCssValue * _gtk_css_position_value_parse (GtkCssParser *parser);
GtkCssValue * _gtk_css_position_value_try_parse (GtkCssParser *parser);
gboolean gtk_css_position_value_check_token (const GtkCssToken *token);
GtkCssValue * gtk_css_position_value_token_parse (GtkCssTokenSource *source);
double _gtk_css_position_value_get_x (const GtkCssValue *position,
double one_hundred_percent);

View File

@@ -28,12 +28,20 @@
#include "gtkbitmaskprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssdefinecolorruleprivate.h"
#include "gtkcssdeclarationprivate.h"
#include "gtkcssimportruleprivate.h"
#include "gtkcsskeyframesprivate.h"
#include "gtkcsskeyframesruleprivate.h"
#include "gtkcsslonghanddeclarationprivate.h"
#include "gtkcssparserprivate.h"
#include "gtkcsssectionprivate.h"
#include "gtkcssselectorprivate.h"
#include "gtkcssshorthandpropertyprivate.h"
#include "gtkcssshorthanddeclarationprivate.h"
#include "gtkcssstylefuncsprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcssstyleruleprivate.h"
#include "gtkcsswidgetstyledeclarationprivate.h"
#include "gtksettingsprivate.h"
#include "gtkstyleprovider.h"
#include "gtkstylecontextprivate.h"
@@ -296,7 +304,7 @@ widget_property_value_new (char *name, GtkCssSection *section)
value = g_slice_new0 (WidgetPropertyValue);
value->name = name;
if (gtk_keep_css_sections)
if (gtk_keep_css_sections && section)
value->section = gtk_css_section_ref (section);
return value;
@@ -395,7 +403,7 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
}
ruleset->styles[i].value = value;
if (gtk_keep_css_sections)
if (gtk_keep_css_sections && section)
ruleset->styles[i].section = gtk_css_section_ref (section);
else
ruleset->styles[i].section = NULL;
@@ -1715,6 +1723,114 @@ gtk_css_provider_postprocess (GtkCssProvider *css_provider)
#endif
}
static void
gtk_css_provider_load_rules (GtkCssProvider *provider,
GtkCssRuleList *list)
{
GtkCssRule *rule;
gsize i;
for (i = 0; i < gtk_css_rule_list_get_length (list); i++)
{
rule = gtk_css_rule_list_get_item (list, i);
if (GTK_IS_CSS_DEFINE_COLOR_RULE (rule))
{
GtkCssDefineColorRule *color_rule = GTK_CSS_DEFINE_COLOR_RULE (rule);
g_hash_table_insert (provider->priv->symbolic_colors,
g_strdup (gtk_css_define_color_rule_get_name (color_rule)),
_gtk_css_value_ref (gtk_css_define_color_rule_get_value (color_rule)));
}
else if (GTK_IS_CSS_IMPORT_RULE (rule))
{
GtkCssStyleSheet *style_sheet = gtk_css_import_rule_get_style_sheet (GTK_CSS_IMPORT_RULE (rule));
gtk_css_provider_load_rules (provider, gtk_css_style_sheet_get_css_rules (style_sheet));
}
else if (GTK_IS_CSS_KEYFRAMES_RULE (rule))
{
g_hash_table_insert (provider->priv->keyframes,
g_strdup (gtk_css_keyframes_rule_get_name (GTK_CSS_KEYFRAMES_RULE (rule))),
gtk_css_keyframes_new_from_rule (GTK_CSS_KEYFRAMES_RULE (rule)));
}
else if (GTK_IS_CSS_STYLE_RULE (rule))
{
GtkCssStyleDeclaration *style = gtk_css_style_rule_get_style (GTK_CSS_STYLE_RULE (rule));
GtkCssRuleset ruleset = { 0, };
guint j;
for (j = 0; j < gtk_css_style_declaration_get_length (style); j++)
{
GtkCssDeclaration *decl = gtk_css_style_declaration_get_declaration (style, j);
if (GTK_IS_CSS_LONGHAND_DECLARATION (decl))
{
GtkCssLonghandDeclaration *longhand = GTK_CSS_LONGHAND_DECLARATION (decl);
gtk_css_ruleset_add (&ruleset,
gtk_css_longhand_declaration_get_property (longhand),
_gtk_css_value_ref (gtk_css_longhand_declaration_get_value (longhand)),
NULL);
}
else if (GTK_IS_CSS_SHORTHAND_DECLARATION (decl))
{
GtkCssShorthandDeclaration *shorthand = GTK_CSS_SHORTHAND_DECLARATION (decl);
guint k;
for (k = 0; k < gtk_css_shorthand_declaration_get_length (shorthand); k++)
{
gtk_css_ruleset_add (&ruleset,
gtk_css_shorthand_declaration_get_subproperty (shorthand, k),
_gtk_css_value_ref (gtk_css_shorthand_declaration_get_value (shorthand, k)),
NULL);
}
}
else if (GTK_IS_CSS_WIDGET_STYLE_DECLARATION (decl))
{
WidgetPropertyValue *val;
val = widget_property_value_new (g_strdup (gtk_css_declaration_get_name (decl)), NULL);
val->value = gtk_css_declaration_get_value_string (decl);
gtk_css_ruleset_add_style (&ruleset, val->name, val);
}
}
if (ruleset.styles != NULL || ruleset.widget_style != NULL)
{
for (j = 0; j < gtk_css_style_rule_get_n_selectors (GTK_CSS_STYLE_RULE (rule)); j++)
{
GtkCssRuleset new;
gtk_css_ruleset_init_copy (&new,
&ruleset,
gtk_css_style_rule_get_selector (GTK_CSS_STYLE_RULE (rule), j));
g_array_append_val (provider->priv->rulesets, new);
}
}
gtk_css_ruleset_clear (&ruleset);
}
else
{
g_warning ("No code to deal with %s", G_OBJECT_TYPE_NAME (rule));
}
}
}
void
gtk_css_provider_load_style_sheet (GtkCssProvider *provider,
GtkCssStyleSheet *style_sheet)
{
gtk_css_provider_reset (provider);
gtk_css_provider_load_rules (provider, gtk_css_style_sheet_get_css_rules (style_sheet));
gtk_css_provider_postprocess (provider);
_gtk_style_provider_private_changed (GTK_STYLE_PROVIDER_PRIVATE (provider));
}
static gboolean
gtk_css_provider_load_internal (GtkCssProvider *css_provider,
GtkCssScanner *parent,

View File

@@ -20,6 +20,8 @@
#include "gtkcssprovider.h"
#include "gtkcssstylesheetprivate.h"
G_BEGIN_DECLS
gchar *_gtk_get_theme_dir (void);
@@ -30,6 +32,9 @@ void _gtk_css_provider_load_named (GtkCssProvider *provider,
const gchar *name,
const gchar *variant);
void gtk_css_provider_load_style_sheet (GtkCssProvider *provider,
GtkCssStyleSheet *style_sheet);
void gtk_css_provider_set_keep_css_sections (void);
G_END_DECLS

750
gtk/gtkcssrbtree.c Normal file
View File

@@ -0,0 +1,750 @@
/* gtkrbtree.c
* Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcssrbtreeprivate.h"
#include "gtkdebug.h"
typedef struct _GtkCssRbNode GtkCssRbNode;
struct _GtkCssRbTree
{
guint ref_count;
gsize element_size;
gsize augment_size;
GtkCssRbTreeAugmentFunc augment_func;
GDestroyNotify clear_func;
GDestroyNotify clear_augment_func;
GtkCssRbNode *root;
};
struct _GtkCssRbNode
{
guint red :1;
guint dirty :1;
GtkCssRbNode *left;
GtkCssRbNode *right;
GtkCssRbNode *parent;
};
#define NODE_FROM_POINTER(ptr) ((GtkCssRbNode *) ((ptr) ? (((guchar *) (ptr)) - sizeof (GtkCssRbNode)) : NULL))
#define NODE_TO_POINTER(node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkCssRbNode)) : NULL))
#define NODE_TO_AUG_POINTER(tree, node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkCssRbNode) + (tree)->element_size) : NULL))
static inline gsize
gtk_css_rb_node_get_size (GtkCssRbTree *tree)
{
return sizeof (GtkCssRbNode) + tree->element_size + tree->augment_size;
}
static GtkCssRbNode *
gtk_css_rb_node_new (GtkCssRbTree *tree)
{
GtkCssRbNode *result;
result = g_slice_alloc0 (gtk_css_rb_node_get_size (tree));
result->red = TRUE;
result->dirty = TRUE;
return result;
}
static void
gtk_css_rb_node_free (GtkCssRbTree *tree,
GtkCssRbNode *node)
{
if (tree->clear_func)
tree->clear_func (NODE_TO_POINTER (node));
if (tree->clear_augment_func)
tree->clear_augment_func (NODE_TO_AUG_POINTER (tree, node));
g_slice_free1 (gtk_css_rb_node_get_size (tree), node);
}
static void
gtk_css_rb_node_free_deep (GtkCssRbTree *tree,
GtkCssRbNode *node)
{
GtkCssRbNode *right = node->right;
if (node->left)
gtk_css_rb_node_free_deep (tree, node->left);
gtk_css_rb_node_free (tree, node);
if (right)
gtk_css_rb_node_free_deep (tree, right);
}
static void
gtk_css_rb_node_mark_dirty (GtkCssRbNode *node,
gboolean mark_parent)
{
if (node->dirty)
return;
node->dirty = TRUE;
if (mark_parent && node->parent)
gtk_css_rb_node_mark_dirty (node->parent, TRUE);
}
static void
gtk_css_rb_node_clean (GtkCssRbTree *tree,
GtkCssRbNode *node)
{
if (!node->dirty)
return;
node->dirty = FALSE;
if (tree->augment_func)
tree->augment_func (tree,
NODE_TO_AUG_POINTER (tree, node),
NODE_TO_POINTER (node),
NODE_TO_POINTER (node->left),
NODE_TO_POINTER (node->right));
}
static GtkCssRbNode *
gtk_css_rb_node_get_first (GtkCssRbNode *node)
{
while (node->left)
node = node->left;
return node;
}
static GtkCssRbNode *
gtk_css_rb_node_get_last (GtkCssRbNode *node)
{
while (node->right)
node = node->right;
return node;
}
static GtkCssRbNode *
gtk_css_rb_node_get_previous (GtkCssRbNode *node)
{
GtkCssRbNode *parent;
if (node->left)
return gtk_css_rb_node_get_last (node->left);
for (parent = node->parent; parent != NULL; parent = node->parent)
{
if (parent->right == node)
return parent;
node = parent;
}
return NULL;
}
static GtkCssRbNode *
gtk_css_rb_node_get_next (GtkCssRbNode *node)
{
GtkCssRbNode *parent;
if (node->right)
return gtk_css_rb_node_get_first (node->right);
for (parent = node->parent; parent != NULL; parent = node->parent)
{
if (parent->left == node)
return parent;
node = parent;
}
return NULL;
}
static void
gtk_css_rb_node_rotate_left (GtkCssRbTree *tree,
GtkCssRbNode *node)
{
GtkCssRbNode *right;
right = node->right;
node->right = right->left;
if (right->left)
right->left->parent = node;
right->parent = node->parent;
if (node->parent)
{
if (node == node->parent->left)
node->parent->left = right;
else
node->parent->right = right;
}
else
{
tree->root = right;
}
right->left = node;
node->parent = right;
gtk_css_rb_node_mark_dirty (node, FALSE);
gtk_css_rb_node_mark_dirty (right, FALSE);
}
static void
gtk_css_rb_node_rotate_right (GtkCssRbTree *tree,
GtkCssRbNode *node)
{
GtkCssRbNode *left;
left = node->left;
node->left = left->right;
if (left->right)
left->right->parent = node;
left->parent = node->parent;
if (node->parent)
{
if (node == node->parent->right)
node->parent->right = left;
else
node->parent->left = left;
}
else
{
tree->root = left;
}
/* link node and left */
left->right = node;
node->parent = left;
gtk_css_rb_node_mark_dirty (node, FALSE);
gtk_css_rb_node_mark_dirty (left, FALSE);
}
static gboolean
is_red (GtkCssRbNode *node_or_null)
{
if (node_or_null == NULL)
return FALSE;
else
return node_or_null->red;
}
static inline gboolean
is_black (GtkCssRbNode *node_or_null)
{
return !is_red (node_or_null);
}
static void
set_black (GtkCssRbNode *node_or_null)
{
if (node_or_null == NULL)
return;
node_or_null->red = FALSE;
}
static void
set_red (GtkCssRbNode *node_or_null)
{
if (node_or_null == NULL)
return;
node_or_null->red = TRUE;
}
static void
gtk_css_rb_tree_insert_fixup (GtkCssRbTree *tree,
GtkCssRbNode *node)
{
/* check Red-Black properties */
while (node->parent && is_red (node->parent))
{
/* we have a violation */
g_assert (node->parent->parent);
if (node->parent == node->parent->parent->left)
{
GtkCssRbNode *uncle = node->parent->parent->right;
if (is_red (uncle))
{
/* uncle is red */
set_black (node->parent);
set_black (uncle);
set_red (node->parent->parent);
node = node->parent->parent;
}
else
{
/* uncle is black */
if (node == node->parent->right)
{
/* make node a left child */
node = node->parent;
gtk_css_rb_node_rotate_left (tree, node);
}
/* recolor and rotate */
set_black (node->parent);
set_red (node->parent->parent);
gtk_css_rb_node_rotate_right (tree, node->parent->parent);
}
}
else
{
/* mirror image of above code */
GtkCssRbNode *uncle = node->parent->parent->left;
if (is_red (uncle))
{
/* uncle is red */
set_black (node->parent);
set_black (uncle);
set_red (node->parent->parent);
node = node->parent->parent;
}
else
{
/* uncle is black */
if (node == node->parent->left)
{
node = node->parent;
gtk_css_rb_node_rotate_right (tree, node);
}
set_black (node->parent);
set_red (node->parent->parent);
gtk_css_rb_node_rotate_left (tree, node->parent->parent);
}
}
}
set_black (tree->root);
}
static void
gtk_css_rb_tree_remove_node_fixup (GtkCssRbTree *tree,
GtkCssRbNode *node,
GtkCssRbNode *parent)
{
while (node->parent && is_black (node))
{
if (node == parent->left)
{
GtkCssRbNode *w = parent->right;
if (is_red (w))
{
set_black (w);
set_red (parent);
gtk_css_rb_node_rotate_left (tree, parent);
w = parent->right;
}
if (is_black (w->left) && is_black (w->right))
{
set_red (w);
node = parent;
}
else
{
if (is_black (w->right))
{
set_black (w->left);
set_red (w);
gtk_css_rb_node_rotate_right (tree, w);
w = parent->right;
}
w->red = parent->red;
set_black (parent);
set_black (w->right);
gtk_css_rb_node_rotate_left (tree, parent);
node = tree->root;
}
}
else
{
GtkCssRbNode *w = parent->left;
if (is_red (w))
{
set_black (w);
set_red (parent);
gtk_css_rb_node_rotate_right (tree, parent);
w = parent->left;
}
if (is_black (w->right) && is_black (w->left))
{
set_red (w);
node = parent;
}
else
{
if (is_black (w->left))
{
set_black (w->right);
set_red (w);
gtk_css_rb_node_rotate_left (tree, w);
w = parent->left;
}
w->red = parent->red;
set_black (parent);
set_black (w->left);
gtk_css_rb_node_rotate_right (tree, parent);
node = tree->root;
}
}
parent = node->parent;
}
set_black (node);
}
GtkCssRbTree *
gtk_css_rb_tree_new_for_size (gsize element_size,
gsize augment_size,
GtkCssRbTreeAugmentFunc augment_func,
GDestroyNotify clear_func,
GDestroyNotify clear_augment_func)
{
GtkCssRbTree *tree;
tree = g_slice_new0 (GtkCssRbTree);
tree->ref_count = 1;
tree->element_size = element_size;
tree->augment_size = augment_size;
tree->augment_func = augment_func;
tree->clear_func = clear_func;
tree->clear_augment_func = clear_augment_func;
return tree;
}
GtkCssRbTree *
gtk_css_rb_tree_ref (GtkCssRbTree *tree)
{
tree->ref_count++;
return tree;
}
void
gtk_css_rb_tree_unref (GtkCssRbTree *tree)
{
tree->ref_count--;
if (tree->ref_count > 0)
return;
if (tree->root)
gtk_css_rb_node_free_deep (tree, tree->root);
g_slice_free (GtkCssRbTree, tree);
}
gpointer
gtk_css_rb_tree_get_first (GtkCssRbTree *tree)
{
if (tree->root == NULL)
return NULL;
return NODE_TO_POINTER (gtk_css_rb_node_get_first (tree->root));
}
gpointer
gtk_css_rb_tree_get_last (GtkCssRbTree *tree)
{
if (tree->root == NULL)
return NULL;
return NODE_TO_POINTER (gtk_css_rb_node_get_last (tree->root));
}
gpointer
gtk_css_rb_tree_get_previous (GtkCssRbTree *tree,
gpointer node)
{
return NODE_TO_POINTER (gtk_css_rb_node_get_previous (NODE_FROM_POINTER (node)));
}
gpointer
gtk_css_rb_tree_get_next (GtkCssRbTree *tree,
gpointer node)
{
return NODE_TO_POINTER (gtk_css_rb_node_get_next (NODE_FROM_POINTER (node)));
}
gpointer
gtk_css_rb_tree_get_root (GtkCssRbTree *tree)
{
return NODE_TO_POINTER (tree->root);
}
gpointer
gtk_css_rb_tree_get_parent (GtkCssRbTree *tree,
gpointer node)
{
return NODE_TO_POINTER (NODE_FROM_POINTER (node)->parent);
}
gpointer
gtk_css_rb_tree_get_left (GtkCssRbTree *tree,
gpointer node)
{
return NODE_TO_POINTER (NODE_FROM_POINTER (node)->left);
}
gpointer
gtk_css_rb_tree_get_right (GtkCssRbTree *tree,
gpointer node)
{
return NODE_TO_POINTER (NODE_FROM_POINTER (node)->right);
}
gpointer
gtk_css_rb_tree_get_augment (GtkCssRbTree *tree,
gpointer node)
{
GtkCssRbNode *rbnode = NODE_FROM_POINTER (node);
gtk_css_rb_node_clean (tree, rbnode);
return NODE_TO_AUG_POINTER (tree, rbnode);
}
void
gtk_css_rb_tree_mark_dirty (GtkCssRbTree *tree,
gpointer node)
{
gtk_css_rb_node_mark_dirty (NODE_FROM_POINTER (node), TRUE);
}
gpointer
gtk_css_rb_tree_insert_before (GtkCssRbTree *tree,
gpointer node)
{
GtkCssRbNode *result;
/* setup new node */
result = gtk_css_rb_node_new (tree);
if (tree->root == NULL)
{
g_assert (node == NULL);
tree->root = result;
}
else if (node == NULL)
{
return gtk_css_rb_tree_insert_after (tree, gtk_css_rb_tree_get_last (tree));
}
else
{
GtkCssRbNode *current = NODE_FROM_POINTER (node);
if (current->left)
{
current = gtk_css_rb_node_get_last (current);
current->right = result;
}
else
{
current->left = result;
}
result->parent = current;
gtk_css_rb_node_mark_dirty (current, TRUE);
}
gtk_css_rb_tree_insert_fixup (tree, result);
return NODE_TO_POINTER (result);
}
gpointer
gtk_css_rb_tree_insert_after (GtkCssRbTree *tree,
gpointer node)
{
GtkCssRbNode *result;
/* setup new node */
result = gtk_css_rb_node_new (tree);
if (tree->root == NULL)
{
g_assert (node == NULL);
tree->root = result;
}
else if (node == NULL)
{
return gtk_css_rb_tree_insert_before (tree, gtk_css_rb_tree_get_first (tree));
}
else
{
GtkCssRbNode *current = NODE_FROM_POINTER (node);
if (current->right )
{
current = gtk_css_rb_node_get_first (current);
current->left = result;
}
else
{
current->right = result;
}
result->parent = current;
gtk_css_rb_node_mark_dirty (current, TRUE);
}
gtk_css_rb_tree_insert_fixup (tree, result);
return NODE_TO_POINTER (result);
}
void
gtk_css_rb_tree_remove (GtkCssRbTree *tree,
gpointer node)
{
GtkCssRbNode *x, *y, *real_node;
real_node = NODE_FROM_POINTER (node);
y = real_node;
if (y->left && y->right)
{
y = y->right;
while (y->left)
y = y->left;
}
/* x is y's only child, or nil */
if (y->left)
x = y->left;
else
x = y->right;
/* remove y from the parent chain */
if (x != NULL)
x->parent = y->parent;
if (y->parent)
{
if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
}
else
{
tree->root = x;
}
/* We need to clean up the validity of the tree.
*/
if (x && is_black (y))
gtk_css_rb_tree_remove_node_fixup (tree, x, y->parent);
if (y != real_node)
{
/* Move the node over */
if (is_red (real_node) != is_red (y))
y->red = !y->red;
y->left = real_node->left;
if (y->left)
y->left->parent = y;
y->right = real_node->right;
if (y->right)
y->right->parent = y;
y->parent = real_node->parent;
if (y->parent)
{
if (y->parent->left == real_node)
y->parent->left = y;
else
y->parent->right = y;
}
else
{
tree->root = y;
}
}
gtk_css_rb_node_free (tree, real_node);
}
gpointer
gtk_css_rb_tree_find (GtkCssRbTree *tree,
gpointer *out_before,
gpointer *out_after,
GtkCssRbTreeFindFunc find_func,
gpointer user_data)
{
GtkCssRbNode *node, *before = NULL, *after = NULL;
int cmp;
if (tree->root == NULL)
{
if (out_before)
*out_before = NULL;
if (out_after)
*out_after = NULL;
return NULL;
}
node = tree->root;
for (cmp = find_func (tree, NODE_TO_POINTER (node), user_data);
cmp != 0;
cmp = find_func (tree, NODE_TO_POINTER (node), user_data))
{
if (cmp < 0)
{
before = node;
node = node->right;
}
else /* cmp > 0 */
{
after = node;
node = node->left;
}
if (node == NULL)
{
if (out_before)
*out_before = NODE_TO_POINTER (before);
if (out_after)
*out_after = NODE_TO_POINTER (after);
return NULL;;
}
}
if (out_before)
*out_before = NODE_TO_POINTER (gtk_css_rb_node_get_previous (node));
if (out_after)
*out_after = NODE_TO_POINTER (gtk_css_rb_node_get_next (node));
return NODE_TO_POINTER (node);
}

89
gtk/gtkcssrbtreeprivate.h Normal file
View File

@@ -0,0 +1,89 @@
/* gtkrb_tree.h
* Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* A Red-Black Tree implementation used specifically by GtkTreeView.
*/
#ifndef __GTK_CSS_RB_TREE_H__
#define __GTK_CSS_RB_TREE_H__
#include <glib.h>
G_BEGIN_DECLS
typedef struct _GtkCssRbTree GtkCssRbTree;
typedef void (* GtkCssRbTreeAugmentFunc) (GtkCssRbTree *tree,
gpointer node_augment,
gpointer node,
gpointer left,
gpointer right);
typedef int (* GtkCssRbTreeFindFunc) (GtkCssRbTree *tree,
gpointer node,
gpointer user_data);
GtkCssRbTree * gtk_css_rb_tree_new_for_size (gsize element_size,
gsize augment_size,
GtkCssRbTreeAugmentFunc augment_func,
GDestroyNotify clear_func,
GDestroyNotify clear_augment_func);
#define gtk_css_rb_tree_new(type, augment_type, augment_func, clear_func, clear_augment_func) \
gtk_css_rb_tree_new_for_size (sizeof (type), sizeof (augment_type), (augment_func), (clear_func), (clear_augment_func))
GtkCssRbTree * gtk_css_rb_tree_ref (GtkCssRbTree *tree);
void gtk_css_rb_tree_unref (GtkCssRbTree *tree);
gpointer gtk_css_rb_tree_get_first (GtkCssRbTree *tree);
gpointer gtk_css_rb_tree_get_last (GtkCssRbTree *tree);
gpointer gtk_css_rb_tree_get_previous (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_get_next (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_get_root (GtkCssRbTree *tree);
gpointer gtk_css_rb_tree_get_parent (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_get_left (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_get_right (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_get_augment (GtkCssRbTree *tree,
gpointer node);
void gtk_css_rb_tree_mark_dirty (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_insert_before (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_insert_after (GtkCssRbTree *tree,
gpointer node);
void gtk_css_rb_tree_remove (GtkCssRbTree *tree,
gpointer node);
gpointer gtk_css_rb_tree_find (GtkCssRbTree *tree,
gpointer *out_before,
gpointer *out_after,
GtkCssRbTreeFindFunc find_func,
gpointer user_data);
G_END_DECLS
#endif /* __GTK_CSS_RB_TREE_H__ */

View File

@@ -205,6 +205,59 @@ _gtk_css_background_repeat_value_try_parse (GtkCssParser *parser)
return _gtk_css_background_repeat_value_new (x, y);
}
static gboolean
gtk_css_background_repeat_value_from_token (const GtkCssToken *token,
GtkCssRepeatStyle *style)
{
if (gtk_css_token_is_ident (token, "repeat"))
*style = GTK_CSS_REPEAT_STYLE_REPEAT;
else if (gtk_css_token_is_ident (token, "space"))
*style = GTK_CSS_REPEAT_STYLE_SPACE;
else if (gtk_css_token_is_ident (token, "round"))
*style = GTK_CSS_REPEAT_STYLE_ROUND;
else if (gtk_css_token_is_ident (token, "no-repeat"))
*style = GTK_CSS_REPEAT_STYLE_NO_REPEAT;
else
return FALSE;
return TRUE;
}
GtkCssValue *
gtk_css_background_repeat_value_token_parse (GtkCssTokenSource *source)
{
GtkCssRepeatStyle x, y;
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "repeat-x"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_background_repeat_value_new (GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
}
if (gtk_css_token_is_ident (token, "repeat-y"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_background_repeat_value_new (GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT);
}
if (!gtk_css_background_repeat_value_from_token (token, &x))
{
gtk_css_token_source_error (source, "Not a repeat-style");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_background_repeat_value_from_token (token, &y))
gtk_css_token_source_consume_token (source);
else
y = x;
return _gtk_css_background_repeat_value_new (x, y);
}
GtkCssRepeatStyle
_gtk_css_background_repeat_value_get_x (const GtkCssValue *repeat)
{
@@ -294,6 +347,48 @@ _gtk_css_border_repeat_value_try_parse (GtkCssParser *parser)
return _gtk_css_border_repeat_value_new (x, y);
}
static gboolean
gtk_css_border_repeat_value_from_token (const GtkCssToken *token,
GtkCssRepeatStyle *style)
{
if (gtk_css_token_is_ident (token, "repeat"))
*style = GTK_CSS_REPEAT_STYLE_REPEAT;
else if (gtk_css_token_is_ident (token, "space"))
*style = GTK_CSS_REPEAT_STYLE_SPACE;
else if (gtk_css_token_is_ident (token, "round"))
*style = GTK_CSS_REPEAT_STYLE_ROUND;
else if (gtk_css_token_is_ident (token, "stretch"))
*style = GTK_CSS_REPEAT_STYLE_STRETCH;
else
return FALSE;
return TRUE;
}
GtkCssValue *
gtk_css_border_repeat_value_token_parse (GtkCssTokenSource *source)
{
GtkCssRepeatStyle x, y;
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_border_repeat_value_from_token (token, &x))
{
gtk_css_token_source_error (source, "Not a repeat style");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_border_repeat_value_from_token (token, &y))
gtk_css_token_source_consume_token (source);
else
y = x;
return _gtk_css_border_repeat_value_new (x, y);
}
GtkCssRepeatStyle
_gtk_css_border_repeat_value_get_x (const GtkCssValue *repeat)
{

View File

@@ -21,6 +21,7 @@
#define __GTK_CSS_REPEAT_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
@@ -36,12 +37,14 @@ typedef enum {
GtkCssValue * _gtk_css_background_repeat_value_new (GtkCssRepeatStyle x,
GtkCssRepeatStyle y);
GtkCssValue * _gtk_css_background_repeat_value_try_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_background_repeat_value_token_parse (GtkCssTokenSource *source);
GtkCssRepeatStyle _gtk_css_background_repeat_value_get_x (const GtkCssValue *repeat);
GtkCssRepeatStyle _gtk_css_background_repeat_value_get_y (const GtkCssValue *repeat);
GtkCssValue * _gtk_css_border_repeat_value_new (GtkCssRepeatStyle x,
GtkCssRepeatStyle y);
GtkCssValue * _gtk_css_border_repeat_value_try_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_border_repeat_value_token_parse (GtkCssTokenSource *source);
GtkCssRepeatStyle _gtk_css_border_repeat_value_get_x (const GtkCssValue *repeat);
GtkCssRepeatStyle _gtk_css_border_repeat_value_get_y (const GtkCssValue *repeat);

355
gtk/gtkcssrule.c Normal file
View File

@@ -0,0 +1,355 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssruleprivate.h"
#include "gtkcssdefinecolorruleprivate.h"
#include "gtkcssimportruleprivate.h"
#include "gtkcsskeyframesruleprivate.h"
#include "gtkcssstylesheetprivate.h"
#include "gtkintl.h"
#include "gtkprivate.h"
enum {
PROP_0,
PROP_CSS_TEXT,
PROP_PARENT_RULE,
PROP_PARENT_STYLESHEET,
NUM_PROPERTIES
};
typedef struct _GtkCssRulePrivate GtkCssRulePrivate;
struct _GtkCssRulePrivate {
GtkCssRule *parent_rule;
GtkCssStyleSheet *parent_style_sheet;
};
typedef struct _GtkCssTokenSourceAt GtkCssTokenSourceAt;
struct _GtkCssTokenSourceAt {
GtkCssTokenSource parent;
GtkCssTokenSource *source;
GSList *blocks;
guint done :1;
};
static GParamSpec *rule_props[NUM_PROPERTIES] = { NULL, };
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkCssRule, gtk_css_rule, G_TYPE_OBJECT)
static void
gtk_css_token_source_at_finalize (GtkCssTokenSource *source)
{
GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
g_slist_free (at->blocks);
gtk_css_token_source_unref (at->source);
}
static void
gtk_css_token_source_at_consume_token (GtkCssTokenSource *source,
GObject *consumer)
{
GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
const GtkCssToken *token;
if (at->done)
return;
token = gtk_css_token_source_peek_token (at->source);
switch (token->type)
{
case GTK_CSS_TOKEN_FUNCTION:
case GTK_CSS_TOKEN_OPEN_PARENS:
at->blocks = g_slist_prepend (at->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_PARENS));
break;
case GTK_CSS_TOKEN_OPEN_SQUARE:
at->blocks = g_slist_prepend (at->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_SQUARE));
break;
case GTK_CSS_TOKEN_OPEN_CURLY:
at->blocks = g_slist_prepend (at->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_CURLY));
break;
case GTK_CSS_TOKEN_CLOSE_PARENS:
case GTK_CSS_TOKEN_CLOSE_SQUARE:
case GTK_CSS_TOKEN_CLOSE_CURLY:
if (at->blocks && GPOINTER_TO_UINT (at->blocks->data) == token->type)
{
at->blocks = g_slist_remove (at->blocks, at->blocks->data);
if (token->type == GTK_CSS_TOKEN_CLOSE_CURLY && at->blocks == NULL)
at->done = TRUE;
}
break;
case GTK_CSS_TOKEN_SEMICOLON:
if (at->blocks == NULL)
at->done = TRUE;
break;
default:
break;
}
gtk_css_token_source_consume_token_as (at->source, consumer);
}
const GtkCssToken *
gtk_css_token_source_at_peek_token (GtkCssTokenSource *source)
{
GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
static GtkCssToken eof_token = { GTK_CSS_TOKEN_EOF };
if (at->done)
return &eof_token;
return gtk_css_token_source_peek_token (at->source);
}
static void
gtk_css_token_source_at_error (GtkCssTokenSource *source,
const GError *error)
{
GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
gtk_css_token_source_emit_error (at->source, error);
}
static GFile *
gtk_css_token_source_at_get_location (GtkCssTokenSource *source)
{
GtkCssTokenSourceAt *at = (GtkCssTokenSourceAt *) source;
return gtk_css_token_source_get_location (at->source);
}
static const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_AT = {
gtk_css_token_source_at_finalize,
gtk_css_token_source_at_consume_token,
gtk_css_token_source_at_peek_token,
gtk_css_token_source_at_error,
gtk_css_token_source_at_get_location,
};
static GtkCssTokenSource *
gtk_css_token_source_new_at (GtkCssTokenSource *source)
{
GtkCssTokenSourceAt *at = gtk_css_token_source_new (GtkCssTokenSourceAt, &GTK_CSS_TOKEN_SOURCE_AT);
at->source = gtk_css_token_source_ref (source);
gtk_css_token_source_set_consumer (&at->parent,
gtk_css_token_source_get_consumer (source));
return &at->parent;
}
static void
gtk_css_rule_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkCssRule *rule = GTK_CSS_RULE (gobject);
GtkCssRulePrivate *priv = gtk_css_rule_get_instance_private (rule);
switch (prop_id)
{
case PROP_PARENT_RULE:
priv->parent_rule = g_value_dup_object (value);
break;
case PROP_PARENT_STYLESHEET:
priv->parent_style_sheet = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_css_rule_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkCssRule *rule = GTK_CSS_RULE (gobject);
GtkCssRulePrivate *priv = gtk_css_rule_get_instance_private (rule);
switch (prop_id)
{
case PROP_CSS_TEXT:
g_value_take_string (value, gtk_css_rule_get_css_text (rule));
break;
case PROP_PARENT_RULE:
g_value_set_object (value, priv->parent_rule);
break;
case PROP_PARENT_STYLESHEET:
g_value_set_object (value, priv->parent_style_sheet);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gtk_css_rule_class_init (GtkCssRuleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = gtk_css_rule_set_property;
object_class->get_property = gtk_css_rule_get_property;
rule_props[PROP_CSS_TEXT] =
g_param_spec_string ("css-text",
P_("CSS text"),
P_("Conversion this rule to text"),
NULL,
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
rule_props[PROP_PARENT_RULE] =
g_param_spec_object ("parent-rule",
P_("parent rule"),
P_("The parent CSS rule if it exists"),
GTK_TYPE_CSS_RULE,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
rule_props[PROP_PARENT_STYLESHEET] =
g_param_spec_object ("parent-stylesheet",
P_("parent style sheet"),
P_("The parent style sheet that contains this rule"),
GTK_TYPE_CSS_STYLE_SHEET,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, rule_props);
}
static void
gtk_css_rule_init (GtkCssRule *rule)
{
}
GtkCssRule *
gtk_css_rule_new_from_at_rule (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
GtkCssTokenSource *at_source;
const GtkCssToken *token;
GtkCssRule *rule;
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);
at_source = gtk_css_token_source_new_at (source);
token = gtk_css_token_source_get_token (at_source);
if (token->type != GTK_CSS_TOKEN_AT_KEYWORD)
{
gtk_css_token_source_error (at_source, "Expected an '@'");
gtk_css_token_source_consume_all (at_source);
gtk_css_token_source_unref (at_source);
return NULL;
}
if (g_ascii_strcasecmp (token->string.string, "import") == 0)
{
rule = gtk_css_import_rule_new_parse (at_source, parent_rule, parent_style_sheet);
}
else if (g_ascii_strcasecmp (token->string.string, "define-color") == 0)
{
rule = gtk_css_define_color_rule_new_parse (at_source, parent_rule, parent_style_sheet);
}
else if (g_ascii_strcasecmp (token->string.string, "keyframes") == 0)
{
rule = gtk_css_keyframes_rule_new_parse (at_source, parent_rule, parent_style_sheet);
}
else
{
gtk_css_token_source_unknown (at_source, "Unknown rule @%s", token->string.string);
gtk_css_token_source_consume_all (at_source);
rule = NULL;
}
token = gtk_css_token_source_get_token (at_source);
if (rule != NULL && !gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
gtk_css_token_source_unknown (at_source, "Junk at end of @-rule");
gtk_css_token_source_consume_all (at_source);
g_object_unref (rule);
rule = NULL;
}
gtk_css_token_source_unref (at_source);
return rule;
}
void
gtk_css_rule_print_css_text (GtkCssRule *rule,
GString *string)
{
GtkCssRuleClass *klass;
g_return_if_fail (GTK_IS_CSS_RULE (rule));
g_return_if_fail (string != NULL);
klass = GTK_CSS_RULE_GET_CLASS (rule);
klass->get_css_text (rule, string);
}
char *
gtk_css_rule_get_css_text (GtkCssRule *rule)
{
GString *string;
g_return_val_if_fail (GTK_IS_CSS_RULE (rule), NULL);
string = g_string_new (NULL);
gtk_css_rule_print_css_text (rule, string);
return g_string_free (string, FALSE);
}
GtkCssRule *
gtk_css_rule_get_parent_rule (GtkCssRule *rule)
{
GtkCssRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_RULE (rule), NULL);
priv = gtk_css_rule_get_instance_private (rule);
return priv->parent_rule;
}
GtkCssStyleSheet *
gtk_css_rule_get_parent_style_sheet (GtkCssRule *rule)
{
GtkCssRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_RULE (rule), NULL);
priv = gtk_css_rule_get_instance_private (rule);
return priv->parent_style_sheet;
}

168
gtk/gtkcssrulelist.c Normal file
View File

@@ -0,0 +1,168 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssrulelistprivate.h"
#include "gtkcssstyleruleprivate.h"
#include "gtkcssstylesheetprivate.h"
typedef struct _GtkCssRuleListPrivate GtkCssRuleListPrivate;
struct _GtkCssRuleListPrivate {
GPtrArray *items;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssRuleList, gtk_css_rule_list, G_TYPE_OBJECT)
static void
gtk_css_rule_list_finalize (GObject *object)
{
GtkCssRuleList *rule_list = GTK_CSS_RULE_LIST (object);
GtkCssRuleListPrivate *priv = gtk_css_rule_list_get_instance_private (rule_list);
g_ptr_array_unref (priv->items);
G_OBJECT_CLASS (gtk_css_rule_list_parent_class)->finalize (object);
}
static void
gtk_css_rule_list_class_init (GtkCssRuleListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_rule_list_finalize;
}
static void
gtk_css_rule_list_init (GtkCssRuleList *rule_list)
{
GtkCssRuleListPrivate *priv = gtk_css_rule_list_get_instance_private (rule_list);
priv->items = g_ptr_array_new_with_free_func (g_object_unref);
}
GtkCssRuleList *
gtk_css_rule_list_new (void)
{
return g_object_new (GTK_TYPE_CSS_RULE_LIST, NULL);
}
void
gtk_css_rule_list_parse (GtkCssRuleList *rule_list,
GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
GtkCssRule *rule;
const GtkCssToken *token;
g_return_if_fail (GTK_IS_CSS_RULE_LIST (rule_list));
g_return_if_fail (source != NULL);
g_return_if_fail (parent_rule == NULL || GTK_IS_CSS_RULE (parent_rule));
g_return_if_fail (GTK_IS_CSS_STYLE_SHEET (parent_style_sheet));
gtk_css_token_source_set_consumer (source, G_OBJECT (rule_list));
for (token = gtk_css_token_source_get_token (source);
token->type != GTK_CSS_TOKEN_EOF;
token = gtk_css_token_source_get_token (source))
{
switch (token->type)
{
case GTK_CSS_TOKEN_WHITESPACE:
gtk_css_token_source_consume_token (source);
break;
case GTK_CSS_TOKEN_AT_KEYWORD:
rule = gtk_css_rule_new_from_at_rule (source, parent_rule, parent_style_sheet);
if (rule)
gtk_css_rule_list_append (rule_list, rule);
break;
case GTK_CSS_TOKEN_CDO:
case GTK_CSS_TOKEN_CDC:
if (parent_rule == NULL)
{
gtk_css_token_source_consume_token (source);
break;
}
/* else fall through */
default:
rule = gtk_css_style_rule_new_parse (source, parent_rule, parent_style_sheet);
if (rule)
gtk_css_rule_list_append (rule_list, rule);
break;
}
}
}
void
gtk_css_rule_list_insert (GtkCssRuleList *rule_list,
gsize id,
GtkCssRule *rule)
{
GtkCssRuleListPrivate *priv;
g_return_if_fail (GTK_IS_CSS_RULE_LIST (rule_list));
g_return_if_fail (GTK_IS_CSS_RULE (rule));
priv = gtk_css_rule_list_get_instance_private (rule_list);
g_ptr_array_insert (priv->items, id, g_object_ref (rule));
}
void
gtk_css_rule_list_append (GtkCssRuleList *rule_list,
GtkCssRule *rule)
{
GtkCssRuleListPrivate *priv;
g_return_if_fail (GTK_IS_CSS_RULE_LIST (rule_list));
g_return_if_fail (GTK_IS_CSS_RULE (rule));
priv = gtk_css_rule_list_get_instance_private (rule_list);
g_ptr_array_add (priv->items, g_object_ref (rule));
}
GtkCssRule *
gtk_css_rule_list_get_item (GtkCssRuleList *rule_list,
gsize id)
{
GtkCssRuleListPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_RULE_LIST (rule_list), NULL);
priv = gtk_css_rule_list_get_instance_private (rule_list);
g_return_val_if_fail (id < priv->items->len, NULL);
return g_ptr_array_index (priv->items, id);
}
gsize
gtk_css_rule_list_get_length (GtkCssRuleList *rule_list)
{
GtkCssRuleListPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_RULE_LIST (rule_list), 0);
priv = gtk_css_rule_list_get_instance_private (rule_list);
return priv->items->len;
}

View File

@@ -0,0 +1,69 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_RULE_LIST_PRIVATE_H__
#define __GTK_CSS_RULE_LIST_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_RULE_LIST (gtk_css_rule_list_get_type ())
#define GTK_CSS_RULE_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_RULE_LIST, GtkCssRuleList))
#define GTK_CSS_RULE_LIST_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_RULE_LIST, GtkCssRuleListClass))
#define GTK_IS_CSS_RULE_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_RULE_LIST))
#define GTK_IS_CSS_RULE_LIST_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_RULE_LIST))
#define GTK_CSS_RULE_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_RULE_LIST, GtkCssRuleListClass))
typedef struct _GtkCssRuleList GtkCssRuleList;
typedef struct _GtkCssRuleListClass GtkCssRuleListClass;
struct _GtkCssRuleList
{
GObject parent;
};
struct _GtkCssRuleListClass
{
GObjectClass parent_class;
};
GType gtk_css_rule_list_get_type (void) G_GNUC_CONST;
GtkCssRuleList * gtk_css_rule_list_new (void);
void gtk_css_rule_list_parse (GtkCssRuleList *rule_list,
GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
void gtk_css_rule_list_insert (GtkCssRuleList *rule_list,
gsize id,
GtkCssRule *rule);
void gtk_css_rule_list_append (GtkCssRuleList *rule_list,
GtkCssRule *rule);
/* GtkCSSRule DOM */
GtkCssRule * gtk_css_rule_list_get_item (GtkCssRuleList *rule_list,
gsize id);
gsize gtk_css_rule_list_get_length (GtkCssRuleList *rule_list);
G_END_DECLS
#endif /* __GTK_CSS_RULE_LIST_PRIVATE_H__ */

70
gtk/gtkcssruleprivate.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_RULE_PRIVATE_H__
#define __GTK_CSS_RULE_PRIVATE_H__
#include "gtk/gtkcsstokensourceprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_RULE (gtk_css_rule_get_type ())
#define GTK_CSS_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_RULE, GtkCssRule))
#define GTK_CSS_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_RULE, GtkCssRuleClass))
#define GTK_IS_CSS_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_RULE))
#define GTK_IS_CSS_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_RULE))
#define GTK_CSS_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_RULE, GtkCssRuleClass))
/* forward declaration */
typedef struct _GtkCssStyleSheet GtkCssStyleSheet;
typedef struct _GtkCssRule GtkCssRule;
typedef struct _GtkCssRuleClass GtkCssRuleClass;
struct _GtkCssRule
{
GObject parent;
};
struct _GtkCssRuleClass
{
GObjectClass parent_class;
/* gets the cssText for this rule */
void (* get_css_text) (GtkCssRule *rule,
GString *string);
};
GType gtk_css_rule_get_type (void) G_GNUC_CONST;
GtkCssRule * gtk_css_rule_new_from_at_rule (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
void gtk_css_rule_print_css_text (GtkCssRule *rule,
GString *string);
char * gtk_css_rule_get_css_text (GtkCssRule *rule);
GtkCssRule * gtk_css_rule_get_parent_rule (GtkCssRule *rule);
GtkCssStyleSheet * gtk_css_rule_get_parent_style_sheet (GtkCssRule *rule);
G_END_DECLS
#endif /* __GTK_CSS_RULE_PRIVATE_H__ */

View File

@@ -25,6 +25,8 @@
#include "gtkcssprovider.h"
#include "gtkstylecontextprivate.h"
#include <errno.h>
#include <stdlib.h>
#if defined(_MSC_VER) && _MSC_VER >= 1500
# include <intrin.h>
#endif
@@ -1102,42 +1104,42 @@ parse_selector_pseudo_class_nth_child (GtkCssParser *parser,
return selector;
}
static const struct {
const char *name;
gboolean deprecated;
GtkStateFlags state_flag;
PositionType position_type;
int position_a;
int position_b;
} pseudo_classes[] = {
{ "first-child", 0, 0, POSITION_FORWARD, 0, 1 },
{ "last-child", 0, 0, POSITION_BACKWARD, 0, 1 },
{ "only-child", 0, 0, POSITION_ONLY, 0, 0 },
{ "sorted", 1, 0, POSITION_SORTED, 0, 0 },
{ "active", 0, GTK_STATE_FLAG_ACTIVE, },
{ "prelight", 1, GTK_STATE_FLAG_PRELIGHT, },
{ "hover", 0, GTK_STATE_FLAG_PRELIGHT, },
{ "selected", 0, GTK_STATE_FLAG_SELECTED, },
{ "insensitive", 1, GTK_STATE_FLAG_INSENSITIVE, },
{ "disabled", 0, GTK_STATE_FLAG_INSENSITIVE, },
{ "inconsistent", 1, GTK_STATE_FLAG_INCONSISTENT, },
{ "indeterminate", 0, GTK_STATE_FLAG_INCONSISTENT, },
{ "focused", 1, GTK_STATE_FLAG_FOCUSED, },
{ "focus", 0, GTK_STATE_FLAG_FOCUSED, },
{ "backdrop", 0, GTK_STATE_FLAG_BACKDROP, },
{ "dir(ltr)", 0, GTK_STATE_FLAG_DIR_LTR, },
{ "dir(rtl)", 0, GTK_STATE_FLAG_DIR_RTL, },
{ "link", 0, GTK_STATE_FLAG_LINK, },
{ "visited", 0, GTK_STATE_FLAG_VISITED, },
{ "checked", 0, GTK_STATE_FLAG_CHECKED, },
{ "drop(active)", 0, GTK_STATE_FLAG_DROP_ACTIVE, }
};
static GtkCssSelector *
parse_selector_pseudo_class (GtkCssParser *parser,
GtkCssSelector *selector,
gboolean negate)
{
static const struct {
const char *name;
gboolean deprecated;
GtkStateFlags state_flag;
PositionType position_type;
int position_a;
int position_b;
} pseudo_classes[] = {
{ "first-child", 0, 0, POSITION_FORWARD, 0, 1 },
{ "last-child", 0, 0, POSITION_BACKWARD, 0, 1 },
{ "only-child", 0, 0, POSITION_ONLY, 0, 0 },
{ "sorted", 1, 0, POSITION_SORTED, 0, 0 },
{ "active", 0, GTK_STATE_FLAG_ACTIVE, },
{ "prelight", 1, GTK_STATE_FLAG_PRELIGHT, },
{ "hover", 0, GTK_STATE_FLAG_PRELIGHT, },
{ "selected", 0, GTK_STATE_FLAG_SELECTED, },
{ "insensitive", 1, GTK_STATE_FLAG_INSENSITIVE, },
{ "disabled", 0, GTK_STATE_FLAG_INSENSITIVE, },
{ "inconsistent", 1, GTK_STATE_FLAG_INCONSISTENT, },
{ "indeterminate", 0, GTK_STATE_FLAG_INCONSISTENT, },
{ "focused", 1, GTK_STATE_FLAG_FOCUSED, },
{ "focus", 0, GTK_STATE_FLAG_FOCUSED, },
{ "backdrop", 0, GTK_STATE_FLAG_BACKDROP, },
{ "dir(ltr)", 0, GTK_STATE_FLAG_DIR_LTR, },
{ "dir(rtl)", 0, GTK_STATE_FLAG_DIR_RTL, },
{ "link", 0, GTK_STATE_FLAG_LINK, },
{ "visited", 0, GTK_STATE_FLAG_VISITED, },
{ "checked", 0, GTK_STATE_FLAG_CHECKED, },
{ "drop(active)", 0, GTK_STATE_FLAG_DROP_ACTIVE, }
};
guint i;
if (_gtk_css_parser_try (parser, "nth-child", FALSE))
@@ -1305,6 +1307,660 @@ _gtk_css_selector_parse (GtkCssParser *parser)
return selector;
}
GtkCssSelector *
token_parse_selector_class (GtkCssTokenSource *source,
GtkCssSelector *selector,
gboolean negate)
{
const GtkCssToken *token;
gtk_css_token_source_consume_token (source);
for (token = gtk_css_token_source_peek_token (source);
gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT);
token = gtk_css_token_source_peek_token (source))
{
gtk_css_token_source_consume_token (source);
}
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_CLASS
: &GTK_CSS_SELECTOR_CLASS,
selector);
selector->style_class.style_class = g_quark_from_string (token->string.string);
gtk_css_token_source_consume_token (source);
return selector;
}
else
{
gtk_css_token_source_error (source, "No class name after '.' in selector");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
}
static gboolean
string_has_number (const char *string,
const char *prefix,
int *number)
{
gsize len = strlen (prefix);
char *end;
if (g_ascii_strncasecmp (string, prefix, len) != 0)
return FALSE;
errno = 0;
*number = strtoul (string + len, &end, 10);
if (*end != '\0' || errno != 0)
return FALSE;
return TRUE;
}
static gboolean
parse_plus_b (GtkCssTokenSource *source,
gboolean negate,
gint *b)
{
const GtkCssToken *token;
gboolean has_seen_sign;
token = gtk_css_token_source_get_token (source);
if (negate)
{
has_seen_sign = TRUE;
}
else
{
if (gtk_css_token_is_delim (token, '+'))
{
gtk_css_token_source_consume_token (source);
has_seen_sign = TRUE;
}
else if (gtk_css_token_is_delim (token, '-'))
{
gtk_css_token_source_consume_token (source);
negate = TRUE;
has_seen_sign = TRUE;
}
}
token = gtk_css_token_source_get_token (source);
if (!has_seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER))
{
*b = token->number.number;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (has_seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
*b = token->number.number;
if (negate)
*b = - *b;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (!has_seen_sign)
{
*b = 0;
return TRUE;
}
gtk_css_token_source_error (source, "Not a valid an+b type");
return FALSE;
}
gboolean
parse_n_plus_b (GtkCssTokenSource *source,
gint before,
gint *a,
gint *b)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "n"))
{
*a = before;
gtk_css_token_source_consume_token (source);
return parse_plus_b (source, FALSE, b);
}
else if (gtk_css_token_is_ident (token, "n-"))
{
*a = before;
gtk_css_token_source_consume_token (source);
return parse_plus_b (source, TRUE, b);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
string_has_number (token->string.string, "n-", b))
{
*a = before;
*b = -*b;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else
{
*b = before;
*a = 0;
return TRUE;
}
gtk_css_token_source_error (source, "Not a valid an+b type");
return FALSE;
}
gboolean
parse_a_n_plus_b (GtkCssTokenSource *source,
gint seen_sign,
gint *a,
gint *b)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (!seen_sign && gtk_css_token_is_ident (token, "even"))
{
*a = 2;
*b = 0;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (!seen_sign && gtk_css_token_is_ident (token, "odd"))
{
*a = 2;
*b = 1;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (!seen_sign && gtk_css_token_is_delim (token, '+'))
{
gtk_css_token_source_consume_token (source);
return parse_a_n_plus_b (source, 1, a, b);
}
else if (!seen_sign && gtk_css_token_is_delim (token, '-'))
{
gtk_css_token_source_consume_token (source);
return parse_a_n_plus_b (source, -1, a, b);
}
else if ((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER)) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
int x = token->number.number * (seen_sign ? seen_sign : 1);
gtk_css_token_source_consume_token (source);
return parse_n_plus_b (source, x , a, b);
}
else if (((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)) &&
g_ascii_strcasecmp (token->dimension.dimension, "n") == 0)
{
*a = token->dimension.value * (seen_sign ? seen_sign : 1);
gtk_css_token_source_consume_token (source);
return parse_plus_b (source, FALSE, b);
}
else if (((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)) &&
g_ascii_strcasecmp (token->dimension.dimension, "n-") == 0)
{
*a = token->dimension.value * (seen_sign ? seen_sign : 1);
gtk_css_token_source_consume_token (source);
return parse_plus_b (source, TRUE, b);
}
else if (((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)) &&
string_has_number (token->dimension.dimension, "n-", b))
{
*a = token->dimension.value * (seen_sign ? seen_sign : 1);
*b = -*b;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (!seen_sign && gtk_css_token_is_ident (token, "-n"))
{
*a = -1;
gtk_css_token_source_consume_token (source);
return parse_plus_b (source, FALSE, b);
}
else if (!seen_sign && gtk_css_token_is_ident (token, "-n-"))
{
*a = -1;
gtk_css_token_source_consume_token (source);
return parse_plus_b (source, TRUE, b);
}
else if (!seen_sign &&
gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
string_has_number (token->string.string, "-n-", b))
{
*a = -1;
*b = -*b;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (gtk_css_token_is_ident (token, "n") ||
gtk_css_token_is_ident (token, "n-"))
{
return parse_n_plus_b (source, seen_sign ? seen_sign : 1, a, b);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
string_has_number (token->string.string, "n-", b))
{
*a = seen_sign ? seen_sign : 1;
*b = -*b;
gtk_css_token_source_consume_token (source);
return TRUE;
}
else if (!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
string_has_number (token->string.string, "-n-", b))
{
*a = -1;
*b = -*b;
gtk_css_token_source_consume_token (source);
return TRUE;
}
gtk_css_token_source_error (source, "Not a valid an+b type");
return FALSE;
}
GtkCssSelector *
token_parse_selector_pseudo_class (GtkCssTokenSource *source,
GtkCssSelector *selector,
gboolean negate)
{
const GtkCssToken *token;
gtk_css_token_source_consume_token (source);
for (token = gtk_css_token_source_peek_token (source);
gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT);
token = gtk_css_token_source_peek_token (source))
{
gtk_css_token_source_consume_token (source);
}
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
guint i;
for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
{
if (g_ascii_strcasecmp (pseudo_classes[i].name, token->string.string) == 0)
{
if (pseudo_classes[i].state_flag)
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
: &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
selector);
selector->state.state = pseudo_classes[i].state_flag;
if (pseudo_classes[i].deprecated)
{
if (pseudo_classes[i + 1].state_flag == pseudo_classes[i].state_flag)
gtk_css_token_source_deprecated (source,
"The :%s pseudo-class is deprecated. Use :%s instead.",
pseudo_classes[i].name,
pseudo_classes[i + 1].name);
else
gtk_css_token_source_deprecated (source,
"The :%s pseudo-class is deprecated.",
pseudo_classes[i].name);
}
}
else
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
: &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
selector);
selector->position.type = pseudo_classes[i].position_type;
selector->position.a = pseudo_classes[i].position_a;
selector->position.b = pseudo_classes[i].position_b;
}
gtk_css_token_source_consume_token (source);
return selector;
}
}
gtk_css_token_source_unknown (source, "Unknown name of pseudo-class");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_FUNCTION))
{
gint a, b;
if (gtk_css_token_is_function (token, "nth-child"))
{
gtk_css_token_source_consume_token (source);
if (parse_a_n_plus_b (source, 0, &a, &b))
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
: &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
selector);
selector->position.type = POSITION_FORWARD;
selector->position.a = a;
selector->position.b = b;
}
else
{
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Expected ')' at end of :nth-child()");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_function (token, "nth-last-child"))
{
gtk_css_token_source_consume_token (source);
if (parse_a_n_plus_b (source, 0, &a, &b))
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
: &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
selector);
selector->position.type = POSITION_BACKWARD;
selector->position.a = a;
selector->position.b = b;
}
else
{
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Expected ')' at end of :nth-last-child()");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_function (token, "not"))
{
if (negate)
{
gtk_css_token_source_error (source, "Nesting of :not() not allowed");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
else
{
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_delim (token, '*'))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_ANY, selector);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_NAME, selector);
selector->name.name = g_intern_string (token->string.string);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_ID, selector);
selector->id.name = g_intern_string (token->string.string);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_delim (token, '.'))
{
selector = token_parse_selector_class (source, selector, TRUE);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
selector = token_parse_selector_pseudo_class (source, selector, TRUE);
}
else
{
gtk_css_token_source_error (source, "Invalid contents of :not() selector");
if (selector)
_gtk_css_selector_free (selector);
selector = NULL;
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_consume_token (source);
}
else
{
gtk_css_token_source_error (source, "Invalid contents of :not() selector");
if (selector)
_gtk_css_selector_free (selector);
selector = NULL;
return NULL;
}
}
}
else if (gtk_css_token_is_function (token, "dir"))
{
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "ltr"))
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
: &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
selector);
selector->state.state = GTK_STATE_FLAG_DIR_LTR;
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "rtl"))
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
: &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
selector);
selector->state.state = GTK_STATE_FLAG_DIR_LTR;
gtk_css_token_source_consume_token (source);
}
else
{
gtk_css_token_source_error (source, "Expected :dir(ltr) or :dir(rtl)");
if (selector)
_gtk_css_selector_free (selector);
selector = NULL;
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Expected ')' at end of :dir()");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_function (token, "drop"))
{
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "active"))
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
: &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
selector);
selector->state.state = GTK_STATE_FLAG_DROP_ACTIVE;
gtk_css_token_source_consume_token (source);
}
else
{
gtk_css_token_source_error (source, "Expected :drop(active)");
if (selector)
_gtk_css_selector_free (selector);
selector = NULL;
return NULL;
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Expected ')' at end of :drop()");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else
{
gtk_css_token_source_unknown (source, "Unknown pseudoclass");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
}
else
{
gtk_css_token_source_error (source, "Unknown pseudoclass");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
return selector;
}
GtkCssSelector *
token_parse_simple_selector (GtkCssTokenSource *source,
GtkCssSelector *selector)
{
gboolean parsed_something = FALSE;
const GtkCssToken *token;
do {
for (token = gtk_css_token_source_peek_token (source);
gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT);
token = gtk_css_token_source_peek_token (source))
{
gtk_css_token_source_consume_token (source);
}
if (!parsed_something && gtk_css_token_is_delim (token, '*'))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ANY, selector);
gtk_css_token_source_consume_token (source);
}
else if (!parsed_something && gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NAME, selector);
selector->name.name = g_intern_string (token->string.string);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ID, selector);
selector->id.name = g_intern_string (token->string.string);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_delim (token, '.'))
{
selector = token_parse_selector_class (source, selector, FALSE);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
selector = token_parse_selector_pseudo_class (source, selector, FALSE);
}
else
{
if (!parsed_something)
{
gtk_css_token_source_error (source, "Expected a valid selector");
if (selector)
_gtk_css_selector_free (selector);
selector = NULL;
}
break;
}
parsed_something = TRUE;
}
while (TRUE);
return selector;
}
GtkCssSelector *
gtk_css_selector_token_parse (GtkCssTokenSource *source)
{
GtkCssSelector *selector = NULL;
const GtkCssToken *token;
while (TRUE)
{
gboolean seen_whitespace = FALSE;
selector = token_parse_simple_selector (source, selector);
if (selector == NULL)
{
gtk_css_token_source_consume_all (source);
return NULL;
}
for (token = gtk_css_token_source_peek_token (source);
gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
token = gtk_css_token_source_peek_token (source))
{
seen_whitespace |= gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
gtk_css_token_source_consume_token (source);
}
if (gtk_css_token_is_delim (token, '+'))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ADJACENT, selector);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_delim (token, '~'))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_SIBLING, selector);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_delim (token, '>'))
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_CHILD, selector);
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
break;
}
else if (seen_whitespace)
{
selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_DESCENDANT, selector);
}
else
{
gtk_css_token_source_error (source, "Expected a valid selector");
_gtk_css_selector_free (selector);
gtk_css_token_source_consume_all (source);
return NULL;
}
token = gtk_css_token_source_get_token (source);
}
return selector;
}
void
_gtk_css_selector_free (GtkCssSelector *selector)
{

View File

@@ -20,6 +20,7 @@
#include "gtk/gtkcssmatcherprivate.h"
#include "gtk/gtkcssparserprivate.h"
#include "gtk/gtkcsstokensourceprivate.h"
G_BEGIN_DECLS
@@ -28,6 +29,7 @@ typedef struct _GtkCssSelectorTree GtkCssSelectorTree;
typedef struct _GtkCssSelectorTreeBuilder GtkCssSelectorTreeBuilder;
GtkCssSelector * _gtk_css_selector_parse (GtkCssParser *parser);
GtkCssSelector * gtk_css_selector_token_parse (GtkCssTokenSource *parser);
void _gtk_css_selector_free (GtkCssSelector *selector);
char * _gtk_css_selector_to_string (const GtkCssSelector *selector);

View File

@@ -240,6 +240,46 @@ _gtk_css_shadows_value_parse (GtkCssParser *parser,
return result;
}
GtkCssValue *
gtk_css_shadows_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode)
{
GtkCssValue *value, *result;
const GtkCssToken *token;
GPtrArray *values;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "none"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_shadows_value_new_none ();
}
values = g_ptr_array_new ();
while (TRUE)
{
value = gtk_css_shadow_value_token_parse (source, box_shadow_mode);
if (value == NULL)
{
g_ptr_array_set_free_func (values, (GDestroyNotify) _gtk_css_value_unref);
g_ptr_array_free (values, TRUE);
return NULL;
}
g_ptr_array_add (values, value);
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);
}
result = gtk_css_shadows_value_new ((GtkCssValue **) values->pdata, values->len);
g_ptr_array_free (values, TRUE);
return result;
}
gboolean
_gtk_css_shadows_value_is_none (const GtkCssValue *shadows)
{

View File

@@ -25,6 +25,7 @@
#include "gtktypes.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtkroundedboxprivate.h"
@@ -33,6 +34,8 @@ G_BEGIN_DECLS
GtkCssValue * _gtk_css_shadows_value_new_none (void);
GtkCssValue * _gtk_css_shadows_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode);
GtkCssValue * gtk_css_shadows_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode);
gboolean _gtk_css_shadows_value_is_none (const GtkCssValue *shadows);

View File

@@ -293,6 +293,104 @@ fail:
return NULL;
}
GtkCssValue *
gtk_css_shadow_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode)
{
enum {
HOFFSET,
VOFFSET,
RADIUS,
SPREAD,
COLOR,
N_VALUES
};
GtkCssValue *values[N_VALUES] = { NULL, };
gboolean inset = FALSE;
const GtkCssToken *token;
guint i;
for (token = gtk_css_token_source_get_token (source);
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
token = gtk_css_token_source_get_token (source))
{
if (box_shadow_mode && !inset &&
gtk_css_token_is_ident (token, "inset"))
{
inset = TRUE;
gtk_css_token_source_consume_token (source);
}
else if (values[COLOR] == NULL && gtk_css_color_value_check_token (token))
{
values[COLOR] = gtk_css_color_value_token_parse (source);
if (values[COLOR] == NULL)
goto fail;
}
else if (values[HOFFSET] == NULL && gtk_css_number_value_check_token (token))
{
values[HOFFSET] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[HOFFSET] == NULL)
goto fail;
values[VOFFSET] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[VOFFSET] == NULL)
goto fail;
if (gtk_css_number_value_check_token (gtk_css_token_source_get_token (source)))
{
values[RADIUS] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_POSITIVE_ONLY
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[RADIUS] == NULL)
goto fail;
}
else
values[RADIUS] = _gtk_css_number_value_new (0.0, GTK_CSS_PX);
if (box_shadow_mode &&
gtk_css_number_value_check_token (gtk_css_token_source_get_token (source)))
{
values[SPREAD] = gtk_css_number_value_token_parse (source,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_NUMBER_AS_PIXELS);
if (values[SPREAD] == NULL)
goto fail;
}
else
values[SPREAD] = _gtk_css_number_value_new (0.0, GTK_CSS_PX);
}
else if (values[HOFFSET] == NULL)
{
gtk_css_token_source_error (source, "Expected a shadow definition");
gtk_css_token_source_consume_all (source);
goto fail;
}
else
break;
}
if (values[COLOR] == NULL)
values[COLOR] = _gtk_css_color_value_new_current_color ();
return gtk_css_shadow_value_new (values[HOFFSET], values[VOFFSET],
values[RADIUS], values[SPREAD],
inset, values[COLOR]);
fail:
for (i = 0; i < N_VALUES; i++)
{
if (values[i])
_gtk_css_value_unref (values[i]);
}
return NULL;
}
static gboolean
needs_blur (const GtkCssValue *shadow)
{

View File

@@ -25,6 +25,7 @@
#include "gtktypes.h"
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtkroundedboxprivate.h"
@@ -34,6 +35,8 @@ GtkCssValue * _gtk_css_shadow_value_new_for_transition (GtkCssValue
GtkCssValue * _gtk_css_shadow_value_parse (GtkCssParser *parser,
gboolean box_shadow_mode);
GtkCssValue * gtk_css_shadow_value_token_parse (GtkCssTokenSource *source,
gboolean box_shadow_mode);
gboolean _gtk_css_shadow_value_get_inset (const GtkCssValue *shadow);

View File

@@ -0,0 +1,205 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssshorthanddeclarationprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcssshorthandpropertyprivate.h"
typedef struct _GtkCssShorthandDeclarationPrivate GtkCssShorthandDeclarationPrivate;
struct _GtkCssShorthandDeclarationPrivate {
GtkCssShorthandProperty *prop;
GtkCssValue **values;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssShorthandDeclaration, gtk_css_shorthand_declaration, GTK_TYPE_CSS_DECLARATION)
static void
gtk_css_shorthand_declaration_finalize (GObject *object)
{
GtkCssShorthandDeclaration *shorthand = GTK_CSS_SHORTHAND_DECLARATION (object);
GtkCssShorthandDeclarationPrivate *priv = gtk_css_shorthand_declaration_get_instance_private (shorthand);
guint i;
if (priv->values)
{
for (i = 0; i < gtk_css_shorthand_declaration_get_length (shorthand); i++)
{
_gtk_css_value_unref (priv->values[i]);
}
g_free (priv->values);
}
G_OBJECT_CLASS (gtk_css_shorthand_declaration_parent_class)->finalize (object);
}
static const char *
gtk_css_shorthand_declaration_get_name (GtkCssDeclaration *decl)
{
GtkCssShorthandDeclaration *shorthand_declaration = GTK_CSS_SHORTHAND_DECLARATION (decl);
GtkCssShorthandDeclarationPrivate *priv = gtk_css_shorthand_declaration_get_instance_private (shorthand_declaration);
return _gtk_style_property_get_name (GTK_STYLE_PROPERTY (priv->prop));
}
static void
gtk_css_shorthand_declaration_print_value (GtkCssDeclaration *decl,
GString *string)
{
GtkCssShorthandDeclaration *shorthand = GTK_CSS_SHORTHAND_DECLARATION (decl);
GtkCssShorthandDeclarationPrivate *priv = gtk_css_shorthand_declaration_get_instance_private (shorthand);
guint i;
/* XXX */
for (i = 0; i < gtk_css_shorthand_declaration_get_length (shorthand); i++)
{
if (i > 0)
g_string_append (string, ", ");
_gtk_css_value_print (priv->values[i], string);
}
}
static void
gtk_css_shorthand_declaration_class_init (GtkCssShorthandDeclarationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCssDeclarationClass *decl_class = GTK_CSS_DECLARATION_CLASS (klass);
object_class->finalize = gtk_css_shorthand_declaration_finalize;
decl_class->get_name = gtk_css_shorthand_declaration_get_name;
decl_class->print_value = gtk_css_shorthand_declaration_print_value;
}
static void
gtk_css_shorthand_declaration_init (GtkCssShorthandDeclaration *shorthand_declaration)
{
}
GtkCssDeclaration *
gtk_css_shorthand_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source)
{
GtkCssShorthandDeclarationPrivate *priv;
const GtkCssToken *token;
GtkCssShorthandDeclaration *decl;
GtkCssValue *array;
guint i;
char *name;
decl = g_object_new (GTK_TYPE_CSS_SHORTHAND_DECLARATION,
"parent-style", style,
NULL);
priv = gtk_css_shorthand_declaration_get_instance_private (decl);
gtk_css_token_source_set_consumer (source, G_OBJECT (decl));
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected a property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
name = g_utf8_strdown (token->string.string, -1);
priv->prop = (GtkCssShorthandProperty *) _gtk_style_property_lookup (name);
if (!GTK_IS_CSS_SHORTHAND_PROPERTY (priv->prop))
{
gtk_css_token_source_unknown (source, "Property name '%s' is not a shorthand property", token->string.string);
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
g_free (name);
return NULL;
}
else if (!g_str_equal (name, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (priv->prop))))
gtk_css_token_source_deprecated (source,
"The '%s' property has been renamed to '%s'",
name, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (priv->prop)));
gtk_css_token_source_consume_token (source);
g_free (name);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
gtk_css_token_source_error (source, "No colon following property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
gtk_css_token_source_consume_token (source);
array = gtk_style_property_token_parse (GTK_STYLE_PROPERTY (priv->prop), source);
if (array == NULL)
{
g_object_unref (decl);
return NULL;
}
priv->values = g_new (GtkCssValue *, gtk_css_shorthand_declaration_get_length (decl));
for (i = 0; i < gtk_css_shorthand_declaration_get_length (decl); i++)
{
priv->values[i] = _gtk_css_value_ref (_gtk_css_array_value_get_nth (array, i));
}
_gtk_css_value_unref (array);
return GTK_CSS_DECLARATION (decl);
}
guint
gtk_css_shorthand_declaration_get_length (GtkCssShorthandDeclaration *decl)
{
GtkCssShorthandDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_SHORTHAND_DECLARATION (decl), 0);
priv = gtk_css_shorthand_declaration_get_instance_private (decl);
return _gtk_css_shorthand_property_get_n_subproperties (priv->prop);
}
GtkCssStyleProperty *
gtk_css_shorthand_declaration_get_subproperty (GtkCssShorthandDeclaration *decl,
guint id)
{
GtkCssShorthandDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_SHORTHAND_DECLARATION (decl), NULL);
g_return_val_if_fail (id < gtk_css_shorthand_declaration_get_length (decl), NULL);
priv = gtk_css_shorthand_declaration_get_instance_private (decl);
return _gtk_css_shorthand_property_get_subproperty (priv->prop, id);
}
GtkCssValue *
gtk_css_shorthand_declaration_get_value (GtkCssShorthandDeclaration *decl,
guint id)
{
GtkCssShorthandDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_SHORTHAND_DECLARATION (decl), NULL);
g_return_val_if_fail (id < gtk_css_shorthand_declaration_get_length (decl), NULL);
priv = gtk_css_shorthand_declaration_get_instance_private (decl);
return priv->values[id];
}

View File

@@ -0,0 +1,64 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_SHORTHAND_DECLARATION_PRIVATE_H__
#define __GTK_CSS_SHORTHAND_DECLARATION_PRIVATE_H__
#include "gtk/gtkcssdeclarationprivate.h"
#include "gtk/gtkcssshorthandpropertyprivate.h"
#include "gtk/gtkcssvalueprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_SHORTHAND_DECLARATION (gtk_css_shorthand_declaration_get_type ())
#define GTK_CSS_SHORTHAND_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_SHORTHAND_DECLARATION, GtkCssShorthandDeclaration))
#define GTK_CSS_SHORTHAND_DECLARATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_SHORTHAND_DECLARATION, GtkCssShorthandDeclarationClass))
#define GTK_IS_CSS_SHORTHAND_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_SHORTHAND_DECLARATION))
#define GTK_IS_CSS_SHORTHAND_DECLARATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_SHORTHAND_DECLARATION))
#define GTK_CSS_SHORTHAND_DECLARATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_SHORTHAND_DECLARATION, GtkCssShorthandDeclarationClass))
typedef struct _GtkCssShorthandDeclaration GtkCssShorthandDeclaration;
typedef struct _GtkCssShorthandDeclarationClass GtkCssShorthandDeclarationClass;
struct _GtkCssShorthandDeclaration
{
GtkCssDeclaration parent;
};
struct _GtkCssShorthandDeclarationClass
{
GtkCssDeclarationClass parent_class;
};
GType gtk_css_shorthand_declaration_get_type (void) G_GNUC_CONST;
GtkCssDeclaration * gtk_css_shorthand_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source);
guint gtk_css_shorthand_declaration_get_length (GtkCssShorthandDeclaration *decl);
GtkCssStyleProperty * gtk_css_shorthand_declaration_get_subproperty (GtkCssShorthandDeclaration *decl,
guint id);
GtkCssValue * gtk_css_shorthand_declaration_get_value (GtkCssShorthandDeclaration *decl,
guint id);
G_END_DECLS
#endif /* __GTK_CSS_SHORTHAND_DECLARATION_PRIVATE_H__ */

View File

@@ -156,6 +156,112 @@ gtk_css_shorthand_property_parse_value (GtkStyleProperty *property,
return result;
}
static GtkCssValue *
gtk_css_shorthand_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
const GtkCssToken *token;
GtkCssValue **data;
GtkCssValue *result;
guint i;
data = g_new0 (GtkCssValue *, shorthand->subproperties->len);
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "initial"))
{
/* the initial value can be explicitly specified with the
* initial keyword which all properties accept.
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
data[i] = _gtk_css_initial_value_new ();
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "inherit"))
{
/* All properties accept the inherit value which
* explicitly specifies that the value will be determined
* by inheritance. The inherit value can be used to
* strengthen inherited values in the cascade, and it can
* also be used on properties that are not normally inherited.
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
data[i] = _gtk_css_inherit_value_new ();
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "unset"))
{
/* If the cascaded value of a property is the unset keyword,
* then if it is an inherited property, this is treated as
* inherit, and if it is not, this is treated as initial.
*/
for (i = 0; i < shorthand->subproperties->len; i++)
{
data[i] = _gtk_css_unset_value_new ();
}
gtk_css_token_source_consume_token (source);
}
else if (!shorthand->token_parse (shorthand, data, source))
{
for (i = 0; i < shorthand->subproperties->len; i++)
{
if (data[i] != NULL)
_gtk_css_value_unref (data[i]);
}
g_free (data);
return NULL;
}
/* All values that aren't set by the parse func are set to their
* default values here.
* XXX: Is the default always initial or can it be inherit? */
for (i = 0; i < shorthand->subproperties->len; i++)
{
if (data[i] == NULL)
data[i] = _gtk_css_initial_value_new ();
}
result = _gtk_css_array_value_new_from_array (data, shorthand->subproperties->len);
g_free (data);
return result;
}
static void
forward_error_to_source (GtkCssParser *parser,
const GError *error,
gpointer source)
{
/* XXX: This is bad because it doesn't emit the error on the right token */
gtk_css_token_source_emit_error (source, error);
}
static gboolean
gtk_css_shorthand_token_parse_default (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssTokenSource *source)
{
GtkCssParser *parser;
char *str;
gboolean result;
str = gtk_css_token_source_consume_to_string (source);
parser = _gtk_css_parser_new (str,
NULL,
forward_error_to_source,
source);
result = shorthand->parse (shorthand, values, parser);
_gtk_css_parser_free (parser);
g_free (str);
return result;
}
static void
_gtk_css_shorthand_property_class_init (GtkCssShorthandPropertyClass *klass)
{
@@ -175,12 +281,15 @@ _gtk_css_shorthand_property_class_init (GtkCssShorthandPropertyClass *klass)
property_class->assign = _gtk_css_shorthand_property_assign;
property_class->query = _gtk_css_shorthand_property_query;
property_class->parse_value = gtk_css_shorthand_property_parse_value;
property_class->token_parse = gtk_css_shorthand_property_token_parse;
}
static void
_gtk_css_shorthand_property_init (GtkCssShorthandProperty *shorthand)
{
shorthand->subproperties = g_ptr_array_new_with_free_func (g_object_unref);
shorthand->token_parse = gtk_css_shorthand_token_parse_default;
}
GtkCssStyleProperty *

View File

@@ -41,6 +41,9 @@ typedef struct _GtkCssShorthandPropertyClass GtkCssShorthandPropertyClass;
typedef gboolean (* GtkCssShorthandPropertyParseFunc) (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssParser *parser);
typedef gboolean (* GtkCssShorthandPropertyTokenParseFunc) (GtkCssShorthandProperty *shorthand,
GtkCssValue **values,
GtkCssTokenSource *source);
typedef void (* GtkCssShorthandPropertyAssignFunc) (GtkCssShorthandProperty *shorthand,
GtkStyleProperties *props,
GtkStateFlags state,
@@ -57,6 +60,7 @@ struct _GtkCssShorthandProperty
GPtrArray *subproperties;
GtkCssShorthandPropertyParseFunc parse;
GtkCssShorthandPropertyTokenParseFunc token_parse;
GtkCssShorthandPropertyAssignFunc assign;
GtkCssShorthandPropertyQueryFunc query;
};

View File

@@ -0,0 +1,132 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssstyledeclarationprivate.h"
#include "gtkcssdeclarationprivate.h"
typedef struct _GtkCssStyleDeclarationPrivate GtkCssStyleDeclarationPrivate;
struct _GtkCssStyleDeclarationPrivate {
GPtrArray *declarations;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssStyleDeclaration, gtk_css_style_declaration, G_TYPE_OBJECT)
static void
gtk_css_style_declaration_finalize (GObject *object)
{
GtkCssStyleDeclaration *style_declaration = GTK_CSS_STYLE_DECLARATION (object);
GtkCssStyleDeclarationPrivate *priv = gtk_css_style_declaration_get_instance_private (style_declaration);
g_ptr_array_unref (priv->declarations);
G_OBJECT_CLASS (gtk_css_style_declaration_parent_class)->finalize (object);
}
static void
gtk_css_style_declaration_class_init (GtkCssStyleDeclarationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_style_declaration_finalize;
}
static void
gtk_css_style_declaration_init (GtkCssStyleDeclaration *style_declaration)
{
GtkCssStyleDeclarationPrivate *priv = gtk_css_style_declaration_get_instance_private (style_declaration);
priv->declarations = g_ptr_array_new_with_free_func (g_object_unref);
}
GtkCssStyleDeclaration *
gtk_css_style_declaration_new (GtkCssRule *parent_rule)
{
return g_object_new (GTK_TYPE_CSS_STYLE_DECLARATION, NULL);
}
void
gtk_css_style_declaration_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source)
{
GtkCssStyleDeclarationPrivate *priv;
GtkCssTokenSource *decl_source;
GtkCssDeclaration *declaration;
const GtkCssToken *token;
priv = gtk_css_style_declaration_get_instance_private (style);
gtk_css_token_source_set_consumer (source, G_OBJECT (style));
for (token = gtk_css_token_source_get_token (source);
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
token = gtk_css_token_source_get_token (source))
{
if (gtk_css_token_is (token, GTK_CSS_TOKEN_SEMICOLON) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE))
{
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
decl_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_SEMICOLON);
declaration = gtk_css_declaration_new_parse (style, decl_source);
if (declaration)
g_ptr_array_add (priv->declarations, declaration);
gtk_css_token_source_unref (decl_source);
gtk_css_token_source_consume_token (source);
}
else
{
gtk_css_token_source_error (source, "Expected property declaration");
decl_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_SEMICOLON);
gtk_css_token_source_consume_all (decl_source);
gtk_css_token_source_unref (decl_source);
gtk_css_token_source_consume_token (source);
}
}
}
GtkCssDeclaration *
gtk_css_style_declaration_get_declaration (GtkCssStyleDeclaration *declaration,
gssize id)
{
GtkCssStyleDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_DECLARATION (declaration), NULL);
priv = gtk_css_style_declaration_get_instance_private (declaration);
g_return_val_if_fail (id < priv->declarations->len, NULL);
return g_ptr_array_index (priv->declarations, id);
}
gsize
gtk_css_style_declaration_get_length (GtkCssStyleDeclaration *declaration)
{
GtkCssStyleDeclarationPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_DECLARATION (declaration), 0);
priv = gtk_css_style_declaration_get_instance_private (declaration);
return priv->declarations->len;
}

View File

@@ -0,0 +1,70 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_STYLE_DECLARATION_PRIVATE_H__
#define __GTK_CSS_STYLE_DECLARATION_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_STYLE_DECLARATION (gtk_css_style_declaration_get_type ())
#define GTK_CSS_STYLE_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_STYLE_DECLARATION, GtkCssStyleDeclaration))
#define GTK_CSS_STYLE_DECLARATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_STYLE_DECLARATION, GtkCssStyleDeclarationClass))
#define GTK_IS_CSS_STYLE_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_STYLE_DECLARATION))
#define GTK_IS_CSS_STYLE_DECLARATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_STYLE_DECLARATION))
#define GTK_CSS_STYLE_DECLARATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_STYLE_DECLARATION, GtkCssStyleDeclarationClass))
typedef struct _GtkCssDeclaration GtkCssDeclaration;
typedef struct _GtkCssStyleDeclaration GtkCssStyleDeclaration;
typedef struct _GtkCssStyleDeclarationClass GtkCssStyleDeclarationClass;
struct _GtkCssStyleDeclaration
{
GObject parent;
};
struct _GtkCssStyleDeclarationClass
{
GObjectClass parent_class;
};
GType gtk_css_style_declaration_get_type (void) G_GNUC_CONST;
GtkCssStyleDeclaration *gtk_css_style_declaration_new (GtkCssRule *parent_rule);
void gtk_css_style_declaration_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source);
GtkCssDeclaration * gtk_css_style_declaration_get_declaration (GtkCssStyleDeclaration *declaration,
gssize id);
/* GtkCssStyleDeclaration DOM */
void gtk_css_style_declaration_print_css_text (GtkCssStyleDeclaration *declaration,
GString *string);
char * gtk_css_style_declaration_get_css_text (GtkCssStyleDeclaration *declaration);
gsize gtk_css_style_declaration_get_length (GtkCssStyleDeclaration *declaration);
char * gtk_css_style_declaration_get_item (GtkCssStyleDeclaration *declaration,
gssize size);
G_END_DECLS
#endif /* __GTK_CSS_STYLE_DECLARATION_PRIVATE_H__ */

View File

@@ -192,6 +192,51 @@ gtk_css_style_property_parse_value (GtkStyleProperty *property,
return (* style_property->parse_value) (style_property, parser);
}
static GtkCssValue *
gtk_css_style_property_token_parse (GtkStyleProperty *property,
GtkCssTokenSource *source)
{
GtkCssStyleProperty *style_property = GTK_CSS_STYLE_PROPERTY (property);
const GtkCssToken *token;
GtkCssValue *value;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "initial"))
{
/* the initial value can be explicitly specified with the
* initial keyword which all properties accept.
*/
value = _gtk_css_initial_value_new ();
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "inherit"))
{
/* All properties accept the inherit value which
* explicitly specifies that the value will be determined
* by inheritance. The inherit value can be used to
* strengthen inherited values in the cascade, and it can
* also be used on properties that are not normally inherited.
*/
value = _gtk_css_inherit_value_new ();
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is_ident (token, "unset"))
{
/* If the cascaded value of a property is the unset keyword,
* then if it is an inherited property, this is treated as
* inherit, and if it is not, this is treated as initial.
*/
value = _gtk_css_unset_value_new ();
gtk_css_token_source_consume_token (source);
}
else
{
value = (* style_property->token_parse) (source);
}
return value;
}
static void
_gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
{
@@ -242,6 +287,7 @@ _gtk_css_style_property_class_init (GtkCssStylePropertyClass *klass)
property_class->assign = _gtk_css_style_property_assign;
property_class->query = _gtk_css_style_property_query;
property_class->parse_value = gtk_css_style_property_parse_value;
property_class->token_parse = gtk_css_style_property_token_parse;
klass->style_properties = g_ptr_array_new ();
@@ -256,10 +302,18 @@ gtk_css_style_property_real_parse_value (GtkCssStyleProperty *property,
return NULL;
}
static GtkCssValue *
gtk_css_style_property_real_token_parse (GtkCssTokenSource *source)
{
g_assert_not_reached ();
return NULL;
}
static void
_gtk_css_style_property_init (GtkCssStyleProperty *property)
{
property->parse_value = gtk_css_style_property_real_parse_value;
property->token_parse = gtk_css_style_property_real_token_parse;
}
/**

File diff suppressed because it is too large Load Diff

View File

@@ -34,13 +34,14 @@ G_BEGIN_DECLS
typedef struct _GtkCssStyleProperty GtkCssStyleProperty;
typedef struct _GtkCssStylePropertyClass GtkCssStylePropertyClass;
typedef GtkCssValue * (* GtkCssStylePropertyParseFunc) (GtkCssStyleProperty *property,
GtkCssParser *parser);
typedef void (* GtkCssStylePropertyQueryFunc) (GtkCssStyleProperty *property,
const GtkCssValue *cssvalue,
GValue *value);
typedef GtkCssValue * (* GtkCssStylePropertyAssignFunc) (GtkCssStyleProperty *property,
const GValue *value);
typedef GtkCssValue * (* GtkCssStylePropertyParseFunc) (GtkCssStyleProperty *property,
GtkCssParser *parser);
typedef GtkCssValue * (* GtkCssStylePropertyTokenParseFunc) (GtkCssTokenSource *source);
typedef void (* GtkCssStylePropertyQueryFunc) (GtkCssStyleProperty *property,
const GtkCssValue *cssvalue,
GValue *value);
typedef GtkCssValue * (* GtkCssStylePropertyAssignFunc) (GtkCssStyleProperty *property,
const GValue *value);
struct _GtkCssStyleProperty
{
GtkStyleProperty parent;
@@ -52,6 +53,7 @@ struct _GtkCssStyleProperty
guint animated :1;
GtkCssStylePropertyParseFunc parse_value;
GtkCssStylePropertyTokenParseFunc token_parse;
GtkCssStylePropertyQueryFunc query_value;
GtkCssStylePropertyAssignFunc assign_value;
};

179
gtk/gtkcssstylerule.c Normal file
View File

@@ -0,0 +1,179 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssstyleruleprivate.h"
#include "gtkcssselectorprivate.h"
#include "gtkcssstylesheetprivate.h"
typedef struct _GtkCssStyleRulePrivate GtkCssStyleRulePrivate;
struct _GtkCssStyleRulePrivate {
GPtrArray *selectors;
GtkCssStyleDeclaration *style;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssStyleRule, gtk_css_style_rule, GTK_TYPE_CSS_RULE)
static void
gtk_css_style_rule_finalize (GObject *object)
{
GtkCssStyleRule *style_rule = GTK_CSS_STYLE_RULE (object);
GtkCssStyleRulePrivate *priv = gtk_css_style_rule_get_instance_private (style_rule);
g_ptr_array_unref (priv->selectors);
g_object_unref (priv->style);
G_OBJECT_CLASS (gtk_css_style_rule_parent_class)->finalize (object);
}
static void
gtk_css_style_rule_class_init (GtkCssStyleRuleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_style_rule_finalize;
}
static void
gtk_css_style_rule_init (GtkCssStyleRule *style_rule)
{
GtkCssStyleRulePrivate *priv = gtk_css_style_rule_get_instance_private (style_rule);
priv->selectors = g_ptr_array_new_with_free_func ((GDestroyNotify) _gtk_css_selector_free);
priv->style = gtk_css_style_declaration_new (GTK_CSS_RULE (style_rule));
}
static GtkCssRule *
gtk_css_style_rule_new (GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
return g_object_new (GTK_TYPE_CSS_STYLE_RULE,
"parent-rule", parent_rule,
"parent-stylesheet", parent_style_sheet,
NULL);
}
static gboolean
gtk_css_style_rule_parse_selectors (GtkCssStyleRule *rule,
GtkCssTokenSource *source)
{
GtkCssStyleRulePrivate *priv = gtk_css_style_rule_get_instance_private (rule);
GtkCssTokenSource *child_source;
GtkCssSelector *selector;
const GtkCssToken *token;
gtk_css_token_source_set_consumer (source, G_OBJECT (rule));
for (token = gtk_css_token_source_get_token (source);
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
token = gtk_css_token_source_get_token (source))
{
child_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_COMMA);
selector = gtk_css_selector_token_parse (child_source);
gtk_css_token_source_unref (child_source);
if (selector == NULL)
return FALSE;
g_ptr_array_add (priv->selectors, selector);
gtk_css_token_source_consume_token (source);
}
return TRUE;
}
GtkCssRule *
gtk_css_style_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet)
{
GtkCssStyleRulePrivate *priv;
GtkCssTokenSource *child_source;
GtkCssStyleRule *rule;
gboolean success;
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_STYLE_RULE (gtk_css_style_rule_new (parent_rule, parent_style_sheet));
priv = gtk_css_style_rule_get_instance_private (rule);
gtk_css_token_source_set_consumer (source, G_OBJECT (rule));
child_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_OPEN_CURLY);
success = gtk_css_style_rule_parse_selectors (rule, child_source);
gtk_css_token_source_unref (child_source);
gtk_css_token_source_consume_token (source);
child_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_CLOSE_CURLY);
if (success)
gtk_css_style_declaration_parse (priv->style, child_source);
else
{
gtk_css_token_source_consume_all (child_source);
}
gtk_css_token_source_unref (child_source);
gtk_css_token_source_consume_token (source);
if (!success)
{
g_object_unref (rule);
return NULL;
}
return GTK_CSS_RULE (rule);
}
gsize
gtk_css_style_rule_get_n_selectors (GtkCssStyleRule *rule)
{
GtkCssStyleRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_RULE (rule), 0);
priv = gtk_css_style_rule_get_instance_private (rule);
return priv->selectors->len;
}
GtkCssSelector *
gtk_css_style_rule_get_selector (GtkCssStyleRule *rule,
gsize id)
{
GtkCssStyleRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_RULE (rule), 0);
priv = gtk_css_style_rule_get_instance_private (rule);
return g_ptr_array_index (priv->selectors, id);
}
GtkCssStyleDeclaration *
gtk_css_style_rule_get_style (GtkCssStyleRule *rule)
{
GtkCssStyleRulePrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_RULE (rule), NULL);
priv = gtk_css_style_rule_get_instance_private (rule);
return priv->style;
}

View File

@@ -0,0 +1,64 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_STYLE_RULE_PRIVATE_H__
#define __GTK_CSS_STYLE_RULE_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
#include "gtk/gtkcssselectorprivate.h"
#include "gtk/gtkcssstyledeclarationprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_STYLE_RULE (gtk_css_style_rule_get_type ())
#define GTK_CSS_STYLE_RULE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_STYLE_RULE, GtkCssStyleRule))
#define GTK_CSS_STYLE_RULE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_STYLE_RULE, GtkCssStyleRuleClass))
#define GTK_IS_CSS_STYLE_RULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_STYLE_RULE))
#define GTK_IS_CSS_STYLE_RULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_STYLE_RULE))
#define GTK_CSS_STYLE_RULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_STYLE_RULE, GtkCssStyleRuleClass))
typedef struct _GtkCssStyleRule GtkCssStyleRule;
typedef struct _GtkCssStyleRuleClass GtkCssStyleRuleClass;
struct _GtkCssStyleRule
{
GtkCssRule parent;
};
struct _GtkCssStyleRuleClass
{
GtkCssRuleClass parent_class;
};
GType gtk_css_style_rule_get_type (void) G_GNUC_CONST;
GtkCssRule * gtk_css_style_rule_new_parse (GtkCssTokenSource *source,
GtkCssRule *parent_rule,
GtkCssStyleSheet *parent_style_sheet);
gsize gtk_css_style_rule_get_n_selectors (GtkCssStyleRule *rule);
GtkCssSelector * gtk_css_style_rule_get_selector (GtkCssStyleRule *rule,
gsize id);
GtkCssStyleDeclaration *gtk_css_style_rule_get_style (GtkCssStyleRule *rule);
G_END_DECLS
#endif /* __GTK_CSS_STYLE_RULE_PRIVATE_H__ */

267
gtk/gtkcssstylesheet.c Normal file
View File

@@ -0,0 +1,267 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcssstylesheetprivate.h"
#include "gtkintl.h"
#include "gtkprivate.h"
enum {
PROP_0,
PROP_CSS_RULES,
PROP_FILE,
PROP_OWNER_RULE,
PROP_PARENT_STYLESHEET,
NUM_PROPERTIES
};
typedef struct _GtkCssStyleSheetPrivate GtkCssStyleSheetPrivate;
struct _GtkCssStyleSheetPrivate {
GtkCssRule *owner_rule;
GtkCssRuleList *css_rules;
GFile *file;
};
static GParamSpec *style_sheet_props[NUM_PROPERTIES] = { NULL, };
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssStyleSheet, gtk_css_style_sheet, G_TYPE_OBJECT)
static void
gtk_css_style_sheet_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkCssStyleSheet *style_sheet = GTK_CSS_STYLE_SHEET (gobject);
GtkCssStyleSheetPrivate *priv = gtk_css_style_sheet_get_instance_private (style_sheet);
switch (prop_id)
{
case PROP_FILE:
priv->file = g_value_dup_object (value);
break;
case PROP_OWNER_RULE:
priv->owner_rule = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_css_style_sheet_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkCssStyleSheet *style_sheet = GTK_CSS_STYLE_SHEET (gobject);
GtkCssStyleSheetPrivate *priv = gtk_css_style_sheet_get_instance_private (style_sheet);
switch (prop_id)
{
case PROP_CSS_RULES:
g_value_set_object (value, priv->css_rules);
break;
case PROP_FILE:
g_value_set_object (value, priv->file);
break;
case PROP_OWNER_RULE:
g_value_set_object (value, priv->owner_rule);
break;
case PROP_PARENT_STYLESHEET:
if (priv->owner_rule)
g_value_set_object (value, gtk_css_rule_get_parent_style_sheet (priv->owner_rule));
else
g_value_set_object (value, NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gtk_css_style_sheet_finalize (GObject *object)
{
GtkCssStyleSheet *style_sheet = GTK_CSS_STYLE_SHEET (object);
GtkCssStyleSheetPrivate *priv = gtk_css_style_sheet_get_instance_private (style_sheet);
g_object_unref (priv->css_rules);
if (priv->owner_rule)
g_object_unref (priv->owner_rule);
if (priv->file)
g_object_unref (priv->file);
G_OBJECT_CLASS (gtk_css_style_sheet_parent_class)->finalize (object);
}
static void
gtk_css_style_sheet_class_init (GtkCssStyleSheetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_style_sheet_finalize;
object_class->get_property = gtk_css_style_sheet_get_property;
object_class->set_property = gtk_css_style_sheet_set_property;
style_sheet_props[PROP_CSS_RULES] =
g_param_spec_object ("css-rules",
P_("css rules"),
P_("The CSS rules of the style sheet"),
GTK_TYPE_CSS_RULE_LIST,
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
style_sheet_props[PROP_FILE] =
g_param_spec_object ("file",
P_("file"),
P_("The file the style sheet was loaded from or NULL if inline"),
G_TYPE_FILE,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
style_sheet_props[PROP_OWNER_RULE] =
g_param_spec_object ("owner-rule",
P_("owner rule"),
P_("The CSS rule that loaded this style sheet or NULL"),
GTK_TYPE_CSS_RULE,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
style_sheet_props[PROP_PARENT_STYLESHEET] =
g_param_spec_object ("parent-stylesheet",
P_("parent style sheet"),
P_("The parent style sheet that loaded this style sheet or NULL"),
GTK_TYPE_CSS_STYLE_SHEET,
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, style_sheet_props);
}
static void
gtk_css_style_sheet_init (GtkCssStyleSheet *style_sheet)
{
GtkCssStyleSheetPrivate *priv = gtk_css_style_sheet_get_instance_private (style_sheet);
priv->css_rules = gtk_css_rule_list_new ();
}
static void
gtk_css_style_sheet_parse (GtkCssStyleSheet *style_sheet,
GtkCssTokenSource *source)
{
GtkCssStyleSheetPrivate *priv;
g_return_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet));
g_return_if_fail (source != NULL);
priv = gtk_css_style_sheet_get_instance_private (style_sheet);
gtk_css_rule_list_parse (priv->css_rules, source, NULL, style_sheet);
}
GtkCssStyleSheet *
gtk_css_style_sheet_new (GtkCssTokenSource *source)
{
GtkCssStyleSheet *sheet;
g_return_val_if_fail (source != NULL, NULL);
sheet = g_object_new (GTK_TYPE_CSS_STYLE_SHEET,
"file", gtk_css_token_source_get_location (source),
NULL);
gtk_css_style_sheet_parse (sheet, source);
return sheet;
}
GtkCssStyleSheet *
gtk_css_style_sheet_new_import (GtkCssTokenSource *source,
GtkCssRule *owner_rule)
{
GtkCssStyleSheet *sheet;
g_return_val_if_fail (source != NULL, NULL);
g_return_val_if_fail (GTK_IS_CSS_RULE (owner_rule), NULL);
sheet = g_object_new (GTK_TYPE_CSS_STYLE_SHEET,
"file", gtk_css_token_source_get_location (source),
"owner-rule", owner_rule,
NULL);
gtk_css_style_sheet_parse (sheet, source);
return sheet;
}
GFile *
gtk_css_style_sheet_get_file (GtkCssStyleSheet *style_sheet)
{
GtkCssStyleSheetPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
priv = gtk_css_style_sheet_get_instance_private (style_sheet);
return priv->file;
}
GtkCssStyleSheet *
gtk_css_style_sheet_get_parent_style_sheet (GtkCssStyleSheet *style_sheet)
{
GtkCssStyleSheetPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
priv = gtk_css_style_sheet_get_instance_private (style_sheet);
if (priv->owner_rule == NULL)
return NULL;
return gtk_css_rule_get_parent_style_sheet (priv->owner_rule);
}
GtkCssRule *
gtk_css_style_sheet_get_owner_rule (GtkCssStyleSheet *style_sheet)
{
GtkCssStyleSheetPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
priv = gtk_css_style_sheet_get_instance_private (style_sheet);
return priv->owner_rule;
}
GtkCssRuleList *
gtk_css_style_sheet_get_css_rules (GtkCssStyleSheet *style_sheet)
{
GtkCssStyleSheetPrivate *priv;
g_return_val_if_fail (GTK_IS_CSS_STYLE_SHEET (style_sheet), NULL);
priv = gtk_css_style_sheet_get_instance_private (style_sheet);
return priv->css_rules;
}

View File

@@ -0,0 +1,68 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_STYLE_SHEET_PRIVATE_H__
#define __GTK_CSS_STYLE_SHEET_PRIVATE_H__
#include "gtk/gtkcssruleprivate.h"
#include "gtk/gtkcssrulelistprivate.h"
#include "gtk/gtkcsstokensourceprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_STYLE_SHEET (gtk_css_style_sheet_get_type ())
#define GTK_CSS_STYLE_SHEET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_STYLE_SHEET, GtkCssStyleSheet))
#define GTK_CSS_STYLE_SHEET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_STYLE_SHEET, GtkCssStyleSheetClass))
#define GTK_IS_CSS_STYLE_SHEET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_STYLE_SHEET))
#define GTK_IS_CSS_STYLE_SHEET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_STYLE_SHEET))
#define GTK_CSS_STYLE_SHEET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_STYLE_SHEET, GtkCssStyleSheetClass))
/* declared with GtkCssRule */
/* typedef struct _GtkCssStyleSheet GtkCssStyleSheet; */
typedef struct _GtkCssStyleSheetClass GtkCssStyleSheetClass;
struct _GtkCssStyleSheet
{
GObject parent;
};
struct _GtkCssStyleSheetClass
{
GObjectClass parent_class;
};
GType gtk_css_style_sheet_get_type (void) G_GNUC_CONST;
GtkCssStyleSheet * gtk_css_style_sheet_new (GtkCssTokenSource *source);
GtkCssStyleSheet * gtk_css_style_sheet_new_import (GtkCssTokenSource *source,
GtkCssRule *owner_rule);
/* StyleSheet interface */
GtkCssStyleSheet * gtk_css_style_sheet_get_parent_style_sheet (GtkCssStyleSheet *style_sheet);
GFile * gtk_css_style_sheet_get_file (GtkCssStyleSheet *style_sheet);
/* CSSStyleSheet interface */
GtkCssRule * gtk_css_style_sheet_get_owner_rule (GtkCssStyleSheet *style_sheet);
GtkCssRuleList * gtk_css_style_sheet_get_css_rules (GtkCssStyleSheet *style_sheet);
G_END_DECLS
#endif /* __GTK_CSS_STYLE_SHEET_PRIVATE_H__ */

1441
gtk/gtkcsstokenizer.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,154 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
*
* 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/>.
*/
#ifndef __GTK_CSS_TOKENIZER_PRIVATE_H__
#define __GTK_CSS_TOKENIZER_PRIVATE_H__
#include <glib.h>
G_BEGIN_DECLS
typedef enum {
/* no content */
GTK_CSS_TOKEN_EOF,
GTK_CSS_TOKEN_WHITESPACE,
GTK_CSS_TOKEN_OPEN_PARENS,
GTK_CSS_TOKEN_CLOSE_PARENS,
GTK_CSS_TOKEN_OPEN_SQUARE,
GTK_CSS_TOKEN_CLOSE_SQUARE,
GTK_CSS_TOKEN_OPEN_CURLY,
GTK_CSS_TOKEN_CLOSE_CURLY,
GTK_CSS_TOKEN_COMMA,
GTK_CSS_TOKEN_COLON,
GTK_CSS_TOKEN_SEMICOLON,
GTK_CSS_TOKEN_CDO,
GTK_CSS_TOKEN_CDC,
GTK_CSS_TOKEN_INCLUDE_MATCH,
GTK_CSS_TOKEN_DASH_MATCH,
GTK_CSS_TOKEN_PREFIX_MATCH,
GTK_CSS_TOKEN_SUFFIX_MATCH,
GTK_CSS_TOKEN_SUBSTRING_MATCH,
GTK_CSS_TOKEN_COLUMN,
GTK_CSS_TOKEN_BAD_STRING,
GTK_CSS_TOKEN_BAD_URL,
GTK_CSS_TOKEN_COMMENT,
/* delim */
GTK_CSS_TOKEN_DELIM,
/* string */
GTK_CSS_TOKEN_STRING,
GTK_CSS_TOKEN_IDENT,
GTK_CSS_TOKEN_FUNCTION,
GTK_CSS_TOKEN_AT_KEYWORD,
GTK_CSS_TOKEN_HASH_UNRESTRICTED,
GTK_CSS_TOKEN_HASH_ID,
GTK_CSS_TOKEN_URL,
/* number */
GTK_CSS_TOKEN_SIGNED_INTEGER,
GTK_CSS_TOKEN_SIGNLESS_INTEGER,
GTK_CSS_TOKEN_SIGNED_NUMBER,
GTK_CSS_TOKEN_SIGNLESS_NUMBER,
GTK_CSS_TOKEN_PERCENTAGE,
/* dimension */
GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION,
GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION,
GTK_CSS_TOKEN_DIMENSION
} GtkCssTokenType;
typedef union _GtkCssToken GtkCssToken;
typedef struct _GtkCssTokenizer GtkCssTokenizer;
typedef struct _GtkCssLocation GtkCssLocation;
typedef struct _GtkCssStringToken GtkCssStringToken;
typedef struct _GtkCssDelimToken GtkCssDelimToken;
typedef struct _GtkCssNumberToken GtkCssNumberToken;
typedef struct _GtkCssDimensionToken GtkCssDimensionToken;
typedef void (* GtkCssTokenizerErrorFunc) (GtkCssTokenizer *parser,
const GtkCssLocation *location,
const GtkCssToken *token,
const GError *error,
gpointer user_data);
struct _GtkCssStringToken {
GtkCssTokenType type;
char *string;
};
struct _GtkCssDelimToken {
GtkCssTokenType type;
gunichar delim;
};
struct _GtkCssNumberToken {
GtkCssTokenType type;
double number;
};
struct _GtkCssDimensionToken {
GtkCssTokenType type;
double value;
char *dimension;
};
union _GtkCssToken {
GtkCssTokenType type;
GtkCssStringToken string;
GtkCssDelimToken delim;
GtkCssNumberToken number;
GtkCssDimensionToken dimension;
};
struct _GtkCssLocation
{
gsize bytes;
gsize chars;
gsize lines;
gsize line_bytes;
gsize line_chars;
};
void gtk_css_token_clear (GtkCssToken *token);
gboolean gtk_css_token_is_finite (const GtkCssToken *token);
#define gtk_css_token_is(token, _type) ((token)->type == (_type))
gboolean gtk_css_token_is_ident (const GtkCssToken *token,
const char *ident);
gboolean gtk_css_token_is_function (const GtkCssToken *token,
const char *ident);
gboolean gtk_css_token_is_delim (const GtkCssToken *token,
gunichar delim);
void gtk_css_token_print (const GtkCssToken *token,
GString *string);
char * gtk_css_token_to_string (const GtkCssToken *token);
GtkCssTokenizer * gtk_css_tokenizer_new (GBytes *bytes,
GtkCssTokenizerErrorFunc func,
gpointer user_data,
GDestroyNotify user_destroy);
GtkCssTokenizer * gtk_css_tokenizer_ref (GtkCssTokenizer *tokenizer);
void gtk_css_tokenizer_unref (GtkCssTokenizer *tokenizer);
const GtkCssLocation * gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer);
void gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
GtkCssToken *token);
G_END_DECLS
#endif /* __GTK_CSS_TOKENIZER_PRIVATE_H__ */

615
gtk/gtkcsstokensource.c Normal file
View File

@@ -0,0 +1,615 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcssprovider.h"
typedef struct _GtkCssTokenSourceTokenizer GtkCssTokenSourceTokenizer;
struct _GtkCssTokenSourceTokenizer {
GtkCssTokenSource parent;
GtkCssTokenizer *tokenizer;
GFile *location;
GtkCssToken current_token;
};
static void
gtk_css_token_source_tokenizer_finalize (GtkCssTokenSource *source)
{
GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
gtk_css_token_clear (&tok->current_token);
gtk_css_tokenizer_unref (tok->tokenizer);
if (tok->location)
g_object_unref (tok->location);
}
static void
gtk_css_token_source_tokenizer_consume_token (GtkCssTokenSource *source,
GObject *consumer)
{
GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
gtk_css_token_clear (&tok->current_token);
}
static const GtkCssToken *
gtk_css_token_source_tokenizer_peek_token (GtkCssTokenSource *source)
{
GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
if (gtk_css_token_is (&tok->current_token, GTK_CSS_TOKEN_EOF))
{
gtk_css_tokenizer_read_token (tok->tokenizer, &tok->current_token);
#if 0
if (!gtk_css_token_is (&tok->current_token, GTK_CSS_TOKEN_EOF)) {
char *s = gtk_css_token_to_string (&tok->current_token);
g_print ("%3zu:%02zu %2d %s\n",
gtk_css_tokenizer_get_line (tok->tokenizer), gtk_css_tokenizer_get_line_char (tok->tokenizer),
tok->current_token.type, s);
g_free (s);
}
#endif
}
return &tok->current_token;
}
static void
gtk_css_token_source_tokenizer_error (GtkCssTokenSource *source,
const GError *error)
{
GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
const GtkCssLocation *pos = gtk_css_tokenizer_get_location (tok->tokenizer);
/* XXX */
g_print ("ERROR: %zu:%zu: %s\n",
pos->lines, pos->line_chars,
error->message);
}
static GFile *
gtk_css_token_source_tokenizer_get_location (GtkCssTokenSource *source)
{
GtkCssTokenSourceTokenizer *tok = (GtkCssTokenSourceTokenizer *) source;
return tok->location;
}
const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_TOKENIZER = {
gtk_css_token_source_tokenizer_finalize,
gtk_css_token_source_tokenizer_consume_token,
gtk_css_token_source_tokenizer_peek_token,
gtk_css_token_source_tokenizer_error,
gtk_css_token_source_tokenizer_get_location,
};
GtkCssTokenSource *
gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer,
GFile *location)
{
GtkCssTokenSourceTokenizer *source;
g_return_val_if_fail (tokenizer != NULL, NULL);
g_return_val_if_fail (location == NULL || G_IS_FILE (location), NULL);
source = gtk_css_token_source_new (GtkCssTokenSourceTokenizer, &GTK_CSS_TOKEN_SOURCE_TOKENIZER);
source->tokenizer = gtk_css_tokenizer_ref (tokenizer);
if (location)
source->location = g_object_ref (location);
return &source->parent;
}
typedef struct _GtkCssTokenSourcePart GtkCssTokenSourcePart;
struct _GtkCssTokenSourcePart {
GtkCssTokenSource parent;
GtkCssTokenSource *source;
GtkCssTokenType end_type;
GSList *blocks; /* of GPOINTER_TO_UINT(GtkCssTokenType) */
};
static void
gtk_css_token_source_part_finalize (GtkCssTokenSource *source)
{
GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
gtk_css_token_source_unref (part->source);
g_slist_free (part->blocks);
}
static void
gtk_css_token_source_part_consume_token (GtkCssTokenSource *source,
GObject *consumer)
{
GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
const GtkCssToken *token;
token = gtk_css_token_source_peek_token (part->source);
if (part->blocks)
{
if (token->type == GPOINTER_TO_UINT (part->blocks->data))
part->blocks = g_slist_remove (part->blocks, part->blocks->data);
}
else if (gtk_css_token_is (token, part->end_type))
{
return;
}
switch (token->type)
{
case GTK_CSS_TOKEN_FUNCTION:
case GTK_CSS_TOKEN_OPEN_PARENS:
part->blocks = g_slist_prepend (part->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_PARENS));
break;
case GTK_CSS_TOKEN_OPEN_SQUARE:
part->blocks = g_slist_prepend (part->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_SQUARE));
break;
case GTK_CSS_TOKEN_OPEN_CURLY:
part->blocks = g_slist_prepend (part->blocks, GUINT_TO_POINTER (GTK_CSS_TOKEN_CLOSE_CURLY));
break;
default:
break;
}
gtk_css_token_source_consume_token_as (part->source, consumer);
}
static const GtkCssToken *
gtk_css_token_source_part_peek_token (GtkCssTokenSource *source)
{
GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
static const GtkCssToken eof_token = { GTK_CSS_TOKEN_EOF };
const GtkCssToken *token;
token = gtk_css_token_source_peek_token (part->source);
if (part->blocks == NULL &&
gtk_css_token_is (token, part->end_type))
return &eof_token;
return token;
}
static void
gtk_css_token_source_part_error (GtkCssTokenSource *source,
const GError *error)
{
GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
gtk_css_token_source_emit_error (part->source, error);
}
static GFile *
gtk_css_token_source_part_get_location (GtkCssTokenSource *source)
{
GtkCssTokenSourcePart *part = (GtkCssTokenSourcePart *) source;
return gtk_css_token_source_get_location (part->source);
}
const GtkCssTokenSourceClass GTK_CSS_TOKEN_SOURCE_PART = {
gtk_css_token_source_part_finalize,
gtk_css_token_source_part_consume_token,
gtk_css_token_source_part_peek_token,
gtk_css_token_source_part_error,
gtk_css_token_source_part_get_location,
};
GtkCssTokenSource *
gtk_css_token_source_new_for_part (GtkCssTokenSource *source,
GtkCssTokenType end_type)
{
GtkCssTokenSourcePart *part;
g_return_val_if_fail (source != NULL, NULL);
g_return_val_if_fail (end_type != GTK_CSS_TOKEN_EOF, NULL);
part = gtk_css_token_source_new (GtkCssTokenSourcePart, &GTK_CSS_TOKEN_SOURCE_PART);
part->source = gtk_css_token_source_ref (source);
part->end_type = end_type;
gtk_css_token_source_set_consumer (&part->parent,
gtk_css_token_source_get_consumer (source));
return &part->parent;
}
GtkCssTokenSource *
gtk_css_token_source_alloc (gsize struct_size,
const GtkCssTokenSourceClass *klass)
{
GtkCssTokenSource *source;
source = g_malloc0 (struct_size);
source->klass = klass;
source->ref_count = 1;
return source;
}
GtkCssTokenSource *
gtk_css_token_source_ref (GtkCssTokenSource *source)
{
source->ref_count++;
return source;
}
void
gtk_css_token_source_unref (GtkCssTokenSource *source)
{
source->ref_count--;
if (source->ref_count > 0)
return;
source->klass->finalize (source);
g_clear_object (&source->consumer);
g_free (source);
}
void
gtk_css_token_source_consume_token (GtkCssTokenSource *source)
{
gtk_css_token_source_consume_token_as (source, source->consumer);
}
void
gtk_css_token_source_consume_token_as (GtkCssTokenSource *source,
GObject *consumer)
{
source->klass->consume_token (source, consumer);
}
const GtkCssToken *
gtk_css_token_source_peek_token (GtkCssTokenSource *source)
{
return source->klass->peek_token (source);
}
const GtkCssToken *
gtk_css_token_source_get_token (GtkCssTokenSource *source)
{
const GtkCssToken *token;
for (token = gtk_css_token_source_peek_token (source);
gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
token = gtk_css_token_source_peek_token (source))
{
gtk_css_token_source_consume_token (source);
}
return token;
}
void
gtk_css_token_source_consume_all (GtkCssTokenSource *source)
{
const GtkCssToken *token;
for (token = gtk_css_token_source_get_token (source);
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
token = gtk_css_token_source_get_token (source))
{
gtk_css_token_source_consume_token (source);
}
}
char *
gtk_css_token_source_consume_to_string (GtkCssTokenSource *source)
{
GString *string;
const GtkCssToken *token;
string = g_string_new (NULL);
for (token = gtk_css_token_source_peek_token (source);
!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
token = gtk_css_token_source_peek_token (source))
{
if (gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT))
continue;
gtk_css_token_print (token, string);
gtk_css_token_source_consume_token (source);
}
return g_string_free (string, FALSE);
}
gboolean
gtk_css_token_source_consume_function (GtkCssTokenSource *source,
guint min_args,
guint max_args,
guint (* parse_func) (GtkCssTokenSource *, guint, gpointer),
gpointer data)
{
const GtkCssToken *token;
GtkCssTokenSource *func_source;
gboolean result = FALSE;
char *function_name;
guint arg;
token = gtk_css_token_source_get_token (source);
g_return_val_if_fail (gtk_css_token_is (token, GTK_CSS_TOKEN_FUNCTION), FALSE);
function_name = g_strdup (token->string.string);
gtk_css_token_source_consume_token (source);
func_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_CLOSE_PARENS);
arg = 0;
while (arg < max_args)
{
guint parse_args = parse_func (func_source, arg, data);
if (parse_args == 0)
{
gtk_css_token_source_consume_all (func_source);
break;
}
arg += parse_args;
token = gtk_css_token_source_get_token (func_source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
if (arg < min_args)
{
gtk_css_token_source_error (source, "%s() requires at least %u arguments", function_name, min_args);
gtk_css_token_source_consume_all (source);
}
else
{
result = TRUE;
}
break;
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COMMA))
{
gtk_css_token_source_consume_token (func_source);
continue;
}
else
{
gtk_css_token_source_error (func_source, "Unexpected data at end of %s() argument", function_name);
gtk_css_token_source_consume_all (func_source);
break;
}
}
gtk_css_token_source_unref (func_source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Expected ')' at end of %s()", function_name);
gtk_css_token_source_consume_all (source);
g_free (function_name);
return FALSE;
}
gtk_css_token_source_consume_token (source);
g_free (function_name);
return result;
}
gboolean
gtk_css_token_source_consume_number (GtkCssTokenSource *source,
double *number)
{
const GtkCssToken *token;
GtkCssValue *value;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
*number = token->number.number;
gtk_css_token_source_consume_token (source);
return TRUE;
}
/* because CSS allows calc() in numbers. Go CSS! */
value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER);
if (value == NULL)
return FALSE;
*number = _gtk_css_number_value_get (value, 100);
_gtk_css_value_unref (value);
return TRUE;
}
gboolean
gtk_css_token_source_consume_integer (GtkCssTokenSource *source,
int *number)
{
const GtkCssToken *token;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
*number = token->number.number;
gtk_css_token_source_consume_token (source);
return TRUE;
}
/* XXX: parse calc() */
gtk_css_token_source_error (source, "Expected an integer");
gtk_css_token_source_consume_all (source);
return FALSE;
}
GFile *
gtk_css_token_source_resolve_url (GtkCssTokenSource *source,
const char *url)
{
char *scheme;
GFile *file, *location, *base;
scheme = g_uri_parse_scheme (url);
if (scheme != NULL)
{
file = g_file_new_for_uri (url);
g_free (scheme);
return file;
}
location = gtk_css_token_source_get_location (source);
if (location)
{
base = g_file_get_parent (location);
}
else
{
char *dir = g_get_current_dir ();
base = g_file_new_for_path (dir);
g_free (dir);
}
file = g_file_resolve_relative_path (base, url);
g_object_unref (base);
return file;
}
GFile *
gtk_css_token_source_consume_url (GtkCssTokenSource *source)
{
const GtkCssToken *token;
GFile *file;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_URL))
{
file = gtk_css_token_source_resolve_url (source, token->string.string);
gtk_css_token_source_consume_token (source);
return file;
}
else if (gtk_css_token_is_function (token, "url"))
{
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_STRING))
{
gtk_css_token_source_error (source, "Expected string inside url()");
gtk_css_token_source_consume_all (source);
return NULL;
}
file = gtk_css_token_source_resolve_url (source, token->string.string);
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
gtk_css_token_source_error (source, "Expected closing ')' for url()");
gtk_css_token_source_consume_all (source);
g_object_unref (file);
return NULL;
}
gtk_css_token_source_consume_token (source);
return file;
}
else
{
gtk_css_token_source_error (source, "Expected url()");
gtk_css_token_source_consume_all (source);
return NULL;
}
}
void
gtk_css_token_source_emit_error (GtkCssTokenSource *source,
const GError *error)
{
source->klass->error (source, error);
}
void
gtk_css_token_source_error (GtkCssTokenSource *source,
const char *format,
...)
{
va_list args;
GError *error;
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
format, args);
gtk_css_token_source_emit_error (source, error);
g_error_free (error);
va_end (args);
}
void
gtk_css_token_source_unknown (GtkCssTokenSource *source,
const char *format,
...)
{
va_list args;
GError *error;
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE,
format, args);
gtk_css_token_source_emit_error (source, error);
g_error_free (error);
va_end (args);
}
void
gtk_css_token_source_deprecated (GtkCssTokenSource *source,
const char *format,
...)
{
va_list args;
GError *error;
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_DEPRECATED,
format, args);
gtk_css_token_source_emit_error (source, error);
g_error_free (error);
va_end (args);
}
GFile *
gtk_css_token_source_get_location (GtkCssTokenSource *source)
{
return source->klass->get_location (source);
}
GObject *
gtk_css_token_source_get_consumer (GtkCssTokenSource *source)
{
return source->consumer;
}
void
gtk_css_token_source_set_consumer (GtkCssTokenSource *source,
GObject *consumer)
{
g_set_object (&source->consumer, consumer);
}

View File

@@ -0,0 +1,103 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__
#define __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__
#include <gio/gio.h>
#include "gtk/gtkcsstokenizerprivate.h"
G_BEGIN_DECLS
typedef struct _GtkCssTokenSource GtkCssTokenSource;
typedef struct _GtkCssTokenSourceClass GtkCssTokenSourceClass;
struct _GtkCssTokenSource
{
const GtkCssTokenSourceClass *klass;
gint ref_count;
GObject *consumer;
};
struct _GtkCssTokenSourceClass
{
void (* finalize) (GtkCssTokenSource *source);
void (* consume_token) (GtkCssTokenSource *source,
GObject *consumer);
const GtkCssToken * (* peek_token) (GtkCssTokenSource *source);
void (* error) (GtkCssTokenSource *source,
const GError *error);
GFile * (* get_location) (GtkCssTokenSource *source);
};
GtkCssTokenSource * gtk_css_token_source_new_for_tokenizer (GtkCssTokenizer *tokenizer,
GFile *location);
GtkCssTokenSource * gtk_css_token_source_new_for_part (GtkCssTokenSource *source,
GtkCssTokenType end_type);
GtkCssTokenSource * gtk_css_token_source_ref (GtkCssTokenSource *source);
void gtk_css_token_source_unref (GtkCssTokenSource *source);
#define gtk_css_token_source_new(type,klass) ((type *) gtk_css_token_source_alloc (sizeof (type), (klass)))
GtkCssTokenSource * gtk_css_token_source_alloc (gsize struct_size,
const GtkCssTokenSourceClass *klass);
void gtk_css_token_source_consume_token (GtkCssTokenSource *source);
void gtk_css_token_source_consume_token_as (GtkCssTokenSource *source,
GObject *consumer);
const GtkCssToken * gtk_css_token_source_peek_token (GtkCssTokenSource *source);
const GtkCssToken * gtk_css_token_source_get_token (GtkCssTokenSource *source);
void gtk_css_token_source_consume_all (GtkCssTokenSource *source);
char * gtk_css_token_source_consume_to_string (GtkCssTokenSource *source);
gboolean gtk_css_token_source_consume_function (GtkCssTokenSource *source,
guint min_args,
guint max_args,
guint (* parse_func) (GtkCssTokenSource *, guint, gpointer),
gpointer data);
gboolean gtk_css_token_source_consume_number (GtkCssTokenSource *source,
double *number);
gboolean gtk_css_token_source_consume_integer (GtkCssTokenSource *source,
int *number);
GFile * gtk_css_token_source_resolve_url (GtkCssTokenSource *source,
const char *url);
GFile * gtk_css_token_source_consume_url (GtkCssTokenSource *source);
void gtk_css_token_source_emit_error (GtkCssTokenSource *source,
const GError *error);
void gtk_css_token_source_error (GtkCssTokenSource *source,
const char *format,
...) G_GNUC_PRINTF(2, 3);
void gtk_css_token_source_unknown (GtkCssTokenSource *source,
const char *format,
...) G_GNUC_PRINTF(2, 3);
void gtk_css_token_source_deprecated (GtkCssTokenSource *source,
const char *format,
...) G_GNUC_PRINTF(2, 3);
GFile * gtk_css_token_source_get_location (GtkCssTokenSource *source);
GObject * gtk_css_token_source_get_consumer (GtkCssTokenSource *source);
void gtk_css_token_source_set_consumer (GtkCssTokenSource *source,
GObject *consumer);
G_END_DECLS
#endif /* __GTK_CSS_TOKEN_SOURCE_PRIVATE_H__ */

View File

@@ -1015,6 +1015,331 @@ _gtk_css_transform_value_parse (GtkCssParser *parser)
return value;
}
static guint
token_parse_matrix (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssTransform *transform = data;
switch (n)
{
case 0:
return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.xx) ? 1 : 0;
case 1:
return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.xy) ? 1 : 0;
case 2:
return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.x0) ? 1 : 0;
case 3:
return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.yx) ? 1 : 0;
case 4:
return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.yy) ? 1 : 0;
case 5:
return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.y0) ? 1 : 0;
default:
g_assert_not_reached ();
return 0;
}
}
static guint
token_parse_translate (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssTransform *transform = data;
if (n == 0)
{
transform->translate.x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_LENGTH);
if (transform->translate.x == NULL)
return 0;
transform->translate.y = _gtk_css_number_value_new (0, GTK_CSS_PX);
}
else if (n == 1)
{
_gtk_css_value_unref (transform->translate.y);
transform->translate.y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_LENGTH);
if (transform->translate.y == NULL)
return 0;
}
else
{
g_assert_not_reached ();
}
return 1;
}
static guint
token_parse_length (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssValue **value = data;
*value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_LENGTH);
if (*value == NULL)
return 0;
return 1;
}
static guint
token_parse_scale (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssTransform *transform = data;
if (n == 0)
{
transform->scale.x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER);
if (transform->scale.x == NULL)
return 0;
transform->scale.y = _gtk_css_value_ref (transform->scale.x);
}
else if (n == 1)
{
_gtk_css_value_unref (transform->scale.y);
transform->scale.y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER);
if (transform->scale.y == NULL)
return 0;
}
else
{
g_assert_not_reached ();
}
return 1;
}
static guint
token_parse_number (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssValue **value = data;
*value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER);
if (*value == NULL)
return 0;
return 1;
}
static guint
token_parse_angle (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssValue **value = data;
*value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE);
if (*value == NULL)
return 0;
return 1;
}
static guint
token_parse_skew (GtkCssTokenSource *source,
guint n,
gpointer data)
{
GtkCssTransform *transform = data;
if (n == 0)
{
transform->skew.x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE);
if (transform->skew.x == NULL)
return 0;
transform->skew.y = _gtk_css_number_value_new (0, GTK_CSS_PX);
}
else if (n == 1)
{
_gtk_css_value_unref (transform->skew.y);
transform->skew.y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE);
if (transform->skew.y == NULL)
return 0;
}
else
{
g_assert_not_reached ();
}
return 1;
}
GtkCssValue *
gtk_css_transform_value_token_parse (GtkCssTokenSource *source)
{
const GtkCssToken *token;
GtkCssValue *value;
GArray *array;
guint i;
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is_ident (token, "none"))
{
gtk_css_token_source_consume_token (source);
return _gtk_css_transform_value_new_none ();
}
array = g_array_new (FALSE, FALSE, sizeof (GtkCssTransform));
while (TRUE)
{
GtkCssTransform transform = { 0, };
if (gtk_css_token_is_function (token, "matrix"))
{
transform.type = GTK_CSS_TRANSFORM_MATRIX;
if (!gtk_css_token_source_consume_function (source, 6, 6, token_parse_matrix, &transform))
goto fail;
}
else if (gtk_css_token_is_function (token, "translate"))
{
transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
if (!gtk_css_token_source_consume_function (source, 2, 2, token_parse_translate, &transform))
{
if (transform.translate.x)
_gtk_css_value_unref (transform.translate.x);
if (transform.translate.y)
_gtk_css_value_unref (transform.translate.y);
goto fail;
}
}
else if (gtk_css_token_is_function (token, "translateX"))
{
transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_length, &transform.translate.x))
{
if (transform.translate.x)
_gtk_css_value_unref (transform.translate.x);
goto fail;
}
transform.translate.y = _gtk_css_number_value_new (0, GTK_CSS_PX);
}
else if (gtk_css_token_is_function (token, "translateY"))
{
transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_length, &transform.translate.y))
{
if (transform.translate.y)
_gtk_css_value_unref (transform.translate.y);
goto fail;
}
transform.translate.x = _gtk_css_number_value_new (0, GTK_CSS_PX);
}
else if (gtk_css_token_is_function (token, "scale"))
{
transform.type = GTK_CSS_TRANSFORM_SCALE;
if (!gtk_css_token_source_consume_function (source, 1, 2, token_parse_scale, &transform))
{
if (transform.scale.x)
_gtk_css_value_unref (transform.scale.x);
if (transform.scale.y)
_gtk_css_value_unref (transform.scale.y);
goto fail;
}
}
else if (gtk_css_token_is_function (token, "scaleX"))
{
transform.type = GTK_CSS_TRANSFORM_SCALE;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_number, &transform.scale.x))
{
if (transform.scale.x)
_gtk_css_value_unref (transform.scale.x);
goto fail;
}
transform.scale.y = _gtk_css_number_value_new (1, GTK_CSS_NUMBER);
}
else if (gtk_css_token_is_function (token, "scaleY"))
{
transform.type = GTK_CSS_TRANSFORM_SCALE;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_number, &transform.scale.y))
{
if (transform.scale.y)
_gtk_css_value_unref (transform.scale.y);
goto fail;
}
transform.scale.x = _gtk_css_number_value_new (1, GTK_CSS_NUMBER);
}
else if (gtk_css_token_is_function (token, "rotate"))
{
transform.type = GTK_CSS_TRANSFORM_ROTATE;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_angle, &transform.rotate.rotate))
{
if (transform.rotate.rotate)
_gtk_css_value_unref (transform.rotate.rotate);
goto fail;
}
}
else if (gtk_css_token_is_function (token, "skew"))
{
transform.type = GTK_CSS_TRANSFORM_SKEW;
if (!gtk_css_token_source_consume_function (source, 1, 2, token_parse_skew, &transform))
{
if (transform.skew.x)
_gtk_css_value_unref (transform.skew.x);
if (transform.skew.y)
_gtk_css_value_unref (transform.skew.y);
goto fail;
}
}
else if (gtk_css_token_is_function (token, "skewX"))
{
transform.type = GTK_CSS_TRANSFORM_SKEW_X;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_angle, &transform.skew_x.skew))
{
if (transform.skew_x.skew)
_gtk_css_value_unref (transform.skew_x.skew);
goto fail;
}
}
else if (gtk_css_token_is_function (token, "skewY"))
{
transform.type = GTK_CSS_TRANSFORM_SKEW_Y;
if (!gtk_css_token_source_consume_function (source, 1, 1, token_parse_angle, &transform.skew_y.skew))
{
if (transform.skew_y.skew)
_gtk_css_value_unref (transform.skew_y.skew);
goto fail;
}
}
else
break;
g_array_append_val (array, transform);
token = gtk_css_token_source_get_token (source);
}
if (array->len == 0)
{
gtk_css_token_source_error (source, "Expected a transform");
gtk_css_token_source_consume_all (source);
goto fail;
}
value = gtk_css_transform_value_alloc (array->len);
memcpy (value->transforms, array->data, sizeof (GtkCssTransform) * array->len);
g_array_free (array, TRUE);
return value;
fail:
for (i = 0; i < array->len; i++)
{
gtk_css_transform_clear (&g_array_index (array, GtkCssTransform, i));
}
g_array_free (array, TRUE);
return NULL;
}
gboolean
_gtk_css_transform_value_get_matrix (const GtkCssValue *transform,
cairo_matrix_t *matrix)

View File

@@ -21,12 +21,14 @@
#define __GTK_CSS_TRANSFORM_VALUE_PRIVATE_H__
#include "gtkcssparserprivate.h"
#include "gtkcsstokensourceprivate.h"
#include "gtkcssvalueprivate.h"
G_BEGIN_DECLS
GtkCssValue * _gtk_css_transform_value_new_none (void);
GtkCssValue * _gtk_css_transform_value_parse (GtkCssParser *parser);
GtkCssValue * gtk_css_transform_value_token_parse (GtkCssTokenSource *source);
gboolean _gtk_css_transform_value_get_matrix (const GtkCssValue *transform,
cairo_matrix_t *matrix);

View File

@@ -0,0 +1,197 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcsswidgetstyledeclarationprivate.h"
#include "gtkwidget.h"
#include <string.h>
typedef struct _GtkCssWidgetStyleDeclarationPrivate GtkCssWidgetStyleDeclarationPrivate;
struct _GtkCssWidgetStyleDeclarationPrivate {
char *name;
char *value;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkCssWidgetStyleDeclaration, gtk_css_widget_style_declaration, GTK_TYPE_CSS_DECLARATION)
static void
gtk_css_widget_style_declaration_finalize (GObject *object)
{
GtkCssWidgetStyleDeclaration *widget_style = GTK_CSS_WIDGET_STYLE_DECLARATION (object);
GtkCssWidgetStyleDeclarationPrivate *priv = gtk_css_widget_style_declaration_get_instance_private (widget_style);
g_free (priv->name);
g_free (priv->value);
G_OBJECT_CLASS (gtk_css_widget_style_declaration_parent_class)->finalize (object);
}
static const char *
gtk_css_widget_style_declaration_get_name (GtkCssDeclaration *decl)
{
GtkCssWidgetStyleDeclaration *widget_style_declaration = GTK_CSS_WIDGET_STYLE_DECLARATION (decl);
GtkCssWidgetStyleDeclarationPrivate *priv = gtk_css_widget_style_declaration_get_instance_private (widget_style_declaration);
return priv->name;
}
static void
gtk_css_widget_style_declaration_print_value (GtkCssDeclaration *decl,
GString *string)
{
GtkCssWidgetStyleDeclaration *widget_style = GTK_CSS_WIDGET_STYLE_DECLARATION (decl);
GtkCssWidgetStyleDeclarationPrivate *priv = gtk_css_widget_style_declaration_get_instance_private (widget_style);
g_string_append (string, priv->value);
}
static void
gtk_css_widget_style_declaration_class_init (GtkCssWidgetStyleDeclarationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCssDeclarationClass *decl_class = GTK_CSS_DECLARATION_CLASS (klass);
object_class->finalize = gtk_css_widget_style_declaration_finalize;
decl_class->get_name = gtk_css_widget_style_declaration_get_name;
decl_class->print_value = gtk_css_widget_style_declaration_print_value;
}
static void
gtk_css_widget_style_declaration_init (GtkCssWidgetStyleDeclaration *widget_style_declaration)
{
}
gboolean
gtk_css_widget_style_declaration_accepts_name (const char *name)
{
g_return_val_if_fail (name != NULL, FALSE);
if (name[0] != '-')
return FALSE;
if (g_str_has_prefix (name, "-gtk-"))
return FALSE;
return TRUE;
}
static void
warn_if_deprecated (GtkCssTokenSource *source,
const gchar *name)
{
gchar *n = NULL;
gchar *p;
const gchar *type_name;
const gchar *property_name;
GType type;
GTypeClass *class = NULL;
GParamSpec *pspec;
n = g_strdup (name);
/* skip initial - */
type_name = n + 1;
p = strchr (type_name, '-');
if (!p)
goto out;
p[0] = '\0';
property_name = p + 1;
type = g_type_from_name (type_name);
if (type == G_TYPE_INVALID ||
!g_type_is_a (type, GTK_TYPE_WIDGET))
goto out;
class = g_type_class_ref (type);
pspec = gtk_widget_class_find_style_property (GTK_WIDGET_CLASS (class), property_name);
if (!pspec)
goto out;
if (!(pspec->flags & G_PARAM_DEPRECATED))
goto out;
gtk_css_token_source_deprecated (source,
"The style property %s:%s is deprecated and shouldn't be "
"used anymore. It will be removed in a future version",
g_type_name (pspec->owner_type), pspec->name);
out:
g_free (n);
if (class)
g_type_class_unref (class);
}
GtkCssDeclaration *
gtk_css_widget_style_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source)
{
GtkCssWidgetStyleDeclarationPrivate *priv;
const GtkCssToken *token;
GtkCssWidgetStyleDeclaration *decl;
decl = g_object_new (GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION,
"parent-style", style,
NULL);
priv = gtk_css_widget_style_declaration_get_instance_private (decl);
gtk_css_token_source_set_consumer (source, G_OBJECT (decl));
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
gtk_css_token_source_error (source, "Expected a property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
if (!gtk_css_widget_style_declaration_accepts_name (token->string.string))
{
gtk_css_token_source_unknown (source, "Property name '%s' is not valid for a widget style property", token->string.string);
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
priv->name = g_strdup (token->string.string);
warn_if_deprecated (source, priv->name);
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
gtk_css_token_source_error (source, "No colon following property name");
gtk_css_token_source_consume_all (source);
g_object_unref (decl);
return NULL;
}
gtk_css_token_source_consume_token (source);
/* skip whitespace */
gtk_css_token_source_get_token (source);
priv->value = gtk_css_token_source_consume_to_string (source);
return GTK_CSS_DECLARATION (decl);
}

View File

@@ -0,0 +1,57 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_WIDGET_STYLE_DECLARATION_PRIVATE_H__
#define __GTK_CSS_WIDGET_STYLE_DECLARATION_PRIVATE_H__
#include "gtk/gtkcssdeclarationprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION (gtk_css_widget_style_declaration_get_type ())
#define GTK_CSS_WIDGET_STYLE_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION, GtkCssWidgetStyleDeclaration))
#define GTK_CSS_WIDGET_STYLE_DECLARATION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION, GtkCssWidgetStyleDeclarationClass))
#define GTK_IS_CSS_WIDGET_STYLE_DECLARATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION))
#define GTK_IS_CSS_WIDGET_STYLE_DECLARATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION))
#define GTK_CSS_WIDGET_STYLE_DECLARATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_WIDGET_STYLE_DECLARATION, GtkCssWidgetStyleDeclarationClass))
typedef struct _GtkCssWidgetStyleDeclaration GtkCssWidgetStyleDeclaration;
typedef struct _GtkCssWidgetStyleDeclarationClass GtkCssWidgetStyleDeclarationClass;
struct _GtkCssWidgetStyleDeclaration
{
GtkCssDeclaration parent;
};
struct _GtkCssWidgetStyleDeclarationClass
{
GtkCssDeclarationClass parent_class;
};
GType gtk_css_widget_style_declaration_get_type (void) G_GNUC_CONST;
gboolean gtk_css_widget_style_declaration_accepts_name (const char *name);
GtkCssDeclaration * gtk_css_widget_style_declaration_new_parse (GtkCssStyleDeclaration *style,
GtkCssTokenSource *source);
G_END_DECLS
#endif /* __GTK_CSS_WIDGET_STYLE_DECLARATION_PRIVATE_H__ */

View File

@@ -33,13 +33,13 @@ typedef enum {
} GtkWin32SizeType;
static const char *css_value_names[] = {
"-gtk-win32-size(",
"-gtk-win32-part-width(",
"-gtk-win32-part-height(",
"-gtk-win32-part-border-top(",
"-gtk-win32-part-border-right(",
"-gtk-win32-part-border-bottom(",
"-gtk-win32-part-border-left("
"-gtk-win32-size",
"-gtk-win32-part-width",
"-gtk-win32-part-height",
"-gtk-win32-part-border-top",
"-gtk-win32-part-border-right",
"-gtk-win32-part-border-bottom",
"-gtk-win32-part-border-left"
};
struct _GtkCssValue {
@@ -160,6 +160,7 @@ gtk_css_value_win32_size_print (const GtkCssValue *value,
g_string_append_printf (string, "%g * ", value->scale);
}
g_string_append (string, css_value_names[value->type]);
g_string_append (string, "(");
gtk_win32_theme_print (value->theme, string);
switch (value->type)
@@ -341,7 +342,7 @@ gtk_css_win32_size_value_parse (GtkCssParser *parser,
for (type = 0; type < G_N_ELEMENTS(css_value_names); type++)
{
if (_gtk_css_parser_try (parser, css_value_names[type], TRUE))
if (_gtk_css_parser_try (parser, css_value_names[type], FALSE))
break;
}
@@ -351,6 +352,12 @@ gtk_css_win32_size_value_parse (GtkCssParser *parser,
return NULL;
}
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
_gtk_css_parser_error (parser, "Expected '('");
return NULL;
}
theme = gtk_win32_theme_parse (parser);
if (theme == NULL)
return NULL;
@@ -399,3 +406,137 @@ gtk_css_win32_size_value_parse (GtkCssParser *parser,
return result;
}
GtkCssValue *
gtk_css_win32_size_value_token_parse (GtkCssTokenSource *source,
GtkCssNumberParseFlags flags)
{
GtkWin32Theme *theme;
const GtkCssToken *token;
GtkCssValue *result;
guint type;
token = gtk_css_token_source_get_token (source);
for (type = 0; type < G_N_ELEMENTS(css_value_names); type++)
{
if (gtk_css_token_is_function (token, css_value_names[type]))
break;
}
if (type >= G_N_ELEMENTS(css_value_names))
{
gtk_css_token_source_error (source, "Not a win32 size value");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
theme = gtk_win32_theme_token_parse (source);
if (theme == NULL)
return NULL;
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_COMMA))
{
gtk_win32_theme_unref (theme);
gtk_css_token_source_error (source, "Expected ','");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
result = gtk_css_win32_size_value_new (1.0, theme, type);
gtk_win32_theme_unref (theme);
switch (result->type)
{
case GTK_WIN32_SIZE:
token = gtk_css_token_source_get_token (source);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
result->val.size.id = gtk_win32_get_sys_metric_id_for_name (token->string.string);
if (result->val.size.id == -1)
{
gtk_css_token_source_error (source, "'%s' is not a name for a win32 metric.", token->string.string);
gtk_css_token_source_consume_all (source);
_gtk_css_value_unref (result);
return NULL;
}
gtk_css_token_source_consume_token (source);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
result->val.size.id = token->number.number;
gtk_css_token_source_consume_token (source);
}
else
{
_gtk_css_value_unref (result);
gtk_css_token_source_error (source, "Expected an integer ID");
gtk_css_token_source_consume_all (source);
return NULL;
}
break;
case GTK_WIN32_PART_WIDTH:
case GTK_WIN32_PART_HEIGHT:
case GTK_WIN32_PART_BORDER_TOP:
case GTK_WIN32_PART_BORDER_RIGHT:
case GTK_WIN32_PART_BORDER_BOTTOM:
case GTK_WIN32_PART_BORDER_LEFT:
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) &&
!gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
_gtk_css_value_unref (result);
gtk_css_token_source_error (source, "Expected an integer part ID");
gtk_css_token_source_consume_all (source);
return NULL;
}
result->val.part.part = token->number.number;
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))
{
_gtk_css_value_unref (result);
gtk_css_token_source_error (source, "Expected ','");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) &&
!gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
_gtk_css_value_unref (result);
gtk_css_token_source_error (source, "Expected an integer state ID");
gtk_css_token_source_consume_all (source);
return NULL;
}
result->val.part.state = token->number.number;
gtk_css_token_source_consume_token (source);
break;
default:
g_assert_not_reached ();
_gtk_css_value_unref (result);
result = NULL;
break;
}
token = gtk_css_token_source_get_token (source);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS))
{
_gtk_css_value_unref (result);
gtk_css_token_source_error (source, "Expected ')'");
gtk_css_token_source_consume_all (source);
return NULL;
}
gtk_css_token_source_consume_token (source);
return result;
}

View File

@@ -26,6 +26,8 @@ G_BEGIN_DECLS
GtkCssValue * gtk_css_win32_size_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags);
GtkCssValue * gtk_css_win32_size_value_token_parse(GtkCssTokenSource *source,
GtkCssNumberParseFlags flags);
G_END_DECLS

View File

@@ -3011,7 +3011,19 @@ gtk_menu_draw (GtkWidget *widget,
gtk_css_gadget_draw (priv->bottom_arrow_gadget, cr);
}
GTK_WIDGET_CLASS (gtk_menu_parent_class)->draw (widget, cr);
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
{
int x, y;
gdk_window_get_position (priv->view_window, &x, &y);
cairo_rectangle (cr,
x, y,
gdk_window_get_width (priv->view_window),
gdk_window_get_height (priv->view_window));
cairo_clip (cr);
GTK_WIDGET_CLASS (gtk_menu_parent_class)->draw (widget, cr);
}
return FALSE;
}

Some files were not shown because too many files have changed in this diff Show More