Refactor filter list checking code
https://bugs.webkit.org/show_bug.cgi?id=185087

Reviewed by Alan Bujtas.

Deduplicate code between filter and backdrop-filter for checking whether function lists
match, by making a shared function that takes a std::function.

The call sites have to declare the return type (-> const FilterOperations&) to avoid std::function
converting the return type into a value.

* animation/KeyframeEffectReadOnly.cpp:
(WebCore::KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists const):
(WebCore::KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists):
(WebCore::KeyframeEffectReadOnly::checkForMatchingBackdropFilterFunctionLists):
* animation/KeyframeEffectReadOnly.h:
* page/animation/KeyframeAnimation.cpp:
(WebCore::KeyframeAnimation::checkForMatchingFilterFunctionLists const):
(WebCore::KeyframeAnimation::checkForMatchingFilterFunctionLists):
(WebCore::KeyframeAnimation::checkForMatchingBackdropFilterFunctionLists):
* page/animation/KeyframeAnimation.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231112 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 4e69617..faf30ce 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,27 @@
+2018-04-27  Simon Fraser  <simon.fraser@apple.com>
+
+        Refactor filter list checking code
+        https://bugs.webkit.org/show_bug.cgi?id=185087
+
+        Reviewed by Alan Bujtas.
+
+        Deduplicate code between filter and backdrop-filter for checking whether function lists
+        match, by making a shared function that takes a std::function.
+        
+        The call sites have to declare the return type (-> const FilterOperations&) to avoid std::function
+        converting the return type into a value.
+
+        * animation/KeyframeEffectReadOnly.cpp:
+        (WebCore::KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists const):
+        (WebCore::KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists):
+        (WebCore::KeyframeEffectReadOnly::checkForMatchingBackdropFilterFunctionLists):
+        * animation/KeyframeEffectReadOnly.h:
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::checkForMatchingFilterFunctionLists const):
+        (WebCore::KeyframeAnimation::checkForMatchingFilterFunctionLists):
+        (WebCore::KeyframeAnimation::checkForMatchingBackdropFilterFunctionLists):
+        * page/animation/KeyframeAnimation.h:
+
 2018-04-27  Chris Dumez  <cdumez@apple.com>
 
         Regression(r222392?): Events can have a negative timestamp which causes app breakage
diff --git a/Source/WebCore/animation/KeyframeEffectReadOnly.cpp b/Source/WebCore/animation/KeyframeEffectReadOnly.cpp
index 843bab6..efad647 100644
--- a/Source/WebCore/animation/KeyframeEffectReadOnly.cpp
+++ b/Source/WebCore/animation/KeyframeEffectReadOnly.cpp
@@ -764,77 +764,53 @@
     m_transformFunctionListsMatch = true;
 }
 
-void KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists()
+bool KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists(CSSPropertyID propertyID, const std::function<const FilterOperations& (const RenderStyle&)>& filtersGetter) const
 {
-    m_filterFunctionListsMatch = false;
-
-    if (m_blendingKeyframes.size() < 2 || !m_blendingKeyframes.containsProperty(CSSPropertyFilter))
-        return;
+    if (m_blendingKeyframes.size() < 2 || !m_blendingKeyframes.containsProperty(propertyID))
+        return false;
 
     // Empty filters match anything, so find the first non-empty entry as the reference.
     size_t numKeyframes = m_blendingKeyframes.size();
-    size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
+    size_t firstNonEmptyKeyframeIndex = numKeyframes;
 
     for (size_t i = 0; i < numKeyframes; ++i) {
-        if (m_blendingKeyframes[i].style()->filter().operations().size()) {
-            firstNonEmptyFilterKeyframeIndex = i;
+        if (filtersGetter(*m_blendingKeyframes[i].style()).operations().size()) {
+            firstNonEmptyKeyframeIndex = i;
             break;
         }
     }
 
-    if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
-        return;
+    if (firstNonEmptyKeyframeIndex == numKeyframes)
+        return false;
 
-    auto& firstVal = m_blendingKeyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
-    for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
-        auto& value = m_blendingKeyframes[i].style()->filter();
+    auto& firstVal = filtersGetter(*m_blendingKeyframes[firstNonEmptyKeyframeIndex].style());
+    for (size_t i = firstNonEmptyKeyframeIndex + 1; i < numKeyframes; ++i) {
+        auto& value = filtersGetter(*m_blendingKeyframes[i].style());
 
         // An empty filter list matches anything.
         if (value.operations().isEmpty())
             continue;
 
         if (!firstVal.operationsMatch(value))
-            return;
+            return false;
     }
 
-    m_filterFunctionListsMatch = true;
+    return true;
+}
+
+void KeyframeEffectReadOnly::checkForMatchingFilterFunctionLists()
+{
+    m_filterFunctionListsMatch = checkForMatchingFilterFunctionLists(CSSPropertyFilter, [] (const RenderStyle& style) -> const FilterOperations& {
+        return style.filter();
+    });
 }
 
 #if ENABLE(FILTERS_LEVEL_2)
 void KeyframeEffectReadOnly::checkForMatchingBackdropFilterFunctionLists()
 {
-    m_backdropFilterFunctionListsMatch = false;
-
-    if (m_blendingKeyframes.size() < 2 || !m_blendingKeyframes.containsProperty(CSSPropertyWebkitBackdropFilter))
-        return;
-
-    // Empty filters match anything, so find the first non-empty entry as the reference.
-    size_t numKeyframes = m_blendingKeyframes.size();
-    size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
-
-    for (size_t i = 0; i < numKeyframes; ++i) {
-        if (m_blendingKeyframes[i].style()->backdropFilter().operations().size()) {
-            firstNonEmptyFilterKeyframeIndex = i;
-            break;
-        }
-    }
-
-    if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
-        return;
-
-    auto& firstVal = m_blendingKeyframes[firstNonEmptyFilterKeyframeIndex].style()->backdropFilter();
-    for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
-        auto& value = m_blendingKeyframes[i].style()->backdropFilter();
-
-        // An empty filter list matches anything.
-        if (value.operations().isEmpty())
-            continue;
-
-        if (!firstVal.operationsMatch(value))
-            return;
-    }
-
-    m_backdropFilterFunctionListsMatch = true;
+    m_backdropFilterFunctionListsMatch = checkForMatchingFilterFunctionLists(CSSPropertyWebkitBackdropFilter, [] (const RenderStyle& style) -> const FilterOperations& {
+        return style.backdropFilter();
+    });
 }
 #endif
 
diff --git a/Source/WebCore/animation/KeyframeEffectReadOnly.h b/Source/WebCore/animation/KeyframeEffectReadOnly.h
index ce44040..59d2229 100644
--- a/Source/WebCore/animation/KeyframeEffectReadOnly.h
+++ b/Source/WebCore/animation/KeyframeEffectReadOnly.h
@@ -150,6 +150,8 @@
     void checkForMatchingBackdropFilterFunctionLists();
 #endif
 
+    bool checkForMatchingFilterFunctionLists(CSSPropertyID, const std::function<const FilterOperations& (const RenderStyle&)>&) const;
+
     bool m_shouldRunAccelerated { false };
     bool m_needsForcedLayout { false };
     bool m_triggersStackingContext { false };
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.cpp b/Source/WebCore/page/animation/KeyframeAnimation.cpp
index 091c91c..564f489 100644
--- a/Source/WebCore/page/animation/KeyframeAnimation.cpp
+++ b/Source/WebCore/page/animation/KeyframeAnimation.cpp
@@ -442,79 +442,54 @@
     m_transformFunctionListsMatch = true;
 }
 
-void KeyframeAnimation::checkForMatchingFilterFunctionLists()
+bool KeyframeAnimation::checkForMatchingFilterFunctionLists(CSSPropertyID propertyID, const std::function<const FilterOperations& (const RenderStyle&)>& filtersGetter) const
 {
-    m_filterFunctionListsMatch = false;
-
-    if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyFilter))
-        return;
+    if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(propertyID))
+        return false;
 
     // Empty filters match anything, so find the first non-empty entry as the reference
     size_t numKeyframes = m_keyframes.size();
-    size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
+    size_t firstNonEmptyKeyframeIndex = numKeyframes;
 
     for (size_t i = 0; i < numKeyframes; ++i) {
-        if (m_keyframes[i].style()->filter().operations().size()) {
-            firstNonEmptyFilterKeyframeIndex = i;
+        if (filtersGetter(*m_keyframes[i].style()).operations().size()) {
+            firstNonEmptyKeyframeIndex = i;
             break;
         }
     }
     
-    if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
-        return;
+    if (firstNonEmptyKeyframeIndex == numKeyframes)
+        return false;
 
-    auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
+    auto& firstVal = filtersGetter(*m_keyframes[firstNonEmptyKeyframeIndex].style());
     
-    for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
-        auto& value = m_keyframes[i].style()->filter();
+    for (size_t i = firstNonEmptyKeyframeIndex + 1; i < numKeyframes; ++i) {
+        auto& value = filtersGetter(*m_keyframes[i].style());
 
         // An emtpy filter list matches anything.
         if (value.operations().isEmpty())
             continue;
 
         if (!firstVal.operationsMatch(value))
-            return;
+            return false;
     }
 
-    m_filterFunctionListsMatch = true;
+    return true;
+}
+
+void KeyframeAnimation::checkForMatchingFilterFunctionLists()
+{
+    m_filterFunctionListsMatch = checkForMatchingFilterFunctionLists(CSSPropertyFilter, [] (const RenderStyle& style) -> const FilterOperations& {
+        return style.filter();
+    });
 }
 
 #if ENABLE(FILTERS_LEVEL_2)
 void KeyframeAnimation::checkForMatchingBackdropFilterFunctionLists()
 {
-    m_backdropFilterFunctionListsMatch = false;
-
-    if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitBackdropFilter))
-        return;
-
-    // Empty filters match anything, so find the first non-empty entry as the reference
-    size_t numKeyframes = m_keyframes.size();
-    size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
-
-    for (size_t i = 0; i < numKeyframes; ++i) {
-        if (m_keyframes[i].style()->backdropFilter().operations().size()) {
-            firstNonEmptyFilterKeyframeIndex = i;
-            break;
-        }
-    }
-
-    if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
-        return;
-
-    auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->backdropFilter();
-
-    for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
-        auto& value = m_keyframes[i].style()->backdropFilter();
-
-        // An emtpy filter list matches anything.
-        if (value.operations().isEmpty())
-            continue;
-
-        if (!firstVal.operationsMatch(value))
-            return;
-    }
-
-    m_backdropFilterFunctionListsMatch = true;
+    m_backdropFilterFunctionListsMatch = checkForMatchingFilterFunctionLists(CSSPropertyWebkitBackdropFilter, [] (const RenderStyle& style) -> const FilterOperations& {
+        return style.backdropFilter();
+    });
 }
 #endif
 
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.h b/Source/WebCore/page/animation/KeyframeAnimation.h
index cb54f7f..208aa6f 100644
--- a/Source/WebCore/page/animation/KeyframeAnimation.h
+++ b/Source/WebCore/page/animation/KeyframeAnimation.h
@@ -91,6 +91,7 @@
 #if ENABLE(FILTERS_LEVEL_2)
     void checkForMatchingBackdropFilterFunctionLists();
 #endif
+    bool checkForMatchingFilterFunctionLists(CSSPropertyID, const std::function<const FilterOperations& (const RenderStyle&)>&) const;
 
 private:
     KeyframeAnimation(const Animation&, Element&, CompositeAnimation&, const RenderStyle& unanimatedStyle);