gtkcssnumbervalue.c 9.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* GTK - The GIMP Toolkit
 * Copyright (C) 2011 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 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/>.
 */

#include "config.h"

#include "gtkcssnumbervalueprivate.h"

22
#include "gtkcssenumvalueprivate.h"
23
#include "gtkcssinitialvalueprivate.h"
24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include "gtkstylepropertyprivate.h"

struct _GtkCssValue {
  GTK_CSS_VALUE_BASE
  GtkCssUnit unit;
  double value;
};

static void
gtk_css_value_number_free (GtkCssValue *value)
{
  g_slice_free (GtkCssValue, value);
}

38 39 40
static double
get_base_font_size (guint                    property_id,
                    GtkStyleProviderPrivate *provider,
41
                    GtkCssStyle             *style,
42
                    GtkCssStyle             *parent_style)
43 44 45
{
  if (property_id == GTK_CSS_PROPERTY_FONT_SIZE)
    {
46 47
      if (parent_style)
        return _gtk_css_number_value_get (gtk_css_style_get_value (parent_style, GTK_CSS_PROPERTY_FONT_SIZE), 100);
48 49 50 51
      else
        return _gtk_css_font_size_get_default (provider);
    }

52
  return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_SIZE), 100);
53 54
}
                    
55
static GtkCssValue *
56 57 58
gtk_css_value_number_compute (GtkCssValue             *number,
                              guint                    property_id,
                              GtkStyleProviderPrivate *provider,
59
                              GtkCssStyle             *style,
60
                              GtkCssStyle             *parent_style)
61
{
62 63 64 65 66 67
  GtkBorderStyle border_style;

  /* special case according to http://dev.w3.org/csswg/css-backgrounds/#the-border-width */
  switch (property_id)
    {
      case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH:
68
        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
69 70 71 72
        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
        break;
      case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH:
73
        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE));
74 75 76 77
        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
        break;
      case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
78
        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE));
79 80 81 82
        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
        break;
      case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH:
83
        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_STYLE));
84 85 86 87
        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
        break;
      case GTK_CSS_PROPERTY_OUTLINE_WIDTH:
88
        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_STYLE));
89 90 91 92 93 94 95
        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
        break;
      default:
        break;
    }

96 97 98 99 100 101
  switch (number->unit)
    {
    default:
      g_assert_not_reached();
      /* fall through */
    case GTK_CSS_PERCENT:
102 103 104
      /* 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 * 
105
                                          get_base_font_size (property_id, provider, style, parent_style),
106
                                          GTK_CSS_PX);
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    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 *
133
                                        get_base_font_size (property_id, provider, style, parent_style),
134 135 136 137 138
                                        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 * 
139
                                        get_base_font_size (property_id, provider, style, parent_style),
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
                                        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);
    }
}

156 157 158 159 160 161 162 163
static gboolean
gtk_css_value_number_equal (const GtkCssValue *number1,
                            const GtkCssValue *number2)
{
  return number1->unit == number2->unit &&
         number1->value == number2->value;
}

164 165 166
static GtkCssValue *
gtk_css_value_number_transition (GtkCssValue *start,
                                 GtkCssValue *end,
167
                                 guint        property_id,
168 169 170 171 172 173 174 175 176 177 178
                                 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);
}

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
static void
gtk_css_value_number_print (const GtkCssValue *number,
                            GString           *string)
{
  char buf[G_ASCII_DTOSTR_BUF_SIZE];

  const char *names[] = {
    /* [GTK_CSS_NUMBER] = */ "",
    /* [GTK_CSS_PERCENT] = */ "%",
    /* [GTK_CSS_PX] = */ "px",
    /* [GTK_CSS_PT] = */ "pt",
    /* [GTK_CSS_EM] = */ "em",
    /* [GTK_CSS_EX] = */ "ex",
    /* [GTK_CSS_PC] = */ "pc",
    /* [GTK_CSS_IN] = */ "in",
    /* [GTK_CSS_CM] = */ "cm",
    /* [GTK_CSS_MM] = */ "mm",
    /* [GTK_CSS_RAD] = */ "rad",
    /* [GTK_CSS_DEG] = */ "deg",
    /* [GTK_CSS_GRAD] = */ "grad",
    /* [GTK_CSS_TURN] = */ "turn",
200 201
    /* [GTK_CSS_S] = */ "s",
    /* [GTK_CSS_MS] = */ "ms",
202 203 204 205 206 207 208 209 210 211
  };

  g_ascii_dtostr (buf, sizeof (buf), number->value);
  g_string_append (string, buf);
  if (number->value != 0.0)
    g_string_append (string, names[number->unit]);
}

static const GtkCssValueClass GTK_CSS_VALUE_NUMBER = {
  gtk_css_value_number_free,
212
  gtk_css_value_number_compute,
213
  gtk_css_value_number_equal,
214
  gtk_css_value_number_transition,
215 216 217 218 219 220 221
  gtk_css_value_number_print
};

GtkCssValue *
_gtk_css_number_value_new (double     value,
                           GtkCssUnit unit)
{
222 223 224 225
  static GtkCssValue number_singletons[] = {
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_NUMBER, 0 },
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_NUMBER, 1 },
  };
226 227 228 229 230 231 232 233 234
  static GtkCssValue px_singletons[] = {
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 0 },
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 1 },
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 2 },
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 3 },
    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 4 },
  };
  GtkCssValue *result;

235 236
  if (unit == GTK_CSS_NUMBER && (value == 0 || value == 1))
    return _gtk_css_value_ref (&number_singletons[(int) value]);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

  if (unit == GTK_CSS_PX &&
      (value == 0 ||
       value == 1 ||
       value == 2 ||
       value == 3 ||
       value == 4))
    {
      return _gtk_css_value_ref (&px_singletons[(int) value]);
    }

  result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_NUMBER);
  result->unit = unit;
  result->value = value;

  return result;
}

255 256 257 258 259 260 261 262
GtkCssUnit
_gtk_css_number_value_get_unit (const GtkCssValue *value)
{
  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_NUMBER, GTK_CSS_NUMBER);

  return value->unit;
}

263 264 265 266 267 268 269 270 271 272 273 274 275
double
_gtk_css_number_value_get (const GtkCssValue *number,
                           double             one_hundred_percent)
{
  g_return_val_if_fail (number != NULL, 0.0);
  g_return_val_if_fail (number->class == &GTK_CSS_VALUE_NUMBER, 0.0);

  if (number->unit == GTK_CSS_PERCENT)
    return number->value * one_hundred_percent / 100;
  else
    return number->value;
}