📄 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) * * 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. * * $Id: dom_elementimpl.cpp,v 1.128.2.2 2001/11/02 14:19:04 mueller Exp $ *///#define EVENT_DEBUG#include "dom_elementimpl.h"#include "dom_exception.h"#include "dom_node.h"#include "dom_textimpl.h"#include "dom_docimpl.h"#include "dom2_eventsimpl.h"#include "dtd.h"#include "css/cssstyleselector.h"#include "rendering/render_object.h"#include "misc/htmlhashes.h"#include <kdebug.h>#include "css_valueimpl.h"#include "css_stylesheetimpl.h"#include "html/htmlparser.h"using namespace DOM;using namespace khtml;/* * NOTE: * According to the DOM docs, an Attr stores the value directly in it's parsed * form, but for values containing entities, creates a subtree with nodes * containing the unexpanded form (for XML). On read, the value is always * returned entity-free, so we decided for HTML we could only store a * parsed DOMString and have no child-nodes. */AttrImpl::AttrImpl() : NodeImpl(0), _name( 0 ), _value( 0 ), _element(0), attrId(0){}AttrImpl::AttrImpl(DocumentPtr *doc, const DOMString &name) : NodeImpl(doc), _name( 0 ), _value( 0 ), _element(0), attrId(0){ setName(name);}AttrImpl::AttrImpl(DocumentPtr *doc, int id) : NodeImpl(doc), _name( 0 ), _value( 0 ), _element(0), attrId(id){}AttrImpl::AttrImpl(const AttrImpl &other) : NodeImpl(other.docPtr()){ m_specified = other.specified(); _element = other._element; _name = other._name; if (_name) _name->ref(); _value = other._value; if (_value) _value->ref(); attrId = other.attrId;}AttrImpl &AttrImpl::operator = (const AttrImpl &other){ NodeImpl::operator =(other); m_specified = other.specified(); _element = other._element; if (_name) _name->deref(); _name = other._name; if (_name) _name->ref(); if (_value) _value->deref(); _value = other._value; if (_value) _value->ref(); attrId = other.attrId; return *this;}AttrImpl::~AttrImpl(){ if(_name) _name->deref(); if(_value) _value->deref();}const DOMString AttrImpl::nodeName() const{ return name();}unsigned short AttrImpl::nodeType() const{ return Node::ATTRIBUTE_NODE;}DOMString AttrImpl::name() const{ if(attrId) return getAttrName(attrId); else if (_name) return _name; else return DOMString();}void AttrImpl::setName(const DOMString &n){ if(_name) _name->deref(); _name = n.implementation(); if(!_name) return; attrId = khtml::getAttrID(QConstString(_name->s, _name->l).string().lower().ascii(), _name->l); if (attrId) _name = 0; else _name->ref();}DOMString AttrImpl::value() const { return _value;}void AttrImpl::setValue( const DOMString &v ){ // according to the DOM docs, we should create an unparsed Text child // node here; we decided this was not necessary for HTML // ### TODO: parse value string, interprete entities (not sure if we are supposed to do this) if (_element) _element->checkReadOnly(); DOMStringImpl *prevValue = _value; _value = v.implementation(); if (_value) _value->ref(); m_specified = true; if (_element) { _element->parseAttribute(this); _element->setChanged(true); if (getDocument()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER)) { int exceptioncode; _element->dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,this,prevValue, _value,_name,MutationEvent::MODIFICATION),exceptioncode); } } if (prevValue) prevValue->deref();}void AttrImpl::setNodeValue( const DOMString &v, int &exceptioncode ){ exceptioncode = 0; setValue(v);}AttrImpl::AttrImpl(const DOMString &name, const DOMString &value, DocumentPtr *doc) : NodeImpl(doc){ attrId = 0; _name = 0; setName(name); _value = value.implementation(); if (_value) _value->ref(); _element = 0; m_specified = 1;}AttrImpl::AttrImpl(int _id, const DOMString &value, DocumentPtr *doc) : NodeImpl(doc){ attrId = _id; _name = 0; _value = value.implementation(); if (_value) _value->ref(); _element = 0; m_specified = false;}NodeImpl *AttrImpl::parentNode() const{ return 0;}NodeImpl *AttrImpl::previousSibling() const{ return 0;}NodeImpl *AttrImpl::nextSibling() const{ return 0;}NodeImpl *AttrImpl::cloneNode ( bool /*deep*/, int &/*exceptioncode*/ ){ AttrImpl *newImpl = new AttrImpl(*this); newImpl->_element = 0; // can't have two attributes with the same name/id attached to an element return newImpl;}bool AttrImpl::deleteMe(){ if(!_element && _ref <= 0) return true; return false;}// 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; }}// -------------------------------------------------------------------------ElementImpl::ElementImpl(DocumentPtr *doc) : NodeBaseImpl(doc){ namedAttrMap = 0; has_tabindex=false; tabindex=0; m_styleDecls = 0;}ElementImpl::~ElementImpl(){ if (m_render) detach(); if(namedAttrMap) { namedAttrMap->detachFromElement(); namedAttrMap->deref(); } if (m_styleDecls) { m_styleDecls->setNode(0); m_styleDecls->setParent(0); m_styleDecls->deref(); }}bool ElementImpl::isInline() const{ if(!m_style) return false; return (m_style->display() == khtml::INLINE);}unsigned short ElementImpl::nodeType() const{ return Node::ELEMENT_NODE;}DOMString ElementImpl::tagName() const{ return nodeName();}DOMString ElementImpl::getAttribute( const DOMString &name ) const{ // search in already set attributes first int exceptioncode; // ### propogate if(!namedAttrMap) return DOMString(); AttrImpl *attr = static_cast<AttrImpl*>(namedAttrMap->getNamedItem(name,exceptioncode)); if (attr) return attr->value(); // then search in default attr in case it is not yet set NamedAttrMapImpl* dm = defaultMap(); if(!dm) return DOMString(); AttrImpl* defattr = static_cast<AttrImpl*>(dm->getNamedItem(name, exceptioncode)); if(!defattr || exceptioncode) return DOMString(); return defattr->value();}DOMString ElementImpl::getAttribute( int id ) const{ // search in already set attributes first if(!namedAttrMap) return DOMString(); AttrImpl *attr = static_cast<AttrImpl*>(namedAttrMap->getIdItem(id)); if (attr) return attr->value(); // then search in default attr in case it is not yet set NamedAttrMapImpl* dm = defaultMap(); if(!dm) return DOMString(); AttrImpl* defattr = static_cast<AttrImpl*>(dm->getIdItem(id)); if(!defattr) return DOMString(); return defattr->value();}AttrImpl *ElementImpl::getAttributeNode ( int index ) const{ return namedAttrMap ? namedAttrMap->getIdItem(index) : 0;}int ElementImpl::getAttributeCount() const{ int exceptioncode; // ### propogate return namedAttrMap ? namedAttrMap->length(exceptioncode) : 0;}void ElementImpl::setAttribute( const DOMString &name, const DOMString &value){ // ### check for invalid characters in value -> throw exception int exceptioncode; // ### propogate if(!namedAttrMap) { namedAttrMap = new NamedAttrMapImpl(this); namedAttrMap->ref(); } if (value.isNull()) namedAttrMap->removeNamedItem(name,exceptioncode); else { AttrImpl *a = static_cast<AttrImpl*>(namedAttrMap->getNamedItem(name)); if (a) a->setValue(value); else namedAttrMap->setNamedItem(new AttrImpl(name,value,docPtr()), exceptioncode); }}void ElementImpl::setAttribute( int id, const DOMString &value ){ if(!namedAttrMap) { namedAttrMap = new NamedAttrMapImpl(this); namedAttrMap->ref(); } if (value.isNull()) namedAttrMap->removeIdItem(id); else { int exceptioncode; AttrImpl* a = static_cast<AttrImpl*>(namedAttrMap->getIdItem(id)); if(a) a->setValue(value); else namedAttrMap->setIdItem(new AttrImpl(id,value,docPtr() ), exceptioncode ); }}void ElementImpl::setAttributeMap( NamedAttrMapImpl* list ){ 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++) { AttrImpl* a = namedAttrMap->attrs[i]; if(a && !a->_element) { a->_element = this; parseAttribute(a); } } }}void ElementImpl::removeAttribute( const DOMString &name ){ int exceptioncode; // ### propogate if(!namedAttrMap) return; namedAttrMap->removeNamedItem(name,exceptioncode);}NodeImpl *ElementImpl::cloneNode ( bool deep, int &exceptioncode ){ ElementImpl *newImpl = ownerDocument()->createElement(tagName()); if (!newImpl) return 0; // clone attributes if(namedAttrMap) *(static_cast<NamedAttrMapImpl*>(newImpl->attributes())) = *namedAttrMap; if (deep) cloneChildNodes(newImpl,exceptioncode); return newImpl;}NamedNodeMapImpl *ElementImpl::attributes(){ if(!namedAttrMap) { namedAttrMap = new NamedAttrMapImpl(this); namedAttrMap->ref(); } return namedAttrMap;}AttrImpl *ElementImpl::getAttributeNode( const DOMString &name ){ int exceptioncode; // ### propogate // ### do we return attribute node if it is in the default map but not specified? if(!namedAttrMap) return 0; return static_cast<AttrImpl*>(namedAttrMap->getNamedItem(name,exceptioncode));}Attr ElementImpl::setAttributeNode( AttrImpl *newAttr, int &exceptioncode ){ exceptioncode = 0; if (!newAttr) { exceptioncode = DOMException::NOT_FOUND_ERR; return 0; } if(!namedAttrMap) { namedAttrMap = new NamedAttrMapImpl(this); namedAttrMap->ref(); } if (newAttr->attrId) return namedAttrMap->setIdItem(newAttr, exceptioncode); else return namedAttrMap->setNamedItem(newAttr, exceptioncode);}Attr ElementImpl::removeAttributeNode( AttrImpl *oldAttr, int &exceptioncode ){ // ### should we replace with default in map? currently default attrs don't exist in map exceptioncode = 0; if(!namedAttrMap) return 0; return namedAttrMap->removeAttr(oldAttr, exceptioncode);}NodeListImpl *ElementImpl::getElementsByTagName( const DOMString &name ){ return new TagNodeListImpl( this, name );}short ElementImpl::tabIndex() const{ if (has_tabindex) return tabindex; else return -1;}void ElementImpl::setTabIndex( short _tabindex ){ has_tabindex=true; tabindex=_tabindex;}void ElementImpl::normalize( int &exceptioncode ){ // In DOM level 2, this gets moved to Node // ### normalize attributes? (when we store attributes using child nodes) exceptioncode = 0; NodeImpl *child = _first; while (child) { NodeImpl *nextChild = child->nextSibling(); if (child->nodeType() == Node::ELEMENT_NODE) { static_cast<ElementImpl*>(child)->normalize(exceptioncode); if (exceptioncode) return; child = nextChild; } else if (nextChild && child->nodeType() == Node::TEXT_NODE && nextChild->nodeType() == Node::TEXT_NODE) { static_cast<TextImpl*>(child)->appendData(static_cast<TextImpl*>(nextChild)->data()); removeChild(nextChild,exceptioncode); if (exceptioncode) return; } else child = nextChild; }}NamedAttrMapImpl* ElementImpl::defaultMap() const{ return 0;}void ElementImpl::attach(){ if (!m_render) {#if SPEED_DEBUG < 2 setStyle(ownerDocument()->styleSelector()->styleForElement(this));#if SPEED_DEBUG < 1 if(_parent && _parent->renderer()) { m_render = khtml::RenderObject::createObject(this); if(m_render) { _parent->renderer()->addChild(m_render, nextRenderer()); } }#endif#endif } NodeBaseImpl::attach();}void ElementImpl::detach(){ NodeBaseImpl::detach(); if ( m_render ) m_render->detach(); m_render = 0;}void ElementImpl::recalcStyle(){ if(!m_style) return; EDisplay oldDisplay = m_style->display(); int dynamicState = StyleSelector::None; if ( m_mouseInside ) dynamicState |= StyleSelector::Hover; if ( m_focused ) dynamicState |= StyleSelector::Focus; if ( m_active ) dynamicState |= StyleSelector::Active; setStyle( ownerDocument()->styleSelector()->styleForElement(this, dynamicState) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -