ToT WebKit doesn't show tooltip on perf dashboard's summary page
https://bugs.webkit.org/show_bug.cgi?id=157705

Reviewed by Darin Adler.

Source/WebCore:

The bug was caused by WebKit doesn't look for the title attribute across shadow boundaries.
Fixed it by using a newly added Node::parentNodeInComposedTree in HitTestResult::title.

Test: fast/shadow-dom/tooltip-on-composed-tree.html

* dom/Node.cpp:
(WebCore::Node::parentInComposedTree): Added.
* dom/Node.h:
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::title): Fixed the bug.
(WebCore::HitTestResult::innerTextIfTruncated): Fixed a related bug when ShowsToolTipOverTruncatedText
is enabled. Unfortunately, there is no machinery to test this feature yet.

LayoutTests:

Added a regression test for finding a tooltip across shadow boundaries.

* fast/shadow-dom/tooltip-on-composed-tree-expected.txt: Added.
* fast/shadow-dom/tooltip-on-composed-tree.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@200923 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 51179e9..c4f39e5 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2016-05-13  Ryosuke Niwa  <rniwa@webkit.org>
+
+        ToT WebKit doesn't show tooltip on perf dashboard's summary page
+        https://bugs.webkit.org/show_bug.cgi?id=157705
+
+        Reviewed by Darin Adler.
+
+        Added a regression test for finding a tooltip across shadow boundaries.
+
+        * fast/shadow-dom/tooltip-on-composed-tree-expected.txt: Added.
+        * fast/shadow-dom/tooltip-on-composed-tree.html: Added.
+
 2016-05-14  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Support ArrayBufferViews in the CSS Font Loading API
diff --git a/LayoutTests/fast/shadow-dom/tooltip-on-composed-tree-expected.txt b/LayoutTests/fast/shadow-dom/tooltip-on-composed-tree-expected.txt
new file mode 100644
index 0000000..7694be8
--- /dev/null
+++ b/LayoutTests/fast/shadow-dom/tooltip-on-composed-tree-expected.txt
@@ -0,0 +1,5 @@
+This tests tooltip across shadow boundaries. To manually test, hover over two boxes below. You should see tooltips for each.
+
+PASS - Tooltip on a node inside a shadow tree with title on its shadow host ancestor
+PASS - Tooltip on a slotted node with title on its slot
+
diff --git a/LayoutTests/fast/shadow-dom/tooltip-on-composed-tree.html b/LayoutTests/fast/shadow-dom/tooltip-on-composed-tree.html
new file mode 100644
index 0000000..434b39f
--- /dev/null
+++ b/LayoutTests/fast/shadow-dom/tooltip-on-composed-tree.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This tests tooltip across shadow boundaries. To manually test, hover over two boxes below. You should see tooltips for each.</p>
+<div class="container"><a title="Tooltip"><span id="hostWithTitle"></span></a></div>
+<div class="container"><span id="hostWithSlottedContent"><span id="content">Hover over here 2</span></span></a></div>
+<style>
+
+.container {
+    border: solid 1px blue;
+    width: 100px;
+    height: 100px;
+    position: relative;
+    margin-bottom: 10px;
+}
+
+#content {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 100px;
+    height: 100px;
+    background: #eee;
+}
+
+</style>
+<pre><script>
+
+var hostWithTitle = document.getElementById('hostWithTitle');
+var shadowRoot = hostWithTitle.attachShadow({mode: 'closed'});
+shadowRoot.innerHTML = `
+    <style>
+        #content {
+            position: absolute;
+            left: 0px;
+            top: 0px;
+            width: 100px;
+            height: 100px;
+            background: #eee;
+        }
+    </style>
+    <div id="content">Hover over here 1</div>
+`;
+
+var nodeInsideShadowRoot = shadowRoot.querySelector('#content');
+var slottedNode = document.querySelector('#content');
+
+shadowRootWithSlot = document.getElementById('hostWithSlottedContent').attachShadow({mode: 'closed'});
+shadowRootWithSlot.innerHTML = `<slot title="Tooltip"></slot>`;
+
+if (window.internals) {
+    testRunner.dumpAsText();
+
+    document.write((internals.toolTipFromElement(nodeInsideShadowRoot) == 'Tooltip' ? 'PASS' : 'FAIL')
+        + ' - Tooltip on a node inside a shadow tree with title on its shadow host ancestor\n');
+
+    document.write((internals.toolTipFromElement(slottedNode) == 'Tooltip' ? 'PASS' : 'FAIL')
+        + ' - Tooltip on a slotted node with title on its slot\n');
+
+    Array.from(document.querySelectorAll('.container')).map(function (node) { node.remove(); });
+}
+
+</script></pre>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 5a73edd..25819d9 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,23 @@
+2016-05-13  Ryosuke Niwa  <rniwa@webkit.org>
+
+        ToT WebKit doesn't show tooltip on perf dashboard's summary page
+        https://bugs.webkit.org/show_bug.cgi?id=157705
+
+        Reviewed by Darin Adler.
+
+        The bug was caused by WebKit doesn't look for the title attribute across shadow boundaries.
+        Fixed it by using a newly added Node::parentNodeInComposedTree in HitTestResult::title.
+
+        Test: fast/shadow-dom/tooltip-on-composed-tree.html
+
+        * dom/Node.cpp:
+        (WebCore::Node::parentInComposedTree): Added.
+        * dom/Node.h:
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::title): Fixed the bug.
+        (WebCore::HitTestResult::innerTextIfTruncated): Fixed a related bug when ShowsToolTipOverTruncatedText
+        is enabled. Unfortunately, there is no machinery to test this feature yet.
+
 2016-05-14  Darin Adler  <darin@apple.com>
 
         CTTE for the HTML editing header
diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp
index b2100ae..901d33e 100644
--- a/Source/WebCore/dom/Node.cpp
+++ b/Source/WebCore/dom/Node.cpp
@@ -1138,6 +1138,22 @@
 }
 #endif
 
+ContainerNode* Node::parentInComposedTree() const
+{
+    ASSERT(isMainThreadOrGCThread());
+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+    if (auto* parent = parentElement()) {
+        if (auto* shadowRoot = parent->shadowRoot()) {
+            if (auto* assignedSlot = shadowRoot->findAssignedSlot(*this))
+                return assignedSlot;
+        }
+    }
+#endif
+    if (is<ShadowRoot>(*this))
+        return downcast<ShadowRoot>(*this).host();
+    return parentNode();
+}
+
 bool Node::isInUserAgentShadowTree() const
 {
     auto* shadowRoot = containingShadowRoot();
diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h
index e33bb21..16a13ae 100644
--- a/Source/WebCore/dom/Node.h
+++ b/Source/WebCore/dom/Node.h
@@ -279,6 +279,7 @@
 
     // Node's parent or shadow tree host.
     ContainerNode* parentOrShadowHostNode() const;
+    ContainerNode* parentInComposedTree() const;
     Element* parentOrShadowHostElement() const;
     void setParentNode(ContainerNode*);
     Node* rootNode() const;
diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp
index 6b4b6e7..6af4d1f 100644
--- a/Source/WebCore/rendering/HitTestResult.cpp
+++ b/Source/WebCore/rendering/HitTestResult.cpp
@@ -257,7 +257,7 @@
     dir = LTR;
     // Find the title in the nearest enclosing DOM node.
     // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
-    for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) {
+    for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentInComposedTree()) {
         if (is<Element>(*titleNode)) {
             Element& titleElement = downcast<Element>(*titleNode);
             String title = titleElement.title();
@@ -273,7 +273,7 @@
 
 String HitTestResult::innerTextIfTruncated(TextDirection& dir) const
 {
-    for (Node* truncatedNode = m_innerNode.get(); truncatedNode; truncatedNode = truncatedNode->parentNode()) {
+    for (Node* truncatedNode = m_innerNode.get(); truncatedNode; truncatedNode = truncatedNode->parentInComposedTree()) {
         if (!is<Element>(*truncatedNode))
             continue;