https://bugs.webkit.org/show_bug.cgi?id=164002
<rdar://problem/
29040471>
Reviewed by Simon Fraser.
Source/WebCore:
The bug was caused by HitTestResult::innerElement returning the parent element of a Text node without
taking the shadow root or slots into account. For hit testing, we always want to use the "flat tree"
or "composed tree" (imprecisely but close enough in this case).
Fixed the bug by making HitTestResult::innerElement use parentNodeInComposedTree. Also renamed it to
HitTestResult::targetElement to be consistent with HitTestResult::targetNode.
Tests: fast/shadow-dom/activate-over-slotted-content.html
fast/shadow-dom/hover-over-slotted-content.html
* dom/Document.cpp:
(WebCore::Document::prepareMouseEvent):
* html/MediaElementSession.cpp:
(WebCore::isMainContentForPurposesOfAutoplay):
* page/EventHandler.cpp:
(WebCore::EventHandler::eventMayStartDrag):
(WebCore::EventHandler::hitTestResultAtPoint):
(WebCore::EventHandler::handleWheelEvent):
(WebCore::EventHandler::sendContextMenuEventForKey):
(WebCore::EventHandler::hoverTimerFired):
(WebCore::EventHandler::handleDrag):
(WebCore::EventHandler::handleTouchEvent):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::targetElement): Renamed from innerElement.
Now finds the parent element in the composed tree.
* rendering/HitTestResult.h:
(WebCore::HitTestResult::innerNode):
Source/WebKit/mac:
* WebView/WebImmediateActionController.mm:
(-[WebImmediateActionController performHitTestAtPoint:]):
Source/WebKit2:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::determinePrimarySnapshottedPlugIn):
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::performImmediateActionHitTestAtLocation):
LayoutTests:
Added two reference tests for activating and hovering over a Text node.
The text node should activate :hover and :activate rules in the shadow tree respectively.
* fast/shadow-dom/activate-over-slotted-content-expected.html: Added.
* fast/shadow-dom/activate-over-slotted-content.html: Added.
* fast/shadow-dom/hover-over-slotted-content-expected.html: Added.
* fast/shadow-dom/hover-over-slotted-content.html: Added.
* platform/ios-simulator/TestExpectations: Skip the newly added tests since iOS doesn't
support :hover or :activate via mouse down.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208630
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2016-11-11 Ryosuke Niwa <rniwa@webkit.org>
+
+ Hovering over a slotted Text node clears hover state
+ https://bugs.webkit.org/show_bug.cgi?id=164002
+ <rdar://problem/29040471>
+
+ Reviewed by Simon Fraser.
+
+ Added two reference tests for activating and hovering over a Text node.
+ The text node should activate :hover and :activate rules in the shadow tree respectively.
+
+ * fast/shadow-dom/activate-over-slotted-content-expected.html: Added.
+ * fast/shadow-dom/activate-over-slotted-content.html: Added.
+ * fast/shadow-dom/hover-over-slotted-content-expected.html: Added.
+ * fast/shadow-dom/hover-over-slotted-content.html: Added.
+ * platform/ios-simulator/TestExpectations: Skip the newly added tests since iOS doesn't
+ support :hover or :activate via mouse down.
+
2016-11-11 Brent Fulgham <bfulgham@apple.com>
Neutered ArrayBuffers are not properly serialized
--- /dev/null
+<!DOCTYPE html>
+<html>
+<body>
+ <p>Test passes if you see a single 100px by 100px green box below.</p>
+ <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+my-host {
+ display: block;
+ width: 100px;
+ height: 100px;
+ background: purple;
+}
+</style>
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<my-host>Mouse down over this text</my-host>
+
+<script>
+const host = document.querySelector('my-host');
+host.attachShadow({mode: 'closed'}).innerHTML = `
+<a><span><slot></slot></span></a>
+<style>
+a {
+ display: block;
+ width: 80px;
+ height: 80px;
+ padding: 10px;
+ background: red;
+}
+a:active {
+ background: green;
+ color: green;
+}
+span {
+ background: green;
+}
+</style>`;
+
+if (window.eventSender) {
+ eventSender.mouseMoveTo(host.offsetLeft + 15, host.offsetTop + 15);
+ eventSender.mouseDown();
+}
+
+</script>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<body>
+ <p>Test passes if you see a single 100px by 100px green box below.</p>
+ <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+my-host {
+ display: block;
+ width: 100px;
+ height: 100px;
+ background: purple;
+}
+</style>
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<my-host>Hover over this text</my-host>
+
+<script>
+const host = document.querySelector('my-host');
+host.attachShadow({mode: 'closed'}).innerHTML = `
+<div id="container"><span><slot></slot></span></div>
+<style>
+#container {
+ width: 80px;
+ height: 80px;
+ padding: 10px;
+ background: red;
+}
+#container:hover {
+ background: green;
+ color: green;
+}
+span {
+ background: green;
+}
+</style>`;
+
+if (window.eventSender)
+ eventSender.mouseMoveTo(host.offsetLeft + 15, host.offsetTop + 15);
+
+</script>
+</body>
+</html>
webkit.org/b/155233 fast/events/max-tabindex-focus.html [ Skip ]
fast/shadow-dom/shadow-host-removal-crash.html [ Skip ]
fast/shadow-dom/input-element-in-shadow.html [ Skip ]
+fast/shadow-dom/activate-over-slotted-content.html [ Skip ]
+fast/shadow-dom/hover-over-slotted-content.html [ Skip ]
fast/events/keyboardevent-key.html [ Skip ]
fast/events/keyboardevent-code.html [ Skip ]
+2016-11-11 Ryosuke Niwa <rniwa@webkit.org>
+
+ Hovering over a slotted Text node clears hover state
+ https://bugs.webkit.org/show_bug.cgi?id=164002
+ <rdar://problem/29040471>
+
+ Reviewed by Simon Fraser.
+
+ The bug was caused by HitTestResult::innerElement returning the parent element of a Text node without
+ taking the shadow root or slots into account. For hit testing, we always want to use the "flat tree"
+ or "composed tree" (imprecisely but close enough in this case).
+
+ Fixed the bug by making HitTestResult::innerElement use parentNodeInComposedTree. Also renamed it to
+ HitTestResult::targetElement to be consistent with HitTestResult::targetNode.
+
+ Tests: fast/shadow-dom/activate-over-slotted-content.html
+ fast/shadow-dom/hover-over-slotted-content.html
+
+ * dom/Document.cpp:
+ (WebCore::Document::prepareMouseEvent):
+ * html/MediaElementSession.cpp:
+ (WebCore::isMainContentForPurposesOfAutoplay):
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::eventMayStartDrag):
+ (WebCore::EventHandler::hitTestResultAtPoint):
+ (WebCore::EventHandler::handleWheelEvent):
+ (WebCore::EventHandler::sendContextMenuEventForKey):
+ (WebCore::EventHandler::hoverTimerFired):
+ (WebCore::EventHandler::handleDrag):
+ (WebCore::EventHandler::handleTouchEvent):
+ * rendering/HitTestResult.cpp:
+ (WebCore::HitTestResult::targetElement): Renamed from innerElement.
+ Now finds the parent element in the composed tree.
+ * rendering/HitTestResult.h:
+ (WebCore::HitTestResult::innerNode):
+
2016-11-11 Brent Fulgham <bfulgham@apple.com>
Unreviewed build fix after r208628
renderView()->hitTest(request, result);
if (!request.readOnly())
- updateHoverActiveState(request, result.innerElement());
+ updateHoverActiveState(request, result.targetElement());
return MouseEventWithHitTestResults(event, result);
}
// Elements which are obscured by other elements cannot be main content.
mainRenderView.hitTest(request, result);
result.setToNonUserAgentShadowAncestor();
- Element* hitElement = result.innerElement();
+ Element* hitElement = result.targetElement();
if (hitElement != &element)
return false;
HitTestResult result(view->windowToContents(event.position()));
renderView->hitTest(request, result);
DragState state;
- return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state);
+ Element* targetElement = result.targetElement();
+ return targetElement && page->dragController().draggableElement(&m_frame, targetElement, result.roundedPointInInnerNodeFrame(), state);
}
void EventHandler::updateSelectionForMouseDrag()
HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
renderView->hitTest(request, result);
if (!request.readOnly())
- m_frame.document()->updateHoverActiveState(request, result.innerElement());
+ m_frame.document()->updateHoverActiveState(request, result.targetElement());
if (request.disallowsUserAgentShadowContent())
result.setToNonUserAgentShadowAncestor();
HitTestResult result(view->windowToContents(event.position()));
renderView->hitTest(request, result);
- RefPtr<Element> element = result.innerElement();
+ RefPtr<Element> element = result.targetElement();
RefPtr<ContainerNode> scrollableContainer;
WeakPtr<ScrollableArea> scrollableArea;
bool isOverWidget = result.isOverWidget();
// Use the focused node as the target for hover and active.
HitTestResult result(position);
result.setInnerNode(targetNode);
- doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent, result.innerElement());
+ doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent, result.targetElement());
// The contextmenu event is a mouse event even when invoked using the keyboard.
// This is required for web compatibility.
HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent);
HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
renderView->hitTest(request, result);
- m_frame.document()->updateHoverActiveState(request, result.innerElement());
+ m_frame.document()->updateHoverActiveState(request, result.targetElement());
}
}
}
HitTestResult result(m_mouseDownPos);
m_frame.contentRenderer()->hitTest(request, result);
if (m_frame.page())
- dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState());
+ dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.targetElement(), m_mouseDownPos, dragState());
if (!dragState().source)
m_mouseDownMayStartDrag = false; // no element is draggable
} else
continue;
- // FIXME: This code should use Element* instead of Node*.
- Node* node = result.innerElement();
- ASSERT(node);
+ Element* element = result.targetElement();
+ ASSERT(element);
- if (node && InspectorInstrumentation::handleTouchEvent(m_frame, *node))
+ if (element && InspectorInstrumentation::handleTouchEvent(m_frame, *element))
return true;
- Document& doc = node->document();
+ Document& doc = element->document();
// Record the originating touch document even if it does not have a touch listener.
if (freshTouchEvents) {
m_originatingTouchPointDocument = &doc;
}
if (!doc.hasTouchEventHandlers())
continue;
- m_originatingTouchPointTargets.set(touchPointTargetKey, node);
- touchTarget = node;
+ m_originatingTouchPointTargets.set(touchPointTargetKey, element);
+ touchTarget = element;
} else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
// No need to perform a hit-test since we only need to unset :hover and :active states.
if (!shouldGesturesTriggerActive() && allTouchReleased)
return node;
}
-Element* HitTestResult::innerElement() const
+Element* HitTestResult::targetElement() const
{
- Node* node = m_innerNode.get();
- if (!node)
- return nullptr;
- if (is<Element>(*node))
- return downcast<Element>(node);
- return node->parentElement();
+ for (Node* node = m_innerNode.get(); node; node = node->parentInComposedTree()) {
+ if (is<Element>(*node))
+ return downcast<Element>(node);
+ }
+ return nullptr;
}
Element* HitTestResult::innerNonSharedElement() const
WEBCORE_EXPORT HitTestResult& operator=(const HitTestResult&);
Node* innerNode() const { return m_innerNode.get(); }
- WEBCORE_EXPORT Element* innerElement() const;
Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); }
WEBCORE_EXPORT Element* innerNonSharedElement() const;
Element* URLElement() const { return m_innerURLElement.get(); }
Vector<String> dictationAlternatives() const;
Node* targetNode() const;
+ WEBCORE_EXPORT Element* targetElement() const;
private:
NodeSet& mutableRectBasedTestResult(); // See above.
+2016-11-11 Ryosuke Niwa <rniwa@webkit.org>
+
+ Hovering over a slotted Text node clears hover state
+ https://bugs.webkit.org/show_bug.cgi?id=164002
+ <rdar://problem/29040471>
+
+ Reviewed by Simon Fraser.
+
+ * WebView/WebImmediateActionController.mm:
+ (-[WebImmediateActionController performHitTestAtPoint:]):
+
2016-11-11 Wenson Hsieh <wenson_hsieh@apple.com>
[WK2] autocorrect and autocapitalize attributes do not work in contenteditable elements
_hitTestResult = coreFrame->eventHandler().hitTestResultAtPoint(IntPoint(viewPoint));
coreFrame->eventHandler().setImmediateActionStage(ImmediateActionStage::PerformedHitTest);
- if (Element* element = _hitTestResult.innerElement())
+ if (Element* element = _hitTestResult.targetElement())
_contentPreventsDefault = element->dispatchMouseForceWillBegin();
}
+2016-11-11 Ryosuke Niwa <rniwa@webkit.org>
+
+ Hovering over a slotted Text node clears hover state
+ https://bugs.webkit.org/show_bug.cgi?id=164002
+ <rdar://problem/29040471>
+
+ Reviewed by Simon Fraser.
+
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::determinePrimarySnapshottedPlugIn):
+ * WebProcess/WebPage/mac/WebPageMac.mm:
+ (WebKit::WebPage::performImmediateActionHitTestAtLocation):
+
2016-11-11 Wenson Hsieh <wenson_hsieh@apple.com>
[WK2] autocorrect and autocapitalize attributes do not work in contenteditable elements
HitTestResult hitTestResult(plugInRectRelativeToTopDocument.center());
mainRenderView.hitTest(request, hitTestResult);
- Element* element = hitTestResult.innerElement();
+ Element* element = hitTestResult.targetElement();
if (!element)
continue;
HitTestResult hitTestResult = mainFrame.eventHandler().hitTestResultAtPoint(locationInContentCoordinates);
bool immediateActionHitTestPreventsDefault = false;
- Element* element = hitTestResult.innerElement();
+ Element* element = hitTestResult.targetElement();
mainFrame.eventHandler().setImmediateActionStage(ImmediateActionStage::PerformedHitTest);
if (element)