static gboolean parse_border_radius (GtkCssShorthandProperty *shorthand, GtkCssValue **values, GtkCssParser *parser) { GtkCssValue *x[4] = { NULL, }, *y[4] = { NULL, }; guint i; for (i = 0; i < 4; i++) { if (!gtk_css_number_value_can_parse (parser)) break; x[i] = _gtk_css_number_value_parse (parser, GTK_CSS_POSITIVE_ONLY | GTK_CSS_PARSE_PERCENT | GTK_CSS_NUMBER_AS_PIXELS | GTK_CSS_PARSE_LENGTH); if (x[i] == NULL) goto fail; } if (i == 0) { _gtk_css_parser_error (parser, "Expected a number"); goto fail; } /* The magic (i - 1) >> 1 below makes it take the correct value * according to spec. Feel free to check the 4 cases */ for (; i < 4; i++) x[i] = _gtk_css_value_ref (x[(i - 1) >> 1]); if (_gtk_css_parser_try (parser, "/", TRUE)) { for (i = 0; i < 4; i++) { if (!gtk_css_number_value_can_parse (parser)) break; y[i] = _gtk_css_number_value_parse (parser, GTK_CSS_POSITIVE_ONLY | GTK_CSS_PARSE_PERCENT | GTK_CSS_NUMBER_AS_PIXELS | GTK_CSS_PARSE_LENGTH); if (y[i] == NULL) goto fail; } if (i == 0) { _gtk_css_parser_error (parser, "Expected a number"); goto fail; } for (; i < 4; i++) y[i] = _gtk_css_value_ref (y[(i - 1) >> 1]); } else { for (i = 0; i < 4; i++)
static gboolean parse_four_numbers (GtkCssShorthandProperty *shorthand, GtkCssValue **values, GtkCssParser *parser, GtkCssNumberParseFlags flags) { guint i; for (i = 0; i < 4; i++) { if (!gtk_css_number_value_can_parse (parser)) break; values[i] = _gtk_css_number_value_parse (parser, flags); if (values[i] == NULL) return FALSE; } if (i == 0) { _gtk_css_parser_error (parser, "Expected a length"); return FALSE; } for (; i < 4; i++) { values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]); } return TRUE; }
GtkCssValue * _gtk_css_bg_size_value_parse (GtkCssParser *parser) { GtkCssValue *x, *y; if (_gtk_css_parser_try (parser, "cover", TRUE)) return _gtk_css_value_ref (&cover_singleton); else if (_gtk_css_parser_try (parser, "contain", TRUE)) return _gtk_css_value_ref (&contain_singleton); if (_gtk_css_parser_try (parser, "auto", TRUE)) x = NULL; else { x = _gtk_css_number_value_parse (parser, GTK_CSS_POSITIVE_ONLY | GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH); if (x == NULL) return NULL; } if (_gtk_css_parser_try (parser, "auto", TRUE)) y = NULL; else if (!gtk_css_number_value_can_parse (parser)) y = NULL; else { y = _gtk_css_number_value_parse (parser, GTK_CSS_POSITIVE_ONLY | GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_LENGTH); if (y == NULL) { _gtk_css_value_unref (x); return NULL; } } return _gtk_css_bg_size_value_new (x, y); }
static gboolean gtk_css_image_cross_fade_parse (GtkCssImage *image, GtkCssParser *parser) { GtkCssImageCrossFade *cross_fade = GTK_CSS_IMAGE_CROSS_FADE (image); if (!_gtk_css_parser_try (parser, "cross-fade(", TRUE)) { _gtk_css_parser_error (parser, "Expected 'cross-fade('"); return FALSE; } if (_gtk_css_parser_has_number (parser)) { GtkCssValue *number; number = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_PERCENT | GTK_CSS_POSITIVE_ONLY); if (number == NULL) return FALSE; cross_fade->progress = _gtk_css_number_value_get (number, 1); _gtk_css_value_unref (number); if (cross_fade->progress > 1.0) { _gtk_css_parser_error (parser, "Percentages over 100%% are not allowed"); return FALSE; } } else cross_fade->progress = 0.5; cross_fade->start = _gtk_css_image_new_parse (parser); if (cross_fade->start == NULL) return FALSE; if (_gtk_css_parser_try (parser, ",", TRUE)) { /* XXX: allow parsing colors here */ cross_fade->end = _gtk_css_image_new_parse (parser); if (cross_fade->end == NULL) return FALSE; } if (!_gtk_css_parser_try (parser, ")", TRUE)) { _gtk_css_parser_error (parser, "Missing closing bracket"); return FALSE; } return TRUE; }
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)) { for (i = 0; i < 2; i++) { if (_gtk_css_parser_try (parser, "left", TRUE)) { if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT))) { _gtk_css_parser_error (parser, "Expected 'top', 'bottom' or comma"); return FALSE; } linear->side |= (1 << GTK_CSS_LEFT); } else if (_gtk_css_parser_try (parser, "right", TRUE)) { if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT))) { _gtk_css_parser_error (parser, "Expected 'top', 'bottom' or comma"); return FALSE; } linear->side |= (1 << GTK_CSS_RIGHT); } else if (_gtk_css_parser_try (parser, "top", TRUE)) { if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM))) { _gtk_css_parser_error (parser, "Expected 'left', 'right' or comma"); return FALSE; } linear->side |= (1 << GTK_CSS_TOP); } else if (_gtk_css_parser_try (parser, "bottom", TRUE)) { if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM))) { _gtk_css_parser_error (parser, "Expected 'left', 'right' or comma"); return FALSE; } linear->side |= (1 << GTK_CSS_BOTTOM); } else break; } if (linear->side == 0) { _gtk_css_parser_error (parser, "Expected side that gradient should go to"); return FALSE; } if (!_gtk_css_parser_try (parser, ",", TRUE)) { _gtk_css_parser_error (parser, "Expected a comma"); return FALSE; } } else if (gtk_css_number_value_can_parse (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->side = 1 << GTK_CSS_BOTTOM; do { GtkCssImageLinearColorStop stop; stop.color = _gtk_css_color_value_parse (parser); if (stop.color == NULL) return FALSE; if (gtk_css_number_value_can_parse (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 (linear->stops->len < 2) { _gtk_css_parser_error_full (parser, GTK_CSS_PROVIDER_ERROR_DEPRECATED, "Using one color stop with %s() is deprecated.", linear->repeating ? "repeating-linear-gradient" : "linear-gradient"); } if (!_gtk_css_parser_try (parser, ")", TRUE)) { _gtk_css_parser_error (parser, "Missing closing bracket at end of linear gradient"); return FALSE; } return TRUE; }