📄 dom_elementimpl.cpp
字号:
// 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 (!inDocument())
return;
if (oldId == newId)
return;
DocumentImpl* doc = getDocument();
if (!oldId.isEmpty())
doc->removeElementById(oldId, this);
if (!newId.isEmpty())
doc->addElementById(newId, this);
}
#ifndef NDEBUG
void ElementImpl::dump(QTextStream *stream, QString ind) const
{
updateStyleAttributeIfNeeded();
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
#ifndef NDEBUG
void ElementImpl::formatForDebugger(char *buffer, unsigned length) const
{
DOMString result;
DOMString s;
s = nodeName();
if (s.length() > 0) {
result += s;
}
s = getAttribute(ATTR_ID);
if (s.length() > 0) {
if (result.length() > 0)
result += "; ";
result += "id=";
result += s;
}
s = getAttribute(ATTR_CLASS);
if (s.length() > 0) {
if (result.length() > 0)
result += "; ";
result += "class=";
result += s;
}
strncpy(buffer, result.string().latin1(), length - 1);
}
#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)
*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();
}
#ifndef __OOM__
delete [] attrs;
#else
MemoryManager::Free( attrs );
#endif
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;
#ifndef __OOM__
attrs = new AttributeImpl* [len];
#else
attrs = (AttributeImpl**)MemoryManager::Alloc( len * sizeof( AttributeImpl* ) );
#endif
// 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
#ifndef __OOM__
AttributeImpl **newAttrs = new AttributeImpl* [len+1];
#else
AttributeImpl **newAttrs = (AttributeImpl **)MemoryManager::Alloc( ( len+1 ) * sizeof(AttributeImpl*) );
#endif
if (attrs) {
for (uint i = 0; i < len; i++)
newAttrs[i] = attrs[i];
#ifndef __OOM__
delete [] attrs;
#else
MemoryManager::Free( attrs );
#endif
}
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(false);
}
}
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) {
#ifndef __OOM__
delete [] attrs;
#else
MemoryManager::Free( attrs );
#endif
attrs = 0;
len = 0;
}
else {
#ifndef __OOM__
AttributeImpl **newAttrs = new AttributeImpl* [len-1];
#else
AttributeImpl **newAttrs = (AttributeImpl **)MemoryManager::Alloc( ( len-1 ) * sizeof(AttributeImpl*) );
#endif
uint i;
for (i = 0; i < uint(index); i++)
newAttrs[i] = attrs[i];
len--;
for (; i < len; i++)
newAttrs[i] = attrs[i+1];
#ifndef __OOM__
delete [] attrs;
#else
MemoryManager::Free( attrs );
#endif
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(false);
}
attr->deref();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -