#ifndef CSSSTYLESHEET_H #define CSSSTYLESHEET_H #include "element.h" #include "pointer.h" #include #include namespace lunasvg { class CSSValue : public RefCounted { public: virtual ~CSSValue() = default; virtual bool isInitialValue() const { return false; } virtual bool isInheritValue() const { return false; } virtual bool isIdentValue() const { return false; } virtual bool isIntegerValue() const { return false; } virtual bool isNumberValue() const { return false; } virtual bool isPercentValue() const { return false; } virtual bool isLengthValue() const { return false; } virtual bool isStringValue() const { return false; } virtual bool isUrlValue() const { return false; } virtual bool isColorValue() const { return false; } virtual bool isPairValue() const { return false; } virtual bool isListValue() const { return false; } protected: CSSValue() = default; }; using CSSValueList = std::vector>; class CSSInitialValue final : public CSSValue { public: static RefPtr create(); bool isInitialValue() const final { return true; } private: CSSInitialValue() = default; }; template<> struct is { static bool check(const CSSValue& value) { return value.isInitialValue(); } }; class CSSInheritValue final : public CSSValue { public: static RefPtr create(); bool isInheritValue() const final { return true; } private: CSSInheritValue() = default; }; template<> struct is { static bool check(const CSSValue& value) { return value.isInheritValue(); } }; enum class CSSValueID { Unknown, Auto, Bevel, Bold, Bolder, Butt, Clip, Collapse, Color, CurrentColor, End, Evenodd, Hidden, Inherit, Initial, Inline, Italic, Large, Larger, Lighter, Medium, Middle, Miter, None, Nonzero, Normal, Oblique, Round, Small, SmallCaps, Smaller, Square, Start, Stroke, Visible, XLarge, XSmall, XxLarge, XxSmall, XxxLarge }; class CSSIdentValue final : public CSSValue { public: static RefPtr create(CSSValueID value); CSSValueID value() const { return m_value; } bool isIdentValue() const final { return true; } private: CSSIdentValue(CSSValueID value) : m_value(value) {} CSSValueID m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isIdentValue(); } }; class CSSIntegerValue final : public CSSValue { public: static RefPtr create(int value); int value() const { return m_value; } bool isIntegerValue() const final { return true; } private: CSSIntegerValue(int value) : m_value(value) {} int m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isIntegerValue(); } }; class CSSNumberValue final : public CSSValue { public: static RefPtr create(double value); double value() const { return m_value; } bool isNumberValue() const final { return true; } private: CSSNumberValue(double value) : m_value(value) {} double m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isNumberValue(); } }; class CSSPercentValue final : public CSSValue { public: static RefPtr create(double value); double value() const { return m_value; } bool isPercentValue() const final { return true; } private: CSSPercentValue(double value) : m_value(value) {} double m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isPercentValue(); } }; class CSSLengthValue final : public CSSValue { public: enum class Unit { None, Ems, Exs, Pixels, Centimeters, Millimeters, Inches, Points, Picas, ViewportWidth, ViewportHeight, ViewportMin, ViewportMax, Rems, Chs }; static RefPtr create(double value, Unit unit); double value() const { return m_value; } Unit unit() const { return m_unit; } bool isLengthValue() const final { return true; } private: CSSLengthValue(double value, Unit unit) : m_value(value), m_unit(unit) {} double m_value; Unit m_unit; }; template<> struct is { static bool check(const CSSValue& value) { return value.isLengthValue(); } }; class CSSStringValue final : public CSSValue { public: static RefPtr create(std::string value); const std::string& value() const { return m_value; } bool isStringValue() const final { return true; } private: CSSStringValue(std::string value) : m_value(std::move(value)) {} std::string m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isStringValue(); } }; class CSSUrlValue final : public CSSValue { public: static RefPtr create(std::string value); const std::string& value() const { return m_value; } bool isUrlValue() const final { return true; } private: CSSUrlValue(std::string value) : m_value(std::move(value)) {} std::string m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isUrlValue(); } }; class CSSColorValue final : public CSSValue { public: static RefPtr create(uint32_t value); static RefPtr create(uint8_t r, uint8_t g, uint8_t b, uint8_t a); uint32_t value() const { return m_value; } bool isColorValue() const final { return true; } private: CSSColorValue(uint32_t value) : m_value(value) {} uint32_t m_value; }; template<> struct is { static bool check(const CSSValue& value) { return value.isColorValue(); } }; class CSSPairValue final : public CSSValue { public: static RefPtr create(RefPtr first, RefPtr second); const RefPtr& first() const { return m_first; } const RefPtr& second() const { return m_second; } bool isPairValue() const final { return true; } private: CSSPairValue(RefPtr first, RefPtr second) : m_first(first), m_second(second) {} RefPtr m_first; RefPtr m_second; }; template<> struct is { static bool check(const CSSValue& value) { return value.isPairValue(); } }; class CSSListValue : public CSSValue { public: static RefPtr create(CSSValueList values); size_t length() const { return m_values.size(); } const RefPtr& front() const { return m_values.front(); } const RefPtr& back() const { return m_values.back(); } const RefPtr& at(size_t index) const { return m_values.at(index); } const CSSValueList& values() const { return m_values; } bool isListValue() const final { return true; } protected: CSSListValue(CSSValueList values) : m_values(std::move(values)) {} CSSValueList m_values; }; enum class CSSPropertyID { Unknown = 0, Clip_Path, Clip_Rule, Color, Display, Fill, Fill_Opacity, Fill_Rule, Font_Family, Font_Size, Font_Style, Font_Variant, Font_Weight, Letter_Spacing, Marker_End, Marker_Mid, Marker_Start, Mask, Opacity, Overflow, Solid_Color, Solid_Opacity, Stop_Color, Stop_Opacity, Stroke, Stroke_Dasharray, Stroke_Dashoffset, Stroke_Linecap, Stroke_Linejoin, Stroke_Miterlimit, Stroke_Opacity, Stroke_Width, Text_Anchor, Text_Decoration, Visibility, Word_Spacing }; CSSPropertyID csspropertyid(const std::string_view& name); class CSSProperty { public: CSSProperty(CSSPropertyID id, bool important, RefPtr value) : m_id(id), m_important(important), m_value(value) {} CSSPropertyID id() const { return m_id; } bool important() const { return m_important; } const RefPtr& value() const { return m_value; } private: CSSPropertyID m_id; bool m_important; RefPtr m_value; }; using CSSPropertyList = std::vector; using CSSPropertyMap = std::map; struct CSSSimpleSelector; using CSSSelector = std::vector; using CSSSelectorList = std::vector; struct CSSSimpleSelector { struct Attribute { enum class Type { None, Equals, Contains, Includes, StartsWith, EndsWith, DashEquals }; Type type{Type::None}; PropertyID id{PropertyID::Unknown}; std::string value; }; struct Pseudo { enum class Type { Unknown, Empty, Root, Is, Not, FirstChild, LastChild, OnlyChild, FirstOfType, LastOfType, OnlyOfType, NthChild, NthLastChild, NthOfType, NthLastOfType }; using MatchPattern = std::pair; bool matchnth(size_t count) const; Type type{Type::Unknown}; MatchPattern pattern; CSSSelectorList selectors; }; enum class Combinator { None, Descendant, Child, DirectAdjacent, InDirectAdjacent }; Combinator combinator{Combinator::Descendant}; ElementID id{ElementID::Star}; std::vector attributes; std::vector pseudos; }; class CSSRule { public: static std::unique_ptr create(CSSSelectorList selectors, CSSPropertyList properties); const CSSSelectorList& selectors() const { return m_selectors; } const CSSPropertyList& properties() const { return m_properties; } private: CSSRule(CSSSelectorList selectors, CSSPropertyList properties) : m_selectors(std::move(selectors)), m_properties(std::move(properties)) {} CSSSelectorList m_selectors; CSSPropertyList m_properties; }; using CSSRuleList = std::vector>; class CSSRuleData { public: CSSRuleData(const CSSSelector& selector, const CSSPropertyList& properties, uint32_t specificity, uint32_t position) : m_selector(selector), m_properties(properties), m_specificity(specificity), m_position(position) {} const CSSSelector& selector() const { return m_selector; } const CSSPropertyList& properties() const { return m_properties; } const uint32_t& specificity() const { return m_specificity; } const uint32_t& position() const { return m_position; } bool match(const Element* element) const; private: static bool matchSimpleSelector(const CSSSimpleSelector& selector, const Element* element); static bool matchAttributeSelector(const CSSSimpleSelector::Attribute& attribute, const Element* element); static bool matchPseudoClassSelector(const CSSSimpleSelector::Pseudo& pseudo, const Element* element); private: const CSSSelector& m_selector; const CSSPropertyList& m_properties; uint32_t m_specificity; uint32_t m_position; }; inline bool operator<(const CSSRuleData& a, const CSSRuleData& b) { return std::tie(a.specificity(), a.position()) < std::tie(b.specificity(), b.position()); } inline bool operator>(const CSSRuleData& a, const CSSRuleData& b) { return std::tie(a.specificity(), a.position()) > std::tie(b.specificity(), b.position()); } using CSSRuleSet = std::multiset; class ComputedStyle; class CSSStyleSheet { public: CSSStyleSheet() = default; void parse(const std::string_view& content); bool empty() const { return m_ruleList.empty(); } RefPtr styleForElement(const Element* element, const RefPtr& parentStyle) const; private: CSSRuleList m_ruleList; CSSRuleSet m_ruleSet; }; } // namespace lunasvg #endif // CSSSTYLESHEET_H