⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 css_valueimpl.cpp

📁 手机浏览器源码程序,功能强大
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/**
 * 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 + -