2020-01-18 09:38:21 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2018 - 2020 , Andreas Kling < andreas @ ladybird . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2023-11-19 15:34:55 +04:00
# include <AK/GenericLexer.h>
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/HTMLFontElementPrototype.h>
2022-09-30 17:16:16 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2024-12-20 11:32:17 +01:00
# include <LibWeb/CSS/ComputedProperties.h>
2023-11-19 15:34:55 +04:00
# include <LibWeb/CSS/Parser/Parser.h>
2024-08-14 16:37:02 +01:00
# include <LibWeb/CSS/StyleValues/CSSColorValue.h>
2020-07-26 15:08:16 +02:00
# include <LibWeb/HTML/HTMLFontElement.h>
2023-05-28 15:06:12 +12:00
# include <LibWeb/HTML/Parser/HTMLParser.h>
2023-11-19 15:34:55 +04:00
# include <LibWeb/Infra/CharacterTypes.h>
2019-10-04 21:14:59 +02:00
2020-07-28 18:20:36 +02:00
namespace Web : : HTML {
2020-03-07 10:27:02 +01:00
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( HTMLFontElement ) ;
2023-11-19 19:47:52 +01:00
2023-11-19 15:34:55 +04:00
enum class Mode {
RelativePlus ,
RelativeMinus ,
Absolute ,
} ;
// https://html.spec.whatwg.org/multipage/rendering.html#rules-for-parsing-a-legacy-font-size
2024-12-22 21:34:50 +01:00
Optional < CSS : : Keyword > HTMLFontElement : : parse_legacy_font_size ( StringView string )
2023-11-19 15:34:55 +04:00
{
// 1. Let input be the attribute's value.
// 2. Let position be a pointer into input, initially pointing at the start of the string.
GenericLexer lexer { string } ;
// 3. Skip ASCII whitespace within input given position.
lexer . ignore_while ( Web : : Infra : : is_ascii_whitespace ) ;
// 4. If position is past the end of input, there is no presentational hint. Return.
if ( lexer . is_eof ( ) )
return { } ;
// 5. If the character at position is a U+002B PLUS SIGN character (+), then let mode be relative-plus, and advance position to the next character. Otherwise, if the character at position is a U+002D HYPHEN-MINUS character (-), then let mode be relative-minus, and advance position to the next character. Otherwise, let mode be absolute.
Mode mode { Mode : : Absolute } ;
if ( lexer . peek ( ) = = ' + ' ) {
mode = Mode : : RelativePlus ;
lexer . consume ( ) ;
} else if ( lexer . peek ( ) = = ' - ' ) {
mode = Mode : : RelativeMinus ;
lexer . consume ( ) ;
}
// 6. Collect a sequence of code points that are ASCII digits from input given position, and let the resulting sequence be digits.
size_t start_index = lexer . tell ( ) ;
lexer . consume_while ( is_ascii_digit ) ;
size_t end_index = lexer . tell ( ) ;
auto digits = lexer . input ( ) . substring_view ( start_index , end_index - start_index ) ;
auto value_or_empty = AK : : StringUtils : : convert_to_int < i32 > ( digits ) ;
// 7. If digits is the empty string, there is no presentational hint. Return.
if ( ! value_or_empty . has_value ( ) )
return { } ;
// 8. Interpret digits as a base-ten integer. Let value be the resulting number.
auto value = value_or_empty . release_value ( ) ;
// 9. If mode is relative-plus, then increment value by 3. If mode is relative-minus, then let value be the result of subtracting value from 3.
if ( mode = = Mode : : RelativePlus )
value + = 3 ;
else if ( mode = = Mode : : RelativeMinus )
value = 3 - value ;
// 10. If value is greater than 7, let it be 7.
if ( value > 7 )
value = 7 ;
// 11. If value is less than 1, let it be 1.
if ( value < 1 )
value = 1 ;
// 12. Set 'font-size' to the keyword corresponding to the value of value according to the following table:
switch ( value ) {
case 1 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : XSmall ;
2023-11-19 15:34:55 +04:00
case 2 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : Small ;
2023-11-19 15:34:55 +04:00
case 3 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : Medium ;
2023-11-19 15:34:55 +04:00
case 4 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : Large ;
2023-11-19 15:34:55 +04:00
case 5 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : XLarge ;
2023-11-19 15:34:55 +04:00
case 6 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : XxLarge ;
2023-11-19 15:34:55 +04:00
case 7 :
2024-08-14 14:06:03 +01:00
return CSS : : Keyword : : XxxLarge ;
2023-11-19 15:34:55 +04:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2022-02-18 21:00:52 +01:00
HTMLFontElement : : HTMLFontElement ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-02-07 11:20:15 +01:00
: HTMLElement ( document , move ( qualified_name ) )
2019-10-04 21:14:59 +02:00
{
}
2022-03-14 13:21:51 -06:00
HTMLFontElement : : ~ HTMLFontElement ( ) = default ;
2019-10-04 21:14:59 +02:00
2023-08-07 08:41:28 +02:00
void HTMLFontElement : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( HTMLFontElement ) ;
2025-04-20 16:22:57 +02:00
Base : : initialize ( realm ) ;
2023-01-10 06:28:20 -05:00
}
2024-12-23 17:51:10 +01:00
bool HTMLFontElement : : is_presentational_hint ( FlyString const & name ) const
{
if ( Base : : is_presentational_hint ( name ) )
return true ;
return first_is_one_of ( name ,
HTML : : AttributeNames : : color ,
HTML : : AttributeNames : : face ,
HTML : : AttributeNames : : size ) ;
}
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
void HTMLFontElement : : apply_presentational_hints ( GC : : Ref < CSS : : CascadedProperties > cascaded_properties ) const
2019-10-04 21:14:59 +02:00
{
for_each_attribute ( [ & ] ( auto & name , auto & value ) {
2025-03-31 17:13:47 +01:00
if ( name = = AttributeNames : : color ) {
2023-05-28 15:06:12 +12:00
// https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3:rules-for-parsing-a-legacy-colour-value
auto color = parse_legacy_color_value ( value ) ;
2019-10-04 21:14:59 +02:00
if ( color . has_value ( ) )
2025-02-19 21:02:12 +11:00
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : Color , CSS : : CSSColorValue : : create_from_color ( color . value ( ) , CSS : : ColorSyntax : : Legacy ) ) ;
2025-03-31 17:13:47 +01:00
} else if ( name = = AttributeNames : : size ) {
2023-11-19 15:34:55 +04:00
// When a font element has a size attribute, the user agent is expected to use the following steps, known as the rules for parsing a legacy font size, to treat the attribute as a presentational hint setting the element's 'font-size' property:
auto font_size_or_empty = parse_legacy_font_size ( value ) ;
if ( font_size_or_empty . has_value ( ) ) {
2024-08-14 14:06:03 +01:00
auto font_size = string_from_keyword ( font_size_or_empty . release_value ( ) ) ;
2025-02-05 12:08:27 +00:00
if ( auto parsed_value = parse_css_value ( CSS : : Parser : : ParsingParams { document ( ) } , font_size , CSS : : PropertyID : : FontSize ) )
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : FontSize , parsed_value . release_nonnull ( ) ) ;
2023-11-19 15:34:55 +04:00
}
2025-03-31 17:13:47 +01:00
} else if ( name = = AttributeNames : : face ) {
// When a font element has a face attribute, the user agent is expected to treat the attribute as a presentational hint setting the element's 'font-family' property to the attribute's value.
if ( auto parsed_value = parse_css_value ( CSS : : Parser : : ParsingParams { document ( ) } , value , CSS : : PropertyID : : FontFamily ) )
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : FontFamily , parsed_value . release_nonnull ( ) ) ;
2019-10-04 21:14:59 +02:00
}
} ) ;
}
2020-03-07 10:27:02 +01:00
}