2020-01-18 08:38:21 +00:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2023-02-17 14:06:55 +00:00
* Copyright ( c ) 2021 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2020-01-18 08:38:21 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 08:38:21 +00:00
*/
2019-06-27 15:47:59 +00:00
# pragma once
2021-12-03 20:00:31 +00:00
# include <AK/HashMap.h>
2022-02-24 15:54:12 +00:00
# include <AK/Optional.h>
2019-09-21 12:32:17 +00:00
# include <AK/OwnPtr.h>
2023-05-26 20:00:54 +00:00
# include <AK/RedBlackTree.h>
2022-03-29 00:14:20 +00:00
# include <LibWeb/CSS/CSSFontFaceRule.h>
2023-05-26 20:00:54 +00:00
# include <LibWeb/CSS/CSSKeyframesRule.h>
2021-05-24 21:02:58 +00:00
# include <LibWeb/CSS/CSSStyleDeclaration.h>
2022-03-31 10:43:07 +00:00
# include <LibWeb/CSS/Parser/ComponentValue.h>
2022-09-27 15:46:22 +00:00
# include <LibWeb/CSS/Parser/TokenStream.h>
2022-02-24 15:54:12 +00:00
# include <LibWeb/CSS/Selector.h>
2020-03-07 09:32:51 +00:00
# include <LibWeb/CSS/StyleProperties.h>
2023-08-17 16:51:32 +00:00
# include <LibWeb/FontCache.h>
2020-07-26 17:37:56 +00:00
# include <LibWeb/Forward.h>
2019-06-27 15:47:59 +00:00
2020-07-26 18:01:35 +00:00
namespace Web : : CSS {
2020-03-07 09:27:02 +00:00
2020-06-12 22:44:26 +00:00
struct MatchingRule {
2023-02-26 23:09:02 +00:00
JS : : GCPtr < CSSStyleRule const > rule ;
2023-07-29 16:51:15 +00:00
JS : : GCPtr < CSSStyleSheet const > sheet ;
2020-06-12 22:44:26 +00:00
size_t style_sheet_index { 0 } ;
size_t rule_index { 0 } ;
size_t selector_index { 0 } ;
2021-05-24 21:01:24 +00:00
u32 specificity { 0 } ;
2023-03-09 18:27:23 +00:00
bool contains_pseudo_element { false } ;
2020-06-12 22:44:26 +00:00
} ;
2021-12-03 20:00:31 +00:00
class PropertyDependencyNode : public RefCounted < PropertyDependencyNode > {
public :
2023-02-17 14:19:16 +00:00
static NonnullRefPtr < PropertyDependencyNode > create ( String name )
2021-12-03 20:00:31 +00:00
{
return adopt_ref ( * new PropertyDependencyNode ( move ( name ) ) ) ;
}
void add_child ( NonnullRefPtr < PropertyDependencyNode > ) ;
bool has_cycles ( ) ;
private :
2023-02-17 14:19:16 +00:00
explicit PropertyDependencyNode ( String name ) ;
2021-12-03 20:00:31 +00:00
2023-02-17 14:19:16 +00:00
String m_name ;
2023-03-06 13:17:01 +00:00
Vector < NonnullRefPtr < PropertyDependencyNode > > m_children ;
2021-12-03 20:00:31 +00:00
bool m_marked { false } ;
} ;
2023-05-24 13:35:30 +00:00
struct FontFaceKey {
FlyString family_name ;
int weight { 0 } ;
int slope { 0 } ;
[ [ nodiscard ] ] u32 hash ( ) const { return pair_int_hash ( family_name . hash ( ) , pair_int_hash ( weight , slope ) ) ; }
[ [ nodiscard ] ] bool operator = = ( FontFaceKey const & ) const = default ;
} ;
2021-09-24 11:49:57 +00:00
class StyleComputer {
2019-06-27 15:47:59 +00:00
public :
2021-09-24 11:49:57 +00:00
explicit StyleComputer ( DOM : : Document & ) ;
2022-03-29 00:14:20 +00:00
~ StyleComputer ( ) ;
2019-06-27 15:47:59 +00:00
2020-07-26 17:37:56 +00:00
DOM : : Document & document ( ) { return m_document ; }
2021-07-14 15:56:11 +00:00
DOM : : Document const & document ( ) const { return m_document ; }
2019-06-27 15:47:59 +00:00
2023-08-17 16:51:32 +00:00
FontCache & font_cache ( ) const { return m_font_cache ; }
2021-09-23 17:48:41 +00:00
NonnullRefPtr < StyleProperties > create_document_style ( ) const ;
2023-03-14 15:36:20 +00:00
2022-12-06 06:08:20 +00:00
ErrorOr < NonnullRefPtr < StyleProperties > > compute_style ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > = { } ) const ;
2023-03-14 15:36:20 +00:00
ErrorOr < RefPtr < StyleProperties > > compute_pseudo_element_style_if_needed ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > ) const ;
2019-06-27 15:47:59 +00:00
2021-09-21 09:38:18 +00:00
// https://www.w3.org/TR/css-cascade/#origin
enum class CascadeOrigin {
Author ,
User ,
UserAgent ,
Animation ,
Transition ,
} ;
2022-02-24 15:54:12 +00:00
Vector < MatchingRule > collect_matching_rules ( DOM : : Element const & , CascadeOrigin , Optional < CSS : : Selector : : PseudoElement > ) const ;
2019-06-27 18:40:21 +00:00
2022-02-10 16:49:50 +00:00
void invalidate_rule_cache ( ) ;
2022-03-11 12:53:32 +00:00
Gfx : : Font const & initial_font ( ) const ;
2023-02-17 14:06:55 +00:00
void did_load_font ( FlyString const & family_name ) ;
2022-03-29 00:14:20 +00:00
2022-04-08 19:27:35 +00:00
void load_fonts_from_sheet ( CSSStyleSheet const & ) ;
2023-08-07 19:48:18 +00:00
RefPtr < Gfx : : Font const > compute_font_for_style_values ( DOM : : Element const * element , Optional < CSS : : Selector : : PseudoElement > pseudo_element , StyleValue const & font_family , StyleValue const & font_size , StyleValue const & font_style , StyleValue const & font_weight , StyleValue const & font_stretch ) const ;
2023-05-26 20:00:54 +00:00
struct AnimationKey {
CSS : : CSSStyleDeclaration const * source_declaration ;
DOM : : Element const * element ;
} ;
2023-07-06 13:26:25 +00:00
struct AnimationTiming {
struct Linear { } ;
struct CubicBezier {
// Regular parameters
double x1 ;
double y1 ;
double x2 ;
double y2 ;
struct CachedSample {
double x ;
double y ;
double t ;
} ;
mutable Vector < CachedSample , 64 > m_cached_x_samples = { } ;
CachedSample sample_around ( double x ) const ;
bool operator = = ( CubicBezier const & other ) const
{
return x1 = = other . x1 & & y1 = = other . y1 & & x2 = = other . x2 & & y2 = = other . y2 ;
}
} ;
struct Steps {
size_t number_of_steps ;
bool jump_at_start ;
bool jump_at_end ;
} ;
Variant < Linear , CubicBezier , Steps > timing_function ;
} ;
2019-06-27 15:47:59 +00:00
private :
2023-03-14 15:36:20 +00:00
enum class ComputeStyleMode {
Normal ,
CreatePseudoElementStyleIfNeeded ,
} ;
2023-05-29 02:16:16 +00:00
class FontLoader ;
2023-08-17 16:45:06 +00:00
struct MatchingFontCandidate ;
2023-05-29 02:16:16 +00:00
2023-03-14 15:36:20 +00:00
ErrorOr < RefPtr < StyleProperties > > compute_style_impl ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , ComputeStyleMode ) const ;
2023-03-14 17:45:24 +00:00
ErrorOr < void > compute_cascaded_values ( StyleProperties & , DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , bool & did_match_any_pseudo_element_rules , ComputeStyleMode ) const ;
2023-05-29 02:16:16 +00:00
static RefPtr < Gfx : : Font const > find_matching_font_weight_ascending ( Vector < MatchingFontCandidate > const & candidates , int target_weight , float font_size_in_pt , bool inclusive ) ;
static RefPtr < Gfx : : Font const > find_matching_font_weight_descending ( Vector < MatchingFontCandidate > const & candidates , int target_weight , float font_size_in_pt , bool inclusive ) ;
RefPtr < Gfx : : Font const > font_matching_algorithm ( FontFaceKey const & key , float font_size_in_pt ) const ;
2022-02-24 15:54:12 +00:00
void compute_font ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
void compute_defaulted_values ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2023-08-19 14:33:21 +00:00
void absolutize_values ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2022-02-24 15:54:12 +00:00
void transform_box_type_if_needed ( StyleProperties & , DOM : : Element const & , Optional < CSS : : Selector : : PseudoElement > ) const ;
2021-09-23 11:13:51 +00:00
2022-02-24 15:54:12 +00:00
void compute_defaulted_property_value ( StyleProperties & , DOM : : Element const * , CSS : : PropertyID , Optional < CSS : : Selector : : PseudoElement > ) const ;
2021-09-21 09:38:18 +00:00
2023-05-17 15:05:36 +00:00
RefPtr < StyleValue > resolve_unresolved_style_value ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , PropertyID , UnresolvedStyleValue const & ) const ;
bool expand_variables ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , StringView property_name , HashMap < FlyString , NonnullRefPtr < PropertyDependencyNode > > & dependencies , Parser : : TokenStream < Parser : : ComponentValue > & source , Vector < Parser : : ComponentValue > & dest ) const ;
2022-11-02 19:19:03 +00:00
bool expand_unresolved_values ( DOM : : Element & , StringView property_name , Parser : : TokenStream < Parser : : ComponentValue > & source , Vector < Parser : : ComponentValue > & dest ) const ;
2021-12-03 12:32:12 +00:00
2023-07-29 15:14:18 +00:00
void set_all_properties ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , StyleProperties & , StyleValue const & , DOM : : Document & , CSS : : CSSStyleDeclaration const * , StyleProperties : : PropertyValues const & properties_for_revert ) const ;
2023-07-29 08:53:24 +00:00
2019-10-05 07:01:12 +00:00
template < typename Callback >
2021-09-21 09:38:18 +00:00
void for_each_stylesheet ( CascadeOrigin , Callback ) const ;
2022-11-09 12:32:20 +00:00
CSSPixelRect viewport_rect ( ) const ;
2023-05-08 08:28:21 +00:00
[ [ nodiscard ] ] Length : : FontMetrics calculate_root_element_font_metrics ( StyleProperties const & ) const ;
2023-03-17 22:08:45 +00:00
CSSPixels parent_or_root_element_line_height ( DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2022-03-19 17:08:52 +00:00
2021-09-21 09:38:18 +00:00
struct MatchingRuleSet {
Vector < MatchingRule > user_agent_rules ;
Vector < MatchingRule > author_rules ;
} ;
2023-04-02 06:35:03 +00:00
void cascade_declarations ( StyleProperties & , DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , Vector < MatchingRule > const & , CascadeOrigin , Important ) const ;
2019-10-05 07:01:12 +00:00
2022-02-10 16:49:50 +00:00
void build_rule_cache ( ) ;
void build_rule_cache_if_needed ( ) const ;
2023-02-26 23:09:02 +00:00
JS : : NonnullGCPtr < DOM : : Document > m_document ;
2022-02-10 16:49:50 +00:00
2023-05-26 20:00:54 +00:00
struct AnimationKeyFrameSet {
struct ResolvedKeyFrame {
struct UseInitial { } ;
Array < Variant < Empty , UseInitial , NonnullRefPtr < StyleValue const > > , to_underlying ( last_property_id ) + 1 > resolved_properties { } ;
} ;
RedBlackTree < u64 , ResolvedKeyFrame > keyframes_by_key ;
} ;
2022-02-10 16:49:50 +00:00
struct RuleCache {
2023-02-17 14:19:16 +00:00
HashMap < FlyString , Vector < MatchingRule > > rules_by_id ;
HashMap < FlyString , Vector < MatchingRule > > rules_by_class ;
HashMap < FlyString , Vector < MatchingRule > > rules_by_tag_name ;
2022-02-10 16:49:50 +00:00
Vector < MatchingRule > other_rules ;
2023-05-26 20:00:54 +00:00
HashMap < FlyString , NonnullOwnPtr < AnimationKeyFrameSet > > rules_by_animation_keyframes ;
2022-02-10 16:49:50 +00:00
} ;
2023-03-07 19:13:13 +00:00
NonnullOwnPtr < RuleCache > make_rule_cache_for_cascade_origin ( CascadeOrigin ) ;
RuleCache const & rule_cache_for_cascade_origin ( CascadeOrigin ) const ;
2023-05-26 20:00:54 +00:00
void ensure_animation_timer ( ) const ;
2023-03-07 19:13:13 +00:00
OwnPtr < RuleCache > m_author_rule_cache ;
OwnPtr < RuleCache > m_user_agent_rule_cache ;
2022-03-29 00:14:20 +00:00
2023-08-17 16:51:32 +00:00
mutable FontCache m_font_cache ;
2023-05-24 13:35:30 +00:00
HashMap < FontFaceKey , NonnullOwnPtr < FontLoader > > m_loaded_fonts ;
2023-05-08 08:28:21 +00:00
Length : : FontMetrics m_default_font_metrics ;
Length : : FontMetrics m_root_element_font_metrics ;
2023-05-26 20:00:54 +00:00
constexpr static u64 AnimationKeyFrameKeyScaleFactor = 1000 ; // 0..100000
enum class AnimationStepTransition {
NoTransition ,
IdleOrBeforeToActive ,
IdleOrBeforeToAfter ,
ActiveToBefore ,
ActiveToActiveChangingTheIteration ,
ActiveToAfter ,
AfterToActive ,
AfterToBefore ,
Cancelled ,
} ;
enum class AnimationState {
Before ,
After ,
Idle ,
Active ,
} ;
2023-05-27 06:15:21 +00:00
struct AnimationStateSnapshot {
Array < RefPtr < StyleValue const > , to_underlying ( last_property_id ) + 1 > state ;
} ;
2023-05-26 20:00:54 +00:00
struct Animation {
String name ;
2023-06-09 13:25:32 +00:00
Optional < CSS : : Time > duration ; // "auto" if not set.
2023-05-26 20:00:54 +00:00
CSS : : Time delay ;
Optional < size_t > iteration_count ; // Infinite if not set.
2023-07-06 13:26:25 +00:00
AnimationTiming timing_function ;
2023-05-26 20:00:54 +00:00
CSS : : AnimationDirection direction ;
CSS : : AnimationFillMode fill_mode ;
WeakPtr < DOM : : Element > owning_element ;
CSS : : Percentage progress { 0 } ;
CSS : : Time remaining_delay { 0 , CSS : : Time : : Type : : Ms } ;
AnimationState current_state { AnimationState : : Before } ;
2023-05-29 01:32:03 +00:00
size_t current_iteration { 1 } ;
2023-05-27 06:15:21 +00:00
mutable AnimationStateSnapshot initial_state { } ;
mutable OwnPtr < AnimationStateSnapshot > active_state_if_fill_forward { } ;
2023-05-26 20:00:54 +00:00
AnimationStepTransition step ( CSS : : Time const & time_step ) ;
ErrorOr < void > collect_into ( StyleProperties & , RuleCache const & ) const ;
bool is_done ( ) const ;
2023-05-29 01:32:03 +00:00
private :
float compute_output_progress ( float input_progress ) const ;
bool is_animating_backwards ( ) const ;
2023-05-26 20:00:54 +00:00
} ;
mutable HashMap < AnimationKey , NonnullOwnPtr < Animation > > m_active_animations ;
2023-05-27 06:15:21 +00:00
mutable HashMap < AnimationKey , OwnPtr < AnimationStateSnapshot > > m_finished_animations ; // If fill-mode is forward/both, this is non-null and contains the final state.
2023-05-26 20:00:54 +00:00
mutable RefPtr < Platform : : Timer > m_animation_driver_timer ;
2019-06-27 15:47:59 +00:00
} ;
2020-03-07 09:27:02 +00:00
}
2023-05-26 20:00:54 +00:00
template < >
struct AK : : Traits < Web : : CSS : : StyleComputer : : AnimationKey > : public AK : : GenericTraits < Web : : CSS : : StyleComputer : : AnimationKey > {
static unsigned hash ( Web : : CSS : : StyleComputer : : AnimationKey const & k ) { return pair_int_hash ( ptr_hash ( k . source_declaration ) , ptr_hash ( k . element ) ) ; }
static bool equals ( Web : : CSS : : StyleComputer : : AnimationKey const & a , Web : : CSS : : StyleComputer : : AnimationKey const & b )
{
return a . element = = b . element & & a . source_declaration = = b . source_declaration ;
}
} ;