This source file includes following definitions.
- sizeForImmutableStylePropertySetWithPropertyCount
- create
- immutableCopyIfNeeded
- findPropertyIndex
- traceAfterDispatch
- getPropertyValue
- getPropertyCSSValue
- trace
- finalizeGarbageCollectedObject
- removeShorthandProperty
- removeProperty
- removePrefixedOrUnprefixedProperty
- propertyIsImportant
- getPropertyShorthand
- isPropertyImplicit
- setProperty
- setProperty
- setProperty
- getIndexInShorthandVectorForPrefixingVariant
- appendPrefixingVariantProperty
- setPrefixingVariantProperty
- setProperty
- setProperty
- parseDeclaration
- addParsedProperties
- addParsedProperty
- asText
- mergeAndOverrideOnConflict
- hasFailedOrCanceledSubresources
- blockProperties
- clear
- copyBlockProperties
- removeBlockProperties
- removePropertiesInSet
- findCSSPropertyWithID
- propertyMatches
- removeEquivalentProperties
- removeEquivalentProperties
- mutableCopy
- copyPropertiesInSet
- ensureCSSStyleDeclaration
- findPropertyIndex
- traceAfterDispatch
- averageSizeInBytes
- showStyle
- create
- create
- cssName
- cssText
#include "config.h"
#include "core/css/StylePropertySet.h"
#include "RuntimeEnabledFeatures.h"
#include "StylePropertyShorthand.h"
#include "core/css/parser/BisonCSSParser.h"
#include "core/css/CSSValuePool.h"
#include "core/css/RuntimeCSSEnabled.h"
#include "core/css/StylePropertySerializer.h"
#include "core/css/StyleSheetContents.h"
#include "core/frame/UseCounter.h"
#include "wtf/text/StringBuilder.h"
#ifndef NDEBUG
#include "wtf/text/CString.h"
#include <stdio.h>
#endif
using namespace std;
namespace WebCore {
static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
{
return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
}
PassRefPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode)
{
ASSERT(count <= MaxArraySize);
#if ENABLE(OILPAN)
void* slot = Heap::allocate<StylePropertySet>(sizeForImmutableStylePropertySetWithPropertyCount(count));
#else
void* slot = WTF::fastMalloc(sizeForImmutableStylePropertySetWithPropertyCount(count));
#endif
return adoptRefWillBeRefCountedGarbageCollected(new (slot) ImmutableStylePropertySet(properties, count, cssParserMode));
}
PassRefPtr<ImmutableStylePropertySet> StylePropertySet::immutableCopyIfNeeded() const
{
if (!isMutable())
return toImmutableStylePropertySet(const_cast<StylePropertySet*>(this));
const MutableStylePropertySet* mutableThis = toMutableStylePropertySet(this);
return ImmutableStylePropertySet::create(mutableThis->m_propertyVector.data(), mutableThis->m_propertyVector.size(), cssParserMode());
}
MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode)
: StylePropertySet(cssParserMode)
{
}
MutableStylePropertySet::MutableStylePropertySet(const CSSProperty* properties, unsigned length)
: StylePropertySet(HTMLStandardMode)
{
m_propertyVector.reserveInitialCapacity(length);
for (unsigned i = 0; i < length; ++i)
m_propertyVector.uncheckedAppend(properties[i]);
}
ImmutableStylePropertySet::ImmutableStylePropertySet(const CSSProperty* properties, unsigned length, CSSParserMode cssParserMode)
: StylePropertySet(cssParserMode, length)
{
StylePropertyMetadata* metadataArray = const_cast<StylePropertyMetadata*>(this->metadataArray());
RawPtrWillBeMember<CSSValue>* valueArray = const_cast<RawPtrWillBeMember<CSSValue>*>(this->valueArray());
for (unsigned i = 0; i < m_arraySize; ++i) {
metadataArray[i] = properties[i].metadata();
valueArray[i] = properties[i].value();
valueArray[i]->ref();
}
}
ImmutableStylePropertySet::~ImmutableStylePropertySet()
{
#if !ENABLE(OILPAN)
RawPtrWillBeMember<CSSValue>* valueArray = const_cast<RawPtrWillBeMember<CSSValue>*>(this->valueArray());
for (unsigned i = 0; i < m_arraySize; ++i)
valueArray[i]->deref();
#endif
}
int ImmutableStylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
{
uint16_t id = static_cast<uint16_t>(propertyID);
for (int n = m_arraySize - 1 ; n >= 0; --n) {
if (metadataArray()[n].m_propertyID == id) {
ASSERT(RuntimeCSSEnabled::isCSSPropertyEnabled(propertyID) || isInternalProperty(propertyID));
return n;
}
}
return -1;
}
void ImmutableStylePropertySet::traceAfterDispatch(Visitor* visitor)
{
const RawPtrWillBeMember<CSSValue>* values = valueArray();
for (unsigned i = 0; i < m_arraySize; i++)
visitor->trace(values[i]);
StylePropertySet::traceAfterDispatch(visitor);
}
MutableStylePropertySet::MutableStylePropertySet(const StylePropertySet& other)
: StylePropertySet(other.cssParserMode())
{
if (other.isMutable()) {
m_propertyVector = toMutableStylePropertySet(other).m_propertyVector;
} else {
m_propertyVector.reserveInitialCapacity(other.propertyCount());
for (unsigned i = 0; i < other.propertyCount(); ++i)
m_propertyVector.uncheckedAppend(other.propertyAt(i).toCSSProperty());
}
}
String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const
{
RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(propertyID);
if (value)
return value->cssText();
return StylePropertySerializer(*this).getPropertyValue(propertyID);
}
PassRefPtrWillBeRawPtr<CSSValue> StylePropertySet::getPropertyCSSValue(CSSPropertyID propertyID) const
{
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex == -1)
return nullptr;
return propertyAt(foundPropertyIndex).value();
}
void StylePropertySet::trace(Visitor* visitor)
{
if (m_isMutable)
toMutableStylePropertySet(this)->traceAfterDispatch(visitor);
else
toImmutableStylePropertySet(this)->traceAfterDispatch(visitor);
}
#if ENABLE(OILPAN)
void StylePropertySet::finalizeGarbageCollectedObject()
{
if (m_isMutable)
toMutableStylePropertySet(this)->~MutableStylePropertySet();
else
toImmutableStylePropertySet(this)->~ImmutableStylePropertySet();
}
#endif
bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID)
{
StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
if (!shorthand.length())
return false;
bool ret = removePropertiesInSet(shorthand.properties(), shorthand.length());
CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propertyID);
if (prefixingVariant == propertyID)
return ret;
StylePropertyShorthand shorthandPrefixingVariant = shorthandForProperty(prefixingVariant);
return removePropertiesInSet(shorthandPrefixingVariant.properties(), shorthandPrefixingVariant.length());
}
bool MutableStylePropertySet::removeProperty(CSSPropertyID propertyID, String* returnText)
{
if (removeShorthandProperty(propertyID)) {
if (returnText)
*returnText = "";
return true;
}
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex == -1) {
if (returnText)
*returnText = "";
return false;
}
if (returnText)
*returnText = propertyAt(foundPropertyIndex).value()->cssText();
m_propertyVector.remove(foundPropertyIndex);
removePrefixedOrUnprefixedProperty(propertyID);
return true;
}
void MutableStylePropertySet::removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)
{
int foundPropertyIndex = findPropertyIndex(prefixingVariantForPropertyId(propertyID));
if (foundPropertyIndex == -1)
return;
m_propertyVector.remove(foundPropertyIndex);
}
bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const
{
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex != -1)
return propertyAt(foundPropertyIndex).isImportant();
StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
if (!shorthand.length())
return false;
for (unsigned i = 0; i < shorthand.length(); ++i) {
if (!propertyIsImportant(shorthand.properties()[i]))
return false;
}
return true;
}
CSSPropertyID StylePropertySet::getPropertyShorthand(CSSPropertyID propertyID) const
{
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex == -1)
return CSSPropertyInvalid;
return propertyAt(foundPropertyIndex).shorthandID();
}
bool StylePropertySet::isPropertyImplicit(CSSPropertyID propertyID) const
{
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex == -1)
return false;
return propertyAt(foundPropertyIndex).isImplicit();
}
bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, const String& value, bool important, StyleSheetContents* contextStyleSheet)
{
if (value.isEmpty())
return removeProperty(propertyID);
return BisonCSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet);
}
void MutableStylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important)
{
StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
if (!shorthand.length()) {
setProperty(CSSProperty(propertyID, prpValue, important));
return;
}
removePropertiesInSet(shorthand.properties(), shorthand.length());
RefPtrWillBeRawPtr<CSSValue> value = prpValue;
for (unsigned i = 0; i < shorthand.length(); ++i)
m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important));
}
void MutableStylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot)
{
if (!removeShorthandProperty(property.id())) {
CSSProperty* toReplace = slot ? slot : findCSSPropertyWithID(property.id());
if (toReplace) {
*toReplace = property;
setPrefixingVariantProperty(property);
return;
}
}
appendPrefixingVariantProperty(property);
}
unsigned getIndexInShorthandVectorForPrefixingVariant(const CSSProperty& property, CSSPropertyID prefixingVariant)
{
if (!property.isSetFromShorthand())
return 0;
CSSPropertyID prefixedShorthand = prefixingVariantForPropertyId(property.shorthandID());
Vector<StylePropertyShorthand, 4> shorthands;
getMatchingShorthandsForLonghand(prefixingVariant, &shorthands);
return indexOfShorthandForLonghand(prefixedShorthand, shorthands);
}
void MutableStylePropertySet::appendPrefixingVariantProperty(const CSSProperty& property)
{
m_propertyVector.append(property);
CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
if (prefixingVariant == property.id())
return;
m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit));
}
void MutableStylePropertySet::setPrefixingVariantProperty(const CSSProperty& property)
{
CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
CSSProperty* toReplace = findCSSPropertyWithID(prefixingVariant);
if (toReplace && prefixingVariant != property.id())
*toReplace = CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit);
}
bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
{
setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
return true;
}
bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
{
setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
return true;
}
void MutableStylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet)
{
m_propertyVector.clear();
CSSParserContext context(cssParserMode(), UseCounter::getFrom(contextStyleSheet));
if (contextStyleSheet) {
context = contextStyleSheet->parserContext();
context.setMode(cssParserMode());
}
BisonCSSParser parser(context);
parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet);
}
void MutableStylePropertySet::addParsedProperties(const WillBeHeapVector<CSSProperty, 256>& properties)
{
m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size());
for (unsigned i = 0; i < properties.size(); ++i)
addParsedProperty(properties[i]);
}
void MutableStylePropertySet::addParsedProperty(const CSSProperty& property)
{
if (!propertyIsImportant(property.id()) || property.isImportant())
setProperty(property);
}
String StylePropertySet::asText() const
{
return StylePropertySerializer(*this).asText();
}
void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other)
{
unsigned size = other->propertyCount();
for (unsigned n = 0; n < size; ++n) {
PropertyReference toMerge = other->propertyAt(n);
CSSProperty* old = findCSSPropertyWithID(toMerge.id());
if (old)
setProperty(toMerge.toCSSProperty(), old);
else
appendPrefixingVariantProperty(toMerge.toCSSProperty());
}
}
bool StylePropertySet::hasFailedOrCanceledSubresources() const
{
unsigned size = propertyCount();
for (unsigned i = 0; i < size; ++i) {
if (propertyAt(i).value()->hasFailedOrCanceledSubresources())
return true;
}
return false;
}
static const CSSPropertyID staticBlockProperties[] = {
CSSPropertyOrphans,
CSSPropertyOverflow,
CSSPropertyWebkitAspectRatio,
CSSPropertyWebkitColumnCount,
CSSPropertyWebkitColumnGap,
CSSPropertyWebkitColumnRuleColor,
CSSPropertyWebkitColumnRuleStyle,
CSSPropertyWebkitColumnRuleWidth,
CSSPropertyWebkitColumnBreakBefore,
CSSPropertyWebkitColumnBreakAfter,
CSSPropertyWebkitColumnBreakInside,
CSSPropertyWebkitColumnWidth,
CSSPropertyPageBreakAfter,
CSSPropertyPageBreakBefore,
CSSPropertyPageBreakInside,
CSSPropertyTextAlign,
CSSPropertyTextAlignLast,
CSSPropertyTextIndent,
CSSPropertyTextJustify,
CSSPropertyWidows
};
static const Vector<CSSPropertyID>& blockProperties()
{
DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
if (properties.isEmpty())
RuntimeCSSEnabled::filterEnabledCSSPropertiesIntoVector(staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), properties);
return properties;
}
void MutableStylePropertySet::clear()
{
m_propertyVector.clear();
}
PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
{
return copyPropertiesInSet(blockProperties());
}
void MutableStylePropertySet::removeBlockProperties()
{
removePropertiesInSet(blockProperties().data(), blockProperties().size());
}
bool MutableStylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length)
{
if (m_propertyVector.isEmpty())
return false;
HashSet<CSSPropertyID> toRemove;
for (unsigned i = 0; i < length; ++i)
toRemove.add(set[i]);
WillBeHeapVector<CSSProperty> newProperties;
newProperties.reserveInitialCapacity(m_propertyVector.size());
unsigned size = m_propertyVector.size();
for (unsigned n = 0; n < size; ++n) {
const CSSProperty& property = m_propertyVector.at(n);
if (!property.isImportant()) {
if (toRemove.contains(property.id()))
continue;
}
newProperties.append(property);
}
bool changed = newProperties.size() != m_propertyVector.size();
m_propertyVector = newProperties;
return changed;
}
CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID)
{
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex == -1)
return 0;
return &m_propertyVector.at(foundPropertyIndex);
}
bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
{
int foundPropertyIndex = findPropertyIndex(propertyID);
if (foundPropertyIndex == -1)
return false;
return propertyAt(foundPropertyIndex).value()->equals(*propertyValue);
}
void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style)
{
Vector<CSSPropertyID> propertiesToRemove;
unsigned size = m_propertyVector.size();
for (unsigned i = 0; i < size; ++i) {
PropertyReference property = propertyAt(i);
if (style->propertyMatches(property.id(), property.value()))
propertiesToRemove.append(property.id());
}
for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
removeProperty(propertiesToRemove[i]);
}
void MutableStylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style)
{
Vector<CSSPropertyID> propertiesToRemove;
unsigned size = m_propertyVector.size();
for (unsigned i = 0; i < size; ++i) {
PropertyReference property = propertyAt(i);
if (style->cssPropertyMatches(property.id(), property.value()))
propertiesToRemove.append(property.id());
}
for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
removeProperty(propertiesToRemove[i]);
}
PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
{
return adoptRefWillBeRefCountedGarbageCollected(new MutableStylePropertySet(*this));
}
PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const Vector<CSSPropertyID>& properties) const
{
WillBeHeapVector<CSSProperty, 256> list;
list.reserveInitialCapacity(properties.size());
for (unsigned i = 0; i < properties.size(); ++i) {
RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(properties[i]);
if (value)
list.append(CSSProperty(properties[i], value.release(), false));
}
return MutableStylePropertySet::create(list.data(), list.size());
}
CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration()
{
if (m_cssomWrapper) {
ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule());
ASSERT(!m_cssomWrapper->parentElement());
return m_cssomWrapper.get();
}
m_cssomWrapper = adoptPtr(new PropertySetCSSStyleDeclaration(*this));
return m_cssomWrapper.get();
}
int MutableStylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
{
uint16_t id = static_cast<uint16_t>(propertyID);
for (int n = m_propertyVector.size() - 1 ; n >= 0; --n) {
if (m_propertyVector.at(n).metadata().m_propertyID == id) {
ASSERT(RuntimeCSSEnabled::isCSSPropertyEnabled(propertyID) || isInternalProperty(propertyID));
return n;
}
}
return -1;
}
void MutableStylePropertySet::traceAfterDispatch(Visitor* visitor)
{
visitor->trace(m_propertyVector);
StylePropertySet::traceAfterDispatch(visitor);
}
unsigned StylePropertySet::averageSizeInBytes()
{
return sizeForImmutableStylePropertySetWithPropertyCount(4);
}
struct SameSizeAsStylePropertySet : public RefCountedWillBeRefCountedGarbageCollected<SameSizeAsStylePropertySet> {
unsigned bitfield;
};
COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
#ifndef NDEBUG
void StylePropertySet::showStyle()
{
fprintf(stderr, "%s\n", asText().ascii().data());
}
#endif
PassRefPtrWillBeRawPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
{
return adoptRefWillBeRefCountedGarbageCollected(new MutableStylePropertySet(cssParserMode));
}
PassRefPtrWillBeRawPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
{
return adoptRefWillBeRefCountedGarbageCollected(new MutableStylePropertySet(properties, count));
}
String StylePropertySet::PropertyReference::cssName() const
{
return getPropertyNameString(id());
}
String StylePropertySet::PropertyReference::cssText() const
{
StringBuilder result;
result.append(cssName());
result.appendLiteral(": ");
result.append(propertyValue()->cssText());
if (isImportant())
result.appendLiteral(" !important");
result.append(';');
return result.toString();
}
}