📄 html_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)
* Copyright (C) 2004 Apple Computer, Inc.
*
* 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 DEBUG
//#define DEBUG_LAYOUT
//#define PAR_DEBUG
//#define EVENT_DEBUG
//#define UNSUPPORTED_ATTR
#include "html/dtd.h"
#include "html/html_elementimpl.h"
#include "html/html_documentimpl.h"
#include "html/htmltokenizer.h"
#include "misc/htmlhashes.h"
#include "editing/visible_text.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "rendering/render_object.h"
#include "rendering/render_replaced.h"
#include "css/css_valueimpl.h"
#include "css/css_stylesheetimpl.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "css/css_ruleimpl.h"
#include "xml/dom_textimpl.h"
#include "xml/dom2_eventsimpl.h"
#include "editing/markup.h"
#include <kdebug.h>
using namespace DOM;
using namespace khtml;
CSSMappedAttributeDeclarationImpl::~CSSMappedAttributeDeclarationImpl() {
if (m_entryType != ePersistent)
HTMLElementImpl::removeMappedAttributeDecl(m_entryType, m_attrName, m_attrValue);
}
QPtrDict<QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> > >* HTMLElementImpl::m_mappedAttributeDecls = 0;
CSSMappedAttributeDeclarationImpl* HTMLElementImpl::getMappedAttributeDecl(MappedAttributeEntry entryType, AttributeImpl* attr)
{
if (!m_mappedAttributeDecls)
return 0;
QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >* attrNameDict = m_mappedAttributeDecls->find((void*)entryType);
if (attrNameDict) {
QPtrDict<CSSMappedAttributeDeclarationImpl>* attrValueDict = attrNameDict->find((void*)attr->id());
if (attrValueDict)
return attrValueDict->find(attr->value().implementation());
}
return 0;
}
void HTMLElementImpl::setMappedAttributeDecl(MappedAttributeEntry entryType, AttributeImpl* attr, CSSMappedAttributeDeclarationImpl* decl)
{
if (!m_mappedAttributeDecls)
m_mappedAttributeDecls = new QPtrDict<QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> > >;
QPtrDict<CSSMappedAttributeDeclarationImpl>* attrValueDict = 0;
QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >* attrNameDict = m_mappedAttributeDecls->find((void*)entryType);
if (!attrNameDict) {
attrNameDict = new QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >;
attrNameDict->setAutoDelete(true);
m_mappedAttributeDecls->insert((void*)entryType, attrNameDict);
}
else
attrValueDict = attrNameDict->find((void*)attr->id());
if (!attrValueDict) {
attrValueDict = new QPtrDict<CSSMappedAttributeDeclarationImpl>;
if (entryType == ePersistent)
attrValueDict->setAutoDelete(true);
attrNameDict->insert((void*)attr->id(), attrValueDict);
}
attrValueDict->replace(attr->value().implementation(), decl);
}
void HTMLElementImpl::removeMappedAttributeDecl(MappedAttributeEntry entryType, NodeImpl::Id attrName, const AtomicString& attrValue)
{
if (!m_mappedAttributeDecls)
return;
QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >* attrNameDict = m_mappedAttributeDecls->find((void*)entryType);
if (!attrNameDict)
return;
QPtrDict<CSSMappedAttributeDeclarationImpl>* attrValueDict = attrNameDict->find((void*)attrName);
if (!attrValueDict)
return;
attrValueDict->remove(attrValue.implementation());
}
void HTMLElementImpl::invalidateStyleAttribute()
{
m_isStyleAttributeValid = false;
}
void HTMLElementImpl::updateStyleAttributeIfNeeded() const
{
if (!m_isStyleAttributeValid) {
m_isStyleAttributeValid = true;
m_synchronizingStyleAttribute = true;
if (m_inlineStyleDecl)
const_cast<HTMLElementImpl*>(this)->setAttribute(ATTR_STYLE, m_inlineStyleDecl->cssText());
m_synchronizingStyleAttribute = false;
}
}
HTMLAttributeImpl::~HTMLAttributeImpl()
{
if (m_styleDecl)
m_styleDecl->deref();
}
AttributeImpl* HTMLAttributeImpl::clone(bool preserveDecl) const
{
return new HTMLAttributeImpl(m_id, _value, preserveDecl ? m_styleDecl : 0);
}
HTMLNamedAttrMapImpl::HTMLNamedAttrMapImpl(ElementImpl *e)
:NamedAttrMapImpl(e), m_mappedAttributeCount(0)
{}
void HTMLNamedAttrMapImpl::clearAttributes()
{
m_classList.clear();
m_mappedAttributeCount = 0;
NamedAttrMapImpl::clearAttributes();
}
bool HTMLNamedAttrMapImpl::isHTMLAttributeMap() const
{
return true;
}
int HTMLNamedAttrMapImpl::declCount() const
{
int result = 0;
for (uint i = 0; i < length(); i++) {
HTMLAttributeImpl* attr = attributeItem(i);
if (attr->decl())
result++;
}
return result;
}
bool HTMLNamedAttrMapImpl::mapsEquivalent(const HTMLNamedAttrMapImpl* otherMap) const
{
// The # of decls must match.
if (declCount() != otherMap->declCount())
return false;
// The values for each decl must match.
for (uint i = 0; i < length(); i++) {
HTMLAttributeImpl* attr = attributeItem(i);
if (attr->decl()) {
AttributeImpl* otherAttr = otherMap->getAttributeItem(attr->id());
if (!otherAttr || (attr->value() != otherAttr->value()))
return false;
}
}
return true;
}
void HTMLNamedAttrMapImpl::parseClassAttribute(const DOMString& classStr)
{
m_classList.clear();
if (!element->hasClass())
return;
DOMString classAttr = element->getDocument()->inCompatMode() ?
(classStr.implementation()->isLower() ? classStr : DOMString(classStr.implementation()->lower())) :
classStr;
if (classAttr.find(' ') == -1 && classAttr.find('\n') == -1)
m_classList.setString(AtomicString(classAttr));
else {
QString val = classAttr.string();
val.replace('\n', ' ');
QStringList list = QStringList::split(' ', val);
AtomicStringList* curr = 0;
for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
const QString& singleClass = *it;
if (!singleClass.isEmpty()) {
if (curr) {
curr->setNext(new AtomicStringList(AtomicString(singleClass)));
curr = curr->next();
}
else {
m_classList.setString(AtomicString(singleClass));
curr = &m_classList;
}
}
}
}
}
// ------------------------------------------------------------------
HTMLElementImpl::HTMLElementImpl(DocumentPtr *doc)
: ElementImpl(doc)
{
m_inlineStyleDecl = 0;
m_isStyleAttributeValid = true;
m_synchronizingStyleAttribute = false;
}
HTMLElementImpl::~HTMLElementImpl()
{
destroyInlineStyleDecl();
}
AttributeImpl* HTMLElementImpl::createAttribute(NodeImpl::Id id, DOMStringImpl* value)
{
return new HTMLAttributeImpl(id, value);
}
bool HTMLElementImpl::isInline() const
{
if (renderer())
return ElementImpl::isInline();
switch(id()) {
case ID_A:
case ID_FONT:
case ID_TT:
case ID_U:
case ID_B:
case ID_I:
case ID_S:
case ID_STRIKE:
case ID_BIG:
case ID_SMALL:
// %phrase
case ID_EM:
case ID_STRONG:
case ID_DFN:
case ID_CODE:
case ID_SAMP:
case ID_KBD:
case ID_VAR:
case ID_CITE:
case ID_ABBR:
case ID_ACRONYM:
// %special
case ID_SUB:
case ID_SUP:
case ID_SPAN:
case ID_NOBR:
case ID_WBR:
return true;
default:
return ElementImpl::isInline();
}
}
void HTMLElementImpl::createInlineStyleDecl()
{
m_inlineStyleDecl = new CSSMutableStyleDeclarationImpl;
m_inlineStyleDecl->ref();
m_inlineStyleDecl->setParent(getDocument()->elementSheet());
m_inlineStyleDecl->setNode(this);
m_inlineStyleDecl->setStrictParsing(!getDocument()->inCompatMode());
}
void HTMLElementImpl::destroyInlineStyleDecl()
{
if (m_inlineStyleDecl) {
m_inlineStyleDecl->setNode(0);
m_inlineStyleDecl->setParent(0);
m_inlineStyleDecl->deref();
m_inlineStyleDecl = 0;
}
}
NodeImpl *HTMLElementImpl::cloneNode(bool deep)
{
HTMLElementImpl *n = static_cast<HTMLElementImpl *>(ElementImpl::cloneNode(deep));
if (n && m_inlineStyleDecl) {
*n->getInlineStyleDecl() = *m_inlineStyleDecl;
}
return n;
}
void HTMLElementImpl::attributeChanged(AttributeImpl* attr, bool preserveDecls)
{
HTMLAttributeImpl* htmlAttr = static_cast<HTMLAttributeImpl*>(attr);
if (htmlAttr->decl() && !preserveDecls) {
htmlAttr->setDecl(0);
setChanged();
if (namedAttrMap)
static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declRemoved();
}
bool checkDecl = true;
MappedAttributeEntry entry;
bool needToParse = mapToEntry(attr->id(), entry);
if (preserveDecls) {
if (htmlAttr->decl()) {
setChanged();
if (namedAttrMap)
static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declAdded();
checkDecl = false;
}
}
else if (!attr->isNull() && entry != eNone) {
CSSMappedAttributeDeclarationImpl* decl = getMappedAttributeDecl(entry, attr);
if (decl) {
htmlAttr->setDecl(decl);
setChanged();
if (namedAttrMap)
static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declAdded();
checkDecl = false;
} else
needToParse = true;
}
if (needToParse)
parseHTMLAttribute(htmlAttr);
if (checkDecl && htmlAttr->decl()) {
// Add the decl to the table in the appropriate spot.
setMappedAttributeDecl(entry, attr, htmlAttr->decl());
htmlAttr->decl()->setMappedState(entry, attr->id(), attr->value());
htmlAttr->decl()->setParent(0);
htmlAttr->decl()->setNode(0);
if (namedAttrMap)
static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declAdded();
}
}
bool HTMLElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
{
switch (attr)
{
case ATTR_ALIGN:
case ATTR_CONTENTEDITABLE:
case ATTR_DIR:
result = eUniversal;
return false;
case ATTR_STYLE:
result = eNone;
return !m_synchronizingStyleAttribute;
default:
break;
}
result = eNone;
return true;
}
void HTMLElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
{
DOMString indexstring;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -