diff options
Diffstat (limited to 'Source/WebCore/dom/StyledElement.cpp')
-rw-r--r-- | Source/WebCore/dom/StyledElement.cpp | 260 |
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())); } } |