/** * This file is part of the DOM implementation for KDE. * * (C) 1999-2003 Lars Knoll (knoll@kde.org) * Copyright (C) 2004, 2005, 2006 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 "config.h" #include "CSSMutableStyleDeclaration.h" #include "CSSImageValue.h" #include "CSSParser.h" #include "CSSProperty.h" #include "CSSPropertyNames.h" #include "CSSStyleSheet.h" #include "CSSValueList.h" #include "Document.h" #include "ExceptionCode.h" #include "StyledElement.h" using namespace std; namespace WebCore { CSSMutableStyleDeclaration::CSSMutableStyleDeclaration() : m_node(0) { } CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent) : CSSStyleDeclaration(parent) , m_node(0) { } CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent, const DeprecatedValueList& values) : CSSStyleDeclaration(parent) , m_values(values) , m_node(0) { // FIXME: This allows duplicate properties. } CSSMutableStyleDeclaration::CSSMutableStyleDeclaration(CSSRule* parent, const CSSProperty* const * properties, int numProperties) : CSSStyleDeclaration(parent) , m_node(0) { for (int i = 0; i < numProperties; ++i) m_values.append(*properties[i]); // FIXME: This allows duplicate properties. } CSSMutableStyleDeclaration& CSSMutableStyleDeclaration::operator=(const CSSMutableStyleDeclaration& other) { // don't attach it to the same node, just leave the current m_node value m_values = other.m_values; return *this; } String CSSMutableStyleDeclaration::getPropertyValue(int propertyID) const { RefPtr value = getPropertyCSSValue(propertyID); if (value) return value->cssText(); // Shorthand and 4-values properties switch (propertyID) { case CSS_PROP_BACKGROUND_POSITION: { // FIXME: 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] = { 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); } } return String(); } String CSSMutableStyleDeclaration::get4Values( const int* properties ) const { String res; for (int i = 0; i < 4; ++i) { if (!isPropertyImplicit(properties[i])) { RefPtr value = getPropertyCSSValue(properties[i]); // apparently all 4 properties must be specified. if (!value) return String(); if (!res.isNull()) res += " "; res += value->cssText(); } } return res; } String CSSMutableStyleDeclaration::getLayeredShorthandValue(const int* properties, unsigned number) const { String res; unsigned i; unsigned j; // Begin by collecting the properties into an array. Vector< RefPtr > values(number); unsigned numLayers = 0; for (i = 0; i < number; ++i) { values[i] = getPropertyCSSValue(properties[i]); if (values[i]) { if (values[i]->isValueList()) { CSSValueList* valueList = static_cast(values[i].get()); numLayers = max(valueList->length(), numLayers); } else numLayers = max(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++) { String layerRes; for (j = 0; j < number; j++) { RefPtr value; if (values[j]) { if (values[j]->isValueList()) value = static_cast(values[j].get())->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; } String CSSMutableStyleDeclaration::getShorthandValue(const int* properties, int number) const { String res; for (int i = 0; i < number; ++i) { if (!isPropertyImplicit(properties[i])) { RefPtr value = getPropertyCSSValue(properties[i]); // FIXME: provide default value if !value if (value) { if (!res.isNull()) res += " "; res += value->cssText(); } } } return res; } PassRefPtr CSSMutableStyleDeclaration::getPropertyCSSValue(int propertyID) const { DeprecatedValueListConstIterator end; for (DeprecatedValueListConstIterator it = m_values.fromLast(); it != end; --it) { if (propertyID == (*it).m_id) return (*it).value(); } return 0; } 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(HashMap& shorthandMap) { #define SET_SHORTHAND_MAP_ENTRY(map, propID, array) \ map.set(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.set(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__WEBKIT_BORDER_HORIZONTAL_SPACING, CSS_PROP__WEBKIT_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); static const int marginCollapseProperties[] = { CSS_PROP__WEBKIT_MARGIN_TOP_COLLAPSE, CSS_PROP__WEBKIT_MARGIN_BOTTOM_COLLAPSE }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__WEBKIT_MARGIN_COLLAPSE, marginCollapseProperties); static const int marqueeProperties[] = { CSS_PROP__WEBKIT_MARQUEE_DIRECTION, CSS_PROP__WEBKIT_MARQUEE_INCREMENT, CSS_PROP__WEBKIT_MARQUEE_REPETITION, CSS_PROP__WEBKIT_MARQUEE_STYLE, CSS_PROP__WEBKIT_MARQUEE_SPEED }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__WEBKIT_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); static const int textStrokeProperties[] = { CSS_PROP__WEBKIT_TEXT_STROKE_COLOR, CSS_PROP__WEBKIT_TEXT_STROKE_WIDTH }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__WEBKIT_TEXT_STROKE, textStrokeProperties); 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__WEBKIT_BACKGROUND_SIZE }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND, backgroundProperties); static const int columnsProperties[] = { CSS_PROP__WEBKIT_COLUMN_WIDTH, CSS_PROP__WEBKIT_COLUMN_COUNT }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__WEBKIT_COLUMNS, columnsProperties); static const int columnRuleProperties[] = { CSS_PROP__WEBKIT_COLUMN_RULE_COLOR, CSS_PROP__WEBKIT_COLUMN_RULE_STYLE, CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__WEBKIT_COLUMN_RULE, columnRuleProperties); 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__WEBKIT_BORDER_TOP_RIGHT_RADIUS, CSS_PROP__WEBKIT_BORDER_TOP_LEFT_RADIUS, CSS_PROP__WEBKIT_BORDER_BOTTOM_LEFT_RADIUS, CSS_PROP__WEBKIT_BORDER_BOTTOM_RIGHT_RADIUS }; SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__WEBKIT_BORDER_RADIUS, borderRadiusProperties); #undef SET_SHORTHAND_MAP_ENTRY } String CSSMutableStyleDeclaration::removeProperty(int propertyID, bool notifyChanged, bool returnText, ExceptionCode& ec) { ec = 0; static HashMap shorthandMap; if (shorthandMap.isEmpty()) initShorthandMap(shorthandMap); PropertyLonghand longhand = shorthandMap.get(propertyID); if (longhand.length()) { removePropertiesInSet(longhand.properties(), longhand.length(), notifyChanged); // FIXME: Return an equivalent shorthand when possible. return String(); } String value; DeprecatedValueListIterator end; for (DeprecatedValueListIterator it = m_values.fromLast(); it != end; --it) { if (propertyID == (*it).m_id) { if (returnText) value = (*it).value()->cssText(); m_values.remove(it); if (notifyChanged) setChanged(); break; } } return value; } void CSSMutableStyleDeclaration::clear() { m_values.clear(); setChanged(); } void CSSMutableStyleDeclaration::setChanged(StyleChangeType changeType) { if (m_node) { m_node->setChanged(changeType); // FIXME: Ideally, this should be factored better and there // should be a subclass of CSSMutableStyleDeclaration just // for inline style declarations that handles this if (m_node->isStyledElement() && this == static_cast(m_node)->inlineStyleDecl()) static_cast(m_node)->invalidateStyleAttribute(); return; } // FIXME: quick&dirty hack for KDE 3.0... make this MUCH better! (Dirk) StyleBase* root = this; while (StyleBase* parent = root->parent()) root = parent; if (root->isCSSStyleSheet()) static_cast(root)->doc()->updateStyleSelector(); } bool CSSMutableStyleDeclaration::getPropertyPriority(int propertyID) const { DeprecatedValueListConstIterator end; for (DeprecatedValueListConstIterator it = m_values.begin(); it != end; ++it) { if (propertyID == (*it).id()) return (*it).isImportant(); } return false; } int CSSMutableStyleDeclaration::getPropertyShorthand(int propertyID) const { DeprecatedValueListConstIterator end; for (DeprecatedValueListConstIterator it = m_values.begin(); it != end; ++it) { if (propertyID == (*it).id()) return (*it).shorthandID(); } return false; } bool CSSMutableStyleDeclaration::isPropertyImplicit(int propertyID) const { DeprecatedValueListConstIterator end; for (DeprecatedValueListConstIterator it = m_values.begin(); it != end; ++it) { if (propertyID == (*it).id()) return (*it).isImplicit(); } return false; } void CSSMutableStyleDeclaration::setProperty(int propertyID, const String& value, bool important, ExceptionCode& ec) { setProperty(propertyID, value, important, true, ec); } String CSSMutableStyleDeclaration::removeProperty(int propertyID, ExceptionCode& ec) { return removeProperty(propertyID, true, true, ec); } bool CSSMutableStyleDeclaration::setProperty(int propertyID, const String& value, bool important, bool notifyChanged, ExceptionCode& 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(propertyID, notifyChanged, false, ec); return ec == 0; } // When replacing an existing property value, this moves the property to the end of the list. // Firefox preserves the position, and MSIE moves the property to the beginning. CSSParser parser(useStrictParsing()); bool success = parser.parseValue(this, propertyID, value, important); if (!success) { // CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility, // see . } else if (notifyChanged) setChanged(InlineStyleChange); ASSERT(!ec); return success; } bool CSSMutableStyleDeclaration::setProperty(int propertyID, int value, bool important, bool notifyChanged) { removeProperty(propertyID); m_values.append(CSSProperty(propertyID, new CSSPrimitiveValue(value), important)); if (notifyChanged) setChanged(); return true; } void CSSMutableStyleDeclaration::setStringProperty(int propertyId, const String &value, CSSPrimitiveValue::UnitTypes type, bool important) { removeProperty(propertyId); m_values.append(CSSProperty(propertyId, new CSSPrimitiveValue(value, type), important)); setChanged(); } void CSSMutableStyleDeclaration::setImageProperty(int propertyId, const String& url, bool important) { removeProperty(propertyId); m_values.append(CSSProperty(propertyId, new CSSImageValue(url, this), important)); setChanged(); } void CSSMutableStyleDeclaration::parseDeclaration(const String& styleDeclaration) { m_values.clear(); CSSParser parser(useStrictParsing()); parser.parseDeclaration(this, styleDeclaration); setChanged(); } void CSSMutableStyleDeclaration::addParsedProperties(const CSSProperty * const * properties, int numProperties) { for (int i = 0; i < numProperties; ++i) { // Only add properties that have no !important counterpart present if (!getPropertyPriority(properties[i]->id()) || properties[i]->isImportant()) { 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 CSSMutableStyleDeclaration::setLengthProperty(int propertyId, const String& value, bool important, bool /*multiLength*/) { bool parseMode = useStrictParsing(); setStrictParsing(false); setProperty(propertyId, value, important); setStrictParsing(parseMode); } unsigned CSSMutableStyleDeclaration::length() const { return m_values.count(); } String CSSMutableStyleDeclaration::item(unsigned i) const { if (i >= m_values.count()) return String(); return getPropertyName(static_cast(m_values[i].id())); } String CSSMutableStyleDeclaration::cssText() const { String result = ""; const CSSProperty* positionXProp = 0; const CSSProperty* positionYProp = 0; DeprecatedValueListConstIterator end; for (DeprecatedValueListConstIterator it = m_values.begin(); it != end; ++it) { const CSSProperty& prop = *it; if (prop.id() == CSS_PROP_BACKGROUND_POSITION_X) positionXProp = ∝ else if (prop.id() == CSS_PROP_BACKGROUND_POSITION_Y) positionYProp = ∝ else result += prop.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 WebKit 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()) { String 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() + " " + positionYProp->value()->cssText(); result += "background-position: " + positionValue + (positionXProp->isImportant() ? " !important" : "") + "; "; } else { if (positionXProp) result += positionXProp->cssText(); if (positionYProp) result += positionYProp->cssText(); } return result; } void CSSMutableStyleDeclaration::setCssText(const String& text, ExceptionCode& ec) { ec = 0; m_values.clear(); CSSParser parser(useStrictParsing()); parser.parseDeclaration(this, text); // FIXME: Detect syntax errors and set ec. setChanged(); } void CSSMutableStyleDeclaration::merge(CSSMutableStyleDeclaration* other, bool argOverridesOnConflict) { DeprecatedValueListConstIterator end; for (DeprecatedValueListConstIterator it = other->valuesIterator(); it != end; ++it) { const CSSProperty& property = *it; RefPtr value = getPropertyCSSValue(property.id()); if (value) { if (!argOverridesOnConflict) continue; removeProperty(property.id()); } m_values.append(property); } // 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. } // This is the list of properties we want to copy in the copyBlockProperties() function. // It is the list of CSS properties that apply specially to block-level elements. static const int blockProperties[] = { CSS_PROP_ORPHANS, CSS_PROP_OVERFLOW, // This can be also be applied to replaced elements CSS_PROP__WEBKIT_COLUMN_COUNT, CSS_PROP__WEBKIT_COLUMN_GAP, CSS_PROP__WEBKIT_COLUMN_RULE_COLOR, CSS_PROP__WEBKIT_COLUMN_RULE_STYLE, CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, CSS_PROP__WEBKIT_COLUMN_BREAK_BEFORE, CSS_PROP__WEBKIT_COLUMN_BREAK_AFTER, CSS_PROP__WEBKIT_COLUMN_BREAK_INSIDE, CSS_PROP__WEBKIT_COLUMN_WIDTH, CSS_PROP_PAGE_BREAK_AFTER, CSS_PROP_PAGE_BREAK_BEFORE, CSS_PROP_PAGE_BREAK_INSIDE, CSS_PROP_TEXT_ALIGN, CSS_PROP_TEXT_INDENT, CSS_PROP_WIDOWS }; const unsigned numBlockProperties = sizeof(blockProperties) / sizeof(blockProperties[0]); PassRefPtr CSSMutableStyleDeclaration::copyBlockProperties() const { return copyPropertiesInSet(blockProperties, numBlockProperties); } void CSSMutableStyleDeclaration::removeBlockProperties() { removePropertiesInSet(blockProperties, numBlockProperties); } void CSSMutableStyleDeclaration::removePropertiesInSet(const int* set, unsigned length, bool notifyChanged) { bool changed = false; for (unsigned i = 0; i < length; i++) { RefPtr value = getPropertyCSSValue(set[i]); if (value) { m_values.remove(CSSProperty(set[i], value.release(), false)); changed = true; } } if (changed && notifyChanged) setChanged(); } PassRefPtr CSSMutableStyleDeclaration::makeMutable() { return this; } PassRefPtr CSSMutableStyleDeclaration::copy() const { return new CSSMutableStyleDeclaration(0, m_values); } } // namespace WebCore