mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
LibWeb: Parse CSS image-set()
Add an abstract image style value for image-set() and parse both the standard and -webkit-prefixed spellings through the existing <image> value path. The parser accepts URL and string image candidates, optional resolution descriptors, and type() filters. Track attr-taint through substituted component values so image-set() candidates using attr()-derived URL-producing tokens are rejected when resolved for URL-using properties. Update the relevant WPT baselines now that image-set() parsing is supported in additional value contexts.
This commit is contained in:
committed by
Andreas Kling
parent
30f37d691c
commit
61d79a1e47
Notes:
github-actions[bot]
2026-04-25 12:55:37 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/61d79a1e47a Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/9090
@@ -264,6 +264,7 @@ set(SOURCES
|
||||
CSS/StyleValues/GridTemplateAreaStyleValue.cpp
|
||||
CSS/StyleValues/GridTrackPlacementStyleValue.cpp
|
||||
CSS/StyleValues/GridTrackSizeListStyleValue.cpp
|
||||
CSS/StyleValues/ImageSetStyleValue.cpp
|
||||
CSS/StyleValues/ImageStyleValue.cpp
|
||||
CSS/StyleValues/IntegerStyleValue.cpp
|
||||
CSS/StyleValues/KeywordStyleValue.cpp
|
||||
|
||||
@@ -85,6 +85,22 @@ bool contains_guaranteed_invalid_value(Vector<ComponentValue> const& values)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool contains_attr_tainted_value(Vector<ComponentValue> const& values)
|
||||
{
|
||||
for (auto const& value : values) {
|
||||
if (value.contains_attr_tainted_value())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Vector<ComponentValue> mark_as_attr_tainted(Vector<ComponentValue> values)
|
||||
{
|
||||
for (auto& value : values)
|
||||
value.set_attr_tainted();
|
||||
return values;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-values-5/#replace-an-attr-function
|
||||
static Vector<ComponentValue> replace_an_attr_function(DOM::AbstractElement& element, GuardedSubstitutionContexts& guarded_contexts, ArbitrarySubstitutionFunctionArguments const& arguments)
|
||||
{
|
||||
@@ -218,7 +234,7 @@ static Vector<ComponentValue> replace_an_attr_function(DOM::AbstractElement& ele
|
||||
});
|
||||
if (return_from_step_4) {
|
||||
if (step_4_result.has_value())
|
||||
return step_4_result.release_value();
|
||||
return mark_as_attr_tainted(step_4_result.release_value());
|
||||
return failure();
|
||||
}
|
||||
|
||||
@@ -228,7 +244,7 @@ static Vector<ComponentValue> replace_an_attr_function(DOM::AbstractElement& ele
|
||||
[](Empty) { return true; },
|
||||
[](RawStringKeyword) { return true; },
|
||||
[](auto&) { return false; })) {
|
||||
return { Token::create_string(*attribute_value) };
|
||||
return mark_as_attr_tainted({ Token::create_string(*attribute_value) });
|
||||
}
|
||||
|
||||
// 6. Substitute arbitrary substitution functions in attr value, with «"attribute", attr name» as the substitution
|
||||
@@ -242,7 +258,7 @@ static Vector<ComponentValue> replace_an_attr_function(DOM::AbstractElement& ele
|
||||
auto parsed_value = parse_with_a_syntax(ParsingParams { element.document() }, substituted_values, *syntax.get<NonnullOwnPtr<SyntaxNode>>());
|
||||
if (parsed_value->is_guaranteed_invalid())
|
||||
return failure();
|
||||
return parsed_value->tokenize();
|
||||
return mark_as_attr_tainted(parsed_value->tokenize());
|
||||
|
||||
// 7. FAILURE:
|
||||
// NB: Step 7 is a lambda defined at the top of the function.
|
||||
@@ -317,6 +333,7 @@ static Vector<ComponentValue> replace_an_if_function(DOM::AbstractElement& eleme
|
||||
// 1. Substitute arbitrary substitution functions in the first <declaration-value> of branch, then parse the
|
||||
// result as an <if-condition>. If parsing returns failure, continue; otherwise, let the result be condition.
|
||||
auto substituted_condition = substitute_arbitrary_substitution_functions(element, guarded_contexts, branch.condition);
|
||||
auto condition_is_attr_tainted = contains_attr_tainted_value(substituted_condition);
|
||||
|
||||
TokenStream<ComponentValue> tokens { substituted_condition };
|
||||
auto maybe_parsed_if_condition = parser.parse_if_condition(tokens);
|
||||
@@ -339,7 +356,10 @@ static Vector<ComponentValue> replace_an_if_function(DOM::AbstractElement& eleme
|
||||
if (!branch.value.has_value())
|
||||
return {};
|
||||
|
||||
return substitute_arbitrary_substitution_functions(element, guarded_contexts, branch.value.value());
|
||||
auto result = substitute_arbitrary_substitution_functions(element, guarded_contexts, branch.value.value());
|
||||
if (condition_is_attr_tainted)
|
||||
return mark_as_attr_tainted(move(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. Return nothing (an empty sequence of component values).
|
||||
|
||||
@@ -106,4 +106,28 @@ bool ComponentValue::contains_guaranteed_invalid_value() const
|
||||
});
|
||||
}
|
||||
|
||||
bool ComponentValue::contains_attr_tainted_value() const
|
||||
{
|
||||
if (m_attr_tainted)
|
||||
return true;
|
||||
|
||||
return m_value.visit(
|
||||
[](Token const&) {
|
||||
return false;
|
||||
},
|
||||
[](SimpleBlock const& block) {
|
||||
return block.value
|
||||
.first_matching([](auto const& it) { return it.contains_attr_tainted_value(); })
|
||||
.has_value();
|
||||
},
|
||||
[](Function const& function) {
|
||||
return function.value
|
||||
.first_matching([](auto const& it) { return it.contains_attr_tainted_value(); })
|
||||
.has_value();
|
||||
},
|
||||
[](GuaranteedInvalidValue const&) {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ public:
|
||||
|
||||
bool is_guaranteed_invalid() const { return m_value.has<GuaranteedInvalidValue>(); }
|
||||
bool contains_guaranteed_invalid_value() const;
|
||||
bool contains_attr_tainted_value() const;
|
||||
void set_attr_tainted() { m_attr_tainted = true; }
|
||||
|
||||
String to_string() const;
|
||||
String to_debug_string() const;
|
||||
@@ -53,6 +55,7 @@ public:
|
||||
|
||||
private:
|
||||
Variant<Token, Function, SimpleBlock, GuaranteedInvalidValue> m_value;
|
||||
bool m_attr_tainted { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -427,7 +427,13 @@ private:
|
||||
RefPtr<StyleValue const> parse_rect_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_ratio_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StringStyleValue const> parse_string_value(TokenStream<ComponentValue>&);
|
||||
enum class AllowImageSet {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
RefPtr<AbstractImageStyleValue const> parse_image_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<AbstractImageStyleValue const> parse_image_value(TokenStream<ComponentValue>&, AllowImageSet);
|
||||
RefPtr<ImageSetStyleValue const> parse_image_set_function(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_paint_value(TokenStream<ComponentValue>&);
|
||||
enum class PositionParsingMode {
|
||||
Normal,
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GuaranteedInvalidStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ImageSetStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/KeywordStyleValue.h>
|
||||
@@ -2674,6 +2675,92 @@ RefPtr<StringStyleValue const> Parser::parse_string_value(TokenStream<ComponentV
|
||||
}
|
||||
|
||||
RefPtr<AbstractImageStyleValue const> Parser::parse_image_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
return parse_image_value(tokens, AllowImageSet::Yes);
|
||||
}
|
||||
|
||||
RefPtr<ImageSetStyleValue const> Parser::parse_image_set_function(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
auto const& function_token = tokens.next_token();
|
||||
if (!function_token.is_function("image-set"sv) && !function_token.is_function("-webkit-image-set"sv))
|
||||
return nullptr;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto const& function = tokens.consume_a_token().function();
|
||||
TokenStream function_tokens { function.value };
|
||||
auto image_set_options_tokens = parse_a_comma_separated_list_of_component_values(function_tokens);
|
||||
function_tokens.discard_whitespace();
|
||||
if (!function_tokens.is_empty())
|
||||
return nullptr;
|
||||
|
||||
Vector<ImageSetStyleValue::Option> options;
|
||||
options.ensure_capacity(image_set_options_tokens.size());
|
||||
for (auto const& option_tokens_list : image_set_options_tokens) {
|
||||
if (option_tokens_list.first_matching([](auto const& component_value) { return component_value.contains_attr_tainted_value(); }).has_value())
|
||||
return nullptr;
|
||||
|
||||
TokenStream option_tokens { option_tokens_list };
|
||||
option_tokens.discard_whitespace();
|
||||
|
||||
RefPtr<AbstractImageStyleValue const> image;
|
||||
if (option_tokens.next_token().is(Token::Type::String)) {
|
||||
auto url = URL { option_tokens.consume_a_token().token().string().to_string() };
|
||||
image = ImageStyleValue::create(url);
|
||||
} else {
|
||||
image = parse_image_value(option_tokens, AllowImageSet::No);
|
||||
}
|
||||
if (!image)
|
||||
return nullptr;
|
||||
|
||||
RefPtr<StyleValue const> resolution;
|
||||
Optional<String> type;
|
||||
while (true) {
|
||||
option_tokens.discard_whitespace();
|
||||
if (option_tokens.is_empty())
|
||||
break;
|
||||
|
||||
if (!resolution) {
|
||||
if (auto parsed_resolution = parse_resolution_value(option_tokens, infinite_range)) {
|
||||
resolution = parsed_resolution;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!type.has_value() && option_tokens.next_token().is_function("type"sv)) {
|
||||
auto const& type_function = option_tokens.consume_a_token().function();
|
||||
TokenStream type_tokens { type_function.value };
|
||||
type_tokens.discard_whitespace();
|
||||
if (!type_tokens.next_token().is(Token::Type::String))
|
||||
return nullptr;
|
||||
type = type_tokens.consume_a_token().token().string().to_string();
|
||||
type_tokens.discard_whitespace();
|
||||
if (!type_tokens.is_empty())
|
||||
return nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!resolution)
|
||||
resolution = ResolutionStyleValue::create(Resolution { 1, ResolutionUnit::X });
|
||||
|
||||
options.unchecked_append({
|
||||
.image = image.release_nonnull(),
|
||||
.resolution = resolution.release_nonnull(),
|
||||
.type = move(type),
|
||||
});
|
||||
}
|
||||
|
||||
if (options.is_empty())
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return ImageSetStyleValue::create(move(options));
|
||||
}
|
||||
|
||||
RefPtr<AbstractImageStyleValue const> Parser::parse_image_value(TokenStream<ComponentValue>& tokens, AllowImageSet allow_image_set)
|
||||
{
|
||||
tokens.mark();
|
||||
auto url = parse_url_function(tokens);
|
||||
@@ -2690,6 +2777,11 @@ RefPtr<AbstractImageStyleValue const> Parser::parse_image_value(TokenStream<Comp
|
||||
}
|
||||
tokens.discard_a_mark();
|
||||
|
||||
if (allow_image_set == AllowImageSet::Yes) {
|
||||
if (auto image_set = parse_image_set_function(tokens))
|
||||
return image_set;
|
||||
}
|
||||
|
||||
if (auto linear_gradient = parse_linear_gradient_function(tokens))
|
||||
return linear_gradient;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "AbstractImageStyleValue.h"
|
||||
#include <LibWeb/CSS/CSSImageValue.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
@@ -16,6 +17,11 @@ GC::Ref<CSSStyleValue> AbstractImageStyleValue::reify(JS::Realm& realm, FlyStrin
|
||||
return CSSImageValue::create(realm, *this);
|
||||
}
|
||||
|
||||
void AbstractImageStyleValue::load_any_resources(Layout::NodeWithStyle const& layout_node)
|
||||
{
|
||||
load_any_resources(const_cast<DOM::Document&>(layout_node.document()));
|
||||
}
|
||||
|
||||
ColorStopListElement ColorStopListElement::absolutized(ComputationContext const& context) const
|
||||
{
|
||||
auto absolutize_if_nonnull = [&context](RefPtr<StyleValue const> const& input) -> RefPtr<StyleValue const> {
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void load_any_resources(DOM::Document&) { }
|
||||
virtual void load_any_resources(Layout::NodeWithStyle const&);
|
||||
virtual void resolve_for_size(Layout::NodeWithStyle const&, CSSPixelSize) const { }
|
||||
|
||||
virtual bool is_paintable() const = 0;
|
||||
|
||||
250
Libraries/LibWeb/CSS/StyleValues/ImageSetStyleValue.cpp
Normal file
250
Libraries/LibWeb/CSS/StyleValues/ImageSetStyleValue.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/CSS/CSSStyleSheet.h>
|
||||
#include <LibWeb/CSS/Resolution.h>
|
||||
#include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ImageSetStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ResolutionStyleValue.h>
|
||||
#include <LibWeb/DOM/AbstractElement.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/HTML/SupportedImageTypes.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/Painting/DisplayListRecordingContext.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
ValueComparingNonnullRefPtr<ImageSetStyleValue const> ImageSetStyleValue::create(Vector<Option> options)
|
||||
{
|
||||
return adopt_ref(*new (nothrow) ImageSetStyleValue(move(options)));
|
||||
}
|
||||
|
||||
ImageSetStyleValue::ImageSetStyleValue(Vector<Option> options)
|
||||
: AbstractImageStyleValue(Type::ImageSet)
|
||||
, m_options(move(options))
|
||||
{
|
||||
}
|
||||
|
||||
static Optional<double> option_resolution_in_dppx(ImageSetStyleValue::Option const& option, Optional<CalculationResolutionContext> const& calculation_resolution_context)
|
||||
{
|
||||
if (option.resolution->is_resolution())
|
||||
return option.resolution->as_resolution().resolution().to_dots_per_pixel();
|
||||
if (option.resolution->is_calculated()) {
|
||||
auto resolution = option.resolution->as_calculated().resolve_resolution(calculation_resolution_context.value_or({}));
|
||||
if (resolution.has_value())
|
||||
return resolution->to_dots_per_pixel();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
AbstractImageStyleValue const* ImageSetStyleValue::select_image(double device_pixels_per_css_pixel, Optional<CalculationResolutionContext> const& calculation_resolution_context) const
|
||||
{
|
||||
ImageSetStyleValue::Option const* best_below_or_equal = nullptr;
|
||||
Optional<double> best_below_or_equal_resolution;
|
||||
ImageSetStyleValue::Option const* best_above = nullptr;
|
||||
Optional<double> best_above_resolution;
|
||||
|
||||
for (auto const& option : m_options) {
|
||||
if (option.type.has_value() && !HTML::is_supported_image_type(*option.type))
|
||||
continue;
|
||||
|
||||
auto resolution = option_resolution_in_dppx(option, calculation_resolution_context);
|
||||
if (!resolution.has_value())
|
||||
continue;
|
||||
|
||||
if (*resolution >= device_pixels_per_css_pixel) {
|
||||
if (!best_above_resolution.has_value() || *resolution < *best_above_resolution) {
|
||||
best_above = &option;
|
||||
best_above_resolution = *resolution;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!best_below_or_equal_resolution.has_value() || *resolution > *best_below_or_equal_resolution) {
|
||||
best_below_or_equal = &option;
|
||||
best_below_or_equal_resolution = *resolution;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_above)
|
||||
return best_above->image.ptr();
|
||||
if (best_below_or_equal)
|
||||
return best_below_or_equal->image.ptr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::visit_edges(JS::Cell::Visitor& visitor) const
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_style_sheet);
|
||||
for (auto const& option : m_options)
|
||||
option.image->visit_edges(visitor);
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::serialize(StringBuilder& builder, SerializationMode mode) const
|
||||
{
|
||||
builder.append("image-set("sv);
|
||||
for (size_t i = 0; i < m_options.size(); ++i) {
|
||||
if (i > 0)
|
||||
builder.append(", "sv);
|
||||
auto const& option = m_options[i];
|
||||
option.image->serialize(builder, mode);
|
||||
builder.append(' ');
|
||||
option.resolution->serialize(builder, mode);
|
||||
if (option.type.has_value()) {
|
||||
builder.append(" type(\""sv);
|
||||
builder.append_escaped_for_json(*option.type);
|
||||
builder.append("\")"sv);
|
||||
}
|
||||
}
|
||||
builder.append(')');
|
||||
}
|
||||
|
||||
bool ImageSetStyleValue::equals(StyleValue const& other) const
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
auto const& other_image_set = other.as_image_set();
|
||||
if (m_options.size() != other_image_set.m_options.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < m_options.size(); ++i) {
|
||||
auto const& option = m_options[i];
|
||||
auto const& other_option = other_image_set.m_options[i];
|
||||
if (!option.image->equals(*other_option.image))
|
||||
return false;
|
||||
if (!option.resolution->equals(*other_option.resolution))
|
||||
return false;
|
||||
if (option.type != other_option.type)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImageSetStyleValue::is_computationally_independent() const
|
||||
{
|
||||
for (auto const& option : m_options) {
|
||||
if (!option.image->is_computationally_independent())
|
||||
return false;
|
||||
if (!option.resolution->is_computationally_independent())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::load_any_resources(DOM::Document& document)
|
||||
{
|
||||
auto dpr = document.page().client().device_pixels_per_css_pixel();
|
||||
if (auto const* image = select_image(dpr, {}); image && image != m_selected_image) {
|
||||
const_cast<AbstractImageStyleValue&>(*image).set_style_sheet(m_style_sheet);
|
||||
m_selected_image = image;
|
||||
}
|
||||
if (m_selected_image)
|
||||
const_cast<AbstractImageStyleValue&>(*m_selected_image).load_any_resources(document);
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::load_any_resources(Layout::NodeWithStyle const& layout_node)
|
||||
{
|
||||
update_selected_image_for_layout_node(layout_node);
|
||||
if (m_selected_image)
|
||||
const_cast<AbstractImageStyleValue&>(*m_selected_image).load_any_resources(const_cast<DOM::Document&>(layout_node.document()));
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::update_selected_image_for_layout_node(Layout::NodeWithStyle const& layout_node) const
|
||||
{
|
||||
Optional<DOM::AbstractElement> abstract_element;
|
||||
if (layout_node.is_generated_for_pseudo_element()) {
|
||||
if (auto const* pseudo_element_generator = layout_node.pseudo_element_generator())
|
||||
abstract_element = DOM::AbstractElement { *pseudo_element_generator, layout_node.generated_for_pseudo_element() };
|
||||
} else if (auto const* dom_node = layout_node.dom_node(); dom_node && dom_node->is_element()) {
|
||||
abstract_element = DOM::AbstractElement { static_cast<DOM::Element const&>(*dom_node) };
|
||||
}
|
||||
|
||||
auto context = CalculationResolutionContext {
|
||||
.length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node),
|
||||
.abstract_element = abstract_element,
|
||||
};
|
||||
auto dpr = layout_node.document().page().client().device_pixels_per_css_pixel();
|
||||
|
||||
if (auto const* image = select_image(dpr, context); image && image != m_selected_image) {
|
||||
const_cast<AbstractImageStyleValue&>(*image).set_style_sheet(m_style_sheet);
|
||||
m_selected_image = image;
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSSPixels> ImageSetStyleValue::natural_width() const
|
||||
{
|
||||
if (m_selected_image)
|
||||
return m_selected_image->natural_width();
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<CSSPixels> ImageSetStyleValue::natural_height() const
|
||||
{
|
||||
if (m_selected_image)
|
||||
return m_selected_image->natural_height();
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<CSSPixelFraction> ImageSetStyleValue::natural_aspect_ratio() const
|
||||
{
|
||||
if (m_selected_image)
|
||||
return m_selected_image->natural_aspect_ratio();
|
||||
return {};
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::resolve_for_size(Layout::NodeWithStyle const& layout_node, CSSPixelSize size) const
|
||||
{
|
||||
update_selected_image_for_layout_node(layout_node);
|
||||
if (m_selected_image)
|
||||
m_selected_image->resolve_for_size(layout_node, size);
|
||||
}
|
||||
|
||||
bool ImageSetStyleValue::is_paintable() const
|
||||
{
|
||||
if (m_selected_image)
|
||||
return m_selected_image->is_paintable();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::paint(DisplayListRecordingContext& context, DevicePixelRect const& dest_rect, ImageRendering image_rendering) const
|
||||
{
|
||||
if (m_selected_image)
|
||||
m_selected_image->paint(context, dest_rect, image_rendering);
|
||||
}
|
||||
|
||||
Optional<Gfx::Color> ImageSetStyleValue::color_if_single_pixel_bitmap() const
|
||||
{
|
||||
if (m_selected_image)
|
||||
return m_selected_image->color_if_single_pixel_bitmap();
|
||||
return {};
|
||||
}
|
||||
|
||||
void ImageSetStyleValue::set_style_sheet(GC::Ptr<CSSStyleSheet> style_sheet)
|
||||
{
|
||||
Base::set_style_sheet(style_sheet);
|
||||
m_style_sheet = style_sheet;
|
||||
}
|
||||
|
||||
ValueComparingNonnullRefPtr<StyleValue const> ImageSetStyleValue::absolutized(ComputationContext const& context) const
|
||||
{
|
||||
Vector<Option> options;
|
||||
options.ensure_capacity(m_options.size());
|
||||
for (auto const& option : m_options) {
|
||||
auto image = option.image->absolutized(context);
|
||||
VERIFY(image->is_abstract_image());
|
||||
options.unchecked_append({
|
||||
.image = image->as_abstract_image(),
|
||||
.resolution = option.resolution->absolutized(context),
|
||||
.type = option.type,
|
||||
});
|
||||
}
|
||||
return ImageSetStyleValue::create(move(options));
|
||||
}
|
||||
|
||||
}
|
||||
61
Libraries/LibWeb/CSS/StyleValues/ImageSetStyleValue.h
Normal file
61
Libraries/LibWeb/CSS/StyleValues/ImageSetStyleValue.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class ImageSetStyleValue final : public AbstractImageStyleValue {
|
||||
using Base = AbstractImageStyleValue;
|
||||
|
||||
public:
|
||||
struct Option {
|
||||
NonnullRefPtr<AbstractImageStyleValue const> image;
|
||||
NonnullRefPtr<StyleValue const> resolution;
|
||||
Optional<String> type;
|
||||
};
|
||||
|
||||
static ValueComparingNonnullRefPtr<ImageSetStyleValue const> create(Vector<Option>);
|
||||
virtual ~ImageSetStyleValue() override = default;
|
||||
|
||||
virtual void visit_edges(JS::Cell::Visitor&) const override;
|
||||
|
||||
virtual void serialize(StringBuilder&, SerializationMode) const override;
|
||||
virtual bool equals(StyleValue const& other) const override;
|
||||
virtual bool is_computationally_independent() const override;
|
||||
|
||||
virtual void load_any_resources(DOM::Document&) override;
|
||||
virtual void load_any_resources(Layout::NodeWithStyle const&) override;
|
||||
|
||||
virtual Optional<CSSPixels> natural_width() const override;
|
||||
virtual Optional<CSSPixels> natural_height() const override;
|
||||
virtual Optional<CSSPixelFraction> natural_aspect_ratio() const override;
|
||||
|
||||
virtual void resolve_for_size(Layout::NodeWithStyle const&, CSSPixelSize) const override;
|
||||
virtual bool is_paintable() const override;
|
||||
virtual void paint(DisplayListRecordingContext&, DevicePixelRect const&, ImageRendering) const override;
|
||||
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const override;
|
||||
|
||||
private:
|
||||
explicit ImageSetStyleValue(Vector<Option>);
|
||||
|
||||
virtual void set_style_sheet(GC::Ptr<CSSStyleSheet>) override;
|
||||
virtual ValueComparingNonnullRefPtr<StyleValue const> absolutized(ComputationContext const&) const override;
|
||||
|
||||
AbstractImageStyleValue const* select_image(double device_pixels_per_css_pixel, Optional<CalculationResolutionContext> const&) const;
|
||||
void update_selected_image_for_layout_node(Layout::NodeWithStyle const&) const;
|
||||
|
||||
Vector<Option> m_options;
|
||||
GC::Ptr<CSSStyleSheet> m_style_sheet;
|
||||
mutable AbstractImageStyleValue const* m_selected_image { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/GuaranteedInvalidStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ImageSetStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/KeywordStyleValue.h>
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace Web::CSS {
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(GridTrackSizeList, grid_track_size_list, GridTrackSizeListStyleValue) \
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(GuaranteedInvalid, guaranteed_invalid, GuaranteedInvalidStyleValue) \
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(Image, image, ImageStyleValue) \
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(ImageSet, image_set, ImageSetStyleValue) \
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(Integer, integer, IntegerStyleValue) \
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(Keyword, keyword, KeywordStyleValue) \
|
||||
__ENUMERATE_CSS_STYLE_VALUE_TYPE(Length, length, LengthStyleValue) \
|
||||
@@ -127,7 +128,7 @@ public:
|
||||
|
||||
bool is_abstract_image() const
|
||||
{
|
||||
return AK::first_is_one_of(type(), Type::Image, Type::LinearGradient, Type::ConicGradient, Type::RadialGradient);
|
||||
return AK::first_is_one_of(type(), Type::Image, Type::ImageSet, Type::LinearGradient, Type::ConicGradient, Type::RadialGradient);
|
||||
}
|
||||
AbstractImageStyleValue const& as_abstract_image() const;
|
||||
AbstractImageStyleValue& as_abstract_image() { return const_cast<AbstractImageStyleValue&>(const_cast<StyleValue const&>(*this).as_abstract_image()); }
|
||||
|
||||
@@ -341,6 +341,7 @@ class GridTrackPlacementStyleValue;
|
||||
class GridTrackSizeList;
|
||||
class GridTrackSizeListStyleValue;
|
||||
class GuaranteedInvalidStyleValue;
|
||||
class ImageSetStyleValue;
|
||||
class ImageStyleValue;
|
||||
class IntegerStyleValue;
|
||||
class InvalidationSet;
|
||||
|
||||
@@ -622,7 +622,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
|
||||
auto background_layers = computed_style.background_layers();
|
||||
|
||||
for (auto const& layer : background_layers)
|
||||
const_cast<CSS::AbstractImageStyleValue&>(*layer.background_image).load_any_resources(document());
|
||||
const_cast<CSS::AbstractImageStyleValue&>(*layer.background_image).load_any_resources(*this);
|
||||
|
||||
computed_values.set_background_layers(move(background_layers));
|
||||
|
||||
@@ -719,7 +719,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
|
||||
auto const& list_style_image = computed_style.property(CSS::PropertyID::ListStyleImage);
|
||||
if (list_style_image.is_abstract_image()) {
|
||||
m_list_style_image = list_style_image.as_abstract_image();
|
||||
const_cast<CSS::AbstractImageStyleValue&>(*m_list_style_image).load_any_resources(document());
|
||||
const_cast<CSS::AbstractImageStyleValue&>(*m_list_style_image).load_any_resources(*this);
|
||||
}
|
||||
|
||||
computed_values.set_text_decoration_color(computed_style.color(CSS::PropertyID::TextDecorationColor, color_resolution_context));
|
||||
@@ -871,7 +871,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
|
||||
} else if (mask_image.is_abstract_image()) {
|
||||
auto const& abstract_image = mask_image.as_abstract_image();
|
||||
computed_values.set_mask_image(abstract_image);
|
||||
const_cast<CSS::AbstractImageStyleValue&>(abstract_image).load_any_resources(document());
|
||||
const_cast<CSS::AbstractImageStyleValue&>(abstract_image).load_any_resources(*this);
|
||||
}
|
||||
|
||||
computed_values.set_mask_type(computed_style.mask_type());
|
||||
|
||||
@@ -2,26 +2,25 @@ Harness status: OK
|
||||
|
||||
Found 144 tests
|
||||
|
||||
48 Pass
|
||||
96 Fail
|
||||
Fail e.style['background-image'] = "image-set(url(example.png) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(example.png) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set('example.jpg' 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set('example.jpg' 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(example.png) 1x, 'example.png' 2x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(example.png) 1x, 'example.png' 2x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(example.png) 1dpcm, 'example.png' 2x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(example.png) 1dpcm, 'example.png' 2x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set('example.jpeg' 222dpi, url(example.png) 3.5x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set('example.jpeg' 222dpi, url(example.png) 3.5x)" should set the property value
|
||||
Fail e.style['content'] = "image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Fail e.style['content'] = "-webkit-image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Fail e.style['content'] = "image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Fail e.style['content'] = "-webkit-image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Fail e.style['border-image-source'] = "image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Fail e.style['border-image-source'] = "-webkit-image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Fail e.style['border-image-source'] = "image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Fail e.style['border-image-source'] = "-webkit-image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
144 Pass
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set('example.jpg' 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set('example.jpg' 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) 1x, 'example.png' 2x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) 1x, 'example.png' 2x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) 1dpcm, 'example.png' 2x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) 1dpcm, 'example.png' 2x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set('example.jpeg' 222dpi, url(example.png) 3.5x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set('example.jpeg' 222dpi, url(example.png) 3.5x)" should set the property value
|
||||
Pass e.style['content'] = "image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Pass e.style['content'] = "-webkit-image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Pass e.style['content'] = "image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Pass e.style['content'] = "-webkit-image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Pass e.style['border-image-source'] = "image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Pass e.style['border-image-source'] = "-webkit-image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Pass e.style['border-image-source'] = "image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Pass e.style['border-image-source'] = "-webkit-image-set(url(\"example.png\") 1x, \"example.png\" 3x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") -20x)" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") -20x)" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(none, url(example.png) 1x)" should not set the property value
|
||||
@@ -34,44 +33,44 @@ Pass e.style['background-image'] = "image-set(url(example.png) 1x url(example.jp
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) 1x url(example.jpeg))" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) 1x 2x)" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) 1x 2x)" should not set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(foo))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(foo))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(foo), url(bar) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(foo), url(bar) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(foo) 1x, url(bar))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(foo) 1x, url(bar))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(foo), url(bar))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(foo), url(bar))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(foo) 1x, url(bar), url(baz) 2x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(foo) 1x, url(bar), url(baz) 2x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(2x * 3))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(2x * 3))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 1dppx)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1dppx)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * 1))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * 1))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(96dpi * 2))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(96dpi * 2))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 1dpcm)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1dpcm)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(1dpcm * 96/2.54))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dpcm * 96/2.54))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 1x, url(\"example.png\") 2dppx, \"example.png\" 250dpi, \"example.png\" 1dpcm)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1x, url(\"example.png\") 2dppx, \"example.png\" 250dpi, \"example.png\" 1dpcm)" should set the property value
|
||||
Fail e.style['content'] = "image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Fail e.style['content'] = "-webkit-image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Fail e.style['content'] = "image-set(url(\"example.png\") calc(1 * 96dpi))" should set the property value
|
||||
Fail e.style['content'] = "-webkit-image-set(url(\"example.png\") calc(1 * 96dpi))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * sibling-index()))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * sibling-index()))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * sign(1em - 10px)))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * sign(1em - 10px)))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * sign(10px)))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * sign(10px)))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(foo))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(foo))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(foo), url(bar) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(foo), url(bar) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(foo) 1x, url(bar))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(foo) 1x, url(bar))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(foo), url(bar))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(foo), url(bar))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(foo) 1x, url(bar), url(baz) 2x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(foo) 1x, url(bar), url(baz) 2x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(2x * 3))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(2x * 3))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1dppx)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1dppx)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * 1))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * 1))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(96dpi * 2))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(96dpi * 2))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1dpcm)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1dpcm)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1dpcm * 96/2.54))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dpcm * 96/2.54))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1x, url(\"example.png\") 2dppx, \"example.png\" 250dpi, \"example.png\" 1dpcm)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1x, url(\"example.png\") 2dppx, \"example.png\" 250dpi, \"example.png\" 1dpcm)" should set the property value
|
||||
Pass e.style['content'] = "image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Pass e.style['content'] = "-webkit-image-set(url(\"example.png\") 1dpi)" should set the property value
|
||||
Pass e.style['content'] = "image-set(url(\"example.png\") calc(1 * 96dpi))" should set the property value
|
||||
Pass e.style['content'] = "-webkit-image-set(url(\"example.png\") calc(1 * 96dpi))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * sibling-index()))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * sibling-index()))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * sign(1em - 10px)))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * sign(1em - 10px)))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1dppx * sign(10px)))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1dppx * sign(10px)))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1invalidResUnit)" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1invalidResUnit)" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(3 * 4))" should not set the property value
|
||||
@@ -82,18 +81,18 @@ Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(2x - 1))
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(2x - 1))" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1 + 4dpi))" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1 + 4dpi))" should not set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 0x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 0dppx)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0dppx)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 0dpi)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0dpi)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 0dpcm)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0dpcm)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(-1 * 1x))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(-1 * 1x))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") calc(1x + -1x))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1x + -1x))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 0x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 0dppx)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0dppx)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 0dpi)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0dpi)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 0dpcm)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 0dpcm)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(-1 * 1x))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(-1 * 1x))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") calc(1x + -1x))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") calc(1x + -1x))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") -1x)" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") -1x)" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") -3dppx)" should not set the property value
|
||||
@@ -102,36 +101,36 @@ Pass e.style['background-image'] = "image-set(url(\"example.png\") -96dpi)" shou
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") -96dpi)" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") -113dpcm)" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") -113dpcm)" should not set the property value
|
||||
Fail e.style['background-image'] = "image-set(linear-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(linear-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(repeating-linear-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(repeating-linear-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(radial-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(radial-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(repeating-radial-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(repeating-radial-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(conic-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(conic-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(repeating-conic-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(repeating-conic-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Fail e.style['content'] = "image-set(linear-gradient(black, white) 1x, url(\"example.png\") 4x)" should set the property value
|
||||
Fail e.style['content'] = "-webkit-image-set(linear-gradient(black, white) 1x, url(\"example.png\") 4x)" should set the property value
|
||||
Fail e.style['content'] = "image-set(url(\"example.png\") 192dpi, linear-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['content'] = "-webkit-image-set(url(\"example.png\") 192dpi, linear-gradient(black, white) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(linear-gradient(red) 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(linear-gradient(red) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(linear-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(linear-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(repeating-linear-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(repeating-linear-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(radial-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(radial-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(repeating-radial-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(repeating-radial-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(conic-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(conic-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(repeating-conic-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(repeating-conic-gradient(red, blue 25%) 1x)" should set the property value
|
||||
Pass e.style['content'] = "image-set(linear-gradient(black, white) 1x, url(\"example.png\") 4x)" should set the property value
|
||||
Pass e.style['content'] = "-webkit-image-set(linear-gradient(black, white) 1x, url(\"example.png\") 4x)" should set the property value
|
||||
Pass e.style['content'] = "image-set(url(\"example.png\") 192dpi, linear-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['content'] = "-webkit-image-set(url(\"example.png\") 192dpi, linear-gradient(black, white) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(linear-gradient(red) 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(linear-gradient(red) 1x)" should set the property value
|
||||
Pass e.style['cursor'] = "image-set(linear-gradient(black, white) 1x)" should not set the property value
|
||||
Pass e.style['cursor'] = "-webkit-image-set(linear-gradient(black, white) 1x)" should not set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"example.png\") 1x type(\"image/png\"))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1x type(\"image/png\"))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(example.png) type('image/png'))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(example.png) type('image/png'))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(example.png) type('image/png') 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(example.png) type('image/png') 1x)" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(example.png) 1x type('image/jpeg'))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(example.png) 1x type('image/jpeg'))" should set the property value
|
||||
Fail e.style['background-image'] = "image-set(url(\"x\") 1x type(\"a\\\"\"))" should set the property value
|
||||
Fail e.style['background-image'] = "-webkit-image-set(url(\"x\") 1x type(\"a\\\"\"))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"example.png\") 1x type(\"image/png\"))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"example.png\") 1x type(\"image/png\"))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) type('image/png'))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) type('image/png'))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) type('image/png') 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) type('image/png') 1x)" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) 1x type('image/jpeg'))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) 1x type('image/jpeg'))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(\"x\") 1x type(\"a\\\"\"))" should set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(\"x\") 1x type(\"a\\\"\"))" should set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) type(image/png))" should not set the property value
|
||||
Pass e.style['background-image'] = "-webkit-image-set(url(example.png) type(image/png))" should not set the property value
|
||||
Pass e.style['background-image'] = "image-set(url(example.png) type('image/png') type('image/png'))" should not set the property value
|
||||
|
||||
@@ -2,8 +2,7 @@ Harness status: OK
|
||||
|
||||
Found 42 tests
|
||||
|
||||
40 Pass
|
||||
2 Fail
|
||||
42 Pass
|
||||
Pass e.style['cursor'] = "auto" should set the property value
|
||||
Pass e.style['cursor'] = "default" should set the property value
|
||||
Pass e.style['cursor'] = "none" should set the property value
|
||||
@@ -44,5 +43,5 @@ Pass e.style['cursor'] = "url(\"https://example.com/\"), alias" should set the p
|
||||
Pass e.style['cursor'] = "url(\"https://example.com/\") 1 calc(2 + 0), copy" should set the property value
|
||||
Pass e.style['cursor'] = "url(\"https://example.com/\"), url(\"https://example.com/\") 3 -4, move" should set the property value
|
||||
Pass e.style['cursor'] = "url(\"https://example.com/\") 5 6, grab" should set the property value
|
||||
Fail e.style['cursor'] = "image-set(\"https://example.com/\" 1x) 5 6, grab" should set the property value
|
||||
Fail e.style['cursor'] = "image-set(\"https://example.com/\" 1x, \"https://example.com/highres\" 2x) 5 6, grab" should set the property value
|
||||
Pass e.style['cursor'] = "image-set(\"https://example.com/\" 1x) 5 6, grab" should set the property value
|
||||
Pass e.style['cursor'] = "image-set(\"https://example.com/\" 1x, \"https://example.com/highres\" 2x) 5 6, grab" should set the property value
|
||||
@@ -2,11 +2,11 @@ Harness status: OK
|
||||
|
||||
Found 43 tests
|
||||
|
||||
28 Pass
|
||||
15 Fail
|
||||
29 Pass
|
||||
14 Fail
|
||||
Pass '--x: image-set(attr(data-foo))' with data-foo="https://does-not-exist.test/404.png"
|
||||
Pass 'background-image: image-set(attr(data-foo))' with data-foo="https://does-not-exist.test/404.png"
|
||||
Fail 'background-image: image-set("https://does-not-exist.test/404.png")' with data-foo="https://does-not-exist.test/404.png"
|
||||
Pass 'background-image: image-set("https://does-not-exist.test/404.png")' with data-foo="https://does-not-exist.test/404.png"
|
||||
Pass '--x: src(attr(data-foo))' with data-foo="https://does-not-exist.test/404.png"
|
||||
Fail 'background-image: src(attr(data-foo))' with data-foo="https://does-not-exist.test/404.png"
|
||||
Fail 'background-image: src("https://does-not-exist.test/404.png")' with data-foo="https://does-not-exist.test/404.png"
|
||||
@@ -42,11 +42,11 @@ Pass 'background-image: image-set(
|
||||
if(style(--some-string): url(https://does-not-exist.test/404.png);))' with data-foo="https://does-not-exist.test/404.png"
|
||||
Pass 'background-image: image-set(
|
||||
if(style(--condition-val: attr(data-foo type(*))): url(https://does-not-exist.test/404.png);))' with data-foo="3"
|
||||
Pass 'background-image: image-set(
|
||||
Fail 'background-image: image-set(
|
||||
if(style(--condition-val: attr(data-foo type(*))): url(https://does-not-exist.test/404.png);
|
||||
style(--true): url(https://does-not-exist.test/404.png);
|
||||
else: url(https://does-not-exist.test/404.png);))' with data-foo="1"
|
||||
Fail 'background-image: image-set(if(style(--true): url(https://does-not-exist.test/404.png);
|
||||
Pass 'background-image: image-set(if(style(--true): url(https://does-not-exist.test/404.png);
|
||||
style(--condition-val): url(https://does-not-exist.test/404.png);
|
||||
else: url(https://does-not-exist.test/404.png);))' with data-foo="attr(data-foo type(*))"
|
||||
Pass 'background-image: image-set(
|
||||
|
||||
@@ -2,8 +2,8 @@ Harness status: OK
|
||||
|
||||
Found 150 tests
|
||||
|
||||
126 Pass
|
||||
24 Fail
|
||||
127 Pass
|
||||
23 Fail
|
||||
Pass Property scale value 'random(1, 11)'
|
||||
Pass Property scale value 'random(--foo, 2, 12)'
|
||||
Pass Property scale value 'random(--foo element-shared, 3, 13)'
|
||||
@@ -103,7 +103,7 @@ Fail Property color value 'rgb(from blue random(51, 10) random(g + 51, g) random
|
||||
Pass Property color value 'color-mix(in srgb, rgb(random(30, 10) 0 0), rgb(random(21, 10) 0 0))'
|
||||
Pass Property math-depth value 'add(random(30, 10))'
|
||||
Fail Property view-transition-name value 'ident("myident" random(30, 10))'
|
||||
Fail Property background-image value 'image-set(url("http://example.com/image.png") calc(random(fixed 0.3, 0, 10) * 1x))'
|
||||
Pass Property background-image value 'image-set(url("http://example.com/image.png") calc(random(fixed 0.3, 0, 10) * 1x))'
|
||||
Pass Property aspect-ratio value 'random(3, 1) / random(9, 6)'
|
||||
Pass Property filter value 'drop-shadow(random(3px, 1px) random(6px, 1px) random(9px, 1px) black)'
|
||||
Pass Property font-variation-settings value '"wght" random(300, 100)'
|
||||
|
||||
Reference in New Issue
Block a user