content/base/src/ChildIterator.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 sw=2 et tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "ChildIterator.h"
michael@0 8 #include "nsContentUtils.h"
michael@0 9 #include "mozilla/dom/XBLChildrenElement.h"
michael@0 10 #include "mozilla/dom/HTMLContentElement.h"
michael@0 11 #include "mozilla/dom/HTMLShadowElement.h"
michael@0 12 #include "mozilla/dom/ShadowRoot.h"
michael@0 13
michael@0 14 namespace mozilla {
michael@0 15 namespace dom {
michael@0 16
michael@0 17 class MatchedNodes {
michael@0 18 public:
michael@0 19 MatchedNodes(HTMLContentElement* aInsertionPoint)
michael@0 20 : mIsContentElement(true), mContentElement(aInsertionPoint) {}
michael@0 21
michael@0 22 MatchedNodes(XBLChildrenElement* aInsertionPoint)
michael@0 23 : mIsContentElement(false), mChildrenElement(aInsertionPoint) {}
michael@0 24
michael@0 25 uint32_t Length() const
michael@0 26 {
michael@0 27 return mIsContentElement ? mContentElement->MatchedNodes().Length()
michael@0 28 : mChildrenElement->mInsertedChildren.Length();
michael@0 29 }
michael@0 30
michael@0 31 nsIContent* operator[](int32_t aIndex) const
michael@0 32 {
michael@0 33 return mIsContentElement ? mContentElement->MatchedNodes()[aIndex]
michael@0 34 : mChildrenElement->mInsertedChildren[aIndex];
michael@0 35 }
michael@0 36
michael@0 37 bool IsEmpty() const
michael@0 38 {
michael@0 39 return mIsContentElement ? mContentElement->MatchedNodes().IsEmpty()
michael@0 40 : mChildrenElement->mInsertedChildren.IsEmpty();
michael@0 41 }
michael@0 42 protected:
michael@0 43 bool mIsContentElement;
michael@0 44 union {
michael@0 45 HTMLContentElement* mContentElement;
michael@0 46 XBLChildrenElement* mChildrenElement;
michael@0 47 };
michael@0 48 };
michael@0 49
michael@0 50 static inline MatchedNodes
michael@0 51 GetMatchedNodesForPoint(nsIContent* aContent)
michael@0 52 {
michael@0 53 if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
michael@0 54 // XBL case
michael@0 55 return MatchedNodes(static_cast<XBLChildrenElement*>(aContent));
michael@0 56 }
michael@0 57
michael@0 58 // Web components case
michael@0 59 MOZ_ASSERT(aContent->IsHTML(nsGkAtoms::content));
michael@0 60 return MatchedNodes(static_cast<HTMLContentElement*>(aContent));
michael@0 61 }
michael@0 62
michael@0 63 nsIContent*
michael@0 64 ExplicitChildIterator::GetNextChild()
michael@0 65 {
michael@0 66 // If we're already in the inserted-children array, look there first
michael@0 67 if (mIndexInInserted) {
michael@0 68 MOZ_ASSERT(mChild);
michael@0 69 MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
michael@0 70 MOZ_ASSERT(!mDefaultChild);
michael@0 71
michael@0 72 MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
michael@0 73 if (mIndexInInserted < assignedChildren.Length()) {
michael@0 74 return assignedChildren[mIndexInInserted++];
michael@0 75 }
michael@0 76 mIndexInInserted = 0;
michael@0 77 mChild = mChild->GetNextSibling();
michael@0 78 } else if (mShadowIterator) {
michael@0 79 // If we're inside of a <shadow> element, look through the
michael@0 80 // explicit children of the projected ShadowRoot via
michael@0 81 // the mShadowIterator.
michael@0 82 nsIContent* nextChild = mShadowIterator->GetNextChild();
michael@0 83 if (nextChild) {
michael@0 84 return nextChild;
michael@0 85 }
michael@0 86
michael@0 87 mShadowIterator = nullptr;
michael@0 88 mChild = mChild->GetNextSibling();
michael@0 89 } else if (mDefaultChild) {
michael@0 90 // If we're already in default content, check if there are more nodes there
michael@0 91 MOZ_ASSERT(mChild);
michael@0 92 MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
michael@0 93
michael@0 94 mDefaultChild = mDefaultChild->GetNextSibling();
michael@0 95 if (mDefaultChild) {
michael@0 96 return mDefaultChild;
michael@0 97 }
michael@0 98
michael@0 99 mChild = mChild->GetNextSibling();
michael@0 100 } else if (mIsFirst) { // at the beginning of the child list
michael@0 101 mChild = mParent->GetFirstChild();
michael@0 102 mIsFirst = false;
michael@0 103 } else if (mChild) { // in the middle of the child list
michael@0 104 mChild = mChild->GetNextSibling();
michael@0 105 }
michael@0 106
michael@0 107 // Iterate until we find a non-insertion point, or an insertion point with
michael@0 108 // content.
michael@0 109 while (mChild) {
michael@0 110 // If the current child being iterated is a shadow insertion point then
michael@0 111 // the iterator needs to go into the projected ShadowRoot.
michael@0 112 if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
michael@0 113 // Look for the next child in the projected ShadowRoot for the <shadow>
michael@0 114 // element.
michael@0 115 HTMLShadowElement* shadowElem = static_cast<HTMLShadowElement*>(mChild);
michael@0 116 ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
michael@0 117 if (projectedShadow) {
michael@0 118 mShadowIterator = new ExplicitChildIterator(projectedShadow);
michael@0 119 nsIContent* nextChild = mShadowIterator->GetNextChild();
michael@0 120 if (nextChild) {
michael@0 121 return nextChild;
michael@0 122 }
michael@0 123 mShadowIterator = nullptr;
michael@0 124 }
michael@0 125 mChild = mChild->GetNextSibling();
michael@0 126 } else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
michael@0 127 // If the current child being iterated is a content insertion point
michael@0 128 // then the iterator needs to return the nodes distributed into
michael@0 129 // the content insertion point.
michael@0 130 MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
michael@0 131 if (!assignedChildren.IsEmpty()) {
michael@0 132 // Iterate through elements projected on insertion point.
michael@0 133 mIndexInInserted = 1;
michael@0 134 return assignedChildren[0];
michael@0 135 }
michael@0 136
michael@0 137 // Insertion points inside fallback/default content
michael@0 138 // are considered inactive and do not get assigned nodes.
michael@0 139 mDefaultChild = mChild->GetFirstChild();
michael@0 140 if (mDefaultChild) {
michael@0 141 return mDefaultChild;
michael@0 142 }
michael@0 143
michael@0 144 // If we have an insertion point with no assigned nodes and
michael@0 145 // no default content, move on to the next node.
michael@0 146 mChild = mChild->GetNextSibling();
michael@0 147 } else {
michael@0 148 // mChild is not an insertion point, thus it is the next node to
michael@0 149 // return from this iterator.
michael@0 150 break;
michael@0 151 }
michael@0 152 }
michael@0 153
michael@0 154 return mChild;
michael@0 155 }
michael@0 156
michael@0 157 FlattenedChildIterator::FlattenedChildIterator(nsIContent* aParent)
michael@0 158 : ExplicitChildIterator(aParent), mXBLInvolved(false)
michael@0 159 {
michael@0 160 nsXBLBinding* binding =
michael@0 161 aParent->OwnerDoc()->BindingManager()->GetBindingWithContent(aParent);
michael@0 162
michael@0 163 if (binding) {
michael@0 164 nsIContent* anon = binding->GetAnonymousContent();
michael@0 165 if (anon) {
michael@0 166 mParent = anon;
michael@0 167 mXBLInvolved = true;
michael@0 168 }
michael@0 169 }
michael@0 170
michael@0 171 // We set mXBLInvolved to true if either:
michael@0 172 // - The node we're iterating has a binding with content attached to it.
michael@0 173 // - The node is generated XBL content and has an <xbl:children> child.
michael@0 174 if (!mXBLInvolved && aParent->GetBindingParent()) {
michael@0 175 for (nsIContent* child = aParent->GetFirstChild();
michael@0 176 child;
michael@0 177 child = child->GetNextSibling()) {
michael@0 178 if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
michael@0 179 MOZ_ASSERT(child->GetBindingParent());
michael@0 180 mXBLInvolved = true;
michael@0 181 break;
michael@0 182 }
michael@0 183 }
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 nsIContent*
michael@0 188 ExplicitChildIterator::Get()
michael@0 189 {
michael@0 190 MOZ_ASSERT(!mIsFirst);
michael@0 191
michael@0 192 if (mIndexInInserted) {
michael@0 193 XBLChildrenElement* point = static_cast<XBLChildrenElement*>(mChild);
michael@0 194 return point->mInsertedChildren[mIndexInInserted - 1];
michael@0 195 } else if (mShadowIterator) {
michael@0 196 return mShadowIterator->Get();
michael@0 197 }
michael@0 198 return mDefaultChild ? mDefaultChild : mChild;
michael@0 199 }
michael@0 200
michael@0 201 nsIContent*
michael@0 202 ExplicitChildIterator::GetPreviousChild()
michael@0 203 {
michael@0 204 // If we're already in the inserted-children array, look there first
michael@0 205 if (mIndexInInserted) {
michael@0 206 // NB: mIndexInInserted points one past the last returned child so we need
michael@0 207 // to look *two* indices back in order to return the previous child.
michael@0 208 MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
michael@0 209 if (--mIndexInInserted) {
michael@0 210 return assignedChildren[mIndexInInserted - 1];
michael@0 211 }
michael@0 212 mChild = mChild->GetPreviousSibling();
michael@0 213 } else if (mShadowIterator) {
michael@0 214 nsIContent* previousChild = mShadowIterator->GetPreviousChild();
michael@0 215 if (previousChild) {
michael@0 216 return previousChild;
michael@0 217 }
michael@0 218 mShadowIterator = nullptr;
michael@0 219 mChild = mChild->GetPreviousSibling();
michael@0 220 } else if (mDefaultChild) {
michael@0 221 // If we're already in default content, check if there are more nodes there
michael@0 222 mDefaultChild = mDefaultChild->GetPreviousSibling();
michael@0 223 if (mDefaultChild) {
michael@0 224 return mDefaultChild;
michael@0 225 }
michael@0 226
michael@0 227 mChild = mChild->GetPreviousSibling();
michael@0 228 } else if (mIsFirst) { // at the beginning of the child list
michael@0 229 return nullptr;
michael@0 230 } else if (mChild) { // in the middle of the child list
michael@0 231 mChild = mChild->GetPreviousSibling();
michael@0 232 } else { // at the end of the child list
michael@0 233 mChild = mParent->GetLastChild();
michael@0 234 }
michael@0 235
michael@0 236 // Iterate until we find a non-insertion point, or an insertion point with
michael@0 237 // content.
michael@0 238 while (mChild) {
michael@0 239 if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
michael@0 240 // If the current child being iterated is a shadow insertion point then
michael@0 241 // the iterator needs to go into the projected ShadowRoot.
michael@0 242 HTMLShadowElement* shadowElem = static_cast<HTMLShadowElement*>(mChild);
michael@0 243 ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
michael@0 244 if (projectedShadow) {
michael@0 245 // Create a ExplicitChildIterator that begins iterating from the end.
michael@0 246 mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
michael@0 247 nsIContent* previousChild = mShadowIterator->GetPreviousChild();
michael@0 248 if (previousChild) {
michael@0 249 return previousChild;
michael@0 250 }
michael@0 251 mShadowIterator = nullptr;
michael@0 252 }
michael@0 253 mChild = mChild->GetPreviousSibling();
michael@0 254 } else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
michael@0 255 // If the current child being iterated is a content insertion point
michael@0 256 // then the iterator needs to return the nodes distributed into
michael@0 257 // the content insertion point.
michael@0 258 MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
michael@0 259 if (!assignedChildren.IsEmpty()) {
michael@0 260 mIndexInInserted = assignedChildren.Length();
michael@0 261 return assignedChildren[mIndexInInserted - 1];
michael@0 262 }
michael@0 263
michael@0 264 mDefaultChild = mChild->GetLastChild();
michael@0 265 if (mDefaultChild) {
michael@0 266 return mDefaultChild;
michael@0 267 }
michael@0 268
michael@0 269 mChild = mChild->GetPreviousSibling();
michael@0 270 } else {
michael@0 271 // mChild is not an insertion point, thus it is the next node to
michael@0 272 // return from this iterator.
michael@0 273 break;
michael@0 274 }
michael@0 275 }
michael@0 276
michael@0 277 if (!mChild) {
michael@0 278 mIsFirst = true;
michael@0 279 }
michael@0 280
michael@0 281 return mChild;
michael@0 282 }
michael@0 283
michael@0 284 } // namespace dom
michael@0 285 } // namespace mozilla

mercurial