📄 dom_elementimpl.cpp
字号:
/** * This file is part of the DOM implementation for KDE. * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Peter Kelly (pmk@post.com) * (C) 2001 Dirk Mueller (mueller@kde.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *///#define EVENT_DEBUG#include "dom/dom_exception.h"#include "dom/dom_node.h"#include "xml/dom_textimpl.h"#include "xml/dom_docimpl.h"#include "xml/dom2_eventsimpl.h"#include "xml/dom_elementimpl.h"#include "khtml_part.h"#include "html/dtd.h"#include "html/htmlparser.h"#include "rendering/render_canvas.h"#include "misc/htmlhashes.h"#include "css/css_valueimpl.h"#include "css/css_stylesheetimpl.h"#include "css/cssstyleselector.h"#include "xml/dom_selection.h"#include "xml/dom_xmlimpl.h"#include <qtextstream.h>#include <kdebug.h>using namespace DOM;using namespace khtml;AttributeImpl* AttributeImpl::clone(bool) const{ AttributeImpl* result = new AttributeImpl(m_id, _value); result->setPrefix(_prefix); return result;}void AttributeImpl::allocateImpl(ElementImpl* e) { _impl = new AttrImpl(e, e->docPtr(), this);}AttrImpl::AttrImpl(ElementImpl* element, DocumentPtr* docPtr, AttributeImpl* a) : NodeBaseImpl(docPtr), m_element(element), m_attribute(a){ assert(!m_attribute->_impl); m_attribute->_impl = this; m_attribute->ref(); m_specified = true;}AttrImpl::~AttrImpl(){ assert(m_attribute->_impl == this); m_attribute->_impl = 0; m_attribute->deref();}DOMString AttrImpl::nodeName() const{ return getDocument()->attrName(m_attribute->id());}unsigned short AttrImpl::nodeType() const{ return Node::ATTRIBUTE_NODE;}DOMString AttrImpl::prefix() const{ return m_attribute->prefix();}void AttrImpl::setPrefix(const DOMString &_prefix, int &exceptioncode ){ checkSetPrefix(_prefix, exceptioncode); if (exceptioncode) return; m_attribute->setPrefix(_prefix.implementation());}DOMString AttrImpl::nodeValue() const { return m_attribute->value();}void AttrImpl::setValue( const DOMString &v, int &exceptioncode ){ exceptioncode = 0; // ### according to the DOM docs, we should create an unparsed Text child // node here // do not interprete entities in the string, its literal! // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly if (isReadOnly()) { exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; return; } // ### what to do on 0 ? if (v.isNull()) { exceptioncode = DOMException::DOMSTRING_SIZE_ERR; return; } m_attribute->setValue(v.implementation()); if (m_element) m_element->attributeChanged(m_attribute);}void AttrImpl::setNodeValue( const DOMString &v, int &exceptioncode ){ exceptioncode = 0; // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue() setValue(v, exceptioncode);}NodeImpl *AttrImpl::cloneNode ( bool /*deep*/){ return new AttrImpl(0, docPtr(), m_attribute->clone());}// DOM Section 1.1.1bool AttrImpl::childAllowed( NodeImpl *newChild ){ if(!newChild) return false; return childTypeAllowed(newChild->nodeType());}bool AttrImpl::childTypeAllowed( unsigned short type ){ switch (type) { case Node::TEXT_NODE: case Node::ENTITY_REFERENCE_NODE: return true; break; default: return false; }}DOMString AttrImpl::toString() const{ DOMString result; result += nodeName(); // FIXME: substitute entities for any instances of " or ' -- // maybe easier to just use text value and ignore existing // entity refs? if (firstChild() != NULL) { result += "=\""; for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) { result += child->toString(); } result += "\""; } return result;}// -------------------------------------------------------------------------ElementImpl::ElementImpl(DocumentPtr *doc) : NodeBaseImpl(doc){ namedAttrMap = 0; m_prefix = 0;}ElementImpl::~ElementImpl(){ if (namedAttrMap) { namedAttrMap->detachFromElement(); namedAttrMap->deref(); } if (m_prefix) m_prefix->deref();}void ElementImpl::removeAttribute( NodeImpl::Id id, int &exceptioncode ){ if (namedAttrMap) { namedAttrMap->removeNamedItem(id, exceptioncode); if (exceptioncode == DOMException::NOT_FOUND_ERR) { exceptioncode = 0; } }}void ElementImpl::setAttribute(NodeImpl::Id id, const DOMString &value){ int exceptioncode = 0; setAttribute(id,value.implementation(),exceptioncode);}unsigned short ElementImpl::nodeType() const{ return Node::ELEMENT_NODE;}const AtomicStringList* ElementImpl::getClassList() const{ return 0;}const AtomicString& ElementImpl::getIDAttribute() const{ return namedAttrMap ? namedAttrMap->id() : nullAtom;}const AtomicString& ElementImpl::getAttribute(NodeImpl::Id id) const{ if (namedAttrMap) { AttributeImpl* a = namedAttrMap->getAttributeItem(id); if (a) return a->value(); } return nullAtom;}const AtomicString& ElementImpl::getAttributeNS(const DOMString &namespaceURI, const DOMString &localName) const{ NodeImpl::Id id = getDocument()->attrId(namespaceURI.implementation(), localName.implementation(), true); if (!id) return nullAtom; return getAttribute(id);}void ElementImpl::setAttribute(NodeImpl::Id id, DOMStringImpl* value, int &exceptioncode ){ // allocate attributemap if necessary AttributeImpl* old = attributes(false)->getAttributeItem(id); // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly if (namedAttrMap->isReadOnly()) { exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; return; } if (id == ATTR_ID) { updateId(old ? old->value() : nullAtom, value); } if (old && !value) namedAttrMap->removeAttribute(id); else if (!old && value) namedAttrMap->addAttribute(createAttribute(id, value)); else if (old && value) { old->setValue(value); attributeChanged(old); }}AttributeImpl* ElementImpl::createAttribute(NodeImpl::Id id, DOMStringImpl* value){ return new AttributeImpl(id, value);}void ElementImpl::setAttributeMap( NamedAttrMapImpl* list ){ // If setting the whole map changes the id attribute, we need to // call updateId. AttributeImpl *oldId = namedAttrMap ? namedAttrMap->getAttributeItem(ATTR_ID) : 0; AttributeImpl *newId = list ? list->getAttributeItem(ATTR_ID) : 0; if (oldId || newId) { updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom); } if(namedAttrMap) namedAttrMap->deref(); namedAttrMap = list; if(namedAttrMap) { namedAttrMap->ref(); namedAttrMap->element = this; unsigned int len = namedAttrMap->length(); for(unsigned int i = 0; i < len; i++) attributeChanged(namedAttrMap->attrs[i]); }}bool ElementImpl::hasAttributes() const{ return namedAttrMap && namedAttrMap->length() > 0;}NodeImpl *ElementImpl::cloneNode(bool deep){ // ### we loose the namespace here ... FIXME int exceptioncode; ElementImpl *clone = getDocument()->createElement(tagName(), exceptioncode); if (!clone) return 0; // clone attributes if (namedAttrMap) *(static_cast<NamedAttrMapImpl*>(clone->attributes())) = *namedAttrMap; if (deep) cloneChildNodes(clone); return clone;}DOMString ElementImpl::nodeName() const{ return tagName();}DOMString ElementImpl::tagName() const{ DOMString tn = getDocument()->tagName(id()); if (m_prefix) return DOMString(m_prefix) + ":" + tn; return tn;}void ElementImpl::setPrefix( const DOMString &_prefix, int &exceptioncode ){ checkSetPrefix(_prefix, exceptioncode); if (exceptioncode) return; if (m_prefix) m_prefix->deref(); m_prefix = _prefix.implementation(); if (m_prefix) m_prefix->ref();}void ElementImpl::createAttributeMap() const{ namedAttrMap = new NamedAttrMapImpl(const_cast<ElementImpl*>(this)); namedAttrMap->ref();}bool ElementImpl::isURLAttribute(AttributeImpl *attr) const{ return false; }void ElementImpl::defaultEventHandler(EventImpl *evt){#if APPLE_CHANGES if (evt->id() == EventImpl::KEYPRESS_EVENT && isContentEditable()) { KHTMLPart *part = getDocument()->part(); // Don't treat command-key combos as editing key events if (part && !static_cast<KeyboardEventImpl*>(evt)->metaKey() && KWQ(part)->interceptEditingKeyEvent()) evt->setDefaultHandled(); }#endif NodeBaseImpl::defaultEventHandler(evt);}RenderStyle *ElementImpl::styleForRenderer(RenderObject *parentRenderer){ return getDocument()->styleSelector()->styleForElement(this);}RenderObject *ElementImpl::createRenderer(RenderArena *arena, RenderStyle *style){ if (getDocument()->documentElement() == this && style->display() == NONE) { // Ignore display: none on root elements. Force a display of block in that case. RenderBlock* result = new (arena) RenderBlock(this); if (result) result->setStyle(style); return result; } return RenderObject::createObject(this, style);}void ElementImpl::attach(){#if SPEED_DEBUG < 1 createRendererIfNeeded();#endif NodeBaseImpl::attach(); if (hasID()) { NamedAttrMapImpl *attrs = attributes(true); if (attrs) { AttributeImpl *idAttr = attrs->getAttributeItem(ATTR_ID); if (idAttr && !idAttr->isNull()) { updateId(nullAtom, idAttr->value()); } } }}void ElementImpl::detach(){ if (hasID()) { NamedAttrMapImpl *attrs = attributes(true); if (attrs) { AttributeImpl *idAttr = attrs->getAttributeItem(ATTR_ID); if (idAttr && !idAttr->isNull()) { updateId(idAttr->value(), nullAtom); } } } NodeBaseImpl::detach();}void ElementImpl::recalcStyle( StyleChange change ){ // ### should go away and be done in renderobject RenderStyle* _style = m_render ? m_render->style() : 0; bool hasParentRenderer = parent() ? parent()->renderer() : false; #if 0 const char* debug; switch(change) { case NoChange: debug = "NoChange"; break; case NoInherit: debug= "NoInherit"; break; case Inherit: debug = "Inherit"; break; case Force: debug = "Force"; break; } qDebug("recalcStyle(%d: %s)[%p: %s]", change, debug, this, tagName().string().latin1());#endif if ( hasParentRenderer && (change >= Inherit || changed()) ) { RenderStyle *newStyle = getDocument()->styleSelector()->styleForElement(this); newStyle->ref(); StyleChange ch = diff( _style, newStyle ); if (ch == Detach) { if (attached()) detach(); // ### Suboptimal. Style gets calculated again. attach(); // attach recalulates the style for all children. No need to do it twice. setChanged( false ); setHasChangedChild( false ); newStyle->deref(getDocument()->renderArena()); return; } else if (ch != NoChange) { if( m_render && newStyle ) { //qDebug("--> setting style on render element bgcolor=%s", newStyle->backgroundColor().name().latin1()); m_render->setStyle(newStyle); } } newStyle->deref(getDocument()->renderArena()); if ( change != Force) { if (getDocument()->usesDescendantRules()) change = Force; else change = ch; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -