| /* |
| * (C) 1999-2003 Lars Knoll (knoll@kde.org) |
| * Copyright (C) 2004, 2005, 2006, 2008, 2012 Apple Inc. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_VALUE_SET_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_VALUE_SET_H_ |
| |
| #include "base/bits.h" |
| |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/css/css_primitive_value.h" |
| #include "third_party/blink/renderer/core/css/css_property_name.h" |
| #include "third_party/blink/renderer/core/css/css_property_names.h" |
| #include "third_party/blink/renderer/core/css/css_property_value.h" |
| #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h" |
| #include "third_party/blink/renderer/core/css/property_set_css_style_declaration.h" |
| #include "third_party/blink/renderer/platform/heap/persistent.h" |
| #include "third_party/blink/renderer/platform/wtf/casting.h" |
| #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" |
| #include "third_party/blink/renderer/platform/wtf/vector.h" |
| |
| namespace blink { |
| |
| class CSSStyleDeclaration; |
| class ExecutionContext; |
| class ImmutableCSSPropertyValueSet; |
| class MutableCSSPropertyValueSet; |
| class StyleSheetContents; |
| enum class CSSValueID; |
| enum class SecureContextMode; |
| |
| class CORE_EXPORT CSSPropertyValueSet |
| : public GarbageCollected<CSSPropertyValueSet> { |
| friend class PropertyReference; |
| |
| public: |
| CSSPropertyValueSet(const CSSPropertyValueSet&) = delete; |
| CSSPropertyValueSet& operator=(const CSSPropertyValueSet&) = delete; |
| |
| void FinalizeGarbageCollectedObject(); |
| |
| class PropertyReference { |
| STACK_ALLOCATED(); |
| |
| public: |
| PropertyReference(const CSSPropertyValueSet& property_set, unsigned index) |
| : property_set_(&property_set), index_(index) {} |
| |
| CSSPropertyID Id() const { |
| return static_cast<CSSPropertyID>(PropertyMetadata().PropertyID()); |
| } |
| CSSPropertyID ShorthandID() const { |
| return PropertyMetadata().ShorthandID(); |
| } |
| |
| CSSPropertyName Name() const { return PropertyMetadata().Name(); } |
| |
| bool IsImportant() const { return PropertyMetadata().important_; } |
| bool IsImplicit() const { return PropertyMetadata().implicit_; } |
| bool IsAffectedByAll() const { |
| return Id() != CSSPropertyID::kVariable && |
| CSSProperty::Get(Id()).IsAffectedByAll(); |
| } |
| |
| const CSSValue& Value() const { return PropertyValue(); } |
| |
| const CSSPropertyValueMetadata& PropertyMetadata() const; |
| |
| private: |
| const CSSValue& PropertyValue() const; |
| |
| const CSSPropertyValueSet* property_set_; |
| unsigned index_; |
| }; |
| |
| unsigned PropertyCount() const; |
| bool IsEmpty() const; |
| PropertyReference PropertyAt(unsigned index) const { |
| return PropertyReference(*this, index); |
| } |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| int FindPropertyIndex(const T& property) const; |
| |
| bool HasProperty(CSSPropertyID property) const { |
| return FindPropertyIndex(property) != -1; |
| } |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| const CSSValue* GetPropertyCSSValue(const T& property) const; |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| String GetPropertyValue(const T& property) const; |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| bool PropertyIsImportant(const T& property) const; |
| |
| const CSSValue* GetPropertyCSSValueWithHint(const AtomicString& property_name, |
| unsigned index) const; |
| String GetPropertyValueWithHint(const AtomicString& property_name, |
| unsigned index) const; |
| bool PropertyIsImportantWithHint(const AtomicString& property_name, |
| unsigned index) const; |
| |
| bool ShorthandIsImportant(CSSPropertyID) const; |
| bool ShorthandIsImportant(const AtomicString& custom_property_name) const { |
| // Custom properties are never shorthands. |
| return false; |
| } |
| |
| CSSPropertyID GetPropertyShorthand(CSSPropertyID) const; |
| bool IsPropertyImplicit(CSSPropertyID) const; |
| |
| CSSParserMode CssParserMode() const { |
| return static_cast<CSSParserMode>(css_parser_mode_); |
| } |
| |
| MutableCSSPropertyValueSet* MutableCopy() const; |
| ImmutableCSSPropertyValueSet* ImmutableCopyIfNeeded() const; |
| |
| MutableCSSPropertyValueSet* CopyPropertiesInSet( |
| const Vector<const CSSProperty*>&) const; |
| |
| String AsText() const; |
| |
| bool IsMutable() const { return is_mutable_; } |
| |
| bool HasFailedOrCanceledSubresources() const; |
| |
| static unsigned AverageSizeInBytes(); |
| |
| #ifndef NDEBUG |
| void ShowStyle(); |
| #endif |
| |
| bool PropertyMatches(CSSPropertyID, const CSSValue&) const; |
| |
| void Trace(Visitor*) const; |
| void TraceAfterDispatch(blink::Visitor* visitor) const {} |
| |
| protected: |
| enum { kMaxArraySize = (1 << 28) - 1 }; |
| |
| explicit CSSPropertyValueSet(CSSParserMode css_parser_mode) |
| : array_size_(0), css_parser_mode_(css_parser_mode), is_mutable_(true) {} |
| |
| CSSPropertyValueSet(CSSParserMode css_parser_mode, |
| unsigned immutable_array_size) |
| // Avoid min()/max() from std here in the header, because that would |
| // require inclusion of <algorithm>, which is slow to compile. |
| : array_size_((immutable_array_size < unsigned(kMaxArraySize)) |
| ? immutable_array_size |
| : unsigned(kMaxArraySize)), |
| css_parser_mode_(css_parser_mode), |
| is_mutable_(false) {} |
| |
| const uint32_t array_size_ : 28; |
| const uint32_t css_parser_mode_ : 3; |
| const uint32_t is_mutable_ : 1; |
| |
| friend class PropertySetCSSStyleDeclaration; |
| }; |
| |
| // Used for lazily parsing properties. |
| class CSSLazyPropertyParser : public GarbageCollected<CSSLazyPropertyParser> { |
| public: |
| CSSLazyPropertyParser() = default; |
| CSSLazyPropertyParser(const CSSLazyPropertyParser&) = delete; |
| CSSLazyPropertyParser& operator=(const CSSLazyPropertyParser&) = delete; |
| virtual ~CSSLazyPropertyParser() = default; |
| virtual CSSPropertyValueSet* ParseProperties() = 0; |
| virtual void Trace(Visitor*) const; |
| }; |
| |
| class CORE_EXPORT ALIGNAS(std::max(alignof(Member<const CSSValue>), |
| alignof(CSSPropertyValueMetadata))) |
| ImmutableCSSPropertyValueSet : public CSSPropertyValueSet { |
| public: |
| ImmutableCSSPropertyValueSet(const CSSPropertyValue*, |
| unsigned count, |
| CSSParserMode); |
| |
| static ImmutableCSSPropertyValueSet* |
| Create(const CSSPropertyValue* properties, unsigned count, CSSParserMode); |
| |
| unsigned PropertyCount() const { return array_size_; } |
| |
| const Member<const CSSValue>* ValueArray() const; |
| const CSSPropertyValueMetadata* MetadataArray() const; |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| int FindPropertyIndex(const T& property) const; |
| |
| void TraceAfterDispatch(blink::Visitor*) const; |
| }; |
| |
| inline const Member<const CSSValue>* ImmutableCSSPropertyValueSet::ValueArray() |
| const { |
| static_assert( |
| sizeof(ImmutableCSSPropertyValueSet) % alignof(Member<const CSSValue>) == |
| 0, |
| "ValueArray may be improperly aligned"); |
| return reinterpret_cast<const Member<const CSSValue>*>(this + 1); |
| } |
| |
| inline const CSSPropertyValueMetadata* |
| ImmutableCSSPropertyValueSet::MetadataArray() const { |
| static_assert(sizeof(ImmutableCSSPropertyValueSet) % |
| alignof(CSSPropertyValueMetadata) == |
| 0, |
| "MetadataArray may be improperly aligned"); |
| // Size of Member<> can be smaller than that of CSSPropertyValueMetadata. |
| // Align it up. |
| return reinterpret_cast<const CSSPropertyValueMetadata*>(base::bits::AlignUp( |
| reinterpret_cast<const uint8_t*>(ValueArray() + array_size_), |
| alignof(CSSPropertyValueMetadata))); |
| } |
| |
| template <> |
| struct DowncastTraits<ImmutableCSSPropertyValueSet> { |
| static bool AllowFrom(const CSSPropertyValueSet& set) { |
| return !set.IsMutable(); |
| } |
| }; |
| |
| class CORE_EXPORT MutableCSSPropertyValueSet : public CSSPropertyValueSet { |
| public: |
| explicit MutableCSSPropertyValueSet(CSSParserMode); |
| explicit MutableCSSPropertyValueSet(const CSSPropertyValueSet&); |
| MutableCSSPropertyValueSet(const CSSPropertyValue* properties, |
| unsigned count); |
| ~MutableCSSPropertyValueSet() = default; |
| |
| unsigned PropertyCount() const { return property_vector_.size(); } |
| |
| enum SetResult { |
| // The value failed to parse correctly, and thus, there was no change. |
| kParseError = 0, |
| |
| // The value parsed correctly, but there was no change, |
| // as it matched the value already in place. |
| kUnchanged = 1, |
| |
| // The value parsed correctly, and there was a change to a property that |
| // already existed. |
| kModifiedExisting = 2, |
| |
| // The value parsed correctly, and caused a property to be added or |
| // modified. (If you do not care whether it did, you can compare the |
| // enum using result >= kModifiedExisting.) |
| kChangedPropertySet = 3, |
| }; |
| |
| // Wrapper around SetLonghandProperty() for setting multiple properties |
| // at a time. |
| SetResult AddParsedProperties(const HeapVector<CSSPropertyValue, 64>&); |
| |
| // Wrapper around SetLonghandProperty() that does nothing if the same property |
| // already exists with an !important declaration. |
| // |
| // Returns whether this style set was changed. |
| bool AddRespectingCascade(const CSSPropertyValue&); |
| |
| // Expands shorthand properties into multiple properties. |
| void SetProperty(CSSPropertyID, const CSSValue&, bool important = false); |
| |
| // Convenience wrapper around the above that also supports custom properties. |
| void SetProperty(const CSSPropertyName&, |
| const CSSValue&, |
| bool important = false); |
| |
| // Also a convenience wrapper around SetProperty(), parsing the value from a |
| // string before setting it. If the value is empty, the property is removed. |
| // Only for non-custom properties. |
| SetResult ParseAndSetProperty( |
| CSSPropertyID unresolved_property, |
| StringView value, |
| bool important, |
| SecureContextMode, |
| StyleSheetContents* context_style_sheet = nullptr); |
| |
| // Similar to ParseAndSetProperty(), but for custom properties instead. |
| // (By implementation quirk, it attempts shorthand expansion, even though |
| // custom properties can never be shorthands.) If the value is empty, |
| // the property is removed. |
| SetResult ParseAndSetCustomProperty(const AtomicString& custom_property_name, |
| StringView value, |
| bool important, |
| SecureContextMode, |
| StyleSheetContents* context_style_sheet, |
| bool is_animation_tainted); |
| |
| // This one does not expand longhands, but is the second-most efficient form |
| // save for the CSSPropertyID variant below. |
| // All the other property setters eventually call down into this. |
| SetResult SetLonghandProperty(CSSPropertyValue); |
| |
| // A streamlined version of the above, which can be used if you don't need |
| // custom properties and don't need the return value (which requires an extra |
| // comparison with the old property). This is the fastest form. |
| void SetLonghandProperty(CSSPropertyID, const CSSValue&); |
| |
| // Convenience form of the CSSPropertyValue overload above. |
| SetResult SetLonghandProperty(CSSPropertyID, |
| CSSValueID identifier, |
| bool important = false); |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| bool RemoveProperty(const T& property, String* return_text = nullptr); |
| bool RemovePropertiesInSet(const CSSProperty* const set[], unsigned length); |
| void RemoveEquivalentProperties(const CSSPropertyValueSet*); |
| void RemoveEquivalentProperties(const CSSStyleDeclaration*); |
| |
| void MergeAndOverrideOnConflict(const CSSPropertyValueSet*); |
| |
| void Clear(); |
| void ParseDeclarationList(const String& style_declaration, |
| SecureContextMode, |
| StyleSheetContents* context_style_sheet); |
| |
| CSSStyleDeclaration* EnsureCSSStyleDeclaration( |
| ExecutionContext* execution_context); |
| |
| template <typename T> // CSSPropertyID or AtomicString |
| int FindPropertyIndex(const T& property) const; |
| |
| void TraceAfterDispatch(blink::Visitor*) const; |
| |
| private: |
| template <typename T> // CSSPropertyID or AtomicString |
| const CSSPropertyValue* FindPropertyPointer(const T& property) const; |
| |
| // Returns nullptr if there is no property to be overwritten. |
| // |
| // If property_id is a logical property we've already seen a different |
| // property matching, this will remove the existing property (and return |
| // nullptr). |
| ALWAYS_INLINE CSSPropertyValue* FindInsertionPointForID( |
| CSSPropertyID property_id); |
| |
| bool RemovePropertyAtIndex(int, String* return_text); |
| |
| bool RemoveShorthandProperty(CSSPropertyID); |
| bool RemoveShorthandProperty(const AtomicString& custom_property_name) { |
| return false; |
| } |
| CSSPropertyValue* FindCSSPropertyWithName(const CSSPropertyName&); |
| Member<PropertySetCSSStyleDeclaration> cssom_wrapper_; |
| |
| friend class CSSPropertyValueSet; |
| |
| HeapVector<CSSPropertyValue, 4> property_vector_; |
| bool may_have_logical_properties_{false}; |
| }; |
| |
| template <> |
| struct DowncastTraits<MutableCSSPropertyValueSet> { |
| static bool AllowFrom(const CSSPropertyValueSet& set) { |
| return set.IsMutable(); |
| } |
| }; |
| |
| inline const CSSPropertyValueMetadata& |
| CSSPropertyValueSet::PropertyReference::PropertyMetadata() const { |
| if (auto* mutable_property_set = |
| DynamicTo<MutableCSSPropertyValueSet>(property_set_)) { |
| return mutable_property_set->property_vector_.at(index_).Metadata(); |
| } |
| return To<ImmutableCSSPropertyValueSet>(*property_set_) |
| .MetadataArray()[index_]; |
| } |
| |
| inline const CSSValue& CSSPropertyValueSet::PropertyReference::PropertyValue() |
| const { |
| if (auto* mutable_property_set = |
| DynamicTo<MutableCSSPropertyValueSet>(property_set_)) { |
| return *mutable_property_set->property_vector_.at(index_).Value(); |
| } |
| return *To<ImmutableCSSPropertyValueSet>(*property_set_).ValueArray()[index_]; |
| } |
| |
| inline unsigned CSSPropertyValueSet::PropertyCount() const { |
| if (auto* mutable_property_set = |
| DynamicTo<MutableCSSPropertyValueSet>(this)) { |
| return mutable_property_set->property_vector_.size(); |
| } |
| return array_size_; |
| } |
| |
| inline bool CSSPropertyValueSet::IsEmpty() const { |
| return !PropertyCount(); |
| } |
| |
| template <typename T> |
| inline int CSSPropertyValueSet::FindPropertyIndex(const T& property) const { |
| if (auto* mutable_property_set = |
| DynamicTo<MutableCSSPropertyValueSet>(this)) { |
| return mutable_property_set->FindPropertyIndex(property); |
| } |
| return To<ImmutableCSSPropertyValueSet>(this)->FindPropertyIndex(property); |
| } |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_VALUE_SET_H_ |