mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 705877 part 3. Hang an optional Bloom filter and some methods for managing it off the TreeMatchContext. r=dbaron
This commit is contained in:
parent
b684c178fb
commit
386bfeacd8
@ -3242,3 +3242,99 @@ nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
|
|||||||
|
|
||||||
return false;
|
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
|
||||||
|
@ -51,12 +51,102 @@
|
|||||||
#include "nsCSSPseudoElements.h"
|
#include "nsCSSPseudoElements.h"
|
||||||
#include "nsRuleWalker.h"
|
#include "nsRuleWalker.h"
|
||||||
#include "nsNthIndexCache.h"
|
#include "nsNthIndexCache.h"
|
||||||
|
#include "mozilla/BloomFilter.h"
|
||||||
|
#include "mozilla/GuardObjects.h"
|
||||||
|
|
||||||
class nsIStyleSheet;
|
class nsIStyleSheet;
|
||||||
class nsIAtom;
|
class nsIAtom;
|
||||||
class nsICSSPseudoComparator;
|
class nsICSSPseudoComparator;
|
||||||
class nsAttrValue;
|
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
|
* A |TreeMatchContext| has data about a matching operation. The
|
||||||
* data are not node-specific but are invariants of the DOM tree the
|
* data are not node-specific but are invariants of the DOM tree the
|
||||||
@ -128,6 +218,9 @@ struct NS_STACK_CLASS TreeMatchContext {
|
|||||||
// The nth-index cache we should use
|
// The nth-index cache we should use
|
||||||
nsNthIndexCache mNthIndexCache;
|
nsNthIndexCache mNthIndexCache;
|
||||||
|
|
||||||
|
// An ancestor filter
|
||||||
|
AncestorFilter mAncestorFilter;
|
||||||
|
|
||||||
// Constructor to use when creating a tree match context for styling
|
// Constructor to use when creating a tree match context for styling
|
||||||
TreeMatchContext(bool aForStyling,
|
TreeMatchContext(bool aForStyling,
|
||||||
nsRuleWalker::VisitedHandlingType aVisitedHandling,
|
nsRuleWalker::VisitedHandlingType aVisitedHandling,
|
||||||
|
Loading…
Reference in New Issue
Block a user