📄 node.cpp
字号:
#endif Node* root = shadowTreeRootNode(); if (root) return root->shadowParentNode(); return this;}Node* Node::shadowTreeRootNode(){ Node* root = this; while (root) { if (root->isShadowNode()) return root; root = root->parentNode(); } return 0;}bool Node::isInShadowTree(){ for (Node* n = this; n; n = n->parentNode()) if (n->isShadowNode()) return true; return false;}bool Node::isBlockFlow() const{ return renderer() && renderer()->isBlockFlow();}bool Node::isBlockFlowOrBlockTable() const{ return renderer() && (renderer()->isBlockFlow() || renderer()->isTable() && !renderer()->isInline());}bool Node::isEditableBlock() const{ return isContentEditable() && isBlockFlow();}Element *Node::enclosingBlockFlowElement() const{ Node *n = const_cast<Node *>(this); if (isBlockFlow()) return static_cast<Element *>(n); while (1) { n = n->parentNode(); if (!n) break; if (n->isBlockFlow() || n->hasTagName(bodyTag)) return static_cast<Element *>(n); } return 0;}Element *Node::enclosingInlineElement() const{ Node *n = const_cast<Node *>(this); Node *p; while (1) { p = n->parentNode(); if (!p || p->isBlockFlow() || p->hasTagName(bodyTag)) return static_cast<Element *>(n); // Also stop if any previous sibling is a block for (Node *sibling = n->previousSibling(); sibling; sibling = sibling->previousSibling()) { if (sibling->isBlockFlow()) return static_cast<Element *>(n); } n = p; } ASSERT_NOT_REACHED(); return 0;}Element* Node::rootEditableElement() const{ Element* result = 0; for (Node* n = const_cast<Node*>(this); n && n->isContentEditable(); n = n->parentNode()) { if (n->isElementNode()) result = static_cast<Element*>(n); if (n->hasTagName(bodyTag)) break; } return result;}bool Node::inSameContainingBlockFlowElement(Node *n){ return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;}// FIXME: End of obviously misplaced HTML editing functions. Try to move these out of Node.PassRefPtr<NodeList> Node::getElementsByTagName(const String& name){ return getElementsByTagNameNS(starAtom, name);} PassRefPtr<NodeList> Node::getElementsByTagNameNS(const AtomicString& namespaceURI, const String& localName){ if (localName.isNull()) return 0; NodeRareData* data = ensureRareData(); if (!data->nodeLists()) { data->setNodeLists(auto_ptr<NodeListsNodeData>(new NodeListsNodeData)); document()->addNodeListCache(); } String name = localName; if (document()->isHTMLDocument()) name = localName.lower(); AtomicString localNameAtom = name; pair<NodeListsNodeData::TagCacheMap::iterator, bool> result = data->nodeLists()->m_tagNodeListCaches.add(QualifiedName(nullAtom, localNameAtom, namespaceURI), 0); if (result.second) result.first->second = new DynamicNodeList::Caches; return TagNodeList::create(this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localNameAtom, result.first->second);}PassRefPtr<NodeList> Node::getElementsByName(const String& elementName){ NodeRareData* data = ensureRareData(); if (!data->nodeLists()) { data->setNodeLists(auto_ptr<NodeListsNodeData>(new NodeListsNodeData)); document()->addNodeListCache(); } pair<NodeListsNodeData::CacheMap::iterator, bool> result = data->nodeLists()->m_nameNodeListCaches.add(elementName, 0); if (result.second) result.first->second = new DynamicNodeList::Caches; return NameNodeList::create(this, elementName, result.first->second);}PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames){ NodeRareData* data = ensureRareData(); if (!data->nodeLists()) { data->setNodeLists(auto_ptr<NodeListsNodeData>(new NodeListsNodeData)); document()->addNodeListCache(); } pair<NodeListsNodeData::CacheMap::iterator, bool> result = data->nodeLists()->m_classNodeListCaches.add(classNames, 0); if (result.second) result.first->second = new DynamicNodeList::Caches; return ClassNodeList::create(this, classNames, result.first->second);}template <typename Functor>static bool forEachTagSelector(Functor& functor, CSSSelector* selector){ ASSERT(selector); do { if (functor(selector)) return true; if (CSSSelector* simpleSelector = selector->simpleSelector()) { if (forEachTagSelector(functor, simpleSelector)) return true; } } while ((selector = selector->tagHistory())); return false;}template <typename Functor>static bool forEachSelector(Functor& functor, const CSSSelectorList& selectorList){ for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { if (forEachTagSelector(functor, selector)) return true; } return false;}class SelectorNeedsNamespaceResolutionFunctor {public: bool operator()(CSSSelector* selector) { if (selector->hasTag() && selector->m_tag.prefix() != nullAtom && selector->m_tag.prefix() != starAtom) return true; if (selector->hasAttribute() && selector->attribute().prefix() != nullAtom && selector->attribute().prefix() != starAtom) return true; return false; }};static bool selectorNeedsNamespaceResolution(const CSSSelectorList& selectorList){ SelectorNeedsNamespaceResolutionFunctor functor; return forEachSelector(functor, selectorList);}PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode& ec){ if (selectors.isEmpty()) { ec = SYNTAX_ERR; return 0; } bool strictParsing = !document()->inCompatMode(); CSSParser p(strictParsing); CSSSelectorList querySelectorList; p.parseSelector(selectors, document(), querySelectorList); if (!querySelectorList.first()) { ec = SYNTAX_ERR; return 0; } // throw a NAMESPACE_ERR if the selector includes any namespace prefixes. if (selectorNeedsNamespaceResolution(querySelectorList)) { ec = NAMESPACE_ERR; return 0; } CSSStyleSelector::SelectorChecker selectorChecker(document(), strictParsing); // FIXME: we could also optimize for the the [id="foo"] case if (strictParsing && inDocument() && querySelectorList.hasOneSelector() && querySelectorList.first()->m_match == CSSSelector::Id) { ASSERT(querySelectorList.first()->attribute() == idAttr); Element* element = document()->getElementById(querySelectorList.first()->m_value); if (element && (isDocumentNode() || element->isDescendantOf(this)) && selectorChecker.checkSelector(querySelectorList.first(), element)) return element; return 0; } // FIXME: We can speed this up by implementing caching similar to the one use by getElementById for (Node* n = firstChild(); n; n = n->traverseNextNode(this)) { if (n->isElementNode()) { Element* element = static_cast<Element*>(n); for (CSSSelector* selector = querySelectorList.first(); selector; selector = CSSSelectorList::next(selector)) { if (selectorChecker.checkSelector(selector, element)) return element; } } } return 0;}PassRefPtr<NodeList> Node::querySelectorAll(const String& selectors, ExceptionCode& ec){ if (selectors.isEmpty()) { ec = SYNTAX_ERR; return 0; } bool strictParsing = !document()->inCompatMode(); CSSParser p(strictParsing); CSSSelectorList querySelectorList; p.parseSelector(selectors, document(), querySelectorList); if (!querySelectorList.first()) { ec = SYNTAX_ERR; return 0; } // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes. if (selectorNeedsNamespaceResolution(querySelectorList)) { ec = NAMESPACE_ERR; return 0; } return createSelectorNodeList(this, querySelectorList);}Document *Node::ownerDocument() const{ Document *doc = document(); return doc == this ? 0 : doc;}KURL Node::baseURI() const{ return parentNode() ? parentNode()->baseURI() : KURL();}bool Node::isEqualNode(Node *other) const{ if (!other) return false; if (nodeType() != other->nodeType()) return false; if (nodeName() != other->nodeName()) return false; if (localName() != other->localName()) return false; if (namespaceURI() != other->namespaceURI()) return false; if (prefix() != other->prefix()) return false; if (nodeValue() != other->nodeValue()) return false; NamedAttrMap *attrs = attributes(); NamedAttrMap *otherAttrs = other->attributes(); if (!attrs && otherAttrs) return false; if (attrs && !attrs->mapsEquivalent(otherAttrs)) return false; Node *child = firstChild(); Node *otherChild = other->firstChild(); while (child) { if (!child->isEqualNode(otherChild)) return false; child = child->nextSibling(); otherChild = otherChild->nextSibling(); } if (otherChild) return false; // FIXME: For DocumentType nodes we should check equality on // the entities and notations NamedNodeMaps as well. return true;}bool Node::isDefaultNamespace(const AtomicString &namespaceURI) const{ // Implemented according to // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#isDefaultNamespaceAlgo switch (nodeType()) { case ELEMENT_NODE: { const Element *elem = static_cast<const Element *>(this); if (elem->prefix().isNull()) return elem->namespaceURI() == namespaceURI; if (elem->hasAttributes()) { NamedAttrMap *attrs = elem->attributes(); for (unsigned i = 0; i < attrs->length(); i++) { Attribute *attr = attrs->attributeItem(i); if (attr->localName() == "xmlns") return attr->value() == namespaceURI; } } if (Element* ancestor = ancestorElement()) return ancestor->isDefaultNamespace(namespaceURI); return false; } case DOCUMENT_NODE: if (Element* de = static_cast<const Document*>(this)->documentElement()) return de->isDefaultNamespace(namespaceURI); return false; case ENTITY_NODE: case NOTATION_NODE: case DOCUMENT_TYPE_NODE: case DOCUMENT_FRAGMENT_NODE: return false; case ATTRIBUTE_NODE: { const Attr *attr = static_cast<const Attr *>(this); if (attr->ownerElement()) return attr->ownerElement()->isDefaultNamespace(namespaceURI); return false; } default: if (Element* ancestor = ancestorElement()) return ancestor->isDefaultNamespace(namespaceURI); return false; }}String Node::lookupPrefix(const AtomicString &namespaceURI) const{ // Implemented according to // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespacePrefixAlgo if (namespaceURI.isEmpty()) return String(); switch (nodeType()) { case ELEMENT_NODE: return lookupNamespacePrefix(namespaceURI, static_cast<const Element *>(this)); case DOCUMENT_NODE: if (Element* de = static_cast<const Document*>(this)->documentElement()) return de->lookupPrefix(namespaceURI); return String(); case ENTITY_NODE: case NOTATION_NODE: case DOCUMENT_FRAGMENT_NODE: case DOCUMENT_TYPE_NODE: return String(); case ATTRIBUTE_NODE: { const Attr *attr = static_cast<const Attr *>(this); if (attr->ownerElement()) return attr->ownerElement()->lookupPrefix(namespaceURI); return String(); } default: if (Element* ancestor = ancestorElement()) return ancestor->lookupPrefix(namespaceURI); return String(); }}String Node::lookupNamespaceURI(const String &prefix) const{ // Implemented according to // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespaceURIAlgo if (!prefix.isNull() && prefix.isEmpty()) return String(); switch (nodeType()) { case ELEMENT_NODE: { const Element *elem = static_cast<const Element *>(this); if (!elem->namespaceURI().isNull() && elem->prefix() == prefix)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -