mirror of
				https://github.com/LadybirdBrowser/ladybird.git
				synced 2025-11-03 23:00:58 +00:00 
			
		
		
		
	CSS Values 5 now defines a `<boolean-expr[]>` type that is used in place of the bespoke grammar that previously existed for `@media` and `@supports` queries. This commit implements some BooleanExpression types to represent the nodes in a `<boolean-expr[]>`, and reimplements `@media` and `@supports` queries using this. The one part of this implementation I'm not convinced on is that the `evaluate()` methods take a `HTML::Window*`. This is a compromise because `@media` requires a Window, and `@supports` does not require anything at all. As more users of `<boolean-expr[]>` get implemented in the future, it will become clear if this is sufficient, or if we need to do something smarter. As a bonus, this actually improves our serialization of media queries!
		
			
				
	
	
		
			171 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: BSD-2-Clause
 | 
						|
 */
 | 
						|
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include <AK/NonnullOwnPtr.h>
 | 
						|
#include <AK/String.h>
 | 
						|
#include <AK/Vector.h>
 | 
						|
#include <LibWeb/Forward.h>
 | 
						|
 | 
						|
namespace Web::CSS {
 | 
						|
 | 
						|
// Corresponds to Kleene 3-valued logic.
 | 
						|
enum class MatchResult {
 | 
						|
    False,
 | 
						|
    True,
 | 
						|
    Unknown,
 | 
						|
};
 | 
						|
 | 
						|
inline MatchResult as_match_result(bool value)
 | 
						|
{
 | 
						|
    return value ? MatchResult::True : MatchResult::False;
 | 
						|
}
 | 
						|
 | 
						|
inline MatchResult negate(MatchResult value)
 | 
						|
{
 | 
						|
    switch (value) {
 | 
						|
    case MatchResult::False:
 | 
						|
        return MatchResult::True;
 | 
						|
    case MatchResult::True:
 | 
						|
        return MatchResult::False;
 | 
						|
    case MatchResult::Unknown:
 | 
						|
        return MatchResult::Unknown;
 | 
						|
    }
 | 
						|
    VERIFY_NOT_REACHED();
 | 
						|
}
 | 
						|
 | 
						|
// The contents of this file implement the `<boolean-expr>` concept.
 | 
						|
// https://drafts.csswg.org/css-values-5/#typedef-boolean-expr
 | 
						|
class BooleanExpression {
 | 
						|
public:
 | 
						|
    virtual ~BooleanExpression() = default;
 | 
						|
 | 
						|
    bool evaluate_to_boolean(HTML::Window const*) const;
 | 
						|
    static void indent(StringBuilder& builder, int levels);
 | 
						|
 | 
						|
    virtual MatchResult evaluate(HTML::Window const*) const = 0;
 | 
						|
    virtual String to_string() const = 0;
 | 
						|
    virtual void dump(StringBuilder&, int indent_levels = 0) const = 0;
 | 
						|
};
 | 
						|
 | 
						|
// https://www.w3.org/TR/mediaqueries-4/#typedef-general-enclosed
 | 
						|
class GeneralEnclosed final : public BooleanExpression {
 | 
						|
public:
 | 
						|
    static NonnullOwnPtr<GeneralEnclosed> create(String serialized_contents, MatchResult matches = MatchResult::Unknown)
 | 
						|
    {
 | 
						|
        return adopt_own(*new GeneralEnclosed(move(serialized_contents), matches));
 | 
						|
    }
 | 
						|
    virtual ~GeneralEnclosed() override = default;
 | 
						|
 | 
						|
    virtual MatchResult evaluate(HTML::Window const*) const override { return m_matches; }
 | 
						|
    virtual String to_string() const override { return m_serialized_contents; }
 | 
						|
    virtual void dump(StringBuilder&, int indent_levels = 0) const override;
 | 
						|
 | 
						|
private:
 | 
						|
    GeneralEnclosed(String serialized_contents, MatchResult matches)
 | 
						|
        : m_serialized_contents(move(serialized_contents))
 | 
						|
        , m_matches(matches)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    String m_serialized_contents;
 | 
						|
    MatchResult m_matches;
 | 
						|
};
 | 
						|
 | 
						|
class BooleanNotExpression final : public BooleanExpression {
 | 
						|
public:
 | 
						|
    static NonnullOwnPtr<BooleanNotExpression> create(NonnullOwnPtr<BooleanExpression>&& child)
 | 
						|
    {
 | 
						|
        return adopt_own(*new BooleanNotExpression(move(child)));
 | 
						|
    }
 | 
						|
    virtual ~BooleanNotExpression() override = default;
 | 
						|
 | 
						|
    virtual MatchResult evaluate(HTML::Window const*) const override;
 | 
						|
    virtual String to_string() const override;
 | 
						|
    virtual void dump(StringBuilder&, int indent_levels = 0) const override;
 | 
						|
 | 
						|
private:
 | 
						|
    BooleanNotExpression(NonnullOwnPtr<BooleanExpression>&& child)
 | 
						|
        : m_child(move(child))
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    NonnullOwnPtr<BooleanExpression> m_child;
 | 
						|
};
 | 
						|
 | 
						|
class BooleanExpressionInParens final : public BooleanExpression {
 | 
						|
public:
 | 
						|
    static NonnullOwnPtr<BooleanExpressionInParens> create(NonnullOwnPtr<BooleanExpression>&& child)
 | 
						|
    {
 | 
						|
        return adopt_own(*new BooleanExpressionInParens(move(child)));
 | 
						|
    }
 | 
						|
    virtual ~BooleanExpressionInParens() override = default;
 | 
						|
 | 
						|
    virtual MatchResult evaluate(HTML::Window const*) const override;
 | 
						|
    virtual String to_string() const override;
 | 
						|
    virtual void dump(StringBuilder&, int indent_levels = 0) const override;
 | 
						|
 | 
						|
private:
 | 
						|
    BooleanExpressionInParens(NonnullOwnPtr<BooleanExpression>&& child)
 | 
						|
        : m_child(move(child))
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    NonnullOwnPtr<BooleanExpression> m_child;
 | 
						|
};
 | 
						|
 | 
						|
class BooleanAndExpression final : public BooleanExpression {
 | 
						|
public:
 | 
						|
    static NonnullOwnPtr<BooleanAndExpression> create(Vector<NonnullOwnPtr<BooleanExpression>>&& children)
 | 
						|
    {
 | 
						|
        return adopt_own(*new BooleanAndExpression(move(children)));
 | 
						|
    }
 | 
						|
    virtual ~BooleanAndExpression() override = default;
 | 
						|
 | 
						|
    virtual MatchResult evaluate(HTML::Window const*) const override;
 | 
						|
    virtual String to_string() const override;
 | 
						|
    virtual void dump(StringBuilder&, int indent_levels = 0) const override;
 | 
						|
 | 
						|
private:
 | 
						|
    BooleanAndExpression(Vector<NonnullOwnPtr<BooleanExpression>>&& children)
 | 
						|
        : m_children(move(children))
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    Vector<NonnullOwnPtr<BooleanExpression>> m_children;
 | 
						|
};
 | 
						|
 | 
						|
class BooleanOrExpression final : public BooleanExpression {
 | 
						|
public:
 | 
						|
    static NonnullOwnPtr<BooleanOrExpression> create(Vector<NonnullOwnPtr<BooleanExpression>>&& children)
 | 
						|
    {
 | 
						|
        return adopt_own(*new BooleanOrExpression(move(children)));
 | 
						|
    }
 | 
						|
    virtual ~BooleanOrExpression() override = default;
 | 
						|
 | 
						|
    virtual MatchResult evaluate(HTML::Window const*) const override;
 | 
						|
    virtual String to_string() const override;
 | 
						|
    virtual void dump(StringBuilder&, int indent_levels = 0) const override;
 | 
						|
 | 
						|
private:
 | 
						|
    BooleanOrExpression(Vector<NonnullOwnPtr<BooleanExpression>>&& children)
 | 
						|
        : m_children(move(children))
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    Vector<NonnullOwnPtr<BooleanExpression>> m_children;
 | 
						|
};
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
template<>
 | 
						|
struct AK::Formatter<Web::CSS::BooleanExpression> : AK::Formatter<StringView> {
 | 
						|
    ErrorOr<void> format(FormatBuilder& builder, Web::CSS::BooleanExpression const& expression)
 | 
						|
    {
 | 
						|
        return Formatter<StringView>::format(builder, expression.to_string());
 | 
						|
    }
 | 
						|
};
 |