Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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