Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
GFile *
_gtk_css_parser_read_url (GtkCssParser *parser)
{
  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))
            {
              _gtk_css_parser_error_full (parser,
                                          GTK_CSS_PROVIDER_ERROR_DEPRECATED,
                                          "Whitespace between 'url' and '(' is deprecated");
            }
          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 = _gtk_css_parser_get_file_for_path (parser, path);
  g_free (path);

  return file;
}
Exemplo n.º 3
0
gboolean
_gtk_css_parser_try_hash_color (GtkCssParser *parser,
                                GdkRGBA      *rgba)
{
  if (parser->data[0] == '#' &&
      g_ascii_isxdigit (parser->data[1]) &&
      g_ascii_isxdigit (parser->data[2]) &&
      g_ascii_isxdigit (parser->data[3]))
    {
      if (g_ascii_isxdigit (parser->data[4]) &&
          g_ascii_isxdigit (parser->data[5]) &&
          g_ascii_isxdigit (parser->data[6]))
        {
          rgba->red   = ((get_xdigit (parser->data[1]) << 4) + get_xdigit (parser->data[2])) / 255.0;
          rgba->green = ((get_xdigit (parser->data[3]) << 4) + get_xdigit (parser->data[4])) / 255.0;
          rgba->blue  = ((get_xdigit (parser->data[5]) << 4) + get_xdigit (parser->data[6])) / 255.0;
          rgba->alpha = 1.0;
          parser->data += 7;
        }
      else
        {
          rgba->red   = get_xdigit (parser->data[1]) / 15.0;
          rgba->green = get_xdigit (parser->data[2]) / 15.0;
          rgba->blue  = get_xdigit (parser->data[3]) / 15.0;
          rgba->alpha = 1.0;
          parser->data += 4;
        }

      _gtk_css_parser_skip_whitespace (parser);

      return TRUE;
    }

  return FALSE;
}
Exemplo n.º 4
0
gboolean
_gtk_css_parser_try_uint (GtkCssParser *parser,
                          guint        *value)
{
  guint64 result;
  char *end;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
  g_return_val_if_fail (value != NULL, FALSE);

  errno = 0;
  result = g_ascii_strtoull (parser->data, &end, 10);
  if (errno)
    return FALSE;
  if (result > G_MAXUINT)
    return FALSE;
  if (parser->data == end)
    return FALSE;

  parser->data = end;
  *value = result;

  _gtk_css_parser_skip_whitespace (parser);

  return TRUE;
}
Exemplo n.º 5
0
gboolean
_gtk_css_parser_try_int (GtkCssParser *parser,
                         int          *value)
{
  gint64 result;
  char *end;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
  g_return_val_if_fail (value != NULL, FALSE);

  /* strtoll parses a plus, but we are not allowed to */
  if (*parser->data == '+')
    return FALSE;

  errno = 0;
  result = g_ascii_strtoll (parser->data, &end, 10);
  if (errno)
    return FALSE;
  if (result > G_MAXINT || result < G_MININT)
    return FALSE;
  if (parser->data == end)
    return FALSE;

  parser->data = end;
  *value = result;

  _gtk_css_parser_skip_whitespace (parser);

  return TRUE;
}
Exemplo n.º 6
0
char *
_gtk_css_parser_read_string (GtkCssParser *parser)
{
  GString *str;
  char quote;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);

  quote = *parser->data;
  
  if (quote != '"' && quote != '\'')
    {
      _gtk_css_parser_error (parser, "Expected a string.");
      return NULL;
    }
  
  parser->data++;
  str = g_string_new (NULL);

  while (TRUE)
    {
      gsize len = strcspn (parser->data, "\\'\"\n\r\f");

      g_string_append_len (str, parser->data, len);

      parser->data += len;

      switch (*parser->data)
        {
        case '\\':
          _gtk_css_parser_unescape (parser, str);
          break;
        case '"':
        case '\'':
          if (*parser->data == quote)
            {
              parser->data++;
              _gtk_css_parser_skip_whitespace (parser);
              return g_string_free (str, FALSE);
            }
          
          g_string_append_c (str, *parser->data);
          parser->data++;
          break;
        case '\0':
          /* FIXME: position */
          _gtk_css_parser_error (parser, "Missing end quote in string.");
          g_string_free (str, TRUE);
          return NULL;
        default:
          _gtk_css_parser_error (parser, 
                                 "Invalid character in string. Must be escaped.");
          g_string_free (str, TRUE);
          return NULL;
        }
    }

  g_assert_not_reached ();
  return NULL;
}
Exemplo n.º 7
0
char *
_gtk_css_parser_try_ident (GtkCssParser *parser,
                           gboolean      skip_whitespace)
{
  const char *start;
  GString *ident;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);

  start = parser->data;
  
  ident = g_string_new (NULL);

  if (*parser->data == '-')
    {
      g_string_append_c (ident, '-');
      parser->data++;
    }

  if (!_gtk_css_parser_read_char (parser, ident, NMSTART))
    {
      parser->data = start;
      g_string_free (ident, TRUE);
      return NULL;
    }

  while (_gtk_css_parser_read_char (parser, ident, NMCHAR))
    ;

  if (skip_whitespace)
    _gtk_css_parser_skip_whitespace (parser);

  return g_string_free (ident, FALSE);
}
Exemplo n.º 8
0
GtkCssValue *
_gtk_css_ease_value_parse (GtkCssParser *parser)
{
  guint i;

  g_return_val_if_fail (parser != NULL, NULL);

  for (i = 0; i < G_N_ELEMENTS (parser_values); i++)
    {
      if (_gtk_css_parser_try (parser, parser_values[i].name, FALSE))
        {
          if (parser_values[i].needs_custom)
            {
              if (parser_values[i].is_bezier)
                return gtk_css_ease_value_parse_cubic_bezier (parser);
              else
                return gtk_css_ease_value_parse_steps (parser);
            }

          _gtk_css_parser_skip_whitespace (parser);

          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);
        }
    }

  _gtk_css_parser_error (parser, "Unknown value");
  return NULL;
}
Exemplo n.º 9
0
GFile *
_gtk_css_parse_url (GtkCssParser *parser,
                    GFile        *base)
{
  gchar *path;
  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 not allowed");
                             
              _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;
        }
    }
  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;
}
Exemplo n.º 10
0
gboolean
_gtk_css_parser_try (GtkCssParser *parser,
                     const char   *string,
                     gboolean      skip_whitespace)
{
  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
  g_return_val_if_fail (string != NULL, FALSE);

  if (g_ascii_strncasecmp (parser->data, string, strlen (string)) != 0)
    return FALSE;

  parser->data += strlen (string);

  if (skip_whitespace)
    _gtk_css_parser_skip_whitespace (parser);
  return TRUE;
}
Exemplo n.º 11
0
char *
_gtk_css_parser_try_name (GtkCssParser *parser,
                          gboolean      skip_whitespace)
{
  GString *name;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);

  name = g_string_new (NULL);

  while (_gtk_css_parser_read_char (parser, name, NMCHAR))
    ;

  if (skip_whitespace)
    _gtk_css_parser_skip_whitespace (parser);

  return g_string_free (name, FALSE);
}
Exemplo n.º 12
0
gboolean
_gtk_css_parser_try_double (GtkCssParser *parser,
                            gdouble      *value)
{
  gdouble result;
  char *end;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
  g_return_val_if_fail (value != NULL, FALSE);

  errno = 0;
  result = g_ascii_strtod (parser->data, &end);
  if (errno)
    return FALSE;
  if (parser->data == end)
    return FALSE;

  parser->data = end;
  *value = result;

  _gtk_css_parser_skip_whitespace (parser);

  return TRUE;
}
Exemplo n.º 13
0
static GtkSymbolicColor *
gtk_css_parser_try_hash_color (GtkCssParser *parser)
{
  if (parser->data[0] == '#' &&
      g_ascii_isxdigit (parser->data[1]) &&
      g_ascii_isxdigit (parser->data[2]) &&
      g_ascii_isxdigit (parser->data[3]))
    {
      GdkRGBA rgba;
      
      if (g_ascii_isxdigit (parser->data[4]) &&
          g_ascii_isxdigit (parser->data[5]) &&
          g_ascii_isxdigit (parser->data[6]))
        {
          rgba.red   = ((get_xdigit (parser->data[1]) << 4) + get_xdigit (parser->data[2])) / 255.0;
          rgba.green = ((get_xdigit (parser->data[3]) << 4) + get_xdigit (parser->data[4])) / 255.0;
          rgba.blue  = ((get_xdigit (parser->data[5]) << 4) + get_xdigit (parser->data[6])) / 255.0;
          rgba.alpha = 1.0;
          parser->data += 7;
        }
      else
        {
          rgba.red   = get_xdigit (parser->data[1]) / 15.0;
          rgba.green = get_xdigit (parser->data[2]) / 15.0;
          rgba.blue  = get_xdigit (parser->data[3]) / 15.0;
          rgba.alpha = 1.0;
          parser->data += 4;
        }

      _gtk_css_parser_skip_whitespace (parser);

      return gtk_symbolic_color_new_literal (&rgba);
    }

  return NULL;
}
Exemplo n.º 14
0
static void
gtk_css_parser_resync_internal (GtkCssParser *parser,
                                gboolean      sync_at_semicolon,
                                gboolean      read_sync_token,
                                char          terminator)
{
  gsize len;

  do {
    len = strcspn (parser->data, "\\\"'/()[]{};" NEWLINE_CHARS);
    parser->data += len;

    if (gtk_css_parser_new_line (parser))
      continue;

    if (_gtk_css_parser_is_string (parser))
      {
        /* Hrm, this emits errors, and i suspect it shouldn't... */
        char *free_me = _gtk_css_parser_read_string (parser);
        g_free (free_me);
        continue;
      }

    if (gtk_css_parser_skip_comment (parser))
      continue;

    switch (*parser->data)
      {
      case '\\':
        {
          GString *ignore = g_string_new (NULL);
          _gtk_css_parser_unescape (parser, ignore);
          g_string_free (ignore, TRUE);
        }
        break;
      case ';':
        if (sync_at_semicolon && !read_sync_token)
          return;
        parser->data++;
        if (sync_at_semicolon)
          {
            _gtk_css_parser_skip_whitespace (parser);
            return;
          }
        break;
      case '(':
        parser->data++;
        _gtk_css_parser_resync (parser, FALSE, ')');
        if (*parser->data)
          parser->data++;
        break;
      case '[':
        parser->data++;
        _gtk_css_parser_resync (parser, FALSE, ']');
        if (*parser->data)
          parser->data++;
        break;
      case '{':
        parser->data++;
        _gtk_css_parser_resync (parser, FALSE, '}');
        if (*parser->data)
          parser->data++;
        if (sync_at_semicolon || !terminator)
          {
            _gtk_css_parser_skip_whitespace (parser);
            return;
          }
        break;
      case '}':
      case ')':
      case ']':
        if (terminator == *parser->data)
          {
            _gtk_css_parser_skip_whitespace (parser);
            return;
          }
        parser->data++;
        continue;
      case '\0':
        break;
      case '/':
      default:
        parser->data++;
        break;
      }
  } while (*parser->data);
}
Exemplo n.º 15
0
GtkCssValue *
_gtk_css_number_value_parse (GtkCssParser           *parser,
                             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  },
    { "s",    GTK_CSS_S,       GTK_CSS_PARSE_TIME   },
    { "ms",   GTK_CSS_MS,      GTK_CSS_PARSE_TIME   }
  };
  char *end, *unit_name;
  double value;
  GtkCssUnit unit;

  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);

  errno = 0;
  value = g_ascii_strtod (parser->data, &end);
  if (errno)
    {
      _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno));
      return NULL;
    }
  if (parser->data == end)
    {
      _gtk_css_parser_error (parser, "not a number");
      return NULL;
    }

  parser->data = end;

  if (flags & GTK_CSS_POSITIVE_ONLY &&
      value < 0)
    {
      _gtk_css_parser_error (parser, "negative values are not allowed.");
      return NULL;
    }

  unit_name = _gtk_css_parser_try_ident (parser, FALSE);

  if (unit_name)
    {
      guint i;

      for (i = 0; i < G_N_ELEMENTS (units); i++)
        {
          if (flags & units[i].required_flags &&
              g_ascii_strcasecmp (unit_name, units[i].name) == 0)
            break;
        }

      if (i >= G_N_ELEMENTS (units))
        {
          _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit_name);
          g_free (unit_name);
          return NULL;
        }

      unit = units[i].unit;

      g_free (unit_name);
    }
  else
    {
      if ((flags & GTK_CSS_PARSE_PERCENT) &&
          _gtk_css_parser_try (parser, "%", FALSE))
        {
          unit = GTK_CSS_PERCENT;
        }
      else if (value == 0.0)
        {
          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 (flags & GTK_CSS_PARSE_TIME)
            unit = GTK_CSS_S;
          else
            unit = GTK_CSS_PERCENT;
        }
      else if (flags & GTK_CSS_NUMBER_AS_PIXELS)
        {
          _gtk_css_parser_error_full (parser,
                                      GTK_CSS_PROVIDER_ERROR_DEPRECATED,
                                      "Not using units is deprecated. Assuming 'px'.");
          unit = GTK_CSS_PX;
        }
      else if (flags & GTK_CSS_PARSE_NUMBER)
        {
          unit = GTK_CSS_NUMBER;
        }
      else
        {
          _gtk_css_parser_error (parser, "Unit is missing.");
          return NULL;
        }
    }

  _gtk_css_parser_skip_whitespace (parser);

  return _gtk_css_number_value_new (value, unit);
}