Page MenuHomePhorge

No OneTemporary

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

Mime Type
text/x-diff
Expires
Fri, Nov 1, 10:05 AM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10076355
Default Alt Text
(246 KB)

Event Timeline