2020-01-18 05:38:21 -03:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2023-02-17 11:06:55 -03:00
* Copyright ( c ) 2021 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2020-01-18 05:38:21 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2019-06-27 12:47:59 -03:00
# pragma once
2021-12-03 17:00:31 -03:00
# include <AK/HashMap.h>
2022-02-24 12:54:12 -03:00
# include <AK/Optional.h>
2019-09-21 09:32:17 -03:00
# include <AK/OwnPtr.h>
2023-05-26 17:00:54 -03:00
# include <AK/RedBlackTree.h>
2022-03-28 21:14:20 -03:00
# include <LibWeb/CSS/CSSFontFaceRule.h>
2023-05-26 17:00:54 -03:00
# include <LibWeb/CSS/CSSKeyframesRule.h>
2021-05-24 18:02:58 -03:00
# include <LibWeb/CSS/CSSStyleDeclaration.h>
2022-02-24 12:54:12 -03:00
# include <LibWeb/CSS/Selector.h>
2020-03-07 06:32:51 -03:00
# include <LibWeb/CSS/StyleProperties.h>
2023-08-17 13:51:32 -03:00
# include <LibWeb/FontCache.h>
2020-07-26 14:37:56 -03:00
# include <LibWeb/Forward.h>
2019-06-27 12:47:59 -03:00
2020-07-26 15:01:35 -03:00
namespace Web : : CSS {
2020-03-07 06:27:02 -03:00
2020-06-12 19:44:26 -03:00
struct MatchingRule {
2023-02-26 20:09:02 -03:00
JS : : GCPtr < CSSStyleRule const > rule ;
2023-07-29 13:51:15 -03:00
JS : : GCPtr < CSSStyleSheet const > sheet ;
2020-06-12 19:44:26 -03:00
size_t style_sheet_index { 0 } ;
size_t rule_index { 0 } ;
size_t selector_index { 0 } ;
2021-05-24 18:01:24 -03:00
u32 specificity { 0 } ;
2023-03-09 15:27:23 -03:00
bool contains_pseudo_element { false } ;
2020-06-12 19:44:26 -03:00
} ;
2023-05-24 10:35:30 -03: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 08:49:57 -03:00
class StyleComputer {
2019-06-27 12:47:59 -03:00
public :
2021-09-24 08:49:57 -03:00
explicit StyleComputer ( DOM : : Document & ) ;
2022-03-28 21:14:20 -03:00
~ StyleComputer ( ) ;
2019-06-27 12:47:59 -03:00
2020-07-26 14:37:56 -03:00
DOM : : Document & document ( ) { return m_document ; }
2021-07-14 12:56:11 -03:00
DOM : : Document const & document ( ) const { return m_document ; }
2019-06-27 12:47:59 -03:00
2023-08-17 13:51:32 -03:00
FontCache & font_cache ( ) const { return m_font_cache ; }
2021-09-23 14:48:41 -03:00
NonnullRefPtr < StyleProperties > create_document_style ( ) const ;
2023-03-14 12:36:20 -03:00
2022-12-06 03:08:20 -03:00
ErrorOr < NonnullRefPtr < StyleProperties > > compute_style ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > = { } ) const ;
2023-03-14 12:36:20 -03:00
ErrorOr < RefPtr < StyleProperties > > compute_pseudo_element_style_if_needed ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > ) const ;
2019-06-27 12:47:59 -03:00
2021-09-21 06:38:18 -03:00
// https://www.w3.org/TR/css-cascade/#origin
enum class CascadeOrigin {
Author ,
User ,
UserAgent ,
Animation ,
Transition ,
} ;
2022-02-24 12:54:12 -03:00
Vector < MatchingRule > collect_matching_rules ( DOM : : Element const & , CascadeOrigin , Optional < CSS : : Selector : : PseudoElement > ) const ;
2019-06-27 15:40:21 -03:00
2022-02-10 13:49:50 -03:00
void invalidate_rule_cache ( ) ;
2022-03-11 09:53:32 -03:00
Gfx : : Font const & initial_font ( ) const ;
2023-02-17 11:06:55 -03:00
void did_load_font ( FlyString const & family_name ) ;
2022-03-28 21:14:20 -03:00
2022-04-08 16:27:35 -03:00
void load_fonts_from_sheet ( CSSStyleSheet const & ) ;
2023-09-07 13:39:07 -03: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 , int math_depth = 0 ) const ;
2023-08-07 16:48:18 -03:00
2023-05-26 17:00:54 -03:00
struct AnimationKey {
CSS : : CSSStyleDeclaration const * source_declaration ;
DOM : : Element const * element ;
} ;
2023-07-06 10:26:25 -03: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 12:47:59 -03:00
private :
2023-03-14 12:36:20 -03:00
enum class ComputeStyleMode {
Normal ,
CreatePseudoElementStyleIfNeeded ,
} ;
2023-05-28 23:16:16 -03:00
class FontLoader ;
2023-08-17 13:45:06 -03:00
struct MatchingFontCandidate ;
2023-05-28 23:16:16 -03:00
2023-03-14 12:36:20 -03:00
ErrorOr < RefPtr < StyleProperties > > compute_style_impl ( DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , ComputeStyleMode ) const ;
2023-03-14 14:45:24 -03:00
ErrorOr < void > compute_cascaded_values ( StyleProperties & , DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , bool & did_match_any_pseudo_element_rules , ComputeStyleMode ) const ;
2023-05-28 23:16:16 -03: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 12:54:12 -03:00
void compute_font ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2023-09-07 11:29:54 -03:00
void compute_math_depth ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2022-02-24 12:54:12 -03:00
void compute_defaulted_values ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2023-08-19 11:33:21 -03:00
void absolutize_values ( StyleProperties & , DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2022-02-24 12:54:12 -03:00
void transform_box_type_if_needed ( StyleProperties & , DOM : : Element const & , Optional < CSS : : Selector : : PseudoElement > ) const ;
2021-09-23 08:13:51 -03:00
2022-02-24 12:54:12 -03:00
void compute_defaulted_property_value ( StyleProperties & , DOM : : Element const * , CSS : : PropertyID , Optional < CSS : : Selector : : PseudoElement > ) const ;
2021-09-21 06:38:18 -03:00
2023-07-29 12:14:18 -03: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 05:53:24 -03:00
2019-10-05 04:01:12 -03:00
template < typename Callback >
2021-09-21 06:38:18 -03:00
void for_each_stylesheet ( CascadeOrigin , Callback ) const ;
2022-11-09 09:32:20 -03:00
CSSPixelRect viewport_rect ( ) const ;
2023-05-08 05:28:21 -03:00
[ [ nodiscard ] ] Length : : FontMetrics calculate_root_element_font_metrics ( StyleProperties const & ) const ;
2023-03-17 19:08:45 -03:00
CSSPixels parent_or_root_element_line_height ( DOM : : Element const * , Optional < CSS : : Selector : : PseudoElement > ) const ;
2022-03-19 14:08:52 -03:00
2021-09-21 06:38:18 -03:00
struct MatchingRuleSet {
Vector < MatchingRule > user_agent_rules ;
2023-08-21 11:50:01 -03:00
Vector < MatchingRule > user_rules ;
2021-09-21 06:38:18 -03:00
Vector < MatchingRule > author_rules ;
} ;
2023-04-02 03:35:03 -03:00
void cascade_declarations ( StyleProperties & , DOM : : Element & , Optional < CSS : : Selector : : PseudoElement > , Vector < MatchingRule > const & , CascadeOrigin , Important ) const ;
2019-10-05 04:01:12 -03:00
2022-02-10 13:49:50 -03:00
void build_rule_cache ( ) ;
void build_rule_cache_if_needed ( ) const ;
2023-02-26 20:09:02 -03:00
JS : : NonnullGCPtr < DOM : : Document > m_document ;
2022-02-10 13:49:50 -03:00
2023-05-26 17:00:54 -03: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 13:49:50 -03:00
struct RuleCache {
2023-02-17 11:19:16 -03: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 13:49:50 -03:00
Vector < MatchingRule > other_rules ;
2023-05-26 17:00:54 -03:00
HashMap < FlyString , NonnullOwnPtr < AnimationKeyFrameSet > > rules_by_animation_keyframes ;
2022-02-10 13:49:50 -03:00
} ;
2023-03-07 16:13:13 -03:00
NonnullOwnPtr < RuleCache > make_rule_cache_for_cascade_origin ( CascadeOrigin ) ;
RuleCache const & rule_cache_for_cascade_origin ( CascadeOrigin ) const ;
2023-05-26 17:00:54 -03:00
void ensure_animation_timer ( ) const ;
2023-03-07 16:13:13 -03:00
OwnPtr < RuleCache > m_author_rule_cache ;
2023-08-21 11:50:01 -03:00
OwnPtr < RuleCache > m_user_rule_cache ;
2023-03-07 16:13:13 -03:00
OwnPtr < RuleCache > m_user_agent_rule_cache ;
2023-08-21 11:50:01 -03:00
JS : : Handle < CSSStyleSheet > m_user_style_sheet ;
2022-03-28 21:14:20 -03:00
2023-08-17 13:51:32 -03:00
mutable FontCache m_font_cache ;
2023-05-24 10:35:30 -03:00
HashMap < FontFaceKey , NonnullOwnPtr < FontLoader > > m_loaded_fonts ;
2023-05-08 05:28:21 -03:00
Length : : FontMetrics m_default_font_metrics ;
Length : : FontMetrics m_root_element_font_metrics ;
2023-05-26 17:00:54 -03: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 03:15:21 -03:00
struct AnimationStateSnapshot {
Array < RefPtr < StyleValue const > , to_underlying ( last_property_id ) + 1 > state ;
} ;
2023-05-26 17:00:54 -03:00
struct Animation {
String name ;
2023-06-09 10:25:32 -03:00
Optional < CSS : : Time > duration ; // "auto" if not set.
2023-05-26 17:00:54 -03:00
CSS : : Time delay ;
Optional < size_t > iteration_count ; // Infinite if not set.
2023-07-06 10:26:25 -03:00
AnimationTiming timing_function ;
2023-05-26 17:00:54 -03: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-28 22:32:03 -03:00
size_t current_iteration { 1 } ;
2023-05-27 03:15:21 -03:00
mutable AnimationStateSnapshot initial_state { } ;
mutable OwnPtr < AnimationStateSnapshot > active_state_if_fill_forward { } ;
2023-05-26 17:00:54 -03:00
AnimationStepTransition step ( CSS : : Time const & time_step ) ;
ErrorOr < void > collect_into ( StyleProperties & , RuleCache const & ) const ;
bool is_done ( ) const ;
2023-05-28 22:32:03 -03:00
private :
float compute_output_progress ( float input_progress ) const ;
bool is_animating_backwards ( ) const ;
2023-05-26 17:00:54 -03:00
} ;
mutable HashMap < AnimationKey , NonnullOwnPtr < Animation > > m_active_animations ;
2023-05-27 03:15:21 -03: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 17:00:54 -03:00
mutable RefPtr < Platform : : Timer > m_animation_driver_timer ;
2019-06-27 12:47:59 -03:00
} ;
2020-03-07 06:27:02 -03:00
}
2023-05-26 17:00:54 -03: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 ;
}
} ;