/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef AccAttributes_h_ #define AccAttributes_h_ #include "mozilla/ServoStyleConsts.h" #include "mozilla/a11y/AccGroupInfo.h" #include "mozilla/Variant.h" #include "nsTHashMap.h" #include "nsStringFwd.h" #include "mozilla/gfx/Matrix.h" class nsVariant; namespace IPC { template struct ParamTraits; } // namespace IPC namespace mozilla { namespace dom { class Element; } namespace a11y { struct FontSize { int32_t mValue; bool operator==(const FontSize& aOther) const { return mValue == aOther.mValue; } bool operator!=(const FontSize& aOther) const { return mValue != aOther.mValue; } }; struct Color { nscolor mValue; bool operator==(const Color& aOther) const { return mValue == aOther.mValue; } bool operator!=(const Color& aOther) const { return mValue != aOther.mValue; } }; // A special type. If an entry has a value of this type, it instructs the // target instance of an Update to remove the entry with the same key value. struct DeleteEntry { DeleteEntry() : mValue(true) {} bool mValue; bool operator==(const DeleteEntry& aOther) const { return true; } bool operator!=(const DeleteEntry& aOther) const { return false; } }; class AccAttributes { // Warning! An AccAttributes can contain another AccAttributes. This is // intended for object and text attributes. However, the nested // AccAttributes should never itself contain another AccAttributes, nor // should it create a cycle. We don't do cycle collection here for // performance reasons, so violating this rule will cause leaks! using AttrValueType = Variant, nsTArray, CSSCoord, FontSize, Color, DeleteEntry, UniquePtr, RefPtr, uint64_t, UniquePtr, UniquePtr, nsTArray>; static_assert(sizeof(AttrValueType) <= 16); using AtomVariantMap = nsTHashMap, AttrValueType>; protected: ~AccAttributes() = default; public: AccAttributes() = default; AccAttributes(const AccAttributes&) = delete; AccAttributes& operator=(const AccAttributes&) = delete; NS_INLINE_DECL_REFCOUNTING(mozilla::a11y::AccAttributes) template void SetAttribute(nsAtom* aAttrName, T&& aAttrValue) { using ValType = std::remove_const_t>; if constexpr (std::is_convertible_v) { static_assert(std::is_rvalue_reference_v, "Please only move strings into this function. To make a " "copy, use SetAttributeStringCopy."); UniquePtr value = MakeUnique(std::move(aAttrValue)); mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); } else if constexpr (std::is_same_v) { UniquePtr value = MakeUnique(aAttrValue); mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); } else if constexpr (std::is_same_v) { UniquePtr value(aAttrValue); mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); } else if constexpr (std::is_convertible_v) { mData.InsertOrUpdate(aAttrName, AsVariant(RefPtr(aAttrValue))); } else { mData.InsertOrUpdate(aAttrName, AsVariant(std::forward(aAttrValue))); } } void SetAttributeStringCopy(nsAtom* aAttrName, nsString aAttrValue) { SetAttribute(aAttrName, std::move(aAttrValue)); } template Maybe GetAttribute(nsAtom* aAttrName) const { if (auto value = mData.Lookup(aAttrName)) { if constexpr (std::is_same_v) { if (value->is>()) { const T& val = *(value->as>().get()); return SomeRef(val); } } else if constexpr (std::is_same_v) { if (value->is>()) { const T& val = *(value->as>()); return SomeRef(val); } } else { if (value->is()) { const T& val = value->as(); return SomeRef(val); } } } return Nothing(); } template RefPtr GetAttributeRefPtr(nsAtom* aAttrName) const { if (auto value = mData.Lookup(aAttrName)) { if (value->is>()) { RefPtr ref = value->as>(); return ref; } } return nullptr; } template Maybe GetMutableAttribute(nsAtom* aAttrName) const { static_assert(std::is_same_v, T> || std::is_same_v, T>, "Only arrays should be mutable attributes"); if (auto value = mData.Lookup(aAttrName)) { if (value->is()) { T& val = value->as(); return SomeRef(val); } } return Nothing(); } // Get stringified value bool GetAttribute(nsAtom* aAttrName, nsAString& aAttrValue) const; bool HasAttribute(nsAtom* aAttrName) const { return mData.Contains(aAttrName); } bool Remove(nsAtom* aAttrName) { return mData.Remove(aAttrName); } uint32_t Count() const { return mData.Count(); } // Update one instance with the entries in another. The supplied AccAttributes // will be emptied. void Update(AccAttributes* aOther); /** * Return true if all the attributes in this instance are equal to all the * attributes in another instance. */ bool Equal(const AccAttributes* aOther) const; /** * Copy attributes from this instance to another instance. * This should only be used in very specific cases; e.g. merging two sets of * cached attributes without modifying the cache. It can only copy simple * value types; e.g. it can't copy array values. Attempting to copy an * AccAttributes with uncopyable values will cause an assertion. */ void CopyTo(AccAttributes* aDest) const; // An entry class for our iterator. class Entry { public: Entry(nsAtom* aAttrName, const AttrValueType* aAttrValue) : mName(aAttrName), mValue(aAttrValue) {} nsAtom* Name() const { return mName; } template Maybe Value() const { if constexpr (std::is_same_v) { if (mValue->is>()) { const T& val = *(mValue->as>().get()); return SomeRef(val); } } else if constexpr (std::is_same_v) { if (mValue->is>()) { const T& val = *(mValue->as>()); return SomeRef(val); } } else { if (mValue->is()) { const T& val = mValue->as(); return SomeRef(val); } } return Nothing(); } void NameAsString(nsString& aName) const { mName->ToString(aName); if (StringBeginsWith(aName, u"aria-"_ns)) { // Found 'aria-' aName.ReplaceLiteral(0, 5, u""); } } void ValueAsString(nsAString& aValueString) const { StringFromValueAndName(mName, *mValue, aValueString); } // Size of the pair in the hash table. size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf); private: nsAtom* mName; const AttrValueType* mValue; friend class AccAttributes; }; class Iterator { public: explicit Iterator(AtomVariantMap::const_iterator aIter) : mHashIterator(aIter) {} Iterator() = delete; Iterator(const Iterator&) = delete; Iterator& operator=(const Iterator&) = delete; bool operator!=(const Iterator& aOther) const { return mHashIterator != aOther.mHashIterator; } Iterator& operator++() { mHashIterator++; return *this; } Entry operator*() const { auto& entry = *mHashIterator; return Entry(entry.GetKey(), &entry.GetData()); } private: AtomVariantMap::const_iterator mHashIterator; }; friend class Iterator; Iterator begin() const { return Iterator(mData.begin()); } Iterator end() const { return Iterator(mData.end()); } #ifdef A11Y_LOG static void DebugPrint(const char* aPrefix, const AccAttributes& aAttributes); #endif size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf); private: static void StringFromValueAndName(nsAtom* aAttrName, const AttrValueType& aValue, nsAString& aValueString); AtomVariantMap mData; friend struct IPC::ParamTraits; }; } // namespace a11y } // namespace mozilla #endif