Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F16571283
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
246 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/khtml/css/css_ruleimpl.cpp b/khtml/css/css_ruleimpl.cpp
index f34fe0710c..56ab874ff8 100644
--- a/khtml/css/css_ruleimpl.cpp
+++ b/khtml/css/css_ruleimpl.cpp
@@ -1,515 +1,516 @@
/**
* This file is part of the DOM implementation for KDE.
*
* Copyright 1999-2003 Lars Knoll (knoll@kde.org)
* Copyright 2002-2003 Dirk Mueller (mueller@kde.org)
* Copyright 2002-2008 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "css_ruleimpl.h"
#include "css_stylesheetimpl.h"
#include "css_valueimpl.h"
#include "cssparser.h"
#include <dom/css_rule.h>
#include <dom/css_stylesheet.h>
#include <dom/dom_exception.h>
#include <dom/dom_string.h>
#include <xml/dom_docimpl.h>
using namespace DOM;
#include <kdebug.h>
CSSStyleSheetImpl *CSSRuleImpl::parentStyleSheet() const
{
return ( m_parent && m_parent->isCSSStyleSheet() ) ?
static_cast<CSSStyleSheetImpl *>(m_parent) : 0;
}
CSSRuleImpl *CSSRuleImpl::parentRule() const
{
return ( m_parent && m_parent->isRule() ) ?
static_cast<CSSRuleImpl *>(m_parent) : 0;
}
DOM::DOMString CSSRuleImpl::cssText() const
{
// ###
return DOMString();
}
void CSSRuleImpl::setCssText(DOM::DOMString /*str*/)
{
// ###
}
// ---------------------------------------------------------------------------
CSSFontFaceRuleImpl::CSSFontFaceRuleImpl(StyleBaseImpl *parent)
: CSSRuleImpl(parent)
{
m_type = CSSRule::FONT_FACE_RULE;
m_style = 0;
}
CSSFontFaceRuleImpl::~CSSFontFaceRuleImpl()
{
-; if(m_style) m_style->deref();
+ if (m_style)
+ m_style->deref();
}
void CSSFontFaceRuleImpl::setDeclaration( CSSStyleDeclarationImpl* decl)
{
assert(!m_style);
if (m_style = decl)
m_style->ref();
}
DOMString CSSFontFaceRuleImpl::cssText() const
{
DOMString result("@font-face");
result += " { ";
result += m_style->cssText();
result += "}";
return result;
}
// --------------------------------------------------------------------------
CSSImportRuleImpl::CSSImportRuleImpl( StyleBaseImpl *parent,
const DOM::DOMString &href,
MediaListImpl *media )
: CSSRuleImpl(parent)
{
m_type = CSSRule::IMPORT_RULE;
m_lstMedia = media;
if ( !m_lstMedia )
m_lstMedia = new MediaListImpl( this, DOMString() );
m_lstMedia->setParent( this );
m_lstMedia->ref();
m_strHref = href;
m_styleSheet = 0;
m_cachedSheet = 0;
init();
}
CSSImportRuleImpl::CSSImportRuleImpl( StyleBaseImpl *parent,
const DOM::DOMString &href,
const DOM::DOMString &media )
: CSSRuleImpl(parent)
{
m_type = CSSRule::IMPORT_RULE;
m_lstMedia = new MediaListImpl( this, media );
m_lstMedia->ref();
m_strHref = href;
m_styleSheet = 0;
m_cachedSheet = 0;
init();
}
CSSImportRuleImpl::~CSSImportRuleImpl()
{
if( m_lstMedia ) {
m_lstMedia->setParent( 0 );
m_lstMedia->deref();
}
if(m_styleSheet) {
m_styleSheet->setParent(0);
m_styleSheet->deref();
}
if(m_cachedSheet) m_cachedSheet->deref(this);
}
void CSSImportRuleImpl::checkLoaded() const
{
if (isLoading())
return;
CSSRuleImpl::checkLoaded();
}
void CSSImportRuleImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheetStr, const DOM::DOMString &charset, const DOM::DOMString &mimetype)
{
if ( m_styleSheet ) {
m_styleSheet->setParent(0);
m_styleSheet->deref();
}
m_styleSheet = new CSSStyleSheetImpl(this, url);
m_styleSheet->setCharset(charset);
m_styleSheet->ref();
CSSStyleSheetImpl *parent = parentStyleSheet();
bool strict = parent ? parent->useStrictParsing() : true;
DOMString sheet = sheetStr;
if (strict && !khtml::isAcceptableCSSMimetype(mimetype))
sheet = "";
m_styleSheet->parseString( sheet, strict );
m_loading = false;
m_done = true;
checkLoaded();
}
void CSSImportRuleImpl::error(int /*err*/, const QString &/*text*/)
{
if ( m_styleSheet ) {
m_styleSheet->setParent(0);
m_styleSheet->deref();
}
m_styleSheet = 0;
m_loading = false;
m_done = true;
checkLoaded();
}
bool CSSImportRuleImpl::isLoading() const
{
return ( m_loading || (m_styleSheet && m_styleSheet->isLoading()) );
}
void CSSImportRuleImpl::init()
{
m_loading = 0;
m_done = false;
khtml::DocLoader *docLoader = 0;
StyleBaseImpl *root = this;
StyleBaseImpl *parent;
while ( ( parent = root->parent()) )
root = parent;
if (root->isCSSStyleSheet())
docLoader = static_cast<CSSStyleSheetImpl*>(root)->docLoader();
DOMString absHref = m_strHref;
CSSStyleSheetImpl *parentSheet = parentStyleSheet();
if (!parentSheet->href().isNull()) {
// use parent styleheet's URL as the base URL
absHref = KUrl(KUrl( parentSheet->href().string() ),m_strHref.string()).url();
}
/*
else {
// use documents's URL as the base URL
DocumentImpl *doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
absHref = KUrl(doc->URL(),m_strHref.string()).url();
}
*/
// Check for a cycle in our import chain. If we encounter a stylesheet
// in our parent chain with the same URL, then just bail.
for ( parent = static_cast<StyleBaseImpl*>( this )->parent();
parent;
parent = parent->parent() )
if ( absHref == parent->baseURL().url() )
return;
m_cachedSheet = docLoader->requestStyleSheet(absHref, parentStyleSheet()->charset().string());
if (m_cachedSheet)
{
// if the import rule is issued dynamically, the sheet may have already been
// removed from the pending sheet count, so let the doc know
// the sheet being imported is pending.
checkPending();
m_loading = true;
m_cachedSheet->ref(this);
}
}
DOMString CSSImportRuleImpl::cssText() const
{
DOMString result = "@import url(\"";
result += m_strHref;
result += "\")";
if (m_lstMedia) {
result += " ";
result += m_lstMedia->mediaText();
}
result += ";";
return result;
}
// --------------------------------------------------------------------------
CSSMediaRuleImpl::CSSMediaRuleImpl( StyleBaseImpl *parent, MediaListImpl *mediaList, CSSRuleListImpl *ruleList )
: CSSRuleImpl( parent )
{
m_type = CSSRule::MEDIA_RULE;
m_lstMedia = mediaList;
if (m_lstMedia)
m_lstMedia->ref();
m_lstCSSRules = ruleList;
m_lstCSSRules->ref();
}
CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent)
: CSSRuleImpl( parent )
{
m_type = CSSRule::MEDIA_RULE;
m_lstMedia = 0;
m_lstCSSRules = new CSSRuleListImpl();
m_lstCSSRules->ref();
}
CSSMediaRuleImpl::CSSMediaRuleImpl( StyleBaseImpl *parent, const DOM::DOMString &media )
: CSSRuleImpl( parent )
{
m_type = CSSRule::MEDIA_RULE;
m_lstMedia = new MediaListImpl( this, media );
m_lstMedia->ref();
m_lstCSSRules = new CSSRuleListImpl();
m_lstCSSRules->ref();
}
CSSMediaRuleImpl::~CSSMediaRuleImpl()
{
if( m_lstMedia ) {
m_lstMedia->setParent( 0 );
m_lstMedia->deref();
}
for ( unsigned int i = 0; i < m_lstCSSRules->length(); ++i )
m_lstCSSRules->item( i )->setParent( 0 );
m_lstCSSRules->deref();
}
unsigned long CSSMediaRuleImpl::append( CSSRuleImpl *rule )
{
return rule ? m_lstCSSRules->insertRule( rule, m_lstCSSRules->length() ) : 0;
}
unsigned long CSSMediaRuleImpl::insertRule( const DOMString &rule,
unsigned long index )
{
CSSParser p( strictParsing );
CSSRuleImpl *newRule = p.parseRule( parentStyleSheet(), rule );
return newRule ? m_lstCSSRules->insertRule( newRule, index ) : 0;
}
DOM::DOMString CSSMediaRuleImpl::cssText() const
{
DOMString result("@media ");
if (m_lstMedia) {
result += m_lstMedia->mediaText();
result += " ";
}
result += "{ \n";
if (m_lstCSSRules) {
unsigned len = m_lstCSSRules->length();
for (unsigned i = 0; i < len; i++) {
result += " ";
result += m_lstCSSRules->item(i)->cssText();
result += "\n";
}
}
result += "}";
return result;
}
// ---------------------------------------------------------------------------
CSSPageRuleImpl::CSSPageRuleImpl(StyleBaseImpl *parent)
: CSSRuleImpl(parent)
{
m_type = CSSRule::PAGE_RULE;
m_style = 0;
}
CSSPageRuleImpl::~CSSPageRuleImpl()
{
if(m_style) m_style->deref();
}
DOM::DOMString CSSPageRuleImpl::selectorText() const
{
// ###
return DOMString();
}
void CSSPageRuleImpl::setSelectorText(DOM::DOMString /*str*/)
{
// ###
}
// --------------------------------------------------------------------------
CSSStyleRuleImpl::CSSStyleRuleImpl(StyleBaseImpl *parent)
: CSSRuleImpl(parent)
{
m_type = CSSRule::STYLE_RULE;
m_style = 0;
m_selector = 0;
}
CSSStyleRuleImpl::~CSSStyleRuleImpl()
{
if(m_style) {
m_style->setParent( 0 );
m_style->deref();
}
qDeleteAll(*m_selector);
delete m_selector;
}
DOMString CSSStyleRuleImpl::cssText() const
{
DOMString result(selectorText());
result += " { ";
result += m_style->cssText();
result += "}";
return result;
}
DOM::DOMString CSSStyleRuleImpl::selectorText() const
{
if (m_selector) {
DOMString str;
foreach (CSSSelector *s, *m_selector) {
if (s != m_selector->at(0))
str += ", ";
str += s->selectorText();
}
return str;
}
return DOMString();
}
void CSSStyleRuleImpl::setSelectorText(DOM::DOMString /*str*/)
{
// ###
}
bool CSSStyleRuleImpl::parseString( const DOMString &/*string*/, bool )
{
// ###
return false;
}
void CSSStyleRuleImpl::setDeclaration( CSSStyleDeclarationImpl *style)
{
if ( m_style != style ) {
if(m_style) m_style->deref();
m_style = style;
if(m_style) m_style->ref();
}
}
// --------------------------------------------------------------------
CSSNamespaceRuleImpl::CSSNamespaceRuleImpl(StyleBaseImpl *parent, const DOMString& prefix, const DOMString& ns)
: CSSRuleImpl(parent)
{
m_type = CSSRule::NAMESPACE_RULE;
m_prefix = prefix;
m_namespace = ns;
}
// --------------------------------------------------------------------
CSSRuleListImpl::CSSRuleListImpl(StyleListImpl* const list, bool omitCharsetRules)
{
m_list = list;
if (list && omitCharsetRules) {
m_list = 0;
unsigned len = list->length();
for (unsigned i = 0; i < len; ++i) {
StyleBaseImpl* rule = list->item(i);
if (rule->isRule() && !rule->isCharsetRule())
append(static_cast<CSSRuleImpl*>(rule));
}
} else if (m_list) {
m_list->ref();
}
}
CSSRuleListImpl::~CSSRuleListImpl()
{
CSSRuleImpl* rule;
while ( !m_lstCSSRules.isEmpty() && ( rule = m_lstCSSRules.takeFirst() ) )
rule->deref();
if (m_list)
m_list->deref();
}
unsigned long CSSRuleListImpl::length() const
{
return m_list ? m_list->length() : m_lstCSSRules.count();
}
CSSRuleImpl* CSSRuleListImpl::item(unsigned long index)
{
if (m_list) {
StyleBaseImpl* rule = m_list->item(index);
assert(!rule || rule->isRule());
return static_cast<CSSRuleImpl*>(rule);
}
return index < length() ? m_lstCSSRules.at(index) : 0;
}
void CSSRuleListImpl::deleteRule ( unsigned long index )
{
assert(!m_list);
if (index+1 > (unsigned) m_lstCSSRules.size()) {
return;
// ### Throw INDEX_SIZE_ERR exception here (TODO)
}
CSSRuleImpl *rule = m_lstCSSRules.takeAt( index );
rule->deref();
}
void CSSRuleListImpl::append(CSSRuleImpl* rule)
{
assert(!m_list);
rule->ref();
m_lstCSSRules.append( rule );
}
unsigned long CSSRuleListImpl::insertRule( CSSRuleImpl *rule,
unsigned long index )
{
assert(!m_list);
if (index > (unsigned) m_lstCSSRules.size()) {
return 0;
// ### Throw INDEX_SIZE_ERR exception here (TODO)
}
if( rule )
{
m_lstCSSRules.insert( index, rule );
rule->ref();
return index;
}
return 0;
}
diff --git a/khtml/css/css_valueimpl.cpp b/khtml/css/css_valueimpl.cpp
index dfd9e3e697..1263146746 100644
--- a/khtml/css/css_valueimpl.cpp
+++ b/khtml/css/css_valueimpl.cpp
@@ -1,1643 +1,1643 @@
/**
* This file is part of the DOM implementation for KDE.
*
* Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
* (C) 2004-2008 Apple Computer, Inc.
* (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
* (C) 2009 Germain Garand (germain@ebooksfrance.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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "css_valueimpl.h"
#include "css_ruleimpl.h"
#include "css_stylesheetimpl.h"
#include "css/csshelper.h"
#include "cssparser.h"
#include "cssproperties.h"
#include "cssvalues.h"
#include <dom/css_value.h>
#include <dom/dom_exception.h>
#include <dom/dom_string.h>
#include <xml/dom_stringimpl.h>
#include <xml/dom_docimpl.h>
#include <misc/loader.h>
#include <rendering/font.h>
#include <rendering/render_style.h>
#include <wtf/ASCIICType.h>
#include <kdebug.h>
#include <QtCore/QRegExp>
#include <QtGui/QPaintDevice>
// Hack for debugging purposes
extern DOM::DOMString getPropertyName(unsigned short id);
using khtml::FontDef;
using namespace DOM;
using namespace WTF;
static int propertyID(const DOMString &s)
{
char buffer[maxCSSPropertyNameLength];
unsigned len = s.length();
if (len > maxCSSPropertyNameLength)
return 0;
for (unsigned i = 0; i != len; ++i) {
unsigned short c = s[i].unicode();
if (c == 0 || c >= 0x7F)
return 0; // illegal character
buffer[i] = s[i].toLower().unicode();
}
return getPropertyID(buffer, len);
}
// "ident" from the CSS tokenizer, minus backslash-escape sequences
static bool isCSSTokenizerIdentifier(const DOMString& string)
{
const QChar* p = string.unicode();
const QChar* end = p + string.length();
// -?
if (p != end && p[0] == '-')
++p;
// {nmstart}
if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p->unicode())))
return false;
++p;
// {nmchar}*
for (; p != end; ++p) {
if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p->unicode())))
return false;
}
return true;
}
static DOMString quoteString(const DOMString &string)
{
// FIXME: Also need to transform control characters into \ sequences.
QString s = string.string();
s.replace('\\', "\\\\");
s.replace('\'', "\\'");
return QString('\'' + s + '\'');
}
// Quotes the string if it needs quoting.
static DOMString quoteStringIfNeeded(const DOMString &string)
{
return isCSSTokenizerIdentifier(string) ? string : quoteString(string);
}
CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent)
: StyleBaseImpl(parent)
{
m_lstValues = 0;
m_node = 0;
}
CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent, QList<CSSProperty*> *lstValues)
: StyleBaseImpl(parent)
{
m_lstValues = lstValues;
m_node = 0;
}
CSSStyleDeclarationImpl& CSSStyleDeclarationImpl::operator= (const CSSStyleDeclarationImpl& o)
{
if (this == &o) return *this;
// don't attach it to the same node, just leave the current m_node value
if (m_lstValues)
qDeleteAll(*m_lstValues);
delete m_lstValues;
m_lstValues = 0;
if (o.m_lstValues) {
m_lstValues = new QList<CSSProperty*>;
QListIterator<CSSProperty*> lstValuesIt(*o.m_lstValues);
while ( lstValuesIt.hasNext() )
m_lstValues->append(new CSSProperty(*lstValuesIt.next()));
}
return *this;
}
CSSStyleDeclarationImpl::~CSSStyleDeclarationImpl()
{
if (m_lstValues)
qDeleteAll( *m_lstValues );
delete m_lstValues;
// we don't use refcounting for m_node, to avoid cyclic references (see ElementImpl)
}
CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue(const DOMString &propertyName) const
{
int propID = propertyID(propertyName);
if (!propID)
return 0;
return getPropertyCSSValue(propID);
}
DOMString CSSStyleDeclarationImpl::getPropertyValue(const DOMString &propertyName) const
{
int propID = propertyID(propertyName);
if (!propID)
return DOMString();
return getPropertyValue(propID);
}
DOMString CSSStyleDeclarationImpl::getPropertyPriority(const DOMString &propertyName) const
{
int propID = propertyID(propertyName);
if (!propID)
return DOMString();
return getPropertyPriority(propID) ? "important" : "";
}
void CSSStyleDeclarationImpl::setProperty(const DOMString &propertyName, const DOMString &value, const DOMString &priority)
{
int propID = propertyID(propertyName);
if (!propID) // set exception?
return;
bool important = priority.string().indexOf("important", 0, Qt::CaseInsensitive) != -1;
setProperty(propID, value, important);
}
DOMString CSSStyleDeclarationImpl::removeProperty(const DOMString &propertyName)
{
int propID = propertyID(propertyName);
if (!propID)
return DOMString();
DOMString old;
removeProperty(propID, &old);
return old;
}
DOMString CSSStyleDeclarationImpl::getPropertyValue( int propertyID ) const
{
if(!m_lstValues) return DOMString();
CSSValueImpl* value = getPropertyCSSValue( propertyID );
if ( value )
return value->cssText();
// Shorthand and 4-values properties
switch ( propertyID ) {
case CSS_PROP_BACKGROUND_POSITION:
{
// ## Is this correct? The code in cssparser.cpp is confusing
const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X,
CSS_PROP_BACKGROUND_POSITION_Y };
return getLayeredShortHandValue( properties, 2 );
}
case CSS_PROP_BACKGROUND:
{
const int properties[6] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
CSS_PROP_BACKGROUND_ATTACHMENT,CSS_PROP_BACKGROUND_POSITION_X,
CSS_PROP_BACKGROUND_POSITION_Y, CSS_PROP_BACKGROUND_COLOR };
return getLayeredShortHandValue( properties, 6 );
}
case CSS_PROP_BORDER:
{
const int properties[3][4] = {{ CSS_PROP_BORDER_TOP_WIDTH,
CSS_PROP_BORDER_RIGHT_WIDTH,
CSS_PROP_BORDER_BOTTOM_WIDTH,
CSS_PROP_BORDER_LEFT_WIDTH },
{ CSS_PROP_BORDER_TOP_STYLE,
CSS_PROP_BORDER_RIGHT_STYLE,
CSS_PROP_BORDER_BOTTOM_STYLE,
CSS_PROP_BORDER_LEFT_STYLE },
{ CSS_PROP_BORDER_TOP_COLOR,
CSS_PROP_BORDER_RIGHT_COLOR,
CSS_PROP_BORDER_LEFT_COLOR,
CSS_PROP_BORDER_BOTTOM_COLOR }};
DOMString res;
const int nrprops = sizeof(properties) / sizeof(properties[0]);
for (int i = 0; i < nrprops; ++i) {
DOMString value = getCommonValue(properties[i], 4);
if (!value.isNull()) {
if (!res.isNull())
res += " ";
res += value;
}
}
return res;
}
case CSS_PROP_BORDER_TOP:
{
const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
CSS_PROP_BORDER_TOP_COLOR};
return getShortHandValue( properties, 3 );
}
case CSS_PROP_BORDER_RIGHT:
{
const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
CSS_PROP_BORDER_RIGHT_COLOR};
return getShortHandValue( properties, 3 );
}
case CSS_PROP_BORDER_BOTTOM:
{
const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
CSS_PROP_BORDER_BOTTOM_COLOR};
return getShortHandValue( properties, 3 );
}
case CSS_PROP_BORDER_LEFT:
{
const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
CSS_PROP_BORDER_LEFT_COLOR};
return getShortHandValue( properties, 3 );
}
case CSS_PROP_OUTLINE:
{
const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
CSS_PROP_OUTLINE_COLOR };
return getShortHandValue( properties, 3 );
}
case CSS_PROP_BORDER_COLOR:
{
const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
return get4Values( properties );
}
case CSS_PROP_BORDER_WIDTH:
{
const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
return get4Values( properties );
}
case CSS_PROP_BORDER_STYLE:
{
const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
return get4Values( properties );
}
case CSS_PROP_MARGIN:
{
const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
return get4Values( properties );
}
case CSS_PROP_PADDING:
{
const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
return get4Values( properties );
}
case CSS_PROP_LIST_STYLE:
{
const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
CSS_PROP_LIST_STYLE_IMAGE };
return getShortHandValue( properties, 3 );
}
}
//kDebug() << "property not found:" << propertyID;
return DOMString();
}
// only returns a non-null value if all properties have the same, non-null value
DOMString CSSStyleDeclarationImpl::getCommonValue(const int* properties, int number) const
{
DOMString res;
for (int i = 0; i < number; ++i) {
CSSValueImpl* value = getPropertyCSSValue(properties[i]);
if (!value)
return DOMString();
DOMString text = value->cssText();
if (text.isNull())
return DOMString();
if (res.isNull())
res = text;
else if (res != text)
return DOMString();
}
return res;
}
DOMString CSSStyleDeclarationImpl::get4Values( const int* properties ) const
{
DOMString res;
for ( int i = 0 ; i < 4 ; ++i ) {
if (!isPropertyImplicit(properties[i])) {
CSSValueImpl* value = getPropertyCSSValue( properties[i] );
if ( !value ) { // apparently all 4 properties must be specified.
return DOMString();
}
if ( i > 0 )
res += " ";
res += value->cssText();
}
}
return res;
}
DOMString CSSStyleDeclarationImpl::getLayeredShortHandValue(const int* properties, unsigned number) const
{
DOMString res;
unsigned i;
unsigned j;
// Begin by collecting the properties into an array.
QVector<CSSValueImpl*> values(number);
unsigned numLayers = 0;
for (i = 0; i < number; ++i) {
values[i] = getPropertyCSSValue(properties[i]);
if (values[i]) {
if (values[i]->isValueList()) {
CSSValueListImpl* valueList = static_cast<CSSValueListImpl*>(values[i]);
numLayers = qMax(valueList->length(), (unsigned long)numLayers);
} else
numLayers = qMax(1U, numLayers);
}
}
// Now stitch the properties together. Implicit initial values are flagged as such and
// can safely be omitted.
for (i = 0; i < numLayers; i++) {
DOMString layerRes;
for (j = 0; j < number; j++) {
CSSValueImpl* value = 0;
if (values[j]) {
if (values[j]->isValueList())
value = static_cast<CSSValueListImpl*>(values[j])->item(i);
else {
value = values[j];
// Color only belongs in the last layer.
if (properties[j] == CSS_PROP_BACKGROUND_COLOR) {
if (i != numLayers - 1)
value = 0;
} else if (i != 0) // Other singletons only belong in the first layer.
value = 0;
}
}
if (value && !value->isImplicitInitialValue()) {
if (!layerRes.isNull())
layerRes += " ";
layerRes += value->cssText();
}
}
if (!layerRes.isNull()) {
if (!res.isNull())
res += ", ";
res += layerRes;
}
}
return res;
}
DOMString CSSStyleDeclarationImpl::getShortHandValue( const int* properties, int number ) const
{
DOMString res;
for ( int i = 0 ; i < number ; ++i ) {
CSSValueImpl* value = getPropertyCSSValue( properties[i] );
if ( value ) { // TODO provide default value if !value
if ( !res.isNull() )
res += " ";
res += value->cssText();
}
}
return res;
}
CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue( int propertyID ) const
{
if(!m_lstValues) return 0;
QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
CSSProperty *current;
while ( lstValuesIt.hasNext() ) {
current = lstValuesIt.next();
if (current->m_id == propertyID)
return current->value();
}
return 0;
}
bool CSSStyleDeclarationImpl::isPropertyImplicit(int propertyID) const
{
QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
CSSProperty const *current;
while ( lstValuesIt.hasNext() ) {
current = lstValuesIt.next();
if (current->m_id == propertyID)
- return current->isImplicit();;
+ return current->isImplicit();
}
return false;
}
// --------------- Shorthands mapping ----------------
// In order top be able to remove a shorthand property,
// we need a reverse mapping from the shorthands to their composing properties.
// ### Warning: keep in sync when introducing new shorthands.
struct PropertyLonghand {
PropertyLonghand()
: m_properties(0)
, m_length(0)
{
}
PropertyLonghand(const int* firstProperty, unsigned numProperties)
: m_properties(firstProperty)
, m_length(numProperties)
{
}
const int* properties() const { return m_properties; }
unsigned length() const { return m_length; }
private:
const int* m_properties;
unsigned m_length;
};
static void initShorthandMap(QHash<int, PropertyLonghand>& shorthandMap)
{
#define SET_SHORTHAND_MAP_ENTRY(map, propID, array) \
map.insert(propID, PropertyLonghand(array, sizeof(array) / sizeof(array[0])))
// FIXME: The 'font' property has "shorthand nature" but is not parsed as a shorthand.
// Do not change the order of the following four shorthands, and keep them together.
static const int borderProperties[4][3] = {
{ CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_TOP_WIDTH },
{ CSS_PROP_BORDER_RIGHT_COLOR, CSS_PROP_BORDER_RIGHT_STYLE, CSS_PROP_BORDER_RIGHT_WIDTH },
{ CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_BOTTOM_WIDTH },
{ CSS_PROP_BORDER_LEFT_COLOR, CSS_PROP_BORDER_LEFT_STYLE, CSS_PROP_BORDER_LEFT_WIDTH }
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_TOP, borderProperties[0]);
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RIGHT, borderProperties[1]);
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_BOTTOM, borderProperties[2]);
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_LEFT, borderProperties[3]);
shorthandMap.insert(CSS_PROP_BORDER, PropertyLonghand(borderProperties[0], sizeof(borderProperties) / sizeof(borderProperties[0][0])));
static const int borderColorProperties[] = {
CSS_PROP_BORDER_TOP_COLOR,
CSS_PROP_BORDER_RIGHT_COLOR,
CSS_PROP_BORDER_BOTTOM_COLOR,
CSS_PROP_BORDER_LEFT_COLOR
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_COLOR, borderColorProperties);
static const int borderStyleProperties[] = {
CSS_PROP_BORDER_TOP_STYLE,
CSS_PROP_BORDER_RIGHT_STYLE,
CSS_PROP_BORDER_BOTTOM_STYLE,
CSS_PROP_BORDER_LEFT_STYLE
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_STYLE, borderStyleProperties);
static const int borderWidthProperties[] = {
CSS_PROP_BORDER_TOP_WIDTH,
CSS_PROP_BORDER_RIGHT_WIDTH,
CSS_PROP_BORDER_BOTTOM_WIDTH,
CSS_PROP_BORDER_LEFT_WIDTH
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_WIDTH, borderWidthProperties);
static const int backgroundPositionProperties[] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y };
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND_POSITION, backgroundPositionProperties);
static const int borderSpacingProperties[] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING, CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_SPACING, borderSpacingProperties);
static const int listStyleProperties[] = {
CSS_PROP_LIST_STYLE_IMAGE,
CSS_PROP_LIST_STYLE_POSITION,
CSS_PROP_LIST_STYLE_TYPE
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_LIST_STYLE, listStyleProperties);
static const int marginProperties[] = {
CSS_PROP_MARGIN_TOP,
CSS_PROP_MARGIN_RIGHT,
CSS_PROP_MARGIN_BOTTOM,
CSS_PROP_MARGIN_LEFT
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARGIN, marginProperties);
#ifdef APPLE_CHANGES
static const int marginCollapseProperties[] = { CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE, CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE };
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARGIN_COLLAPSE, marginCollapseProperties);
#endif
static const int marqueeProperties[] = {
CSS_PROP__KHTML_MARQUEE_DIRECTION,
CSS_PROP__KHTML_MARQUEE_INCREMENT,
CSS_PROP__KHTML_MARQUEE_REPETITION,
CSS_PROP__KHTML_MARQUEE_STYLE,
CSS_PROP__KHTML_MARQUEE_SPEED
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARQUEE, marqueeProperties);
static const int outlineProperties[] = {
CSS_PROP_OUTLINE_COLOR,
CSS_PROP_OUTLINE_OFFSET,
CSS_PROP_OUTLINE_STYLE,
CSS_PROP_OUTLINE_WIDTH
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OUTLINE, outlineProperties);
static const int paddingProperties[] = {
CSS_PROP_PADDING_TOP,
CSS_PROP_PADDING_RIGHT,
CSS_PROP_PADDING_BOTTOM,
CSS_PROP_PADDING_LEFT
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_PADDING, paddingProperties);
#ifdef APPLE_CHANGES
static const int textStrokeProperties[] = { CSS_PROP__KHTML_TEXT_STROKE_COLOR, CSS_PROP__KHTML_TEXT_STROKE_WIDTH };
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_TEXT_STROKE, textStrokeProperties);
#endif
static const int backgroundProperties[] = {
CSS_PROP_BACKGROUND_ATTACHMENT,
CSS_PROP_BACKGROUND_COLOR,
CSS_PROP_BACKGROUND_IMAGE,
CSS_PROP_BACKGROUND_POSITION_X,
CSS_PROP_BACKGROUND_POSITION_Y,
CSS_PROP_BACKGROUND_REPEAT,
CSS_PROP__KHTML_BACKGROUND_SIZE,
CSS_PROP_BACKGROUND_SIZE
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND, backgroundProperties);
#ifdef APPLE_CHANGES
static const int columnsProperties[] = { CSS_PROP__KHTML_COLUMN_WIDTH, CSS_PROP__KHTML_COLUMN_COUNT };
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMNS, columnsProperties);
static const int columnRuleProperties[] = {
CSS_PROP__KHTML_COLUMN_RULE_COLOR,
CSS_PROP__KHTML_COLUMN_RULE_STYLE,
CSS_PROP__KHTML_COLUMN_RULE_WIDTH
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMN_RULE, columnRuleProperties);
#endif
static const int overflowProperties[] = { CSS_PROP_OVERFLOW_X, CSS_PROP_OVERFLOW_Y };
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OVERFLOW, overflowProperties);
static const int borderRadiusProperties[] = {
CSS_PROP_BORDER_TOP_RIGHT_RADIUS,
CSS_PROP_BORDER_TOP_LEFT_RADIUS,
CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS,
CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RADIUS, borderRadiusProperties);
static const int prefixedBorderRadiusProperties[] = {
CSS_PROP__KHTML_BORDER_TOP_RIGHT_RADIUS,
CSS_PROP__KHTML_BORDER_TOP_LEFT_RADIUS,
CSS_PROP__KHTML_BORDER_BOTTOM_LEFT_RADIUS,
CSS_PROP__KHTML_BORDER_BOTTOM_RIGHT_RADIUS
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_BORDER_RADIUS, prefixedBorderRadiusProperties);
static const int markerProperties[] = {
CSS_PROP_MARKER_START,
CSS_PROP_MARKER_MID,
CSS_PROP_MARKER_END
};
SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARKER, markerProperties);
#undef SET_SHORTHAND_MAP_ENTRY
}
// -------------------------------------------
void CSSStyleDeclarationImpl::removeProperty(int propertyID,
DOM::DOMString* old)
{
if(!m_lstValues)
return;
static QHash<int, PropertyLonghand> shorthandMap;
if (shorthandMap.isEmpty())
initShorthandMap(shorthandMap);
PropertyLonghand longhand = shorthandMap.value(propertyID);
if (longhand.length()) {
removePropertiesInSet(longhand.properties(), longhand.length());
// FIXME: Return an equivalent shorthand when possible.
return;
}
QMutableListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
CSSProperty *current;
lstValuesIt.toBack();
while ( lstValuesIt.hasPrevious() ) {
current = lstValuesIt.previous();
if (current->m_id == propertyID) {
if (old)
*old = current->value()->cssText();
delete lstValuesIt.value();
lstValuesIt.remove();
setChanged();
break;
}
}
}
void CSSStyleDeclarationImpl::removePropertiesInSet(const int* set, unsigned length)
{
bool changed = false;
for (unsigned i = 0; i < length; i++) {
QMutableListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
CSSProperty *current;
lstValuesIt.toBack();
while ( lstValuesIt.hasPrevious() ) {
current = lstValuesIt.previous();
if (current->m_id == set[i]) {
delete lstValuesIt.value();
lstValuesIt.remove();
changed = true;
break;
}
}
}
if (changed)
setChanged();
}
void CSSStyleDeclarationImpl::setChanged()
{
if (m_node) {
m_node->setChanged();
return;
}
// ### quick&dirty hack for KDE 3.0... make this MUCH better! (Dirk)
for (StyleBaseImpl* stylesheet = this; stylesheet; stylesheet = stylesheet->parent())
if (stylesheet->isCSSStyleSheet()) {
static_cast<CSSStyleSheetImpl*>(stylesheet)->doc()->updateStyleSelector();
break;
}
}
void CSSStyleDeclarationImpl::clear()
{
if (!m_lstValues)
return;
QMutableListIterator<CSSProperty*> it(*m_lstValues);
while (it.hasNext()) {
delete it.next();
it.remove();
}
}
bool CSSStyleDeclarationImpl::getPropertyPriority( int propertyID ) const
{
if ( m_lstValues) {
QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
CSSProperty *current;
while (lstValuesIt.hasNext()) {
current = lstValuesIt.next();
if( propertyID == current->m_id )
return current->m_important;
}
}
return false;
}
bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important, int &ec)
{
ec = 0;
// Setting the value to an empty string just removes the property in both IE and Gecko.
// Setting it to null seems to produce less consistent results, but we treat it just the same.
if (value.isEmpty()) {
removeProperty(id);
return true;
}
bool success = setProperty(id, value, important);
#if 0
if (!success) {
// CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility,
// see <http://bugs.webkit.org/show_bug.cgi?id=7296>.
}
#endif
return success;
}
bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important)
{
if(!m_lstValues) {
m_lstValues = new QList<CSSProperty*>;
}
CSSParser parser( strictParsing );
bool success = parser.parseValue( this, id, value, important );
if(!success)
kDebug( 6080 ) << "CSSStyleDeclarationImpl::setProperty invalid property: [" << getPropertyName(id).string()
<< "] value: [" << value.string() << "]"<< endl;
else
setChanged();
return success;
}
void CSSStyleDeclarationImpl::setProperty(int id, int value, bool important )
{
if(!m_lstValues) {
m_lstValues = new QList<CSSProperty*>;
}
removeProperty(id);
CSSValueImpl * cssValue = new CSSPrimitiveValueImpl(value);
setParsedValue(id, cssValue, important, m_lstValues);
setChanged();
}
void CSSStyleDeclarationImpl::setLengthProperty(int id, const DOM::DOMString &value, bool important, bool _multiLength )
{
bool parseMode = strictParsing;
strictParsing = false;
multiLength = _multiLength;
setProperty( id, value, important );
strictParsing = parseMode;
multiLength = false;
}
void CSSStyleDeclarationImpl::setProperty ( const DOMString &propertyString)
{
if(!m_lstValues) {
m_lstValues = new QList<CSSProperty*>;
}
CSSParser parser( strictParsing );
parser.parseDeclaration( this, propertyString );
setChanged();
}
unsigned long CSSStyleDeclarationImpl::length() const
{
return m_lstValues ? m_lstValues->count() : 0;
}
DOMString CSSStyleDeclarationImpl::item( unsigned long index ) const
{
if(m_lstValues && index < (unsigned)m_lstValues->count() && m_lstValues->at(index))
return getPropertyName(m_lstValues->at(index)->m_id);
return DOMString();
}
CSSRuleImpl *CSSStyleDeclarationImpl::parentRule() const
{
return (m_parent && m_parent->isRule() ) ?
static_cast<CSSRuleImpl *>(m_parent) : 0;
}
DOM::DOMString CSSStyleDeclarationImpl::cssText() const
{
DOMString result;
const CSSProperty* positionXProp = 0;
const CSSProperty* positionYProp = 0;
if ( m_lstValues) {
QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
while (lstValuesIt.hasNext()) {
const CSSProperty* cur = lstValuesIt.next();
if (cur->id() == CSS_PROP_BACKGROUND_POSITION_X)
positionXProp = cur;
else if (cur->id() == CSS_PROP_BACKGROUND_POSITION_Y)
positionYProp = cur;
else
result += cur->cssText();
}
}
// FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
// It is required because background-position-x/y are non-standard properties and generated output
// would not work in Firefox
// It would be a better solution if background-position was CSS_PAIR.
if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) {
DOMString positionValue;
const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y };
if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList())
positionValue = getLayeredShortHandValue(properties, 2);
else
positionValue = positionXProp->value()->cssText() + DOMString(" ") + positionYProp->value()->cssText();
result += DOMString("background-position: ") + positionValue
+ DOMString((positionXProp->isImportant() ? " !important" : ""))
+ DOMString("; ");
} else {
if (positionXProp)
result += positionXProp->cssText();
if (positionYProp)
result += positionYProp->cssText();
}
return result;
}
void CSSStyleDeclarationImpl::setCssText(const DOM::DOMString& text)
{
if (m_lstValues) {
qDeleteAll(*m_lstValues);
m_lstValues->clear();
} else {
m_lstValues = new QList<CSSProperty*>;
}
CSSParser parser( strictParsing );
parser.parseDeclaration( this, text );
setChanged();
}
bool CSSStyleDeclarationImpl::parseString( const DOMString &/*string*/, bool )
{
kDebug() << "WARNING: CSSStyleDeclarationImpl::parseString, unimplemented, was called";
return false;
// ###
}
// --------------------------------------------------------------------------------------
void CSSInlineStyleDeclarationImpl::setChanged()
{
if (m_node)
m_node->setNeedsStyleAttributeUpdate();
CSSStyleDeclarationImpl::setChanged();
}
void CSSInlineStyleDeclarationImpl::updateFromAttribute(const DOMString &value)
{
if(!m_lstValues) {
m_lstValues = new QList<CSSProperty*>;
} else {
clear();
}
CSSParser parser( strictParsing );
parser.parseDeclaration( this, value );
CSSStyleDeclarationImpl::setChanged();
}
// --------------------------------------------------------------------------------------
unsigned short CSSInheritedValueImpl::cssValueType() const
{
return CSSValue::CSS_INHERIT;
}
DOM::DOMString CSSInheritedValueImpl::cssText() const
{
return DOMString("inherit");
}
unsigned short CSSInitialValueImpl::cssValueType() const
{
return CSSValue::CSS_INITIAL;
}
DOM::DOMString CSSInitialValueImpl::cssText() const
{
return DOMString("initial");
}
// ----------------------------------------------------------------------------------------
CSSValueListImpl::~CSSValueListImpl()
{
for (QListIterator<CSSValueImpl*> iterator(m_values); iterator.hasNext();)
iterator.next()->deref();
}
unsigned short CSSValueListImpl::cssValueType() const
{
return CSSValue::CSS_VALUE_LIST;
}
void CSSValueListImpl::append(CSSValueImpl *val)
{
m_values.append(val);
val->ref();
}
DOM::DOMString CSSValueListImpl::cssText() const
{
DOMString result = "";
for (QListIterator<CSSValueImpl*> iterator(m_values); iterator.hasNext();) {
if (!result.isEmpty()) {
if (m_separator == Comma)
result += ", ";
else if (m_separator == Space)
result += " ";
}
result += iterator.next()->cssText();
}
return result;
}
// -------------------------------------------------------------------------------------
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl()
: CSSValueImpl()
{
m_type = 0;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(int ident)
: CSSValueImpl()
{
m_value.ident = ident;
m_type = CSSPrimitiveValue::CSS_IDENT;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(double num, CSSPrimitiveValue::UnitTypes type)
{
m_value.num = num;
m_type = type;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(const DOMString &str, CSSPrimitiveValue::UnitTypes type)
{
m_value.string = str.implementation();
if(m_value.string) m_value.string->ref();
m_type = type;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(CounterImpl *c)
{
m_value.counter = c;
if (m_value.counter)
m_value.counter->ref();
m_type = CSSPrimitiveValue::CSS_COUNTER;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl( RectImpl *r)
{
m_value.rect = r;
if (m_value.rect)
m_value.rect->ref();
m_type = CSSPrimitiveValue::CSS_RECT;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(QRgb color)
{
m_value.rgbcolor = color;
m_type = CSSPrimitiveValue::CSS_RGBCOLOR;
}
CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(PairImpl *p)
{
m_value.pair = p;
if (m_value.pair)
m_value.pair->ref();
m_type = CSSPrimitiveValue::CSS_PAIR;
}
CSSPrimitiveValueImpl::~CSSPrimitiveValueImpl()
{
cleanup();
}
void CSSPrimitiveValueImpl::cleanup()
{
switch(m_type) {
case CSSPrimitiveValue::CSS_STRING:
case CSSPrimitiveValue::CSS_URI:
case CSSPrimitiveValue::CSS_ATTR:
if(m_value.string) m_value.string->deref();
break;
case CSSPrimitiveValue::CSS_COUNTER:
m_value.counter->deref();
break;
case CSSPrimitiveValue::CSS_RECT:
m_value.rect->deref();
break;
case CSSPrimitiveValue::CSS_PAIR:
m_value.pair->deref();
break;
default:
break;
}
m_type = 0;
}
int CSSPrimitiveValueImpl::computeLength( khtml::RenderStyle *style, int logicalDpiY)
{
return snapValue( computeLengthFloat( style, logicalDpiY ) );
}
double CSSPrimitiveValueImpl::computeLengthFloat( khtml::RenderStyle *style, int logicalDpiY)
{
unsigned short type = primitiveType();
double dpiY = 72.; // fallback
if ( logicalDpiY )
dpiY = logicalDpiY;
if ( !khtml::printpainter && dpiY < 96 )
dpiY = 96.;
double factor = 1.;
switch(type)
{
case CSSPrimitiveValue::CSS_EMS:
factor = style->font().pixelSize();
break;
case CSSPrimitiveValue::CSS_EXS:
{
QFontMetrics fm = style->fontMetrics();
factor = fm.xHeight();
break;
}
case CSSPrimitiveValue::CSS_PX:
break;
case CSSPrimitiveValue::CSS_CM:
factor = dpiY/2.54; //72dpi/(2.54 cm/in)
break;
case CSSPrimitiveValue::CSS_MM:
factor = dpiY/25.4;
break;
case CSSPrimitiveValue::CSS_IN:
factor = dpiY;
break;
case CSSPrimitiveValue::CSS_PT:
factor = dpiY/72.;
break;
case CSSPrimitiveValue::CSS_PC:
// 1 pc == 12 pt
factor = dpiY*12./72.;
break;
default:
return -1;
}
return floatValue(type)*factor;
}
int CSSPrimitiveValueImpl::getDPIResolution() const
{
unsigned short type = primitiveType();
double factor = 1.;
switch(type)
{
case CSSPrimitiveValue::CSS_DPI:
break;
case CSSPrimitiveValue::CSS_DPCM:
factor = 2.54;
break;
default:
return -1;
}
return (int)(0.01+floatValue(type)*factor);
}
void CSSPrimitiveValueImpl::setFloatValue( unsigned short unitType, double floatValue, int &exceptioncode )
{
exceptioncode = 0;
cleanup();
// ### check if property supports this type
if(m_type > CSSPrimitiveValue::CSS_DIMENSION) {
exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
return;
}
//if(m_type > CSSPrimitiveValue::CSS_DIMENSION) throw DOMException(DOMException::INVALID_ACCESS_ERR);
m_value.num = floatValue;
m_type = unitType;
}
void CSSPrimitiveValueImpl::setStringValue( unsigned short stringType, const DOMString &stringValue, int &exceptioncode )
{
exceptioncode = 0;
cleanup();
//if(m_type < CSSPrimitiveValue::CSS_STRING) throw DOMException(DOMException::INVALID_ACCESS_ERR);
//if(m_type > CSSPrimitiveValue::CSS_ATTR) throw DOMException(DOMException::INVALID_ACCESS_ERR);
if(m_type < CSSPrimitiveValue::CSS_STRING || m_type > CSSPrimitiveValue::CSS_ATTR) {
exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
return;
}
if(stringType != CSSPrimitiveValue::CSS_IDENT)
{
m_value.string = stringValue.implementation();
m_value.string->ref();
m_type = stringType;
}
// ### parse ident
}
unsigned short CSSPrimitiveValueImpl::cssValueType() const
{
return CSSValue::CSS_PRIMITIVE_VALUE;
}
bool CSSPrimitiveValueImpl::parseString( const DOMString &/*string*/, bool )
{
// ###
kDebug() << "WARNING: CSSPrimitiveValueImpl::parseString, unimplemented, was called";
return false;
}
int CSSPrimitiveValueImpl::getIdent()
{
if(m_type != CSSPrimitiveValue::CSS_IDENT) return 0;
return m_value.ident;
}
DOM::DOMString CSSPrimitiveValueImpl::cssText() const
{
// ### return the original value instead of a generated one (e.g. color
// name if it was specified) - check what spec says about this
DOMString text;
switch ( m_type ) {
case CSSPrimitiveValue::CSS_UNKNOWN:
// ###
break;
case CSSPrimitiveValue::CSS_NUMBER:
// We want to output integral values w/o a period, but others as-is
if ( m_value.num == (int)m_value.num )
text = DOMString(QString::number( (int)m_value.num ));
else
text = DOMString(QString::number( m_value.num ));
break;
case CSSPrimitiveValue::CSS_PERCENTAGE:
text = DOMString(QString::number( m_value.num ) + "%");
break;
case CSSPrimitiveValue::CSS_EMS:
text = DOMString(QString::number( m_value.num ) + "em");
break;
case CSSPrimitiveValue::CSS_EXS:
text = DOMString(QString::number( m_value.num ) + "ex");
break;
case CSSPrimitiveValue::CSS_PX:
text = DOMString(QString::number( m_value.num ) + "px");
break;
case CSSPrimitiveValue::CSS_CM:
text = DOMString(QString::number( m_value.num ) + "cm");
break;
case CSSPrimitiveValue::CSS_MM:
text = DOMString(QString::number( m_value.num ) + "mm");
break;
case CSSPrimitiveValue::CSS_IN:
text = DOMString(QString::number( m_value.num ) + "in");
break;
case CSSPrimitiveValue::CSS_PT:
text = DOMString(QString::number( m_value.num ) + "pt");
break;
case CSSPrimitiveValue::CSS_PC:
text = DOMString(QString::number( m_value.num ) + "pc");
break;
case CSSPrimitiveValue::CSS_DEG:
text = DOMString(QString::number( m_value.num ) + "deg");
break;
case CSSPrimitiveValue::CSS_RAD:
text = DOMString(QString::number( m_value.num ) + "rad");
break;
case CSSPrimitiveValue::CSS_GRAD:
text = DOMString(QString::number( m_value.num ) + "grad");
break;
case CSSPrimitiveValue::CSS_MS:
text = DOMString(QString::number( m_value.num ) + "ms");
break;
case CSSPrimitiveValue::CSS_S:
text = DOMString(QString::number( m_value.num ) + "s");
break;
case CSSPrimitiveValue::CSS_HZ:
text = DOMString(QString::number( m_value.num ) + "hz");
break;
case CSSPrimitiveValue::CSS_KHZ:
text = DOMString(QString::number( m_value.num ) + "khz");
break;
case CSSPrimitiveValue::CSS_DIMENSION:
// ###
break;
case CSSPrimitiveValue::CSS_STRING:
text = quoteStringIfNeeded(m_value.string);
break;
case CSSPrimitiveValue::CSS_URI:
text = "url(";
text += DOMString( m_value.string );
text += ")";
break;
case CSSPrimitiveValue::CSS_IDENT:
text = getValueName(m_value.ident);
break;
case CSSPrimitiveValue::CSS_ATTR:
text = "attr(";
text += DOMString( m_value.string );
text += ")";
break;
case CSSPrimitiveValue::CSS_COUNTER:
text = "counter(";
text += m_value.counter->m_identifier;
text += ")";
// ### add list-style and separator
break;
case CSSPrimitiveValue::CSS_RECT:
{
RectImpl* rectVal = getRectValue();
text = "rect(";
text += rectVal->top()->cssText() + DOMString(" ");
text += rectVal->right()->cssText() + DOMString(" ");
text += rectVal->bottom()->cssText() + DOMString(" ");
text += rectVal->left()->cssText() + DOMString(")");
break;
}
case CSSPrimitiveValue::CSS_RGBCOLOR:
if (qAlpha(m_value.rgbcolor) != 0xFF) {
if (m_value.rgbcolor == khtml::transparentColor)
text = "transparent";
else
text = QString("rgba(" + QString::number(qRed (m_value.rgbcolor)) + ", "
+ QString::number(qGreen(m_value.rgbcolor)) + ", "
+ QString::number(qBlue (m_value.rgbcolor)) + ", "
+ QString::number(qAlpha(m_value.rgbcolor)/255.0) + ")");
} else {
text = QString("rgb(" + QString::number(qRed (m_value.rgbcolor)) + ", "
+ QString::number(qGreen(m_value.rgbcolor)) + ", "
+ QString::number(qBlue (m_value.rgbcolor)) + ")");
}
break;
case CSSPrimitiveValue::CSS_PAIR:
text = m_value.pair->first()->cssText();
text += " ";
text += m_value.pair->second()->cssText();
break;
default:
break;
}
return text;
}
// -----------------------------------------------------------------
RectImpl::RectImpl()
{
m_top = 0;
m_right = 0;
m_bottom = 0;
m_left = 0;
}
RectImpl::~RectImpl()
{
if (m_top) m_top->deref();
if (m_right) m_right->deref();
if (m_bottom) m_bottom->deref();
if (m_left) m_left->deref();
}
void RectImpl::setTop( CSSPrimitiveValueImpl *top )
{
if( top ) top->ref();
if ( m_top ) m_top->deref();
m_top = top;
}
void RectImpl::setRight( CSSPrimitiveValueImpl *right )
{
if( right ) right->ref();
if ( m_right ) m_right->deref();
m_right = right;
}
void RectImpl::setBottom( CSSPrimitiveValueImpl *bottom )
{
if( bottom ) bottom->ref();
if ( m_bottom ) m_bottom->deref();
m_bottom = bottom;
}
void RectImpl::setLeft( CSSPrimitiveValueImpl *left )
{
if( left ) left->ref();
if ( m_left ) m_left->deref();
m_left = left;
}
// -----------------------------------------------------------------
PairImpl::~PairImpl()
{
if (m_first) m_first->deref(); if (m_second) m_second->deref();
}
void PairImpl::setFirst(CSSPrimitiveValueImpl* first)
{
if (first == m_first) return;
if (m_first) m_first->deref();
m_first = first;
if (m_first) m_first->ref();
}
void PairImpl::setSecond(CSSPrimitiveValueImpl* second)
{
if (second == m_second) return;
if (m_second) m_second->deref();
m_second = second;
if (m_second) m_second->ref();
}
// -----------------------------------------------------------------
CSSImageValueImpl::CSSImageValueImpl(const DOMString &url, StyleBaseImpl* style)
: CSSPrimitiveValueImpl(url, CSSPrimitiveValue::CSS_URI)
{
khtml::DocLoader *docLoader = 0;
const StyleBaseImpl *root = style;
while (root->parent())
root = root->parent();
if (root->isCSSStyleSheet())
docLoader = static_cast<const CSSStyleSheetImpl*>(root)->docLoader();
if (docLoader) {
KUrl fullURL( style->baseURL(), khtml::parseURL(url).string() );
m_image = docLoader->requestImage( fullURL.url() );
if(m_image) m_image->ref(this);
}
}
CSSImageValueImpl::CSSImageValueImpl()
: CSSPrimitiveValueImpl(CSS_VAL_NONE)
{
m_image = 0;
}
CSSImageValueImpl::~CSSImageValueImpl()
{
if(m_image) m_image->deref(this);
}
// ------------------------------------------------------------------------
FontFamilyValueImpl::FontFamilyValueImpl( const QString &string)
: CSSPrimitiveValueImpl( DOMString(string), CSSPrimitiveValue::CSS_STRING)
{
static const QRegExp parenReg(" \\(.*\\)$");
// static const QRegExp braceReg(" \\[.*\\]$");
parsedFontName = string;
// a language tag is often added in braces at the end. Remove it.
parsedFontName.replace(parenReg, QString());
#if 0
// cannot use such early checks against the font database anymore,
// as the font subsystem might not contain the requested font yet
// (case of downloadable font faces)
// remove [Xft] qualifiers
parsedFontName.replace(braceReg, QString());
const QString &available = KHTMLSettings::availableFamilies();
parsedFontName = parsedFontName.toLower();
// kDebug(0) << "searching for face '" << parsedFontName << "'";
int pos = available.indexOf( ',' + parsedFontName + ',', 0, Qt::CaseInsensitive );
if ( pos == -1 ) {
// many pages add extra MSs to make sure it's windows only ;(
if ( parsedFontName.startsWith( "ms " ) )
parsedFontName = parsedFontName.mid( 3 );
if ( parsedFontName.endsWith( " ms" ) )
parsedFontName.truncate( parsedFontName.length() - 3 );
pos = available.indexOf( ",ms " + parsedFontName + ',', 0, Qt::CaseInsensitive );
if ( pos == -1 )
pos = available.indexOf( ',' + parsedFontName + " ms,", 0, Qt::CaseInsensitive );
}
if ( pos != -1 ) {
++pos;
int p = available.indexOf(',', pos);
assert( p != -1 ); // available is supposed to start and end with ,
parsedFontName = available.mid( pos, p - pos);
// kDebug(0) << "going for '" << parsedFontName << "'";
}
#endif // !APPLE_CHANGES
}
FontValueImpl::FontValueImpl()
: style(0), variant(0), weight(0), size(0), lineHeight(0), family(0)
{
}
FontValueImpl::~FontValueImpl()
{
delete style;
delete variant;
delete weight;
delete size;
delete lineHeight;
delete family;
}
DOMString FontValueImpl::cssText() const
{
// font variant weight size / line-height family
DOMString result("");
if (style) {
result += style->cssText();
}
if (variant) {
if (result.length() > 0) {
result += " ";
}
result += variant->cssText();
}
if (weight) {
if (result.length() > 0) {
result += " ";
}
result += weight->cssText();
}
if (size) {
if (result.length() > 0) {
result += " ";
}
result += size->cssText();
}
if (lineHeight) {
if (!size) {
result += " ";
}
result += "/";
result += lineHeight->cssText();
}
if (family) {
if (result.length() > 0) {
result += " ";
}
result += family->cssText();
}
return result;
}
QuotesValueImpl::QuotesValueImpl()
: levels(0)
{
}
DOMString QuotesValueImpl::cssText() const
{
return QString("\"" + data.join("\" \"") + "\"");
}
void QuotesValueImpl::addLevel(const QString& open, const QString& close)
{
data.append(open);
data.append(close);
levels++;
}
QString QuotesValueImpl::openQuote(int level) const
{
if (levels == 0) return "";
level--; // increments are calculated before openQuote is called
// kDebug( 6080 ) << "Open quote level:" << level;
if (level < 0) level = 0;
else
if (level >= (int) levels) level = (int) (levels-1);
return data[level*2];
}
QString QuotesValueImpl::closeQuote(int level) const
{
if (levels == 0) return "";
// kDebug( 6080 ) << "Close quote level:" << level;
if (level < 0) level = 0;
else
if (level >= (int) levels) level = (int) (levels-1);
return data[level*2+1];
}
// Used for text-shadow and box-shadow
ShadowValueImpl::ShadowValueImpl(CSSPrimitiveValueImpl* _x, CSSPrimitiveValueImpl* _y,
CSSPrimitiveValueImpl* _blur, CSSPrimitiveValueImpl* _color)
:x(_x), y(_y), blur(_blur), color(_color)
{}
ShadowValueImpl::~ShadowValueImpl()
{
delete x;
delete y;
delete blur;
delete color;
}
DOMString ShadowValueImpl::cssText() const
{
DOMString text("");
if (color) {
text += color->cssText();
}
if (x) {
if (text.length() > 0) {
text += " ";
}
text += x->cssText();
}
if (y) {
if (text.length() > 0) {
text += " ";
}
text += y->cssText();
}
if (blur) {
if (text.length() > 0) {
text += " ";
}
text += blur->cssText();
}
return text;
}
DOMString CounterActImpl::cssText() const
{
DOMString text(m_counter);
text += DOMString(QString::number(m_value));
return text;
}
DOMString CSSProperty::cssText() const
{
return getPropertyName(m_id) + DOMString(": ") + m_value->cssText() + (m_important ? DOMString(" !important") : DOMString()) + DOMString("; ");
}
// -------------------------------------------------------------------------
#if 0
// ENABLE(SVG_FONTS)
bool CSSFontFaceSrcValueImpl::isSVGFontFaceSrc() const
{
return !strcasecmp(m_format, "svg");
}
#endif
bool CSSFontFaceSrcValueImpl::isSupportedFormat() const
{
// Normally we would just check the format, but in order to avoid conflicts with the old WinIE style of font-face,
// we will also check to see if the URL ends with .eot. If so, we'll go ahead and assume that we shouldn't load it.
if (m_format.isEmpty()) {
// Check for .eot.
if (m_resource.endsWith(".eot") || m_resource.endsWith(".EOT"))
return false;
return true;
}
return !strcasecmp(m_format, "truetype") || !strcasecmp(m_format, "opentype") || !strcasecmp(m_format, "woff")
#if 0
//ENABLE(SVG_FONTS)
|| isSVGFontFaceSrc()
#endif
;
}
DOMString CSSFontFaceSrcValueImpl::cssText() const
{
DOMString result;
if (isLocal())
result += "local(";
else
result += "url(";
result += m_resource;
result += ")";
if (!m_format.isEmpty()) {
result += " format(";
result += m_format;
result += ")";
}
return result;
}
diff --git a/khtml/ecma/xmlhttprequest.cpp b/khtml/ecma/xmlhttprequest.cpp
index 83bea66d4f..162cb2b0ab 100644
--- a/khtml/ecma/xmlhttprequest.cpp
+++ b/khtml/ecma/xmlhttprequest.cpp
@@ -1,992 +1,993 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xmlhttprequest.h"
#include "xmlhttprequest.lut.h"
#include "kjs_window.h"
#include "kjs_events.h"
#include "dom/dom_doc.h"
#include "dom/dom_exception.h"
#include "dom/dom_string.h"
#include "misc/loader.h"
#include "misc/translator.h"
#include "html/html_documentimpl.h"
#include "xml/dom2_eventsimpl.h"
#include "khtml_part.h"
#include "khtmlview.h"
#include <kio/scheduler.h>
#include <kio/job.h>
#include <QtCore/QObject>
#include <QtCore/QHash>
#include <kdebug.h>
#include <kio/netaccess.h>
using KIO::NetAccess;
using namespace KJS;
using namespace DOM;
//
////////////////////// XMLHttpRequest Object ////////////////////////
/* Source for XMLHttpRequestProtoTable.
@begin XMLHttpRequestProtoTable 7
abort XMLHttpRequest::Abort DontDelete|Function 0
getAllResponseHeaders XMLHttpRequest::GetAllResponseHeaders DontDelete|Function 0
getResponseHeader XMLHttpRequest::GetResponseHeader DontDelete|Function 1
open XMLHttpRequest::Open DontDelete|Function 5
overrideMimeType XMLHttpRequest::OverrideMIMEType DontDelete|Function 1
send XMLHttpRequest::Send DontDelete|Function 1
setRequestHeader XMLHttpRequest::SetRequestHeader DontDelete|Function 2
@end
*/
namespace KJS {
KJS_DEFINE_PROTOTYPE(XMLHttpRequestProto)
KJS_IMPLEMENT_PROTOFUNC(XMLHttpRequestProtoFunc)
KJS_IMPLEMENT_PROTOTYPE("XMLHttpRequest", XMLHttpRequestProto,XMLHttpRequestProtoFunc, ObjectPrototype)
XMLHttpRequestQObject::XMLHttpRequestQObject(XMLHttpRequest *_jsObject)
{
jsObject = _jsObject;
}
#ifdef APPLE_CHANGES
void XMLHttpRequestQObject::slotData( KIO::Job* job, const char *data, int size )
{
jsObject->slotData(job, data, size);
}
#else
void XMLHttpRequestQObject::slotData( KIO::Job* job, const QByteArray &data )
{
jsObject->slotData(job, data);
}
#endif
void XMLHttpRequestQObject::slotFinished( KJob* job )
{
jsObject->slotFinished(job);
}
void XMLHttpRequestQObject::slotRedirection( KIO::Job* job, const KUrl& url)
{
jsObject->slotRedirection( job, url );
}
XMLHttpRequestConstructorImp::XMLHttpRequestConstructorImp(ExecState *exec, DOM::DocumentImpl* d)
: JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), doc(d)
{
JSObject* proto = XMLHttpRequestProto::self(exec);
putDirect(exec->propertyNames().prototype, proto, DontDelete|ReadOnly);
}
bool XMLHttpRequestConstructorImp::implementsConstruct() const
{
return true;
}
JSObject *XMLHttpRequestConstructorImp::construct(ExecState *exec, const List &)
{
return new XMLHttpRequest(exec, doc.get());
}
const ClassInfo XMLHttpRequest::info = { "XMLHttpRequest", 0, &XMLHttpRequestTable, 0 };
/* Source for XMLHttpRequestTable.
@begin XMLHttpRequestTable 7
readyState XMLHttpRequest::ReadyState DontDelete|ReadOnly
responseText XMLHttpRequest::ResponseText DontDelete|ReadOnly
responseXML XMLHttpRequest::ResponseXML DontDelete|ReadOnly
status XMLHttpRequest::Status DontDelete|ReadOnly
statusText XMLHttpRequest::StatusText DontDelete|ReadOnly
onreadystatechange XMLHttpRequest::Onreadystatechange DontDelete
onload XMLHttpRequest::Onload DontDelete
@end
*/
bool XMLHttpRequest::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
{
return getStaticValueSlot<XMLHttpRequest, DOMObject>(exec, &XMLHttpRequestTable, this, propertyName, slot);
}
JSValue *XMLHttpRequest::getValueProperty(ExecState *exec, int token) const
{
switch (token) {
case ReadyState:
return jsNumber(m_state);
case ResponseText:
return ::getStringOrNull(DOM::DOMString(response));
case ResponseXML:
if (m_state != XHRS_Loaded) {
return jsNull();
}
if (!createdDocument) {
QString mimeType = "text/xml";
if (!m_mimeTypeOverride.isEmpty()) {
mimeType = m_mimeTypeOverride;
} else {
int dummy;
JSValue *header = getResponseHeader("Content-Type", dummy);
if (header->type() != UndefinedType)
mimeType = header->toString(exec).qstring().split(";")[0].trimmed();
}
if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "application/xhtml+xml") {
responseXML = doc->implementation()->createDocument();
responseXML->open();
responseXML->setURL(url.url());
responseXML->write(response);
responseXML->finishParsing();
responseXML->close();
typeIsXML = true;
} else {
typeIsXML = false;
}
createdDocument = true;
}
if (!typeIsXML) {
return jsNull();
}
return getDOMNode(exec,responseXML.get());
case Status:
return getStatus();
case StatusText:
return getStatusText();
case Onreadystatechange:
if (onReadyStateChangeListener && onReadyStateChangeListener->listenerObj()) {
return onReadyStateChangeListener->listenerObj();
} else {
return jsNull();
}
case Onload:
if (onLoadListener && onLoadListener->listenerObj()) {
return onLoadListener->listenerObj();
} else {
return jsNull();
}
default:
kWarning() << "XMLHttpRequest::getValueProperty unhandled token " << token;
return 0;
}
}
void XMLHttpRequest::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
{
lookupPut<XMLHttpRequest,DOMObject>(exec, propertyName, value, attr, &XMLHttpRequestTable, this );
}
void XMLHttpRequest::putValueProperty(ExecState *exec, int token, JSValue *value, int /*attr*/)
{
switch(token) {
case Onreadystatechange:
if (onReadyStateChangeListener) onReadyStateChangeListener->deref();
onReadyStateChangeListener = Window::retrieveActive(exec)->getJSEventListener(value, true);
if (onReadyStateChangeListener) onReadyStateChangeListener->ref();
break;
case Onload:
if (onLoadListener) onLoadListener->deref();
onLoadListener = Window::retrieveActive(exec)->getJSEventListener(value, true);
if (onLoadListener) onLoadListener->ref();
break;
default:
kWarning() << "XMLHttpRequest::putValue unhandled token " << token;
}
}
// Token according to RFC 2616
static bool isValidFieldName(const QString& name)
{
- const QChar* c = name.constData();
int l = name.length();
if (l == 0)
return false;
+
+ const QChar* c = name.constData();
for (int i = 0; i < l; ++i, ++c) {
int u = c->unicode();
if (u < 32 || u > 126)
return false;
switch (u) {
case '(': case ')': case '<': case '>':
case '@': case ',': case ';': case ':':
case '\\': case '"': case '/':
case '[': case ']': case '?': case '=':
case '{': case '}': case '\t': case ' ':
return false;
default:
break;
}
}
return true;
}
static bool isValidFieldValue(const QString& name)
{
- const QChar* c = name.constData();
int l = name.length();
if (l == 0)
return true;
+ const QChar* c = name.constData();
for (int i = 0; i < l; ++i, ++c) {
int u = c->unicode();
- if ( u == '\n' || u == '\r' )
- return false;
+ if ( u == '\n' || u == '\r' )
+ return false;
}
// ### what is invalid?
return true;
}
static bool canSetRequestHeader(const QString& name)
{
static QSet<CaseInsensitiveString> forbiddenHeaders;
if (forbiddenHeaders.isEmpty()) {
static const char* const hdrs[] = {
"accept-charset",
"accept-encoding",
"content-length",
"connect",
"copy",
"date",
"delete",
"expect",
"head",
"host",
"keep-alive",
"lock",
"mkcol",
"move",
"options",
"put",
"propfind",
"proppatch",
"proxy-authorization",
"referer",
"te",
"trace",
"trailer",
"transfer-encoding",
"unlock",
"upgrade",
"via"
};
for (size_t i = 0; i < sizeof(hdrs)/sizeof(char*); ++i)
forbiddenHeaders.insert(CaseInsensitiveString(hdrs[i]));
}
return !forbiddenHeaders.contains(name);
}
XMLHttpRequest::XMLHttpRequest(ExecState *exec, DOM::DocumentImpl* d)
: qObject(new XMLHttpRequestQObject(this)),
doc(d),
async(true),
contentType(QString()),
job(0),
m_state(XHRS_Uninitialized),
onReadyStateChangeListener(0),
onLoadListener(0),
decoder(0),
binaryMode(false),
response(QString::fromLatin1("")),
createdDocument(false),
aborted(false)
{
ref(); // we're a GC point, so refcount pin.
setPrototype(XMLHttpRequestProto::self(exec));
}
XMLHttpRequest::~XMLHttpRequest()
{
if (job && m_method != QLatin1String("POST")) {
job->kill();
job = 0;
}
if (onLoadListener)
onLoadListener->deref();
if (onReadyStateChangeListener)
onReadyStateChangeListener->deref();
delete qObject;
qObject = 0;
delete decoder;
decoder = 0;
}
void XMLHttpRequest::changeState(XMLHttpRequestState newState)
{
// Other engines cancel transfer if the controlling document doesn't
// exist anymore. Match that, though being paranoid about post
// (And don't emit any events w/o a doc, if we're kept alive otherwise).
if (!doc) {
if (job && m_method != QLatin1String("POST")) {
job->kill();
job = 0;
}
return;
}
if (m_state != newState) {
m_state = newState;
ProtectedPtr<JSObject> ref(this);
if (onReadyStateChangeListener != 0 && doc->view() && doc->view()->part()) {
DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents");
ev.initEvent("readystatechange", true, true);
ev.handle()->setTarget(this);
ev.handle()->setCurrentTarget(this);
onReadyStateChangeListener->handleEvent(ev);
// Make sure the event doesn't point to us, since it can't prevent
// us from being collecte.
ev.handle()->setTarget(0);
ev.handle()->setCurrentTarget(0);
}
if (m_state == XHRS_Loaded && onLoadListener != 0 && doc->view() && doc->view()->part()) {
DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents");
ev.initEvent("load", true, true);
ev.handle()->setTarget(this);
ev.handle()->setCurrentTarget(this);
onLoadListener->handleEvent(ev);
ev.handle()->setTarget(0);
ev.handle()->setCurrentTarget(0);
}
}
}
bool XMLHttpRequest::urlMatchesDocumentDomain(const KUrl& _url) const
{
// No need to do work if _url is not valid...
if (!_url.isValid())
return false;
KUrl documentURL(doc->URL());
// a local file can load anything
if (documentURL.protocol().toLower() == "file") {
return true;
}
// but a remote document can only load from the same port on the server
if (documentURL.protocol().toLower() == _url.protocol().toLower() &&
documentURL.host().toLower() == _url.host().toLower() &&
documentURL.port() == _url.port()) {
return true;
}
return false;
}
// Methods we're to recognize per the XHR spec (3.6.1, #3).
// We map it to whether the method should be permitted or not (#4)
static const IDTranslator<QByteArray, bool, const char*>::Info methodsTable[] = {
{"CONNECT", false},
{"DELETE", true},
{"GET", true},
{"HEAD", true},
{"OPTIONS", true},
{"POST", true},
{"PUT", true},
{"TRACE", false},
{"TRACK", false},
{0, false}
};
MAKE_TRANSLATOR(methodsLookup, QByteArray, bool, const char*, methodsTable)
void XMLHttpRequest::open(const QString& _method, const KUrl& _url, bool _async, int& ec)
{
abort();
aborted = false;
// clear stuff from possible previous load
m_requestHeaders.clear();
responseHeaders.clear();
response = QString::fromLatin1("");
createdDocument = false;
responseXML = 0;
if (!urlMatchesDocumentDomain(_url)) {
ec = DOMException::SECURITY_ERR;
return;
}
// ### potentially raise a SYNTAX_ERR
// Lookup if the method is well-known, and if so check if it's OK
QByteArray methodNormalized = _method.toUpper().toUtf8();
if (methodsLookup()->hasLeft(methodNormalized)) {
if (methodsLookup()->toRight(methodNormalized)) {
// OK, replace with the canonical version...
m_method = _method.toUpper();
} else {
// Scary stuff like CONNECT
ec = DOMException::SECURITY_ERR;
return;
}
} else {
// Unknown -> pass through unchanged
m_method = _method;
}
url = _url;
async = _async;
changeState(XHRS_Open);
}
void XMLHttpRequest::send(const QString& _body, int& ec)
{
aborted = false;
if (m_state != XHRS_Open) {
ec = DOMException::INVALID_STATE_ERR;
return;
}
const QString protocol = url.protocol().toLower();
// Abandon the request when the protocol is other than "http",
// instead of blindly doing a KIO::get on other protocols like file:/.
if (!protocol.startsWith(QLatin1String("http")) &&
!protocol.startsWith(QLatin1String("webdav")))
{
ec = DOMException::INVALID_ACCESS_ERR;
abort();
return;
}
// We need to use a POST-like setup even for non-post whenever we
// have a payload.
if (m_method == QLatin1String("POST") || !_body.isEmpty()) {
// FIXME: determine post encoding correctly by looking in headers
// for charset.
QByteArray buf = _body.toUtf8();
job = KIO::http_post( url, buf, KIO::HideProgressInfo );
if(contentType.isNull())
job->addMetaData( "content-type", "Content-type: text/plain" );
else
job->addMetaData( "content-type", contentType );
}
else {
job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo );
}
// Regardless of job type, make sure the method is set
job->addMetaData("CustomHTTPMethod", m_method);
if (!m_requestHeaders.isEmpty()) {
QString rh;
HTTPHeaderMap::ConstIterator begin = m_requestHeaders.constBegin();
HTTPHeaderMap::ConstIterator end = m_requestHeaders.constEnd();
for (HTTPHeaderMap::ConstIterator i = begin; i != end; ++i) {
QString key = i.key().original();
QString value = i.value();
if (key.toLower() == "accept") {
// The HTTP KIO slave supports an override this way
job->addMetaData("accept", value);
} else {
if (!rh.isEmpty())
rh += "\r\n";
rh += key + ": " + value;
}
}
job->addMetaData("customHTTPHeader", rh);
}
job->addMetaData("PropagateHttpHeader", "true");
// Set the default referrer. NOTE: the user can still disable
// this feature at the protocol level (kio_http).
KUrl documentURL(doc->URL());
documentURL.setPass(QString());
documentURL.setUser(QString());
job->addMetaData("referrer", documentURL.url());
// kDebug() << "Adding referrer: " << documentURL;
if (!async) {
QByteArray data;
KUrl finalURL;
QString headers;
#ifdef APPLE_CHANGES
data = KWQServeSynchronousRequest(khtml::Cache::loader(), doc->docLoader(), job, finalURL, headers);
#else
QMap<QString, QString> metaData;
if ( NetAccess::synchronousRun( job, 0, &data, &finalURL, &metaData ) ) {
headers = metaData[ "HTTP-Headers" ];
}
#endif
job = 0;
processSyncLoadResults(data, finalURL, headers);
return;
}
qObject->connect( job, SIGNAL(result(KJob*)),
SLOT(slotFinished(KJob*)) );
#ifdef APPLE_CHANGES
qObject->connect( job, SIGNAL(data(KIO::Job*,const char*,int)),
SLOT(slotData(KIO::Job*,const char*,int)) );
#else
qObject->connect( job, SIGNAL(data(KIO::Job*,QByteArray)),
SLOT(slotData(KIO::Job*,QByteArray)) );
#endif
qObject->connect( job, SIGNAL(redirection(KIO::Job*,KUrl)),
SLOT(slotRedirection(KIO::Job*,KUrl)) );
#ifdef APPLE_CHANGES
KWQServeRequest(khtml::Cache::loader(), doc->docLoader(), job);
#else
KIO::Scheduler::setJobPriority( job, 1 );
#endif
}
void XMLHttpRequest::clearDecoder()
{
delete decoder;
decoder = 0;
binaryMode = false;
}
void XMLHttpRequest::abort()
{
if (job) {
job->kill();
job = 0;
}
aborted = true;
clearDecoder();
changeState(XHRS_Uninitialized);
}
void XMLHttpRequest::overrideMIMEType(const QString& override)
{
m_mimeTypeOverride = override;
}
void XMLHttpRequest::setRequestHeader(const QString& _name, const QString& _value, int& ec)
{
// throw exception if connection is not open or the send flag is set
if (m_state != XHRS_Open || job != 0) {
ec = DOMException::INVALID_STATE_ERR;
return;
}
if (!isValidFieldName(_name) || !isValidFieldValue(_value)) {
ec = DOMException::SYNTAX_ERR;
return;
}
QString name = _name.toLower();
QString value = _value.trimmed();
if (value.isEmpty())
return;
// Content-type needs to be set separately from the other headers
if(name == "content-type") {
contentType = "Content-type: " + value;
return;
}
// Sanitize the referrer header to protect against spoofing...
if(name == "referer") {
KUrl referrerURL(value);
if (urlMatchesDocumentDomain(referrerURL))
m_requestHeaders[name] = referrerURL.url();
return;
}
// Sanitize the request headers below and handle them as if they are
// calls to open. Otherwise, we will end up ignoring them all together!
// TODO: Do something about "put" which kio_http sort of supports and
// the webDAV headers such as PROPFIND etc...
if (name == "get" || name == "post") {
KUrl reqURL (doc->URL(), value.trimmed());
open(name, reqURL, async, ec);
return;
}
// Reject all banned headers.
if (!canSetRequestHeader(_name)) {
kWarning(6070) << "Refusing to set unsafe XMLHttpRequest header "
<< name << endl;
return;
}
m_requestHeaders[_name] = value;
}
JSValue *XMLHttpRequest::getAllResponseHeaders(int& ec) const
{
if (m_state < XHRS_Receiving) {
ec = DOMException::INVALID_STATE_ERR;
return jsString("");
}
// ### test error flag, return jsNull
if (responseHeaders.isEmpty()) {
return jsUndefined();
}
int endOfLine = responseHeaders.indexOf("\n");
if (endOfLine == -1) {
return jsUndefined();
}
return jsString(responseHeaders.mid(endOfLine + 1) + '\n');
}
JSValue *XMLHttpRequest::getResponseHeader(const QString& name, int& ec) const
{
if (m_state < XHRS_Receiving) {
ec = DOMException::INVALID_STATE_ERR;
return jsString("");
}
if (!isValidFieldName(name)) {
return jsString("");
}
// ### test error flag, return jsNull
if (responseHeaders.isEmpty()) {
return jsUndefined();
}
QRegExp headerLinePattern(name + ':', Qt::CaseInsensitive);
int matchLength;
int headerLinePos = headerLinePattern.indexIn(responseHeaders, 0);
matchLength = headerLinePattern.matchedLength();
while (headerLinePos != -1) {
if (headerLinePos == 0 || responseHeaders[headerLinePos-1] == '\n') {
break;
}
headerLinePos = headerLinePattern.indexIn(responseHeaders, headerLinePos + 1);
matchLength = headerLinePattern.matchedLength();
}
if (headerLinePos == -1) {
return jsNull();
}
int endOfLine = responseHeaders.indexOf("\n", headerLinePos + matchLength);
return jsString(responseHeaders.mid(headerLinePos + matchLength, endOfLine - (headerLinePos + matchLength)).trimmed());
}
static JSValue *httpStatus(const QString& response, bool textStatus = false)
{
if (response.isEmpty()) {
return jsUndefined();
}
int endOfLine = response.indexOf("\n");
QString firstLine = (endOfLine == -1) ? response : response.left(endOfLine);
int codeStart = firstLine.indexOf(" ");
int codeEnd = firstLine.indexOf(" ", codeStart + 1);
if (codeStart == -1 || codeEnd == -1) {
return jsUndefined();
}
if (textStatus) {
QString statusText = firstLine.mid(codeEnd + 1, endOfLine - (codeEnd + 1)).trimmed();
return jsString(statusText);
}
QString number = firstLine.mid(codeStart + 1, codeEnd - (codeStart + 1));
bool ok = false;
int code = number.toInt(&ok);
if (!ok) {
return jsUndefined();
}
return jsNumber(code);
}
JSValue *XMLHttpRequest::getStatus() const
{
return httpStatus(responseHeaders);
}
JSValue *XMLHttpRequest::getStatusText() const
{
return httpStatus(responseHeaders, true);
}
void XMLHttpRequest::processSyncLoadResults(const QByteArray &data, const KUrl &finalURL, const QString &headers)
{
if (!urlMatchesDocumentDomain(finalURL)) {
abort();
return;
}
responseHeaders = headers;
changeState(XHRS_Sent);
if (aborted) {
return;
}
#ifdef APPLE_CHANGES
const char *bytes = (const char *)data.data();
int len = (int)data.size();
slotData(0, bytes, len);
#else
slotData(0, data);
#endif
if (aborted) {
return;
}
slotFinished(0);
}
void XMLHttpRequest::slotFinished(KJob *)
{
if (decoder) {
response += decoder->flush();
}
// make sure to forget about the job before emitting completed,
// since changeState triggers JS code, which might e.g. call abort.
job = 0;
changeState(XHRS_Loaded);
clearDecoder();
}
void XMLHttpRequest::slotRedirection(KIO::Job*, const KUrl& url)
{
if (!urlMatchesDocumentDomain(url)) {
abort();
}
}
static QString encodingFromContentType(const QString& type)
{
QString encoding;
int index = type.indexOf(';');
if (index > -1)
encoding = type.mid( index+1 ).remove(QRegExp("charset[ ]*=[ ]*", Qt::CaseInsensitive)).trimmed();
return encoding;
}
#ifdef APPLE_CHANGES
void XMLHttpRequest::slotData( KIO::Job*, const char *data, int len )
#else
void XMLHttpRequest::slotData(KIO::Job*, const QByteArray &_data)
#endif
{
if (m_state < XHRS_Sent ) {
responseHeaders = job->queryMetaData("HTTP-Headers");
// NOTE: Replace a 304 response with a 200! Both IE and Mozilla do this.
// Problem first reported through bug# 110272.
int codeStart = responseHeaders.indexOf("304");
if ( codeStart != -1) {
int codeEnd = responseHeaders.indexOf("\n", codeStart+3);
if (codeEnd != -1)
responseHeaders.replace(codeStart, (codeEnd-codeStart), "200 OK");
}
changeState(XHRS_Sent);
}
#ifndef APPLE_CHANGES
const char *data = (const char *)_data.data();
int len = (int)_data.size();
#endif
if ( !decoder && !binaryMode ) {
if (!m_mimeTypeOverride.isEmpty())
encoding = encodingFromContentType(m_mimeTypeOverride);
if (encoding.isEmpty()) {
int pos = responseHeaders.indexOf(QLatin1String("content-type:"), 0, Qt::CaseInsensitive);
if ( pos > -1 ) {
pos += 13;
int index = responseHeaders.indexOf('\n', pos);
QString type = responseHeaders.mid(pos, (index-pos));
encoding = encodingFromContentType(type);
}
}
if (encoding == QLatin1String("x-user-defined")) {
binaryMode = true;
} else {
decoder = new KEncodingDetector;
if (!encoding.isEmpty())
decoder->setEncoding(encoding.toLatin1().constData(), KEncodingDetector::EncodingFromHTTPHeader);
else
decoder->setEncoding("UTF-8", KEncodingDetector::DefaultEncoding);
}
}
if (len == 0)
return;
if (len == -1)
len = strlen(data);
QString decoded;
if (binaryMode)
decoded = QString::fromLatin1(data, len);
else
decoded = decoder->decodeWithBuffering(data, len);
response += decoded;
if (!aborted) {
changeState(XHRS_Receiving);
}
}
JSValue *XMLHttpRequestProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
{
if (!thisObj->inherits(&XMLHttpRequest::info)) {
return throwError(exec, TypeError);
}
XMLHttpRequest *request = static_cast<XMLHttpRequest *>(thisObj);
if (!request->doc) {
setDOMException(exec, DOMException::INVALID_STATE_ERR);
return jsUndefined();
}
int ec = 0;
switch (id) {
case XMLHttpRequest::Abort:
request->abort();
return jsUndefined();
case XMLHttpRequest::GetAllResponseHeaders:
{
JSValue *ret = request->getAllResponseHeaders(ec);
setDOMException(exec, ec);
return ret;
}
case XMLHttpRequest::GetResponseHeader:
{
if (args.size() < 1)
return throwError(exec, SyntaxError, "Not enough arguments");
JSValue *ret = request->getResponseHeader(args[0]->toString(exec).qstring(), ec);
setDOMException(exec, ec);
return ret;
}
case XMLHttpRequest::Open:
{
if (args.size() < 2)
return throwError(exec, SyntaxError, "Not enough arguments");
QString method = args[0]->toString(exec).qstring();
KUrl url = KUrl(request->doc->completeURL(args[1]->toString(exec).qstring()));
bool async = true;
if (args.size() >= 3) {
async = args[2]->toBoolean(exec);
}
if (args.size() >= 4) {
url.setUser(args[3]->toString(exec).qstring());
}
if (args.size() >= 5) {
url.setPass(args[4]->toString(exec).qstring());
}
request->open(method, url, async, ec);
setDOMException(exec, ec);
return jsUndefined();
}
case XMLHttpRequest::Send:
{
QString body;
if (!args[0]->isUndefinedOrNull()
// make sure we don't marshal "undefined" or such;
&& request->m_method != QLatin1String("GET")
&& request->m_method != QLatin1String("HEAD")) {
// ... or methods that don't have payload
DOM::NodeImpl* docNode = toNode(args[0]);
if (docNode && docNode->isDocumentNode()) {
DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(docNode);
body = doc->toString().string();
// FIXME: also need to set content type, including encoding!
} else {
body = args[0]->toString(exec).qstring();
}
}
request->send(body, ec);
setDOMException(exec, ec);
return jsUndefined();
}
case XMLHttpRequest::SetRequestHeader:
{
if (args.size() < 2)
return throwError(exec, SyntaxError, "Not enough arguments");
JSValue* keyArgument = args[0];
JSValue* valArgument = args[1];
QString key, val;
if (!keyArgument->isUndefined() && !keyArgument->isNull())
key = keyArgument->toString(exec).qstring();
if (!valArgument->isUndefined() && !valArgument->isNull())
val = valArgument->toString(exec).qstring();
request->setRequestHeader(key, val, ec);
setDOMException(exec, ec);
return jsUndefined();
}
case XMLHttpRequest::OverrideMIMEType:
if (args.size() < 1)
return throwError(exec, SyntaxError, "Not enough arguments");
request->overrideMIMEType(args[0]->toString(exec).qstring());
return jsUndefined();
}
return jsUndefined();
}
} // end namespace
#include "xmlhttprequest.moc"
// kate: indent-width 2; replace-tabs on; tab-width 4; space-indent on;
diff --git a/khtml/ecma/xmlserializer.cpp b/khtml/ecma/xmlserializer.cpp
index 8a4bc48a6e..7493c8f74f 100644
--- a/khtml/ecma/xmlserializer.cpp
+++ b/khtml/ecma/xmlserializer.cpp
@@ -1,104 +1,104 @@
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xmlserializer.h"
#include "xmlserializer.lut.h"
#include "dom/dom_exception.h"
#include "dom/dom_doc.h"
#include "xml/dom_docimpl.h"
#include <kdebug.h>
using namespace KJS;
////////////////////// XMLSerializer Object ////////////////////////
/* Source for XMLSerializerProtoTable.
@begin XMLSerializerProtoTable 1
serializeToString XMLSerializer::SerializeToString DontDelete|Function 1
@end
*/
namespace KJS {
KJS_DEFINE_PROTOTYPE(XMLSerializerProto)
KJS_IMPLEMENT_PROTOFUNC(XMLSerializerProtoFunc)
KJS_IMPLEMENT_PROTOTYPE("XMLSerializer", XMLSerializerProto,XMLSerializerProtoFunc, ObjectPrototype)
XMLSerializerConstructorImp::XMLSerializerConstructorImp(ExecState* exec)
: JSObject(exec->lexicalInterpreter()->builtinObjectPrototype())
{
}
bool XMLSerializerConstructorImp::implementsConstruct() const
{
return true;
}
JSObject *XMLSerializerConstructorImp::construct(ExecState *exec, const List &)
{
return new XMLSerializer(exec);
}
const ClassInfo XMLSerializer::info = { "XMLSerializer", 0, 0, 0 };
XMLSerializer::XMLSerializer(ExecState *exec)
{
setPrototype(XMLSerializerProto::self(exec));
}
JSValue *XMLSerializerProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
{
KJS_CHECK_THIS( XMLSerializer, thisObj );
switch (id) {
case XMLSerializer::SerializeToString:
{
if (args.size() != 1) {
return jsUndefined();
}
if (!args[0]->toObject(exec)->inherits(&DOMNode::info)) {
return jsUndefined();
}
DOM::NodeImpl* node = static_cast<KJS::DOMNode *>(args[0]->toObject(exec))->impl();
if (!node) {
return jsUndefined();
}
- QString body;
+ DOMString body;
try {
- body = node->toString().string();
+ body = node->toString();
} catch(DOM::DOMException&) {
JSObject *err = Error::create(exec, GeneralError, "Exception serializing document");
exec->setException(err);
return err;
}
return ::getStringOrNull(body);
}
}
return jsUndefined();
}
} // end namespace
diff --git a/khtml/html/html_baseimpl.cpp b/khtml/html/html_baseimpl.cpp
index 6a65e8977c..baa13b50b1 100644
--- a/khtml/html/html_baseimpl.cpp
+++ b/khtml/html/html_baseimpl.cpp
@@ -1,853 +1,852 @@
-
/**
* 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) 2000 Simon Hausmann (hausmann@kde.org)
* (C) 2001-2003 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// -------------------------------------------------------------------------
#include "html/html_baseimpl.h"
#include "html/html_documentimpl.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "khtmlpart_p.h"
#include "rendering/render_frames.h"
#include "rendering/render_body.h"
#include "css/cssstyleselector.h"
#include "css/css_stylesheetimpl.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "css/csshelper.h"
#include "misc/loader.h"
#include "dom/dom_string.h"
#include "dom/dom_doc.h"
#include "xml/dom2_eventsimpl.h"
#include <kurl.h>
#include <kdebug.h>
using namespace DOM;
using namespace khtml;
HTMLBodyElementImpl::HTMLBodyElementImpl(DocumentImpl *doc)
: HTMLElementImpl(doc),
m_bgSet( false ), m_fgSet( false )
{
m_styleSheet = 0;
}
HTMLBodyElementImpl::~HTMLBodyElementImpl()
{
if(m_styleSheet) m_styleSheet->deref();
}
NodeImpl::Id HTMLBodyElementImpl::id() const
{
return ID_BODY;
}
void HTMLBodyElementImpl::parseAttribute(AttributeImpl *attr)
{
switch(attr->id())
{
case ATTR_BACKGROUND:
{
QString url = khtml::parseURL( attr->value() ).string();
if (!url.isEmpty()) {
url = document()->completeURL( url );
addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('"+url+"')") );
m_bgSet = true;
}
else {
removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
m_bgSet = false;
}
break;
}
case ATTR_MARGINWIDTH: {
KHTMLView* w = document()->view();
if (w)
w->setMarginWidth( -1 ); // unset this, so it doesn't override the setting here
addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value() );
}
/* nobreak; */
case ATTR_LEFTMARGIN:
addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value() );
break;
case ATTR_MARGINHEIGHT: {
KHTMLView* w = document()->view();
if (w)
w->setMarginHeight( -1 ); // unset this, so it doesn't override the setting here
addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
}
/* nobreak */
case ATTR_TOPMARGIN:
addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
break;
case ATTR_BGCOLOR:
addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
m_bgSet = !attr->value().isNull();
break;
case ATTR_TEXT:
addHTMLColor(CSS_PROP_COLOR, attr->value());
m_fgSet = !attr->value().isNull();
break;
case ATTR_BGPROPERTIES:
if ( strcasecmp( attr->value(), "fixed" ) == 0)
addCSSProperty(CSS_PROP_BACKGROUND_ATTACHMENT, CSS_VAL_FIXED);
break;
case ATTR_VLINK:
case ATTR_ALINK:
case ATTR_LINK:
{
if(!m_styleSheet) {
m_styleSheet = new CSSStyleSheetImpl(this,DOMString(),true /*implicit*/);
m_styleSheet->ref();
}
QString aStr;
if ( attr->id() == ATTR_LINK )
aStr = "a:link";
else if ( attr->id() == ATTR_VLINK )
aStr = "a:visited";
else if ( attr->id() == ATTR_ALINK )
aStr = "a:active";
aStr += " { color: " + attr->value().string() + "; }";
m_styleSheet->parseString(aStr, false);
if (attached())
document()->updateStyleSelector();
break;
}
case ATTR_ONLOAD:
document()->setHTMLWindowEventListener(EventImpl::LOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onload", NULL));
break;
case ATTR_ONUNLOAD:
document()->setHTMLWindowEventListener(EventImpl::UNLOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onunload", NULL));
break;
case ATTR_ONBLUR:
document()->setHTMLWindowEventListener(EventImpl::BLUR_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onblur", NULL));
break;
case ATTR_ONFOCUS:
document()->setHTMLWindowEventListener(EventImpl::FOCUS_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onfocus", NULL));
break;
case ATTR_ONRESIZE:
document()->setHTMLWindowEventListener(EventImpl::RESIZE_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onresize", NULL));
break;
case ATTR_ONKEYUP:
document()->setHTMLWindowEventListener(EventImpl::KEYUP_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onkeyup", NULL));
break;
case ATTR_ONKEYDOWN:
document()->setHTMLWindowEventListener(EventImpl::KEYDOWN_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onkeydown", NULL));
break;
case ATTR_ONKEYPRESS:
document()->setHTMLWindowEventListener(EventImpl::KEYPRESS_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onkeypress", NULL));
break;
case ATTR_ONSCROLL:
document()->setHTMLWindowEventListener(EventImpl::SCROLL_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onscroll", NULL));
break;
case ATTR_ONMESSAGE:
document()->setHTMLWindowEventListener(EventImpl::MESSAGE_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onmessage", NULL));
break;
case ATTR_NOSAVE:
break;
default:
HTMLElementImpl::parseAttribute(attr);
}
}
void HTMLBodyElementImpl::insertedIntoDocument()
{
HTMLElementImpl::insertedIntoDocument();
KHTMLView* w = document()->view();
if(w && w->marginWidth() != -1) {
QString s;
s.sprintf( "%d", w->marginWidth() );
addCSSLength(CSS_PROP_MARGIN_LEFT, s);
addCSSLength(CSS_PROP_MARGIN_RIGHT, s);
}
if(w && w->marginHeight() != -1) {
QString s;
s.sprintf( "%d", w->marginHeight() );
addCSSLength(CSS_PROP_MARGIN_TOP, s);
addCSSLength(CSS_PROP_MARGIN_BOTTOM, s);
}
if ( m_bgSet && !m_fgSet )
addCSSProperty(CSS_PROP_COLOR, CSS_VAL_BLACK);
if (m_styleSheet)
document()->updateStyleSelector();
}
void HTMLBodyElementImpl::removedFromDocument()
{
HTMLElementImpl::removedFromDocument();
if (m_styleSheet)
document()->updateStyleSelector();
}
void HTMLBodyElementImpl::attach()
{
assert(!m_render);
assert(parentNode());
RenderStyle* style = document()->styleSelector()->styleForElement(this);
style->ref();
if (parentNode()->renderer() && parentNode()->renderer()->childAllowed()
&& style->display() != NONE) {
if (style->display() == BLOCK)
// only use the quirky class for block display
m_render = new (document()->renderArena()) RenderBody(this);
else
m_render = RenderObject::createObject(this, style);
m_render->setStyle(style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
style->deref();
NodeBaseImpl::attach();
}
// -------------------------------------------------------------------------
HTMLFrameElementImpl::HTMLFrameElementImpl(DocumentImpl *doc)
: HTMLPartContainerElementImpl(doc)
{
frameBorder = true;
frameBorderSet = false;
marginWidth = -1;
marginHeight = -1;
scrolling = Qt::ScrollBarAsNeeded;
noresize = false;
url = "about:blank";
}
HTMLFrameElementImpl::~HTMLFrameElementImpl()
{
}
NodeImpl::Id HTMLFrameElementImpl::id() const
{
return ID_FRAME;
}
void HTMLFrameElementImpl::ensureUniqueName()
{
// If we already have a name, don't do anything.
if (!name.isEmpty())
return;
// Use the specified name first..
name = getAttribute(ATTR_NAME);
if (name.isNull())
name = getAttribute(ATTR_ID);
// Generate synthetic name if there isn't a natural one or
// if the natural one conflicts
KHTMLPart* parentPart = document()->part();
// If there is no part, we will not load anything, so no
// worry about names being unique or not.
if (!parentPart)
return;
KHTMLPart* otherFrame = parentPart->findFrame( name.string() );
if (name.isEmpty() || (otherFrame && otherFrame != contentPart()))
name = DOMString(parentPart->requestFrameName());
// Make sure we're registered properly.
parentPart->d->renameFrameForContainer(this, name.string());
}
void HTMLFrameElementImpl::defaultEventHandler(EventImpl *e)
{
// ### duplicated in HTMLObjectBaseElementImpl
if ( e->target() == this && m_render && m_render->isWidget()
&& static_cast<RenderWidget*>(m_render)->isRedirectedWidget()
&& qobject_cast<KHTMLView*>(static_cast<RenderWidget*>(m_render)->widget())) {
switch(e->id()) {
case EventImpl::MOUSEDOWN_EVENT:
case EventImpl::MOUSEUP_EVENT:
case EventImpl::MOUSEMOVE_EVENT:
case EventImpl::MOUSEOUT_EVENT:
case EventImpl::MOUSEOVER_EVENT:
case EventImpl::KHTML_MOUSEWHEEL_EVENT:
case EventImpl::KEYDOWN_EVENT:
case EventImpl::KEYUP_EVENT:
case EventImpl::KEYPRESS_EVENT:
case EventImpl::DOMFOCUSIN_EVENT:
case EventImpl::DOMFOCUSOUT_EVENT:
if (static_cast<RenderWidget*>(m_render)->handleEvent(*e))
e->setDefaultHandled();
default:
break;
}
}
HTMLPartContainerElementImpl::defaultEventHandler(e);
}
void HTMLFrameElementImpl::parseAttribute(AttributeImpl *attr)
{
switch(attr->id())
{
case ATTR_SRC:
setLocation(khtml::parseURL(attr->val()));
break;
case ATTR_FRAMEBORDER:
{
frameBorder = attr->value().toInt();
frameBorderSet = ( attr->val() != 0 );
// FIXME: when attached, has no effect
}
break;
case ATTR_MARGINWIDTH:
marginWidth = attr->val()->toInt();
// FIXME: when attached, has no effect
break;
case ATTR_MARGINHEIGHT:
marginHeight = attr->val()->toInt();
// FIXME: when attached, has no effect
break;
case ATTR_NORESIZE:
noresize = true;
// FIXME: when attached, has no effect
break;
case ATTR_SCROLLING:
if( strcasecmp( attr->value(), "auto" ) == 0 )
scrolling = Qt::ScrollBarAsNeeded;
else if( strcasecmp( attr->value(), "yes" ) == 0 )
scrolling = Qt::ScrollBarAlwaysOn;
else if( strcasecmp( attr->value(), "no" ) == 0 )
scrolling = Qt::ScrollBarAlwaysOff;
// when attached, has no effect
break;
case ATTR_ONLOAD:
setHTMLEventListener(EventImpl::LOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onload", this));
break;
case ATTR_ONUNLOAD:
setHTMLEventListener(EventImpl::UNLOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onunload", this));
break;
default:
HTMLElementImpl::parseAttribute(attr);
}
}
void HTMLFrameElementImpl::attach()
{
assert(!attached());
assert(parentNode());
computeContentIfNeeded();
// inherit default settings from parent frameset
HTMLElementImpl* node = static_cast<HTMLElementImpl*>(parentNode());
while(node)
{
if(node->id() == ID_FRAMESET)
{
HTMLFrameSetElementImpl* frameset = static_cast<HTMLFrameSetElementImpl*>(node);
if(!frameBorderSet) frameBorder = frameset->frameBorder();
if(!noresize) noresize = frameset->noResize();
break;
}
node = static_cast<HTMLElementImpl*>(node->parentNode());
}
if (parentNode()->renderer() && parentNode()->renderer()->childAllowed()
&& document()->isURLAllowed(url.string())) {
RenderStyle* _style = document()->styleSelector()->styleForElement(this);
_style->ref();
if ( _style->display() != NONE ) {
m_render = new (document()->renderArena()) RenderFrame(this);
m_render->setStyle(_style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
_style->deref();
}
// If we already have a widget, set it.
if (m_render && childWidget())
static_cast<RenderFrame*>(m_render)->setWidget(childWidget());
NodeBaseImpl::attach();
}
void HTMLFrameElementImpl::setWidgetNotify(QWidget* widget)
{
if (m_render)
static_cast<RenderFrame*>(m_render)->setWidget(widget);
}
void HTMLFrameElementImpl::computeContent()
{
KHTMLPart* parentPart = document()->part();
if (!parentPart)
return;
// Bail out on any disallowed URLs
if( !document()->isURLAllowed(url.string()) )
return;
// If we have a part already, make sure it's in the right spot...
// (can happen if someone asks to change location while we're in process
// of loading the original one)
if ( contentPart() ) {
setLocation(url);
return;
}
ensureUniqueName();
// Go ahead and load a part... We don't need to clear the widget here,
// since the -frames- have their lifetime managed, using the name uniqueness.
parentPart->loadFrameElement( this, url.string(), name.string() );
}
void HTMLFrameElementImpl::setLocation( const DOMString& str )
{
url = str;
if( !document()->isURLAllowed(url.string()) )
return;
// if we already have a child part, ask it to go there..
KHTMLPart* childPart = contentPart();
if ( childPart )
childPart->openUrl( KUrl( document()->completeURL( url.string() ) ) );
else
setNeedComputeContent(); // otherwise, request it..
}
bool HTMLFrameElementImpl::isFocusableImpl(FocusType ft) const
{
if (m_render!=0)
return true;
return HTMLPartContainerElementImpl::isFocusableImpl(ft);
}
void HTMLFrameElementImpl::setFocus(bool received)
{
HTMLElementImpl::setFocus(received);
khtml::RenderFrame *renderFrame = static_cast<khtml::RenderFrame *>(m_render);
if (!renderFrame || !renderFrame->widget())
return;
if (received)
renderFrame->widget()->setFocus();
else
renderFrame->widget()->clearFocus();
}
DocumentImpl* HTMLFrameElementImpl::contentDocument() const
{
if (!childWidget()) return 0;
if (::qobject_cast<KHTMLView*>( childWidget() ) )
return static_cast<KHTMLView*>( childWidget() )->part()->xmlDocImpl();
return 0;
}
KHTMLPart* HTMLFrameElementImpl::contentPart() const
{
if (!childWidget()) return 0;
if (::qobject_cast<KHTMLView*>( childWidget() ) )
return static_cast<KHTMLView*>( childWidget() )->part();
return 0;
}
// -------------------------------------------------------------------------
DOMString HTMLBodyElementImpl::aLink() const
{
return getAttribute(ATTR_ALINK);
}
void HTMLBodyElementImpl::setALink( const DOMString &value )
{
setAttribute(ATTR_ALINK, value);
}
DOMString HTMLBodyElementImpl::bgColor() const
{
return getAttribute(ATTR_BGCOLOR);
}
void HTMLBodyElementImpl::setBgColor( const DOMString &value )
{
setAttribute(ATTR_BGCOLOR, value);
}
DOMString HTMLBodyElementImpl::link() const
{
return getAttribute(ATTR_LINK);
}
void HTMLBodyElementImpl::setLink( const DOMString &value )
{
setAttribute(ATTR_LINK, value);
}
DOMString HTMLBodyElementImpl::text() const
{
return getAttribute(ATTR_TEXT);
}
void HTMLBodyElementImpl::setText( const DOMString &value )
{
setAttribute(ATTR_TEXT, value);
}
DOMString HTMLBodyElementImpl::vLink() const
{
return getAttribute(ATTR_VLINK);
}
void HTMLBodyElementImpl::setVLink( const DOMString &value )
{
setAttribute(ATTR_VLINK, value);
}
// -------------------------------------------------------------------------
HTMLFrameSetElementImpl::HTMLFrameSetElementImpl(DocumentImpl *doc)
: HTMLElementImpl(doc)
{
// default value for rows and cols...
m_totalRows = 1;
m_totalCols = 1;
m_rows = m_cols = 0;
frameborder = true;
frameBorderSet = false;
m_border = 4;
noresize = false;
m_resizing = false;
}
HTMLFrameSetElementImpl::~HTMLFrameSetElementImpl()
{
delete [] m_rows;
delete [] m_cols;
}
NodeImpl::Id HTMLFrameSetElementImpl::id() const
{
return ID_FRAMESET;
}
void HTMLFrameSetElementImpl::parseAttribute(AttributeImpl *attr)
{
switch(attr->id())
{
case ATTR_ROWS:
if (!attr->val()) break;
delete [] m_rows;
m_rows = attr->val()->toLengthArray(m_totalRows);
setChanged();
break;
case ATTR_COLS:
if (!attr->val()) break;
delete [] m_cols;
m_cols = attr->val()->toLengthArray(m_totalCols);
setChanged();
break;
case ATTR_FRAMEBORDER:
// false or "no" or "0"..
if ( attr->value().toInt() == 0 ) {
frameborder = false;
m_border = 0;
}
frameBorderSet = true;
break;
case ATTR_NORESIZE:
noresize = true;
break;
case ATTR_BORDER:
m_border = attr->val()->toInt();
if(!m_border)
frameborder = false;
break;
case ATTR_ONLOAD:
document()->setHTMLWindowEventListener(EventImpl::LOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onload", NULL));
break;
case ATTR_ONUNLOAD:
document()->setHTMLWindowEventListener(EventImpl::UNLOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onunload", NULL));
break;
case ATTR_ONMESSAGE:
document()->setHTMLWindowEventListener(EventImpl::MESSAGE_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onmessage", NULL));
break;
default:
HTMLElementImpl::parseAttribute(attr);
}
}
void HTMLFrameSetElementImpl::attach()
{
assert(!attached() );
assert(parentNode());
// inherit default settings from parent frameset
HTMLElementImpl* node = static_cast<HTMLElementImpl*>(parentNode());
while(node)
{
if(node->id() == ID_FRAMESET)
{
HTMLFrameSetElementImpl* frameset = static_cast<HTMLFrameSetElementImpl*>(node);
if(!frameBorderSet) frameborder = frameset->frameBorder();
if(!noresize) noresize = frameset->noResize();
break;
}
node = static_cast<HTMLElementImpl*>(node->parentNode());
}
// ignore display: none
if ( parentNode()->renderer() && parentNode()->renderer()->childAllowed() ) {
RenderStyle* _style = document()->styleSelector()->styleForElement(this);
m_render = new (document()->renderArena()) RenderFrameSet(this);
m_render->setStyle(_style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
NodeBaseImpl::attach();
}
void HTMLFrameSetElementImpl::defaultEventHandler(EventImpl *evt)
{
if (evt->isMouseEvent() && !noresize && m_render)
static_cast<khtml::RenderFrameSet *>(m_render)->userResize(static_cast<MouseEventImpl*>(evt));
evt->setDefaultHandled();
HTMLElementImpl::defaultEventHandler(evt);
}
void HTMLFrameSetElementImpl::detach()
{
if(attached())
// ### send the event when we actually get removed from the doc instead of here
document()->dispatchHTMLEvent(EventImpl::UNLOAD_EVENT,false,false);
HTMLElementImpl::detach();
}
void HTMLFrameSetElementImpl::recalcStyle( StyleChange ch )
{
if (changed() && m_render) {
m_render->setNeedsLayout(true);
// m_render->layout();
setChanged(false);
}
HTMLElementImpl::recalcStyle( ch );
}
// -------------------------------------------------------------------------
NodeImpl::Id HTMLHeadElementImpl::id() const
{
return ID_HEAD;
}
// -------------------------------------------------------------------------
NodeImpl::Id HTMLHtmlElementImpl::id() const
{
return ID_HTML;
}
// -------------------------------------------------------------------------
HTMLIFrameElementImpl::HTMLIFrameElementImpl(DocumentImpl *doc) : HTMLFrameElementImpl(doc)
{
frameBorder = false;
marginWidth = 0;
marginHeight = 0;
m_frame = true;
}
void HTMLIFrameElementImpl::insertedIntoDocument()
{
HTMLFrameElementImpl::insertedIntoDocument();
assert(!contentPart());
setNeedComputeContent();
computeContentIfNeeded(); // also clears
}
void HTMLIFrameElementImpl::removedFromDocument()
{
HTMLFrameElementImpl::removedFromDocument();
clearChildWidget();
}
HTMLIFrameElementImpl::~HTMLIFrameElementImpl()
{
}
NodeImpl::Id HTMLIFrameElementImpl::id() const
{
return ID_IFRAME;
}
void HTMLIFrameElementImpl::parseAttribute(AttributeImpl *attr )
{
switch ( attr->id() )
{
case ATTR_WIDTH:
if (!attr->value().isEmpty())
addCSSLength(CSS_PROP_WIDTH, attr->value());
else
removeCSSProperty(CSS_PROP_WIDTH);
break;
case ATTR_HEIGHT:
if (!attr->value().isEmpty())
addCSSLength(CSS_PROP_HEIGHT, attr->value());
else
removeCSSProperty(CSS_PROP_HEIGHT);
break;
case ATTR_ALIGN:
addHTMLAlignment( attr->value() );
break;
case ATTR_SRC:
url = khtml::parseURL(attr->val());
setNeedComputeContent();
// ### synchronously start the process?
break;
case ATTR_NAME:
ensureUniqueName();
break;
case ATTR_ID:
HTMLFrameElementImpl::parseAttribute( attr ); // want default ID handling
ensureUniqueName();
break;
case ATTR_FRAMEBORDER:
{
m_frame = (!attr->val() || attr->value().toInt() > 0);
if (attached()) updateFrame();
break;
}
default:
HTMLFrameElementImpl::parseAttribute( attr );
}
}
void HTMLIFrameElementImpl::updateFrame()
{
if (m_frame) {
addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_OUTSET);
addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_OUTSET);
addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_OUTSET);
addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_OUTSET);
addCSSLength(CSS_PROP_BORDER_WIDTH, "2");
} else {
addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_NONE);
addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_NONE);
addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_NONE);
addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_NONE);
removeCSSProperty(CSS_PROP_BORDER_WIDTH);
}
}
void HTMLIFrameElementImpl::attach()
{
assert(!attached());
assert(!m_render);
assert(parentNode());
updateFrame();
RenderStyle* style = document()->styleSelector()->styleForElement(this);
style->ref();
if (document()->isURLAllowed(url.string()) && parentNode()->renderer()
&& parentNode()->renderer()->childAllowed() && style->display() != NONE) {
m_render = new (document()->renderArena()) RenderPartObject(this);
m_render->setStyle(style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
style->deref();
NodeBaseImpl::attach();
if (m_render && childWidget())
static_cast<RenderPartObject*>(m_render)->setWidget(childWidget());
}
void HTMLIFrameElementImpl::computeContent()
{
KHTMLPart* parentPart = document()->part();
if (!parentPart)
return;
if (!document()->isURLAllowed(url.string()))
return;
if (!inDocument()) {
clearChildWidget();
return;
}
// get our name in order..
ensureUniqueName();
// make sure "" is handled as about: blank
const QString aboutBlank = QLatin1String("about:blank");
QString effectiveURL = url.string();
if (effectiveURL.isEmpty())
effectiveURL = aboutBlank;
kDebug(6031) << "-> requesting:" << name.string() << effectiveURL << contentPart();
parentPart->loadFrameElement(this, effectiveURL, name.string(), QStringList(), true);
}
void HTMLIFrameElementImpl::setWidgetNotify(QWidget* widget)
{
if (m_render)
static_cast<RenderPartObject*>(m_render)->setWidget(widget);
}
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
diff --git a/khtml/html/html_objectimpl.cpp b/khtml/html/html_objectimpl.cpp
index c88418caf5..72ca621f71 100644
--- a/khtml/html/html_objectimpl.cpp
+++ b/khtml/html/html_objectimpl.cpp
@@ -1,860 +1,858 @@
/**
* 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) 2000 Stefan Schimanski (1Stein@gmx.de)
* (C) 2007, 2008 Maks Orlovich (maksim@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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "html/html_objectimpl.h"
#include "khtml_part.h"
#include "dom/dom_string.h"
#include "imload/imagemanager.h"
#include "khtmlview.h"
#include <QtCore/QCharRef>
#include <QtCore/QVariant>
#include <QtCore/QMap>
#include <QtCore/QTimer>
#include <QImageReader>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include "xml/dom_docimpl.h"
#include "css/cssstyleselector.h"
#include "css/csshelper.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "rendering/render_frames.h"
#include "rendering/render_image.h"
#include "xml/dom2_eventsimpl.h"
using namespace DOM;
using namespace khtml;
HTMLPartContainerElementImpl::HTMLPartContainerElementImpl(DocumentImpl *doc)
: HTMLElementImpl(doc)
{
m_needToComputeContent = true;
m_childWidget = 0;
}
HTMLPartContainerElementImpl::~HTMLPartContainerElementImpl()
{
// Kill the renderer here, since we are asking for a widget to be deleted
if (m_render)
detach();
if (m_childWidget)
m_childWidget->deleteLater();
}
void HTMLPartContainerElementImpl::recalcStyle(StyleChange ch)
{
computeContentIfNeeded();
HTMLElementImpl::recalcStyle( ch );
}
void HTMLPartContainerElementImpl::close()
{
HTMLElementImpl::close(); // Do it first, to make sure closed() is set.
computeContentIfNeeded();
}
void HTMLPartContainerElementImpl::computeContentIfNeeded()
{
if (!m_needToComputeContent)
return;
m_needToComputeContent = false;
computeContent();
}
void HTMLPartContainerElementImpl::setNeedComputeContent()
{
m_needToComputeContent = true;
if (closed())
setChanged(); //React quickly when not in the middle of parsing..
}
void HTMLPartContainerElementImpl::setWidget(QWidget* widget)
{
if (widget == m_childWidget)
return; // The same part got navigated. Don't do anything
QWidget* oldWidget = m_childWidget;
m_childWidget = widget;
if (m_childWidget)
m_childWidget->hide();
setWidgetNotify(m_childWidget);
if (oldWidget) {
oldWidget->hide();
oldWidget->deleteLater();
}
}
void HTMLPartContainerElementImpl::partLoadingErrorNotify()
{
clearChildWidget();
}
void HTMLPartContainerElementImpl::clearChildWidget()
{
setWidget(0);
}
bool HTMLPartContainerElementImpl::mimetypeHandledInternally(const QString&)
{
return false;
}
void HTMLPartContainerElementImpl::slotEmitLoadEvent()
{
dispatchHTMLEvent(EventImpl::LOAD_EVENT, false, false);
}
void HTMLPartContainerElementImpl::postResizeEvent()
{
QApplication::postEvent( this, new QEvent(static_cast<QEvent::Type>(DOMCFResizeEvent)) );
}
void HTMLPartContainerElementImpl::sendPostedResizeEvents()
{
QApplication::sendPostedEvents(0, DOMCFResizeEvent);
}
bool HTMLPartContainerElementImpl::event(QEvent *e)
{
if (e->type() == static_cast<QEvent::Type>(DOMCFResizeEvent)) {
dispatchWindowEvent(EventImpl::RESIZE_EVENT, false, false);
e->accept();
return true;
}
return QObject::event(e);
}
// -------------------------------------------------------------------------
HTMLObjectBaseElementImpl::HTMLObjectBaseElementImpl(DocumentImpl *doc)
: HTMLPartContainerElementImpl(doc)
{
m_renderAlternative = false;
m_imageLike = false;
m_rerender = false;
}
void HTMLObjectBaseElementImpl::setServiceType(const QString & val) {
serviceType = val.toLower();
int pos = serviceType.indexOf( ";" );
if ( pos!=-1 )
serviceType.truncate( pos );
}
void HTMLObjectBaseElementImpl::parseAttribute(AttributeImpl *attr)
{
switch ( attr->id() )
{
case ATTR_TYPE:
case ATTR_CODETYPE:
if (attr->val()) {
- DOM::DOMStringImpl *stringImpl = attr->val();
- QString val = QString( stringImpl->s, stringImpl->l );
- setServiceType( val );
+ setServiceType(attr->val()->string());
setNeedComputeContent();
}
break;
case ATTR_WIDTH:
if (!attr->value().isEmpty())
addCSSLength(CSS_PROP_WIDTH, attr->value());
else
removeCSSProperty(CSS_PROP_WIDTH);
break;
case ATTR_HEIGHT:
if (!attr->value().isEmpty())
addCSSLength(CSS_PROP_HEIGHT, attr->value());
else
removeCSSProperty(CSS_PROP_HEIGHT);
break;
case ATTR_NAME:
if (inDocument() && m_name != attr->value()) {
document()->underDocNamedCache().remove(m_name, this);
document()->underDocNamedCache().add (attr->value(), this);
}
m_name = attr->value();
//fallthrough
default:
HTMLElementImpl::parseAttribute( attr );
}
}
void HTMLObjectBaseElementImpl::defaultEventHandler(EventImpl *e)
{
// ### duplicated in HTMLIFrameElementImpl
if ( e->target() == this && m_render && m_render->isWidget()
&& static_cast<RenderWidget*>(m_render)->isRedirectedWidget()
&& qobject_cast<KHTMLView*>(static_cast<RenderWidget*>(m_render)->widget())) {
switch(e->id()) {
case EventImpl::MOUSEDOWN_EVENT:
case EventImpl::MOUSEUP_EVENT:
case EventImpl::MOUSEMOVE_EVENT:
case EventImpl::MOUSEOUT_EVENT:
case EventImpl::MOUSEOVER_EVENT:
case EventImpl::KHTML_MOUSEWHEEL_EVENT:
case EventImpl::KEYDOWN_EVENT:
case EventImpl::KEYUP_EVENT:
case EventImpl::KEYPRESS_EVENT:
case EventImpl::DOMFOCUSIN_EVENT:
case EventImpl::DOMFOCUSOUT_EVENT:
if (static_cast<RenderWidget*>(m_render)->handleEvent(*e))
e->setDefaultHandled();
default:
break;
}
}
HTMLElementImpl::defaultEventHandler(e);
}
void HTMLObjectBaseElementImpl::removedFromDocument()
{
document()->underDocNamedCache().remove(m_name, this);
// When removed from document, we destroy the widget/plugin.
// We have to do it here and not just call setNeedComputeContent(),
// since khtml will not try to restyle changed() things not in document.
clearChildWidget();
HTMLPartContainerElementImpl::removedFromDocument();
}
void HTMLObjectBaseElementImpl::insertedIntoDocument()
{
document()->underDocNamedCache().add(m_name, this);
setNeedComputeContent();
HTMLPartContainerElementImpl::insertedIntoDocument();
}
void HTMLObjectBaseElementImpl::removeId(const DOMString& id)
{
document()->underDocNamedCache().remove(id, this);
HTMLElementImpl::removeId(id);
}
void HTMLObjectBaseElementImpl::addId (const DOMString& id)
{
document()->underDocNamedCache().add(id, this);
HTMLElementImpl::addId(id);
}
void HTMLObjectBaseElementImpl::requestRerender()
{
if (m_rerender) return;
m_rerender = true;
QTimer::singleShot( 0, this, SLOT(slotRerender()) );
}
void HTMLObjectBaseElementImpl::slotRerender()
{
// the singleshot timer might have fired after we're removed
// from the document, but not yet deleted due to references
if ( !inDocument() || !m_rerender ) return;
// ### there can be a m_render if this is called from our attach indirectly
if ( attached() || m_render) {
detach();
attach();
}
m_rerender = false;
}
void HTMLObjectBaseElementImpl::attach() {
assert(!attached());
assert(!m_render);
computeContentIfNeeded();
m_rerender = false;
if (m_renderAlternative && !m_imageLike) {
// render alternative content
ElementImpl::attach();
return;
}
if (!parentNode()->renderer()) {
NodeBaseImpl::attach();
return;
}
RenderStyle* _style = document()->styleSelector()->styleForElement(this);
_style->ref();
if (parentNode()->renderer() && parentNode()->renderer()->childAllowed() &&
_style->display() != NONE)
{
if (m_imageLike) {
m_render = new (document()->renderArena()) RenderImage(this);
} else {
m_render = new (document()->renderArena()) RenderPartObject(this);
// If we already have a widget, set it.
if (childWidget())
static_cast<RenderFrame*>(m_render)->setWidget(childWidget());
}
m_render->setStyle(_style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
if (m_imageLike)
m_render->updateFromElement();
}
_style->deref();
NodeBaseImpl::attach();
}
HTMLEmbedElementImpl* HTMLObjectBaseElementImpl::relevantEmbed()
{
for (NodeImpl *child = firstChild(); child; child = child->nextSibling()) {
if ( child->id() == ID_EMBED ) {
return static_cast<HTMLEmbedElementImpl *>( child );
}
}
return 0;
}
bool HTMLObjectBaseElementImpl::mimetypeHandledInternally(const QString& mime)
{
QStringList supportedImageTypes = khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes();
bool newImageLike = supportedImageTypes.contains(mime);
if (newImageLike != m_imageLike) {
m_imageLike = newImageLike;
requestRerender();
}
return newImageLike; // No need for kpart for that.
}
void HTMLObjectBaseElementImpl::computeContent()
{
QStringList params;
QString effectiveURL = url; // May be overwritten by some of the <params>
// if the URL isn't there
QString effectiveServiceType = serviceType;
// We need to wait until everything has parsed, since we need the <param>s,
// and the embedded <embed>
if (!closed()) {
setNeedComputeContent();
return;
}
// Not in document => no plugin.
if (!inDocument()) {
clearChildWidget();
return;
}
// Collect information from <param> children for ...
// It also sometimes supplements or replaces some of the element's attributes
for (NodeImpl* child = firstChild(); child; child = child->nextSibling()) {
if (child->id() == ID_PARAM) {
HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>( child );
QString aStr = p->name();
aStr += QLatin1String("=\"");
aStr += p->value();
aStr += QLatin1String("\"");
QString name_lower = p->name().toLower();
if (name_lower == QLatin1String("type") && id() != ID_APPLET) {
setServiceType(p->value());
effectiveServiceType = serviceType;
} else if (effectiveURL.isEmpty() &&
(name_lower == QLatin1String("src") ||
name_lower == QLatin1String("movie") ||
name_lower == QLatin1String("code"))) {
effectiveURL = p->value();
}
params.append(aStr);
}
}
// For <applet>(?) and <embed> we also make each attribute a part parameter
if (id() != ID_OBJECT) {
NamedAttrMapImpl* a = attributes();
if (a) {
for (unsigned i = 0; i < a->length(); ++i) {
NodeImpl::Id id = a->idAt(i);
DOMString value = a->valueAt(i);
params.append(LocalName::fromId(localNamePart(id)).toString().string() + "=\"" + value.string() + "\"");
}
}
}
params.append( QLatin1String("__KHTML__PLUGINEMBED=\"YES\"") );
params.append( QString::fromLatin1("__KHTML__PLUGINBASEURL=\"%1\"").arg(document()->baseURL().url()));
params.append( QString::fromLatin1("__KHTML__PLUGINPAGEURL=\"%1\"").arg(document()->URL().url()));
// Non-embed elements parse a bunch of attributes and inherit things off <embed>, if any
HTMLEmbedElementImpl* embed = relevantEmbed();
if (id() != ID_EMBED) {
params.append( QString::fromLatin1("__KHTML__CLASSID=\"%1\"").arg( classId ) );
params.append( QString::fromLatin1("__KHTML__CODEBASE=\"%1\"").arg( getAttribute(ATTR_CODEBASE).string() ) );
if (embed && !embed->getAttribute(ATTR_WIDTH).isEmpty())
setAttribute(ATTR_WIDTH, embed->getAttribute(ATTR_WIDTH));
if (embed && !embed->getAttribute(ATTR_HEIGHT).isEmpty())
setAttribute(ATTR_HEIGHT, embed->getAttribute(ATTR_HEIGHT));
if (!getAttribute(ATTR_WIDTH).isEmpty())
params.append( QString::fromLatin1("WIDTH=\"%1\"").arg( getAttribute(ATTR_WIDTH).string() ) );
if (!getAttribute(ATTR_HEIGHT).isEmpty())
params.append( QString::fromLatin1("HEIGHT=\"%1\"").arg( getAttribute(ATTR_HEIGHT).string() ) );
// Fix up the serviceType from embed, or applet info..
if (embed) {
effectiveURL = embed->url;
if (!embed->serviceType.isEmpty())
effectiveServiceType = embed->serviceType;
} else if (effectiveURL.isEmpty() &&
classId.startsWith(QLatin1String("java:"))) {
effectiveServiceType = "application/x-java-applet";
effectiveURL = classId.mid(5);
}
// Translate ActiveX gibberish into mimetypes
if ((effectiveServiceType.isEmpty() || serviceType == "application/x-oleobject") && !classId.isEmpty()) {
if(classId.indexOf(QString::fromLatin1("D27CDB6E-AE6D-11cf-96B8-444553540000")) >= 0)
effectiveServiceType = "application/x-shockwave-flash";
else if(classId.indexOf(QLatin1String("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) >= 0)
effectiveServiceType = "audio/x-pn-realaudio-plugin";
else if(classId.indexOf(QLatin1String("8AD9C840-044E-11D1-B3E9-00805F499D93")) >= 0 ||
classId.indexOf(QLatin1String("CAFEEFAC-0014-0000-0000-ABCDEFFEDCBA")) >= 0)
effectiveServiceType = "application/x-java-applet";
// http://www.apple.com/quicktime/tools_tips/tutorials/activex.html
else if(classId.indexOf(QLatin1String("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) >= 0)
effectiveServiceType = "video/quicktime";
// http://msdn.microsoft.com/library/en-us/dnwmt/html/adding_windows_media_to_web_pages__etse.asp?frame=true
else if(classId.indexOf(QString::fromLatin1("6BF52A52-394A-11d3-B153-00C04F79FAA6")) >= 0 ||
classId.indexOf(QString::fromLatin1("22D6f312-B0F6-11D0-94AB-0080C74C7E95")) >= 0)
effectiveServiceType = "video/x-msvideo";
else
kDebug(6031) << "ActiveX classId " << classId;
// TODO: add more plugins here
}
}
if (effectiveServiceType.isEmpty() &&
effectiveURL.startsWith(QLatin1String("data:"))) {
// Extract the MIME type from the data URL.
int index = effectiveURL.indexOf(';');
if (index == -1)
index = effectiveURL.indexOf(',');
if (index != -1) {
int len = index - 5;
if (len > 0)
effectiveServiceType = effectiveURL.mid(5, len);
else
effectiveServiceType = "text/plain"; // Data URLs with no MIME type are considered text/plain.
}
}
// Figure out if may be we're image-like. In this case, we don't need to load anything,
// but may need to do a detach/attach
QStringList supportedImageTypes = khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes();
bool newImageLike = effectiveServiceType.startsWith(QLatin1String("image/")) && supportedImageTypes.contains(effectiveServiceType);
if (newImageLike != m_imageLike) {
m_imageLike = newImageLike;
requestRerender();
}
if (m_imageLike)
return;
// Now see if we have to render alternate content.
bool newRenderAlternative = false;
// If we aren't permitted to load this by security policy, render alternative content instead.
if (!document()->isURLAllowed(effectiveURL))
newRenderAlternative = true;
// If Java is off, render alternative as well...
if (effectiveServiceType == "application/x-java-applet") {
KHTMLPart* p = document()->part();
if (!p || !p->javaEnabled())
newRenderAlternative = true;
} else {
// Similarly for plugins.
KHTMLPart* p = document()->part();
if (!p || !p->pluginsEnabled())
newRenderAlternative = true;
}
// If there is no <embed> (here or as a child), and we don't have a type + url to go on,
// we need to render alternative as well
if (!embed && effectiveURL.isEmpty() && effectiveServiceType.isEmpty())
newRenderAlternative = true;
if (newRenderAlternative != m_renderAlternative) {
m_renderAlternative = newRenderAlternative;
requestRerender();
}
if (m_renderAlternative)
return;
KHTMLPart* part = document()->part();
clearChildWidget();
kDebug(6031) << effectiveURL << effectiveServiceType << params;
if (!part->loadObjectElement( this, effectiveURL, effectiveServiceType, params)) {
// Looks like we are gonna need alternative content after all...
m_renderAlternative = true;
}
// Either way, we need to re-attach, either for alternative content, or because
// we got the part..
requestRerender();
}
void HTMLObjectBaseElementImpl::setWidgetNotify(QWidget *widget)
{
// Ick.
if(m_render && strcmp( m_render->renderName(), "RenderPartObject" ) == 0 )
static_cast<RenderPartObject*>(m_render)->setWidget(widget);
}
void HTMLObjectBaseElementImpl::renderAlternative()
{
if (m_renderAlternative)
return;
m_renderAlternative = true;
requestRerender();
}
void HTMLObjectBaseElementImpl::partLoadingErrorNotify()
{
// Defer ourselves from the current event loop (to prevent crashes due to the message box staying up)
QTimer::singleShot(0, this, SLOT(slotPartLoadingErrorNotify()));
// Either way, we don't have stuff to display, so have to render alternative content.
if (!m_renderAlternative) {
m_renderAlternative = true;
requestRerender();
}
clearChildWidget();
}
void HTMLObjectBaseElementImpl::slotPartLoadingErrorNotify()
{
// If we have an embed, we may be able to tell the user where to
// download the plugin.
HTMLEmbedElementImpl *embed = relevantEmbed();
QString serviceType; // shadows ours, but we don't care.
if (!embed)
return;
serviceType = embed->serviceType;
KHTMLPart* part = document()->part();
KParts::BrowserExtension *ext = part->browserExtension();
if(!embed->pluginPage.isEmpty() && ext) {
// Prepare the mimetype to show in the question (comment if available, name as fallback)
QString mimeName = serviceType;
KMimeType::Ptr mime = KMimeType::mimeType(serviceType, KMimeType::ResolveAliases);
if ( mime && mime->name() != KMimeType::defaultMimeType() )
mimeName = mime->comment();
// Check if we already asked the user, for this page
if (!mimeName.isEmpty() && !part->pluginPageQuestionAsked(serviceType))
{
part->setPluginPageQuestionAsked(serviceType);
// Prepare the URL to show in the question (host only if http, to make it short)
KUrl pluginPageURL(embed->pluginPage);
QString shortURL = pluginPageURL.protocol() == "http" ? pluginPageURL.host() : pluginPageURL.prettyUrl();
int res = KMessageBox::questionYesNo( part->view(),
i18n("No plugin found for '%1'.\nDo you want to download one from %2?", mimeName, shortURL),
i18n("Missing Plugin"), KGuiItem(i18n("Download")), KGuiItem(i18n("Do Not Download")), QString("plugin-")+serviceType);
if (res == KMessageBox::Yes)
{
// Display vendor download page
ext->createNewWindow(pluginPageURL);
return;
}
}
}
}
// -------------------------------------------------------------------------
HTMLAppletElementImpl::HTMLAppletElementImpl(DocumentImpl *doc)
: HTMLObjectBaseElementImpl(doc)
{
serviceType = "application/x-java-applet";
}
HTMLAppletElementImpl::~HTMLAppletElementImpl()
{
}
NodeImpl::Id HTMLAppletElementImpl::id() const
{
return ID_APPLET;
}
void HTMLAppletElementImpl::parseAttribute(AttributeImpl *attr)
{
switch( attr->id() )
{
case ATTR_CODEBASE:
case ATTR_ARCHIVE:
case ATTR_CODE:
case ATTR_OBJECT:
case ATTR_ALT:
break;
case ATTR_ALIGN:
addHTMLAlignment( attr->value() );
break;
case ATTR_VSPACE:
addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
break;
case ATTR_HSPACE:
addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
break;
case ATTR_VALIGN:
addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower() );
break;
default:
HTMLObjectBaseElementImpl::parseAttribute(attr);
}
}
void HTMLAppletElementImpl::computeContent()
{
DOMString codeBase = getAttribute( ATTR_CODEBASE );
DOMString code = getAttribute( ATTR_CODE );
if ( !codeBase.isEmpty() )
url = codeBase.string();
if ( !code.isEmpty() )
url = code.string();
HTMLObjectBaseElementImpl::computeContent();
}
// -------------------------------------------------------------------------
HTMLEmbedElementImpl::HTMLEmbedElementImpl(DocumentImpl *doc)
: HTMLObjectBaseElementImpl(doc)
{
}
HTMLEmbedElementImpl::~HTMLEmbedElementImpl()
{
}
NodeImpl::Id HTMLEmbedElementImpl::id() const
{
return ID_EMBED;
}
HTMLEmbedElementImpl* HTMLEmbedElementImpl::relevantEmbed()
{
return this;
}
void HTMLEmbedElementImpl::parseAttribute(AttributeImpl *attr)
{
switch ( attr->id() )
{
case ATTR_CODE:
case ATTR_SRC:
url = khtml::parseURL(attr->val()).string();
setNeedComputeContent();
break;
case ATTR_BORDER:
addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
addCSSProperty( CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID );
addCSSProperty( CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID );
addCSSProperty( CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID );
addCSSProperty( CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID );
break;
case ATTR_VSPACE:
addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
break;
case ATTR_HSPACE:
addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
break;
case ATTR_ALIGN:
addHTMLAlignment( attr->value() );
break;
case ATTR_VALIGN:
addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower() );
break;
case ATTR_PLUGINPAGE:
case ATTR_PLUGINSPAGE: {
pluginPage = attr->value().string();
break;
}
case ATTR_HIDDEN:
if (strcasecmp( attr->value(), "yes" ) == 0 || strcasecmp( attr->value() , "true") == 0 )
hidden = true;
else
hidden = false;
break;
default:
HTMLObjectBaseElementImpl::parseAttribute( attr );
}
}
void HTMLEmbedElementImpl::attach()
{
if (parentNode()->id() == ID_OBJECT)
NodeBaseImpl::attach();
else
HTMLObjectBaseElementImpl::attach();
}
void HTMLEmbedElementImpl::computeContent()
{
if (parentNode()->id() != ID_OBJECT)
HTMLObjectBaseElementImpl::computeContent();
}
// -------------------------------------------------------------------------
HTMLObjectElementImpl::HTMLObjectElementImpl(DocumentImpl *doc)
: HTMLObjectBaseElementImpl(doc)
{
}
HTMLObjectElementImpl::~HTMLObjectElementImpl()
{
}
NodeImpl::Id HTMLObjectElementImpl::id() const
{
return ID_OBJECT;
}
HTMLFormElementImpl *HTMLObjectElementImpl::form() const
{
return 0;
}
void HTMLObjectElementImpl::parseAttribute(AttributeImpl *attr)
{
switch ( attr->id() )
{
case ATTR_DATA:
url = khtml::parseURL( attr->val() ).string();
setNeedComputeContent();
break;
case ATTR_CLASSID:
classId = attr->value().string();
setNeedComputeContent();
break;
case ATTR_ONLOAD: // ### support load/unload on object elements
setHTMLEventListener(EventImpl::LOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onload", this));
break;
case ATTR_ONUNLOAD:
setHTMLEventListener(EventImpl::UNLOAD_EVENT,
document()->createHTMLEventListener(attr->value().string(), "onunload", this));
break;
case ATTR_VSPACE:
addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
break;
case ATTR_HSPACE:
addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
break;
case ATTR_ALIGN:
addHTMLAlignment( attr->value() );
break;
case ATTR_VALIGN:
addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower() );
break;
default:
HTMLObjectBaseElementImpl::parseAttribute( attr );
}
}
DocumentImpl* HTMLObjectElementImpl::contentDocument() const
{
QWidget* widget = childWidget();
if( widget && qobject_cast<KHTMLView*>( widget ) )
return static_cast<KHTMLView*>( widget )->part()->xmlDocImpl();
return 0;
}
void HTMLObjectElementImpl::attach()
{
HTMLObjectBaseElementImpl::attach();
}
// -------------------------------------------------------------------------
NodeImpl::Id HTMLParamElementImpl::id() const
{
return ID_PARAM;
}
void HTMLParamElementImpl::parseAttribute(AttributeImpl *attr)
{
switch( attr->id() )
{
case ATTR_VALUE:
m_value = attr->value().string();
break;
case ATTR_ID:
if (document()->htmlMode() != DocumentImpl::XHtml) break;
// fall through
case ATTR_NAME:
m_name = attr->value().string();
// fall through
default:
HTMLElementImpl::parseAttribute(attr);
}
}
#include "html_objectimpl.moc"
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
diff --git a/khtml/xml/dom_docimpl.cpp b/khtml/xml/dom_docimpl.cpp
index b1f940e078..6345f2e5ba 100644
--- a/khtml/xml/dom_docimpl.cpp
+++ b/khtml/xml/dom_docimpl.cpp
@@ -1,3255 +1,3255 @@
/**
* 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 Dirk Mueller (mueller@kde.org)
* (C) 2002-2006 Apple Computer, Inc.
* (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
* (C) 2005 Frerich Raabe <raabe@kde.org>
* (C) 2010 Maksim Orlovich <maksim@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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "dom_docimpl.h"
#include <dom/dom_exception.h>
#include "dom_textimpl.h"
#include "dom_xmlimpl.h"
#include "dom2_rangeimpl.h"
#include "dom2_eventsimpl.h"
#include "xml_tokenizer.h"
#include <html/htmltokenizer.h>
#include "dom_restyler.h"
#include <css/csshelper.h>
#include <css/cssstyleselector.h>
#include <css/css_stylesheetimpl.h>
#include <misc/helper.h>
#include <misc/seed.h>
#include <misc/loader.h>
#include <ecma/kjs_proxy.h>
#include <ecma/kjs_binding.h>
#include <QtCore/QStack>
//Added by qt3to4:
#include <QTimerEvent>
#include <QtCore/QList>
#include <kdebug.h>
#include <klocale.h>
#include <rendering/counter_tree.h>
#include <rendering/render_canvas.h>
#include <rendering/render_replaced.h>
#include <rendering/render_arena.h>
#include <rendering/render_layer.h>
#include <rendering/render_frames.h>
#include <rendering/render_image.h>
#include <khtmlview.h>
#include <khtml_part.h>
#include <kauthorized.h>
#include <kglobalsettings.h>
#include <kstringhandler.h>
#include <kdatetime.h>
#include <khtml_settings.h>
#include <khtmlpart_p.h>
#include <xml/dom3_xpathimpl.h>
#include <html/html_baseimpl.h>
#include <html/html_blockimpl.h>
#include <html/html_canvasimpl.h>
#include <html/html_documentimpl.h>
#include <html/html_formimpl.h>
#include <html/html_headimpl.h>
#include <html/html_imageimpl.h>
#include <html/html_listimpl.h>
#include <html/html_miscimpl.h>
#include <html/html_tableimpl.h>
#include <html/html_objectimpl.h>
#include <html/HTMLAudioElement.h>
#include <html/HTMLVideoElement.h>
#include <html/HTMLSourceElement.h>
#include <editing/jsediting.h>
#include <ecma/kjs_window.h>
// SVG (WebCore)
#include <svg/SVGElement.h>
#include <svg/SVGSVGElement.h>
#include <svg/SVGNames.h>
#include <svg/SVGDocumentExtensions.h>
#include <svg/SVGRectElement.h>
#include <svg/SVGDocument.h>
#include <svg/SVGCircleElement.h>
#include <svg/SVGStyleElement.h>
#include <svg/SVGEllipseElement.h>
#include <svg/SVGPolygonElement.h>
#include <svg/SVGPolylineElement.h>
#include <svg/SVGPathElement.h>
#include <svg/SVGDefsElement.h>
#include <svg/SVGLinearGradientElement.h>
#include <svg/SVGRadialGradientElement.h>
#include <svg/SVGStopElement.h>
#include <svg/SVGClipPathElement.h>
#include <svg/SVGGElement.h>
#include <svg/SVGUseElement.h>
#include <svg/SVGLineElement.h>
#include <svg/SVGTextElement.h>
#include <svg/SVGAElement.h>
#include <svg/SVGScriptElement.h>
#include <svg/SVGDescElement.h>
#include <svg/SVGTitleElement.h>
#include <svg/SVGTextPathElement.h>
#include <svg/SVGTSpanElement.h>
#include <svg/SVGHKernElement.h>
#include <svg/SVGAltGlyphElement.h>
#include <svg/SVGFontElement.h>
#include <kio/job.h>
#include <stdlib.h>
#include <limits.h>
template class QStack<DOM::NodeImpl*>;
using namespace DOM;
using namespace khtml;
// ------------------------------------------------------------------------
DOMImplementationImpl::DOMImplementationImpl()
{
}
DOMImplementationImpl::~DOMImplementationImpl()
{
}
bool DOMImplementationImpl::hasFeature ( const DOMString &feature, const DOMString &version )
{
// ### update when we (fully) support the relevant features
QString lower = feature.string().toLower();
if ((lower == "html" || lower == "xml") &&
(version.isEmpty() || version == "1.0" || version == "2.0"))
return true;
// ## Do we support Core Level 3 ?
if ((lower == "core" ) &&
(version.isEmpty() || version == "2.0"))
return true;
if ((lower == "traversal") &&
(version.isEmpty() || version == "2.0"))
return true;
if ((lower == "css") &&
(version.isEmpty() || version == "2.0"))
return true;
if ((lower == "events" || lower == "uievents" ||
lower == "mouseevents" || lower == "mutationevents" ||
lower == "htmlevents" || lower == "textevents" ) &&
(version.isEmpty() || version == "2.0" || version == "3.0"))
return true;
if (lower == "selectors-api" && version == "1.0")
return true;
return false;
}
DocumentTypeImpl *DOMImplementationImpl::createDocumentType( const DOMString &qualifiedName, const DOMString &publicId,
const DOMString &systemId, int &exceptioncode )
{
// Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
if (qualifiedName.isNull()) {
exceptioncode = DOMException::NAMESPACE_ERR;
return 0;
}
// INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
if (!Element::khtmlValidQualifiedName(qualifiedName)) {
exceptioncode = DOMException::INVALID_CHARACTER_ERR;
return 0;
}
// NAMESPACE_ERR: Raised if the qualifiedName is malformed.
// Added special case for the empty string, which seems to be a common pre-DOM2 misuse
if (!qualifiedName.isEmpty() && Element::khtmlMalformedQualifiedName(qualifiedName)) {
exceptioncode = DOMException::NAMESPACE_ERR;
return 0;
}
return new DocumentTypeImpl(this, 0, qualifiedName, publicId, systemId);
}
DocumentImpl *DOMImplementationImpl::createDocument( const DOMString &namespaceURI, const DOMString &qualifiedName,
DocumentTypeImpl* dtype,
KHTMLView* v,
int &exceptioncode )
{
exceptioncode = 0;
if (!checkQualifiedName(qualifiedName, namespaceURI, 0, true/*nameCanBeNull*/,
true /*nameCanBeEmpty, see #61650*/, &exceptioncode) )
return 0;
// WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
// created from a different implementation.
// We elide the "different implementation" case here, since we're not doing interop
// of different implementations, and different impl objects exist only for
// isolation reasons
if (dtype && dtype->document()) {
exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
return 0;
}
// ### view can be 0 which can cause problems
DocumentImpl* doc;
if (namespaceURI == XHTML_NAMESPACE)
doc = new HTMLDocumentImpl(v);
else
doc = new DocumentImpl(v);
if (dtype) {
dtype->setDocument(doc);
doc->appendChild(dtype,exceptioncode);
}
// the document must be created empty if all parameters are null
// (or empty for qName/nsURI as a tolerance) - see DOM 3 Core.
if (dtype || !qualifiedName.isEmpty() || !namespaceURI.isEmpty()) {
ElementImpl *element = doc->createElementNS(namespaceURI,qualifiedName);
doc->appendChild(element,exceptioncode);
if (exceptioncode) {
delete element;
delete doc;
return 0;
}
}
return doc;
}
CSSStyleSheetImpl *DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl* title, DOMStringImpl *media,
int &/*exceptioncode*/)
{
// ### TODO : media could have wrong syntax, in which case we should
// generate an exception.
CSSStyleSheetImpl *parent = 0L;
CSSStyleSheetImpl *sheet = new CSSStyleSheetImpl(parent, DOMString());
sheet->setMedia(new MediaListImpl(sheet, media, true /*fallbackToDescriptor*/));
sheet->setTitle(DOMString(title));
return sheet;
}
DocumentImpl *DOMImplementationImpl::createDocument( KHTMLView *v )
{
DocumentImpl* doc = new DocumentImpl(v);
return doc;
}
XMLDocumentImpl *DOMImplementationImpl::createXMLDocument( KHTMLView *v )
{
XMLDocumentImpl* doc = new XMLDocumentImpl(v);
return doc;
}
HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument( KHTMLView *v )
{
HTMLDocumentImpl* doc = new HTMLDocumentImpl(v);
return doc;
}
// create SVG document
WebCore::SVGDocument *DOMImplementationImpl::createSVGDocument( KHTMLView *v )
{
WebCore::SVGDocument* doc = new WebCore::SVGDocument(v);
return doc;
}
HTMLDocumentImpl* DOMImplementationImpl::createHTMLDocument( const DOMString& title )
{
HTMLDocumentImpl* r = createHTMLDocument( 0 /* ### create a view otherwise it doesn't work */);
r->open();
r->write(QLatin1String("<HTML><HEAD><TITLE>") + title.string() +
QLatin1String("</TITLE></HEAD>"));
return r;
}
// ------------------------------------------------------------------------
ElementMappingCache::ElementMappingCache():m_dict()
{
}
ElementMappingCache::~ElementMappingCache()
{
qDeleteAll( m_dict );
}
void ElementMappingCache::add(const DOMString& id, ElementImpl* nd)
{
if (id.isEmpty()) return;
ItemInfo* info = m_dict.value(id);
if (info)
{
info->ref++;
info->nd = 0; //Now ambigous
}
else
{
ItemInfo* info = new ItemInfo();
info->ref = 1;
info->nd = nd;
m_dict.insert(id, info);
}
}
void ElementMappingCache::set(const DOMString& id, ElementImpl* nd)
{
if (id.isEmpty()) return;
assert(m_dict.contains(id));
ItemInfo* info = m_dict.value(id);
info->nd = nd;
}
void ElementMappingCache::remove(const DOMString& id, ElementImpl* nd)
{
if (id.isEmpty()) return;
assert(m_dict.contains(id));
ItemInfo* info = m_dict.value(id);
info->ref--;
if (info->ref == 0)
{
m_dict.take(id);
delete info;
}
else
{
if (info->nd == nd)
info->nd = 0;
}
}
bool ElementMappingCache::contains(const DOMString& id)
{
if (id.isEmpty()) return false;
return m_dict.contains(id);
}
ElementMappingCache::ItemInfo* ElementMappingCache::get(const DOMString& id)
{
if (id.isEmpty()) return 0;
return m_dict.value(id);
}
typedef QList<DocumentImpl*> ChangedDocuments ;
K_GLOBAL_STATIC(ChangedDocuments, s_changedDocuments)
// KHTMLView might be 0
DocumentImpl::DocumentImpl(KHTMLView *v)
: NodeBaseImpl( 0 ), m_svgExtensions(0), m_counterDict(),
m_imageLoadEventTimer(0)
{
m_document.resetSkippingRef(this); //Make document return us..
m_selfOnlyRefCount = 0;
m_paintDevice = 0;
//m_decoderMibEnum = 0;
m_textColor = Qt::black;
m_view = v;
m_renderArena.reset();
KHTMLGlobal::registerDocumentImpl(this);
if ( v ) {
m_docLoader = new DocLoader(v->part(), this );
setPaintDevice( m_view );
}
else
m_docLoader = new DocLoader( 0, this );
visuallyOrdered = false;
m_bParsing = false;
m_docChanged = false;
m_elemSheet = 0;
m_tokenizer = 0;
m_decoder = 0;
m_doctype = 0;
m_implementation = 0;
pMode = Strict;
hMode = XHtml;
m_htmlCompat = false;
m_textColor = "#000000";
m_focusNode = 0;
m_hoverNode = 0;
m_activeNode = 0;
m_defaultView = new AbstractViewImpl(this);
m_defaultView->ref();
m_listenerTypes = 0;
m_styleSheets = new StyleSheetListImpl(this);
m_styleSheets->ref();
m_addedStyleSheets = 0;
m_inDocument = true;
m_styleSelectorDirty = false;
m_styleSelector = 0;
m_styleSheetListDirty = true;
m_inStyleRecalc = false;
m_pendingStylesheets = 0;
m_ignorePendingStylesheets = false;
m_async = true;
m_hadLoadError = false;
m_docLoading = false;
m_bVariableLength = false;
m_inSyncLoad = 0;
m_loadingXMLDoc = 0;
m_documentElement = 0;
m_cssTarget = 0;
m_jsEditor = 0;
m_dynamicDomRestyler = new khtml::DynamicDomRestyler();
m_stateRestorePos = 0;
m_windowEventTarget = new WindowEventTargetImpl(this);
m_windowEventTarget->ref();
for (int c = 0; c < NumTreeVersions; ++c)
m_domTreeVersions[c] = 0;
}
void DocumentImpl::removedLastRef()
{
if (m_selfOnlyRefCount) {
/* In this case, the only references to us are from children,
so we have a cycle. We'll try to break it by disconnecting the
children from us; this sucks/is wrong, but it's pretty much
the best we can do without tracing.
Of course, if dumping the children causes the refcount from them to
drop to 0 we can get killed right here, so better hold
a temporary reference, too
*/
DocPtr<DocumentImpl> guard(this);
// we must make sure not to be retaining any of our children through
// these extra pointers or we will create a reference cycle
if (m_doctype) {
m_doctype->deref();
m_doctype = 0;
}
if (m_cssTarget) {
m_cssTarget->deref();
m_cssTarget = 0;
}
if (m_focusNode) {
m_focusNode->deref();
m_focusNode = 0;
}
if (m_hoverNode) {
m_hoverNode->deref();
m_hoverNode = 0;
}
if (m_activeNode) {
m_activeNode->deref();
m_activeNode = 0;
}
if (m_documentElement) {
m_documentElement->deref();
m_documentElement = 0;
}
removeChildren();
delete m_tokenizer;
m_tokenizer = 0;
} else {
delete this;
}
}
DocumentImpl::~DocumentImpl()
{
//Important: if you need to remove stuff here,
//you may also have to fix removedLastRef() above - M.O.
assert( !m_render );
QHashIterator<long,DynamicNodeListImpl::Cache*> it(m_nodeListCache);
while (it.hasNext())
it.next().value()->deref();
if (m_loadingXMLDoc)
m_loadingXMLDoc->deref(this);
if (s_changedDocuments && m_docChanged)
s_changedDocuments->removeAll(this);
delete m_tokenizer;
m_document.resetSkippingRef(0);
delete m_styleSelector;
delete m_docLoader;
if (m_elemSheet ) m_elemSheet->deref();
if (m_doctype)
m_doctype->deref();
if (m_implementation)
m_implementation->deref();
delete m_dynamicDomRestyler;
delete m_jsEditor;
m_defaultView->deref();
m_styleSheets->deref();
if (m_addedStyleSheets)
m_addedStyleSheets->deref();
if (m_cssTarget)
m_cssTarget->deref();
if (m_focusNode)
m_focusNode->deref();
if ( m_hoverNode )
m_hoverNode->deref();
if (m_activeNode)
m_activeNode->deref();
if (m_documentElement)
m_documentElement->deref();
m_windowEventTarget->deref();
qDeleteAll(m_counterDict);
m_renderArena.reset();
KHTMLGlobal::deregisterDocumentImpl(this);
}
DOMImplementationImpl *DocumentImpl::implementation() const
{
if (!m_implementation) {
m_implementation = new DOMImplementationImpl();
m_implementation->ref();
}
return m_implementation;
}
void DocumentImpl::childrenChanged()
{
// invalidate the document element we have cached in case it was replaced
if (m_documentElement)
m_documentElement->deref();
m_documentElement = 0;
// same for m_docType
if (m_doctype)
m_doctype->deref();
m_doctype = 0;
}
ElementImpl *DocumentImpl::documentElement() const
{
if (!m_documentElement) {
NodeImpl* n = firstChild();
while (n && n->nodeType() != Node::ELEMENT_NODE)
n = n->nextSibling();
m_documentElement = static_cast<ElementImpl*>(n);
if (m_documentElement)
m_documentElement->ref();
}
return m_documentElement;
}
DocumentTypeImpl *DocumentImpl::doctype() const
{
if (!m_doctype) {
NodeImpl* n = firstChild();
while (n && n->nodeType() != Node::DOCUMENT_TYPE_NODE)
n = n->nextSibling();
m_doctype = static_cast<DocumentTypeImpl*>(n);
if (m_doctype)
m_doctype->ref();
}
return m_doctype;
}
ElementImpl *DocumentImpl::createElement( const DOMString &name, int* pExceptioncode )
{
if (pExceptioncode && !Element::khtmlValidQualifiedName(name)) {
*pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
return 0;
}
PrefixName prefix;
LocalName localName;
bool htmlCompat = htmlMode() != XHtml;
splitPrefixLocalName(name, prefix, localName, htmlCompat);
XMLElementImpl* e = new XMLElementImpl(document(), emptyNamespaceName, localName, prefix);
e->setHTMLCompat(htmlCompat); // Not a real HTML element, but inside an html-compat doc all tags are uppercase.
return e;
}
AttrImpl *DocumentImpl::createAttribute( const DOMString &tagName, int* pExceptioncode )
{
if (pExceptioncode && !Element::khtmlValidAttrName(tagName)) {
*pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
return 0;
}
PrefixName prefix;
LocalName localName;
bool htmlCompat = (htmlMode() != XHtml);
splitPrefixLocalName(tagName, prefix, localName, htmlCompat);
AttrImpl* attr = new AttrImpl(0, document(), NamespaceName::fromId(emptyNamespace),
localName, prefix, DOMString("").implementation());
attr->setHTMLCompat(htmlCompat);
return attr;
}
DocumentFragmentImpl *DocumentImpl::createDocumentFragment( )
{
return new DocumentFragmentImpl( docPtr() );
}
CommentImpl *DocumentImpl::createComment ( DOMStringImpl* data )
{
return new CommentImpl( docPtr(), data );
}
CDATASectionImpl *DocumentImpl::createCDATASection ( DOMStringImpl* data )
{
return new CDATASectionImpl( docPtr(), data );
}
ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction ( const DOMString &target, DOMStringImpl* data )
{
return new ProcessingInstructionImpl( docPtr(),target,data);
}
EntityReferenceImpl *DocumentImpl::createEntityReference ( const DOMString &name )
{
return new EntityReferenceImpl(docPtr(), name.implementation());
}
EditingTextImpl *DocumentImpl::createEditingTextNode(const DOMString &text)
{
return new EditingTextImpl(docPtr(), text);
}
NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
{
NodeImpl *result = 0;
// Not mentioned in spec: throw NOT_FOUND_ERR if evt is null
if (!importedNode) {
exceptioncode = DOMException::NOT_FOUND_ERR;
return 0;
}
if(importedNode->nodeType() == Node::ELEMENT_NODE)
{
// Why not use cloneNode?
ElementImpl *otherElem = static_cast<ElementImpl*>(importedNode);
NamedAttrMapImpl *otherMap = static_cast<ElementImpl *>(importedNode)->attributes(true);
ElementImpl *tempElementImpl;
tempElementImpl = createElementNS(otherElem->namespaceURI(),otherElem->nonCaseFoldedTagName());
tempElementImpl->setHTMLCompat(htmlMode() != XHtml && otherElem->htmlCompat());
result = tempElementImpl;
if(otherMap) {
for(unsigned i = 0; i < otherMap->length(); i++)
{
AttrImpl *otherAttr = otherMap->attributeAt(i).createAttr(otherElem,otherElem->docPtr());
tempElementImpl->setAttributeNS(otherAttr->namespaceURI(),
otherAttr->name(),
otherAttr->nodeValue(),
exceptioncode);
if(exceptioncode != 0)
break; // ### properly cleanup here
}
}
}
else if(importedNode->nodeType() == Node::TEXT_NODE)
{
result = createTextNode(static_cast<TextImpl*>(importedNode)->string());
deep = false;
}
else if(importedNode->nodeType() == Node::CDATA_SECTION_NODE)
{
result = createCDATASection(static_cast<CDATASectionImpl*>(importedNode)->string());
deep = false;
}
else if(importedNode->nodeType() == Node::ENTITY_REFERENCE_NODE)
result = createEntityReference(importedNode->nodeName());
else if(importedNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
{
result = createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue().implementation());
deep = false;
}
else if(importedNode->nodeType() == Node::COMMENT_NODE)
{
result = createComment(static_cast<CommentImpl*>(importedNode)->string());
deep = false;
}
else if (importedNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
result = createDocumentFragment();
else
exceptioncode = DOMException::NOT_SUPPORTED_ERR;
//### FIXME: This should handle Attributes, and a few other things
if(deep && result)
{
for(Node n = importedNode->firstChild(); !n.isNull(); n = n.nextSibling())
result->appendChild(importNode(n.handle(), true, exceptioncode), exceptioncode);
}
return result;
}
ElementImpl *DocumentImpl::createElementNS( const DOMString &_namespaceURI, const DOMString &_qualifiedName, int* pExceptioncode )
{
ElementImpl *e = 0;
int colonPos = -2;
// check NAMESPACE_ERR/INVALID_CHARACTER_ERR
if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos,
false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
pExceptioncode))
return 0;
DOMString prefix, localName;
splitPrefixLocalName(_qualifiedName.implementation(), prefix, localName, colonPos);
if (_namespaceURI == SVG_NAMESPACE) {
e = createSVGElement(QualifiedName(prefix, localName, _namespaceURI));
if (e) return e;
if (!e) {
kWarning() << "svg element" << localName << "either is not supported by khtml or it's not a proper svg element";
}
}
// Regardless of document type (even for HTML), this method will only create HTML
// elements if given the namespace explicitly. Further, this method is always
// case sensitive, again, even in HTML; however .tagName will case-normalize
// in HTML regardless
if (_namespaceURI == XHTML_NAMESPACE) {
e = createHTMLElement(localName, false /* case sensitive */);
int _exceptioncode = 0;
if (!prefix.isNull())
e->setPrefix(prefix, _exceptioncode);
if ( _exceptioncode ) {
if ( pExceptioncode ) *pExceptioncode = _exceptioncode;
delete e;
return 0;
}
}
if (!e) {
e = new XMLElementImpl(document(), NamespaceName::fromString(_namespaceURI),
LocalName::fromString(localName), PrefixName::fromString(prefix));
}
return e;
}
AttrImpl *DocumentImpl::createAttributeNS( const DOMString &_namespaceURI,
const DOMString &_qualifiedName, int* pExceptioncode)
{
int colonPos = -2;
// check NAMESPACE_ERR/INVALID_CHARACTER_ERR
if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos,
false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
pExceptioncode))
return 0;
PrefixName prefix;
LocalName localName;
bool htmlCompat = _namespaceURI.isNull() && htmlMode() != XHtml;
splitPrefixLocalName(_qualifiedName, prefix, localName, false, colonPos);
AttrImpl* attr = new AttrImpl(0, document(), NamespaceName::fromString(_namespaceURI),
localName, prefix, DOMString("").implementation());
attr->setHTMLCompat( htmlCompat );
return attr;
}
ElementImpl *DocumentImpl::getElementById( const DOMString &elementId ) const
{
ElementMappingCache::ItemInfo* info = m_getElementByIdCache.get(elementId);
if (!info)
return 0;
//See if cache has an unambiguous answer.
if (info->nd)
return info->nd;
//Now we actually have to walk.
QStack<NodeImpl*> nodeStack;
NodeImpl *current = _first;
while(1)
{
if(!current)
{
if(nodeStack.isEmpty()) break;
current = nodeStack.pop();
current = current->nextSibling();
}
else
{
if(current->isElementNode())
{
ElementImpl *e = static_cast<ElementImpl *>(current);
if(e->getAttribute(ATTR_ID) == elementId) {
info->nd = e;
return e;
}
}
NodeImpl *child = current->firstChild();
if(child)
{
nodeStack.push(current);
current = child;
}
else
{
current = current->nextSibling();
}
}
}
assert(0); //If there is no item with such an ID, we should never get here
//kDebug() << "WARNING: *DocumentImpl::getElementById not found " << elementId.string();
return 0;
}
void DocumentImpl::setTitle(const DOMString& _title)
{
if (_title == m_title && !m_title.isNull()) return;
m_title = _title;
QString titleStr = m_title.string();
for (int i = 0; i < titleStr.length(); ++i)
if (titleStr[i] < ' ')
titleStr[i] = ' ';
titleStr = titleStr.simplified();
if ( view() && !view()->part()->parentPart() ) {
- if (titleStr.isNull() || titleStr.isEmpty()) {
+ if (titleStr.isEmpty()) {
// empty title... set window caption as the URL
KUrl url = m_url;
url.setRef(QString());
url.setQuery(QString());
titleStr = url.prettyUrl();
}
emit view()->part()->setWindowCaption( titleStr );
}
}
DOMString DocumentImpl::nodeName() const
{
return "#document";
}
unsigned short DocumentImpl::nodeType() const
{
return Node::DOCUMENT_NODE;
}
ElementImpl *DocumentImpl::createHTMLElement( const DOMString &name, bool caseInsensitive )
{
LocalName localname = LocalName::fromString(name,
caseInsensitive ? IDS_NormalizeLower : IDS_CaseSensitive);
uint id = localname.id();
ElementImpl *n = 0;
switch(id)
{
case ID_HTML:
n = new HTMLHtmlElementImpl(docPtr());
break;
case ID_HEAD:
n = new HTMLHeadElementImpl(docPtr());
break;
case ID_BODY:
n = new HTMLBodyElementImpl(docPtr());
break;
// head elements
case ID_BASE:
n = new HTMLBaseElementImpl(docPtr());
break;
case ID_LINK:
n = new HTMLLinkElementImpl(docPtr());
break;
case ID_META:
n = new HTMLMetaElementImpl(docPtr());
break;
case ID_STYLE:
n = new HTMLStyleElementImpl(docPtr());
break;
case ID_TITLE:
n = new HTMLTitleElementImpl(docPtr());
break;
// frames
case ID_FRAME:
n = new HTMLFrameElementImpl(docPtr());
break;
case ID_FRAMESET:
n = new HTMLFrameSetElementImpl(docPtr());
break;
case ID_IFRAME:
n = new HTMLIFrameElementImpl(docPtr());
break;
// form elements
// ### FIXME: we need a way to set form dependency after we have made the form elements
case ID_FORM:
n = new HTMLFormElementImpl(docPtr(), false);
break;
case ID_BUTTON:
n = new HTMLButtonElementImpl(docPtr());
break;
case ID_FIELDSET:
n = new HTMLFieldSetElementImpl(docPtr());
break;
case ID_INPUT:
n = new HTMLInputElementImpl(docPtr());
break;
case ID_ISINDEX:
n = new HTMLIsIndexElementImpl(docPtr());
break;
case ID_LABEL:
n = new HTMLLabelElementImpl(docPtr());
break;
case ID_LEGEND:
n = new HTMLLegendElementImpl(docPtr());
break;
case ID_OPTGROUP:
n = new HTMLOptGroupElementImpl(docPtr());
break;
case ID_OPTION:
n = new HTMLOptionElementImpl(docPtr());
break;
case ID_SELECT:
n = new HTMLSelectElementImpl(docPtr());
break;
case ID_TEXTAREA:
n = new HTMLTextAreaElementImpl(docPtr());
break;
// lists
case ID_DL:
n = new HTMLDListElementImpl(docPtr());
break;
case ID_DD:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
case ID_DT:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
case ID_UL:
n = new HTMLUListElementImpl(docPtr());
break;
case ID_OL:
n = new HTMLOListElementImpl(docPtr());
break;
case ID_DIR:
n = new HTMLDirectoryElementImpl(docPtr());
break;
case ID_MENU:
n = new HTMLMenuElementImpl(docPtr());
break;
case ID_LI:
n = new HTMLLIElementImpl(docPtr());
break;
// formatting elements (block)
case ID_DIV:
case ID_P:
n = new HTMLDivElementImpl( docPtr(), id );
break;
case ID_BLOCKQUOTE:
case ID_H1:
case ID_H2:
case ID_H3:
case ID_H4:
case ID_H5:
case ID_H6:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
case ID_HR:
n = new HTMLHRElementImpl(docPtr());
break;
case ID_PLAINTEXT:
case ID_XMP:
case ID_PRE:
case ID_LISTING:
n = new HTMLPreElementImpl(docPtr(), id);
break;
// font stuff
case ID_BASEFONT:
n = new HTMLBaseFontElementImpl(docPtr());
break;
case ID_FONT:
n = new HTMLFontElementImpl(docPtr());
break;
// ins/del
case ID_DEL:
case ID_INS:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
// anchor
case ID_A:
n = new HTMLAnchorElementImpl(docPtr());
break;
// images
case ID_IMG:
case ID_IMAGE: // legacy name
n = new HTMLImageElementImpl(docPtr());
break;
case ID_CANVAS:
n = new HTMLCanvasElementImpl(docPtr());
break;
case ID_MAP:
n = new HTMLMapElementImpl(docPtr());
/*n = map;*/
break;
case ID_AREA:
n = new HTMLAreaElementImpl(docPtr());
break;
// objects, applets and scripts
case ID_APPLET:
n = new HTMLAppletElementImpl(docPtr());
break;
case ID_OBJECT:
n = new HTMLObjectElementImpl(docPtr());
break;
case ID_EMBED:
n = new HTMLEmbedElementImpl(docPtr());
break;
case ID_PARAM:
n = new HTMLParamElementImpl(docPtr());
break;
case ID_SCRIPT:
n = new HTMLScriptElementImpl(docPtr());
break;
// media
case ID_AUDIO:
n = new HTMLAudioElement(docPtr());
break;
case ID_VIDEO:
n = new HTMLVideoElement(docPtr());
break;
case ID_SOURCE:
n = new HTMLSourceElement(docPtr());
break;
// tables
case ID_TABLE:
n = new HTMLTableElementImpl(docPtr());
break;
case ID_CAPTION:
n = new HTMLTableCaptionElementImpl(docPtr());
break;
case ID_COLGROUP:
case ID_COL:
n = new HTMLTableColElementImpl(docPtr(), id);
break;
case ID_TR:
n = new HTMLTableRowElementImpl(docPtr());
break;
case ID_TD:
case ID_TH:
n = new HTMLTableCellElementImpl(docPtr(), id);
break;
case ID_THEAD:
case ID_TBODY:
case ID_TFOOT:
n = new HTMLTableSectionElementImpl(docPtr(), id, false);
break;
// inline elements
case ID_BR:
n = new HTMLBRElementImpl(docPtr());
break;
case ID_WBR:
n = new HTMLWBRElementImpl(docPtr());
break;
case ID_Q:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
// elements with no special representation in the DOM
// block:
case ID_ADDRESS:
case ID_CENTER:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
// inline
// %fontstyle
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_BDO:
case ID_NOFRAMES:
case ID_NOSCRIPT:
case ID_NOEMBED:
case ID_NOLAYER:
n = new HTMLGenericElementImpl(docPtr(), id);
break;
case ID_MARQUEE:
n = new HTMLMarqueeElementImpl(docPtr());
break;
// text
case ID_TEXT:
kDebug( 6020 ) << "Use document->createTextNode()";
break;
default:
n = new HTMLGenericElementImpl(docPtr(), localname);
break;
}
assert(n);
return n;
}
// SVG
ElementImpl *DocumentImpl::createSVGElement(const QualifiedName& name)
{
uint id = name.localNameId().id();
kDebug() << getPrintableName(name.id()) << endl;
kDebug() << "svg text: " << getPrintableName(WebCore::SVGNames::textTag.id()) << endl;
ElementImpl *n = 0;
switch (id)
{
case ID_TEXTPATH:
n = new WebCore::SVGTextPathElement(name, docPtr());
break;
case ID_TSPAN:
n = new WebCore::SVGTSpanElement(name, docPtr());
break;
case ID_HKERN:
n = new WebCore::SVGHKernElement(name, docPtr());
break;
case ID_ALTGLYPH:
n = new WebCore::SVGAltGlyphElement(name, docPtr());
break;
case ID_FONT:
n = new WebCore::SVGFontElement(name, docPtr());
break;
}
if (id == WebCore::SVGNames::svgTag.localNameId().id()) {
n = new WebCore::SVGSVGElement(name, docPtr());
}
if (id == WebCore::SVGNames::rectTag.localNameId().id()) {
n = new WebCore::SVGRectElement(name, docPtr());
}
if (id == WebCore::SVGNames::circleTag.localNameId().id()) {
n = new WebCore::SVGCircleElement(name, docPtr());
}
if (id == WebCore::SVGNames::ellipseTag.localNameId().id()) {
n = new WebCore::SVGEllipseElement(name, docPtr());
}
if (id == WebCore::SVGNames::polylineTag.localNameId().id()) {
n = new WebCore::SVGPolylineElement(name, docPtr());
}
if (id == WebCore::SVGNames::polygonTag.localNameId().id()) {
n = new WebCore::SVGPolygonElement(name, docPtr());
}
if (id == WebCore::SVGNames::pathTag.localNameId().id()) {
n = new WebCore::SVGPathElement(name, docPtr());
}
if (id == WebCore::SVGNames::defsTag.localNameId().id()) {
n = new WebCore::SVGDefsElement(name, docPtr());
}
if (id == WebCore::SVGNames::linearGradientTag.localNameId().id()) {
n = new WebCore::SVGLinearGradientElement(name, docPtr());
}
if (id == WebCore::SVGNames::radialGradientTag.localNameId().id()) {
n = new WebCore::SVGRadialGradientElement(name, docPtr());
}
if (id == WebCore::SVGNames::stopTag.localNameId().id()) {
n = new WebCore::SVGStopElement(name, docPtr());
}
if (id == WebCore::SVGNames::clipPathTag.localNameId().id()) {
n = new WebCore::SVGClipPathElement(name, docPtr());
}
if (id == WebCore::SVGNames::gTag.localNameId().id()) {
n = new WebCore::SVGGElement(name, docPtr());
}
if (id == WebCore::SVGNames::useTag.localNameId().id()) {
n = new WebCore::SVGUseElement(name, docPtr());
}
if (id == WebCore::SVGNames::lineTag.localNameId().id()) {
n = new WebCore::SVGLineElement(name, docPtr());
}
if (id == WebCore::SVGNames::textTag.localNameId().id()) {
n = new WebCore::SVGTextElement(name, docPtr());
}
if (id == WebCore::SVGNames::aTag.localNameId().id()) {
n = new WebCore::SVGAElement(name, docPtr());
}
if (id == WebCore::SVGNames::scriptTag.localNameId().id()) {
n = new WebCore::SVGScriptElement(name, docPtr());
}
if (id == WebCore::SVGNames::descTag.localNameId().id()) {
n = new WebCore::SVGDescElement(name, docPtr());
}
if (id == WebCore::SVGNames::titleTag.localNameId().id()) {
n = new WebCore::SVGTitleElement(name, docPtr());
}
if (id == makeId(svgNamespace, ID_STYLE)) {
n = new WebCore::SVGStyleElement(name, docPtr());
}
return n;
}
void DocumentImpl::attemptRestoreState(NodeImpl* n)
{
if (!n->isElementNode())
return;
ElementImpl* el = static_cast<ElementImpl*>(n);
if (m_stateRestorePos >= m_state.size())
return;
// Grab the state and element info..
QString idStr = m_state[m_stateRestorePos];
QString nmStr = m_state[m_stateRestorePos + 1];
QString tpStr = m_state[m_stateRestorePos + 2];
QString stStr = m_state[m_stateRestorePos + 3];
// Make sure it matches!
if (idStr.toUInt() != el->id())
return;
if (nmStr != el->getAttribute(ATTR_NAME).string())
return;
if (tpStr != el->getAttribute(ATTR_TYPE).string())
return;
m_stateRestorePos += 4;
if (!stStr.isNull())
el->restoreState(stStr);
}
QStringList DocumentImpl::docState()
{
QStringList s;
for (QListIterator<NodeImpl*> it(m_maintainsState); it.hasNext();) {
NodeImpl* n = it.next();
if (!n->isElementNode())
continue;
ElementImpl* el = static_cast<ElementImpl*>(n);
// Encode the element ID, as well as the name and type attributes
s.append(QString::number(el->id()));
s.append(el->getAttribute(ATTR_NAME).string());
s.append(el->getAttribute(ATTR_TYPE).string());
s.append(el->state());
}
return s;
}
bool DocumentImpl::unsubmittedFormChanges()
{
for (QListIterator<NodeImpl*> it(m_maintainsState); it.hasNext();) {
NodeImpl* node = it.next();
if (node->isGenericFormElement() && static_cast<HTMLGenericFormElementImpl*>(node)->unsubmittedFormChanges())
return true;
}
return false;
}
RangeImpl *DocumentImpl::createRange()
{
return new RangeImpl( docPtr() );
}
NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned long whatToShow,
NodeFilterImpl* filter, bool entityReferenceExpansion,
int &exceptioncode)
{
if (!root) {
exceptioncode = DOMException::NOT_SUPPORTED_ERR;
return 0;
}
return new NodeIteratorImpl(root,whatToShow,filter,entityReferenceExpansion);
}
TreeWalkerImpl *DocumentImpl::createTreeWalker(NodeImpl *root, unsigned long whatToShow, NodeFilterImpl *filter,
bool entityReferenceExpansion, int &exceptioncode)
{
if (!root) {
exceptioncode = DOMException::NOT_SUPPORTED_ERR;
return 0;
}
return new TreeWalkerImpl( root, whatToShow, filter, entityReferenceExpansion );
}
void DocumentImpl::setDocumentChanged(bool b)
{
if (b && !m_docChanged)
s_changedDocuments->append(this);
else if (!b && m_docChanged)
s_changedDocuments->removeAll(this);
m_docChanged = b;
}
void DocumentImpl::recalcStyle( StyleChange change )
{
// qDebug("recalcStyle(%p)", this);
// QTime qt;
// qt.start();
if (m_inStyleRecalc)
return; // Guard against re-entrancy. -dwh
m_inStyleRecalc = true;
if( !m_render ) goto bail_out;
if ( change == Force ) {
RenderStyle* oldStyle = m_render->style();
if ( oldStyle ) oldStyle->ref();
RenderStyle* _style = new RenderStyle();
_style->setDisplay(BLOCK);
_style->setVisuallyOrdered( visuallyOrdered );
// ### make the font stuff _really_ work!!!!
khtml::FontDef fontDef;
QFont f = KGlobalSettings::generalFont();
fontDef.family = f.family();
fontDef.italic = f.italic();
fontDef.weight = f.weight();
if (m_view) {
const KHTMLSettings *settings = m_view->part()->settings();
QString stdfont = settings->stdFontName();
if ( !stdfont.isEmpty() )
fontDef.family = stdfont;
fontDef.size = m_styleSelector->fontSizes()[3];
}
//kDebug() << "DocumentImpl::attach: setting to charset " << settings->charset();
_style->setFontDef(fontDef);
_style->htmlFont().update( 0 );
if ( inCompatMode() )
_style->setHtmlHacks(true); // enable html specific rendering tricks
StyleChange ch = diff( _style, oldStyle );
if(m_render && ch != NoChange)
m_render->setStyle(_style);
else
delete _style;
if (oldStyle)
oldStyle->deref();
}
NodeImpl *n;
for (n = _first; n; n = n->nextSibling())
if ( change>= Inherit || n->hasChangedChild() || n->changed() )
n->recalcStyle( change );
//kDebug( 6020 ) << "TIME: recalcStyle() dt=" << qt.elapsed();
if (changed() && m_view)
m_view->layout();
bail_out:
setChanged( false );
setHasChangedChild( false );
setDocumentChanged( false );
m_inStyleRecalc = false;
}
void DocumentImpl::updateRendering()
{
if (!hasChangedChild()) return;
// QTime time;
// time.start();
// kDebug() << "UPDATERENDERING: ";
StyleChange change = NoChange;
#if 0
if ( m_styleSelectorDirty ) {
recalcStyleSelector();
change = Force;
}
#endif
recalcStyle( change );
// kDebug() << "UPDATERENDERING time used="<<time.elapsed();
}
void DocumentImpl::updateDocumentsRendering()
{
if (!s_changedDocuments)
return;
while ( !s_changedDocuments->isEmpty() ) {
DocumentImpl* it = s_changedDocuments->takeFirst();
if (it->isDocumentChanged())
it->updateRendering();
}
}
void DocumentImpl::updateLayout()
{
if (ElementImpl* oe = ownerElement())
oe->document()->updateLayout();
bool oldIgnore = m_ignorePendingStylesheets;
if (!haveStylesheetsLoaded()) {
m_ignorePendingStylesheets = true;
updateStyleSelector();
}
updateRendering();
// Only do a layout if changes have occurred that make it necessary.
if (m_view && renderer() && renderer()->needsLayout())
m_view->layout();
m_ignorePendingStylesheets = oldIgnore;
}
void DocumentImpl::attach()
{
assert(!attached());
if ( m_view )
setPaintDevice( m_view );
if (!m_renderArena)
m_renderArena.reset(new RenderArena());
// Create the rendering tree
assert(!m_styleSelector);
m_styleSelector = new CSSStyleSelector( this, m_usersheet, m_styleSheets, m_url,
!inCompatMode() );
m_render = new (m_renderArena.get()) RenderCanvas(this, m_view);
m_styleSelector->computeFontSizes(m_paintDevice->logicalDpiY(), m_view ? m_view->part()->fontScaleFactor() : 100);
recalcStyle( Force );
RenderObject* render = m_render;
m_render = 0;
NodeBaseImpl::attach();
m_render = render;
}
void DocumentImpl::detach()
{
RenderObject* render = m_render;
// indicate destruction mode, i.e. attached() but m_render == 0
m_render = 0;
delete m_tokenizer;
m_tokenizer = 0;
// Empty out these lists as a performance optimization
m_imageLoadEventDispatchSoonList.clear();
m_imageLoadEventDispatchingList.clear();
NodeBaseImpl::detach();
if ( render )
render->detach();
m_view = 0;
m_renderArena.reset();
}
void DocumentImpl::setVisuallyOrdered()
{
visuallyOrdered = true;
if (m_render)
m_render->style()->setVisuallyOrdered(true);
}
void DocumentImpl::setSelection(NodeImpl* s, int sp, NodeImpl* e, int ep)
{
if ( m_render )
static_cast<RenderCanvas*>(m_render)->setSelection(s->renderer(),sp,e->renderer(),ep);
}
void DocumentImpl::clearSelection()
{
if ( m_render )
static_cast<RenderCanvas*>(m_render)->clearSelection();
}
void DocumentImpl::updateSelection()
{
if (!m_render)
return;
RenderCanvas *canvas = static_cast<RenderCanvas*>(m_render);
Selection s = part()->caret();
if (s.isEmpty() || s.state() == Selection::CARET) {
canvas->clearSelection();
}
else {
RenderObject *startRenderer = s.start().node() ? s.start().node()->renderer() : 0;
RenderObject *endRenderer = s.end().node() ? s.end().node()->renderer() : 0;
RenderPosition renderedStart = RenderPosition::fromDOMPosition(s.start());
RenderPosition renderedEnd = RenderPosition::fromDOMPosition(s.end());
static_cast<RenderCanvas*>(m_render)->setSelection(startRenderer, renderedStart.renderedOffset(), endRenderer, renderedEnd.renderedOffset());
}
}
khtml::Tokenizer *DocumentImpl::createTokenizer()
{
return new khtml::XMLTokenizer(docPtr(),m_view);
}
int DocumentImpl::logicalDpiY()
{
return m_paintDevice->logicalDpiY();
}
void DocumentImpl::open( bool clearEventListeners )
{
if (parsing()) return;
if (m_tokenizer)
close();
delete m_tokenizer;
m_tokenizer = 0;
KHTMLView* view = m_view;
bool was_attached = attached();
if ( was_attached )
detach();
removeChildren();
childrenChanged(); // Reset m_documentElement, m_doctype
delete m_styleSelector;
m_styleSelector = 0;
m_view = view;
if ( was_attached )
attach();
if (clearEventListeners)
windowEventTarget()->listenerList().clear();
m_tokenizer = createTokenizer();
//m_decoderMibEnum = 0;
connect(m_tokenizer,SIGNAL(finishedParsing()),this,SIGNAL(finishedParsing()));
m_tokenizer->begin();
}
HTMLElementImpl* DocumentImpl::body() const
{
NodeImpl *de = documentElement();
if (!de)
return 0;
// try to prefer a FRAMESET element over BODY
NodeImpl* body = 0;
for (NodeImpl* i = de->firstChild(); i; i = i->nextSibling()) {
if (i->id() == ID_FRAMESET)
return static_cast<HTMLElementImpl*>(i);
if (i->id() == ID_BODY)
body = i;
}
return static_cast<HTMLElementImpl *>(body);
}
void DocumentImpl::close( )
{
if (parsing() && hasVariableLength() && m_tokenizer) {
m_tokenizer->finish();
} else if (parsing() || !m_tokenizer)
return;
if ( m_render )
m_render->close();
// on an explicit document.close(), the tokenizer might still be waiting on scripts,
// and in that case we don't want to destroy it because that will prevent the
// scripts from getting processed.
if (m_tokenizer && !m_tokenizer->isWaitingForScripts() && !m_tokenizer->isExecutingScript()) {
delete m_tokenizer;
m_tokenizer = 0;
}
if (m_view)
m_view->part()->checkEmitLoadEvent();
}
void DocumentImpl::write( const DOMString &text )
{
write(text.string());
}
void DocumentImpl::write( const QString &text )
{
if (!m_tokenizer) {
open();
if (m_view)
m_view->part()->resetFromScript();
setHasVariableLength();
}
m_tokenizer->write(text, false);
}
void DocumentImpl::writeln( const DOMString &text )
{
write(text);
write(DOMString("\n"));
}
void DocumentImpl::finishParsing ( )
{
if(m_tokenizer)
m_tokenizer->finish();
}
QString DocumentImpl::completeURL(const QString& url) const
{
return KUrl(baseURL(),url /*,m_decoderMibEnum*/).url();
}
void DocumentImpl::setUserStyleSheet( const QString& sheet )
{
if ( m_usersheet != sheet ) {
m_usersheet = sheet;
updateStyleSelector();
}
}
CSSStyleSheetImpl* DocumentImpl::elementSheet()
{
if (!m_elemSheet) {
m_elemSheet = new CSSStyleSheetImpl(this, baseURL().url() );
m_elemSheet->ref();
}
return m_elemSheet;
}
void DocumentImpl::determineParseMode()
{
// For XML documents, use strict parse mode
pMode = Strict;
hMode = XHtml;
m_htmlCompat = false;
kDebug(6020) << " using strict parseMode";
}
NodeImpl *DocumentImpl::nextFocusNode(NodeImpl *fromNode)
{
short fromTabIndex;
if (!fromNode) {
// No starting node supplied; begin with the top of the document
NodeImpl *n;
int lowestTabIndex = SHRT_MAX + 1;
for (n = this; n != 0; n = n->traverseNextNode()) {
if (n->isTabFocusable()) {
if ((n->tabIndex() > 0) && (n->tabIndex() < lowestTabIndex))
lowestTabIndex = n->tabIndex();
}
}
if (lowestTabIndex == SHRT_MAX + 1)
lowestTabIndex = 0;
// Go to the first node in the document that has the desired tab index
for (n = this; n != 0; n = n->traverseNextNode()) {
if (n->isTabFocusable() && (n->tabIndex() == lowestTabIndex))
return n;
}
return 0;
}
else {
fromTabIndex = fromNode->tabIndex();
}
if (fromTabIndex == 0) {
// Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index
NodeImpl *n = fromNode->traverseNextNode();
while (n && !(n->isTabFocusable() && n->tabIndex() == 0))
n = n->traverseNextNode();
return n;
}
else {
// Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's
// tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after
// fromNode in document order.
// If we don't find a suitable tab index, the next focus node will be one with a tab index of 0.
int lowestSuitableTabIndex = SHRT_MAX + 1;
NodeImpl *n;
bool reachedFromNode = false;
for (n = this; n != 0; n = n->traverseNextNode()) {
if (n->isTabFocusable() &&
((reachedFromNode && (n->tabIndex() >= fromTabIndex)) ||
(!reachedFromNode && (n->tabIndex() > fromTabIndex))) &&
(n->tabIndex() < lowestSuitableTabIndex) &&
(n != fromNode)) {
// We found a selectable node with a tab index at least as high as fromNode's. Keep searching though,
// as there may be another node which has a lower tab index but is still suitable for use.
lowestSuitableTabIndex = n->tabIndex();
}
if (n == fromNode)
reachedFromNode = true;
}
if (lowestSuitableTabIndex == SHRT_MAX + 1) {
// No next node with a tab index -> just take first node with tab index of 0
NodeImpl *n = this;
while (n && !(n->isTabFocusable() && n->tabIndex() == 0))
n = n->traverseNextNode();
return n;
}
// Search forwards from fromNode
for (n = fromNode->traverseNextNode(); n != 0; n = n->traverseNextNode()) {
if (n->isTabFocusable() && (n->tabIndex() == lowestSuitableTabIndex))
return n;
}
// The next node isn't after fromNode, start from the beginning of the document
for (n = this; n != fromNode; n = n->traverseNextNode()) {
if (n->isTabFocusable() && (n->tabIndex() == lowestSuitableTabIndex))
return n;
}
assert(false); // should never get here
return 0;
}
}
NodeImpl *DocumentImpl::previousFocusNode(NodeImpl *fromNode)
{
NodeImpl *lastNode = this;
while (lastNode->lastChild())
lastNode = lastNode->lastChild();
if (!fromNode) {
// No starting node supplied; begin with the very last node in the document
NodeImpl *n;
int highestTabIndex = 0;
for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
if (n->isTabFocusable()) {
if (n->tabIndex() == 0)
return n;
else if (n->tabIndex() > highestTabIndex)
highestTabIndex = n->tabIndex();
}
}
// No node with a tab index of 0; just go to the last node with the highest tab index
for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
if (n->isTabFocusable() && (n->tabIndex() == highestTabIndex))
return n;
}
return 0;
}
else {
short fromTabIndex = fromNode->tabIndex();
if (fromTabIndex == 0) {
// Find the previous selectable node before fromNode (in document order) that doesn't have a tab index
NodeImpl *n = fromNode->traversePreviousNode();
while (n && !(n->isTabFocusable() && n->tabIndex() == 0))
n = n->traversePreviousNode();
if (n)
return n;
// No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index
int highestTabIndex = 0;
for (n = this; n != 0; n = n->traverseNextNode()) {
if (n->isTabFocusable() && (n->tabIndex() > highestTabIndex))
highestTabIndex = n->tabIndex();
}
if (highestTabIndex == 0)
return 0;
for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
if (n->isTabFocusable() && (n->tabIndex() == highestTabIndex))
return n;
}
assert(false); // should never get here
return 0;
}
else {
// Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's
// tab index. For nodes with the same tab index as fromNode, we are only interested in those before
// fromNode.
// If we don't find a suitable tab index, then there will be no previous focus node.
short highestSuitableTabIndex = 0;
NodeImpl *n;
bool reachedFromNode = false;
for (n = this; n != 0; n = n->traverseNextNode()) {
if (n->isTabFocusable() &&
((!reachedFromNode && (n->tabIndex() <= fromTabIndex)) ||
(reachedFromNode && (n->tabIndex() < fromTabIndex))) &&
(n->tabIndex() > highestSuitableTabIndex) &&
(n != fromNode)) {
// We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as
// there may be another node which has a higher tab index but is still suitable for use.
highestSuitableTabIndex = n->tabIndex();
}
if (n == fromNode)
reachedFromNode = true;
}
if (highestSuitableTabIndex == 0) {
// No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0
// first, this means that there is no previous node.
return 0;
}
// Search backwards from fromNode
for (n = fromNode->traversePreviousNode(); n != 0; n = n->traversePreviousNode()) {
if (n->isTabFocusable() && (n->tabIndex() == highestSuitableTabIndex))
return n;
}
// The previous node isn't before fromNode, start from the end of the document
for (n = lastNode; n != fromNode; n = n->traversePreviousNode()) {
if (n->isTabFocusable() && (n->tabIndex() == highestSuitableTabIndex))
return n;
}
assert(false); // should never get here
return 0;
}
}
}
ElementImpl* DocumentImpl::findAccessKeyElement(QChar c)
{
c = c.toUpper();
for( NodeImpl* n = this;
n != NULL;
n = n->traverseNextNode()) {
if( n->isElementNode()) {
ElementImpl* en = static_cast< ElementImpl* >( n );
DOMString s = en->getAttribute( ATTR_ACCESSKEY );
if( s.length() == 1
&& s[ 0 ].toUpper() == c )
return en;
}
}
return NULL;
}
int DocumentImpl::nodeAbsIndex(NodeImpl *node)
{
assert(node->document() == this);
int absIndex = 0;
for (NodeImpl *n = node; n && n != this; n = n->traversePreviousNode())
absIndex++;
return absIndex;
}
NodeImpl *DocumentImpl::nodeWithAbsIndex(int absIndex)
{
NodeImpl *n = this;
for (int i = 0; n && (i < absIndex); i++) {
n = n->traverseNextNode();
}
return n;
}
void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content)
{
assert(!equiv.isNull() && !content.isNull());
KHTMLView *v = document()->view();
if(strcasecmp(equiv, "refresh") == 0 && v && v->part()->metaRefreshEnabled())
{
// get delay and url
QString str = content.string().trimmed();
int pos = str.indexOf(QRegExp("[;,]"));
if ( pos == -1 )
pos = str.indexOf(QRegExp("[ \t]"));
bool ok = false;
int delay = qMax( 0, content.implementation()->toInt(&ok) );
if ( !ok && str.length() && str[0] == '.' )
ok = true;
if (pos == -1) // There can be no url (David)
{
if(ok)
v->part()->scheduleRedirection(delay, v->part()->url().url() );
} else {
pos++;
while(pos < (int)str.length() && str[pos].isSpace()) pos++;
str = str.mid(pos);
if(str.indexOf("url", 0, Qt::CaseInsensitive ) == 0) str = str.mid(3);
str = str.trimmed();
if ( str.length() && str[0] == '=' ) str = str.mid( 1 ).trimmed();
while(str.length() &&
(str[str.length()-1] == ';' || str[str.length()-1] == ','))
str.resize(str.length()-1);
str = parseURL( DOMString(str) ).string();
QString newURL = document()->completeURL( str );
if ( ok )
v->part()->scheduleRedirection(delay, document()->completeURL( str ), delay < 2 || newURL == URL().url());
}
}
else if(strcasecmp(equiv, "expires") == 0)
{
bool relative = false;
QString str = content.string().trimmed();
time_t expire_date = KDateTime::fromString(str, KDateTime::RFCDate).toTime_t();
if (!expire_date)
{
expire_date = str.toULong();
relative = true;
}
if (!expire_date)
expire_date = 1; // expire now
if (m_docLoader)
m_docLoader->setExpireDate(expire_date, relative);
}
else if(v && (strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0))
{
QString str = content.string().toLower().trimmed();
KUrl url = v->part()->url();
if ((str == "no-cache") && url.protocol().startsWith(QLatin1String("http")))
{
KIO::http_update_cache(url, true, 0);
}
}
else if( (strcasecmp(equiv, "set-cookie") == 0))
{
// ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
HTMLDocumentImpl *d = static_cast<HTMLDocumentImpl *>(this);
d->setCookie(content);
}
else if (strcasecmp(equiv, "default-style") == 0) {
// HTML 4.0 14.3.2
// http://www.hixie.ch/tests/evil/css/import/main/preferred.html
m_preferredStylesheetSet = content;
updateStyleSelector();
}
else if (strcasecmp(equiv, "content-language") == 0) {
m_contentLanguage = content.string();
}
}
bool DocumentImpl::prepareMouseEvent( bool readonly, int _x, int _y, MouseEvent *ev )
{
if ( m_render ) {
assert(m_render->isCanvas());
RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress);
bool isInside = m_render->layer()->nodeAtPoint(renderInfo, _x, _y);
ev->innerNode = renderInfo.innerNode();
ev->innerNonSharedNode = renderInfo.innerNonSharedNode();
if (renderInfo.URLElement()) {
assert(renderInfo.URLElement()->isElementNode());
//qDebug("urlnode: %s (%d)", getTagName(renderInfo.URLElement()->id()).string().toLatin1().constData(), renderInfo.URLElement()->id());
ElementImpl* e = static_cast<ElementImpl*>(renderInfo.URLElement());
DOMString href = khtml::parseURL(e->getAttribute(ATTR_HREF));
DOMString target = e->getAttribute(ATTR_TARGET);
if (!target.isNull() && !href.isNull()) {
ev->target = target;
ev->url = href;
}
else
ev->url = href;
}
if (!readonly)
updateRendering();
return isInside;
}
return false;
}
// DOM Section 1.1.1
bool DocumentImpl::childTypeAllowed( unsigned short type )
{
switch (type) {
case Node::ATTRIBUTE_NODE:
case Node::CDATA_SECTION_NODE:
case Node::DOCUMENT_FRAGMENT_NODE:
case Node::DOCUMENT_NODE:
case Node::ENTITY_NODE:
case Node::ENTITY_REFERENCE_NODE:
case Node::NOTATION_NODE:
case Node::TEXT_NODE:
// case Node::XPATH_NAMESPACE_NODE:
return false;
case Node::COMMENT_NODE:
case Node::PROCESSING_INSTRUCTION_NODE:
return true;
case Node::DOCUMENT_TYPE_NODE:
case Node::ELEMENT_NODE:
// Documents may contain no more than one of each of these.
// (One Element and one DocumentType.)
for (NodeImpl* c = firstChild(); c; c = c->nextSibling())
if (c->nodeType() == type)
return false;
return true;
}
return false;
}
WTF::PassRefPtr<NodeImpl> DocumentImpl::cloneNode ( bool deep )
{
#if 0
NodeImpl *dtn = m_doctype->cloneNode(deep);
DocumentTypeImpl *dt = static_cast<DocumentTypeImpl*>(dtn);
#endif
int exceptioncode;
WTF::RefPtr<NodeImpl> clone = DOMImplementationImpl::createDocument("",
"",
0, 0,
exceptioncode);
assert( exceptioncode == 0 );
// ### attributes, styles, ...
if (deep)
cloneChildNodes(clone.get());
return clone;
}
// This method is called whenever a top-level stylesheet has finished loading.
void DocumentImpl::styleSheetLoaded()
{
// Make sure we knew this sheet was pending, and that our count isn't out of sync.
assert(m_pendingStylesheets > 0);
m_pendingStylesheets--;
updateStyleSelector();
if (!m_pendingStylesheets && m_tokenizer)
m_tokenizer->executeScriptsWaitingForStylesheets();
}
void DocumentImpl::addPendingSheet()
{
m_pendingStylesheets++;
}
DOMString DocumentImpl::selectedStylesheetSet() const
{
if (!view()) return DOMString();
return view()->part()->d->m_sheetUsed;
}
void DocumentImpl::setSelectedStylesheetSet(const DOMString& s)
{
// this code is evil
if (view() && view()->part()->d->m_sheetUsed != s.string()) {
view()->part()->d->m_sheetUsed = s.string();
updateStyleSelector();
}
}
void DocumentImpl::addStyleSheet(StyleSheetImpl *sheet, int *exceptioncode)
{
int excode = 0;
if (!m_addedStyleSheets) {
m_addedStyleSheets = new StyleSheetListImpl;
m_addedStyleSheets->ref();
}
m_addedStyleSheets->add(sheet);
if (sheet->isCSSStyleSheet()) updateStyleSelector();
if (exceptioncode) *exceptioncode = excode;
}
void DocumentImpl::removeStyleSheet(StyleSheetImpl *sheet, int *exceptioncode)
{
int excode = 0;
bool removed = false;
bool is_css = sheet->isCSSStyleSheet();
if (m_addedStyleSheets) {
bool in_main_list = !sheet->hasOneRef();
removed = m_addedStyleSheets->styleSheets.removeAll(sheet);
sheet->deref();
if (m_addedStyleSheets->styleSheets.count() == 0) {
bool reset = m_addedStyleSheets->hasOneRef();
m_addedStyleSheets->deref();
if (reset) m_addedStyleSheets = 0;
}
// remove from main list, too
if (in_main_list) m_styleSheets->remove(sheet);
}
if (removed) {
if (is_css) updateStyleSelector();
} else
excode = DOMException::NOT_FOUND_ERR;
if (exceptioncode) *exceptioncode = excode;
}
void DocumentImpl::updateStyleSelector(bool shallow)
{
// kDebug() << "PENDING " << m_pendingStylesheets;
// Don't bother updating, since we haven't loaded all our style info yet.
if (m_pendingStylesheets > 0) {
// ... however, if the list of stylesheets changed, mark it as dirty
// so DOM ops can get an up-to-date version.
if (!shallow)
m_styleSheetListDirty = true;
return;
}
if (!shallow)
rebuildStyleSheetList();
rebuildStyleSelector();
recalcStyle(Force);
#if 0
m_styleSelectorDirty = true;
#endif
if ( renderer() )
renderer()->setNeedsLayoutAndMinMaxRecalc();
}
bool DocumentImpl::readyForLayout() const
{
return renderer() && haveStylesheetsLoaded() && (!isHTMLDocument() || (body() && body()->renderer()));
}
void DocumentImpl::rebuildStyleSheetList(bool force)
{
if ( !m_render || !attached() ) {
// Unless we're forced due to CSS DOM ops, we don't have to compute info
// when there is nothing to display
if (!force) {
m_styleSheetListDirty = true;
return;
}
}
// Mark us as clean, as we can call add on the list below, forcing us to re-enter
m_styleSheetListDirty = false;
QList<StyleSheetImpl*> oldStyleSheets = m_styleSheets->styleSheets;
m_styleSheets->styleSheets.clear();
QString sheetUsed = view() ? view()->part()->d->m_sheetUsed.replace("&&", "&") : QString();
bool autoselect = sheetUsed.isEmpty();
if (autoselect && !m_preferredStylesheetSet.isEmpty())
sheetUsed = m_preferredStylesheetSet.string();
NodeImpl *n;
for (int i=0 ; i<2 ; i++) {
m_availableSheets.clear();
m_availableSheets << i18n("Basic Page Style");
bool canResetSheet = false;
QString title;
for (n = this; n; n = n->traverseNextNode()) {
StyleSheetImpl *sheet = 0;
if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
{
// Processing instruction (XML documents only)
ProcessingInstructionImpl* pi = static_cast<ProcessingInstructionImpl*>(n);
sheet = pi->sheet();
if (!sheet && !pi->localHref().isEmpty())
{
// Processing instruction with reference to an element in this document - e.g.
// <?xml-stylesheet href="#mystyle">, with the element
// <foo id="mystyle">heading { color: red; }</foo> at some location in
// the document
ElementImpl* elem = getElementById(pi->localHref());
if (elem) {
DOMString sheetText("");
NodeImpl *c;
for (c = elem->firstChild(); c; c = c->nextSibling()) {
if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE)
sheetText += c->nodeValue();
}
CSSStyleSheetImpl *cssSheet = new CSSStyleSheetImpl(this);
cssSheet->parseString(sheetText);
pi->setStyleSheet(cssSheet);
sheet = cssSheet;
}
}
if (sheet) {
title = sheet->title().string();
if ((autoselect || title != sheetUsed) && sheet->disabled()) {
sheet = 0;
} else if (!title.isEmpty() && !pi->isAlternate() && sheetUsed.isEmpty()) {
sheetUsed = title;
sheet->setDisabled(false);
}
}
}
else if (n->isHTMLElement() && ( n->id() == ID_LINK || n->id() == ID_STYLE) ) {
if ( n->id() == ID_LINK ) {
HTMLLinkElementImpl* l = static_cast<HTMLLinkElementImpl*>(n);
if (l->isCSSStyleSheet()) {
sheet = l->sheet();
if (sheet || l->isLoading() || l->isAlternate() )
title = l->getAttribute(ATTR_TITLE).string();
if ((autoselect || title != sheetUsed) && l->isDisabled()) {
sheet = 0;
} else if (!title.isEmpty() && !l->isAlternate() && sheetUsed.isEmpty()) {
sheetUsed = title;
l->setDisabled(false);
}
}
}
else {
// <STYLE> element
HTMLStyleElementImpl* s = static_cast<HTMLStyleElementImpl*>(n);
if (!s->isLoading()) {
sheet = s->sheet();
if (sheet) title = s->getAttribute(ATTR_TITLE).string();
}
if (!title.isEmpty() && sheetUsed.isEmpty())
sheetUsed = title;
}
}
else if (n->isHTMLElement() && n->id() == ID_BODY) {
// <BODY> element (doesn't contain styles as such but vlink="..." and friends
// are treated as style declarations)
sheet = static_cast<HTMLBodyElementImpl*>(n)->sheet();
}
if ( !title.isEmpty() ) {
if ( title != sheetUsed )
sheet = 0; // don't use it
title = title.replace('&', "&&");
if ( !m_availableSheets.contains( title ) )
m_availableSheets.append( title );
title.clear();
}
if (sheet) {
sheet->ref();
m_styleSheets->styleSheets.append(sheet);
}
// For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
// can stop searching here.
if (isHTMLDocument() && n->id() == ID_BODY) {
canResetSheet = !canResetSheet;
break;
}
}
// we're done if we don't select an alternative sheet
// or we found the sheet we selected
if (sheetUsed.isEmpty() ||
(!canResetSheet && tokenizer()) ||
m_availableSheets.contains(sheetUsed)) {
break;
}
// the alternative sheet we used doesn't exist anymore
// so try from scratch again
if (view())
view()->part()->d->m_sheetUsed.clear();
if (!m_preferredStylesheetSet.isEmpty() && !(sheetUsed == m_preferredStylesheetSet))
sheetUsed = m_preferredStylesheetSet.string();
else
sheetUsed.clear();
autoselect = true;
}
// Include programmatically added style sheets
if (m_addedStyleSheets) {
foreach (StyleSheetImpl* sh, m_addedStyleSheets->styleSheets) {
if (sh->isCSSStyleSheet() && !sh->disabled())
m_styleSheets->add(sh);
}
}
// De-reference all the stylesheets in the old list
foreach ( StyleSheetImpl* sh, oldStyleSheets)
sh->deref();
}
void DocumentImpl::rebuildStyleSelector()
{
if ( !m_render || !attached() )
return;
// Create a new style selector
delete m_styleSelector;
QString usersheet = m_usersheet;
if ( m_view && m_view->mediaType() == "print" )
usersheet += m_printSheet;
m_styleSelector = new CSSStyleSelector( this, usersheet, m_styleSheets, m_url,
!inCompatMode() );
m_styleSelectorDirty = false;
}
void DocumentImpl::setBaseURL(const KUrl& _baseURL)
{
m_baseURL = _baseURL;
if (m_elemSheet)
m_elemSheet->setHref( baseURL().url() );
}
void DocumentImpl::setHoverNode(NodeImpl *newHoverNode)
{
NodeImpl* oldHoverNode = m_hoverNode;
if (newHoverNode ) newHoverNode->ref();
m_hoverNode = newHoverNode;
if ( oldHoverNode ) oldHoverNode->deref();
}
void DocumentImpl::setActiveNode(NodeImpl* newActiveNode)
{
NodeImpl* oldActiveNode = m_activeNode;
if (newActiveNode ) newActiveNode->ref();
m_activeNode = newActiveNode;
if ( oldActiveNode ) oldActiveNode->deref();
}
void DocumentImpl::quietResetFocus()
{
assert(m_focusNode != this);
if (m_focusNode) {
if (m_focusNode->active())
setActiveNode(0);
m_focusNode->setFocus(false);
m_focusNode->deref();
}
m_focusNode = 0;
//We're blurring. Better clear the Qt focus/give it to the view...
if (view())
view()->setFocus();
}
void DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
{
// don't process focus changes while detaching
if( !m_render ) return;
// See if the new node is really focusable. It might not be
// if focus() was called explicitly.
if (newFocusNode && !newFocusNode->isFocusable())
return;
// Make sure newFocusNode is actually in this document
if (newFocusNode && (newFocusNode->document() != this))
return;
if (m_focusNode != newFocusNode) {
NodeImpl *oldFocusNode = m_focusNode;
// We are blurring, so m_focusNode ATM is 0; this is observable to the
// event handlers.
m_focusNode = 0;
// Remove focus from the existing focus node (if any)
if (oldFocusNode) {
if (oldFocusNode->active())
oldFocusNode->setActive(false);
oldFocusNode->setFocus(false);
if (oldFocusNode->renderer() && oldFocusNode->renderer()->isWidget()) {
// Editable widgets may need to dispatch CHANGE_EVENT
RenderWidget* rw = static_cast<RenderWidget*>(oldFocusNode->renderer());
if (rw->isRedirectedWidget())
rw->handleFocusOut();
}
oldFocusNode->dispatchHTMLEvent(EventImpl::BLUR_EVENT,false,false);
oldFocusNode->dispatchUIEvent(EventImpl::DOMFOCUSOUT_EVENT);
if ((oldFocusNode == this) && oldFocusNode->hasOneRef()) {
oldFocusNode->deref(); // may delete this, if there are not kids keeping it alive...
// so we better not add any.
return;
}
else {
oldFocusNode->deref();
}
}
// It's possible that one of the blur, etc. handlers has already set focus.
// in that case, we don't want to override it.
if (!m_focusNode && newFocusNode) {
// Set focus on the new node
m_focusNode = newFocusNode;
m_focusNode->ref();
m_focusNode->dispatchHTMLEvent(EventImpl::FOCUS_EVENT,false,false);
if (m_focusNode != newFocusNode) return;
m_focusNode->dispatchUIEvent(EventImpl::DOMFOCUSIN_EVENT);
if (m_focusNode != newFocusNode) return;
m_focusNode->setFocus();
if (m_focusNode != newFocusNode) return;
// eww, I suck. set the qt focus correctly
// ### find a better place in the code for this
if (view()) {
if (!m_focusNode->renderer() || !m_focusNode->renderer()->isWidget())
view()->setFocus();
else if (static_cast<RenderWidget*>(m_focusNode->renderer())->widget())
{
if (view()->isVisible())
static_cast<RenderWidget*>(m_focusNode->renderer())->widget()->setFocus();
}
}
} else {
//We're blurring. Better clear the Qt focus/give it to the view...
if (view())
view()->setFocus();
}
updateRendering();
}
}
void DocumentImpl::setCSSTarget(NodeImpl* n)
{
if (n == m_cssTarget)
return;
if (m_cssTarget) {
m_cssTarget->setChanged();
m_cssTarget->deref();
}
m_cssTarget = n;
if (n) {
n->setChanged();
n->ref();
}
}
void DocumentImpl::attachNodeIterator(NodeIteratorImpl *ni)
{
m_nodeIterators.append(ni);
}
void DocumentImpl::detachNodeIterator(NodeIteratorImpl *ni)
{
int i = m_nodeIterators.indexOf(ni);
if (i != -1)
m_nodeIterators.removeAt(i);
}
void DocumentImpl::notifyBeforeNodeRemoval(NodeImpl *n)
{
QListIterator<NodeIteratorImpl*> it(m_nodeIterators);
while (it.hasNext())
it.next()->notifyBeforeNodeRemoval(n);
}
bool DocumentImpl::isURLAllowed(const QString& url) const
{
KHTMLPart *thisPart = part();
KUrl newURL(completeURL(url));
newURL.setRef(QString());
if (KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( newURL.url() ))
return false;
// Prohibit non-file URLs if we are asked to.
if (!thisPart || ( thisPart->onlyLocalReferences() && newURL.protocol() != "file" && newURL.protocol() != "data" ))
return false;
// do we allow this suburl ?
if (newURL.protocol() != "javascript" && !KAuthorized::authorizeUrlAction("redirect", thisPart->url(), newURL))
return false;
// We allow one level of self-reference because some sites depend on that.
// But we don't allow more than one.
bool foundSelfReference = false;
for (KHTMLPart *part = thisPart; part; part = part->parentPart()) {
KUrl partURL = part->url();
partURL.setRef(QString());
if (partURL == newURL) {
if (foundSelfReference)
return false;
foundSelfReference = true;
}
}
return true;
}
void DocumentImpl::setDesignMode(bool b)
{
if (part())
part()->setEditable(b);
}
bool DocumentImpl::designMode() const
{
return part() ? part()->isEditable() : false;
}
EventImpl *DocumentImpl::createEvent(const DOMString &eventType, int &exceptioncode)
{
if (eventType == "UIEvents" || eventType == "UIEvent")
return new UIEventImpl();
else if (eventType == "MouseEvents" || eventType == "MouseEvent")
return new MouseEventImpl();
else if (eventType == "TextEvent")
return new TextEventImpl();
else if (eventType == "KeyboardEvent")
return new KeyboardEventImpl();
else if (eventType == "MutationEvents" || eventType == "MutationEvent")
return new MutationEventImpl();
else if (eventType == "HTMLEvents" || eventType == "Events" ||
eventType == "HTMLEvent" || eventType == "Event")
return new EventImpl();
else {
exceptioncode = DOMException::NOT_SUPPORTED_ERR;
return 0;
}
}
CSSStyleDeclarationImpl *DocumentImpl::getOverrideStyle(ElementImpl* /*elt*/, DOMStringImpl* /*pseudoElt*/)
{
return 0; // ###
}
void DocumentImpl::abort()
{
if (m_inSyncLoad) {
assert(m_inSyncLoad->isRunning());
m_inSyncLoad->exit();
}
if (m_loadingXMLDoc)
m_loadingXMLDoc->deref(this);
m_loadingXMLDoc = 0;
}
void DocumentImpl::load(const DOMString &uri)
{
if (m_inSyncLoad) {
assert(m_inSyncLoad->isRunning());
m_inSyncLoad->exit();
}
m_hadLoadError = false;
if (m_loadingXMLDoc)
m_loadingXMLDoc->deref(this);
// Use the document loader to retrieve the XML file. We use CachedCSSStyleSheet because
// this is an easy way to retrieve an arbitrary text file... it is not specific to
// stylesheets.
// ### Note: By loading the XML document this way we do not get the proper decoding
// of the data retrieved from the server based on the character set, as happens with
// HTML files. Need to look into a way of using the decoder in CachedCSSStyleSheet.
m_docLoading = true;
m_loadingXMLDoc = m_docLoader->requestStyleSheet(uri.string(),QString(),"text/xml");
if (!m_loadingXMLDoc) {
m_docLoading = false;
return;
}
m_loadingXMLDoc->ref(this);
if (!m_async && m_docLoading) {
assert(!m_inSyncLoad);
m_inSyncLoad = new QEventLoop();
m_inSyncLoad->exec();
// returning from event loop:
assert(!m_inSyncLoad->isRunning());
delete m_inSyncLoad;
m_inSyncLoad = 0;
}
}
void DocumentImpl::loadXML(const DOMString &source)
{
open(false);
write(source);
finishParsing();
close();
dispatchHTMLEvent(EventImpl::LOAD_EVENT,false,false);
}
void DocumentImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheet, const DOM::DOMString &/*charset*/, const DOM::DOMString &mimetype)
{
if (!m_hadLoadError) {
m_url = url.string();
loadXML(khtml::isAcceptableCSSMimetype(mimetype) ? sheet : "");
}
m_docLoading = false;
if (m_inSyncLoad) {
assert(m_inSyncLoad->isRunning());
m_inSyncLoad->exit();
}
assert(m_loadingXMLDoc != 0);
m_loadingXMLDoc->deref(this);
m_loadingXMLDoc = 0;
}
void DocumentImpl::error(int err, const QString &text)
{
m_docLoading = false;
if (m_inSyncLoad) {
assert(m_inSyncLoad->isRunning());
m_inSyncLoad->exit();
}
m_hadLoadError = true;
int exceptioncode = 0;
EventImpl *evt = new EventImpl(EventImpl::ERROR_EVENT,false,false);
if (err != 0)
evt->setMessage(KIO::buildErrorString(err,text));
else
evt->setMessage(text);
evt->ref();
dispatchEvent(evt,exceptioncode,true);
evt->deref();
assert(m_loadingXMLDoc != 0);
m_loadingXMLDoc->deref(this);
m_loadingXMLDoc = 0;
}
void DocumentImpl::defaultEventHandler(EventImpl *evt)
{
if ( evt->id() == EventImpl::KHTML_CONTENTLOADED_EVENT && !evt->propagationStopped() && !evt->defaultPrevented() )
contentLoaded();
}
void DocumentImpl::setHTMLWindowEventListener(EventName id, EventListener *listener)
{
windowEventTarget()->listenerList().setHTMLEventListener(id, listener);
}
void DocumentImpl::setHTMLWindowEventListener(unsigned id, EventListener *listener)
{
windowEventTarget()->listenerList().setHTMLEventListener(EventName::fromId(id), listener);
}
EventListener *DocumentImpl::getHTMLWindowEventListener(EventName id)
{
return windowEventTarget()->listenerList().getHTMLEventListener(id);
}
EventListener *DocumentImpl::getHTMLWindowEventListener(unsigned id)
{
return windowEventTarget()->listenerList().getHTMLEventListener(EventName::fromId(id));
}
void DocumentImpl::addWindowEventListener(EventName id, EventListener *listener, const bool useCapture)
{
windowEventTarget()->listenerList().addEventListener(id, listener, useCapture);
}
void DocumentImpl::removeWindowEventListener(EventName id, EventListener *listener, bool useCapture)
{
windowEventTarget()->listenerList().removeEventListener(id, listener, useCapture);
}
bool DocumentImpl::hasWindowEventListener(EventName id)
{
return windowEventTarget()->listenerList().hasEventListener(id);
}
EventListener *DocumentImpl::createHTMLEventListener(const QString& code, const QString& name, NodeImpl* node)
{
return part() ? part()->createHTMLEventListener(code, name, node) : 0;
}
void DocumentImpl::dispatchImageLoadEventSoon(HTMLImageElementImpl *image)
{
m_imageLoadEventDispatchSoonList.append(image);
if (!m_imageLoadEventTimer) {
m_imageLoadEventTimer = startTimer(0);
}
}
void DocumentImpl::removeImage(HTMLImageElementImpl *image)
{
// Remove instances of this image from both lists.
m_imageLoadEventDispatchSoonList.removeAll(image);
m_imageLoadEventDispatchingList.removeAll(image);
if (m_imageLoadEventDispatchSoonList.isEmpty() && m_imageLoadEventTimer) {
killTimer(m_imageLoadEventTimer);
m_imageLoadEventTimer = 0;
}
}
void DocumentImpl::dispatchImageLoadEventsNow()
{
// need to avoid re-entering this function; if new dispatches are
// scheduled before the parent finishes processing the list, they
// will set a timer and eventually be processed
if (!m_imageLoadEventDispatchingList.isEmpty()) {
return;
}
if (m_imageLoadEventTimer) {
killTimer(m_imageLoadEventTimer);
m_imageLoadEventTimer = 0;
}
m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
m_imageLoadEventDispatchSoonList.clear();
while (!m_imageLoadEventDispatchingList.isEmpty())
m_imageLoadEventDispatchingList.takeFirst()->dispatchLoadEvent();
m_imageLoadEventDispatchingList.clear();
}
void DocumentImpl::timerEvent(QTimerEvent *e)
{
assert(e->timerId() == m_imageLoadEventTimer);
Q_UNUSED(e);
dispatchImageLoadEventsNow();
}
/*void DocumentImpl::setDecoderCodec(const QTextCodec *codec)
{
m_decoderMibEnum = codec->mibEnum();
}*/
HTMLPartContainerElementImpl *DocumentImpl::ownerElement() const
{
KHTMLPart *childPart = part();
if (!childPart)
return 0;
ChildFrame *childFrame = childPart->d->m_frame;
if (!childFrame)
return 0;
return childFrame->m_partContainerElement.data();
}
khtml::SecurityOrigin* DocumentImpl::origin() const
{
if (!m_origin)
m_origin = SecurityOrigin::create(URL());
return m_origin.get();
}
void DocumentImpl::setOrigin(khtml::SecurityOrigin* newOrigin)
{
assert(origin()->isEmpty());
m_origin = newOrigin;
}
DOMString DocumentImpl::domain() const
{
return origin()->domain();
}
void DocumentImpl::setDomain(const DOMString &newDomain)
{
// ### this test really should move to SecurityOrigin..
DOMString oldDomain = origin()->domain();
// Both NS and IE specify that changing the domain is only allowed when
// the new domain is a suffix of the old domain.
int oldLength = oldDomain.length();
int newLength = newDomain.length();
if ( newLength < oldLength ) { // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
DOMString test = oldDomain.copy();
DOMString reference = newDomain.lower();
if ( test[oldLength - newLength - 1] == '.' ) // Check that it's a subdomain, not e.g. "de.org"
{
test.remove( 0, oldLength - newLength ); // now test is "kde.org" from m_domain
if ( test == reference ) // and we check that it's the same thing as newDomain
m_origin->setDomainFromDOM( reference.string() );
}
} else if ( oldLength == newLength ) {
// It's OK and not a no-op to set the domain to the present one:
// we want to set the 'set from DOM' bit in that case
DOMString reference = newDomain.lower();
if ( oldDomain.lower() == reference )
m_origin->setDomainFromDOM( reference.string() );
}
}
DOMString DocumentImpl::toString() const
{
DOMString result;
for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
result += child->toString();
}
return result;
}
void DOM::DocumentImpl::setRestoreState( const QStringList &s)
{
m_state = s;
m_stateRestorePos = 0;
}
KHTMLView* DOM::DocumentImpl::view() const
{
return m_view;
}
KHTMLPart* DOM::DocumentImpl::part() const
{
// ### TODO: make this independent from a KHTMLView one day.
return view() ? view()->part() : 0;
}
DynamicNodeListImpl::Cache* DOM::DocumentImpl::acquireCachedNodeListInfo(
DynamicNodeListImpl::CacheFactory* factory, NodeImpl* base, int type)
{
//### might want to flush the dict when the version number
//changes
DynamicNodeListImpl::CacheKey key(base, type);
//Check to see if we have this sort of item cached.
DynamicNodeListImpl::Cache* cached =
(type == DynamicNodeListImpl::UNCACHEABLE) ? 0 : m_nodeListCache.value(key.hash());
if (cached) {
if (cached->key == key) {
cached->ref(); //Add the nodelist's reference
return cached;
} else {
//Conflict. Drop our reference to the old item.
cached->deref();
}
}
//Nothing to reuse, make a new item.
DynamicNodeListImpl::Cache* newInfo = factory();
newInfo->key = key;
newInfo->clear(this);
newInfo->ref(); //Add the nodelist's reference
if (type != DynamicNodeListImpl::UNCACHEABLE) {
newInfo->ref(); //Add the cache's reference
m_nodeListCache.insert(key.hash(), newInfo);
}
return newInfo;
}
void DOM::DocumentImpl::releaseCachedNodeListInfo(DynamicNodeListImpl::Cache* entry)
{
entry->deref();
}
bool DOM::DocumentImpl::isSVGDocument() const
{
return (documentElement()->id() == WebCore::SVGNames::svgTag.id());
}
const WebCore::SVGDocumentExtensions* DOM::DocumentImpl::svgExtensions()
{
return m_svgExtensions;
}
WebCore::SVGDocumentExtensions* DOM::DocumentImpl::accessSVGExtensions()
{
if (!m_svgExtensions) {
m_svgExtensions = new WebCore::SVGDocumentExtensions(this);
}
return m_svgExtensions;
}
// ----------------------------------------------------------------------------
// Support for Javascript execCommand, and related methods
JSEditor *DocumentImpl::jsEditor()
{
if (!m_jsEditor)
m_jsEditor = new JSEditor(this);
return m_jsEditor;
}
bool DocumentImpl::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
{
kDebug() << "[execute command]" << command << userInterface << value << endl;
return jsEditor()->execCommand(jsEditor()->commandImp(command), userInterface, value);
}
bool DocumentImpl::queryCommandEnabled(const DOMString &command)
{
return jsEditor()->queryCommandEnabled(jsEditor()->commandImp(command));
}
bool DocumentImpl::queryCommandIndeterm(const DOMString &command)
{
return jsEditor()->queryCommandIndeterm(jsEditor()->commandImp(command));
}
bool DocumentImpl::queryCommandState(const DOMString &command)
{
return jsEditor()->queryCommandState(jsEditor()->commandImp(command));
}
bool DocumentImpl::queryCommandSupported(const DOMString &command)
{
kDebug() << "[query command supported]" << command << endl;
return jsEditor()->queryCommandSupported(jsEditor()->commandImp(command));
}
DOMString DocumentImpl::queryCommandValue(const DOMString &command)
{
return jsEditor()->queryCommandValue(jsEditor()->commandImp(command));
}
// ----------------------------------------------------------------------------
// DOM3 XPath, from XPathEvaluator interface
khtml::XPathExpressionImpl* DocumentImpl::createExpression(DOMString &expression,
khtml::XPathNSResolverImpl *resolver,
int &exceptioncode )
{
XPathExpressionImpl* cand = new XPathExpressionImpl( expression, resolver );
if ((exceptioncode = cand->parseExceptionCode())) {
delete cand;
return 0;
}
return cand;
}
khtml::XPathNSResolverImpl* DocumentImpl::createNSResolver( NodeImpl *nodeResolver )
{
return nodeResolver ? new DefaultXPathNSResolverImpl(nodeResolver) : 0;
}
khtml::XPathResultImpl * DocumentImpl::evaluate( DOMString &expression,
NodeImpl *contextNode,
khtml::XPathNSResolverImpl *resolver,
unsigned short type,
khtml::XPathResultImpl * /*result*/,
int &exceptioncode )
{
XPathExpressionImpl *expr = createExpression( expression, resolver, exceptioncode );
if ( exceptioncode )
return 0;
XPathResultImpl *res = expr->evaluate( contextNode, type, 0, exceptioncode );
delete expr; // don't need it anymore.
if ( exceptioncode ) {
delete res;
return 0;
}
return res;
}
// ----------------------------------------------------------------------------
WindowEventTargetImpl::WindowEventTargetImpl(DOM::DocumentImpl* owner):
m_owner(owner)
{}
EventTargetImpl::Type WindowEventTargetImpl::eventTargetType() const
{
return WINDOW;
}
DocumentImpl* WindowEventTargetImpl::eventTargetDocument()
{
return m_owner;
}
KJS::Window* WindowEventTargetImpl::window()
{
if (m_owner->part())
return KJS::Window::retrieveWindow(m_owner->part());
else
return 0;
}
// ----------------------------------------------------------------------------
DocumentFragmentImpl::DocumentFragmentImpl(DocumentImpl *doc) : NodeBaseImpl(doc)
{
}
DocumentFragmentImpl::DocumentFragmentImpl(const DocumentFragmentImpl &other)
: NodeBaseImpl(other)
{
}
DOMString DocumentFragmentImpl::nodeName() const
{
return "#document-fragment";
}
unsigned short DocumentFragmentImpl::nodeType() const
{
return Node::DOCUMENT_FRAGMENT_NODE;
}
// DOM Section 1.1.1
bool DocumentFragmentImpl::childTypeAllowed( unsigned short type )
{
switch (type) {
case Node::ELEMENT_NODE:
case Node::PROCESSING_INSTRUCTION_NODE:
case Node::COMMENT_NODE:
case Node::TEXT_NODE:
case Node::CDATA_SECTION_NODE:
case Node::ENTITY_REFERENCE_NODE:
return true;
break;
default:
return false;
}
}
DOMString DocumentFragmentImpl::toString() const
{
DOMString result;
for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
if (child->nodeType() == Node::COMMENT_NODE || child->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
continue;
result += child->toString();
}
return result;
}
WTF::PassRefPtr<NodeImpl> DocumentFragmentImpl::cloneNode ( bool deep )
{
WTF::RefPtr<DocumentFragmentImpl> clone = new DocumentFragmentImpl( docPtr() );
if (deep)
cloneChildNodes(clone.get());
return clone;
}
// ----------------------------------------------------------------------------
DocumentTypeImpl::DocumentTypeImpl(DOMImplementationImpl *implementation, DocumentImpl *doc,
const DOMString &qualifiedName, const DOMString &publicId,
const DOMString &systemId)
: NodeImpl(doc), m_implementation(implementation),
m_qualifiedName(qualifiedName), m_publicId(publicId), m_systemId(systemId)
{
m_implementation->ref();
m_entities = 0;
m_notations = 0;
// if doc is 0, it is not attached to a document and / or
// therefore does not provide entities or notations. (DOM Level 3)
}
DocumentTypeImpl::~DocumentTypeImpl()
{
m_implementation->deref();
if (m_entities)
m_entities->deref();
if (m_notations)
m_notations->deref();
}
DOMString DocumentTypeImpl::toString() const
{
DOMString result = "<!DOCTYPE ";
result += m_qualifiedName;
if (!m_publicId.isEmpty()) {
result += " PUBLIC \"";
result += m_publicId;
result += "\" \"";
result += m_systemId;
result += "\"";
} else if (!m_systemId.isEmpty()) {
result += " SYSTEM \"";
result += m_systemId;
result += "\"";
}
if (!m_subset.isEmpty()) {
result += " [";
result += m_subset;
result += "]";
}
result += ">";
return result;
}
DOMString DocumentTypeImpl::nodeName() const
{
return name();
}
unsigned short DocumentTypeImpl::nodeType() const
{
return Node::DOCUMENT_TYPE_NODE;
}
// DOM Section 1.1.1
bool DocumentTypeImpl::childTypeAllowed( unsigned short /*type*/ )
{
return false;
}
WTF::PassRefPtr<NodeImpl> DocumentTypeImpl::cloneNode ( bool /*deep*/ )
{
DocumentTypeImpl *clone = new DocumentTypeImpl(implementation(),
0,
name(), publicId(),
systemId());
// ### copy entities etc.
return clone;
}
NamedNodeMapImpl * DocumentTypeImpl::entities() const
{
if ( !m_entities ) {
m_entities = new GenericRONamedNodeMapImpl( docPtr() );
m_entities->ref();
}
return m_entities;
}
NamedNodeMapImpl * DocumentTypeImpl::notations() const
{
if ( !m_notations ) {
m_notations = new GenericRONamedNodeMapImpl( docPtr() );
m_notations->ref();
}
return m_notations;
}
void XMLDocumentImpl::close()
{
bool doload = !parsing() && m_tokenizer;
DocumentImpl::close();
if (doload) {
document()->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false);
}
}
#include "dom_docimpl.moc"
// kate: indent-width 4; replace-tabs on; tab-width 8; space-indent on;
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 1, 10:05 AM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10076355
Default Alt Text
(246 KB)
Attached To
Mode
rKL kdelibs
Attached
Detach File
Event Timeline
Log In to Comment