summaryrefslogtreecommitdiff
path: root/Source/WebCore/dom/TreeScope.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/dom/TreeScope.cpp')
-rw-r--r--Source/WebCore/dom/TreeScope.cpp328
1 files changed, 154 insertions, 174 deletions
diff --git a/Source/WebCore/dom/TreeScope.cpp b/Source/WebCore/dom/TreeScope.cpp
index dcd165ec1..cc0e8e3ab 100644
--- a/Source/WebCore/dom/TreeScope.cpp
+++ b/Source/WebCore/dom/TreeScope.cpp
@@ -27,7 +27,6 @@
#include "config.h"
#include "TreeScope.h"
-#include "DOMSelection.h"
#include "DOMWindow.h"
#include "ElementIterator.h"
#include "FocusController.h"
@@ -40,6 +39,7 @@
#include "HitTestResult.h"
#include "IdTargetObserverRegistry.h"
#include "Page.h"
+#include "PointerLockController.h"
#include "RenderView.h"
#include "RuntimeEnabledFeatures.h"
#include "ShadowRoot.h"
@@ -49,98 +49,71 @@
namespace WebCore {
struct SameSizeAsTreeScope {
- virtual ~SameSizeAsTreeScope();
- void* pointers[9];
- int ints[1];
+ void* pointers[8];
};
COMPILE_ASSERT(sizeof(TreeScope) == sizeof(SameSizeAsTreeScope), treescope_should_stay_small);
using namespace HTMLNames;
-TreeScope::TreeScope(ContainerNode* rootNode, Document* document)
- : m_rootNode(rootNode)
+TreeScope::TreeScope(ShadowRoot& shadowRoot, Document& document)
+ : m_rootNode(shadowRoot)
, m_documentScope(document)
- , m_parentTreeScope(document)
- , m_selfOnlyRefCount(0)
- , m_idTargetObserverRegistry(IdTargetObserverRegistry::create())
+ , m_parentTreeScope(&document)
+ , m_idTargetObserverRegistry(std::make_unique<IdTargetObserverRegistry>())
{
- ASSERT(rootNode);
- ASSERT(document);
- ASSERT(rootNode != document);
- m_parentTreeScope->selfOnlyRef();
- m_rootNode->setTreeScope(*this);
+ shadowRoot.setTreeScope(*this);
}
-TreeScope::TreeScope(Document* document)
+TreeScope::TreeScope(Document& document)
: m_rootNode(document)
, m_documentScope(document)
, m_parentTreeScope(nullptr)
- , m_selfOnlyRefCount(0)
- , m_idTargetObserverRegistry(IdTargetObserverRegistry::create())
-{
- ASSERT(document);
- m_rootNode->setTreeScope(*this);
-}
-
-TreeScope::TreeScope()
- : m_rootNode(nullptr)
- , m_documentScope(nullptr)
- , m_parentTreeScope(nullptr)
- , m_selfOnlyRefCount(0)
+ , m_idTargetObserverRegistry(std::make_unique<IdTargetObserverRegistry>())
{
+ document.setTreeScope(*this);
}
TreeScope::~TreeScope()
{
- ASSERT(!m_selfOnlyRefCount);
- m_rootNode->setTreeScope(noDocumentInstance());
-
- if (m_selection) {
- m_selection->clearTreeScope();
- m_selection = nullptr;
- }
-
- if (m_parentTreeScope)
- m_parentTreeScope->selfOnlyDeref();
}
void TreeScope::destroyTreeScopeData()
{
- m_elementsById.clear();
- m_imageMapsByName.clear();
- m_labelsByForAttribute.clear();
+ m_elementsById = nullptr;
+ m_imageMapsByName = nullptr;
+ m_labelsByForAttribute = nullptr;
}
-void TreeScope::clearDocumentScope()
-{
- ASSERT(rootNode()->isDocumentNode());
- m_documentScope = nullptr;
-}
-
-void TreeScope::setParentTreeScope(TreeScope* newParentScope)
+void TreeScope::setParentTreeScope(TreeScope& newParentScope)
{
// A document node cannot be re-parented.
- ASSERT(!rootNode()->isDocumentNode());
- // Every scope other than document needs a parent scope.
- ASSERT(newParentScope);
-
- newParentScope->selfOnlyRef();
- if (m_parentTreeScope)
- m_parentTreeScope->selfOnlyDeref();
- m_parentTreeScope = newParentScope;
- setDocumentScope(newParentScope->documentScope());
+ ASSERT(!m_rootNode.isDocumentNode());
+
+ m_parentTreeScope = &newParentScope;
+ setDocumentScope(newParentScope.documentScope());
}
Element* TreeScope::getElementById(const AtomicString& elementId) const
{
- if (elementId.isEmpty())
+ if (elementId.isNull())
return nullptr;
if (!m_elementsById)
return nullptr;
return m_elementsById->getElementById(*elementId.impl(), *this);
}
+Element* TreeScope::getElementById(const String& elementId) const
+{
+ if (!m_elementsById)
+ return nullptr;
+
+ if (RefPtr<AtomicStringImpl> atomicElementId = AtomicStringImpl::lookUp(elementId.impl()))
+ return m_elementsById->getElementById(*atomicElementId, *this);
+
+ return nullptr;
+}
+
const Vector<Element*>* TreeScope::getAllElementsById(const AtomicString& elementId) const
{
if (elementId.isEmpty())
@@ -153,7 +126,7 @@ const Vector<Element*>* TreeScope::getAllElementsById(const AtomicString& elemen
void TreeScope::addElementById(const AtomicStringImpl& elementId, Element& element, bool notifyObservers)
{
if (!m_elementsById)
- m_elementsById = adoptPtr(new DocumentOrderedMap);
+ m_elementsById = std::make_unique<DocumentOrderedMap>();
m_elementsById->add(elementId, element, *this);
if (notifyObservers)
m_idTargetObserverRegistry->notifyObservers(elementId);
@@ -180,7 +153,7 @@ Element* TreeScope::getElementByName(const AtomicString& name) const
void TreeScope::addElementByName(const AtomicStringImpl& name, Element& element)
{
if (!m_elementsByName)
- m_elementsByName = adoptPtr(new DocumentOrderedMap);
+ m_elementsByName = std::make_unique<DocumentOrderedMap>();
m_elementsByName->add(name, element, *this);
}
@@ -191,7 +164,39 @@ void TreeScope::removeElementByName(const AtomicStringImpl& name, Element& eleme
m_elementsByName->remove(name, element);
}
-Node* TreeScope::ancestorInThisScope(Node* node) const
+
+Node& TreeScope::retargetToScope(Node& node) const
+{
+ auto& scope = node.treeScope();
+ if (LIKELY(this == &scope || !node.isInShadowTree()))
+ return node;
+ ASSERT(is<ShadowRoot>(scope.rootNode()));
+
+ Vector<TreeScope*, 8> nodeTreeScopes;
+ for (auto* currentScope = &scope; currentScope; currentScope = currentScope->parentTreeScope())
+ nodeTreeScopes.append(currentScope);
+ ASSERT(nodeTreeScopes.size() >= 2);
+
+ Vector<const TreeScope*, 8> 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<ShadowRoot>(nodeTreeScopes[i - 1]->rootNode());
+ return *shadowRootInLowestCommonTreeScope.host();
+}
+
+Node* TreeScope::ancestorNodeInThisScope(Node* node) const
{
for (; node; node = node->shadowHost()) {
if (&node->treeScope() == this)
@@ -202,13 +207,24 @@ Node* TreeScope::ancestorInThisScope(Node* node) const
return nullptr;
}
+Element* TreeScope::ancestorElementInThisScope(Element* element) const
+{
+ for (; element; element = element->shadowHost()) {
+ if (&element->treeScope() == this)
+ return element;
+ if (!element->isInShadowTree())
+ return nullptr;
+ }
+ return nullptr;
+}
+
void TreeScope::addImageMap(HTMLMapElement& imageMap)
{
AtomicStringImpl* name = imageMap.getName().impl();
if (!name)
return;
if (!m_imageMapsByName)
- m_imageMapsByName = adoptPtr(new DocumentOrderedMap);
+ m_imageMapsByName = std::make_unique<DocumentOrderedMap>();
m_imageMapsByName->add(*name, imageMap, *this);
}
@@ -224,63 +240,17 @@ void TreeScope::removeImageMap(HTMLMapElement& imageMap)
HTMLMapElement* TreeScope::getImageMap(const String& url) const
{
- if (url.isNull())
- return nullptr;
if (!m_imageMapsByName)
return nullptr;
- size_t hashPos = url.find('#');
- String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl();
+ auto hashPosition = url.find('#');
+ if (hashPosition == notFound)
+ return nullptr;
+ String name = url.substring(hashPosition + 1);
if (name.isEmpty())
return nullptr;
- if (rootNode()->document().isHTMLDocument()) {
- AtomicString lowercasedName = name.lower();
- return m_imageMapsByName->getElementByLowercasedMapName(*lowercasedName.impl(), *this);
- }
return m_imageMapsByName->getElementByMapName(*AtomicString(name).impl(), *this);
}
-Node* nodeFromPoint(Document* document, int x, int y, LayoutPoint* localPoint)
-{
- Frame* frame = document->frame();
-
- if (!frame)
- return nullptr;
- FrameView* frameView = frame->view();
- if (!frameView)
- return nullptr;
-
- float scaleFactor = frame->pageZoomFactor() * frame->frameScaleFactor();
-#if !PLATFORM(IOS)
- IntPoint point = roundedIntPoint(FloatPoint(x * scaleFactor + frameView->scrollX(), y * scaleFactor + frameView->scrollY()));
-
- if (!frameView->visibleContentRect().contains(point))
- return nullptr;
-#else
- IntPoint point = roundedIntPoint(FloatPoint(x * scaleFactor + frameView->actualScrollX(), y * scaleFactor + frameView->actualScrollY()));
-
- if (!frameView->actualVisibleContentRect().contains(point))
- return nullptr;
-#endif
- HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
- HitTestResult result(point);
- document->renderView()->hitTest(request, result);
-
- if (localPoint)
- *localPoint = result.localPoint();
-
- return result.innerNode();
-}
-
-Element* TreeScope::elementFromPoint(int x, int y) const
-{
- Node* node = nodeFromPoint(&rootNode()->document(), x, y);
- while (node && !node->isElementNode())
- node = node->parentNode();
- if (node)
- node = ancestorInThisScope(node);
- return toElement(node);
-}
-
void TreeScope::addLabel(const AtomicStringImpl& forAttributeValue, HTMLLabelElement& element)
{
ASSERT(m_labelsByForAttribute);
@@ -300,10 +270,10 @@ HTMLLabelElement* TreeScope::labelElementForId(const AtomicString& forAttributeV
if (!m_labelsByForAttribute) {
// Populate the map on first access.
- m_labelsByForAttribute = adoptPtr(new DocumentOrderedMap);
+ m_labelsByForAttribute = std::make_unique<DocumentOrderedMap>();
- for (auto& label : descendantsOfType<HTMLLabelElement>(*rootNode())) {
- const AtomicString& forValue = label.fastGetAttribute(forAttr);
+ for (auto& label : descendantsOfType<HTMLLabelElement>(m_rootNode)) {
+ const AtomicString& forValue = label.attributeWithoutSynchronization(forAttr);
if (!forValue.isEmpty())
addLabel(*forValue.impl(), label);
}
@@ -312,29 +282,56 @@ HTMLLabelElement* TreeScope::labelElementForId(const AtomicString& forAttributeV
return m_labelsByForAttribute->getElementByLabelForAttribute(*forAttributeValue.impl(), *this);
}
-DOMSelection* TreeScope::getSelection() const
+Node* TreeScope::nodeFromPoint(const LayoutPoint& clientPoint, LayoutPoint* localPoint)
{
- if (!rootNode()->document().frame())
+ auto* frame = documentScope().frame();
+ auto* view = documentScope().view();
+ if (!frame || !view)
return nullptr;
- if (m_selection)
- return m_selection.get();
+ float scaleFactor = frame->pageZoomFactor() * frame->frameScaleFactor();
- // FIXME: The correct selection in Shadow DOM requires that Position can have a ShadowRoot
- // as a container. It is now enabled only if runtime Shadow DOM feature is enabled.
- // See https://bugs.webkit.org/show_bug.cgi?id=82697
-#if ENABLE(SHADOW_DOM)
- if (RuntimeEnabledFeatures::sharedFeatures().shadowDOMEnabled()) {
- m_selection = DOMSelection::create(this);
- return m_selection.get();
- }
+ LayoutPoint contentsPoint = clientPoint;
+ contentsPoint.scale(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(double x, double y)
+{
+ Document& document = documentScope();
+ if (!document.hasLivingRenderTree())
+ return nullptr;
- if (this != &rootNode()->document())
- return rootNode()->document().getSelection();
+ Node* node = nodeFromPoint(LayoutPoint(x, y), nullptr);
+ if (!node)
+ return nullptr;
+
+ node = &retargetToScope(*node);
+ while (!is<Element>(*node)) {
+ node = node->parentInComposedTree();
+ if (!node)
+ break;
+ node = &retargetToScope(*node);
+ }
- m_selection = DOMSelection::create(&rootNode()->document());
- return m_selection.get();
+ return downcast<Element>(node);
}
Element* TreeScope::findAnchor(const String& name)
@@ -343,10 +340,12 @@ Element* TreeScope::findAnchor(const String& name)
return nullptr;
if (Element* element = getElementById(name))
return element;
- for (auto& anchor : descendantsOfType<HTMLAnchorElement>(*rootNode())) {
- if (rootNode()->document().inQuirksMode()) {
- // Quirks mode, case insensitive comparison of names.
- if (equalIgnoringCase(anchor.name(), name))
+ for (auto& anchor : descendantsOfType<HTMLAnchorElement>(m_rootNode)) {
+ if (m_rootNode.document().inQuirksMode()) {
+ // Quirks mode, ASCII case-insensitive comparison of names.
+ // FIXME: This behavior is not mentioned in the HTML specification.
+ // We should either remove this or get this into the specification.
+ if (equalIgnoringASCIICase(anchor.name(), name))
return &anchor;
} else {
// Strict mode, names need to match exactly.
@@ -357,17 +356,10 @@ Element* TreeScope::findAnchor(const String& name)
return nullptr;
}
-bool TreeScope::applyAuthorStyles() const
-{
- return true;
-}
-
-void TreeScope::adoptIfNeeded(Node* node)
+void TreeScope::adoptIfNeeded(Node& node)
{
- ASSERT(this);
- ASSERT(node);
- ASSERT(!node->isDocumentNode());
- ASSERT(!node->m_deletionHasBegun);
+ ASSERT(!node.isDocumentNode());
+ ASSERT(!node.m_deletionHasBegun);
TreeScopeAdopter adopter(node, *this);
if (adopter.needsScopeChange())
adopter.execute();
@@ -382,25 +374,33 @@ static Element* focusedFrameOwnerElement(Frame* focusedFrame, Frame* currentFram
return nullptr;
}
-Element* TreeScope::focusedElement()
+Element* TreeScope::focusedElementInScope()
{
- Document& document = rootNode()->document();
+ Document& document = documentScope();
Element* element = document.focusedElement();
if (!element && document.page())
element = focusedFrameOwnerElement(document.page()->focusController().focusedFrame(), document.frame());
- if (!element)
+
+ return ancestorElementInThisScope(element);
+}
+
+#if ENABLE(POINTER_LOCK)
+
+Element* TreeScope::pointerLockElement() const
+{
+ Document& document = documentScope();
+ Page* page = document.page();
+ if (!page || page->pointerLockController().lockPending())
return nullptr;
- TreeScope* treeScope = &element->treeScope();
- while (treeScope != this && treeScope != &document) {
- element = toShadowRoot(treeScope->rootNode())->hostElement();
- treeScope = &element->treeScope();
- }
- if (this != treeScope)
+ auto* element = page->pointerLockController().element();
+ if (!element || &element->document() != &document)
return nullptr;
- return element;
+ return ancestorElementInThisScope(element);
}
+#endif
+
static void listTreeScopes(Node* node, Vector<TreeScope*, 5>& treeScopes)
{
while (true) {
@@ -438,24 +438,4 @@ TreeScope* commonTreeScope(Node* nodeA, Node* nodeB)
return treeScopesA[indexA] == treeScopesB[indexB] ? treeScopesA[indexA] : nullptr;
}
-#ifndef NDEBUG
-bool TreeScope::deletionHasBegun()
-{
- return rootNode() && rootNode()->m_deletionHasBegun;
-}
-
-void TreeScope::beginDeletion()
-{
- ASSERT(this != &noDocumentInstance());
- rootNode()->m_deletionHasBegun = true;
-}
-#endif
-
-int TreeScope::refCount() const
-{
- if (Node* root = rootNode())
- return root->refCount();
- return 0;
-}
-
} // namespace WebCore