Index: Source/core/dom/Element.cpp |
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp |
index 11fd64410aed458f4724644c0aa80bf11ce89a07..3e566abf16ce2457f0f45f2980a0d8e2cbe0a6b2 100644 |
--- a/Source/core/dom/Element.cpp |
+++ b/Source/core/dom/Element.cpp |
@@ -113,7 +113,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" |
@@ -129,6 +131,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; |
@@ -156,6 +177,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 |
@@ -471,7 +495,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()) |
@@ -491,13 +527,29 @@ 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); |
+ return; |
+ } |
+ |
+ if (callback->nativeScrollBehavior() != NativeScrollBehavior::PerformAfterNativeScroll) |
+ callback->handleEvent(&scrollState); |
+ if (callback->nativeScrollBehavior() != NativeScrollBehavior::DisableNativeScroll) |
+ nativeDistributeScroll(scrollState); |
+ if (callback->nativeScrollBehavior() == NativeScrollBehavior::PerformAfterNativeScroll) |
+ callback->handleEvent(&scrollState); |
+}; |
+ |
+void Element::nativeApplyScroll(ScrollState& scrollState) |
{ |
ASSERT(RuntimeEnabledFeatures::scrollCustomizationEnabled()); |
if (scrollState.fullyConsumed()) |
@@ -507,8 +559,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; |
@@ -545,6 +600,22 @@ void Element::applyScroll(ScrollState& scrollState) |
} |
}; |
+void Element::callApplyScroll(ScrollState& scrollState) |
+{ |
+ ScrollStateCallback* callback = scrollCustomizationCallbacks().getApplyScroll(this); |
+ if (!callback) { |
+ nativeApplyScroll(scrollState); |
+ return; |
+ } |
+ |
+ if (callback->nativeScrollBehavior() != NativeScrollBehavior::PerformAfterNativeScroll) |
+ callback->handleEvent(&scrollState); |
+ if (callback->nativeScrollBehavior() != NativeScrollBehavior::DisableNativeScroll) |
+ nativeApplyScroll(scrollState); |
+ if (callback->nativeScrollBehavior() == NativeScrollBehavior::PerformAfterNativeScroll) |
+ callback->handleEvent(&scrollState); |
+}; |
+ |
static float localZoomForLayoutObject(LayoutObject& layoutObject) |
{ |
// FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each |