Commit 9f77ca91 authored by rune@opera.com's avatar rune@opera.com

Prepare for multiple !important author ranges.

This CL is split out from [1] where we support multiple author origins in
terms of shadow dom scopes. The vector of MatchedProperties contains
matched declarations from all origins in the order in which they should
be applied. For !important declarations, they are applied in the same
order within the same origin, but the order of the origins are different
as the cascading order is:

  - UA important
  - Author important
  - Author
  - UA

We used to have two ranges, one for UA and one for author to accomplish
this. However, with the normal/!important cascading order for
declarations from different shadow doms, we need multiple author ranges:

  - UA important
  - Author important scope n
  ...
  - Author important scope 1
  - Author scope 1
  ...
  - Author scope n
  - UA

We introduce an ImportantAuthorRangeIterator to iterate through the
author ranges and add iterator-style iteration for each range through the
MatchedPropertiesRange class.

As the applyMatchedProperties code is hot, I've run the blink_perf.css
tests locally. Some improved by 2-4%, some became worse by similar
percentages.

[1] https://codereview.chromium.org/1224673002/

BUG=487125
TEST=fast/css

Review URL: https://codereview.chromium.org/1282243002

git-svn-id: svn://svn.chromium.org/blink/trunk@200697 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 4423b43c
...@@ -3736,6 +3736,7 @@ ...@@ -3736,6 +3736,7 @@
'css/parser/SizesAttributeParserTest.cpp', 'css/parser/SizesAttributeParserTest.cpp',
'css/parser/SizesCalcParserTest.cpp', 'css/parser/SizesCalcParserTest.cpp',
'css/resolver/FontBuilderTest.cpp', 'css/resolver/FontBuilderTest.cpp',
'css/resolver/MatchResultTest.cpp',
'dom/ActiveDOMObjectTest.cpp', 'dom/ActiveDOMObjectTest.cpp',
'dom/AttrTest.cpp', 'dom/AttrTest.cpp',
'dom/CrossThreadTaskTest.cpp', 'dom/CrossThreadTaskTest.cpp',
......
...@@ -110,7 +110,7 @@ void ElementRuleCollector::addElementStyleProperties(const StylePropertySet* pro ...@@ -110,7 +110,7 @@ void ElementRuleCollector::addElementStyleProperties(const StylePropertySet* pro
return; return;
m_result.addMatchedProperties(propertySet); m_result.addMatchedProperties(propertySet);
if (!isCacheable) if (!isCacheable)
m_result.isCacheable = false; m_result.setIsCacheable(false);
} }
static bool rulesApplicableInCurrentTreeScope(const Element* element, const ContainerNode* scopingNode, bool matchingTreeBoundaryRules) static bool rulesApplicableInCurrentTreeScope(const Element* element, const ContainerNode* scopingNode, bool matchingTreeBoundaryRules)
...@@ -293,9 +293,6 @@ void ElementRuleCollector::sortAndTransferMatchedRules() ...@@ -293,9 +293,6 @@ void ElementRuleCollector::sortAndTransferMatchedRules()
const RuleData* ruleData = m_matchedRules[i].ruleData(); const RuleData* ruleData = m_matchedRules[i].ruleData();
m_result.addMatchedProperties(&ruleData->rule()->properties(), ruleData->linkMatchType(), ruleData->propertyWhitelistType(m_matchingUARules)); m_result.addMatchedProperties(&ruleData->rule()->properties(), ruleData->linkMatchType(), ruleData->propertyWhitelistType(m_matchingUARules));
} }
if (m_matchingUARules)
m_result.uaEnd = m_result.matchedProperties.size();
} }
void ElementRuleCollector::didMatchRule(const RuleData& ruleData, const SelectorChecker::MatchResult& result, CascadeOrder cascadeOrder, const MatchRequest& matchRequest) void ElementRuleCollector::didMatchRule(const RuleData& ruleData, const SelectorChecker::MatchResult& result, CascadeOrder cascadeOrder, const MatchRequest& matchRequest)
......
...@@ -127,6 +127,8 @@ public: ...@@ -127,6 +127,8 @@ public:
void sortAndTransferMatchedRules(); void sortAndTransferMatchedRules();
void clearMatchedRules(); void clearMatchedRules();
void addElementStyleProperties(const StylePropertySet*, bool isCacheable = true); void addElementStyleProperties(const StylePropertySet*, bool isCacheable = true);
void finishAddingUARules() { m_result.finishAddingUARules(); }
void finishAddingAuthorRulesForTreeScope() { m_result.finishAddingAuthorRulesForTreeScope(); }
private: private:
template<typename RuleDataListType> template<typename RuleDataListType>
......
...@@ -50,11 +50,26 @@ DEFINE_TRACE(MatchedProperties) ...@@ -50,11 +50,26 @@ DEFINE_TRACE(MatchedProperties)
void MatchResult::addMatchedProperties(const StylePropertySet* properties, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType) void MatchResult::addMatchedProperties(const StylePropertySet* properties, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType)
{ {
matchedProperties.grow(matchedProperties.size() + 1); m_matchedProperties.grow(m_matchedProperties.size() + 1);
MatchedProperties& newProperties = matchedProperties.last(); MatchedProperties& newProperties = m_matchedProperties.last();
newProperties.properties = const_cast<StylePropertySet*>(properties); newProperties.properties = const_cast<StylePropertySet*>(properties);
newProperties.m_types.linkMatchType = linkMatchType; newProperties.m_types.linkMatchType = linkMatchType;
newProperties.m_types.whitelistType = propertyWhitelistType; newProperties.m_types.whitelistType = propertyWhitelistType;
} }
void MatchResult::finishAddingUARules()
{
m_uaRangeEnd = m_matchedProperties.size();
}
void MatchResult::finishAddingAuthorRulesForTreeScope()
{
// Don't add empty ranges.
if (m_authorRangeEnds.isEmpty() && m_uaRangeEnd == m_matchedProperties.size())
return;
if (!m_authorRangeEnds.isEmpty() && m_authorRangeEnds.last() == m_matchedProperties.size())
return;
m_authorRangeEnds.append(m_matchedProperties.size());
}
} // namespace blink } // namespace blink
...@@ -33,7 +33,7 @@ namespace blink { ...@@ -33,7 +33,7 @@ namespace blink {
class StylePropertySet; class StylePropertySet;
struct MatchedProperties { struct CORE_EXPORT MatchedProperties {
ALLOW_ONLY_INLINE_ALLOCATION(); ALLOW_ONLY_INLINE_ALLOCATION();
public: public:
MatchedProperties(); MatchedProperties();
...@@ -59,21 +59,97 @@ WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::MatchedProperties); ...@@ -59,21 +59,97 @@ WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::MatchedProperties);
namespace blink { namespace blink {
class MatchResult { using MatchedPropertiesVector = WillBeHeapVector<MatchedProperties, 64>;
// MatchedPropertiesRange is used to represent a subset of the matched properties from
// a given origin, for instance UA rules, author rules, or a shadow tree scope. This is
// needed because rules from different origins are applied in the opposite order for
// !important rules, yet in the same order as for normal rules within the same origin.
class MatchedPropertiesRange {
public:
MatchedPropertiesRange(MatchedPropertiesVector::const_iterator begin, MatchedPropertiesVector::const_iterator end)
: m_begin(begin)
, m_end(end)
{
}
MatchedPropertiesVector::const_iterator begin() const { return m_begin; }
MatchedPropertiesVector::const_iterator end() const { return m_end; }
bool isEmpty() const { return begin() == end(); }
private:
MatchedPropertiesVector::const_iterator m_begin;
MatchedPropertiesVector::const_iterator m_end;
};
class CORE_EXPORT MatchResult {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
void addMatchedProperties(const StylePropertySet* properties, unsigned linkMatchType = CSSSelector::MatchAll, PropertyWhitelistType = PropertyWhitelistNone); void addMatchedProperties(const StylePropertySet* properties, unsigned linkMatchType = CSSSelector::MatchAll, PropertyWhitelistType = PropertyWhitelistNone);
bool hasMatchedProperties() const { return m_matchedProperties.size(); }
void finishAddingUARules();
void finishAddingAuthorRulesForTreeScope();
void setIsCacheable(bool cacheable) { m_isCacheable = cacheable; }
bool isCacheable() const { return m_isCacheable; }
MatchedPropertiesRange allRules() const { return MatchedPropertiesRange(m_matchedProperties.begin(), m_matchedProperties.end()); }
MatchedPropertiesRange uaRules() const { return MatchedPropertiesRange(m_matchedProperties.begin(), m_matchedProperties.begin() + m_uaRangeEnd); }
MatchedPropertiesRange authorRules() const { return MatchedPropertiesRange(m_matchedProperties.begin() + m_uaRangeEnd, m_matchedProperties.end()); }
const MatchedPropertiesVector& matchedProperties() const { return m_matchedProperties; }
private:
friend class ImportantAuthorRanges;
friend class ImportantAuthorRangeIterator;
MatchedPropertiesVector m_matchedProperties;
Vector<unsigned, 16> m_authorRangeEnds;
unsigned m_uaRangeEnd = 0;
bool m_isCacheable = true;
};
class ImportantAuthorRangeIterator {
public:
ImportantAuthorRangeIterator(const MatchResult& result, int endIndex)
: m_result(result)
, m_endIndex(endIndex) { }
MatchedPropertiesRange operator*() const
{
ASSERT(m_endIndex >= 0);
unsigned rangeEnd = m_result.m_authorRangeEnds[m_endIndex];
unsigned rangeBegin = m_endIndex ? m_result.m_authorRangeEnds[m_endIndex - 1] : m_result.m_uaRangeEnd;
return MatchedPropertiesRange(m_result.matchedProperties().begin() + rangeBegin, m_result.matchedProperties().begin() + rangeEnd);
}
ImportantAuthorRangeIterator& operator++()
{
ASSERT(m_endIndex >= 0);
--m_endIndex;
return *this;
}
bool operator==(const ImportantAuthorRangeIterator& other) const { return m_endIndex == other.m_endIndex && &m_result == &other.m_result; }
bool operator!=(const ImportantAuthorRangeIterator& other) const { return !(*this == other); }
private:
const MatchResult& m_result;
unsigned m_endIndex;
};
class ImportantAuthorRanges {
public:
explicit ImportantAuthorRanges(const MatchResult& result) : m_result(result) { }
unsigned begin() const { return 0; } ImportantAuthorRangeIterator begin() const { return ImportantAuthorRangeIterator(m_result, m_result.m_authorRangeEnds.size() - 1); }
unsigned end() const { return matchedProperties.size(); } ImportantAuthorRangeIterator end() const { return ImportantAuthorRangeIterator(m_result, -1); }
unsigned beginUA() const { return 0; }
unsigned endUA() const { return uaEnd; }
unsigned beginAuthor() const { return uaEnd; }
unsigned endAuthor() const { return matchedProperties.size(); }
WillBeHeapVector<MatchedProperties, 64> matchedProperties; private:
unsigned uaEnd = 0; const MatchResult& m_result;
bool isCacheable = true;
}; };
inline bool operator==(const MatchedProperties& a, const MatchedProperties& b) inline bool operator==(const MatchedProperties& a, const MatchedProperties& b)
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/css/resolver/MatchResult.h"
#include "core/css/StylePropertySet.h"
#include <gtest/gtest.h>
namespace blink {
class MatchResultTest : public ::testing::Test {
protected:
void SetUp() override;
const StylePropertySet* propertySet(unsigned index) const
{
return propertySets[index].get();
}
private:
WillBePersistentHeapVector<RefPtrWillBeMember<MutableStylePropertySet>, 6> propertySets;
};
void MatchResultTest::SetUp()
{
for (unsigned i = 0; i < 6; i++)
propertySets.append(MutableStylePropertySet::create());
}
void testMatchedPropertiesRange(const MatchedPropertiesRange& range, int expectedLength, const StylePropertySet** expectedSets)
{
EXPECT_EQ(expectedLength, range.end() - range.begin());
for (const auto& matchedProperties : range)
EXPECT_EQ(*expectedSets++, matchedProperties.properties);
}
TEST_F(MatchResultTest, UARules)
{
const StylePropertySet* uaSets[] = { propertySet(0), propertySet(1) };
MatchResult result;
result.addMatchedProperties(uaSets[0]);
result.addMatchedProperties(uaSets[1]);
result.finishAddingUARules();
result.finishAddingAuthorRulesForTreeScope();
testMatchedPropertiesRange(result.allRules(), 2, uaSets);
testMatchedPropertiesRange(result.uaRules(), 2, uaSets);
testMatchedPropertiesRange(result.authorRules(), 0, nullptr);
ImportantAuthorRanges important(result);
EXPECT_EQ(important.end(), important.begin());
}
TEST_F(MatchResultTest, AuthorRules)
{
const StylePropertySet* authorSets[] = { propertySet(0), propertySet(1) };
MatchResult result;
result.finishAddingUARules();
result.addMatchedProperties(authorSets[0]);
result.addMatchedProperties(authorSets[1]);
result.finishAddingAuthorRulesForTreeScope();
testMatchedPropertiesRange(result.allRules(), 2, authorSets);
testMatchedPropertiesRange(result.uaRules(), 0, nullptr);
testMatchedPropertiesRange(result.authorRules(), 2, authorSets);
ImportantAuthorRanges important(result);
EXPECT_EQ(important.end(), ++important.begin());
}
TEST_F(MatchResultTest, UAAndAuthorRules)
{
const StylePropertySet* allSets[] = { propertySet(0), propertySet(1), propertySet(2), propertySet(3) };
const StylePropertySet** uaSets = &allSets[0];
const StylePropertySet** authorSets = &allSets[2];
MatchResult result;
result.addMatchedProperties(uaSets[0]);
result.addMatchedProperties(uaSets[1]);
result.finishAddingUARules();
result.addMatchedProperties(authorSets[0]);
result.addMatchedProperties(authorSets[1]);
result.finishAddingAuthorRulesForTreeScope();
testMatchedPropertiesRange(result.allRules(), 4, allSets);
testMatchedPropertiesRange(result.uaRules(), 2, uaSets);
testMatchedPropertiesRange(result.authorRules(), 2, authorSets);
ImportantAuthorRanges important(result);
EXPECT_EQ(important.end(), ++important.begin());
}
TEST_F(MatchResultTest, AuthorRulesMultipleScopes)
{
const StylePropertySet* authorSets[] = { propertySet(0), propertySet(1), propertySet(2), propertySet(3) };
MatchResult result;
result.finishAddingUARules();
result.addMatchedProperties(authorSets[0]);
result.addMatchedProperties(authorSets[1]);
result.finishAddingAuthorRulesForTreeScope();
result.addMatchedProperties(authorSets[2]);
result.addMatchedProperties(authorSets[3]);
result.finishAddingAuthorRulesForTreeScope();
testMatchedPropertiesRange(result.allRules(), 4, authorSets);
testMatchedPropertiesRange(result.uaRules(), 0, nullptr);
testMatchedPropertiesRange(result.authorRules(), 4, authorSets);
ImportantAuthorRanges important(result);
auto iter = important.begin();
EXPECT_NE(important.end(), iter);
testMatchedPropertiesRange(*iter, 2, &authorSets[2]);
++iter;
EXPECT_NE(important.end(), iter);
testMatchedPropertiesRange(*iter, 2, authorSets);
++iter;
EXPECT_EQ(important.end(), iter);
}
TEST_F(MatchResultTest, UARulesAndAuthorRulesMultipleScopes)
{
const StylePropertySet* allSets[] = { propertySet(0), propertySet(1), propertySet(2), propertySet(3), propertySet(4), propertySet(5) };
const StylePropertySet** uaSets = &allSets[0];
const StylePropertySet** authorSets = &allSets[2];
MatchResult result;
result.addMatchedProperties(uaSets[0]);
result.addMatchedProperties(uaSets[1]);
result.finishAddingUARules();
result.addMatchedProperties(authorSets[0]);
result.addMatchedProperties(authorSets[1]);
result.finishAddingAuthorRulesForTreeScope();
result.addMatchedProperties(authorSets[2]);
result.addMatchedProperties(authorSets[3]);
result.finishAddingAuthorRulesForTreeScope();
testMatchedPropertiesRange(result.allRules(), 6, allSets);
testMatchedPropertiesRange(result.uaRules(), 2, uaSets);
testMatchedPropertiesRange(result.authorRules(), 4, authorSets);
ImportantAuthorRanges important(result);
ImportantAuthorRangeIterator iter = important.begin();
EXPECT_NE(important.end(), iter);
testMatchedPropertiesRange(*iter, 2, &authorSets[2]);
++iter;
EXPECT_NE(important.end(), iter);
testMatchedPropertiesRange(*iter, 2, authorSets);
++iter;
EXPECT_EQ(important.end(), iter);
}
} // namespace blink
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
namespace blink { namespace blink {
void CachedMatchedProperties::set(const ComputedStyle& style, const ComputedStyle& parentStyle, const MatchResult& matchResult) void CachedMatchedProperties::set(const ComputedStyle& style, const ComputedStyle& parentStyle, const MatchedPropertiesVector& properties)
{ {
matchedProperties.appendVector(matchResult.matchedProperties); matchedProperties.appendVector(properties);
// Note that we don't cache the original ComputedStyle instance. It may be further modified. // Note that we don't cache the original ComputedStyle instance. It may be further modified.
// The ComputedStyle in the cache is really just a holder for the substructures and never used as-is. // The ComputedStyle in the cache is really just a holder for the substructures and never used as-is.
...@@ -60,7 +60,7 @@ MatchedPropertiesCache::MatchedPropertiesCache() ...@@ -60,7 +60,7 @@ MatchedPropertiesCache::MatchedPropertiesCache()
{ {
} }
const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const StyleResolverState& styleResolverState, const MatchResult& matchResult) const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const StyleResolverState& styleResolverState, const MatchedPropertiesVector& properties)
{ {
ASSERT(hash); ASSERT(hash);
...@@ -70,19 +70,19 @@ const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const ...@@ -70,19 +70,19 @@ const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const
CachedMatchedProperties* cacheItem = it->value.get(); CachedMatchedProperties* cacheItem = it->value.get();
ASSERT(cacheItem); ASSERT(cacheItem);
size_t size = matchResult.matchedProperties.size(); size_t size = properties.size();
if (size != cacheItem->matchedProperties.size()) if (size != cacheItem->matchedProperties.size())
return 0; return 0;
if (cacheItem->computedStyle->insideLink() != styleResolverState.style()->insideLink()) if (cacheItem->computedStyle->insideLink() != styleResolverState.style()->insideLink())
return 0; return 0;
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
if (matchResult.matchedProperties[i] != cacheItem->matchedProperties[i]) if (properties[i] != cacheItem->matchedProperties[i])
return 0; return 0;
} }
return cacheItem; return cacheItem;
} }
void MatchedPropertiesCache::add(const ComputedStyle& style, const ComputedStyle& parentStyle, unsigned hash, const MatchResult& matchResult) void MatchedPropertiesCache::add(const ComputedStyle& style, const ComputedStyle& parentStyle, unsigned hash, const MatchedPropertiesVector& properties)
{ {
#if !ENABLE(OILPAN) #if !ENABLE(OILPAN)
static const unsigned maxAdditionsBetweenSweeps = 100; static const unsigned maxAdditionsBetweenSweeps = 100;
...@@ -102,7 +102,7 @@ void MatchedPropertiesCache::add(const ComputedStyle& style, const ComputedStyle ...@@ -102,7 +102,7 @@ void MatchedPropertiesCache::add(const ComputedStyle& style, const ComputedStyle
if (!addResult.isNewEntry) if (!addResult.isNewEntry)
cacheItem->clear(); cacheItem->clear();
cacheItem->set(style, parentStyle, matchResult); cacheItem->set(style, parentStyle, properties);
} }
void MatchedPropertiesCache::clear() void MatchedPropertiesCache::clear()
......
...@@ -43,7 +43,7 @@ public: ...@@ -43,7 +43,7 @@ public:
RefPtr<ComputedStyle> computedStyle; RefPtr<ComputedStyle> computedStyle;
RefPtr<ComputedStyle> parentComputedStyle; RefPtr<ComputedStyle> parentComputedStyle;
void set(const ComputedStyle&, const ComputedStyle& parentStyle, const MatchResult&); void set(const ComputedStyle&, const ComputedStyle& parentStyle, const MatchedPropertiesVector&);
void clear(); void clear();
DEFINE_INLINE_TRACE() DEFINE_INLINE_TRACE()
{ {
...@@ -95,8 +95,8 @@ class MatchedPropertiesCache { ...@@ -95,8 +95,8 @@ class MatchedPropertiesCache {
public: public:
MatchedPropertiesCache(); MatchedPropertiesCache();
const CachedMatchedProperties* find(unsigned hash, const StyleResolverState&, const MatchResult&); const CachedMatchedProperties* find(unsigned hash, const StyleResolverState&, const MatchedPropertiesVector&);
void add(const ComputedStyle&, const ComputedStyle& parentStyle, unsigned hash, const MatchResult&); void add(const ComputedStyle&, const ComputedStyle& parentStyle, unsigned hash, const MatchedPropertiesVector&);
void clear(); void clear();
void clearViewportDependent(); void clearViewportDependent();
......
...@@ -413,6 +413,7 @@ void StyleResolver::matchUARules(ElementRuleCollector& collector) ...@@ -413,6 +413,7 @@ void StyleResolver::matchUARules(ElementRuleCollector& collector)
if (document().isViewSource()) if (document().isViewSource())
matchRuleSet(collector, defaultStyleSheets.defaultViewSourceStyle()); matchRuleSet(collector, defaultStyleSheets.defaultViewSourceStyle());
collector.finishAddingUARules();
collector.setMatchingUARules(false); collector.setMatchingUARules(false);
} }
...@@ -459,6 +460,8 @@ void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollecto ...@@ -459,6 +460,8 @@ void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollecto
if (includeSMILProperties && state.element()->isSVGElement()) if (includeSMILProperties && state.element()->isSVGElement())
collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */); collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */);
} }
collector.finishAddingAuthorRulesForTreeScope();
} }
PassRefPtr<ComputedStyle> StyleResolver::styleForDocument(Document& document) PassRefPtr<ComputedStyle> StyleResolver::styleForDocument(Document& document)
...@@ -756,8 +759,9 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo ...@@ -756,8 +759,9 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo
matchUARules(collector); matchUARules(collector);
matchAuthorRules(state.element(), collector, false); matchAuthorRules(state.element(), collector, false);
collector.finishAddingAuthorRulesForTreeScope();
if (collector.matchedResult().matchedProperties.isEmpty()) if (!collector.matchedResult().hasMatchedProperties())
return false; return false;
applyMatchedProperties(state, collector.matchedResult()); applyMatchedProperties(state, collector.matchedResult());
...@@ -830,12 +834,12 @@ PassRefPtr<ComputedStyle> StyleResolver::styleForPage(int pageIndex) ...@@ -830,12 +834,12 @@ PassRefPtr<ComputedStyle> StyleResolver::styleForPage(int pageIndex)
bool inheritedOnly = false; bool inheritedOnly = false;
const MatchResult& result = collector.matchedResult(); const MatchResult& result = collector.matchedResult();
applyMatchedProperties<HighPropertyPriority>(state, result, false, result.begin(), result.end(), inheritedOnly); applyMatchedProperties<HighPropertyPriority>(state, result.allRules(), false, inheritedOnly);
// If our font got dirtied, go ahead and update it now. // If our font got dirtied, go ahead and update it now.
updateFont(state); updateFont(state);
applyMatchedProperties<LowPropertyPriority>(state, result, false, result.begin(), result.end(), inheritedOnly); applyMatchedProperties<LowPropertyPriority>(state, result.allRules(), false, inheritedOnly);
loadPendingResources(state); loadPendingResources(state);
...@@ -1233,16 +1237,13 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper ...@@ -1233,16 +1237,13 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper
} }
template <CSSPropertyPriority priority> template <CSSPropertyPriority priority>
void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, unsigned startIndex, unsigned endIndex, bool inheritedOnly) void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchedPropertiesRange& range, bool isImportant, bool inheritedOnly)
{ {
if (startIndex == endIndex) if (range.isEmpty())
return; return;
ASSERT_WITH_SECURITY_IMPLICATION(endIndex <= matchResult.matchedProperties.size());
if (state.style()->insideLink() != NotInsideLink) { if (state.style()->insideLink() != NotInsideLink) {
for (unsigned i = startIndex; i < endIndex; ++i) { for (const auto& matchedProperties : range) {
const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
unsigned linkMatchType = matchedProperties.m_types.linkMatchType; unsigned linkMatchType = matchedProperties.m_types.linkMatchType;
// FIXME: It would be nicer to pass these as arguments but that requires changes in many places. // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
state.setApplyPropertyToRegularStyle(linkMatchType & CSSSelector::MatchLink); state.setApplyPropertyToRegularStyle(linkMatchType & CSSSelector::MatchLink);
...@@ -1254,10 +1255,8 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc ...@@ -1254,10 +1255,8 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc
state.setApplyPropertyToVisitedLinkStyle(false); state.setApplyPropertyToVisitedLinkStyle(false);
return; return;
} }
for (unsigned i = startIndex; i < endIndex; ++i) { for (const auto& matchedProperties : range)
const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
applyProperties<priority>(state, matchedProperties.properties.get(), isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType)); applyProperties<priority>(state, matchedProperties.properties.get(), isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType));
}
} }
static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size) static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
...@@ -1283,9 +1282,9 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc ...@@ -1283,9 +1282,9 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc
INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply, 1); INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply, 1);
unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0; unsigned cacheHash = matchResult.isCacheable() ? computeMatchedPropertiesHash(matchResult.matchedProperties().data(), matchResult.matchedProperties().size()) : 0;
bool applyInheritedOnly = false; bool applyInheritedOnly = false;
const CachedMatchedProperties* cachedMatchedProperties = cacheHash ? m_matchedPropertiesCache.find(cacheHash, state, matchResult) : 0; const CachedMatchedProperties* cachedMatchedProperties = cacheHash ? m_matchedPropertiesCache.find(cacheHash, state, matchResult.matchedProperties()) : 0;
if (cachedMatchedProperties && MatchedPropertiesCache::isCacheable(element, *state.style(), *state.parentStyle())) { if (cachedMatchedProperties && MatchedPropertiesCache::isCacheable(element, *state.style(), *state.parentStyle())) {
INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit, 1); INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit, 1);
...@@ -1316,9 +1315,10 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc ...@@ -1316,9 +1315,10 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc
// high-priority properties first, i.e., those properties that other properties depend on. // high-priority properties first, i.e., those properties that other properties depend on.
// The order is (1) high-priority not important, (2) high-priority important, (3) normal not important // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
// and (4) normal important. // and (4) normal important.
applyMatchedProperties<HighPropertyPriority>(state, matchResult, false, matchResult.begin(), matchResult.end(), applyInheritedOnly); applyMatchedProperties<HighPropertyPriority>(state, matchResult.allRules(), false, applyInheritedOnly);
applyMatchedProperties<HighPropertyPriority>(state, matchResult, true, matchResult.beginAuthor(), matchResult.endAuthor(), applyInheritedOnly); for (auto range : ImportantAuthorRanges(matchResult))
applyMatchedProperties<HighPropertyPriority>(state, matchResult, true, matchResult.beginUA(), matchResult.endUA(), applyInheritedOnly); applyMatchedProperties<HighPropertyPriority>(state, range, true, applyInheritedOnly);
applyMatchedProperties<HighPropertyPriority>(state, matchResult.uaRules(), true, applyInheritedOnly);
if (UNLIKELY(isSVGForeignObjectElement(element))) { if (UNLIKELY(isSVGForeignObjectElement(element))) {
// LayoutSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again. // LayoutSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again.
...@@ -1344,21 +1344,22 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc ...@@ -1344,21 +1344,22 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc
applyInheritedOnly = false; applyInheritedOnly = false;
// Now do the normal priority UA properties. // Now do the normal priority UA properties.
applyMatchedProperties<LowPropertyPriority>(state, matchResult, false, matchResult.beginUA(), matchResult.endUA(), applyInheritedOnly); applyMatchedProperties<LowPropertyPriority>(state, matchResult.uaRules(), false, applyInheritedOnly);
// Cache the UA properties to pass them to LayoutTheme in adjustComputedStyle. // Cache the UA properties to pass them to LayoutTheme in adjustComputedStyle.
state.cacheUserAgentBorderAndBackground(); state.cacheUserAgentBorderAndBackground();
// Now do the author and user normal priority properties and all the !important properties. // Now do the author and user normal priority properties and all the !important properties.
applyMatchedProperties<LowPropertyPriority>(state, matchResult, false, matchResult.beginAuthor(), matchResult.endAuthor(), applyInheritedOnly); applyMatchedProperties<LowPropertyPriority>(state, matchResult.authorRules(), false, applyInheritedOnly);
applyMatchedProperties<LowPropertyPriority>(state, matchResult, true, matchResult.beginAuthor(), matchResult.endAuthor(), applyInheritedOnly); for (auto range : ImportantAuthorRanges(matchResult))
applyMatchedProperties<LowPropertyPriority>(state, matchResult, true, matchResult.beginUA(), matchResult.endUA(), applyInheritedOnly); applyMatchedProperties<LowPropertyPriority>(state, range, true, applyInheritedOnly);
applyMatchedProperties<LowPropertyPriority>(state, matchResult.uaRules(), true, applyInheritedOnly);
loadPendingResources(state); loadPendingResources(state);
if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, *state.style(), *state.parentStyle())) { if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, *state.style(), *state.parentStyle())) {
INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded, 1); INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded, 1);
m_matchedPropertiesCache.add(*state.style(), *state.parentStyle(), cacheHash, matchResult); m_matchedPropertiesCache.add(*state.style(), *state.parentStyle(), cacheHash, matchResult.matchedProperties());
} }
ASSERT(!state.fontBuilder().fontDirty()); ASSERT(!state.fontBuilder().fontDirty());
......
...@@ -211,7 +211,7 @@ private: ...@@ -211,7 +211,7 @@ private:
void applyCallbackSelectors(StyleResolverState&); void applyCallbackSelectors(StyleResolverState&);
template <CSSPropertyPriority priority> template <CSSPropertyPriority priority>
void applyMatchedProperties(StyleResolverState&, const MatchResult&, bool important, unsigned startIndex, unsigned endIndex, bool inheritedOnly); void applyMatchedProperties(StyleResolverState&, const MatchedPropertiesRange&, bool important, bool inheritedOnly);
template <CSSPropertyPriority priority> template <CSSPropertyPriority priority>
void applyProperties(StyleResolverState&, const StylePropertySet* properties, bool isImportant, bool inheritedOnly, PropertyWhitelistType = PropertyWhitelistNone); void applyProperties(StyleResolverState&, const StylePropertySet* properties, bool isImportant, bool inheritedOnly, PropertyWhitelistType = PropertyWhitelistNone);
template <CSSPropertyPriority priority> template <CSSPropertyPriority priority>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment