Skip to content

Instantly share code, notes, and snippets.

@Constellation
Created October 26, 2014 17:25
Show Gist options
  • Select an option

  • Save Constellation/8a1995829e2c7ed65abb to your computer and use it in GitHub Desktop.

Select an option

Save Constellation/8a1995829e2c7ed65abb to your computer and use it in GitHub Desktop.
diff --git a/Source/WebCore/css/SelectorChecker.cpp b/Source/WebCore/css/SelectorChecker.cpp
index c4d461c..4a0e550 100644
--- a/Source/WebCore/css/SelectorChecker.cpp
+++ b/Source/WebCore/css/SelectorChecker.cpp
@@ -171,14 +171,14 @@ static inline int countElementsOfTypeAfter(const Element* element, const Qualifi
bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext) const
{
CheckingContextWithStatus context(providedContext, selector, element);
- PseudoId pseudoId = NOPSEUDO;
- if (matchRecursively(context, pseudoId) != SelectorMatches)
+ PseudoIdSet pseudoIdSet = NOPSEUDO;
+ if (matchRecursively(context, pseudoIdSet) != SelectorMatches)
return false;
- if (context.pseudoId != NOPSEUDO && context.pseudoId != pseudoId)
+ if (context.pseudoId != NOPSEUDO && !(pseudoIdSet & (1 << context.pseudoId)))
return false;
- if (context.pseudoId == NOPSEUDO && pseudoId != NOPSEUDO) {
- if (context.resolvingMode == Mode::ResolvingStyle && pseudoId < FIRST_INTERNAL_PSEUDOID)
- context.elementStyle->setHasPseudoStyle(pseudoId);
+ if (context.pseudoId == NOPSEUDO && pseudoIdSet != NOPSEUDO) {
+ if (context.resolvingMode == Mode::ResolvingStyle && pseudoIdSet & PUBLIC_PSEUDOID_MASK)
+ context.elementStyle->setHasPseudoStyles(pseudoIdSet);
// When ignoring virtual pseudo elements, the context's pseudo should also be NOPSEUDO but that does
// not cause a failure.
@@ -187,20 +187,21 @@ bool SelectorChecker::match(const CSSSelector* selector, Element* element, const
return true;
}
-inline static bool hasScrollbarPseudoElement(PseudoId& dynamicPseudo)
+inline static bool hasScrollbarPseudoElement(const PseudoIdSet& dynamicPseudoIdSet)
{
- if (dynamicPseudo == SCROLLBAR
- || dynamicPseudo == SCROLLBAR_THUMB
- || dynamicPseudo == SCROLLBAR_BUTTON
- || dynamicPseudo == SCROLLBAR_TRACK
- || dynamicPseudo == SCROLLBAR_TRACK_PIECE
- || dynamicPseudo == SCROLLBAR_CORNER) {
+ if (dynamicPseudoIdSet &
+ ((1 << SCROLLBAR) |
+ (1 << SCROLLBAR_THUMB) |
+ (1 << SCROLLBAR_BUTTON) |
+ (1 << SCROLLBAR_TRACK) |
+ (1 << SCROLLBAR_TRACK_PIECE) |
+ (1 << SCROLLBAR_CORNER))) {
return true;
}
// RESIZER does not always have a scrollbar but it is a scrollbar-like pseudo element
// because it can have more than one pseudo element.
- return dynamicPseudo == RESIZER;
+ return dynamicPseudoIdSet & (1 << RESIZER);
}
static SelectorChecker::CheckingContextWithStatus checkingContextForParent(const SelectorChecker::CheckingContextWithStatus& context)
@@ -219,7 +220,7 @@ static SelectorChecker::CheckingContextWithStatus checkingContextForParent(const
// * SelectorFailsLocally - the selector fails for the element e
// * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
// * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
-SelectorChecker::Match SelectorChecker::matchRecursively(const CheckingContextWithStatus& context, PseudoId& dynamicPseudo) const
+SelectorChecker::Match SelectorChecker::matchRecursively(const CheckingContextWithStatus& context, PseudoIdSet& dynamicPseudoIdSet) const
{
// The first selector has to match.
if (!checkOne(context))
@@ -246,7 +247,7 @@ static SelectorChecker::CheckingContextWithStatus checkingContextForParent(const
PseudoId pseudoId = CSSSelector::pseudoId(context.selector->pseudoElementType());
if (pseudoId != NOPSEUDO)
- dynamicPseudo = pseudoId;
+ dynamicPseudoIdSet |= (1 << pseudoId);
}
}
@@ -261,10 +262,10 @@ static SelectorChecker::CheckingContextWithStatus checkingContextForParent(const
CheckingContextWithStatus nextContext(context);
nextContext.selector = historySelector;
- PseudoId ignoreDynamicPseudo = NOPSEUDO;
+ PseudoIdSet ignoreDynamicPseudo = NOPSEUDO;
if (relation != CSSSelector::SubSelector) {
// Bail-out if this selector is irrelevant for the pseudoId
- if (context.pseudoId != NOPSEUDO && context.pseudoId != dynamicPseudo)
+ if (context.pseudoId != NOPSEUDO && !((1 << context.pseudoId) & dynamicPseudoIdSet))
return SelectorFailsCompletely;
// Disable :visited matching when we try to match anything else than an ancestors.
@@ -334,13 +335,13 @@ static SelectorChecker::CheckingContextWithStatus checkingContextForParent(const
// a selector is invalid if something follows a pseudo-element
// We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
// to follow the pseudo elements.
- nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudo);
- nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION;
- if ((context.elementStyle || context.resolvingMode == Mode::CollectingRules) && dynamicPseudo != NOPSEUDO
+ nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudoIdSet);
+ nextContext.hasSelectionPseudo = dynamicPseudoIdSet & (1 << SELECTION);
+ if ((context.elementStyle || context.resolvingMode == Mode::CollectingRules) && dynamicPseudoIdSet != NOPSEUDO
&& !nextContext.hasSelectionPseudo
&& !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass))
return SelectorFailsCompletely;
- return matchRecursively(nextContext, dynamicPseudo);
+ return matchRecursively(nextContext, dynamicPseudoIdSet);
case CSSSelector::ShadowDescendant:
{
@@ -534,7 +535,7 @@ bool SelectorChecker::checkOne(const CheckingContextWithStatus& context) const
subcontext.firstSelectorOfTheFragment = selectorList->first();
#if ENABLE(CSS_SELECTORS_LEVEL4)
- PseudoId ignoreDynamicPseudo = NOPSEUDO;
+ PseudoIdSet ignoreDynamicPseudo = NOPSEUDO;
if (matchRecursively(subcontext, ignoreDynamicPseudo) == SelectorMatches) {
ASSERT(ignoreDynamicPseudo == NOPSEUDO);
return false;
@@ -770,7 +771,7 @@ bool SelectorChecker::checkOne(const CheckingContextWithStatus& context) const
{
CheckingContextWithStatus subContext(context);
subContext.inFunctionalPseudoClass = true;
- PseudoId ignoreDynamicPseudo = NOPSEUDO;
+ PseudoIdSet ignoreDynamicPseudo = NOPSEUDO;
for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
subContext.firstSelectorOfTheFragment = subContext.selector;
if (matchRecursively(subContext, ignoreDynamicPseudo) == SelectorMatches)
@@ -915,7 +916,7 @@ bool SelectorChecker::checkOne(const CheckingContextWithStatus& context) const
if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementCue) {
CheckingContextWithStatus subContext(context);
- PseudoId ignoreDynamicPseudo = NOPSEUDO;
+ PseudoIdSet ignoreDynamicPseudo = NOPSEUDO;
const CSSSelector* const & selector = context.selector;
for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
subContext.firstSelectorOfTheFragment = subContext.selector;
@@ -938,7 +939,7 @@ bool SelectorChecker::matchSelectorList(const CheckingContextWithStatus& baseCon
subcontext.selector = subselector;
subcontext.inFunctionalPseudoClass = true;
subcontext.firstSelectorOfTheFragment = subselector;
- PseudoId ignoreDynamicPseudo = NOPSEUDO;
+ PseudoIdSet ignoreDynamicPseudo = NOPSEUDO;
if (matchRecursively(subcontext, ignoreDynamicPseudo) == SelectorMatches) {
ASSERT(ignoreDynamicPseudo == NOPSEUDO);
return true;
diff --git a/Source/WebCore/css/SelectorChecker.h b/Source/WebCore/css/SelectorChecker.h
index 655b195..54ee943 100644
--- a/Source/WebCore/css/SelectorChecker.h
+++ b/Source/WebCore/css/SelectorChecker.h
@@ -83,7 +83,7 @@ class SelectorChecker {
static unsigned determineLinkMatchType(const CSSSelector*);
private:
- Match matchRecursively(const CheckingContextWithStatus&, PseudoId&) const;
+ Match matchRecursively(const CheckingContextWithStatus&, PseudoIdSet&) const;
bool checkOne(const CheckingContextWithStatus&) const;
bool matchSelectorList(const CheckingContextWithStatus&, Element&, const CSSSelectorList&) const;
diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h
index 9863950..ff3f18a 100644
--- a/Source/WebCore/rendering/style/RenderStyle.h
+++ b/Source/WebCore/rendering/style/RenderStyle.h
@@ -234,6 +234,13 @@ class RenderStyle: public RefCounted<RenderStyle> {
ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
m_flags |= oneBitMask << (pseudoBitsOffset - 1 + pseudo);
}
+ void setHasPseudoStyles(PseudoIdSet pseudo)
+ {
+ ASSERT(pseudo != NOPSEUDO);
+ ASSERT((pseudo & PUBLIC_PSEUDOID_MASK) == pseudo);
+ static_assert(pseudoBitsOffset >= 1, "(pseudoBitsOffset - 1) should be valid.");
+ m_flags |= (static_cast<uint64_t>(pseudo) << (pseudoBitsOffset - 1));
+ }
ETableLayout tableLayout() const { return static_cast<ETableLayout>(getValue(tableLayoutBitMask, tableLayoutOffset)); }
void setTableLayout(ETableLayout tableLayout) { updateValue(tableLayout, tableLayoutBitMask, tableLayoutOffset); }
@@ -561,6 +568,7 @@ class RenderStyle: public RefCounted<RenderStyle> {
bool hasAnyPublicPseudoStyles() const;
bool hasPseudoStyle(PseudoId pseudo) const;
void setHasPseudoStyle(PseudoId pseudo);
+ void setHasPseudoStyles(PseudoIdSet pseudo);
bool hasUniquePseudoStyle() const;
// attribute getter methods
@@ -2155,6 +2163,11 @@ inline void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
noninherited_flags.setHasPseudoStyle(pseudo);
}
+inline void RenderStyle::setHasPseudoStyles(PseudoIdSet pseudo)
+{
+ noninherited_flags.setHasPseudoStyles(pseudo);
+}
+
} // namespace WebCore
#endif // RenderStyle_h
diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h
index 2a4aef5..6884901 100644
--- a/Source/WebCore/rendering/style/RenderStyleConstants.h
+++ b/Source/WebCore/rendering/style/RenderStyleConstants.h
@@ -80,6 +80,8 @@ enum PseudoId : unsigned char {
PUBLIC_PSEUDOID_MASK = ((1 << FIRST_INTERNAL_PSEUDOID) - 1) & ~((1 << FIRST_PUBLIC_PSEUDOID) - 1)
};
+typedef unsigned PseudoIdSet;
+
enum ColumnFill { ColumnFillBalance, ColumnFillAuto };
enum ColumnSpan { ColumnSpanNone = 0, ColumnSpanAll };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment