📄 node.cpp
字号:
return elem->namespaceURI(); if (elem->hasAttributes()) { NamedAttrMap *attrs = elem->attributes(); for (unsigned i = 0; i < attrs->length(); i++) { Attribute *attr = attrs->attributeItem(i); if (attr->prefix() == "xmlns" && attr->localName() == prefix) { if (!attr->value().isEmpty()) return attr->value(); return String(); } else if (attr->localName() == "xmlns" && prefix.isNull()) { if (!attr->value().isEmpty()) return attr->value(); return String(); } } } if (Element* ancestor = ancestorElement()) return ancestor->lookupNamespaceURI(prefix); return String(); } case DOCUMENT_NODE: if (Element* de = static_cast<const Document*>(this)->documentElement()) return de->lookupNamespaceURI(prefix); return String(); case ENTITY_NODE: case NOTATION_NODE: case DOCUMENT_TYPE_NODE: case DOCUMENT_FRAGMENT_NODE: return String(); case ATTRIBUTE_NODE: { const Attr *attr = static_cast<const Attr *>(this); if (attr->ownerElement()) return attr->ownerElement()->lookupNamespaceURI(prefix); else return String(); } default: if (Element* ancestor = ancestorElement()) return ancestor->lookupNamespaceURI(prefix); return String(); }}String Node::lookupNamespacePrefix(const AtomicString &_namespaceURI, const Element *originalElement) const{ if (_namespaceURI.isNull()) return String(); if (originalElement->lookupNamespaceURI(prefix()) == _namespaceURI) return prefix(); if (hasAttributes()) { NamedAttrMap *attrs = attributes(); for (unsigned i = 0; i < attrs->length(); i++) { Attribute *attr = attrs->attributeItem(i); if (attr->prefix() == "xmlns" && attr->value() == _namespaceURI && originalElement->lookupNamespaceURI(attr->localName()) == _namespaceURI) return attr->localName(); } } if (Element* ancestor = ancestorElement()) return ancestor->lookupNamespacePrefix(_namespaceURI, originalElement); return String();}void Node::appendTextContent(bool convertBRsToNewlines, StringBuilder& content) const{ switch (nodeType()) { case TEXT_NODE: case CDATA_SECTION_NODE: case COMMENT_NODE: content.append(static_cast<const CharacterData*>(this)->CharacterData::nodeValue()); break; case PROCESSING_INSTRUCTION_NODE: content.append(static_cast<const ProcessingInstruction*>(this)->ProcessingInstruction::nodeValue()); break; case ELEMENT_NODE: if (hasTagName(brTag) && convertBRsToNewlines) { content.append('\n'); break; } // Fall through. case ATTRIBUTE_NODE: case ENTITY_NODE: case ENTITY_REFERENCE_NODE: case DOCUMENT_FRAGMENT_NODE: content.setNonNull(); for (Node *child = firstChild(); child; child = child->nextSibling()) { if (child->nodeType() == COMMENT_NODE || child->nodeType() == PROCESSING_INSTRUCTION_NODE) continue; child->appendTextContent(convertBRsToNewlines, content); } break; case DOCUMENT_NODE: case DOCUMENT_TYPE_NODE: case NOTATION_NODE: case XPATH_NAMESPACE_NODE: break; }}String Node::textContent(bool convertBRsToNewlines) const{ StringBuilder content; appendTextContent(convertBRsToNewlines, content); return content.toString();}void Node::setTextContent(const String &text, ExceptionCode& ec){ switch (nodeType()) { case TEXT_NODE: case CDATA_SECTION_NODE: case COMMENT_NODE: case PROCESSING_INSTRUCTION_NODE: setNodeValue(text, ec); break; case ELEMENT_NODE: case ATTRIBUTE_NODE: case ENTITY_NODE: case ENTITY_REFERENCE_NODE: case DOCUMENT_FRAGMENT_NODE: { ContainerNode *container = static_cast<ContainerNode *>(this); container->removeChildren(); if (!text.isEmpty()) appendChild(document()->createTextNode(text), ec); break; } case DOCUMENT_NODE: case DOCUMENT_TYPE_NODE: case NOTATION_NODE: default: // Do nothing break; }}Element* Node::ancestorElement() const{ // In theory, there can be EntityReference nodes between elements, but this is currently not supported. for (Node* n = parentNode(); n; n = n->parentNode()) { if (n->isElementNode()) return static_cast<Element*>(n); } return 0;}bool Node::offsetInCharacters() const{ return false;}unsigned short Node::compareDocumentPosition(Node* otherNode){ // It is not clear what should be done if |otherNode| is 0. if (!otherNode) return DOCUMENT_POSITION_DISCONNECTED; if (otherNode == this) return DOCUMENT_POSITION_EQUIVALENT; Attr* attr1 = nodeType() == ATTRIBUTE_NODE ? static_cast<Attr*>(this) : 0; Attr* attr2 = otherNode->nodeType() == ATTRIBUTE_NODE ? static_cast<Attr*>(otherNode) : 0; Node* start1 = attr1 ? attr1->ownerElement() : this; Node* start2 = attr2 ? attr2->ownerElement() : otherNode; // If either of start1 or start2 is null, then we are disconnected, since one of the nodes is // an orphaned attribute node. if (!start1 || !start2) return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; Vector<Node*, 16> chain1; Vector<Node*, 16> chain2; if (attr1) chain1.append(attr1); if (attr2) chain2.append(attr2); if (attr1 && attr2 && start1 == start2 && start1) { // We are comparing two attributes on the same node. Crawl our attribute map // and see which one we hit first. NamedAttrMap* map = attr1->ownerElement()->attributes(true); unsigned length = map->length(); for (unsigned i = 0; i < length; ++i) { // If neither of the two determining nodes is a child node and nodeType is the same for both determining nodes, then an // implementation-dependent order between the determining nodes is returned. This order is stable as long as no nodes of // the same nodeType are inserted into or removed from the direct container. This would be the case, for example, // when comparing two attributes of the same element, and inserting or removing additional attributes might change // the order between existing attributes. Attribute* attr = map->attributeItem(i); if (attr1->attr() == attr) return DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_FOLLOWING; if (attr2->attr() == attr) return DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_PRECEDING; } ASSERT_NOT_REACHED(); return DOCUMENT_POSITION_DISCONNECTED; } // If one node is in the document and the other is not, we must be disconnected. // If the nodes have different owning documents, they must be disconnected. Note that we avoid // comparing Attr nodes here, since they return false from inDocument() all the time (which seems like a bug). if (start1->inDocument() != start2->inDocument() || start1->document() != start2->document()) return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; // We need to find a common ancestor container, and then compare the indices of the two immediate children. Node* current; for (current = start1; current; current = current->parentNode()) chain1.append(current); for (current = start2; current; current = current->parentNode()) chain2.append(current); // Walk the two chains backwards and look for the first difference. unsigned index1 = chain1.size(); unsigned index2 = chain2.size(); for (unsigned i = min(index1, index2); i; --i) { Node* child1 = chain1[--index1]; Node* child2 = chain2[--index2]; if (child1 != child2) { // If one of the children is an attribute, it wins. if (child1->nodeType() == ATTRIBUTE_NODE) return DOCUMENT_POSITION_FOLLOWING; if (child2->nodeType() == ATTRIBUTE_NODE) return DOCUMENT_POSITION_PRECEDING; if (!child2->nextSibling()) return DOCUMENT_POSITION_FOLLOWING; if (!child1->nextSibling()) return DOCUMENT_POSITION_PRECEDING; // Otherwise we need to see which node occurs first. Crawl backwards from child2 looking for child1. for (Node* child = child2->previousSibling(); child; child = child->previousSibling()) { if (child == child1) return DOCUMENT_POSITION_FOLLOWING; } return DOCUMENT_POSITION_PRECEDING; } } // There was no difference between the two parent chains, i.e., one was a subset of the other. The shorter // chain is the ancestor. return index1 < index2 ? DOCUMENT_POSITION_FOLLOWING | DOCUMENT_POSITION_CONTAINED_BY : DOCUMENT_POSITION_PRECEDING | DOCUMENT_POSITION_CONTAINS;}FloatPoint Node::convertToPage(const FloatPoint& p) const{ // If there is a renderer, just ask it to do the conversion if (renderer()) return renderer()->localToAbsolute(p, false, true); // Otherwise go up the tree looking for a renderer Element *parent = ancestorElement(); if (parent) return parent->convertToPage(p); // No parent - no conversion needed return p;}FloatPoint Node::convertFromPage(const FloatPoint& p) const{ // If there is a renderer, just ask it to do the conversion if (renderer()) return renderer()->absoluteToLocal(p, false, true); // Otherwise go up the tree looking for a renderer Element *parent = ancestorElement(); if (parent) return parent->convertFromPage(p); // No parent - no conversion needed return p;}#ifndef NDEBUGstatic void appendAttributeDesc(const Node* node, String& string, const QualifiedName& name, const char* attrDesc){ if (node->isElementNode()) { String attr = static_cast<const Element*>(node)->getAttribute(name); if (!attr.isEmpty()) { string += attrDesc; string += attr; } }}void Node::showNode(const char* prefix) const{ if (!prefix) prefix = ""; if (isTextNode()) { String value = nodeValue(); value.replace('\\', "\\\\"); value.replace('\n', "\\n"); fprintf(stderr, "%s%s\t%p \"%s\"\n", prefix, nodeName().utf8().data(), this, value.utf8().data()); } else { String attrs = ""; appendAttributeDesc(this, attrs, classAttr, " CLASS="); appendAttributeDesc(this, attrs, styleAttr, " STYLE="); fprintf(stderr, "%s%s\t%p%s\n", prefix, nodeName().utf8().data(), this, attrs.utf8().data()); }}void Node::showTreeForThis() const{ showTreeAndMark(this, "*");}void Node::showTreeAndMark(const Node* markedNode1, const char* markedLabel1, const Node* markedNode2, const char * markedLabel2) const{ const Node* rootNode; const Node* node = this; while (node->parentNode() && !node->hasTagName(bodyTag)) node = node->parentNode(); rootNode = node; for (node = rootNode; node; node = node->traverseNextNode()) { if (node == markedNode1) fprintf(stderr, "%s", markedLabel1); if (node == markedNode2) fprintf(stderr, "%s", markedLabel2); for (const Node* tmpNode = node; tmpNode && tmpNode != rootNode; tmpNode = tmpNode->parentNode()) fprintf(stderr, "\t"); node->showNode(); }}void Node::formatForDebugger(char* buffer, unsigned length) const{ String result; String s; s = nodeName(); if (s.length() == 0) result += "<none>"; else result += s; strncpy(buffer, result.utf8().data(), length - 1);}#endif// --------void NodeListsNodeData::invalidateCaches(){ m_childNodeListCaches.reset(); TagCacheMap::const_iterator tagCachesEnd = m_tagNodeListCaches.end(); for (TagCacheMap::const_iterator it = m_tagNodeListCaches.begin(); it != tagCachesEnd; ++it) it->second->reset(); invalidateCachesThatDependOnAttributes();}void NodeListsNodeData::invalidateCachesThatDependOnAttributes(){ CacheMap::iterator classCachesEnd = m_classNodeListCaches.end(); for (CacheMap::iterator it = m_classNodeListCaches.begin(); it != classCachesEnd; ++it) it->second->reset(); CacheMap::iterator nameCachesEnd = m_nameNodeListCaches.end(); for (CacheMap::iterator it = m_nameNodeListCaches.begin(); it != nameCachesEnd; ++it) it->second->reset();}bool NodeListsNodeData::isEmpty() const{ if (!m_listsWithCaches.isEmpty()) return false; if (m_childNodeListCaches.refCount) return false; TagCacheMap::const_iterator tagCachesEnd = m_tagNodeListCaches.end(); for (TagCacheMap::const_iterator it = m_tagNodeListCaches.begin(); it != tagCachesEnd; ++it) { if (it->second->refCount) return false; } CacheMap::const_iterator classCachesEnd = m_classNodeListCaches.end(); for (CacheMap::const_iterator it = m_classNodeListCaches.begin(); it != classCachesEnd; ++it) { if (it->second->refCount) return false; } CacheMap::const_iterator nameCachesEnd = m_nameNodeListCaches.end(); for (CacheMap::const_iterator it = m_nameNodeListCaches.begin(); it != nameCachesEnd; ++it) { if (it->second->refCount) return false; } return true;}void Node::getSubresourceURLs(ListHashSet<KURL>& urls) const{ addSubresourceAttributeURLs(urls);}ContainerNode* Node::eventParentNode(){ Node* parent = parentNode(); ASSERT(!parent || parent->isContainerNode()); return static_cast<ContainerNode*>(parent);}// --------ScriptExecutionContext* Node::scri
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -