Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / layout / base / nsFrameTraversal.cpp
blob8b0a87bed5521a3d80f9a1297f324506d2d82cb6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsFrameTraversal.h"
9 #include "mozilla/Assertions.h"
10 #include "nsCOMPtr.h"
11 #include "nsGkAtoms.h"
13 #include "nsFrameList.h"
14 #include "nsPlaceholderFrame.h"
15 #include "nsPresContext.h"
16 #include "nsContainerFrame.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/PopoverData.h"
20 using namespace mozilla;
21 using namespace mozilla::dom;
23 nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame* aStart,
24 Type aType, bool aVisual,
25 bool aLockInScrollView, bool aFollowOOFs,
26 bool aSkipPopupChecks, nsIFrame* aLimiter)
27 : mPresContext(aPresContext),
28 mLockScroll(aLockInScrollView),
29 mFollowOOFs(aFollowOOFs),
30 mSkipPopupChecks(aSkipPopupChecks),
31 mVisual(aVisual),
32 mType(aType),
33 mStart(aFollowOOFs ? nsPlaceholderFrame::GetRealFrameFor(aStart)
34 : aStart),
35 mCurrent(aStart),
36 mLast(aStart),
37 mLimiter(aLimiter),
38 mOffEdge(0) {}
40 nsIFrame* nsFrameIterator::CurrentItem() {
41 if (mOffEdge) {
42 return nullptr;
45 return mCurrent;
48 bool nsFrameIterator::IsDone() { return mOffEdge != 0; }
50 void nsFrameIterator::First() { mCurrent = mStart; }
52 static bool IsRootFrame(nsIFrame* aFrame) { return aFrame->IsCanvasFrame(); }
54 void nsFrameIterator::Last() {
55 nsIFrame* result;
56 nsIFrame* parent = GetCurrent();
57 // If the current frame is a popup, don't move farther up the tree.
58 // Otherwise, get the nearest root frame or popup.
59 if (mSkipPopupChecks || !parent->IsMenuPopupFrame()) {
60 while (!IsRootFrame(parent) && (result = GetParentFrameNotPopup(parent))) {
61 parent = result;
65 while ((result = GetLastChild(parent))) {
66 parent = result;
69 SetCurrent(parent);
70 if (!parent) {
71 SetOffEdge(1);
75 void nsFrameIterator::Next() {
76 // recursive-oid method to get next frame
77 nsIFrame* result = nullptr;
78 nsIFrame* parent = GetCurrent();
79 if (!parent) {
80 parent = GetLast();
83 if (mType == Type::Leaf) {
84 // Drill down to first leaf
85 while ((result = GetFirstChild(parent))) {
86 parent = result;
88 } else if (mType == Type::PreOrder) {
89 result = GetFirstChild(parent);
90 if (result) {
91 parent = result;
95 if (parent != GetCurrent()) {
96 result = parent;
97 } else {
98 while (parent) {
99 result = GetNextSibling(parent);
100 if (result) {
101 if (mType != Type::PreOrder) {
102 parent = result;
103 while ((result = GetFirstChild(parent))) {
104 parent = result;
106 result = parent;
108 break;
110 result = GetParentFrameNotPopup(parent);
111 if (!result || IsRootFrame(result) ||
112 (mLockScroll && result->IsScrollContainerFrame())) {
113 result = nullptr;
114 break;
116 if (mType == Type::PostOrder) {
117 break;
119 parent = result;
123 SetCurrent(result);
124 if (!result) {
125 SetOffEdge(1);
126 SetLast(parent);
130 void nsFrameIterator::Prev() {
131 // recursive-oid method to get prev frame
132 nsIFrame* result = nullptr;
133 nsIFrame* parent = GetCurrent();
134 if (!parent) {
135 parent = GetLast();
138 if (mType == Type::Leaf) {
139 // Drill down to last leaf
140 while ((result = GetLastChild(parent))) {
141 parent = result;
143 } else if (mType == Type::PostOrder) {
144 result = GetLastChild(parent);
145 if (result) {
146 parent = result;
150 if (parent != GetCurrent()) {
151 result = parent;
152 } else {
153 while (parent) {
154 result = GetPrevSibling(parent);
155 if (result) {
156 if (mType != Type::PostOrder) {
157 parent = result;
158 while ((result = GetLastChild(parent))) {
159 parent = result;
161 result = parent;
163 break;
165 result = GetParentFrameNotPopup(parent);
166 if (!result || IsRootFrame(result) ||
167 (mLockScroll && result->IsScrollContainerFrame())) {
168 result = nullptr;
169 break;
171 if (mType == Type::PreOrder) {
172 break;
174 parent = result;
178 SetCurrent(result);
179 if (!result) {
180 SetOffEdge(-1);
181 SetLast(parent);
185 nsIFrame* nsFrameIterator::GetParentFrame(nsIFrame* aFrame) {
186 if (mFollowOOFs) {
187 aFrame = GetPlaceholderFrame(aFrame);
189 if (aFrame == mLimiter) {
190 return nullptr;
192 if (aFrame) {
193 return aFrame->GetParent();
196 return nullptr;
199 nsIFrame* nsFrameIterator::GetParentFrameNotPopup(nsIFrame* aFrame) {
200 if (mFollowOOFs) {
201 aFrame = GetPlaceholderFrame(aFrame);
203 if (aFrame == mLimiter) {
204 return nullptr;
206 if (aFrame) {
207 nsIFrame* parent = aFrame->GetParent();
208 if (!IsPopupFrame(parent)) {
209 return parent;
213 return nullptr;
216 nsIFrame* nsFrameIterator::GetFirstChild(nsIFrame* aFrame) {
217 nsIFrame* result = GetFirstChildInner(aFrame);
218 if (mLockScroll && result && result->IsScrollContainerFrame()) {
219 return nullptr;
221 if (result && mFollowOOFs) {
222 result = nsPlaceholderFrame::GetRealFrameFor(result);
224 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
225 result = GetNextSibling(result);
229 return result;
232 nsIFrame* nsFrameIterator::GetLastChild(nsIFrame* aFrame) {
233 nsIFrame* result = GetLastChildInner(aFrame);
234 if (mLockScroll && result && result->IsScrollContainerFrame()) {
235 return nullptr;
237 if (result && mFollowOOFs) {
238 result = nsPlaceholderFrame::GetRealFrameFor(result);
240 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
241 result = GetPrevSibling(result);
245 return result;
248 nsIFrame* nsFrameIterator::GetNextSibling(nsIFrame* aFrame) {
249 nsIFrame* result = nullptr;
250 if (mFollowOOFs) {
251 aFrame = GetPlaceholderFrame(aFrame);
253 if (aFrame == mLimiter) {
254 return nullptr;
256 if (aFrame) {
257 result = GetNextSiblingInner(aFrame);
258 if (result && mFollowOOFs) {
259 result = nsPlaceholderFrame::GetRealFrameFor(result);
260 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
261 result = GetNextSibling(result);
266 return result;
269 nsIFrame* nsFrameIterator::GetPrevSibling(nsIFrame* aFrame) {
270 nsIFrame* result = nullptr;
271 if (mFollowOOFs) {
272 aFrame = GetPlaceholderFrame(aFrame);
274 if (aFrame == mLimiter) {
275 return nullptr;
277 if (aFrame) {
278 result = GetPrevSiblingInner(aFrame);
279 if (result && mFollowOOFs) {
280 result = nsPlaceholderFrame::GetRealFrameFor(result);
281 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
282 result = GetPrevSibling(result);
287 return result;
290 nsIFrame* nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) {
291 return mVisual ? aFrame->PrincipalChildList().GetNextVisualFor(nullptr)
292 : aFrame->PrincipalChildList().FirstChild();
295 nsIFrame* nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) {
296 return mVisual ? aFrame->PrincipalChildList().GetPrevVisualFor(nullptr)
297 : aFrame->PrincipalChildList().LastChild();
300 nsIFrame* nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) {
301 if (!mVisual) {
302 return aFrame->GetNextSibling();
304 nsIFrame* parent = GetParentFrame(aFrame);
305 return parent ? parent->PrincipalChildList().GetNextVisualFor(aFrame)
306 : nullptr;
309 nsIFrame* nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
310 if (!mVisual) {
311 return aFrame->GetPrevSibling();
313 nsIFrame* parent = GetParentFrame(aFrame);
314 return parent ? parent->PrincipalChildList().GetPrevVisualFor(aFrame)
315 : nullptr;
318 nsIFrame* nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame) {
319 if (MOZ_LIKELY(!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
320 return aFrame;
322 nsIFrame* placeholder = aFrame->GetPlaceholderFrame();
323 return placeholder ? placeholder : aFrame;
326 bool nsFrameIterator::IsPopupFrame(nsIFrame* aFrame) {
327 // If skipping popup checks, pretend this isn't one.
328 if (mSkipPopupChecks) {
329 return false;
331 return aFrame && aFrame->IsMenuPopupFrame();
334 bool nsFrameIterator::IsInvokerOpenPopoverFrame(nsIFrame* aFrame) {
335 if (const nsIContent* currentContent = aFrame->GetContent()) {
336 if (const auto* popover = Element::FromNode(currentContent)) {
337 return popover && popover->IsPopoverOpen() &&
338 popover->GetPopoverData()->GetInvoker();
341 return false;