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