WebAnimationUtilities.cpp [plain text]
#include "config.h"
#include "WebAnimationUtilities.h"
#include "Animation.h"
#include "AnimationList.h"
#include "CSSAnimation.h"
#include "CSSTransition.h"
#include "DeclarativeAnimation.h"
#include "Element.h"
#include "KeyframeEffectStack.h"
#include "PseudoElement.h"
#include "WebAnimation.h"
namespace WebCore {
static bool compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(const Styleable& a, const Styleable& b)
{
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(a != b);
enum SortingIndex : uint8_t { NotPseudo, Marker, Before, FirstLetter, FirstLine, Highlight, Scrollbar, Selection, After, Other };
auto sortingIndex = [](PseudoId pseudoId) -> SortingIndex {
switch (pseudoId) {
case PseudoId::None:
return NotPseudo;
case PseudoId::Marker:
return Marker;
case PseudoId::Before:
return Before;
case PseudoId::FirstLetter:
return FirstLetter;
case PseudoId::FirstLine:
return FirstLine;
case PseudoId::Highlight:
return Highlight;
case PseudoId::Scrollbar:
return Scrollbar;
case PseudoId::Selection:
return Selection;
case PseudoId::After:
return After;
default:
ASSERT_NOT_REACHED();
return Other;
}
};
auto& aReferenceElement = a.element;
int aSortingIndex = sortingIndex(a.pseudoId);
auto& bReferenceElement = b.element;
int bSortingIndex = sortingIndex(b.pseudoId);
if (&aReferenceElement == &bReferenceElement) {
ASSERT(aSortingIndex != bSortingIndex);
return aSortingIndex < bSortingIndex;
}
return aReferenceElement.compareDocumentPosition(bReferenceElement) & Node::DOCUMENT_POSITION_FOLLOWING;
}
static bool compareCSSTransitions(const CSSTransition& a, const CSSTransition& b)
{
ASSERT(a.owningElement());
ASSERT(b.owningElement());
auto& aOwningElement = a.owningElement();
auto& bOwningElement = b.owningElement();
if (*aOwningElement != *bOwningElement)
return compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(*aOwningElement, *bOwningElement);
if (a.generationTime() != b.generationTime())
return a.generationTime() < b.generationTime();
return a.transitionProperty().utf8() < b.transitionProperty().utf8();
}
static bool compareCSSAnimations(const CSSAnimation& a, const CSSAnimation& b)
{
ASSERT(a.owningElement());
ASSERT(b.owningElement());
auto& aOwningElement = a.owningElement();
auto& bOwningElement = b.owningElement();
if (*aOwningElement != *bOwningElement)
return compareDeclarativeAnimationOwningElementPositionsInDocumentTreeOrder(*aOwningElement, *bOwningElement);
auto* cssAnimationList = aOwningElement->ensureKeyframeEffectStack().cssAnimationList();
ASSERT(cssAnimationList);
ASSERT(!cssAnimationList->isEmpty());
auto& aBackingAnimation = a.backingAnimation();
auto& bBackingAnimation = b.backingAnimation();
for (size_t i = 0; i < cssAnimationList->size(); ++i) {
auto& animation = cssAnimationList->animation(i);
if (animation == aBackingAnimation)
return true;
if (animation == bBackingAnimation)
return false;
}
RELEASE_ASSERT_NOT_REACHED();
}
bool compareAnimationsByCompositeOrder(const WebAnimation& a, const WebAnimation& b)
{
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(&a != &b);
bool aHasOwningElement = is<DeclarativeAnimation>(a) && downcast<DeclarativeAnimation>(a).owningElement();
bool bHasOwningElement = is<DeclarativeAnimation>(b) && downcast<DeclarativeAnimation>(b).owningElement();
bool aIsCSSTransition = aHasOwningElement && is<CSSTransition>(a);
bool bIsCSSTransition = bHasOwningElement && is<CSSTransition>(b);
if (aIsCSSTransition || bIsCSSTransition) {
if (aIsCSSTransition == bIsCSSTransition)
return compareCSSTransitions(downcast<CSSTransition>(a), downcast<CSSTransition>(b));
return !bIsCSSTransition;
}
bool aIsCSSAnimation = aHasOwningElement && is<CSSAnimation>(a);
bool bIsCSSAnimation = bHasOwningElement && is<CSSAnimation>(b);
if (aIsCSSAnimation || bIsCSSAnimation) {
if (aIsCSSAnimation == bIsCSSAnimation)
return compareCSSAnimations(downcast<CSSAnimation>(a), downcast<CSSAnimation>(b));
return !bIsCSSAnimation;
}
RELEASE_ASSERT(a.globalPosition() != b.globalPosition());
return a.globalPosition() < b.globalPosition();
}
String pseudoIdAsString(PseudoId pseudoId)
{
static NeverDestroyed<const String> after(MAKE_STATIC_STRING_IMPL("::after"));
static NeverDestroyed<const String> before(MAKE_STATIC_STRING_IMPL("::before"));
static NeverDestroyed<const String> firstLetter(MAKE_STATIC_STRING_IMPL("::first-letter"));
static NeverDestroyed<const String> firstLine(MAKE_STATIC_STRING_IMPL("::first-line"));
static NeverDestroyed<const String> highlight(MAKE_STATIC_STRING_IMPL("::highlight"));
static NeverDestroyed<const String> marker(MAKE_STATIC_STRING_IMPL("::marker"));
static NeverDestroyed<const String> selection(MAKE_STATIC_STRING_IMPL("::selection"));
static NeverDestroyed<const String> scrollbar(MAKE_STATIC_STRING_IMPL("::scrollbar"));
switch (pseudoId) {
case PseudoId::After:
return after;
case PseudoId::Before:
return before;
case PseudoId::FirstLetter:
return firstLetter;
case PseudoId::FirstLine:
return firstLine;
case PseudoId::Highlight:
return highlight;
case PseudoId::Marker:
return marker;
case PseudoId::Selection:
return selection;
case PseudoId::Scrollbar:
return scrollbar;
default:
return emptyString();
}
}
}