AccAttributes.h (12120B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef AccAttributes_h_ 7 #define AccAttributes_h_ 8 9 #include "mozilla/ServoStyleConsts.h" 10 #include "mozilla/a11y/AccGroupInfo.h" 11 #include "mozilla/Variant.h" 12 #include "nsTHashMap.h" 13 #include "nsStringFwd.h" 14 #include "mozilla/gfx/Matrix.h" 15 #include "mozilla/WritingModes.h" 16 17 class nsVariant; 18 19 namespace IPC { 20 template <typename T> 21 struct ParamTraits; 22 } // namespace IPC 23 24 namespace mozilla { 25 26 namespace dom { 27 class Element; 28 } 29 30 namespace a11y { 31 32 struct FontSize { 33 int32_t mValue; 34 35 bool operator==(const FontSize& aOther) const { 36 return mValue == aOther.mValue; 37 } 38 39 bool operator!=(const FontSize& aOther) const { 40 return mValue != aOther.mValue; 41 } 42 }; 43 44 struct Color { 45 nscolor mValue; 46 47 bool operator==(const Color& aOther) const { return mValue == aOther.mValue; } 48 49 bool operator!=(const Color& aOther) const { return mValue != aOther.mValue; } 50 }; 51 52 // A special type. If an entry has a value of this type, it instructs the 53 // target instance of an Update to remove the entry with the same key value. 54 struct DeleteEntry { 55 DeleteEntry() : mValue(true) {} 56 bool mValue; 57 58 bool operator==(const DeleteEntry& aOther) const { return true; } 59 60 bool operator!=(const DeleteEntry& aOther) const { return false; } 61 }; 62 63 /** 64 * An attribute that applies to an offset range in a text leaf. This allows it 65 * to span only part of a text leaf. This is used for spelling errors, 66 * highlights, etc. which are mapped to DOM selections. This is in contrast to 67 * most other attributes which can only apply to an entire text leaf and so just 68 * reside on the leaf itself, rather than requiring offsets. 69 */ 70 struct TextOffsetAttribute { 71 // An offset used to indicate that this attribute extends outside of this 72 // leaf. 73 static const int32_t kOutsideLeaf = -1; 74 // The offset in the text leaf where the attribute starts. If this is 75 // kOutsideLeaf, the attribute begins before this leaf, crossing Accessibles. 76 int32_t mStartOffset; 77 // The offset in the text leaf where the attribute ends (exclusive). If this 78 // is kOutsideLeaf, the attribute ends after this leaf, crossing Accessibles. 79 int32_t mEndOffset; 80 // The attribute: 81 // nsGkAtoms::grammar: Grammar error. 82 // nsGkAtoms::mark: Semantic highlight such as a text fragment. 83 // nsGkAtoms::spelling: Spelling error. 84 RefPtr<nsAtom> mAttribute; 85 86 bool operator==(const TextOffsetAttribute& aOther) const { 87 return mStartOffset == aOther.mStartOffset && 88 mEndOffset == aOther.mEndOffset && mAttribute == aOther.mAttribute; 89 } 90 91 bool operator!=(const TextOffsetAttribute& aOther) const { 92 return !(*this == aOther); 93 } 94 95 bool operator<(const TextOffsetAttribute& aOther) const { 96 return mStartOffset < aOther.mStartOffset; 97 } 98 }; 99 100 class AccAttributes { 101 // Warning! An AccAttributes can contain another AccAttributes. This is 102 // intended for object and text attributes. However, the nested 103 // AccAttributes should never itself contain another AccAttributes, nor 104 // should it create a cycle. We don't do cycle collection here for 105 // performance reasons, so violating this rule will cause leaks! 106 using AttrValueType = 107 Variant<bool, float, double, int32_t, RefPtr<nsAtom>, nsTArray<int32_t>, 108 CSSCoord, FontSize, Color, DeleteEntry, UniquePtr<nsString>, 109 RefPtr<AccAttributes>, uint64_t, UniquePtr<AccGroupInfo>, 110 UniquePtr<gfx::Matrix4x4>, UniquePtr<nsRect>, nsTArray<uint64_t>, 111 nsTArray<TextOffsetAttribute>, WritingMode, 112 nsTArray<RefPtr<nsAtom>>>; 113 static_assert(sizeof(AttrValueType) <= 16); 114 using AtomVariantMap = nsTHashMap<RefPtr<nsAtom>, AttrValueType>; 115 116 protected: 117 ~AccAttributes() = default; 118 119 public: 120 AccAttributes() = default; 121 AccAttributes(const AccAttributes&) = delete; 122 AccAttributes& operator=(const AccAttributes&) = delete; 123 124 NS_INLINE_DECL_REFCOUNTING(mozilla::a11y::AccAttributes) 125 126 template <typename T> 127 void SetAttribute(nsAtom* aAttrName, T&& aAttrValue) { 128 using ValType = 129 std::remove_const_t<std::remove_reference_t<decltype(aAttrValue)>>; 130 if constexpr (std::is_convertible_v<ValType, nsString>) { 131 static_assert(std::is_rvalue_reference_v<decltype(aAttrValue)>, 132 "Please only move strings into this function. To make a " 133 "copy, use SetAttributeStringCopy."); 134 UniquePtr<nsString> value = MakeUnique<nsString>(std::move(aAttrValue)); 135 mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); 136 } else if constexpr (std::is_same_v<ValType, gfx::Matrix4x4>) { 137 UniquePtr<gfx::Matrix4x4> value = MakeUnique<gfx::Matrix4x4>(aAttrValue); 138 mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); 139 } else if constexpr (std::is_same_v<ValType, nsRect>) { 140 UniquePtr<nsRect> value = MakeUnique<nsRect>(aAttrValue); 141 mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); 142 } else if constexpr (std::is_same_v<ValType, AccGroupInfo*>) { 143 UniquePtr<AccGroupInfo> value(aAttrValue); 144 mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value))); 145 } else if constexpr (std::is_convertible_v<ValType, nsAtom*>) { 146 mData.InsertOrUpdate(aAttrName, AsVariant(RefPtr<nsAtom>(aAttrValue))); 147 } else { 148 mData.InsertOrUpdate(aAttrName, AsVariant(std::forward<T>(aAttrValue))); 149 } 150 } 151 152 void SetAttributeStringCopy(nsAtom* aAttrName, nsString aAttrValue) { 153 SetAttribute(aAttrName, std::move(aAttrValue)); 154 } 155 156 template <typename T> 157 Maybe<const T&> GetAttribute(nsAtom* aAttrName) const { 158 if (auto value = mData.Lookup(aAttrName)) { 159 if constexpr (std::is_same_v<nsString, T>) { 160 if (value->is<UniquePtr<nsString>>()) { 161 const T& val = *(value->as<UniquePtr<nsString>>().get()); 162 return SomeRef(val); 163 } 164 } else if constexpr (std::is_same_v<gfx::Matrix4x4, T>) { 165 if (value->is<UniquePtr<gfx::Matrix4x4>>()) { 166 const T& val = *(value->as<UniquePtr<gfx::Matrix4x4>>()); 167 return SomeRef(val); 168 } 169 } else if constexpr (std::is_same_v<nsRect, T>) { 170 if (value->is<UniquePtr<nsRect>>()) { 171 const T& val = *(value->as<UniquePtr<nsRect>>()); 172 return SomeRef(val); 173 } 174 } else { 175 if (value->is<T>()) { 176 const T& val = value->as<T>(); 177 return SomeRef(val); 178 } 179 } 180 } 181 return Nothing(); 182 } 183 184 template <typename T> 185 RefPtr<const T> GetAttributeRefPtr(nsAtom* aAttrName) const { 186 if (auto value = mData.Lookup(aAttrName)) { 187 if (value->is<RefPtr<T>>()) { 188 RefPtr<const T> ref = value->as<RefPtr<T>>(); 189 return ref; 190 } 191 } 192 return nullptr; 193 } 194 195 template <typename T> 196 const T* GetAttributeWeakPtr(nsAtom* aAttrName) const { 197 if (auto value = mData.Lookup(aAttrName)) { 198 if (value->is<RefPtr<T>>()) { 199 const T* ref = value->as<RefPtr<T>>(); 200 return ref; 201 } 202 } 203 return nullptr; 204 } 205 206 template <typename T> 207 Maybe<T&> GetMutableAttribute(nsAtom* aAttrName) const { 208 static_assert(std::is_same_v<nsTArray<int32_t>, T> || 209 std::is_same_v<nsTArray<uint64_t>, T> || 210 std::is_same_v<nsTArray<RefPtr<nsAtom>>, T>, 211 "Only arrays should be mutable attributes"); 212 if (auto value = mData.Lookup(aAttrName)) { 213 if (value->is<T>()) { 214 T& val = value->as<T>(); 215 return SomeRef(val); 216 } 217 } 218 return Nothing(); 219 } 220 221 // Get stringified value 222 bool GetAttribute(nsAtom* aAttrName, nsAString& aAttrValue) const; 223 224 bool HasAttribute(nsAtom* aAttrName) const { 225 return mData.Contains(aAttrName); 226 } 227 228 bool Remove(nsAtom* aAttrName) { return mData.Remove(aAttrName); } 229 230 uint32_t Count() const { return mData.Count(); } 231 232 // Update one instance with the entries in another. The supplied AccAttributes 233 // will be emptied. 234 void Update(AccAttributes* aOther); 235 236 // Remove all entries that are identical to the supplied AccAttributes. 237 void RemoveIdentical(const AccAttributes* aOther); 238 239 /** 240 * Return true if all the attributes in this instance are equal to all the 241 * attributes in another instance. 242 */ 243 bool Equal(const AccAttributes* aOther) const; 244 245 /** 246 * Copy attributes from this instance to another instance. 247 * This should only be used in very specific cases; e.g. merging two sets of 248 * cached attributes without modifying the cache. It can only copy simple 249 * value types; e.g. it can't copy array values. Attempting to copy an 250 * AccAttributes with uncopyable values will cause an assertion. 251 * If aOnlyMissing is true, don't copy entries if destination already has 252 * a given key. 253 */ 254 void CopyTo(AccAttributes* aDest, bool aOnlyMissing = false) const; 255 256 // An entry class for our iterator. 257 class Entry { 258 public: 259 Entry(nsAtom* aAttrName, const AttrValueType* aAttrValue) 260 : mName(aAttrName), mValue(aAttrValue) {} 261 262 nsAtom* Name() const { return mName; } 263 264 template <typename T> 265 Maybe<const T&> Value() const { 266 if constexpr (std::is_same_v<nsString, T>) { 267 if (mValue->is<UniquePtr<nsString>>()) { 268 const T& val = *(mValue->as<UniquePtr<nsString>>().get()); 269 return SomeRef(val); 270 } 271 } else if constexpr (std::is_same_v<gfx::Matrix4x4, T>) { 272 if (mValue->is<UniquePtr<gfx::Matrix4x4>>()) { 273 const T& val = *(mValue->as<UniquePtr<gfx::Matrix4x4>>()); 274 return SomeRef(val); 275 } 276 } else if constexpr (std::is_same_v<nsRect, T>) { 277 if (mValue->is<UniquePtr<nsRect>>()) { 278 const T& val = *(mValue->as<UniquePtr<nsRect>>()); 279 return SomeRef(val); 280 } 281 } else { 282 if (mValue->is<T>()) { 283 const T& val = mValue->as<T>(); 284 return SomeRef(val); 285 } 286 } 287 return Nothing(); 288 } 289 290 void NameAsString(nsString& aName) const { 291 mName->ToString(aName); 292 if (StringBeginsWith(aName, u"aria-"_ns)) { 293 // Found 'aria-' 294 aName.ReplaceLiteral(0, 5, u""); 295 } 296 } 297 298 void ValueAsString(nsAString& aValueString) const { 299 StringFromValueAndName(mName, *mValue, aValueString); 300 } 301 302 // Size of the pair in the hash table. 303 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf); 304 305 private: 306 nsAtom* mName; 307 const AttrValueType* mValue; 308 309 friend class AccAttributes; 310 }; 311 312 class Iterator { 313 public: 314 explicit Iterator(AtomVariantMap::const_iterator aIter) 315 : mHashIterator(aIter) {} 316 317 Iterator() = delete; 318 Iterator(const Iterator&) = delete; 319 Iterator& operator=(const Iterator&) = delete; 320 321 bool operator!=(const Iterator& aOther) const { 322 return mHashIterator != aOther.mHashIterator; 323 } 324 325 Iterator& operator++() { 326 mHashIterator++; 327 return *this; 328 } 329 330 Entry operator*() const { 331 auto& entry = *mHashIterator; 332 return Entry(entry.GetKey(), &entry.GetData()); 333 } 334 335 private: 336 AtomVariantMap::const_iterator mHashIterator; 337 }; 338 339 friend class Iterator; 340 341 Iterator begin() const { return Iterator(mData.begin()); } 342 Iterator end() const { return Iterator(mData.end()); } 343 344 #ifdef A11Y_LOG 345 static void DebugPrint(const char* aPrefix, const AccAttributes& aAttributes); 346 #endif 347 348 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf); 349 350 private: 351 static void StringFromValueAndName(nsAtom* aAttrName, 352 const AttrValueType& aValue, 353 nsAString& aValueString); 354 355 // Opts AccAttributes into the common ToString function. 356 friend std::ostream& operator<<(std::ostream& aStream, 357 const AccAttributes& aAttributes); 358 359 AtomVariantMap mData; 360 361 friend struct IPC::ParamTraits<AccAttributes*>; 362 }; 363 364 } // namespace a11y 365 } // namespace mozilla 366 367 #endif