mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
LibWeb: Allow calculated values in css filters
This commit is contained in:
parent
af3383df09
commit
4ecf56cadf
Notes:
github-actions[bot]
2024-10-31 07:20:39 +00:00
Author: https://github.com/Gingeh Commit: https://github.com/LadybirdBrowser/ladybird/commit/4ecf56cadf2 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2072
11 changed files with 166 additions and 59 deletions
|
@ -20,3 +20,4 @@
|
||||||
<div style="filter: drop-shadow(5px 5px 5px)"></div>
|
<div style="filter: drop-shadow(5px 5px 5px)"></div>
|
||||||
<div style="filter: drop-shadow(red 5px 5px 5px)"></div>
|
<div style="filter: drop-shadow(red 5px 5px 5px)"></div>
|
||||||
<div style="filter: drop-shadow(5px 5px 5px red)"></div>
|
<div style="filter: drop-shadow(5px 5px 5px red)"></div>
|
||||||
|
<div style="filter: drop-shadow(calc(5*1px) calc(2px + 3px))"></div>
|
||||||
|
|
74
Tests/LibWeb/Screenshot/css-filter.html
Normal file
74
Tests/LibWeb/Screenshot/css-filter.html
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<link rel="match" href="reference/css-filter-ref.html" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- blur() -->
|
||||||
|
<img src="assets/car.png" style="filter: blur()">
|
||||||
|
<img src="assets/car.png" style="filter: blur(0)">
|
||||||
|
<img src="assets/car.png" style="filter: blur(4px)">
|
||||||
|
<img src="assets/car.png" style="filter: blur(calc(4 * 1px))">
|
||||||
|
|
||||||
|
<!-- drop-shadow() is tested in css-filter-drop-shadow.html -->
|
||||||
|
|
||||||
|
<!-- hue-rotate() -->
|
||||||
|
<img src="assets/car.png" style="filter: hue-rotate()">
|
||||||
|
<img src="assets/car.png" style="filter: hue-rotate(0)">
|
||||||
|
<img src="assets/car.png" style="filter: hue-rotate(90)">
|
||||||
|
<img src="assets/car.png" style="filter: hue-rotate(90deg)">
|
||||||
|
<img src="assets/car.png" style="filter: hue-rotate(-90deg)">
|
||||||
|
<img src="assets/car.png" style="filter: hue-rotate(calc(180 * 1deg))">
|
||||||
|
|
||||||
|
<!-- simple color filters -->
|
||||||
|
<!-- omitted -->
|
||||||
|
<img src="assets/car.png" style="filter: brightness()">
|
||||||
|
<img src="assets/car.png" style="filter: contrast()">
|
||||||
|
<img src="assets/car.png" style="filter: grayscale()">
|
||||||
|
<img src="assets/car.png" style="filter: invert()">
|
||||||
|
<img src="assets/car.png" style="filter: opacity()">
|
||||||
|
<img src="assets/car.png" style="filter: sepia()">
|
||||||
|
<img src="assets/car.png" style="filter: saturate()">
|
||||||
|
|
||||||
|
<!-- number -->
|
||||||
|
<img src="assets/car.png" style="filter: brightness(0.75)">
|
||||||
|
<img src="assets/car.png" style="filter: contrast(0.75)">
|
||||||
|
<img src="assets/car.png" style="filter: grayscale(0.75)">
|
||||||
|
<img src="assets/car.png" style="filter: invert(0.75)">
|
||||||
|
<img src="assets/car.png" style="filter: opacity(0.75)">
|
||||||
|
<img src="assets/car.png" style="filter: sepia(0.75)">
|
||||||
|
<img src="assets/car.png" style="filter: saturate(0.75)">
|
||||||
|
|
||||||
|
<!-- percentage -->
|
||||||
|
<img src="assets/car.png" style="filter: brightness(75%)">
|
||||||
|
<img src="assets/car.png" style="filter: contrast(75%)">
|
||||||
|
<img src="assets/car.png" style="filter: grayscale(75%)">
|
||||||
|
<img src="assets/car.png" style="filter: invert(75%)">
|
||||||
|
<img src="assets/car.png" style="filter: opacity(75%)">
|
||||||
|
<img src="assets/car.png" style="filter: sepia(75%)">
|
||||||
|
<img src="assets/car.png" style="filter: saturate(75%)">
|
||||||
|
|
||||||
|
<!-- calculated number -->
|
||||||
|
<img src="assets/car.png" style="filter: brightness(calc(3 / 4))">
|
||||||
|
<img src="assets/car.png" style="filter: contrast(calc(3 / 4))">
|
||||||
|
<img src="assets/car.png" style="filter: grayscale(calc(3 / 4))">
|
||||||
|
<img src="assets/car.png" style="filter: invert(calc(3 / 4))">
|
||||||
|
<img src="assets/car.png" style="filter: opacity(calc(3 / 4))">
|
||||||
|
<img src="assets/car.png" style="filter: sepia(calc(3 / 4))">
|
||||||
|
<img src="assets/car.png" style="filter: saturate(calc(3 / 4))">
|
||||||
|
|
||||||
|
<!-- calculated percentage -->
|
||||||
|
<img src="assets/car.png" style="filter: brightness(calc(3 * 25%))">
|
||||||
|
<img src="assets/car.png" style="filter: contrast(calc(3 * 25%))">
|
||||||
|
<img src="assets/car.png" style="filter: grayscale(calc(3 * 25%))">
|
||||||
|
<img src="assets/car.png" style="filter: invert(calc(3 * 25%))">
|
||||||
|
<img src="assets/car.png" style="filter: opacity(calc(3 * 25%))">
|
||||||
|
<img src="assets/car.png" style="filter: sepia(calc(3 * 25%))">
|
||||||
|
<img src="assets/car.png" style="filter: saturate(calc(3 * 25%))">
|
Binary file not shown.
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
BIN
Tests/LibWeb/Screenshot/images/css-filter-ref.png
Normal file
BIN
Tests/LibWeb/Screenshot/images/css-filter-ref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 113 KiB |
10
Tests/LibWeb/Screenshot/reference/css-filter-ref.html
Normal file
10
Tests/LibWeb/Screenshot/reference/css-filter-ref.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<img src="../images/css-filter-ref.png">
|
|
@ -4,10 +4,10 @@ animation-duration: 'calc(2s)' -> 'calc(2s)'
|
||||||
animation-duration: 'calc(2s * var(--n))' -> '4s'
|
animation-duration: 'calc(2s * var(--n))' -> '4s'
|
||||||
animation-iteration-count: 'calc(2)' -> 'calc(2)'
|
animation-iteration-count: 'calc(2)' -> 'calc(2)'
|
||||||
animation-iteration-count: 'calc(2 * var(--n))' -> '4'
|
animation-iteration-count: 'calc(2 * var(--n))' -> '4'
|
||||||
backdrop-filter: 'grayscale(calc(2%))' -> 'none'
|
backdrop-filter: 'grayscale(calc(2%))' -> 'grayscale(calc(2%))'
|
||||||
backdrop-filter: 'grayscale(calc(2% * var(--n)))' -> 'none'
|
backdrop-filter: 'grayscale(calc(2% * var(--n)))' -> 'grayscale(calc(2% * 2))'
|
||||||
backdrop-filter: 'grayscale(calc(0.02))' -> 'none'
|
backdrop-filter: 'grayscale(calc(0.02))' -> 'grayscale(calc(0.02))'
|
||||||
backdrop-filter: 'grayscale(calc(0.02 * var(--n)))' -> 'none'
|
backdrop-filter: 'grayscale(calc(0.02 * var(--n)))' -> 'grayscale(calc(0.02 * 2))'
|
||||||
background-position-x: 'calc(2px)' -> 'left calc(2px)'
|
background-position-x: 'calc(2px)' -> 'left calc(2px)'
|
||||||
background-position-x: 'calc(2px * var(--n))' -> 'left calc(2px * 2)'
|
background-position-x: 'calc(2px * var(--n))' -> 'left calc(2px * 2)'
|
||||||
background-position-y: 'calc(2%)' -> 'top calc(2%)'
|
background-position-y: 'calc(2%)' -> 'top calc(2%)'
|
||||||
|
@ -56,10 +56,10 @@ cy: 'calc(2%)' -> 'calc(2%)'
|
||||||
cy: 'calc(2% * var(--n))' -> '4%'
|
cy: 'calc(2% * var(--n))' -> '4%'
|
||||||
fill-opacity: 'calc(2)' -> 'calc(2)'
|
fill-opacity: 'calc(2)' -> 'calc(2)'
|
||||||
fill-opacity: 'calc(2 * var(--n))' -> '4'
|
fill-opacity: 'calc(2 * var(--n))' -> '4'
|
||||||
filter: 'grayscale(calc(2%))' -> 'none'
|
filter: 'grayscale(calc(2%))' -> 'grayscale(calc(2%))'
|
||||||
filter: 'grayscale(calc(2% * var(--n)))' -> 'none'
|
filter: 'grayscale(calc(2% * var(--n)))' -> 'grayscale(calc(2% * 2))'
|
||||||
filter: 'grayscale(calc(0.02))' -> 'none'
|
filter: 'grayscale(calc(0.02))' -> 'grayscale(calc(0.02))'
|
||||||
filter: 'grayscale(calc(0.02 * var(--n)))' -> 'none'
|
filter: 'grayscale(calc(0.02 * var(--n)))' -> 'grayscale(calc(0.02 * 2))'
|
||||||
flex-basis: 'calc(2px)' -> 'calc(2px)'
|
flex-basis: 'calc(2px)' -> 'calc(2px)'
|
||||||
flex-basis: 'calc(2px * var(--n))' -> 'calc(2px * 2)'
|
flex-basis: 'calc(2px * var(--n))' -> 'calc(2px * 2)'
|
||||||
flex-grow: 'calc(2)' -> 'calc(2)'
|
flex-grow: 'calc(2)' -> 'calc(2)'
|
||||||
|
|
|
@ -2246,6 +2246,29 @@ Optional<NumberOrCalculated> Parser::parse_number(TokenStream<ComponentValue>& t
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<NumberPercentage> Parser::parse_number_percentage(TokenStream<ComponentValue>& tokens)
|
||||||
|
{
|
||||||
|
auto transaction = tokens.begin_transaction();
|
||||||
|
auto& token = tokens.consume_a_token();
|
||||||
|
|
||||||
|
if (token.is(Token::Type::Number)) {
|
||||||
|
transaction.commit();
|
||||||
|
return token.token().number();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is(Token::Type::Percentage)) {
|
||||||
|
transaction.commit();
|
||||||
|
return Percentage(token.token().percentage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_number_percentage()) {
|
||||||
|
transaction.commit();
|
||||||
|
return calc.release_nonnull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Optional<ResolutionOrCalculated> Parser::parse_resolution(TokenStream<ComponentValue>& tokens)
|
Optional<ResolutionOrCalculated> Parser::parse_resolution(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
auto transaction = tokens.begin_transaction();
|
auto transaction = tokens.begin_transaction();
|
||||||
|
@ -5395,14 +5418,6 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
|
||||||
return static_cast<FilterOperation::Color::Type>(filter);
|
return static_cast<FilterOperation::Color::Type>(filter);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parse_number_percentage = [&](auto& token) -> Optional<NumberPercentage> {
|
|
||||||
if (token.is(Token::Type::Percentage))
|
|
||||||
return NumberPercentage(Percentage(token.token().percentage()));
|
|
||||||
if (token.is(Token::Type::Number))
|
|
||||||
return NumberPercentage(Number(Number::Type::Number, token.token().number_value()));
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
auto parse_filter_function_name = [&](auto name) -> Optional<FilterToken> {
|
auto parse_filter_function_name = [&](auto name) -> Optional<FilterToken> {
|
||||||
if (name.equals_ignoring_ascii_case("blur"sv))
|
if (name.equals_ignoring_ascii_case("blur"sv))
|
||||||
return FilterToken::Blur;
|
return FilterToken::Blur;
|
||||||
|
@ -5446,8 +5461,7 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
|
||||||
tokens.discard_whitespace();
|
tokens.discard_whitespace();
|
||||||
if (!blur_radius.has_value())
|
if (!blur_radius.has_value())
|
||||||
return {};
|
return {};
|
||||||
// FIXME: Support calculated radius
|
return if_no_more_tokens_return(FilterOperation::Blur { blur_radius.value() });
|
||||||
return if_no_more_tokens_return(FilterOperation::Blur { blur_radius->value() });
|
|
||||||
} else if (filter_token == FilterToken::DropShadow) {
|
} else if (filter_token == FilterToken::DropShadow) {
|
||||||
if (!tokens.has_next_token())
|
if (!tokens.has_next_token())
|
||||||
return {};
|
return {};
|
||||||
|
@ -5481,29 +5495,24 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
|
||||||
if (maybe_color)
|
if (maybe_color)
|
||||||
color = maybe_color->to_color({});
|
color = maybe_color->to_color({});
|
||||||
|
|
||||||
// FIXME: Support calculated offsets and radius
|
return if_no_more_tokens_return(FilterOperation::DropShadow { x_offset.value(), y_offset.value(), maybe_radius, color });
|
||||||
return if_no_more_tokens_return(FilterOperation::DropShadow { x_offset->value(), y_offset->value(), maybe_radius.map([](auto& it) { return it.value(); }), color });
|
|
||||||
} else if (filter_token == FilterToken::HueRotate) {
|
} else if (filter_token == FilterToken::HueRotate) {
|
||||||
// hue-rotate( [ <angle> | <zero> ]? )
|
// hue-rotate( [ <angle> | <zero> ]? )
|
||||||
if (!tokens.has_next_token())
|
if (!tokens.has_next_token())
|
||||||
return FilterOperation::HueRotate {};
|
return FilterOperation::HueRotate {};
|
||||||
auto& token = tokens.consume_a_token();
|
|
||||||
if (token.is(Token::Type::Number)) {
|
if (tokens.next_token().is(Token::Type::Number)) {
|
||||||
// hue-rotate(0)
|
// hue-rotate(0)
|
||||||
auto number = token.token().number();
|
auto number = tokens.consume_a_token().token().number();
|
||||||
if (number.is_integer() && number.integer_value() == 0)
|
if (number.is_integer() && number.integer_value() == 0)
|
||||||
return if_no_more_tokens_return(FilterOperation::HueRotate { FilterOperation::HueRotate::Zero {} });
|
return if_no_more_tokens_return(FilterOperation::HueRotate { FilterOperation::HueRotate::Zero {} });
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!token.is(Token::Type::Dimension))
|
|
||||||
return {};
|
if (auto angle = parse_angle(tokens); angle.has_value())
|
||||||
auto angle_value = token.token().dimension_value();
|
return if_no_more_tokens_return(FilterOperation::HueRotate { angle.value() });
|
||||||
auto angle_unit_name = token.token().dimension_unit();
|
|
||||||
auto angle_unit = Angle::unit_from_name(angle_unit_name);
|
return {};
|
||||||
if (!angle_unit.has_value())
|
|
||||||
return {};
|
|
||||||
Angle angle { angle_value, angle_unit.release_value() };
|
|
||||||
return if_no_more_tokens_return(FilterOperation::HueRotate { angle });
|
|
||||||
} else {
|
} else {
|
||||||
// Simple filters:
|
// Simple filters:
|
||||||
// brightness( <number-percentage>? )
|
// brightness( <number-percentage>? )
|
||||||
|
@ -5515,10 +5524,8 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
|
||||||
// saturate( <number-percentage>? )
|
// saturate( <number-percentage>? )
|
||||||
if (!tokens.has_next_token())
|
if (!tokens.has_next_token())
|
||||||
return FilterOperation::Color { filter_token_to_operation(filter_token) };
|
return FilterOperation::Color { filter_token_to_operation(filter_token) };
|
||||||
auto amount = parse_number_percentage(tokens.consume_a_token());
|
auto amount = parse_number_percentage(tokens);
|
||||||
if (!amount.has_value())
|
return if_no_more_tokens_return(FilterOperation::Color { filter_token_to_operation(filter_token), amount });
|
||||||
return {};
|
|
||||||
return if_no_more_tokens_return(FilterOperation::Color { filter_token_to_operation(filter_token), *amount });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,7 @@ private:
|
||||||
Optional<LengthOrCalculated> parse_length(TokenStream<ComponentValue>&);
|
Optional<LengthOrCalculated> parse_length(TokenStream<ComponentValue>&);
|
||||||
Optional<LengthPercentage> parse_length_percentage(TokenStream<ComponentValue>&);
|
Optional<LengthPercentage> parse_length_percentage(TokenStream<ComponentValue>&);
|
||||||
Optional<NumberOrCalculated> parse_number(TokenStream<ComponentValue>&);
|
Optional<NumberOrCalculated> parse_number(TokenStream<ComponentValue>&);
|
||||||
|
Optional<NumberPercentage> parse_number_percentage(TokenStream<ComponentValue>&);
|
||||||
Optional<ResolutionOrCalculated> parse_resolution(TokenStream<ComponentValue>&);
|
Optional<ResolutionOrCalculated> parse_resolution(TokenStream<ComponentValue>&);
|
||||||
Optional<TimeOrCalculated> parse_time(TokenStream<ComponentValue>&);
|
Optional<TimeOrCalculated> parse_time(TokenStream<ComponentValue>&);
|
||||||
Optional<TimePercentage> parse_time_percentage(TokenStream<ComponentValue>&);
|
Optional<TimePercentage> parse_time_percentage(TokenStream<ComponentValue>&);
|
||||||
|
|
|
@ -15,30 +15,42 @@ namespace Web::CSS {
|
||||||
|
|
||||||
float FilterOperation::Blur::resolved_radius(Layout::Node const& node) const
|
float FilterOperation::Blur::resolved_radius(Layout::Node const& node) const
|
||||||
{
|
{
|
||||||
// Default value when omitted is 0px.
|
|
||||||
auto sigma = 0;
|
|
||||||
if (radius.has_value())
|
if (radius.has_value())
|
||||||
sigma = radius->to_px(node).to_int();
|
return radius->resolved(Length::ResolutionContext::for_layout_node(node)).to_px(node).to_float();
|
||||||
return sigma;
|
|
||||||
|
// Default value when omitted is 0px.
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float FilterOperation::HueRotate::angle_degrees() const
|
float FilterOperation::HueRotate::angle_degrees(Layout::Node const& node) const
|
||||||
{
|
{
|
||||||
// Default value when omitted is 0deg.
|
// Default value when omitted is 0deg.
|
||||||
if (!angle.has_value())
|
if (!angle.has_value())
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
return angle->visit([&](Angle const& a) { return a.to_degrees(); }, [&](auto) { return 0.0; });
|
return angle->visit([&](AngleOrCalculated const& a) { return a.resolved(node).to_degrees(); }, [&](Zero) { return 0.0; });
|
||||||
}
|
}
|
||||||
|
|
||||||
float FilterOperation::Color::resolved_amount() const
|
float FilterOperation::Color::resolved_amount() const
|
||||||
{
|
{
|
||||||
if (amount.has_value()) {
|
// Default value when omitted is 1.
|
||||||
if (amount->is_percentage())
|
if (!amount.has_value())
|
||||||
return amount->percentage().as_fraction();
|
return 1;
|
||||||
|
|
||||||
|
if (amount->is_number())
|
||||||
return amount->number().value();
|
return amount->number().value();
|
||||||
|
|
||||||
|
if (amount->is_percentage())
|
||||||
|
return amount->percentage().as_fraction();
|
||||||
|
|
||||||
|
if (amount->is_calculated()) {
|
||||||
|
if (amount->calculated()->resolves_to_number())
|
||||||
|
return amount->calculated()->resolve_number().value();
|
||||||
|
|
||||||
|
if (amount->calculated()->resolves_to_percentage())
|
||||||
|
return amount->calculated()->resolve_percentage()->as_fraction();
|
||||||
}
|
}
|
||||||
// All color filters (brightness, sepia, etc) have a default amount of 1.
|
|
||||||
return 1.0f;
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
String FilterValueListStyleValue::to_string() const
|
String FilterValueListStyleValue::to_string() const
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LibWeb/CSS/Angle.h>
|
#include <LibWeb/CSS/Angle.h>
|
||||||
|
#include <LibWeb/CSS/CalculatedOr.h>
|
||||||
#include <LibWeb/CSS/Length.h>
|
#include <LibWeb/CSS/Length.h>
|
||||||
#include <LibWeb/CSS/Number.h>
|
#include <LibWeb/CSS/Number.h>
|
||||||
#include <LibWeb/CSS/PercentageOr.h>
|
#include <LibWeb/CSS/PercentageOr.h>
|
||||||
|
@ -19,16 +20,16 @@ namespace Web::CSS {
|
||||||
namespace FilterOperation {
|
namespace FilterOperation {
|
||||||
|
|
||||||
struct Blur {
|
struct Blur {
|
||||||
Optional<Length> radius {};
|
Optional<LengthOrCalculated> radius;
|
||||||
float resolved_radius(Layout::Node const&) const;
|
float resolved_radius(Layout::Node const&) const;
|
||||||
bool operator==(Blur const&) const = default;
|
bool operator==(Blur const&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DropShadow {
|
struct DropShadow {
|
||||||
Length offset_x;
|
LengthOrCalculated offset_x;
|
||||||
Length offset_y;
|
LengthOrCalculated offset_y;
|
||||||
Optional<Length> radius {};
|
Optional<LengthOrCalculated> radius;
|
||||||
Optional<Color> color {};
|
Optional<Color> color;
|
||||||
bool operator==(DropShadow const&) const = default;
|
bool operator==(DropShadow const&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,9 +37,9 @@ struct HueRotate {
|
||||||
struct Zero {
|
struct Zero {
|
||||||
bool operator==(Zero const&) const = default;
|
bool operator==(Zero const&) const = default;
|
||||||
};
|
};
|
||||||
using AngleOrZero = Variant<Angle, Zero>;
|
using AngleOrZero = Variant<AngleOrCalculated, Zero>;
|
||||||
Optional<AngleOrZero> angle {};
|
Optional<AngleOrZero> angle;
|
||||||
float angle_degrees() const;
|
float angle_degrees(Layout::Node const&) const;
|
||||||
bool operator==(HueRotate const&) const = default;
|
bool operator==(HueRotate const&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -523,12 +523,13 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
|
||||||
.radius = blur.resolved_radius(*this) });
|
.radius = blur.resolved_radius(*this) });
|
||||||
},
|
},
|
||||||
[&](CSS::FilterOperation::DropShadow const& drop_shadow) {
|
[&](CSS::FilterOperation::DropShadow const& drop_shadow) {
|
||||||
|
auto context = CSS::Length::ResolutionContext::for_layout_node(*this);
|
||||||
// The default value for omitted values is missing length values set to 0
|
// The default value for omitted values is missing length values set to 0
|
||||||
// and the missing used color is taken from the color property.
|
// and the missing used color is taken from the color property.
|
||||||
resolved_filter.filters.append(CSS::ResolvedFilter::DropShadow {
|
resolved_filter.filters.append(CSS::ResolvedFilter::DropShadow {
|
||||||
.offset_x = drop_shadow.offset_x.to_px(*this).to_double(),
|
.offset_x = drop_shadow.offset_x.resolved(context).to_px(*this).to_double(),
|
||||||
.offset_y = drop_shadow.offset_y.to_px(*this).to_double(),
|
.offset_y = drop_shadow.offset_y.resolved(context).to_px(*this).to_double(),
|
||||||
.radius = drop_shadow.radius.has_value() ? drop_shadow.radius->to_px(*this).to_double() : 0.0,
|
.radius = drop_shadow.radius.has_value() ? drop_shadow.radius->resolved(context).to_px(*this).to_double() : 0.0,
|
||||||
.color = drop_shadow.color.has_value() ? *drop_shadow.color : this->computed_values().color() });
|
.color = drop_shadow.color.has_value() ? *drop_shadow.color : this->computed_values().color() });
|
||||||
},
|
},
|
||||||
[&](CSS::FilterOperation::Color const& color_operation) {
|
[&](CSS::FilterOperation::Color const& color_operation) {
|
||||||
|
@ -537,7 +538,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
|
||||||
.amount = color_operation.resolved_amount() });
|
.amount = color_operation.resolved_amount() });
|
||||||
},
|
},
|
||||||
[&](CSS::FilterOperation::HueRotate const& hue_rotate) {
|
[&](CSS::FilterOperation::HueRotate const& hue_rotate) {
|
||||||
resolved_filter.filters.append(CSS::ResolvedFilter::HueRotate { .angle_degrees = hue_rotate.angle_degrees() });
|
resolved_filter.filters.append(CSS::ResolvedFilter::HueRotate { .angle_degrees = hue_rotate.angle_degrees(*this) });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return resolved_filter;
|
return resolved_filter;
|
||||||
|
|
Loading…
Reference in a new issue