diff --git a/dom/base/ChildIterator.cpp b/dom/base/ChildIterator.cpp index 1929a05d1b3e..058e4b4aa450 100644 --- a/dom/base/ChildIterator.cpp +++ b/dom/base/ChildIterator.cpp @@ -124,6 +124,7 @@ void FlattenedChildIterator::Init(bool aIgnoreXBL) { if (aIgnoreXBL) { + mXBLInvolved = Some(false); return; } @@ -132,7 +133,7 @@ FlattenedChildIterator::Init(bool aIgnoreXBL) if (mParent->IsElement()) { if (ShadowRoot* shadow = mParent->AsElement()->GetShadowRoot()) { mParent = shadow; - mXBLInvolved = true; + mXBLInvolved = Some(true); return; } } @@ -143,25 +144,31 @@ FlattenedChildIterator::Init(bool aIgnoreXBL) if (binding) { MOZ_ASSERT(binding->GetAnonymousContent()); mParent = binding->GetAnonymousContent(); - mXBLInvolved = true; + mXBLInvolved = Some(true); + } +} + +bool +FlattenedChildIterator::ComputeWhetherXBLIsInvolved() const +{ + MOZ_ASSERT(mXBLInvolved.isNothing()); + // We set mXBLInvolved to true if either the node we're iterating has a + // binding with content attached to it (in which case it is handled in Init), + // or the node is generated XBL content and has an child. + if (!mParent->GetBindingParent()) { + return false; } - // We set mXBLInvolved to true if either: - // - The node we're iterating has a binding with content attached to it. - // - The node is generated XBL content and has an child. - // - // FIXME(emilio): This is very slow :( - if (!mXBLInvolved && mParent->GetBindingParent()) { - for (nsIContent* child = mParent->GetFirstChild(); - child; - child = child->GetNextSibling()) { - if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { - MOZ_ASSERT(child->GetBindingParent()); - mXBLInvolved = true; - break; - } + for (nsIContent* child = mParent->GetFirstChild(); + child; + child = child->GetNextSibling()) { + if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { + MOZ_ASSERT(child->GetBindingParent()); + return true; } } + + return false; } bool diff --git a/dom/base/ChildIterator.h b/dom/base/ChildIterator.h index 2b20b4e12e71..be95b8a54eee 100644 --- a/dom/base/ChildIterator.h +++ b/dom/base/ChildIterator.h @@ -134,7 +134,6 @@ public: explicit FlattenedChildIterator(const nsIContent* aParent, bool aStartAtBeginning = true) : ExplicitChildIterator(aParent, aStartAtBeginning) - , mXBLInvolved(false) , mOriginalContent(aParent) { Init(false); @@ -142,20 +141,30 @@ public: FlattenedChildIterator(FlattenedChildIterator&& aOther) : ExplicitChildIterator(Move(aOther)) - , mXBLInvolved(aOther.mXBLInvolved) , mOriginalContent(aOther.mOriginalContent) + , mXBLInvolved(aOther.mXBLInvolved) {} FlattenedChildIterator(const FlattenedChildIterator& aOther) : ExplicitChildIterator(aOther) - , mXBLInvolved(aOther.mXBLInvolved) , mOriginalContent(aOther.mOriginalContent) + , mXBLInvolved(aOther.mXBLInvolved) {} - bool XBLInvolved() { return mXBLInvolved; } + bool XBLInvolved() { + if (mXBLInvolved.isNothing()) { + mXBLInvolved = Some(ComputeWhetherXBLIsInvolved()); + } + return *mXBLInvolved; + } const nsIContent* Parent() const { return mOriginalContent; } +private: + bool ComputeWhetherXBLIsInvolved() const; + + void Init(bool aIgnoreXBL); + protected: /** * This constructor is a hack to help AllChildrenIterator which sometimes @@ -164,20 +173,20 @@ protected: FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags, bool aStartAtBeginning = true) : ExplicitChildIterator(aParent, aStartAtBeginning) - , mXBLInvolved(false) , mOriginalContent(aParent) { bool ignoreXBL = aFlags & nsIContent::eAllButXBL; Init(ignoreXBL); } - void Init(bool aIgnoreXBL); - - // For certain optimizations, nsCSSFrameConstructor needs to know if the - // child list of the element that we're iterating matches its .childNodes. - bool mXBLInvolved; - const nsIContent* mOriginalContent; + +private: + // For certain optimizations, nsCSSFrameConstructor needs to know if the child + // list of the element that we're iterating matches its .childNodes. + // + // This is lazily computed when asked for it. + Maybe mXBLInvolved; }; /**