예제 #1
0
static GtkCssValue *
gtk_css_value_initial_compute (GtkCssValue             *value,
                               guint                    property_id,
                               GtkStyleProviderPrivate *provider,
                               GtkCssStyle             *style,
                               GtkCssStyle             *parent_style)
{
  GtkSettings *settings;

  switch (property_id)
    {
    case GTK_CSS_PROPERTY_DPI:
      settings = _gtk_style_provider_private_get_settings (provider);
      if (settings)
        {
          GdkScreen *screen = _gtk_settings_get_screen (settings);
          double resolution = gdk_screen_get_resolution (screen);

          if (resolution > 0.0)
            return _gtk_css_number_value_new (resolution, GTK_CSS_NUMBER);
        }
      break;

    case GTK_CSS_PROPERTY_FONT_FAMILY:
      settings = _gtk_style_provider_private_get_settings (provider);
      if (settings)
        {
          PangoFontDescription *description;
          char *font_name;
          GtkCssValue *value;

          g_object_get (settings, "gtk-font-name", &font_name, NULL);
          description = pango_font_description_from_string (font_name);
          g_free (font_name);
          if (description == NULL)
            break;

          if (pango_font_description_get_set_fields (description) & PANGO_FONT_MASK_FAMILY)
            {
              value = _gtk_css_array_value_new (_gtk_css_string_value_new (pango_font_description_get_family (description)));
              pango_font_description_free (description);
              return value;
            }
 
          pango_font_description_free (description);
        }
      break;

    default:
      break;
    }

  return _gtk_css_value_compute (_gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (property_id)),
                                 property_id,
                                 provider,
                                 style,
                                 parent_style);
}
예제 #2
0
static GtkCssValue *
gtk_css_value_win32_size_compute (GtkCssValue             *value,
                                  guint                    property_id,
                                  GtkStyleProviderPrivate *provider,
                                  GtkCssStyle             *style,
                                  GtkCssStyle             *parent_style)
{
  return _gtk_css_number_value_new (value->scale * gtk_css_value_win32_compute_size (value), GTK_CSS_PX);
}
예제 #3
0
static GtkCssValue *
gtk_css_value_number_transition (GtkCssValue *start,
                                 GtkCssValue *end,
                                 guint        property_id,
                                 double       progress)
{
  /* FIXME: This needs to be supported at least for percentages,
   * but for that we kinda need to support calc(5px + 50%) */
  if (start->unit != end->unit)
    return NULL;

  return _gtk_css_number_value_new (start->value + (end->value - start->value) * progress,
                                    start->unit);
}
예제 #4
0
static GtkCssValue *
gtk_css_value_number_compute (GtkCssValue             *number,
                              guint                    property_id,
                              GtkStyleProviderPrivate *provider,
			      int                      scale,
                              GtkCssComputedValues    *values,
                              GtkCssComputedValues    *parent_values,
                              GtkCssDependencies      *dependencies)
{
  switch (number->unit)
    {
    default:
      g_assert_not_reached();
      /* fall through */
    case GTK_CSS_PERCENT:
      /* percentages for font sizes are computed, other percentages aren't */
      if (property_id == GTK_CSS_PROPERTY_FONT_SIZE)
        return _gtk_css_number_value_new (number->value / 100.0 * 
                                          get_base_font_size (property_id, provider, values, parent_values, dependencies),
                                          GTK_CSS_PX);
    case GTK_CSS_NUMBER:
    case GTK_CSS_PX:
    case GTK_CSS_DEG:
    case GTK_CSS_S:
      return _gtk_css_value_ref (number);
    case GTK_CSS_PT:
      return _gtk_css_number_value_new (number->value * 96.0 / 72.0,
                                        GTK_CSS_PX);
    case GTK_CSS_PC:
      return _gtk_css_number_value_new (number->value * 96.0 / 72.0 * 12.0,
                                        GTK_CSS_PX);
      break;
    case GTK_CSS_IN:
      return _gtk_css_number_value_new (number->value * 96.0,
                                        GTK_CSS_PX);
      break;
    case GTK_CSS_CM:
      return _gtk_css_number_value_new (number->value * 96.0 * 0.39370078740157477,
                                        GTK_CSS_PX);
      break;
    case GTK_CSS_MM:
      return _gtk_css_number_value_new (number->value * 96.0 * 0.039370078740157477,
                                        GTK_CSS_PX);
      break;
    case GTK_CSS_EM:
      return _gtk_css_number_value_new (number->value *
                                        get_base_font_size (property_id, provider, values, parent_values, dependencies),
                                        GTK_CSS_PX);
      break;
    case GTK_CSS_EX:
      /* for now we pretend ex is half of em */
      return _gtk_css_number_value_new (number->value * 0.5 * 
                                        get_base_font_size (property_id, provider, values, parent_values, dependencies),
                                        GTK_CSS_PX);
    case GTK_CSS_RAD:
      return _gtk_css_number_value_new (number->value * 360.0 / (2 * G_PI),
                                        GTK_CSS_DEG);
    case GTK_CSS_GRAD:
      return _gtk_css_number_value_new (number->value * 360.0 / 400.0,
                                        GTK_CSS_DEG);
    case GTK_CSS_TURN:
      return _gtk_css_number_value_new (number->value * 360.0,
                                        GTK_CSS_DEG);
    case GTK_CSS_MS:
      return _gtk_css_number_value_new (number->value / 1000.0,
                                        GTK_CSS_S);
    }
}
예제 #5
0
파일: gtkcssparser.c 프로젝트: 3v1n0/gtk
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);
}
예제 #6
0
static gboolean
gtk_css_image_radial_parse (GtkCssImage  *image,
                            GtkCssParser *parser)
{
    GtkCssImageRadial *radial = GTK_CSS_IMAGE_RADIAL (image);
    gboolean has_shape = FALSE;
    gboolean has_size = FALSE;
    gboolean found_one = FALSE;
    guint i;
    static 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 }
    };

    if (_gtk_css_parser_try (parser, "repeating-radial-gradient(", TRUE))
        radial->repeating = TRUE;
    else if (_gtk_css_parser_try (parser, "radial-gradient(", TRUE))
        radial->repeating = FALSE;
    else
    {
        _gtk_css_parser_error (parser, "Not a radial gradient");
        return FALSE;
    }

    do {
        found_one = FALSE;
        if (!has_shape && _gtk_css_parser_try (parser, "circle", TRUE))
        {
            radial->circle = TRUE;
            found_one = has_shape = TRUE;
        }
        else if (!has_shape && _gtk_css_parser_try (parser, "ellipse", TRUE))
        {
            radial->circle = FALSE;
            found_one = has_shape = TRUE;
        }
        else if (!has_size)
        {
            for (i = 0; i < G_N_ELEMENTS (names); i++)
            {
                if (_gtk_css_parser_try (parser, names[i].name, TRUE))
                {
                    found_one = has_size = TRUE;
                    radial->size = names[i].value;
                    break;
                }
            }

            if (!has_size)
            {
                if (_gtk_css_parser_has_number (parser))
                    radial->sizes[0] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH | GTK_CSS_PARSE_PERCENT);
                if (_gtk_css_parser_has_number (parser))
                    radial->sizes[1] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH | GTK_CSS_PARSE_PERCENT);
                found_one = has_size = radial->sizes[0] != NULL;
            }
        }

    } while (found_one && !(has_shape && has_size));

    if (_gtk_css_parser_try (parser, "at", TRUE))
    {
        radial->position = _gtk_css_position_value_parse (parser);
        if (!radial->position)
            return FALSE;
        if (!_gtk_css_parser_try (parser, ",", TRUE))
        {
            _gtk_css_parser_error (parser, "Expected a comma here");
            return FALSE;
        }
    }
    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) &&
                !_gtk_css_parser_try (parser, ",", TRUE))
        {
            _gtk_css_parser_error (parser, "Expected a comma here");
            return FALSE;
        }
    }

    if (!has_size)
    {
        radial->size = GTK_CSS_FARTHEST_CORNER;
    }

    if (!has_shape)
    {
        if (radial->sizes[0] && radial->sizes[1])
            radial->circle = FALSE;
        else
            radial->circle = TRUE;
    }

    if (has_shape && radial->circle)
    {
        if (radial->sizes[0] && radial->sizes[1])
        {
            _gtk_css_parser_error (parser, "Circular gradient can only have one size");
            return FALSE;
        }

        if (radial->sizes[0] && _gtk_css_number_value_get_unit (radial->sizes[0]) == GTK_CSS_PERCENT)
        {
            _gtk_css_parser_error (parser, "Circular gradient cannot have percentage as size");
            return FALSE;
        }
    }

    if (has_size && !radial->circle)
    {
        if (!radial->sizes[1])
            radial->sizes[1] = _gtk_css_value_ref (radial->sizes[0]);
    }

    do {
        GtkCssImageRadialColorStop stop;

        stop.color = _gtk_css_color_value_parse (parser);
        if (stop.color == NULL)
            return FALSE;

        if (_gtk_css_parser_has_number (parser))
        {
            stop.offset = _gtk_css_number_value_parse (parser,
                          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);

    } while (_gtk_css_parser_try (parser, ",", TRUE));

    if (!_gtk_css_parser_try (parser, ")", TRUE))
    {
        _gtk_css_parser_error (parser, "Missing closing bracket at end of radial gradient");
        return FALSE;
    }

    return TRUE;
}
예제 #7
0
static gboolean
gtk_css_image_linear_parse (GtkCssImage  *image,
                            GtkCssParser *parser)
{
  GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
  guint i;

  if (_gtk_css_parser_try (parser, "repeating-linear-gradient(", TRUE))
    linear->repeating = TRUE;
  else if (_gtk_css_parser_try (parser, "linear-gradient(", TRUE))
    linear->repeating = FALSE;
  else
    {
      _gtk_css_parser_error (parser, "Not a linear gradient");
      return FALSE;
    }

  if (_gtk_css_parser_try (parser, "to", TRUE))
    {
      guint side = 0;

      for (i = 0; i < 2; i++)
        {
          if (_gtk_css_parser_try (parser, "left", TRUE))
            {
              if (side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT)))
                {
                  _gtk_css_parser_error (parser, "Expected 'top', 'bottom' or comma");
                  return FALSE;
                }
              side |= (1 << GTK_CSS_LEFT);
            }
          else if (_gtk_css_parser_try (parser, "right", TRUE))
            {
              if (side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT)))
                {
                  _gtk_css_parser_error (parser, "Expected 'top', 'bottom' or comma");
                  return FALSE;
                }
              side |= (1 << GTK_CSS_RIGHT);
            }
          else if (_gtk_css_parser_try (parser, "top", TRUE))
            {
              if (side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM)))
                {
                  _gtk_css_parser_error (parser, "Expected 'left', 'right' or comma");
                  return FALSE;
                }
              side |= (1 << GTK_CSS_TOP);
            }
          else if (_gtk_css_parser_try (parser, "bottom", TRUE))
            {
              if (side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM)))
                {
                  _gtk_css_parser_error (parser, "Expected 'left', 'right' or comma");
                  return FALSE;
                }
              side |= (1 << GTK_CSS_BOTTOM);
            }
          else
            break;
        }

      if (side == 0)
        {
          _gtk_css_parser_error (parser, "Expected side that gradient should go to");
          return FALSE;
        }

      linear->angle = _gtk_css_number_value_new (side, GTK_CSS_NUMBER);

      if (!_gtk_css_parser_try (parser, ",", TRUE))
        {
          _gtk_css_parser_error (parser, "Expected a comma");
          return FALSE;
        }
    }
  else if (_gtk_css_parser_has_number (parser))
    {
      linear->angle = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
      if (linear->angle == NULL)
        return FALSE;

      if (!_gtk_css_parser_try (parser, ",", TRUE))
        {
          _gtk_css_parser_error (parser, "Expected a comma");
          return FALSE;
        }
    }
  else
    linear->angle = _gtk_css_number_value_new (1 << GTK_CSS_BOTTOM, GTK_CSS_NUMBER);

  do {
    GtkCssImageLinearColorStop stop;

    stop.color = _gtk_css_color_value_parse (parser);
    if (stop.color == NULL)
      return FALSE;

    if (_gtk_css_parser_has_number (parser))
      {
        stop.offset = _gtk_css_number_value_parse (parser,
                                                   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);

  } while (_gtk_css_parser_try (parser, ",", TRUE));

  if (!_gtk_css_parser_try (parser, ")", TRUE))
    {
      _gtk_css_parser_error (parser, "Missing closing bracket at end of linear gradient");
      return FALSE;
    }

  return TRUE;
}