226 lines
7.2 KiB
C++
226 lines
7.2 KiB
C++
/* -*- 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<RefPtr<nsAtom>>;
|
|
|
|
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
|