diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index d1ae186d280a2..646c57f6ceef3 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,15 @@ +2016-10-03 Ryosuke Niwa + + ShadowRoot interface should have elementFromPoint + https://bugs.webkit.org/show_bug.cgi?id=162882 + + Reviewed by Chris Dumez. + + Add a W3C style testharness.js test for elementFromPoint on ShadowRoot. + + * fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint-expected.txt: Added. + * fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html: Added. + 2016-10-04 Myles C. Maxfield font-family: cursive should map to KaiTi in Chinese diff --git a/LayoutTests/fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint-expected.txt b/LayoutTests/fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint-expected.txt new file mode 100644 index 0000000000000..d50824d164054 --- /dev/null +++ b/LayoutTests/fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint-expected.txt @@ -0,0 +1,35 @@ + +PASS document.elementFromPoint must return the shadow host of the hit-tested text node when the host has display: inline +PASS document.elementFromPoint must return the shadow host of the hit-tested text node when the host has display: block +PASS document.elementFromPoint must return the shadow host of the hit-tested text node when the host has display: inline-block +PASS document.elementFromPoint must return the shadow host of the hit-tested text node assigned to a slot when the host has display: inline +PASS document.elementFromPoint must return the shadow host of the hit-tested text node assigned to a slot when the host has display: block +PASS document.elementFromPoint must return the shadow host of the hit-tested text node assigned to a slot when the host has display: inline-block +PASS document.elementFromPoint must return the element assigned to a slot when the shadow host of the slot has display: inline +PASS document.elementFromPoint must return the element assigned to a slot when the shadow host of the slot has display: block +PASS document.elementFromPoint must return the element assigned to a slot when the shadow host of the slot has display: inline-block +PASS shadowRoot.elementFromPoint must return the element parent of the hit-tested text node under the point when the shadow host has display: inline +PASS shadowRoot.elementFromPoint must return the element parent of the hit-tested text node under the point when the shadow host has display: block +PASS shadowRoot.elementFromPoint must return the element parent of the hit-tested text node under the point when the shadow host has display: inline-block +PASS shadowRoot.elementFromPoint must return the shadow host when the hit-tested text node is a direct child of the root and the host has display: inline +PASS shadowRoot.elementFromPoint must return the shadow host when the hit-tested text node is a direct child of the root and the host has display: block +PASS shadowRoot.elementFromPoint must return the shadow host when the hit-tested text node is a direct child of the root and the host has display: inline-block +PASS shadowRoot.elementFromPoint must return the slot to which the hit-tested text node is assigned when its host has display: inline +PASS shadowRoot.elementFromPoint must return the slot to which the hit-tested text node is assigned when its host has display: block +PASS shadowRoot.elementFromPoint must return the slot to which the hit-tested text node is assigned when its host has display: inline-block +PASS shadowRoot.elementFromPoint must return the element parent of the hit-tested text node assigned to a slot in the shadow tree when its host has display: inline +PASS shadowRoot.elementFromPoint must return the element parent of the hit-tested text node assigned to a slot in the shadow tree when its host has display: block +PASS shadowRoot.elementFromPoint must return the element parent of the hit-tested text node assigned to a slot in the shadow tree when its host has display: inline-block +PASS shadowRoot.elementFromPoint must return a child element assigned to a slot when the hit-tested text node is assigned to the shadow tree of the child element and the outer shadow host has display: inline +PASS shadowRoot.elementFromPoint must return a child element assigned to a slot when the hit-tested text node is assigned to the shadow tree of the child element and the outer shadow host has display: block +PASS shadowRoot.elementFromPoint must return a child element assigned to a slot when the hit-tested text node is assigned to the shadow tree of the child element and the outer shadow host has display: inline-block +PASS shadowRoot.elementFromPoint must return a child element assigned to a slot when the hit-tested text node is assigned to a slot in the shadow tree of the child element and the outer shadow host has display: inline +PASS shadowRoot.elementFromPoint must return a child element assigned to a slot when the hit-tested text node is assigned to a slot in the shadow tree of the child element and the outer shadow host has display: block +PASS shadowRoot.elementFromPoint must return a child element assigned to a slot when the hit-tested text node is assigned to a slot in the shadow tree of the child element and the outer shadow host has display: inline-block +PASS shadowRoot.elementFromPoint must return a child element with its own shadow tree assigned to a slot when the hit-tested text node is its direct child and the outer shadow host has display: inline +PASS shadowRoot.elementFromPoint must return a child element with its own shadow tree assigned to a slot when the hit-tested text node is its direct child and the outer shadow host has display: block +PASS shadowRoot.elementFromPoint must return a child element with its own shadow tree assigned to a slot when the hit-tested text node is its direct child and the outer shadow host has display: inline-block +PASS shadowRoot.elementFromPoint must return a child element with its own shadow tree assigned to a slot when the hit-tested text node is a child of another element and the outer shadow host has display: inline +PASS shadowRoot.elementFromPoint must return a child element with its own shadow tree assigned to a slot when the hit-tested text node is a child of another element and the outer shadow host has display: block +PASS shadowRoot.elementFromPoint must return a child element with its own shadow tree assigned to a slot when the hit-tested text node is a child of another element and the outer shadow host has display: inline-block + diff --git a/LayoutTests/fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html b/LayoutTests/fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html new file mode 100644 index 0000000000000..a8dc4da243071 --- /dev/null +++ b/LayoutTests/fast/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html @@ -0,0 +1,204 @@ + + + +Shadow DOM and CSSOM View: Document.prototype.elementFromPoint + + + + + + + + +
+ + + + diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt index 77aac2160dcbc..5b4d982aa5238 100644 --- a/Source/WebCore/CMakeLists.txt +++ b/Source/WebCore/CMakeLists.txt @@ -391,6 +391,7 @@ set(WebCore_NON_SVG_IDL_FILES dom/DeviceOrientationEvent.idl dom/Document.idl dom/DocumentFragment.idl + dom/DocumentOrShadowRoot.idl dom/DocumentType.idl dom/Element.idl dom/ErrorEvent.idl diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index f49f167d2876a..f3fb44f76dae9 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,46 @@ +2016-10-03 Ryosuke Niwa + + ShadowRoot interface should have elementFromPoint + https://bugs.webkit.org/show_bug.cgi?id=162882 + + Reviewed by Chris Dumez. + + Add elementFromPoint to ShadowRoot's prototype as specified at: + https://www.w3.org/TR/shadow-dom/#extensions-to-the-documentorshadowroot-mixin + with changes proposed at https://github.com/w3c/csswg-drafts/issues/556 + + Added TreeScope::retargetToScope which implements + + This patch also factors DocumentOrShadowRoot.idl out of Document and ShadowRoot interfaces to better match + the latest DOM specification: https://dom.spec.whatwg.org/#mixin-documentorshadowroot + + Test: fast/shadow-dom/Document-prototype-elementFromPoint.html + + * CMakeLists.txt: + * DerivedSources.make: + * WebCore.xcodeproj/project.pbxproj: + * dom/Document.cpp: + (WebCore::Document::nodeFromPoint): Moved to TreeScope. + (WebCore::Document::elementFromPoint): Moved to TreeScope. + * dom/Document.h: + * dom/Document.idl: Moved elementFromPoint and activeElement to DocumentOrShadowRoot.idl. + * dom/DocumentOrShadowRoot.idl: Added. + * dom/EventPath.cpp: + (WebCore::RelatedNodeRetargeter::checkConsistency): Use newly added TreeScope::retargetToScope. + * dom/ShadowRoot.idl: Moved activeElement to DocumentOrShadowRoot.idl. + * dom/TreeScope.cpp: + (WebCore::TreeScope::retargetToScope): Added. Implements https://dom.spec.whatwg.org/#retarget efficiently. + Instead of checking whether A (node) is a shadow-including inclusive ancestor of B (this scope) at each + parent, find the lowest ancestor which contains both A and B, and return the self-inclusive ancestor of B + in that tree. To find the lowest common ancestor in O(n), traverse all ancestors of A and B separately and + do a top-down traversal. The last tree scope in which A's ancestor and B's ancestor match is the lowest + common ancestor. + (WebCore::TreeScope::nodeFromPoint): Moved from Document. + (WebCore::TreeScope::elementFromPoint): Moved from Document. Use retargetToScope and parentInComposedTree + instead of parentNode and ancestorInThisScope to match the semantics proposed in + https://github.com/w3c/csswg-drafts/issues/556 + * dom/TreeScope.h: + 2016-10-04 Myles C. Maxfield font-family: cursive should map to KaiTi in Chinese diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make index 27f2c61068ddf..1912b9a9996c8 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make @@ -301,6 +301,7 @@ JS_BINDING_IDLS = \ $(WebCore)/dom/DeviceOrientationEvent.idl \ $(WebCore)/dom/Document.idl \ $(WebCore)/dom/DocumentFragment.idl \ + $(WebCore)/dom/DocumentOrShadowRoot.idl \ $(WebCore)/dom/DocumentType.idl \ $(WebCore)/dom/Element.idl \ $(WebCore)/dom/ErrorEvent.idl \ diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj index 76a8ded8ca817..7ddd852afd239 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj @@ -10877,6 +10877,7 @@ 9B03D8061BB3110D00B764D9 /* ReadableStreamInternalsBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReadableStreamInternalsBuiltins.h; sourceTree = ""; }; 9B03D8061BB3110D00B764E8 /* WritableStreamBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WritableStreamBuiltins.h; sourceTree = ""; }; 9B03D8061BB3110D00B764E9 /* WritableStreamInternalsBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WritableStreamInternalsBuiltins.h; sourceTree = ""; }; + 9B0FE8731D9E02DF004A8ACB /* DocumentOrShadowRoot.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DocumentOrShadowRoot.idl; sourceTree = ""; }; 9B19B67E1B964E5200348745 /* ShadowRoot.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ShadowRoot.idl; sourceTree = ""; }; 9B1AB0791648C69D0051F3F2 /* HTMLFormControlsCollection.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = HTMLFormControlsCollection.idl; sourceTree = ""; }; 9B1AB07B1648C7C40051F3F2 /* JSHTMLFormControlsCollectionCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLFormControlsCollectionCustom.cpp; sourceTree = ""; }; @@ -23014,6 +23015,7 @@ ED2BA83B09A24B91006C0AC4 /* DocumentMarker.h */, CE057FA31220731100A476D5 /* DocumentMarkerController.cpp */, CE057FA41220731100A476D5 /* DocumentMarkerController.h */, + 9B0FE8731D9E02DF004A8ACB /* DocumentOrShadowRoot.idl */, 14947FFB12F80CD200A0F631 /* DocumentOrderedMap.cpp */, 14947FFC12F80CD200A0F631 /* DocumentOrderedMap.h */, A8C2280D11D4A59700D5A7D3 /* DocumentParser.cpp */, diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index 19fc924bf6c28..c1ccdc02aeab9 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -1425,52 +1425,6 @@ String Document::contentType() const return ASCIILiteral("application/xml"); } -Node* Document::nodeFromPoint(const LayoutPoint& clientPoint, LayoutPoint* localPoint) -{ - if (!frame() || !view()) - return nullptr; - - Frame& frame = *this->frame(); - - float scaleFactor = frame.pageZoomFactor() * frame.frameScaleFactor(); - - LayoutPoint contentsPoint = clientPoint; - contentsPoint.scale(scaleFactor, scaleFactor); - contentsPoint.moveBy(view()->contentsScrollPosition()); - - LayoutRect visibleRect; -#if PLATFORM(IOS) - visibleRect = view()->unobscuredContentRect(); -#else - visibleRect = view()->visibleContentRect(); -#endif - if (!visibleRect.contains(contentsPoint)) - return nullptr; - - HitTestResult result(contentsPoint); - renderView()->hitTest(HitTestRequest(), result); - - if (localPoint) - *localPoint = result.localPoint(); - - return result.innerNode(); -} - -Element* Document::elementFromPoint(const LayoutPoint& clientPoint) -{ - if (!hasLivingRenderTree()) - return nullptr; - - Node* node = nodeFromPoint(clientPoint); - while (node && !is(*node)) - node = node->parentNode(); - - if (node) - node = ancestorInThisScope(node); - - return downcast(node); -} - RefPtr Document::caretRangeFromPoint(int x, int y) { return caretRangeFromPoint(LayoutPoint(x, y)); diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index c235322f77ae5..0c3b3f569a6d9 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -397,9 +397,6 @@ class Document NamedFlowCollection& namedFlows(); - Element* elementFromPoint(int x, int y) { return elementFromPoint(LayoutPoint(x, y)); } - WEBCORE_EXPORT Element* elementFromPoint(const LayoutPoint& clientPoint); - WEBCORE_EXPORT RefPtr caretRangeFromPoint(int x, int y); RefPtr caretRangeFromPoint(const LayoutPoint& clientPoint); @@ -1363,8 +1360,6 @@ class Document PageVisibilityState pageVisibilityState() const; - Node* nodeFromPoint(const LayoutPoint& clientPoint, LayoutPoint* localPoint = nullptr); - template Ref ensureCachedCollection(); diff --git a/Source/WebCore/dom/Document.idl b/Source/WebCore/dom/Document.idl index 3b182f08cf9ec..cda4e6bb7e101 100644 --- a/Source/WebCore/dom/Document.idl +++ b/Source/WebCore/dom/Document.idl @@ -126,7 +126,6 @@ [ImplementedAs=characterSetWithUTF8Fallback] readonly attribute DOMString charset; readonly attribute DOMString readyState; - Element elementFromPoint(optional long x = 0, optional long y = 0); Range caretRangeFromPoint(optional long x = 0, optional long y = 0); // Mozilla extensions @@ -141,7 +140,6 @@ HTMLCollection getElementsByClassName(DOMString classNames); - readonly attribute Element? activeElement; boolean hasFocus(); readonly attribute DOMString compatMode; @@ -214,4 +212,5 @@ Document implements ParentNode; Document implements NonElementParentNode; +Document implements DocumentOrShadowRoot; Document implements GlobalEventHandlers; diff --git a/Source/WebCore/dom/DocumentOrShadowRoot.idl b/Source/WebCore/dom/DocumentOrShadowRoot.idl new file mode 100644 index 0000000000000..4c54e4eb401a2 --- /dev/null +++ b/Source/WebCore/dom/DocumentOrShadowRoot.idl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +// https://dom.spec.whatwg.org/#documentorshadowroot +// https://www.w3.org/TR/shadow-dom/#extensions-to-the-documentorshadowroot-mixin +[ + NoInterfaceObject, +] interface DocumentOrShadowRoot { + Element? elementFromPoint(optional long x = 0, optional long y = 0); // FIXME: x and y should be double and not be optional. + readonly attribute Element? activeElement; +}; diff --git a/Source/WebCore/dom/EventPath.cpp b/Source/WebCore/dom/EventPath.cpp index 618d8b3c334e9..818a5174778ac 100644 --- a/Source/WebCore/dom/EventPath.cpp +++ b/Source/WebCore/dom/EventPath.cpp @@ -360,17 +360,10 @@ void RelatedNodeRetargeter::collectTreeScopes() #if !ASSERT_DISABLED void RelatedNodeRetargeter::checkConsistency(Node& currentTarget) { - ASSERT(!m_retargetedRelatedNode || currentTarget.isUnclosedNode(*m_retargetedRelatedNode)); - - // http://w3c.github.io/webcomponents/spec/shadow/#dfn-retargeting-algorithm - Node& base = currentTarget; - for (Node* targetAncestor = &m_relatedNode; targetAncestor; targetAncestor = targetAncestor->parentOrShadowHostNode()) { - if (targetAncestor->rootNode().containsIncludingShadowDOM(&base)) { - ASSERT(m_retargetedRelatedNode == targetAncestor); - return; - } - } - ASSERT(!m_retargetedRelatedNode || m_hasDifferentTreeRoot); + if (!m_retargetedRelatedNode) + return; + ASSERT(currentTarget.isUnclosedNode(*m_retargetedRelatedNode)); + ASSERT(m_retargetedRelatedNode == ¤tTarget.treeScope().retargetToScope(m_relatedNode)); } #endif diff --git a/Source/WebCore/dom/ShadowRoot.idl b/Source/WebCore/dom/ShadowRoot.idl index 3a7bd664fbdf8..83efa44ee05de 100644 --- a/Source/WebCore/dom/ShadowRoot.idl +++ b/Source/WebCore/dom/ShadowRoot.idl @@ -28,7 +28,6 @@ JSGenerateToJSObject ] interface ShadowRoot : DocumentFragment { readonly attribute ShadowRootMode mode; - readonly attribute Element activeElement; readonly attribute Element host; [TreatNullAs=EmptyString, SetterMayThrowLegacyException] attribute DOMString innerHTML; @@ -36,3 +35,5 @@ // "user-agent" is a WebKit extension that is not exposed to the Web. enum ShadowRootMode { "user-agent", "closed", "open" }; + +ShadowRoot implements DocumentOrShadowRoot; diff --git a/Source/WebCore/dom/TreeScope.cpp b/Source/WebCore/dom/TreeScope.cpp index 7f6930927eab4..3606a650c934e 100644 --- a/Source/WebCore/dom/TreeScope.cpp +++ b/Source/WebCore/dom/TreeScope.cpp @@ -32,6 +32,7 @@ #include "ElementIterator.h" #include "FocusController.h" #include "Frame.h" +#include "FrameView.h" #include "HTMLAnchorElement.h" #include "HTMLFrameOwnerElement.h" #include "HTMLLabelElement.h" @@ -39,6 +40,7 @@ #include "HitTestResult.h" #include "IdTargetObserverRegistry.h" #include "Page.h" +#include "RenderView.h" #include "RuntimeEnabledFeatures.h" #include "ShadowRoot.h" #include "TreeScopeAdopter.h" @@ -168,6 +170,38 @@ void TreeScope::removeElementByName(const AtomicStringImpl& name, Element& eleme m_elementsByName->remove(name, element); } + +Node& TreeScope::retargetToScope(Node& node) const +{ + auto& scope = node.treeScope(); + if (LIKELY(this == &scope || !node.isInShadowTree())) + return node; + ASSERT(is(scope.rootNode())); + + Vector nodeTreeScopes; + for (auto* currentScope = &scope; currentScope; currentScope = currentScope->parentTreeScope()) + nodeTreeScopes.append(currentScope); + ASSERT(nodeTreeScopes.size() >= 2); + + Vector ancestorScopes; + for (auto* currentScope = this; currentScope; currentScope = currentScope->parentTreeScope()) + ancestorScopes.append(currentScope); + + size_t i = nodeTreeScopes.size(); + size_t j = ancestorScopes.size(); + while (i > 0 && j > 0 && nodeTreeScopes[i - 1] == ancestorScopes[j - 1]) { + --i; + --j; + } + + bool nodeIsInOuterTreeScope = !i; + if (nodeIsInOuterTreeScope) + return node; + + ShadowRoot& shadowRootInLowestCommonTreeScope = downcast(nodeTreeScopes[i - 1]->rootNode()); + return *shadowRootInLowestCommonTreeScope.host(); +} + Node* TreeScope::ancestorInThisScope(Node* node) const { for (; node; node = node->shadowHost()) { @@ -245,6 +279,58 @@ HTMLLabelElement* TreeScope::labelElementForId(const AtomicString& forAttributeV return m_labelsByForAttribute->getElementByLabelForAttribute(*forAttributeValue.impl(), *this); } +Node* TreeScope::nodeFromPoint(const LayoutPoint& clientPoint, LayoutPoint* localPoint) +{ + auto* frame = documentScope().frame(); + auto* view = documentScope().view(); + if (!frame || !view) + return nullptr; + + float scaleFactor = frame->pageZoomFactor() * frame->frameScaleFactor(); + + LayoutPoint contentsPoint = clientPoint; + contentsPoint.scale(scaleFactor, scaleFactor); + contentsPoint.moveBy(view->contentsScrollPosition()); + + LayoutRect visibleRect; +#if PLATFORM(IOS) + visibleRect = view->unobscuredContentRect(); +#else + visibleRect = view->visibleContentRect(); +#endif + if (!visibleRect.contains(contentsPoint)) + return nullptr; + + HitTestResult result(contentsPoint); + documentScope().renderView()->hitTest(HitTestRequest(), result); + + if (localPoint) + *localPoint = result.localPoint(); + + return result.innerNode(); +} + +Element* TreeScope::elementFromPoint(int x, int y) +{ + Document& document = documentScope(); + if (!document.hasLivingRenderTree()) + return nullptr; + + Node* node = nodeFromPoint(LayoutPoint(x, y), nullptr); + if (!node) + return nullptr; + + node = &retargetToScope(*node); + while (!is(*node)) { + node = node->parentInComposedTree(); + if (!node) + break; + node = &retargetToScope(*node); + } + + return downcast(node); +} + DOMSelection* TreeScope::getSelection() const { if (!m_rootNode.document().frame()) diff --git a/Source/WebCore/dom/TreeScope.h b/Source/WebCore/dom/TreeScope.h index 5b0c4407e4eff..0b66b64d23cda 100644 --- a/Source/WebCore/dom/TreeScope.h +++ b/Source/WebCore/dom/TreeScope.h @@ -71,6 +71,9 @@ class TreeScope { Document& documentScope() const { return *m_documentScope; } static ptrdiff_t documentScopeMemoryOffset() { return OBJECT_OFFSETOF(TreeScope, m_documentScope); } + // https://dom.spec.whatwg.org/#retarget + Node& retargetToScope(Node&) const; + Node* ancestorInThisScope(Node*) const; void addImageMap(HTMLMapElement&); @@ -83,6 +86,8 @@ class TreeScope { void removeLabel(const AtomicStringImpl& forAttributeValue, HTMLLabelElement&); HTMLLabelElement* labelElementForId(const AtomicString& forAttributeValue); + WEBCORE_EXPORT Element* elementFromPoint(int x, int y); + DOMSelection* getSelection() const; // Find first anchor with the given name. @@ -111,6 +116,8 @@ class TreeScope { m_documentScope = document; } + Node* nodeFromPoint(const LayoutPoint& clientPoint, LayoutPoint* localPoint); + private: ContainerNode& m_rootNode; Document* m_documentScope; diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp index c46c82856803a..aaf6f8a9180b1 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp @@ -3213,7 +3213,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) #endif #if ENABLE(CUSTOM_ELEMENTS) - RuntimeEnabledFeatures::sharedFeatures().setCustomElementsEnabled(store.getBoolValueForKey(WebPreferencesKey::customElementsEnabledKey())); + RuntimeEnabledFeatures::sharedFeatures().setCustomElementsEnabled(true || store.getBoolValueForKey(WebPreferencesKey::customElementsEnabledKey())); #endif #if ENABLE(WEBGL2)