MatchedDeclarationsCache.cpp [plain text]
#include "config.h"
#include "MatchedDeclarationsCache.h"
#include "CSSFontSelector.h"
#include "FontCascade.h"
#include <wtf/text/StringHash.h>
namespace WebCore {
namespace Style {
MatchedDeclarationsCache::MatchedDeclarationsCache()
: m_sweepTimer(*this, &MatchedDeclarationsCache::sweep)
{
}
MatchedDeclarationsCache::~MatchedDeclarationsCache() = default;
bool MatchedDeclarationsCache::isCacheable(const Element& element, const RenderStyle& style, const RenderStyle& parentStyle)
{
if (&element == element.document().documentElement())
return false;
if (style.hasAttrContent() || (style.styleType() != PseudoId::None && parentStyle.hasAttrContent()))
return false;
if (style.hasAppearance())
return false;
if (style.zoom() != RenderStyle::initialZoom())
return false;
if (style.writingMode() != RenderStyle::initialWritingMode() || style.direction() != RenderStyle::initialDirection())
return false;
if (style.hasExplicitlyInheritedProperties())
return false;
auto& fontSelector = element.document().fontSelector();
if (!style.fontCascade().isCurrent(fontSelector))
return false;
if (!parentStyle.fontCascade().isCurrent(fontSelector))
return false;
return true;
}
bool MatchedDeclarationsCache::Entry::isUsableAfterHighPriorityProperties(const RenderStyle& style) const
{
if (style.effectiveZoom() != renderStyle->effectiveZoom())
return false;
return CSSPrimitiveValue::equalForLengthResolution(style, *renderStyle);
}
unsigned MatchedDeclarationsCache::computeHash(const MatchResult& matchResult)
{
if (!matchResult.isCacheable)
return 0;
return StringHasher::hashMemory(matchResult.userAgentDeclarations.data(), sizeof(MatchedProperties) * matchResult.userAgentDeclarations.size())
^ StringHasher::hashMemory(matchResult.userDeclarations.data(), sizeof(MatchedProperties) * matchResult.userDeclarations.size())
^ StringHasher::hashMemory(matchResult.authorDeclarations.data(), sizeof(MatchedProperties) * matchResult.authorDeclarations.size());
}
const MatchedDeclarationsCache::Entry* MatchedDeclarationsCache::find(unsigned hash, const MatchResult& matchResult)
{
if (!hash)
return nullptr;
auto it = m_entries.find(hash);
if (it == m_entries.end())
return nullptr;
auto& entry = it->value;
if (matchResult != entry.matchResult)
return nullptr;
return &entry;
}
void MatchedDeclarationsCache::add(const RenderStyle& style, const RenderStyle& parentStyle, unsigned hash, const MatchResult& matchResult)
{
constexpr unsigned additionsBetweenSweeps = 100;
if (++m_additionsSinceLastSweep >= additionsBetweenSweeps && !m_sweepTimer.isActive()) {
constexpr auto sweepDelay = 1_min;
m_sweepTimer.startOneShot(sweepDelay);
}
ASSERT(hash);
m_entries.add(hash, Entry { matchResult, RenderStyle::clonePtr(style), RenderStyle::clonePtr(parentStyle) });
}
void MatchedDeclarationsCache::invalidate()
{
m_entries.clear();
}
void MatchedDeclarationsCache::clearEntriesAffectedByViewportUnits()
{
m_entries.removeIf([](auto& keyValue) {
return keyValue.value.renderStyle->hasViewportUnits();
});
}
void MatchedDeclarationsCache::sweep()
{
auto hasOneRef = [](auto& declarations) {
for (auto& matchedProperties : declarations) {
if (matchedProperties.properties->hasOneRef())
return true;
}
return false;
};
m_entries.removeIf([&](auto& keyValue) {
auto& matchResult = keyValue.value.matchResult;
return hasOneRef(matchResult.userAgentDeclarations) || hasOneRef(matchResult.userDeclarations) || hasOneRef(matchResult.authorDeclarations);
});
m_additionsSinceLastSweep = 0;
}
}
}