--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -170,24 +170,21 @@ enum {
NODE_DESCENDANTS_NEED_FRAMES = 0x00010000U,
// Set if the node has the accesskey attribute set.
NODE_HAS_ACCESSKEY = 0x00020000U,
// Set if the node is handling a click.
NODE_HANDLING_CLICK = 0x00040000U,
- // Set if the node has had :hover selectors matched against it
- NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
-
// Two bits for the script-type ID. Not enough to represent all
// nsIProgrammingLanguage values, but we don't care. In practice,
// we can represent the ones we want, and we can fail the others at
// runtime.
- NODE_SCRIPT_TYPE_OFFSET = 20,
+ NODE_SCRIPT_TYPE_OFFSET = 19,
NODE_SCRIPT_TYPE_SIZE = 2,
NODE_SCRIPT_TYPE_MASK = (1 << NODE_SCRIPT_TYPE_SIZE) - 1,
// Remaining bits are node type specific.
NODE_TYPE_SPECIFIC_BITS_OFFSET =
NODE_SCRIPT_TYPE_OFFSET + NODE_SCRIPT_TYPE_SIZE
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2308,19 +2308,16 @@ nsCSSFrameConstructor::ConstructDocEleme
PropagateScrollToViewport();
SetUpDocElementContainingBlock(aDocElement);
NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
nsFrameConstructorState state(mPresShell, mFixedContainingBlock, nsnull,
nsnull, aFrameState);
- // Initialize the ancestor filter with null for now; we'll push
- // aDocElement once we finish resolving style for it.
- state.mTreeMatchContext.mAncestorFilter.Init(nsnull);
// XXXbz why, exactly?
if (!mTempFrameTreeState)
state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
// Make sure that we'll handle restyles for this document element in
// the future. We need this, because the document element might
// have stale restyle bits from a previous frame constructor for
@@ -2377,19 +2374,16 @@ nsCSSFrameConstructor::ConstructDocEleme
"Scrollbars should have been propagated to the viewport");
#endif
if (NS_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) {
SetUndisplayedContent(aDocElement, styleContext);
return NS_OK;
}
- AncestorFilter::AutoAncestorPusher
- ancestorPusher(true, state.mTreeMatchContext.mAncestorFilter, aDocElement);
-
// Make sure to start any background image loads for the root element now.
styleContext->StartBackgroundImageLoads();
nsFrameConstructorSaveState absoluteSaveState;
if (mHasRootAbsPosContainingBlock) {
// Push the absolute containing block now so we can absolutely position
// the root element
state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
@@ -3599,43 +3593,31 @@ nsCSSFrameConstructor::ConstructFrameFro
if (aState.mCreatingExtraFrames && aItem.mContent->IsHTML() &&
aItem.mContent->Tag() == nsGkAtoms::iframe)
{
return NS_OK;
}
nsStyleContext* const styleContext = aItem.mStyleContext;
const nsStyleDisplay* display = styleContext->GetStyleDisplay();
- nsIContent* const content = aItem.mContent;
-
- // Push the content as a style ancestor now, so we don't have to do
- // it in our various full-constructor functions. In particular,
- // since a number of full-constructor functions don't actually call
- // ProcessChildren in some cases (e.g. for CSS anonymous table boxes
- // or for situations where only anonymouse children are having
- // frames constructed), this is the best place to bottleneck the
- // pushing of the content instead of having to do it in multiple
- // places.
- AncestorFilter::AutoAncestorPusher
- ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
- aState.mTreeMatchContext.mAncestorFilter,
- content->IsElement() ? content->AsElement() : nsnull);
nsIFrame* newFrame;
nsIFrame* primaryFrame;
if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
nsresult rv =
(this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
display, aFrameItems, &newFrame);
if (NS_FAILED(rv)) {
return rv;
}
primaryFrame = newFrame;
} else {
+ nsIContent* const content = aItem.mContent;
+
newFrame =
(*data->mFunc.mCreationFunc)(mPresShell, styleContext);
if (!newFrame) {
return NS_ERROR_OUT_OF_MEMORY;
}
bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
bool isPopup = aItem.mIsPopup;
@@ -3836,20 +3818,16 @@ nsCSSFrameConstructor::CreateAnonymousFr
PRUint32 count = newAnonymousItems.Length();
if (count == 0) {
return NS_OK;
}
nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
aPendingBinding);
- AncestorFilter::AutoAncestorPusher
- ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
- aState.mTreeMatchContext.mAncestorFilter,
- aParent->AsElement());
nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
NS_ASSERTION(creator,
"How can that happen if we have nodes to construct frames for?");
for (PRUint32 i=0; i < count; i++) {
nsIContent* content = newAnonymousItems[i].mContent;
NS_ASSERTION(content, "null anonymous content?");
@@ -6528,17 +6506,16 @@ nsCSSFrameConstructor::ContentAppended(n
::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
aContainer, parentFrame,
&parentAfterFrame);
// Create some new frames
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(parentFrame),
GetFloatContainingBlock(parentFrame));
- state.mTreeMatchContext.mAncestorFilter.Init(aContainer->AsElement());
// See if the containing block has :first-letter style applied.
bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
if (containingBlock) {
haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
haveFirstLineStyle =
ShouldHaveFirstLineStyle(containingBlock->GetContent(),
@@ -6956,19 +6933,17 @@ nsCSSFrameConstructor::ContentRangeInser
LAYOUT_PHASE_TEMP_REENTER();
return rv;
}
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(parentFrame),
GetFloatContainingBlock(parentFrame),
aFrameState);
- state.mTreeMatchContext.mAncestorFilter.Init(aContainer ?
- aContainer->AsElement() :
- nsnull);
+
// Recover state for the containing block - we need to know if
// it has :first-letter or :first-line style applied to it. The
// reason we care is that the internal structure in these cases
// is not the normal structure and requires custom updating
// logic.
nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
bool haveFirstLetterStyle = false;
@@ -8080,24 +8055,18 @@ nsCSSFrameConstructor::ContentStateChang
}
}
}
}
primaryFrame->ContentStatesChanged(aStateMask);
}
- if (aStateMask.HasState(NS_EVENT_STATE_HOVER) &&
- !aElement->HasFlag(NODE_HAS_RELEVANT_HOVER_RULES)) {
- aStateMask &= ~NS_EVENT_STATE_HOVER;
- }
-
- nsRestyleHint rshint = aStateMask.IsEmpty() ?
- nsRestyleHint(0) :
- styleSet->HasStateDependentStyle(presContext, aElement, aStateMask);
+ nsRestyleHint rshint =
+ styleSet->HasStateDependentStyle(presContext, aElement, aStateMask);
if (aStateMask.HasState(NS_EVENT_STATE_HOVER) && rshint != 0) {
++mHoverGeneration;
}
if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
// Exposing information to the page about whether the link is
// visited or not isn't really something we can worry about here.
@@ -8684,21 +8653,16 @@ nsCSSFrameConstructor::ReplicateFixedFra
// This should not normally be possible (because fixed-pos elements should
// be absolute containers) but fixed-pos tables currently aren't abs-pos
// containers.
nsFrameConstructorState state(mPresShell, aParentFrame,
nsnull,
mRootElementFrame);
state.mCreatingExtraFrames = true;
- // We can't use an ancestor filter here, because we're not going to
- // be usefully recurring down the tree. This means that other
- // places in frame construction can't assume a filter is
- // initialized!
-
// Iterate across fixed frames and replicate each whose placeholder is a
// descendant of aFrame. (We don't want to explicitly copy placeholders that
// are within fixed frames, because that would cause duplicates on the new
// page - bug 389619)
for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed);
if (prevPlaceholder &&
nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
@@ -10515,19 +10479,16 @@ nsCSSFrameConstructor::CreateListBoxCont
// Construct a new frame
if (nsnull != aParentFrame) {
nsFrameItems frameItems;
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(aParentFrame),
GetFloatContainingBlock(aParentFrame),
mTempFrameTreeState);
- // If we ever initialize the ancestor filter on |state|, make sure
- // to push the right parent!
-
nsRefPtr<nsStyleContext> styleContext;
styleContext = ResolveStyleContext(aParentFrame, aChild, &state);
// Pre-check for display "none" - only if we find that, do we create
// any frame at all
const nsStyleDisplay* display = styleContext->GetStyleDisplay();
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
@@ -10862,22 +10823,16 @@ nsCSSFrameConstructor::BuildInlineChildI
// XXXbz should we preallocate aParentItem.mChildItems to some sane
// length? Maybe even to parentContent->GetChildCount()?
nsFrameConstructorState::PendingBindingAutoPusher
pusher(aState, aParentItem.mPendingBinding);
// Probe for generated content before
nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
nsIContent* const parentContent = aParentItem.mContent;
-
- AncestorFilter::AutoAncestorPusher
- ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
- aState.mTreeMatchContext.mAncestorFilter,
- parentContent->AsElement());
-
CreateGeneratedContentItem(aState, nsnull, parentContent, parentStyleContext,
nsCSSPseudoElements::ePseudo_before,
aParentItem.mChildItems);
ChildIterator iter, last;
for (ChildIterator::Init(parentContent, &iter, &last);
iter != last;
++iter) {
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -1136,21 +1136,16 @@ nsFrameManager::ReResolveStyleContext(ns
bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
if (!isChild) {
if (providerFrame)
parentContext = providerFrame->GetStyleContext();
else
parentContext = nsnull;
}
else {
- MOZ_ASSERT(providerFrame->GetContent() == aFrame->GetContent(),
- "Postcondition for GetParentStyleContextFrame() violated. "
- "That means we need to add the current element to the "
- "ancestor filter.");
-
// resolve the provider here (before aFrame below).
// assumeDifferenceHint forces the parent's change to be also
// applied to this frame, no matter what
// nsStyleContext::CalcStyleDifference says. CalcStyleDifference
// can't be trusted because it assumes any changes to the parent
// style context provider will be automatically propagated to
// the frame(s) with child style contexts.
@@ -1389,22 +1384,18 @@ nsFrameManager::ReResolveStyleContext(ns
checkUndisplayed = aFrame == mPresShell->FrameConstructor()->
GetDocElementContainingBlock();
undisplayedParent = nsnull;
} else {
checkUndisplayed = !!localContent;
undisplayedParent = localContent;
}
if (checkUndisplayed && mUndisplayedMap) {
- UndisplayedNode* undisplayed =
- mUndisplayedMap->GetFirstNode(undisplayedParent);
- for (AncestorFilter::AutoAncestorPusher
- pushAncestor(undisplayed, aTreeMatchContext.mAncestorFilter,
- undisplayedParent ? undisplayedParent->AsElement()
- : nsnull);
+ for (UndisplayedNode* undisplayed =
+ mUndisplayedMap->GetFirstNode(undisplayedParent);
undisplayed; undisplayed = undisplayed->mNext) {
NS_ASSERTION(undisplayedParent ||
undisplayed->mContent ==
mPresShell->GetDocument()->GetRootElement(),
"undisplayed node child of null must be root");
NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
"Shouldn't have random pseudo style contexts in the "
"undisplayed map");
@@ -1542,22 +1533,17 @@ nsFrameManager::ReResolveStyleContext(ns
// There is no need to waste time crawling into a frame's children on a frame change.
// The act of reconstructing frames will force new style contexts to be resolved on all
// of this frame's descendants anyway, so we want to avoid wasting time processing
// style contexts that we're just going to throw away anyway. - dwh
// now do children
nsIFrame::ChildListIterator lists(aFrame);
- for (AncestorFilter::AutoAncestorPusher
- pushAncestor(!lists.IsDone(),
- aTreeMatchContext.mAncestorFilter,
- content && content->IsElement() ? content->AsElement()
- : nsnull);
- !lists.IsDone(); lists.Next()) {
+ for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame* child = childFrames.get();
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
|| (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
// only do frames that don't have placeholders
if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
// get out of flow frame and recur there
@@ -1658,19 +1644,18 @@ nsFrameManager::ReResolveStyleContext(ns
void
nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
nsStyleChangeList *aChangeList,
nsChangeHint aMinChange,
RestyleTracker& aRestyleTracker,
bool aRestyleDescendants)
{
- nsIContent *content = aFrame->GetContent();
if (aMinChange) {
- aChangeList->AppendChange(aFrame, content, aMinChange);
+ aChangeList->AppendChange(aFrame, aFrame->GetContent(), aMinChange);
}
nsChangeHint topLevelChange = aMinChange;
nsIFrame* frame = aFrame;
nsIFrame* frame2 = aFrame;
NS_ASSERTION(!frame->GetPrevContinuation(), "must start with the first in flow");
@@ -1679,20 +1664,16 @@ nsFrameManager::ComputeStyleChangeFor(ns
// as well as all its special siblings and their next-in-flows,
// reresolving style on all the frames we encounter in this walk.
FramePropertyTable *propTable = GetPresContext()->PropertyTable();
TreeMatchContext treeMatchContext(true,
nsRuleWalker::eRelevantLinkUnvisited,
mPresShell->GetDocument());
- nsIContent *parent = content ? content->GetParent() : nsnull;
- Element *parentElement =
- parent && parent->IsElement() ? parent->AsElement() : nsnull;
- treeMatchContext.mAncestorFilter.Init(parentElement);
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
do {
// Outer loop over special siblings
do {
// Inner loop over next-in-flows of the current frame
nsChangeHint frameChange =
ReResolveStyleContext(GetPresContext(), frame, nsnull,
aChangeList, topLevelChange,
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2419,19 +2419,18 @@ public:
#ifdef ACCESSIBILITY
virtual already_AddRefed<nsAccessible> CreateAccessible() = 0;
#endif
/**
* Get the frame whose style context should be the parent of this
* frame's style context (i.e., provide the parent style context).
* This frame must either be an ancestor of this frame or a child. If
- * this returns a child frame, then the child frame must be sure to
- * return a grandparent or higher! Furthermore, if a child frame is
- * returned it must have the same GetContent() as this frame.
+ * this frame returns a child frame, then the child frame must be sure
+ * to return a grandparent or higher!
*
* @return The frame whose style context should be the parent of this frame's
* style context. Null is permitted, and means that this frame's
* style context should be the root of the style context tree.
*/
virtual nsIFrame* GetParentStyleContextFrame() const = 0;
/**
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -119,90 +119,27 @@ struct RuleSelectorPair {
: mRule(aRule), mSelector(aSelector) {}
// If this class ever grows a destructor, deal with
// PerWeightDataListItem appropriately.
css::StyleRule* mRule;
nsCSSSelector* mSelector; // which of |mRule|'s selectors
};
-#define NS_IS_ANCESTOR_OPERATOR(ch) \
- ((ch) == PRUnichar(' ') || (ch) == PRUnichar('>'))
-
/**
* A struct representing a particular rule in an ordered list of rules
* (the ordering depending on the weight of mSelector and the order of
* our rules to start with).
*/
struct RuleValue : RuleSelectorPair {
- enum {
- eMaxAncestorHashes = 4
- };
-
RuleValue(const RuleSelectorPair& aRuleSelectorPair, PRInt32 aIndex) :
RuleSelectorPair(aRuleSelectorPair),
mIndex(aIndex)
- {
- CollectAncestorHashes();
- }
-
+ {}
PRInt32 mIndex; // High index means high weight/order.
- uint32_t mAncestorSelectorHashes[eMaxAncestorHashes];
-
-private:
- void CollectAncestorHashes() {
- // Collect up our mAncestorSelectorHashes. It's not clear whether it's
- // better to stop once we've found eMaxAncestorHashes of them or to keep
- // going and preferentially collect information from selectors higher up the
- // chain... Let's do the former for now.
- size_t hashIndex = 0;
- for (nsCSSSelector* sel = mSelector->mNext; sel; sel = sel->mNext) {
- if (!NS_IS_ANCESTOR_OPERATOR(sel->mOperator)) {
- // |sel| is going to select something that's not actually one of our
- // ancestors, so don't add it to mAncestorSelectorHashes. But keep
- // going, because it'll select a sibling of one of our ancestors, so its
- // ancestors would be our ancestors too.
- continue;
- }
-
- // Now sel is supposed to select one of our ancestors. Grab whatever info
- // we can from it into mAncestorSelectorHashes.
- nsAtomList* ids = sel->mIDList;
- while (ids) {
- mAncestorSelectorHashes[hashIndex++] = ids->mAtom->hash();
- if (hashIndex == eMaxAncestorHashes) {
- return;
- }
- ids = ids->mNext;
- }
-
- nsAtomList* classes = sel->mClassList;
- while (classes) {
- mAncestorSelectorHashes[hashIndex++] = classes->mAtom->hash();
- if (hashIndex == eMaxAncestorHashes) {
- return;
- }
- classes = classes->mNext;
- }
-
- // Only put in the tag name if it's all-lowercase. Otherwise we run into
- // trouble because we may test the wrong one of mLowercaseTag and
- // mCasedTag against the filter.
- if (sel->mLowercaseTag && sel->mCasedTag == sel->mLowercaseTag) {
- mAncestorSelectorHashes[hashIndex++] = sel->mLowercaseTag->hash();
- if (hashIndex == eMaxAncestorHashes) {
- return;
- }
- }
- }
-
- while (hashIndex != eMaxAncestorHashes) {
- mAncestorSelectorHashes[hashIndex++] = 0;
- }
- }
};
// ------------------------------
// Rule hash table
//
// Uses any of the sets of ops below.
struct RuleHashTableEntry : public PLDHashEntryHdr {
@@ -708,19 +645,18 @@ void RuleHash::AppendRule(const RuleSele
#define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
(var_) += (list_).Length()
#else
#define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
PR_BEGIN_MACRO PR_END_MACRO
#endif
static inline
-void ContentEnumFunc(const RuleValue &value, nsCSSSelector* selector,
- RuleProcessorData* data, NodeMatchContext& nodeContext,
- AncestorFilter *ancestorFilter);
+void ContentEnumFunc(css::StyleRule* aRule, nsCSSSelector* aSelector,
+ RuleProcessorData* data, NodeMatchContext& nodeContext);
void RuleHash::EnumerateAllRules(Element* aElement, RuleProcessorData* aData,
NodeMatchContext& aNodeContext)
{
PRInt32 nameSpace = aElement->GetNameSpaceID();
nsIAtom* tag = aElement->Tag();
nsIAtom* id = aElement->GetID();
const nsAttrValue* classList = aElement->GetClasses();
@@ -781,50 +717,42 @@ void RuleHash::EnumerateAllRules(Element
mEnumList[valueCount++] = ToEnumData(entry->mRules);
RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementClassCalls);
}
}
}
NS_ASSERTION(valueCount <= testCount, "values exceeded list size");
if (valueCount > 0) {
- AncestorFilter *filter =
- aData->mTreeMatchContext.mAncestorFilter.HasFilter() ?
- &aData->mTreeMatchContext.mAncestorFilter : nsnull;
-#ifdef DEBUG
- if (filter) {
- filter->AssertHasAllAncestors(aElement);
- }
-#endif
// Merge the lists while there are still multiple lists to merge.
while (valueCount > 1) {
PRInt32 valueIndex = 0;
PRInt32 lowestRuleIndex = mEnumList[valueIndex].mCurValue->mIndex;
for (PRInt32 index = 1; index < valueCount; ++index) {
PRInt32 ruleIndex = mEnumList[index].mCurValue->mIndex;
if (ruleIndex < lowestRuleIndex) {
valueIndex = index;
lowestRuleIndex = ruleIndex;
}
}
const RuleValue *cur = mEnumList[valueIndex].mCurValue;
- ContentEnumFunc(*cur, cur->mSelector, aData, aNodeContext, filter);
+ ContentEnumFunc(cur->mRule, cur->mSelector, aData, aNodeContext);
cur++;
if (cur == mEnumList[valueIndex].mEnd) {
mEnumList[valueIndex] = mEnumList[--valueCount];
} else {
mEnumList[valueIndex].mCurValue = cur;
}
}
// Fast loop over single value.
for (const RuleValue *value = mEnumList[0].mCurValue,
*end = mEnumList[0].mEnd;
value != end; ++value) {
- ContentEnumFunc(*value, value->mSelector, aData, aNodeContext, filter);
+ ContentEnumFunc(value->mRule, value->mSelector, aData, aNodeContext);
}
}
}
static size_t
SizeOfRuleHashTableEntry(PLDHashEntryHdr* aHdr, nsMallocSizeOfFun aMallocSizeOf, void *)
{
RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(aHdr);
@@ -2109,21 +2037,16 @@ static bool SelectorMatches(Element* aEl
!isNegated &&
// important for |IsQuirkEventSensitive|:
aElement->IsHTML() && !nsCSSRuleProcessor::IsLink(aElement) &&
!IsQuirkEventSensitive(aElement->Tag())) {
// In quirks mode, only make certain elements sensitive to
// selectors ":hover" and ":active".
return false;
} else {
- if (aTreeMatchContext.mForStyling &&
- statesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER)) {
- // Mark the element as having :hover-dependent style
- aElement->SetFlags(NODE_HAS_RELEVANT_HOVER_RULES);
- }
if (aNodeMatchContext.mStateMask.HasAtLeastOneOfStates(statesToCheck)) {
if (aDependence)
*aDependence = true;
} else {
nsEventStates contentState =
nsCSSRuleProcessor::GetContentStateForVisitedHandling(
aElement,
aTreeMatchContext.VisitedHandling(),
@@ -2307,17 +2230,18 @@ static bool SelectorMatchesTree(Element*
// descendant or general sibling combinator and the next
// combinator is different, but we can make an exception for
// sibling, then parent, since a sibling's parent is always the
// same.
if (NS_IS_GREEDY_OPERATOR(selector->mOperator) &&
selector->mNext &&
selector->mNext->mOperator != selector->mOperator &&
!(selector->mOperator == '~' &&
- NS_IS_ANCESTOR_OPERATOR(selector->mNext->mOperator))) {
+ (selector->mNext->mOperator == PRUnichar(' ') ||
+ selector->mNext->mOperator == PRUnichar('>')))) {
// pretend the selector didn't match, and step through content
// while testing the same selector
// This approach is slightly strange in that when it recurs
// it tests from the top of the content tree, down. This
// doesn't matter much for performance since most selectors
// don't match. (If most did, it might be faster...)
@@ -2336,39 +2260,30 @@ static bool SelectorMatchesTree(Element*
}
}
prevElement = element;
}
return true; // all the selectors matched.
}
static inline
-void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector,
- RuleProcessorData* data, NodeMatchContext& nodeContext,
- AncestorFilter *ancestorFilter)
+void ContentEnumFunc(css::StyleRule* aRule, nsCSSSelector* aSelector,
+ RuleProcessorData* data, NodeMatchContext& nodeContext)
{
if (nodeContext.mIsRelevantLink) {
data->mTreeMatchContext.SetHaveRelevantLink();
}
- if (ancestorFilter &&
- !ancestorFilter->MightHaveMatchingAncestor<
- NS_ARRAY_LENGTH(value.mAncestorSelectorHashes)>(
- value.mAncestorSelectorHashes)) {
- // We won't match; nothing else to do here
- return;
- }
if (SelectorMatches(data->mElement, aSelector, nodeContext,
data->mTreeMatchContext)) {
nsCSSSelector *next = aSelector->mNext;
if (!next || SelectorMatchesTree(data->mElement, next,
data->mTreeMatchContext,
!nodeContext.mIsRelevantLink)) {
- css::StyleRule *rule = value.mRule;
- rule->RuleMatched();
- data->mRuleWalker->Forward(rule);
+ aRule->RuleMatched();
+ data->mRuleWalker->Forward(aRule);
// nsStyleSet will deal with the !important rule
}
}
}
/* virtual */ void
nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
{
@@ -2428,18 +2343,18 @@ nsCSSRuleProcessor::RulesMatching(XULTre
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
NodeMatchContext nodeContext(nsEventStates(),
nsCSSRuleProcessor::IsLink(aData->mElement));
nsTArray<RuleValue>& rules = entry->mRules;
for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
value != end; ++value) {
if (aData->mComparator->PseudoMatches(value->mSelector)) {
- ContentEnumFunc(*value, value->mSelector->mNext, aData, nodeContext,
- nsnull);
+ ContentEnumFunc(value->mRule, value->mSelector->mNext, aData,
+ nodeContext);
}
}
}
}
}
#endif
static inline nsRestyleHint RestyleHintForOp(PRUnichar oper)
@@ -3260,104 +3175,8 @@ nsCSSRuleProcessor::SelectorListMatches(
}
}
aSelectorList = aSelectorList->mNext;
}
return false;
}
-
-// AncestorFilter out of line methods
-void
-AncestorFilter::Init(Element *aElement)
-{
- MOZ_ASSERT(!mFilter);
- MOZ_ASSERT(mHashes.IsEmpty());
-
- mFilter = new Filter();
-
- if (NS_LIKELY(aElement)) {
- MOZ_ASSERT(aElement->IsInDoc(),
- "aElement must be in the document for the assumption that "
- "GetNodeParent() is non-null on all element ancestors of "
- "aElement to be true");
- // Collect up the ancestors
- nsAutoTArray<Element*, 50> ancestors;
- Element* cur = aElement;
- do {
- ancestors.AppendElement(cur);
- nsINode* parent = cur->GetNodeParent();
- if (!parent->IsElement()) {
- break;
- }
- cur = parent->AsElement();
- } while (true);
-
- // Now push them in reverse order.
- for (PRUint32 i = ancestors.Length(); i-- != 0; ) {
- PushAncestor(ancestors[i]);
- }
- }
-}
-
-void
-AncestorFilter::PushAncestor(Element *aElement)
-{
- MOZ_ASSERT(mFilter);
-
- PRUint32 oldLength = mHashes.Length();
-
- mPopTargets.AppendElement(oldLength);
-#ifdef DEBUG
- mElements.AppendElement(aElement);
-#endif
- mHashes.AppendElement(aElement->Tag()->hash());
- nsIAtom *id = aElement->GetID();
- if (id) {
- mHashes.AppendElement(id->hash());
- }
- const nsAttrValue *classes = aElement->GetClasses();
- if (classes) {
- PRUint32 classCount = classes->GetAtomCount();
- for (PRUint32 i = 0; i < classCount; ++i) {
- mHashes.AppendElement(classes->AtomAt(i)->hash());
- }
- }
-
- PRUint32 newLength = mHashes.Length();
- for (PRUint32 i = oldLength; i < newLength; ++i) {
- mFilter->add(mHashes[i]);
- }
-}
-
-void
-AncestorFilter::PopAncestor()
-{
- MOZ_ASSERT(!mPopTargets.IsEmpty());
- MOZ_ASSERT(mPopTargets.Length() == mElements.Length());
-
- PRUint32 popTargetLength = mPopTargets.Length();
- PRUint32 newLength = mPopTargets[popTargetLength-1];
-
- mPopTargets.TruncateLength(popTargetLength-1);
-#ifdef DEBUG
- mElements.TruncateLength(popTargetLength-1);
-#endif
-
- PRUint32 oldLength = mHashes.Length();
- for (PRUint32 i = newLength; i < oldLength; ++i) {
- mFilter->remove(mHashes[i]);
- }
- mHashes.TruncateLength(newLength);
-}
-
-#ifdef DEBUG
-void
-AncestorFilter::AssertHasAllAncestors(Element *aElement) const
-{
- nsINode* cur = aElement->GetNodeParent();
- while (cur && cur->IsElement()) {
- MOZ_ASSERT(mElements.Contains(cur));
- cur = cur->GetNodeParent();
- }
-}
-#endif
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -46,113 +46,23 @@
#include "nsPresContext.h" // for nsCompatibility
#include "nsString.h"
#include "nsChangeHint.h"
#include "nsIContent.h"
#include "nsCSSPseudoElements.h"
#include "nsRuleWalker.h"
#include "nsNthIndexCache.h"
-#include "mozilla/BloomFilter.h"
-#include "mozilla/GuardObjects.h"
class nsIStyleSheet;
class nsIAtom;
class nsICSSPseudoComparator;
class nsAttrValue;
/**
- * An AncestorFilter is used to keep track of ancestors so that we can
- * quickly tell that a particular selector is not relevant to a given
- * element.
- */
-class NS_STACK_CLASS AncestorFilter {
- public:
- /**
- * Initialize the filter. If aElement is not null, it and all its
- * ancestors will be passed to PushAncestor, starting from the root
- * and going down the tree.
- */
- void Init(mozilla::dom::Element *aElement);
-
- /* Maintenance of our ancestor state */
- void PushAncestor(mozilla::dom::Element *aElement);
- void PopAncestor();
-
- /* Helper class for maintaining the ancestor state */
- class NS_STACK_CLASS AutoAncestorPusher {
- public:
- AutoAncestorPusher(bool aDoPush,
- AncestorFilter &aFilter,
- mozilla::dom::Element *aElement
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mPushed(aDoPush && aElement), mFilter(aFilter)
- {
- MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- if (mPushed) {
- mFilter.PushAncestor(aElement);
- }
- }
- ~AutoAncestorPusher() {
- if (mPushed) {
- mFilter.PopAncestor();
- }
- }
-
- private:
- bool mPushed;
- AncestorFilter &mFilter;
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
- };
-
- /* Check whether we might have an ancestor matching one of the given
- atom hashes. |hashes| must have length hashListLength */
- template<size_t hashListLength>
- bool MightHaveMatchingAncestor(const uint32_t* aHashes) const
- {
- MOZ_ASSERT(mFilter);
- for (size_t i = 0; i < hashListLength && aHashes[i]; ++i) {
- if (!mFilter->mightContain(aHashes[i])) {
- return false;
- }
- }
-
- return true;
- }
-
- bool HasFilter() const { return mFilter; }
-
-#ifdef DEBUG
- void AssertHasAllAncestors(mozilla::dom::Element *aElement) const;
-#endif
-
- private:
- // Using 2^12 slots makes the Bloom filter a nice round page in
- // size, so let's do that. We get a false positive rate of 1% or
- // less even with several hundred things in the filter. Note that
- // we allocate the filter lazily, because not all tree match
- // contexts can use one effectively.
- typedef mozilla::BloomFilter<12, nsIAtom> Filter;
- nsAutoPtr<Filter> mFilter;
-
- // Stack of indices to pop to. These are indices into mHashes.
- nsTArray<PRUint32> mPopTargets;
-
- // List of hashes; this is what we pop using mPopTargets. We store
- // hashes of our ancestor element tag names, ids, and classes in
- // here.
- nsTArray<uint32_t> mHashes;
-
- // A debug-only stack of Elements for use in assertions
-#ifdef DEBUG
- nsTArray<mozilla::dom::Element*> mElements;
-#endif
-};
-
-/**
* A |TreeMatchContext| has data about a matching operation. The
* data are not node-specific but are invariants of the DOM tree the
* nodes being matched against are in.
*
* Most of the members are in parameters to selector matching. The
* one out parameter is mHaveRelevantLink. Consumers that use a
* TreeMatchContext for more than one matching operation and care
* about :visited and mHaveRelevantLink need to
@@ -213,19 +123,16 @@ struct NS_STACK_CLASS TreeMatchContext {
// Possibly remove use of mCompatMode in SelectorMatches?
// XXX XBL2 issue: Should we be caching this? What should it be for XBL2?
const nsCompatibility mCompatMode;
// The nth-index cache we should use
nsNthIndexCache mNthIndexCache;
- // An ancestor filter
- AncestorFilter mAncestorFilter;
-
// Constructor to use when creating a tree match context for styling
TreeMatchContext(bool aForStyling,
nsRuleWalker::VisitedHandlingType aVisitedHandling,
nsIDocument* aDocument)
: mForStyling(aForStyling)
, mHaveRelevantLink(false)
, mVisitedHandling(aVisitedHandling)
, mDocument(aDocument)
--- a/mfbt/BloomFilter.h
+++ b/mfbt/BloomFilter.h
@@ -128,24 +128,24 @@ public:
void remove(const T* t);
/*
* Check whether the filter might contain an item. This can
* sometimes return true even if the item is not in the filter,
* but will never return false for items that are actually in the
* filter.
*/
- bool mightContain(const T* t) const;
+ bool mayContain(const T* t) const;
/*
* Methods for add/remove/contain when we already have a hash computed
*/
void add(uint32_t hash);
void remove(uint32_t hash);
- bool mightContain(uint32_t hash) const;
+ bool mayContain(uint32_t hash) const;
private:
static const size_t arraySize = (1 << KeySize);
static const uint32_t keyMask = (1 << KeySize) - 1;
static const uint32_t keyShift = 16;
static uint32_t hash1(uint32_t hash) { return hash & keyMask; }
static uint32_t hash2(uint32_t hash) { return (hash >> keyShift) & keyMask; }
@@ -208,25 +208,25 @@ MOZ_ALWAYS_INLINE void
BloomFilter<KeySize, T>::remove(const T* t)
{
uint32_t hash = t->hash();
remove(hash);
}
template<unsigned KeySize, class T>
MOZ_ALWAYS_INLINE bool
-BloomFilter<KeySize, T>::mightContain(uint32_t hash) const
+BloomFilter<KeySize, T>::mayContain(uint32_t hash) const
{
// Check that all the slots for this hash contain something
return firstSlot(hash) && secondSlot(hash);
}
template<unsigned KeySize, class T>
MOZ_ALWAYS_INLINE bool
-BloomFilter<KeySize, T>::mightContain(const T* t) const
+BloomFilter<KeySize, T>::mayContain(const T* t) const
{
uint32_t hash = t->hash();
- return mightContain(hash);
+ return mayContain(hash);
}
} // namespace mozilla
#endif /* mozilla_BloomFilter_h_ */
--- a/xpcom/tests/TestBloomFilter.cpp
+++ b/xpcom/tests/TestBloomFilter.cpp
@@ -27,94 +27,94 @@ int main()
BloomFilter<12, FilterChecker> *filter = new BloomFilter<12, FilterChecker>();
FilterChecker one(1);
FilterChecker two(0x20000);
FilterChecker many(0x10000);
FilterChecker multiple(0x20001);
filter->add(&one);
- if (!filter->mightContain(&one)) {
+ if (!filter->mayContain(&one)) {
fail("Filter should contain 'one'");
return -1;
}
- if (filter->mightContain(&multiple)) {
+ if (filter->mayContain(&multiple)) {
fail("Filter claims to contain 'multiple' when it should not");
return -1;
}
- if (!filter->mightContain(&many)) {
+ if (!filter->mayContain(&many)) {
fail("Filter should contain 'many' (false positive)");
return -1;
}
filter->add(&two);
- if (!filter->mightContain(&multiple)) {
+ if (!filter->mayContain(&multiple)) {
fail("Filter should contain 'multiple' (false positive)");
return -1;
}
// Test basic removals
filter->remove(&two);
- if (filter->mightContain(&multiple)) {
+ if (filter->mayContain(&multiple)) {
fail("Filter claims to contain 'multiple' when it should not after two was "
"removed");
return -1;
}
// Test multiple addition/removal
const unsigned FILTER_SIZE = 255;
for (unsigned i = 0; i < FILTER_SIZE - 1; ++i) {
filter->add(&two);
}
- if (!filter->mightContain(&multiple)) {
+ if (!filter->mayContain(&multiple)) {
fail("Filter should contain 'multiple' after 'two' added lots of times "
"(false positive)");
return -1;
}
for (unsigned i = 0; i < FILTER_SIZE - 1; ++i) {
filter->remove(&two);
}
- if (filter->mightContain(&multiple)) {
+ if (filter->mayContain(&multiple)) {
fail("Filter claims to contain 'multiple' when it should not after two was "
"removed lots of times");
return -1;
}
// Test overflowing the filter buckets
for (unsigned i = 0; i < FILTER_SIZE + 1; ++i) {
filter->add(&two);
}
- if (!filter->mightContain(&multiple)) {
+ if (!filter->mayContain(&multiple)) {
fail("Filter should contain 'multiple' after 'two' added lots more times "
"(false positive)");
return -1;
}
for (unsigned i = 0; i < FILTER_SIZE + 1; ++i) {
filter->remove(&two);
}
- if (!filter->mightContain(&multiple)) {
+ if (!filter->mayContain(&multiple)) {
fail("Filter claims to not contain 'multiple' even though we should have "
"run out of space in the buckets (false positive)");
return -1;
}
- if (!filter->mightContain(&two)) {
+ if (!filter->mayContain(&two)) {
fail("Filter claims to not contain 'two' even though we should have run "
"out of space in the buckets (false positive)");
return -1;
}
filter->remove(&one);
- if (filter->mightContain(&one)) {
+ if (filter->mayContain(&one)) {
fail("Filter should not contain 'one', because we didn't overflow its "
"bucket");
return -1;
}
filter->clear();
- if (filter->mightContain(&multiple)) {
+ if (filter->mayContain(&multiple)) {
fail("clear() failed to work");
return -1;
}
return 0;
}