This source file includes following definitions.
- presentationAttributeCache
- m_cleanTimer
- didHitPresentationAttributeCache
- cleanCache
- attributeNameSort
- makePresentationAttributeCacheKey
- computePresentationAttributeCacheHash
- computePresentationAttributeStyle
#include "config.h"
#include "core/dom/PresentationAttributeStyle.h"
#include "core/css/StylePropertySet.h"
#include "core/dom/Attribute.h"
#include "core/dom/Element.h"
#include "core/html/HTMLInputElement.h"
#include "wtf/HashFunctions.h"
#include "wtf/HashMap.h"
#include "wtf/text/CString.h"
namespace WebCore {
using namespace HTMLNames;
struct PresentationAttributeCacheKey {
PresentationAttributeCacheKey() : tagName(0) { }
StringImpl* tagName;
Vector<std::pair<StringImpl*, AtomicString>, 3> attributesAndValues;
};
static bool operator!=(const PresentationAttributeCacheKey& a, const PresentationAttributeCacheKey& b)
{
if (a.tagName != b.tagName)
return true;
return a.attributesAndValues != b.attributesAndValues;
}
struct PresentationAttributeCacheEntry {
WTF_MAKE_FAST_ALLOCATED;
public:
PresentationAttributeCacheKey key;
RefPtr<StylePropertySet> value;
};
typedef HashMap<unsigned, OwnPtr<PresentationAttributeCacheEntry>, AlreadyHashed> PresentationAttributeCache;
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, FROM_HERE);
}
private:
static const unsigned presentationAttributeCacheCleanTimeInSeconds = 60;
static const unsigned 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 bool attributeNameSort(const pair<StringImpl*, AtomicString>& p1, const pair<StringImpl*, AtomicString>& p2)
{
return p1.first < p2.first;
}
static void makePresentationAttributeCacheKey(Element& element, PresentationAttributeCacheKey& result)
{
if (!element.isHTMLElement())
return;
if (isHTMLInputElement(element))
return;
unsigned size = element.attributeCount();
for (unsigned i = 0; i < size; ++i) {
const Attribute& attribute = element.attributeItem(i);
if (!element.isPresentationAttribute(attribute.name()))
continue;
if (!attribute.namespaceURI().isNull())
return;
if (attribute.name() == backgroundAttr)
return;
result.attributesAndValues.append(std::make_pair(attribute.localName().impl(), attribute.value()));
}
if (result.attributesAndValues.isEmpty())
return;
std::sort(result.attributesAndValues.begin(), result.attributesAndValues.end(), attributeNameSort);
result.tagName = element.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);
}
PassRefPtr<StylePropertySet> computePresentationAttributeStyle(Element& element)
{
DEFINE_STATIC_LOCAL(PresentationAttributeCacheCleaner, cacheCleaner, ());
ASSERT(element.isStyledElement());
PresentationAttributeCacheKey cacheKey;
makePresentationAttributeCacheKey(element, cacheKey);
unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey);
PresentationAttributeCache::ValueType* cacheValue;
if (cacheHash) {
cacheValue = presentationAttributeCache().add(cacheHash, nullptr).storedValue;
if (cacheValue->value && cacheValue->value->key != cacheKey)
cacheHash = 0;
} else {
cacheValue = 0;
}
RefPtr<StylePropertySet> style;
if (cacheHash && cacheValue->value) {
style = cacheValue->value->value;
cacheCleaner.didHitPresentationAttributeCache();
} else {
style = MutableStylePropertySet::create(element.isSVGElement() ? SVGAttributeMode : HTMLAttributeMode);
unsigned size = element.attributeCount();
for (unsigned i = 0; i < size; ++i) {
const Attribute& attribute = element.attributeItem(i);
element.collectStyleForPresentationAttribute(attribute.name(), attribute.value(), toMutableStylePropertySet(style));
}
}
if (!cacheHash || cacheValue->value)
return style.release();
OwnPtr<PresentationAttributeCacheEntry> newEntry = adoptPtr(new PresentationAttributeCacheEntry);
newEntry->key = cacheKey;
newEntry->value = style;
static const unsigned presentationAttributeCacheMaximumSize = 4096;
if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) {
presentationAttributeCache().clear();
presentationAttributeCache().set(cacheHash, newEntry.release());
} else {
cacheValue->value = newEntry.release();
}
return style.release();
}
}