?? css_valueimpl.cpp
字號:
/**
* This file is part of the DOM implementation for KDE.
*
* (C) 1999-2003 Lars Knoll (knoll@kde.org)
* Copyright (C) 2004 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "dom/css_value.h"
#include "dom/dom_exception.h"
#include "dom/dom_string.h"
#include "css/css_valueimpl.h"
#include "css/css_ruleimpl.h"
#include "css/css_stylesheetimpl.h"
#include "css/cssparser.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "css/cssstyleselector.h"
#include "xml/dom_stringimpl.h"
#include "xml/dom_docimpl.h"
#include "html/html_elementimpl.h"
#include "misc/loader.h"
#include "rendering/font.h"
#include "rendering/render_style.h"
#include <kdebug.h>
#include <qregexp.h>
#include <qpaintdevice.h>
#include <qpaintdevicemetrics.h>
// Hack for debugging purposes
extern DOM::DOMString getPropertyName(unsigned short id);
using khtml::FontDef;
using khtml::CSSStyleSelector;
namespace DOM {
#if 0
// Too risky to quote all legal identifiers right now.
// Post-Tiger we should use this function or something like it.
// Return true if this string qualifies as an identifier (from the point of view of CSS syntax).
static bool isLegalIdentifier(const DOMString &string)
{
int len = string.length();
if (len == 0) {
return false;
}
QChar *p = string.unicode();
int i = 0;
if (p[0] == '-') {
++i;
}
if (i == len) {
return false;
}
ushort code = p[i].unicode();
if (!(code >= 0x80 || code == '_' || isalpha(code))) {
return false;
}
++i;
while (i != len) {
code = p[i].unicode();
if (!(code >= 0x80 || code == '-' || code == '_' || isalnum(code))) {
return false;
}
++i;
}
return true;
}
#endif
// Quotes the string if it needs quoting.
// We use single quotes for now beause markup.cpp uses double quotes.
static DOMString quoteStringIfNeeded(const DOMString &string)
{
// For now, just do this for strings that start with "#" to fix Korean font names that start with "#".
// Post-Tiger, we should isLegalIdentifier instead after working out all the ancillary issues.
if (string[0] != '#') {
return string;
}
// FIXME: Also need to transform control characters into \ sequences.
QString s = string.string();
s.replace('\\', "\\\\");
s.replace('\'', "\\'");
return '\'' + s + '\'';
}
CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent)
: StyleBaseImpl(parent)
{
}
bool CSSStyleDeclarationImpl::isStyleDeclaration()
{
return true;
}
CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl()
: m_node(0)
{
}
CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl(CSSRuleImpl *parent)
: CSSStyleDeclarationImpl(parent), m_node(0)
{
}
CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl(CSSRuleImpl *parent, const QValueList<CSSProperty> &values)
: CSSStyleDeclarationImpl(parent), m_values(values), m_node(0)
{
// FIXME: This allows duplicate properties.
}
CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl(CSSRuleImpl *parent, const CSSProperty * const *properties, int numProperties)
: CSSStyleDeclarationImpl(parent), m_node(0)
{
for (int i = 0; i < numProperties; ++i)
m_values.append(*properties[i]);
// FIXME: This allows duplicate properties.
}
CSSMutableStyleDeclarationImpl& CSSMutableStyleDeclarationImpl::operator=(const CSSMutableStyleDeclarationImpl& o)
{
// don't attach it to the same node, just leave the current m_node value
m_values = o.m_values;
return *this;
}
CSSMutableStyleDeclarationImpl::~CSSMutableStyleDeclarationImpl()
{
// we don't use refcounting for m_node, to avoid cyclic references (see ElementImpl)
}
DOMString CSSMutableStyleDeclarationImpl::getPropertyValue( int propertyID ) const
{
CSSValueImpl* value = getPropertyCSSValue( propertyID );
if (value)
return CSSValue(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 getShortHandValue( properties, 2 );
}
case CSS_PROP_BACKGROUND:
{
const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
CSS_PROP_BACKGROUND_COLOR };
return getShortHandValue( properties, 5 );
}
case CSS_PROP_BORDER:
{
const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
CSS_PROP_BORDER_COLOR };
return getShortHandValue( properties, 3 );
}
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 );
}
}
//kdDebug() << k_funcinfo << "property not found:" << propertyID << endl;
return DOMString();
}
DOMString CSSMutableStyleDeclarationImpl::get4Values( const int* properties ) const
{
DOMString res;
for ( int i = 0 ; i < 4 ; ++i ) {
CSSValueImpl* value = getPropertyCSSValue( properties[i] );
if ( !value ) { // apparently all 4 properties must be specified.
return DOMString();
}
value->ref();
if ( i > 0 )
res += " ";
res += value->cssText();
value->deref();
}
return res;
}
DOMString CSSMutableStyleDeclarationImpl::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
value->ref();
if ( !res.isNull() )
res += " ";
res += value->cssText();
value->deref();
}
}
return res;
}
CSSValueImpl *CSSMutableStyleDeclarationImpl::getPropertyCSSValue( int propertyID ) const
{
QValueListConstIterator<CSSProperty> end;
for (QValueListConstIterator<CSSProperty> it = m_values.fromLast(); it != end; --it)
if (propertyID == (*it).m_id)
return (*it).value();
return 0;
}
DOMString CSSMutableStyleDeclarationImpl::removeProperty(int propertyID, bool notifyChanged, int &exceptionCode)
{
if (m_node && !m_node->getDocument())
return ""; // FIXME: This (not well-understood) situation happens on albertsons.com. We don't really know how they managed to run a script on a node
// with no document pointer, but this sidesteps the crash.
exceptionCode = 0;
DOMString value;
QValueListIterator<CSSProperty> end;
for (QValueListIterator<CSSProperty> it = m_values.fromLast(); it != end; --it)
if (propertyID == (*it).m_id) {
value = (*it).value()->cssText();
m_values.remove(it);
if (notifyChanged)
setChanged();
break;
}
return value;
}
void CSSMutableStyleDeclarationImpl::clear()
{
m_values.clear();
setChanged();
}
void CSSMutableStyleDeclarationImpl::setChanged()
{
if (m_node) {
m_node->setChanged();
// FIXME: Ideally, this should be factored better and there
// should be a subclass of CSSMutableStyleDeclarationImpl just
// for inline style declarations that handles this
if (m_node->isHTMLElement() && this == static_cast<HTMLElementImpl *>(m_node)->inlineStyleDecl())
static_cast<HTMLElementImpl *>(m_node)->invalidateStyleAttribute();
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;
}
}
bool CSSMutableStyleDeclarationImpl::getPropertyPriority(int propertyID) const
{
QValueListConstIterator<CSSProperty> end;
for (QValueListConstIterator<CSSProperty> it = m_values.begin(); it != end; ++it)
if (propertyID == (*it).m_id)
return (*it).m_bImportant;
return false;
}
void CSSMutableStyleDeclarationImpl::setProperty(int propertyID, const DOMString &value, bool important, int &exceptionCode)
{
setProperty(propertyID, value, important, true, exceptionCode);
}
DOMString CSSMutableStyleDeclarationImpl::removeProperty(int propertyID, int &exceptionCode)
{
return removeProperty(propertyID, true, exceptionCode);
}
bool CSSMutableStyleDeclarationImpl::setProperty(int propertyID, const DOMString &value, bool important, bool notifyChanged, int &exceptionCode)
{
if (m_node && !m_node->getDocument())
return false; // FIXME: This (not well-understood) situation happens on albertsons.com. We don't really know how they managed to run a script on a node
// with no document pointer, but this sidesteps the crash.
exceptionCode = 0;
removeProperty(propertyID);
CSSParser parser(strictParsing);
bool success = parser.parseValue(this, propertyID, value, important);
if (!success) {
#if !APPLE_CHANGES
kdDebug( 6080 ) << "CSSMutableStyleDeclarationImpl::setProperty invalid property: [" << getPropertyName(id).string()
<< "] value: [" << value.string() << "]"<< endl;
#endif
exceptionCode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
} else if (notifyChanged)
setChanged();
return success;
}
bool CSSMutableStyleDeclarationImpl::setProperty(int propertyID, int value, bool important, bool notifyChanged)
{
removeProperty(propertyID);
m_values.append(CSSProperty(propertyID, new CSSPrimitiveValueImpl(value), important));
if (notifyChanged)
setChanged();
return true;
}
void CSSMutableStyleDeclarationImpl::setStringProperty(int propertyId, const DOMString &value, CSSPrimitiveValue::UnitTypes type, bool important)
{
removeProperty(propertyId);
m_values.append(CSSProperty(propertyId, new CSSPrimitiveValueImpl(value, type), important));
setChanged();
}
void CSSMutableStyleDeclarationImpl::setImageProperty(int propertyId, const DOMString &URL, bool important)
{
removeProperty(propertyId);
m_values.append(CSSProperty(propertyId, new CSSImageValueImpl(URL, this), important));
setChanged();
}
void CSSMutableStyleDeclarationImpl::parseDeclaration(const DOMString &styleDeclaration)
{
m_values.clear();
CSSParser parser(strictParsing);
parser.parseDeclaration(this, styleDeclaration);
setChanged();
}
void CSSMutableStyleDeclarationImpl::addParsedProperties(const CSSProperty * const *properties, int numProperties)
{
for (int i = 0; i < numProperties; ++i) {
removeProperty(properties[i]->id(), false);
m_values.append(*properties[i]);
}
// FIXME: This probably should have a call to setChanged() if something changed. We may also wish to add
// a notifyChanged argument to this function to follow the model of other functions in this class.
}
void CSSMutableStyleDeclarationImpl::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;
}
unsigned long CSSMutableStyleDeclarationImpl::length() const
{
return m_values.count();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -