summaryrefslogtreecommitdiff
path: root/Source/WebCore/dom/StyledElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/dom/StyledElement.cpp')
-rw-r--r--Source/WebCore/dom/StyledElement.cpp260
1 files changed, 66 insertions, 194 deletions
diff --git a/Source/WebCore/dom/StyledElement.cpp b/Source/WebCore/dom/StyledElement.cpp
index a942efb59..2ee9997fd 100644
--- a/Source/WebCore/dom/StyledElement.cpp
+++ b/Source/WebCore/dom/StyledElement.cpp
@@ -3,7 +3,7 @@
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Peter Kelly (pmk@post.com)
* (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2008, 2010, 2014 Apple Inc. 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
@@ -28,8 +28,10 @@
#include "CSSParser.h"
#include "CSSStyleSheet.h"
#include "CSSValuePool.h"
+#include "CachedResource.h"
#include "ContentSecurityPolicy.h"
#include "DOMTokenList.h"
+#include "HTMLElement.h"
#include "HTMLParserIdioms.h"
#include "InspectorInstrumentation.h"
#include "PropertySetCSSStyleDeclaration.h"
@@ -44,87 +46,13 @@ COMPILE_ASSERT(sizeof(StyledElement) == sizeof(Element), styledelement_should_re
using namespace HTMLNames;
-struct PresentationAttributeCacheKey {
- PresentationAttributeCacheKey() : tagName(0) { }
- AtomicStringImpl* tagName;
- // Only the values need refcounting.
- Vector<std::pair<AtomicStringImpl*, AtomicString>, 3> attributesAndValues;
-};
-
-struct PresentationAttributeCacheEntry {
- WTF_MAKE_FAST_ALLOCATED;
-public:
- PresentationAttributeCacheKey key;
- RefPtr<StyleProperties> value;
-};
-
-typedef HashMap<unsigned, OwnPtr<PresentationAttributeCacheEntry>, AlreadyHashed> PresentationAttributeCache;
-
-static bool operator!=(const PresentationAttributeCacheKey& a, const PresentationAttributeCacheKey& b)
-{
- if (a.tagName != b.tagName)
- return true;
- return a.attributesAndValues != b.attributesAndValues;
-}
-
-static PresentationAttributeCache& presentationAttributeCache()
-{
- DEFINE_STATIC_LOCAL(PresentationAttributeCache, cache, ());
- return cache;
-}
-
-class PresentationAttributeCacheCleaner {
- WTF_MAKE_NONCOPYABLE(PresentationAttributeCacheCleaner); WTF_MAKE_FAST_ALLOCATED;
-public:
- PresentationAttributeCacheCleaner()
- : m_hitCount(0)
- , m_cleanTimer(this, &PresentationAttributeCacheCleaner::cleanCache)
- {
- }
-
- void didHitPresentationAttributeCache()
- {
- if (presentationAttributeCache().size() < minimumPresentationAttributeCacheSizeForCleaning)
- return;
-
- m_hitCount++;
-
- if (!m_cleanTimer.isActive())
- m_cleanTimer.startOneShot(presentationAttributeCacheCleanTimeInSeconds);
- }
-
-private:
- static const unsigned presentationAttributeCacheCleanTimeInSeconds = 60;
- static const int minimumPresentationAttributeCacheSizeForCleaning = 100;
- static const unsigned minimumPresentationAttributeCacheHitCountPerMinute = (100 * presentationAttributeCacheCleanTimeInSeconds) / 60;
-
- void cleanCache(Timer<PresentationAttributeCacheCleaner>* timer)
- {
- ASSERT_UNUSED(timer, timer == &m_cleanTimer);
- unsigned hitCount = m_hitCount;
- m_hitCount = 0;
- if (hitCount > minimumPresentationAttributeCacheHitCountPerMinute)
- return;
- presentationAttributeCache().clear();
- }
-
- unsigned m_hitCount;
- Timer<PresentationAttributeCacheCleaner> m_cleanTimer;
-};
-
-static PresentationAttributeCacheCleaner& presentationAttributeCacheCleaner()
+void StyledElement::synchronizeStyleAttributeInternal(StyledElement* styledElement)
{
- DEFINE_STATIC_LOCAL(PresentationAttributeCacheCleaner, cleaner, ());
- return cleaner;
-}
-
-void StyledElement::synchronizeStyleAttributeInternal() const
-{
- ASSERT(elementData());
- ASSERT(elementData()->styleAttributeIsDirty());
- elementData()->setStyleAttributeIsDirty(false);
- if (const StyleProperties* inlineStyle = this->inlineStyle())
- const_cast<StyledElement*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
+ ASSERT(styledElement->elementData());
+ ASSERT(styledElement->elementData()->styleAttributeIsDirty());
+ styledElement->elementData()->setStyleAttributeIsDirty(false);
+ if (const StyleProperties* inlineStyle = styledElement->inlineStyle())
+ styledElement->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
}
StyledElement::~StyledElement()
@@ -133,7 +61,7 @@ StyledElement::~StyledElement()
cssomWrapper->clearParentElement();
}
-CSSStyleDeclaration* StyledElement::style()
+CSSStyleDeclaration* StyledElement::cssomStyle()
{
return ensureMutableInlineStyle().ensureInlineCSSStyleDeclaration(this);
}
@@ -143,19 +71,20 @@ MutableStyleProperties& StyledElement::ensureMutableInlineStyle()
RefPtr<StyleProperties>& inlineStyle = ensureUniqueElementData().m_inlineStyle;
if (!inlineStyle)
inlineStyle = MutableStyleProperties::create(strictToCSSParserMode(isHTMLElement() && !document().inQuirksMode()));
- else if (!inlineStyle->isMutable())
+ else if (!is<MutableStyleProperties>(*inlineStyle))
inlineStyle = inlineStyle->mutableCopy();
- ASSERT_WITH_SECURITY_IMPLICATION(inlineStyle->isMutable());
- return static_cast<MutableStyleProperties&>(*inlineStyle);
+ return downcast<MutableStyleProperties>(*inlineStyle);
}
void StyledElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
{
- if (name == styleAttr)
- styleAttributeChanged(newValue, reason);
- else if (isPresentationAttribute(name)) {
- elementData()->setPresentationAttributeStyleIsDirty(true);
- setNeedsStyleRecalc(InlineStyleChange);
+ if (oldValue != newValue) {
+ if (name == styleAttr)
+ styleAttributeChanged(newValue, reason);
+ else if (isPresentationAttribute(name)) {
+ elementData()->setPresentationAttributeStyleIsDirty(true);
+ invalidateStyle();
+ }
}
Element::attributeChanged(name, oldValue, newValue, reason);
@@ -170,7 +99,12 @@ PropertySetCSSStyleDeclaration* StyledElement::inlineStyleCSSOMWrapper()
return cssomWrapper;
}
-inline void StyledElement::setInlineStyleFromString(const AtomicString& newStyleString)
+static bool usesStyleBasedEditability(const StyleProperties& properties)
+{
+ return properties.getPropertyCSSValue(CSSPropertyWebkitUserModify);
+}
+
+void StyledElement::setInlineStyleFromString(const AtomicString& newStyleString)
{
RefPtr<StyleProperties>& inlineStyle = elementData()->m_inlineStyle;
@@ -180,15 +114,16 @@ inline void StyledElement::setInlineStyleFromString(const AtomicString& newStyle
// We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
// This makes wrapperless property sets immutable and so cacheable.
- if (inlineStyle && !inlineStyle->isMutable())
- inlineStyle.clear();
+ if (inlineStyle && !is<MutableStyleProperties>(*inlineStyle))
+ inlineStyle = nullptr;
if (!inlineStyle)
inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
- else {
- ASSERT(inlineStyle->isMutable());
- static_pointer_cast<MutableStyleProperties>(inlineStyle)->parseDeclaration(newStyleString, &document().elementSheet().contents());
- }
+ else
+ downcast<MutableStyleProperties>(*inlineStyle).parseDeclaration(newStyleString, document());
+
+ if (usesStyleBasedEditability(*inlineStyle))
+ document().setHasElementUsingStyleBasedEditability();
}
void StyledElement::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason reason)
@@ -200,48 +135,55 @@ void StyledElement::styleAttributeChanged(const AtomicString& newStyleString, At
if (newStyleString.isNull()) {
if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
cssomWrapper->clearParentElement();
- ensureUniqueElementData().m_inlineStyle.clear();
- } else if (reason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber))
+ ensureUniqueElementData().m_inlineStyle = nullptr;
+ } else if (reason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber, String(), isInUserAgentShadowTree()))
setInlineStyleFromString(newStyleString);
elementData()->setStyleAttributeIsDirty(false);
- setNeedsStyleRecalc(InlineStyleChange);
- InspectorInstrumentation::didInvalidateStyleAttr(&document(), this);
+ invalidateStyle();
+ InspectorInstrumentation::didInvalidateStyleAttr(document(), *this);
}
-void StyledElement::inlineStyleChanged()
+void StyledElement::invalidateStyleAttribute()
{
- setNeedsStyleRecalc(InlineStyleChange);
- ASSERT(elementData());
+ if (usesStyleBasedEditability(*inlineStyle()))
+ document().setHasElementUsingStyleBasedEditability();
+
elementData()->setStyleAttributeIsDirty(true);
- InspectorInstrumentation::didInvalidateStyleAttr(&document(), this);
+ invalidateStyle();
+}
+
+void StyledElement::inlineStyleChanged()
+{
+ invalidateStyleAttribute();
+ InspectorInstrumentation::didInvalidateStyleAttr(document(), *this);
}
bool StyledElement::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
{
- ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
+ ensureMutableInlineStyle().setProperty(propertyID, CSSValuePool::singleton().createIdentifierValue(identifier), important);
inlineStyleChanged();
return true;
}
bool StyledElement::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
{
- ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
+ ensureMutableInlineStyle().setProperty(propertyID, CSSValuePool::singleton().createIdentifierValue(identifier), important);
inlineStyleChanged();
return true;
}
-bool StyledElement::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
+bool StyledElement::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitType unit, bool important)
{
- ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createValue(value, unit), important);
+ ensureMutableInlineStyle().setProperty(propertyID, CSSValuePool::singleton().createValue(value, unit), important);
inlineStyleChanged();
return true;
}
bool StyledElement::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
{
- bool changes = ensureMutableInlineStyle().setProperty(propertyID, value, important, &document().elementSheet().contents());
+ bool changes = ensureMutableInlineStyle().setProperty(propertyID, value, important, CSSParserContext(document()));
if (changes)
inlineStyleChanged();
return changes;
@@ -267,111 +209,41 @@ void StyledElement::removeAllInlineStyleProperties()
void StyledElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
{
- if (const StyleProperties* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
- inlineStyle->addSubresourceStyleURLs(urls, &document().elementSheet().contents());
-}
-
-static inline bool attributeNameSort(const std::pair<AtomicStringImpl*, AtomicString>& p1, const std::pair<AtomicStringImpl*, AtomicString>& p2)
-{
- // Sort based on the attribute name pointers. It doesn't matter what the order is as long as it is always the same.
- return p1.first < p2.first;
-}
-
-void StyledElement::makePresentationAttributeCacheKey(PresentationAttributeCacheKey& result) const
-{
- // FIXME: Enable for SVG.
- if (namespaceURI() != xhtmlNamespaceURI)
- return;
- // Interpretation of the size attributes on <input> depends on the type attribute.
- if (hasTagName(inputTag))
- return;
- for (const Attribute& attribute : attributesIterator()) {
- if (!isPresentationAttribute(attribute.name()))
- continue;
- if (!attribute.namespaceURI().isNull())
- return;
- // FIXME: Background URL may depend on the base URL and can't be shared. Disallow caching.
- if (attribute.name() == backgroundAttr)
- return;
- result.attributesAndValues.append(std::make_pair(attribute.localName().impl(), attribute.value()));
- }
- if (result.attributesAndValues.isEmpty())
+ auto* inlineStyle = this->inlineStyle();
+ if (!inlineStyle)
return;
- // Attribute order doesn't matter. Sort for easy equality comparison.
- std::sort(result.attributesAndValues.begin(), result.attributesAndValues.end(), attributeNameSort);
- // The cache key is non-null when the tagName is set.
- result.tagName = localName().impl();
-}
-
-static unsigned computePresentationAttributeCacheHash(const PresentationAttributeCacheKey& key)
-{
- if (!key.tagName)
- return 0;
- ASSERT(key.attributesAndValues.size());
- unsigned attributeHash = StringHasher::hashMemory(key.attributesAndValues.data(), key.attributesAndValues.size() * sizeof(key.attributesAndValues[0]));
- return WTF::pairIntHash(key.tagName->existingHash(), attributeHash);
+ inlineStyle->traverseSubresources([&] (auto& resource) {
+ urls.add(resource.url());
+ return false;
+ });
}
void StyledElement::rebuildPresentationAttributeStyle()
{
- PresentationAttributeCacheKey cacheKey;
- makePresentationAttributeCacheKey(cacheKey);
-
- unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey);
-
- PresentationAttributeCache::iterator cacheIterator;
- if (cacheHash) {
- cacheIterator = presentationAttributeCache().add(cacheHash, nullptr).iterator;
- if (cacheIterator->value && cacheIterator->value->key != cacheKey)
- cacheHash = 0;
- } else
- cacheIterator = presentationAttributeCache().end();
-
- RefPtr<StyleProperties> style;
- if (cacheHash && cacheIterator->value) {
- style = cacheIterator->value->value;
- presentationAttributeCacheCleaner().didHitPresentationAttributeCache();
- } else {
- style = MutableStyleProperties::create(isSVGElement() ? SVGAttributeMode : CSSQuirksMode);
- for (const Attribute& attribute : attributesIterator())
- collectStyleForPresentationAttribute(attribute.name(), attribute.value(), static_cast<MutableStyleProperties&>(*style));
- }
+ RefPtr<StyleProperties> style = MutableStyleProperties::create(isSVGElement() ? SVGAttributeMode : HTMLQuirksMode);
+ for (const Attribute& attribute : attributesIterator())
+ collectStyleForPresentationAttribute(attribute.name(), attribute.value(), static_cast<MutableStyleProperties&>(*style));
// ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
UniqueElementData& elementData = ensureUniqueElementData();
elementData.setPresentationAttributeStyleIsDirty(false);
- elementData.m_presentationAttributeStyle = style->isEmpty() ? 0 : style;
-
- if (!cacheHash || cacheIterator->value)
- return;
-
- OwnPtr<PresentationAttributeCacheEntry> newEntry = adoptPtr(new PresentationAttributeCacheEntry);
- newEntry->key = cacheKey;
- newEntry->value = style.release();
-
- static const int presentationAttributeCacheMaximumSize = 4096;
- if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) {
- // Start building from scratch if the cache ever gets big.
- presentationAttributeCache().clear();
- presentationAttributeCache().set(cacheHash, newEntry.release());
- } else
- cacheIterator->value = newEntry.release();
+ elementData.m_presentationAttributeStyle = style->isEmpty() ? nullptr : WTFMove(style);
}
void StyledElement::addPropertyToPresentationAttributeStyle(MutableStyleProperties& style, CSSPropertyID propertyID, CSSValueID identifier)
{
- style.setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
+ style.setProperty(propertyID, CSSValuePool::singleton().createIdentifierValue(identifier));
}
-void StyledElement::addPropertyToPresentationAttributeStyle(MutableStyleProperties& style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
+void StyledElement::addPropertyToPresentationAttributeStyle(MutableStyleProperties& style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitType unit)
{
- style.setProperty(propertyID, cssValuePool().createValue(value, unit));
+ style.setProperty(propertyID, CSSValuePool::singleton().createValue(value, unit));
}
void StyledElement::addPropertyToPresentationAttributeStyle(MutableStyleProperties& style, CSSPropertyID propertyID, const String& value)
{
- style.setProperty(propertyID, value, false, &document().elementSheet().contents());
+ style.setProperty(propertyID, value, false, CSSParserContext(document()));
}
}