📄 dom_elementimpl.cpp
字号:
NodeImpl *n; for (n = _first; n; n = n->nextSibling()) { //qDebug(" (%p) calling recalcStyle on child %s/%p, change=%d", this, n, n->isElementNode() ? ((ElementImpl *)n)->tagName().string().latin1() : n->isTextNode() ? "text" : "unknown", change ); if ( change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed() ) n->recalcStyle( change ); } setChanged( false ); setHasChangedChild( false );}// DOM Section 1.1.1bool ElementImpl::childAllowed( NodeImpl *newChild ){ if (!childTypeAllowed(newChild->nodeType())) return false; // For XML documents, we are non-validating and do not check against a DTD, even for HTML elements. if (getDocument()->isHTMLDocument()) return checkChild(id(), newChild->id()); return true;}bool ElementImpl::childTypeAllowed( unsigned short type ){ switch (type) { case Node::ELEMENT_NODE: case Node::TEXT_NODE: case Node::COMMENT_NODE: case Node::PROCESSING_INSTRUCTION_NODE: case Node::CDATA_SECTION_NODE: case Node::ENTITY_REFERENCE_NODE: return true; break; default: return false; }}void ElementImpl::dispatchAttrRemovalEvent(AttributeImpl *attr){ if (!getDocument()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER)) return; //int exceptioncode = 0;// dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,attr,attr->value(),// attr->value(), getDocument()->attrName(attr->id()),MutationEvent::REMOVAL),exceptioncode);}void ElementImpl::dispatchAttrAdditionEvent(AttributeImpl *attr){ if (!getDocument()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER)) return; // int exceptioncode = 0;// dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,attr,attr->value(),// attr->value(),getDocument()->attrName(attr->id()),MutationEvent::ADDITION),exceptioncode);}DOMString ElementImpl::openTagStartToString() const{ DOMString result = DOMString("<") + tagName(); NamedAttrMapImpl *attrMap = attributes(true); if (attrMap) { unsigned long numAttrs = attrMap->length(); for (unsigned long i = 0; i < numAttrs; i++) { result += " "; AttributeImpl *attribute = attrMap->attributeItem(i); AttrImpl *attr = attribute->attrImpl(); if (attr) { result += attr->toString(); } else { result += getDocument()->attrName(attribute->id()); if (!attribute->value().isNull()) { result += "=\""; // FIXME: substitute entities for any instances of " or ' result += attribute->value(); result += "\""; } } } } return result;}DOMString ElementImpl::toString() const{ DOMString result = openTagStartToString(); if (hasChildNodes()) { result += ">"; for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) { result += child->toString(); } result += "</"; result += tagName(); result += ">"; } else { result += " />"; } return result;}void ElementImpl::updateId(const AtomicString& oldId, const AtomicString& newId){ if (!attached()) return; if (oldId == newId) return; DocumentImpl* doc = getDocument(); if (!oldId.isEmpty()) doc->removeElementById(oldId, this); if (!newId.isEmpty()) doc->addElementById(newId, this);}#ifndef NDEBUGvoid ElementImpl::dump(QTextStream *stream, QString ind) const{ if (namedAttrMap) { for (uint i = 0; i < namedAttrMap->length(); i++) { AttributeImpl *attr = namedAttrMap->attributeItem(i); *stream << " " << DOMString(getDocument()->attrName(attr->id())).string().ascii() << "=\"" << DOMString(attr->value()).string().ascii() << "\""; } } NodeBaseImpl::dump(stream,ind);}#endif// -------------------------------------------------------------------------XMLElementImpl::XMLElementImpl(DocumentPtr *doc, DOMStringImpl *_tagName) : ElementImpl(doc){ m_id = doc->document()->tagId(0 /* no namespace */, _tagName, false /* allocate */);}XMLElementImpl::XMLElementImpl(DocumentPtr *doc, DOMStringImpl *_qualifiedName, DOMStringImpl *_namespaceURI) : ElementImpl(doc){ int colonpos = -1; for (uint i = 0; i < _qualifiedName->l; ++i) if (_qualifiedName->s[i] == ':') { colonpos = i; break; } if (colonpos >= 0) { // we have a prefix DOMStringImpl* localName = _qualifiedName->copy(); localName->ref(); localName->remove(0,colonpos+1); m_id = doc->document()->tagId(_namespaceURI, localName, false /* allocate */); localName->deref(); m_prefix = _qualifiedName->copy(); m_prefix->ref(); m_prefix->truncate(colonpos); } else { // no prefix m_id = doc->document()->tagId(_namespaceURI, _qualifiedName, false /* allocate */); m_prefix = 0; }}XMLElementImpl::~XMLElementImpl(){}DOMString XMLElementImpl::localName() const{ return getDocument()->tagName(m_id);}NodeImpl *XMLElementImpl::cloneNode ( bool deep ){ // ### we loose namespace here FIXME // should pass id around XMLElementImpl *clone = new XMLElementImpl(docPtr(), getDocument()->tagName(m_id).implementation()); clone->m_id = m_id; // clone attributes if(namedAttrMap) *(static_cast<NamedAttrMapImpl*>(clone->attributes())) = *namedAttrMap; if (deep) cloneChildNodes(clone); return clone;}// -------------------------------------------------------------------------NamedAttrMapImpl::NamedAttrMapImpl(ElementImpl *e) : element(e){ attrs = 0; len = 0;}NamedAttrMapImpl::~NamedAttrMapImpl(){ NamedAttrMapImpl::clearAttributes(); // virtual method, so qualify just to be explicit}bool NamedAttrMapImpl::isHTMLAttributeMap() const{ return false;}AttrImpl *NamedAttrMapImpl::getNamedItem ( NodeImpl::Id id ) const{ AttributeImpl* a = getAttributeItem(id); if (!a) return 0; if (!a->attrImpl()) a->allocateImpl(element); return a->attrImpl();}Node NamedAttrMapImpl::setNamedItem ( NodeImpl* arg, int &exceptioncode ){ if (!element) { exceptioncode = DOMException::NOT_FOUND_ERR; return 0; } // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly. if (isReadOnly()) { exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; return 0; } // WRONG_DOCUMENT_ERR: Raised if arg was created from a different document than the one that created this map. if (arg->getDocument() != element->getDocument()) { exceptioncode = DOMException::WRONG_DOCUMENT_ERR; return 0; } // Not mentioned in spec: throw a HIERARCHY_REQUEST_ERROR if the user passes in a non-attribute node if (!arg->isAttributeNode()) { exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; return 0; } AttrImpl *attr = static_cast<AttrImpl*>(arg); AttributeImpl* a = attr->attrImpl(); AttributeImpl* old = getAttributeItem(a->id()); if (old == a) return arg; // we know about it already // INUSE_ATTRIBUTE_ERR: Raised if arg is an Attr that is already an attribute of another Element object. // The DOM user must explicitly clone Attr nodes to re-use them in other elements. if (attr->ownerElement()) { exceptioncode = DOMException::INUSE_ATTRIBUTE_ERR; return 0; } if (a->id() == ATTR_ID) { element->updateId(old ? old->value() : nullAtom, a->value()); } // ### slightly inefficient - resizes attribute array twice. Node r; if (old) { if (!old->attrImpl()) old->allocateImpl(element); r = old->_impl; removeAttribute(a->id()); } addAttribute(a); return r;}// The DOM2 spec doesn't say that removeAttribute[NS] throws NOT_FOUND_ERR// if the attribute is not found, but at this level we have to throw NOT_FOUND_ERR// because of removeNamedItem, removeNamedItemNS, and removeAttributeNode.Node NamedAttrMapImpl::removeNamedItem ( NodeImpl::Id id, int &exceptioncode ){ // ### should this really be raised when the attribute to remove isn't there at all? // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly if (isReadOnly()) { exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; return Node(); } AttributeImpl* a = getAttributeItem(id); if (!a) { exceptioncode = DOMException::NOT_FOUND_ERR; return Node(); } if (!a->attrImpl()) a->allocateImpl(element); Node r(a->attrImpl()); if (id == ATTR_ID) { element->updateId(a->value(), nullAtom); } removeAttribute(id); return r;}AttrImpl *NamedAttrMapImpl::item ( unsigned long index ) const{ if (index >= len) return 0; if (!attrs[index]->attrImpl()) attrs[index]->allocateImpl(element); return attrs[index]->attrImpl();}AttributeImpl* NamedAttrMapImpl::getAttributeItem(NodeImpl::Id id) const{ bool matchAnyNamespace = (namespacePart(id) == anyNamespace); for (unsigned long i = 0; i < len; ++i) { if (attrs[i]->id() == id) return attrs[i]; else if (matchAnyNamespace) { if (localNamePart(attrs[i]->id()) == localNamePart(id)) return attrs[i]; } } return 0;}NodeImpl::Id NamedAttrMapImpl::mapId(const DOMString& namespaceURI, const DOMString& localName, bool readonly){ assert(element); if (!element) return 0; return element->getDocument()->attrId(namespaceURI.implementation(), localName.implementation(), readonly);}void NamedAttrMapImpl::clearAttributes(){ if (attrs) { uint i; for (i = 0; i < len; i++) { if (attrs[i]->_impl) attrs[i]->_impl->m_element = 0; attrs[i]->deref(); } delete [] attrs; attrs = 0; } len = 0;}void NamedAttrMapImpl::detachFromElement(){ // we allow a NamedAttrMapImpl w/o an element in case someone still has a reference // to if after the element gets deleted - but the map is now invalid element = 0; clearAttributes();}NamedAttrMapImpl& NamedAttrMapImpl::operator=(const NamedAttrMapImpl& other){ // clone all attributes in the other map, but attach to our element if (!element) return *this; // If assigning the map changes the id attribute, we need to call // updateId. AttributeImpl *oldId = getAttributeItem(ATTR_ID); AttributeImpl *newId = other.getAttributeItem(ATTR_ID); if (oldId || newId) { element->updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom); } clearAttributes(); len = other.len; attrs = new AttributeImpl* [len]; // first initialize attrs vector, then call attributeChanged on it // this allows attributeChanged to use getAttribute for (uint i = 0; i < len; i++) { attrs[i] = other.attrs[i]->clone(); attrs[i]->ref(); } // FIXME: This is wasteful. The class list could be preserved on a copy, and we // wouldn't have to waste time reparsing the attribute. // The derived class, HTMLNamedAttrMapImpl, which manages a parsed class list for the CLASS attribute, // will update its member variable when parse attribute is called. for(uint i = 0; i < len; i++) element->attributeChanged(attrs[i], true); return *this;}void NamedAttrMapImpl::addAttribute(AttributeImpl *attr){ // Add the attribute to the list AttributeImpl **newAttrs = new AttributeImpl* [len+1]; if (attrs) { for (uint i = 0; i < len; i++) newAttrs[i] = attrs[i]; delete [] attrs; } attrs = newAttrs; attrs[len++] = attr; attr->ref(); AttrImpl * const attrImpl = attr->_impl; if (attrImpl) attrImpl->m_element = element; // Notify the element that the attribute has been added, and dispatch appropriate mutation events // Note that element may be null here if we are called from insertAttr() during parsing if (element) { element->attributeChanged(attr); element->dispatchAttrAdditionEvent(attr); element->dispatchSubtreeModifiedEvent(); }}void NamedAttrMapImpl::removeAttribute(NodeImpl::Id id){ unsigned long index = len+1; for (unsigned long i = 0; i < len; ++i) if (attrs[i]->id() == id) { index = i; break; } if (index >= len) return; // Remove the attribute from the list AttributeImpl* attr = attrs[index]; if (attrs[index]->_impl) attrs[index]->_impl->m_element = 0; if (len == 1) { delete [] attrs; attrs = 0; len = 0; } else { AttributeImpl **newAttrs = new AttributeImpl* [len-1]; uint i; for (i = 0; i < uint(index); i++) newAttrs[i] = attrs[i]; len--; for (; i < len; i++) newAttrs[i] = attrs[i+1]; delete [] attrs; attrs = newAttrs; } // Notify the element that the attribute has been removed // dispatch appropriate mutation events if (element && !attr->_value.isNull()) { AtomicString value = attr->_value; attr->_value = nullAtom; element->attributeChanged(attr); attr->_value = value; } if (element) { element->dispatchAttrRemovalEvent(attr); element->dispatchSubtreeModifiedEvent(); } attr->deref();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -