/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 mozilla_AnimatedPropertyIDSet_h #define mozilla_AnimatedPropertyIDSet_h #include "mozilla/ServoBindings.h" #include "AnimatedPropertyID.h" #include "nsCSSPropertyIDSet.h" #include "nsTHashSet.h" namespace mozilla { class AnimatedPropertyIDSet { public: using CustomNameSet = nsTHashSet>; AnimatedPropertyIDSet() = default; AnimatedPropertyIDSet(AnimatedPropertyIDSet&& aOther) = default; AnimatedPropertyIDSet(nsCSSPropertyIDSet&& aIDs, CustomNameSet&& aNames) : mIDs(std::move(aIDs)), mCustomNames(std::move(aNames)) {} AnimatedPropertyIDSet& operator=(AnimatedPropertyIDSet&& aRhs) { MOZ_ASSERT(&aRhs != this); this->~AnimatedPropertyIDSet(); new (this) AnimatedPropertyIDSet(std::move(aRhs)); return *this; } void AddProperty(const AnimatedPropertyID& aProperty) { if (aProperty.IsCustom()) { mCustomNames.Insert(aProperty.mCustomName); } else { mIDs.AddProperty(aProperty.mID); } } void RemoveProperty(const AnimatedPropertyID& aProperty) { if (aProperty.IsCustom()) { mCustomNames.Remove(aProperty.mCustomName); } else { mIDs.RemoveProperty(aProperty.mID); } } bool HasProperty(const AnimatedPropertyID& aProperty) const { if (aProperty.IsCustom()) { return mCustomNames.Contains(aProperty.mCustomName); } return mIDs.HasProperty(aProperty.mID); } bool Intersects(const nsCSSPropertyIDSet& aIDs) const { return mIDs.Intersects(aIDs); } bool IsSubsetOf(const AnimatedPropertyIDSet& aOther) const { if (!mIDs.IsSubsetOf(aOther.mIDs) || mCustomNames.Count() > aOther.mCustomNames.Count()) { return false; } for (const auto& name : mCustomNames) { if (!aOther.mCustomNames.Contains(name)) { return false; } } return true; } bool IsEmpty() const { return mIDs.IsEmpty() && mCustomNames.IsEmpty(); } void AddProperties(const AnimatedPropertyIDSet& aOther) { mIDs |= aOther.mIDs; for (const auto& name : aOther.mCustomNames) { mCustomNames.Insert(name); } } // Returns a new nsCSSPropertyIDSet with all properties that are both in this // set and |aOther|. nsCSSPropertyIDSet Intersect(const nsCSSPropertyIDSet& aOther) const { return mIDs.Intersect(aOther); } // Returns a new AnimatedPropertyIDSet with all properties that are both in // this set and |aOther|. AnimatedPropertyIDSet Intersect(const AnimatedPropertyIDSet& aOther) const { nsCSSPropertyIDSet ids = mIDs.Intersect(aOther.mIDs); CustomNameSet names; for (const auto& name : mCustomNames) { if (!aOther.mCustomNames.Contains(name)) { continue; } names.Insert(name); } return AnimatedPropertyIDSet(std::move(ids), std::move(names)); } // Returns a new AnimatedPropertyIDSet with all properties that are in either // this set or |aOther| but not both. AnimatedPropertyIDSet Xor(const AnimatedPropertyIDSet& aOther) const { nsCSSPropertyIDSet ids = mIDs.Xor(aOther.mIDs); CustomNameSet names; for (const auto& name : mCustomNames) { if (aOther.mCustomNames.Contains(name)) { continue; } names.Insert(name); } for (const auto& name : aOther.mCustomNames) { if (mCustomNames.Contains(name)) { continue; } names.Insert(name); } return AnimatedPropertyIDSet(std::move(ids), std::move(names)); } // Iterator for use in range-based for loops class Iterator { public: Iterator(Iterator&& aOther) : mPropertySet(aOther.mPropertySet), mIDIterator(std::move(aOther.mIDIterator)), mCustomNameIterator(std::move(aOther.mCustomNameIterator)), mPropertyID(eCSSProperty_UNKNOWN) {} Iterator() = delete; Iterator(const Iterator&) = delete; Iterator& operator=(const Iterator&) = delete; Iterator& operator=(const Iterator&&) = delete; static Iterator BeginIterator(const AnimatedPropertyIDSet& aPropertySet) { return Iterator(aPropertySet, aPropertySet.mIDs.begin(), aPropertySet.mCustomNames.begin()); } static Iterator EndIterator(const AnimatedPropertyIDSet& aPropertySet) { return Iterator(aPropertySet, aPropertySet.mIDs.end(), aPropertySet.mCustomNames.end()); } bool operator!=(const Iterator& aOther) const { return mIDIterator != aOther.mIDIterator || mCustomNameIterator != aOther.mCustomNameIterator; } Iterator& operator++() { MOZ_ASSERT(mIDIterator != mPropertySet.mIDs.end() || mCustomNameIterator != mPropertySet.mCustomNames.end(), "Should not iterate beyond end"); if (mIDIterator != mPropertySet.mIDs.end()) { ++mIDIterator; } else { ++mCustomNameIterator; } return *this; } AnimatedPropertyID operator*() { if (mIDIterator != mPropertySet.mIDs.end()) { mPropertyID.mID = *mIDIterator; mPropertyID.mCustomName = nullptr; } else if (mCustomNameIterator != mPropertySet.mCustomNames.end()) { mPropertyID.mID = eCSSPropertyExtra_variable; mPropertyID.mCustomName = *mCustomNameIterator; } else { MOZ_ASSERT_UNREACHABLE("Should not dereference beyond end"); mPropertyID.mID = eCSSProperty_UNKNOWN; mPropertyID.mCustomName = nullptr; } return mPropertyID; } private: Iterator(const AnimatedPropertyIDSet& aPropertySet, nsCSSPropertyIDSet::Iterator aIDIterator, CustomNameSet::const_iterator aCustomNameIterator) : mPropertySet(aPropertySet), mIDIterator(std::move(aIDIterator)), mCustomNameIterator(std::move(aCustomNameIterator)), mPropertyID(eCSSProperty_UNKNOWN) {} const AnimatedPropertyIDSet& mPropertySet; nsCSSPropertyIDSet::Iterator mIDIterator; CustomNameSet::const_iterator mCustomNameIterator; AnimatedPropertyID mPropertyID; }; Iterator begin() const { return Iterator::BeginIterator(*this); } Iterator end() const { return Iterator::EndIterator(*this); } private: AnimatedPropertyIDSet(const AnimatedPropertyIDSet&) = delete; AnimatedPropertyIDSet& operator=(const AnimatedPropertyIDSet&) = delete; nsCSSPropertyIDSet mIDs; CustomNameSet mCustomNames; }; // A wrapper to support the inversion of AnimatedPropertyIDSet. // // We are using this struct (for convenience) to check if we should skip the // AnimatedPropertyIDs when composing an animation rule, on either // CascadeLevel::Animations or CascadeLevel::Tranistions. struct InvertibleAnimatedPropertyIDSet { const AnimatedPropertyIDSet* mSet = nullptr; bool mIsInverted = false; void Setup(const AnimatedPropertyIDSet* aSet, bool aIsInverted) { mSet = aSet; mIsInverted = aIsInverted; } bool HasProperty(const AnimatedPropertyID& aProperty) const { return mSet && mIsInverted != mSet->HasProperty(aProperty); } }; } // namespace mozilla #endif // mozilla_AnimatedPropertyIDSet_h