Index: Source/core/dom/Element.cpp |
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp |
index 9b72286ae6c846cfcce1055b957dd715018fe121..f635b5d48fe2260f689530a8f06435e86abaa3c7 100644 |
--- a/Source/core/dom/Element.cpp |
+++ b/Source/core/dom/Element.cpp |
@@ -112,7 +112,9 @@ |
#include "core/page/Page.h" |
#include "core/page/PointerLockController.h" |
#include "core/page/SpatialNavigation.h" |
+#include "core/page/scrolling/ScrollCustomizationCallbacks.h" |
#include "core/page/scrolling/ScrollState.h" |
+#include "core/page/scrolling/ScrollStateCallback.h" |
#include "core/paint/DeprecatedPaintLayer.h" |
#include "core/svg/SVGDocumentExtensions.h" |
#include "core/svg/SVGElement.h" |
@@ -128,6 +130,25 @@ |
namespace blink { |
+namespace { |
+ |
+// We need to retain the scroll customization callbacks until the element |
+// they're associated with is destroyed. It would be simplest if the callbacks |
+// could be stored in ElementRareData, but we can't afford the space |
+// increase. Instead, keep the scroll customization callbacks here. The other |
+// option would be to store these callbacks on the FrameHost or document, but |
+// that necessitates a bunch more logic for transferring the callbacks between |
+// FrameHosts when elements are moved around. |
+ScrollCustomizationCallbacks& scrollCustomizationCallbacks() |
+{ |
+ ASSERT(RuntimeEnabledFeatures::scrollCustomizationEnabled()); |
+ DEFINE_STATIC_LOCAL(Persistent<ScrollCustomizationCallbacks>, |
+ scrollCustomizationCallbacks, (new ScrollCustomizationCallbacks())); |
+ return *scrollCustomizationCallbacks; |
+} |
+ |
+} // namespace |
+ |
using namespace HTMLNames; |
using namespace XMLNames; |
@@ -155,6 +176,9 @@ Element::~Element() |
if (isCustomElement()) |
CustomElement::wasDestroyed(this); |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) |
+ scrollCustomizationCallbacks().removeCallbacksForElement(this); |
+ |
// With Oilpan, either the Element has been removed from the Document |
// or the Document is dead as well. If the Element has been removed from |
// the Document the element has already been removed from the pending |
@@ -470,7 +494,19 @@ void Element::scrollIntoViewIfNeeded(bool centerIfNeeded) |
layoutObject()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); |
} |
-void Element::distributeScroll(ScrollState& scrollState) |
+void Element::setDistributeScroll(ScrollStateCallback* scrollStateCallback, String nativeScrollBehavior) |
+{ |
+ scrollStateCallback->setNativeScrollBehavior(ScrollStateCallback::toNativeScrollBehavior(nativeScrollBehavior)); |
+ scrollCustomizationCallbacks().setDistributeScroll(this, scrollStateCallback); |
+} |
+ |
+void Element::setApplyScroll(ScrollStateCallback* scrollStateCallback, String nativeScrollBehavior) |
+{ |
+ scrollStateCallback->setNativeScrollBehavior(ScrollStateCallback::toNativeScrollBehavior(nativeScrollBehavior)); |
+ scrollCustomizationCallbacks().setApplyScroll(this, scrollStateCallback); |
+} |
+ |
+void Element::nativeDistributeScroll(ScrollState& scrollState) |
{ |
ASSERT(RuntimeEnabledFeatures::scrollCustomizationEnabled()); |
if (scrollState.fullyConsumed()) |
@@ -490,13 +526,27 @@ void Element::distributeScroll(ScrollState& scrollState) |
const double deltaX = scrollState.deltaX(); |
const double deltaY = scrollState.deltaY(); |
- applyScroll(scrollState); |
+ callApplyScroll(scrollState); |
if (deltaX != scrollState.deltaX() || deltaY != scrollState.deltaY()) |
scrollState.setCurrentNativeScrollingElement(this); |
} |
-void Element::applyScroll(ScrollState& scrollState) |
+void Element::callDistributeScroll(ScrollState& scrollState) |
+{ |
+ ScrollStateCallback* callback = scrollCustomizationCallbacks().getDistributeScroll(this); |
+ if (!callback) { |
+ nativeDistributeScroll(scrollState); |
+ } else { |
+ if (callback->nativeScrollBehavior() == NativeScrollBehavior::PerformAfterNativeScroll) |
+ nativeDistributeScroll(scrollState); |
+ callback->handleEvent(&scrollState); |
+ if (callback->nativeScrollBehavior() == NativeScrollBehavior::PerformBeforeNativeScroll) |
+ nativeDistributeScroll(scrollState); |
+ } |
+}; |
+ |
+void Element::nativeApplyScroll(ScrollState& scrollState) |
{ |
ASSERT(RuntimeEnabledFeatures::scrollCustomizationEnabled()); |
if (scrollState.fullyConsumed()) |
@@ -506,8 +556,11 @@ void Element::applyScroll(ScrollState& scrollState) |
const double deltaY = scrollState.deltaY(); |
bool scrolled = false; |
- // Handle the documentElement separately, as it scrolls the FrameView. |
- if (this == document().documentElement()) { |
+ if (deltaY || deltaX) |
+ document().updateLayoutIgnorePendingStylesheets(); |
+ |
+ // Handle the scrollingElement separately, as it scrolls the viewport. |
+ if (this == document().scrollingElement()) { |
FloatSize delta(deltaX, deltaY); |
if (document().frame()->applyScrollDelta(delta, scrollState.isBeginning()).didScroll()) { |
scrolled = true; |
@@ -542,6 +595,20 @@ void Element::applyScroll(ScrollState& scrollState) |
document().frame()->view()->setWasScrolledByUser(true); |
}; |
+void Element::callApplyScroll(ScrollState& scrollState) |
+{ |
+ ScrollStateCallback* callback = scrollCustomizationCallbacks().getApplyScroll(this); |
+ if (!callback) { |
+ nativeApplyScroll(scrollState); |
+ } else { |
+ if (callback->nativeScrollBehavior() == NativeScrollBehavior::PerformAfterNativeScroll) |
+ nativeApplyScroll(scrollState); |
+ callback->handleEvent(&scrollState); |
+ if (callback->nativeScrollBehavior() == NativeScrollBehavior::PerformBeforeNativeScroll) |
+ nativeApplyScroll(scrollState); |
+ } |
+}; |
+ |
static float localZoomForLayoutObject(LayoutObject& layoutObject) |
{ |
// FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each |