blob: d917fcc47fe7cc114466dc4a11e44700fbaf64c8 [file] [log] [blame]
/*
* (C) 1999-2003 Lars Knoll (knoll@kde.org)
* Copyright (C) 2004, 2005, 2006, 2008, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013 Intel Corporation. All rights reserved.
*
* 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.
*/
#pragma once
#include "CSSParserContext.h"
#include "CSSParserTokenRange.h"
#include "CSSProperty.h"
#include "CSSValueKeywords.h"
#include <memory>
#include <wtf/Function.h>
#include <wtf/TypeCasts.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
class CSSDeferredParser;
class CSSStyleDeclaration;
class CachedResource;
class Color;
class ImmutableStyleProperties;
class MutableStyleProperties;
class PropertySetCSSStyleDeclaration;
class StyledElement;
class StylePropertyShorthand;
class StyleSheetContents;
enum StylePropertiesType { ImmutablePropertiesType, MutablePropertiesType, DeferredPropertiesType };
class StylePropertiesBase : public RefCounted<StylePropertiesBase> {
public:
// Override RefCounted's deref() to ensure operator delete is called on
// the appropriate subclass type.
void deref() const;
StylePropertiesType type() const { return static_cast<StylePropertiesType>(m_type); }
CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
protected:
StylePropertiesBase(CSSParserMode cssParserMode, StylePropertiesType type)
: m_cssParserMode(cssParserMode)
, m_type(type)
, m_arraySize(0)
{ }
StylePropertiesBase(CSSParserMode cssParserMode, unsigned immutableArraySize)
: m_cssParserMode(cssParserMode)
, m_type(ImmutablePropertiesType)
, m_arraySize(immutableArraySize)
{ }
unsigned m_cssParserMode : 3;
mutable unsigned m_type : 2;
unsigned m_arraySize : 27;
};
class StyleProperties : public StylePropertiesBase {
friend class PropertyReference;
public:
class PropertyReference {
public:
PropertyReference(const StylePropertyMetadata& metadata, const CSSValue* value)
: m_metadata(metadata)
, m_value(value)
{ }
CSSPropertyID id() const { return static_cast<CSSPropertyID>(m_metadata.m_propertyID); }
CSSPropertyID shorthandID() const { return m_metadata.shorthandID(); }
bool isImportant() const { return m_metadata.m_important; }
bool isInherited() const { return m_metadata.m_inherited; }
bool isImplicit() const { return m_metadata.m_implicit; }
String cssName() const;
String cssText() const;
const CSSValue* value() const { return m_value; }
// FIXME: We should try to remove this mutable overload.
CSSValue* value() { return const_cast<CSSValue*>(m_value); }
// FIXME: Remove this.
CSSProperty toCSSProperty() const { return CSSProperty(id(), const_cast<CSSValue*>(m_value), isImportant(), m_metadata.m_isSetFromShorthand, m_metadata.m_indexInShorthandsVector, isImplicit()); }
private:
const StylePropertyMetadata& m_metadata;
const CSSValue* m_value;
};
unsigned propertyCount() const;
bool isEmpty() const { return !propertyCount(); }
PropertyReference propertyAt(unsigned) const;
WEBCORE_EXPORT RefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
WEBCORE_EXPORT String getPropertyValue(CSSPropertyID) const;
WEBCORE_EXPORT Optional<Color> propertyAsColor(CSSPropertyID) const;
WEBCORE_EXPORT CSSValueID propertyAsValueID(CSSPropertyID) const;
bool propertyIsImportant(CSSPropertyID) const;
String getPropertyShorthand(CSSPropertyID) const;
bool isPropertyImplicit(CSSPropertyID) const;
RefPtr<CSSValue> getCustomPropertyCSSValue(const String& propertyName) const;
String getCustomPropertyValue(const String& propertyName) const;
bool customPropertyIsImportant(const String& propertyName) const;
Ref<MutableStyleProperties> copyBlockProperties() const;
WEBCORE_EXPORT Ref<MutableStyleProperties> mutableCopy() const;
Ref<ImmutableStyleProperties> immutableCopyIfNeeded() const;
Ref<MutableStyleProperties> copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const;
String asText() const;
bool hasCSSOMWrapper() const;
bool isMutable() const { return type() == MutablePropertiesType; }
bool traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const;
static unsigned averageSizeInBytes();
#ifndef NDEBUG
void showStyle();
#endif
bool propertyMatches(CSSPropertyID, const CSSValue*) const;
protected:
StyleProperties(CSSParserMode cssParserMode, StylePropertiesType type)
: StylePropertiesBase(cssParserMode, type)
{ }
StyleProperties(CSSParserMode cssParserMode, unsigned immutableArraySize)
: StylePropertiesBase(cssParserMode, immutableArraySize)
{ }
int findPropertyIndex(CSSPropertyID) const;
int findCustomPropertyIndex(const String& propertyName) const;
private:
String getShorthandValue(const StylePropertyShorthand&) const;
String getCommonValue(const StylePropertyShorthand&) const;
String getAlignmentShorthandValue(const StylePropertyShorthand&) const;
String borderPropertyValue(const StylePropertyShorthand&, const StylePropertyShorthand&, const StylePropertyShorthand&) const;
String pageBreakPropertyValue(const StylePropertyShorthand&) const;
String getLayeredShorthandValue(const StylePropertyShorthand&) const;
String get2Values(const StylePropertyShorthand&) const;
String get4Values(const StylePropertyShorthand&) const;
String borderSpacingValue(const StylePropertyShorthand&) const;
String fontValue() const;
void appendFontLonghandValueIfExplicit(CSSPropertyID, StringBuilder& result, String& value) const;
RefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) const;
friend class PropertySetCSSStyleDeclaration;
};
class ImmutableStyleProperties final : public StyleProperties {
public:
WEBCORE_EXPORT ~ImmutableStyleProperties();
static Ref<ImmutableStyleProperties> create(const CSSProperty* properties, unsigned count, CSSParserMode);
unsigned propertyCount() const { return m_arraySize; }
bool isEmpty() const { return !propertyCount(); }
PropertyReference propertyAt(unsigned index) const;
const CSSValue** valueArray() const;
const StylePropertyMetadata* metadataArray() const;
int findPropertyIndex(CSSPropertyID) const;
int findCustomPropertyIndex(const String& propertyName) const;
void* m_storage;
private:
ImmutableStyleProperties(const CSSProperty*, unsigned count, CSSParserMode);
};
inline const CSSValue** ImmutableStyleProperties::valueArray() const
{
return reinterpret_cast<const CSSValue**>(const_cast<const void**>((&(this->m_storage))));
}
inline const StylePropertyMetadata* ImmutableStyleProperties::metadataArray() const
{
return reinterpret_cast_ptr<const StylePropertyMetadata*>(&reinterpret_cast_ptr<const char*>(&(this->m_storage))[m_arraySize * sizeof(CSSValue*)]);
}
class MutableStyleProperties final : public StyleProperties {
public:
WEBCORE_EXPORT static Ref<MutableStyleProperties> create(CSSParserMode = HTMLQuirksMode);
static Ref<MutableStyleProperties> create(Vector<CSSProperty>&&);
WEBCORE_EXPORT ~MutableStyleProperties();
unsigned propertyCount() const { return m_propertyVector.size(); }
bool isEmpty() const { return !propertyCount(); }
PropertyReference propertyAt(unsigned index) const;
PropertySetCSSStyleDeclaration* cssStyleDeclaration();
bool addParsedProperties(const ParsedPropertyVector&);
bool addParsedProperty(const CSSProperty&);
// These expand shorthand properties into multiple properties.
bool setProperty(CSSPropertyID, const String& value, bool important, CSSParserContext);
bool setProperty(CSSPropertyID, const String& value, bool important = false);
void setProperty(CSSPropertyID, RefPtr<CSSValue>&&, bool important = false);
// These do not. FIXME: This is too messy, we can do better.
bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
bool setProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false);
bool setProperty(const CSSProperty&, CSSProperty* slot = nullptr);
bool removeProperty(CSSPropertyID, String* returnText = nullptr);
void removeBlockProperties();
bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
void mergeAndOverrideOnConflict(const StyleProperties&);
void clear();
bool parseDeclaration(const String& styleDeclaration, CSSParserContext);
WEBCORE_EXPORT CSSStyleDeclaration& ensureCSSStyleDeclaration();
CSSStyleDeclaration& ensureInlineCSSStyleDeclaration(StyledElement& parentElement);
int findPropertyIndex(CSSPropertyID) const;
int findCustomPropertyIndex(const String& propertyName) const;
Vector<CSSProperty, 4> m_propertyVector;
// Methods for querying and altering CSS custom properties.
bool setCustomProperty(const Document*, const String& propertyName, const String& value, bool important, CSSParserContext);
bool removeCustomProperty(const String& propertyName, String* returnText = nullptr);
private:
explicit MutableStyleProperties(CSSParserMode);
explicit MutableStyleProperties(const StyleProperties&);
MutableStyleProperties(Vector<CSSProperty>&&);
bool removeShorthandProperty(CSSPropertyID);
CSSProperty* findCSSPropertyWithID(CSSPropertyID);
CSSProperty* findCustomCSSPropertyWithName(const String&);
std::unique_ptr<PropertySetCSSStyleDeclaration> m_cssomWrapper;
friend class StyleProperties;
};
class DeferredStyleProperties final : public StylePropertiesBase {
public:
WEBCORE_EXPORT ~DeferredStyleProperties();
static Ref<DeferredStyleProperties> create(const CSSParserTokenRange&, CSSDeferredParser&);
Ref<ImmutableStyleProperties> parseDeferredProperties();
private:
DeferredStyleProperties(const CSSParserTokenRange&, CSSDeferredParser&);
Vector<CSSParserToken> m_tokens;
Ref<CSSDeferredParser> m_parser;
};
inline ImmutableStyleProperties::PropertyReference ImmutableStyleProperties::propertyAt(unsigned index) const
{
return PropertyReference(metadataArray()[index], valueArray()[index]);
}
inline MutableStyleProperties::PropertyReference MutableStyleProperties::propertyAt(unsigned index) const
{
const CSSProperty& property = m_propertyVector[index];
return PropertyReference(property.metadata(), property.value());
}
inline StyleProperties::PropertyReference StyleProperties::propertyAt(unsigned index) const
{
if (is<MutableStyleProperties>(*this))
return downcast<MutableStyleProperties>(*this).propertyAt(index);
return downcast<ImmutableStyleProperties>(*this).propertyAt(index);
}
inline unsigned StyleProperties::propertyCount() const
{
if (is<MutableStyleProperties>(*this))
return downcast<MutableStyleProperties>(*this).propertyCount();
return downcast<ImmutableStyleProperties>(*this).propertyCount();
}
inline void StylePropertiesBase::deref() const
{
if (!derefBase())
return;
if (is<MutableStyleProperties>(*this))
delete downcast<MutableStyleProperties>(this);
else if (is<ImmutableStyleProperties>(*this))
delete downcast<ImmutableStyleProperties>(this);
else
delete downcast<DeferredStyleProperties>(this);
}
inline int StyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
{
if (is<MutableStyleProperties>(*this))
return downcast<MutableStyleProperties>(*this).findPropertyIndex(propertyID);
return downcast<ImmutableStyleProperties>(*this).findPropertyIndex(propertyID);
}
inline int StyleProperties::findCustomPropertyIndex(const String& propertyName) const
{
if (is<MutableStyleProperties>(*this))
return downcast<MutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
return downcast<ImmutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
}
} // namespace WebCore
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::StyleProperties)
static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() != WebCore::DeferredPropertiesType; }
SPECIALIZE_TYPE_TRAITS_END()
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MutableStyleProperties)
static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() == WebCore::MutablePropertiesType; }
SPECIALIZE_TYPE_TRAITS_END()
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ImmutableStyleProperties)
static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() == WebCore::ImmutablePropertiesType; }
SPECIALIZE_TYPE_TRAITS_END()
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::DeferredStyleProperties)
static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() == WebCore::DeferredPropertiesType; }
SPECIALIZE_TYPE_TRAITS_END()