]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkcssparser.c
Assamese translation completed
[~andy/gtk] / gtk / gtkcssparser.c
index e9fe6a4fdb795c8a38c701ea2435dcddf038412e..b6fae8768678a53a2d2b56f7b643c5440af6b7b3 100644 (file)
  * 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, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
 
 #include "gtkcssparserprivate.h"
+#include "gtkwin32themeprivate.h"
 
 #include <errno.h>
 #include <string.h>
@@ -61,7 +60,7 @@ _gtk_css_parser_new (const char            *data,
   parser->user_data = user_data;
 
   parser->line_start = data;
-  parser->line = 1;
+  parser->line = 0;
 
   return parser;
 }
@@ -91,6 +90,15 @@ _gtk_css_parser_begins_with (GtkCssParser *parser,
   return *parser->data == c;
 }
 
+gboolean
+_gtk_css_parser_has_prefix (GtkCssParser *parser,
+                            const char   *prefix)
+{
+  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+
+  return g_ascii_strncasecmp (parser->data, prefix, strlen (prefix)) == 0;
+}
+
 guint
 _gtk_css_parser_get_line (GtkCssParser *parser)
 {
@@ -436,55 +444,6 @@ _gtk_css_parser_read_string (GtkCssParser *parser)
   return NULL;
 }
 
-char *
-_gtk_css_parser_read_uri (GtkCssParser *parser)
-{
-  char *result;
-
-  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
-
-  if (!_gtk_css_parser_try (parser, "url(", TRUE))
-    {
-      _gtk_css_parser_error (parser, "expected 'url('");
-      return NULL;
-    }
-
-  _gtk_css_parser_skip_whitespace (parser);
-
-  if (_gtk_css_parser_is_string (parser))
-    {
-      result = _gtk_css_parser_read_string (parser);
-    }
-  else
-    {
-      GString *str = g_string_new (NULL);
-
-      while (_gtk_css_parser_read_char (parser, str, URLCHAR))
-        ;
-      result = g_string_free (str, FALSE);
-      if (result == NULL)
-        _gtk_css_parser_error (parser, "not a url");
-    }
-  
-  if (result == NULL)
-    return NULL;
-
-  _gtk_css_parser_skip_whitespace (parser);
-
-  if (*parser->data != ')')
-    {
-      _gtk_css_parser_error (parser, "missing ')' for url");
-      g_free (result);
-      return NULL;
-    }
-
-  parser->data++;
-
-  _gtk_css_parser_skip_whitespace (parser);
-
-  return result;
-}
-
 gboolean
 _gtk_css_parser_try_int (GtkCssParser *parser,
                          int          *value)
@@ -568,6 +527,192 @@ _gtk_css_parser_try_double (GtkCssParser *parser,
   return TRUE;
 }
 
+gboolean
+_gtk_css_parser_has_number (GtkCssParser *parser)
+{
+  /* ahem */
+  return strchr ("+-0123456789.", parser->data[0]) != NULL;
+}
+
+gboolean
+_gtk_css_parser_read_number (GtkCssParser           *parser,
+                             GtkCssNumber           *number,
+                             GtkCssNumberParseFlags  flags)
+{
+  static const struct {
+    const char *name;
+    GtkCssUnit unit;
+    GtkCssNumberParseFlags required_flags;
+  } 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 },
+    { "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  }
+  };
+  char *end, *unit;
+
+  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+  g_return_val_if_fail (number != NULL, FALSE);
+
+  errno = 0;
+  number->unit = GTK_CSS_NUMBER;
+  number->value = g_ascii_strtod (parser->data, &end);
+  if (errno)
+    {
+      _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno));
+      return FALSE;
+    }
+  if (parser->data == end)
+    {
+      _gtk_css_parser_error (parser, "not a number");
+      return FALSE;
+    }
+
+  parser->data = end;
+
+  if (flags & GTK_CSS_POSITIVE_ONLY &&
+      number->value < 0)
+    {
+      _gtk_css_parser_error (parser, "negative values are not allowed.");
+      return FALSE;
+    }
+
+  unit = _gtk_css_parser_try_ident (parser, FALSE);
+
+  if (unit)
+    {
+      guint i;
+
+      for (i = 0; i < G_N_ELEMENTS (units); i++)
+        {
+          if (flags & units[i].required_flags &&
+              g_ascii_strcasecmp (unit, units[i].name) == 0)
+            break;
+        }
+
+      if (i >= G_N_ELEMENTS (units))
+        {
+          _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit);
+          g_free (unit);
+          return FALSE;
+        }
+
+      number->unit = units[i].unit;
+      g_free (unit);
+    }
+  else
+    {
+      if ((flags & GTK_CSS_PARSE_PERCENT) &&
+          _gtk_css_parser_try (parser, "%", FALSE))
+        {
+          number->unit = GTK_CSS_PERCENT;
+        }
+      else if (number->value == 0.0)
+        {
+          if (flags & GTK_CSS_PARSE_NUMBER)
+            number->unit = GTK_CSS_NUMBER;
+          else if (flags & GTK_CSS_PARSE_LENGTH)
+            number->unit = GTK_CSS_PX;
+          else
+            number->unit = GTK_CSS_PERCENT;
+        }
+      else if (flags & GTK_CSS_NUMBER_AS_PIXELS)
+        {
+          GError *error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
+                                               GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+                                               "Not using units is deprecated. Assuming 'px'.");
+          _gtk_css_parser_take_error (parser, error);
+          number->unit = GTK_CSS_PX;
+        }
+      else if (flags & GTK_CSS_PARSE_NUMBER)
+        {
+          number->unit = GTK_CSS_NUMBER;
+        }
+      else
+        {
+          _gtk_css_parser_error (parser, "Unit is missing.");
+          return FALSE;
+        }
+    }
+
+  _gtk_css_parser_skip_whitespace (parser);
+
+  return TRUE;
+}
+
+/* XXX: we should introduce GtkCssLenght that deals with
+ * different kind of units */
+gboolean
+_gtk_css_parser_try_length (GtkCssParser *parser,
+                            int          *value)
+{
+  if (!_gtk_css_parser_try_int (parser, value))
+    return FALSE;
+
+  /* FIXME: _try_uint skips spaces while the
+   * spec forbids them
+   */
+  _gtk_css_parser_try (parser, "px", TRUE);
+
+  return TRUE;
+}
+
+gboolean
+_gtk_css_parser_try_enum (GtkCssParser *parser,
+                         GType         enum_type,
+                         int          *value)
+{
+  GEnumClass *enum_class;
+  gboolean result;
+  const char *start;
+  char *str;
+
+  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+  g_return_val_if_fail (value != NULL, FALSE);
+
+  result = FALSE;
+
+  enum_class = g_type_class_ref (enum_type);
+
+  start = parser->data;
+
+  str = _gtk_css_parser_try_ident (parser, TRUE);
+  if (str == NULL)
+    return FALSE;
+
+  if (enum_class->n_values)
+    {
+      GEnumValue *enum_value;
+
+      for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
+       {
+         if (enum_value->value_nick &&
+             g_ascii_strcasecmp (str, enum_value->value_nick) == 0)
+           {
+             *value = enum_value->value;
+             result = TRUE;
+             break;
+           }
+       }
+    }
+
+  g_free (str);
+  g_type_class_unref (enum_class);
+
+  if (!result)
+    parser->data = start;
+
+  return result;
+}
+
 typedef enum {
   COLOR_RGBA,
   COLOR_RGB,
@@ -575,7 +720,8 @@ typedef enum {
   COLOR_DARKER,
   COLOR_SHADE,
   COLOR_ALPHA,
-  COLOR_MIX
+  COLOR_MIX,
+  COLOR_WIN32
 } ColorType;
 
 static GtkSymbolicColor *
@@ -644,6 +790,12 @@ gtk_css_parser_read_symbolic_color_function (GtkCssParser *parser,
       
       symbolic = gtk_symbolic_color_new_literal (&rgba);
     }
+  else if (color == COLOR_WIN32)
+    {
+      symbolic = _gtk_win32_theme_color_parse (parser);
+      if (symbolic == NULL)
+       return NULL;
+    }
   else
     {
       child1 = _gtk_css_parser_read_symbolic_color (parser);
@@ -769,11 +921,19 @@ _gtk_css_parser_read_symbolic_color (GtkCssParser *parser)
 {
   GtkSymbolicColor *symbolic;
   guint color;
-  const char *names[] = {"rgba", "rgb",  "lighter", "darker", "shade", "alpha", "mix" };
+  const char *names[] = {"rgba", "rgb",  "lighter", "darker", "shade", "alpha", "mix",
+                        GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME};
   char *name;
 
   g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
 
+  if (_gtk_css_parser_try (parser, "transparent", TRUE))
+    {
+      GdkRGBA transparent = { 0, 0, 0, 0 };
+      
+      return gtk_symbolic_color_new_literal (&transparent);
+    }
+
   if (_gtk_css_parser_try (parser, "@", FALSE))
     {
       name = _gtk_css_parser_try_name (parser, TRUE);
@@ -827,6 +987,72 @@ _gtk_css_parser_read_symbolic_color (GtkCssParser *parser)
   return NULL;
 }
 
+GFile *
+_gtk_css_parser_read_url (GtkCssParser *parser,
+                          GFile        *base)
+{
+  gchar *path;
+  char *scheme;
+  GFile *file;
+
+  if (_gtk_css_parser_try (parser, "url", FALSE))
+    {
+      if (!_gtk_css_parser_try (parser, "(", TRUE))
+        {
+          _gtk_css_parser_skip_whitespace (parser);
+          if (_gtk_css_parser_try (parser, "(", TRUE))
+            {
+              GError *error;
+              
+              error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
+                                           GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+                                           "Whitespace between 'url' and '(' is deprecated");
+                             
+              _gtk_css_parser_take_error (parser, error);
+            }
+          else
+            {
+              _gtk_css_parser_error (parser, "Expected '(' after 'url'");
+              return NULL;
+            }
+        }
+
+      path = _gtk_css_parser_read_string (parser);
+      if (path == NULL)
+        return NULL;
+
+      if (!_gtk_css_parser_try (parser, ")", TRUE))
+        {
+          _gtk_css_parser_error (parser, "No closing ')' found for 'url'");
+          g_free (path);
+          return NULL;
+        }
+
+      scheme = g_uri_parse_scheme (path);
+      if (scheme != NULL)
+       {
+         file = g_file_new_for_uri (path);
+         g_free (path);
+         g_free (scheme);
+         return file;
+       }
+    }
+  else
+    {
+      path = _gtk_css_parser_try_name (parser, TRUE);
+      if (path == NULL)
+        {
+          _gtk_css_parser_error (parser, "Not a valid url");
+          return NULL;
+        }
+    }
+
+  file = g_file_resolve_relative_path (base, path);
+  g_free (path);
+
+  return file;
+}
+
 void
 _gtk_css_parser_resync_internal (GtkCssParser *parser,
                                  gboolean      sync_at_semicolon,
@@ -875,17 +1101,20 @@ _gtk_css_parser_resync_internal (GtkCssParser *parser,
       case '(':
         parser->data++;
         _gtk_css_parser_resync (parser, FALSE, ')');
-        parser->data++;
+        if (*parser->data)
+          parser->data++;
         break;
       case '[':
         parser->data++;
         _gtk_css_parser_resync (parser, FALSE, ']');
-        parser->data++;
+        if (*parser->data)
+          parser->data++;
         break;
       case '{':
         parser->data++;
         _gtk_css_parser_resync (parser, FALSE, '}');
-        parser->data++;
+        if (*parser->data)
+          parser->data++;
         if (sync_at_semicolon || !terminator)
           {
             _gtk_css_parser_skip_whitespace (parser);
@@ -902,6 +1131,8 @@ _gtk_css_parser_resync_internal (GtkCssParser *parser,
           }
         parser->data++;
         continue;
+      case '\0':
+        break;
       case '/':
       default:
         parser->data++;