Bug 1869043 allow a device to be specified with MediaTrackGraph::NotifyWhenDeviceStar...
[gecko.git] / layout / base / nsFrameTraversal.cpp
blob138e8e018edf52b704927b32cbe14e0f2e236b00
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) return nullptr;
43 return mCurrent;
46 bool nsFrameIterator::IsDone() { return mOffEdge != 0; }
48 void nsFrameIterator::First() { mCurrent = mStart; }
50 static bool IsRootFrame(nsIFrame* aFrame) { return aFrame->IsCanvasFrame(); }
52 void nsFrameIterator::Last() {
53 nsIFrame* result;
54 nsIFrame* parent = GetCurrent();
55 // If the current frame is a popup, don't move farther up the tree.
56 // Otherwise, get the nearest root frame or popup.
57 if (mSkipPopupChecks || !parent->IsMenuPopupFrame()) {
58 while (!IsRootFrame(parent) && (result = GetParentFrameNotPopup(parent)))
59 parent = result;
62 while ((result = GetLastChild(parent))) {
63 parent = result;
66 SetCurrent(parent);
67 if (!parent) SetOffEdge(1);
70 void nsFrameIterator::Next() {
71 // recursive-oid method to get next frame
72 nsIFrame* result = nullptr;
73 nsIFrame* parent = GetCurrent();
74 if (!parent) parent = GetLast();
76 if (mType == Type::Leaf) {
77 // Drill down to first leaf
78 while ((result = GetFirstChild(parent))) {
79 parent = result;
81 } else if (mType == Type::PreOrder) {
82 result = GetFirstChild(parent);
83 if (result) parent = result;
86 if (parent != GetCurrent()) {
87 result = parent;
88 } else {
89 while (parent) {
90 result = GetNextSibling(parent);
91 if (result) {
92 if (mType != Type::PreOrder) {
93 parent = result;
94 while ((result = GetFirstChild(parent))) {
95 parent = result;
97 result = parent;
99 break;
101 result = GetParentFrameNotPopup(parent);
102 if (!result || IsRootFrame(result) ||
103 (mLockScroll && result->IsScrollFrame())) {
104 result = nullptr;
105 break;
107 if (mType == Type::PostOrder) {
108 break;
110 parent = result;
114 SetCurrent(result);
115 if (!result) {
116 SetOffEdge(1);
117 SetLast(parent);
121 void nsFrameIterator::Prev() {
122 // recursive-oid method to get prev frame
123 nsIFrame* result = nullptr;
124 nsIFrame* parent = GetCurrent();
125 if (!parent) parent = GetLast();
127 if (mType == Type::Leaf) {
128 // Drill down to last leaf
129 while ((result = GetLastChild(parent))) {
130 parent = result;
132 } else if (mType == Type::PostOrder) {
133 result = GetLastChild(parent);
134 if (result) parent = result;
137 if (parent != GetCurrent()) {
138 result = parent;
139 } else {
140 while (parent) {
141 result = GetPrevSibling(parent);
142 if (result) {
143 if (mType != Type::PostOrder) {
144 parent = result;
145 while ((result = GetLastChild(parent))) {
146 parent = result;
148 result = parent;
150 break;
152 result = GetParentFrameNotPopup(parent);
153 if (!result || IsRootFrame(result) ||
154 (mLockScroll && result->IsScrollFrame())) {
155 result = nullptr;
156 break;
158 if (mType == Type::PreOrder) {
159 break;
161 parent = result;
165 SetCurrent(result);
166 if (!result) {
167 SetOffEdge(-1);
168 SetLast(parent);
172 nsIFrame* nsFrameIterator::GetParentFrame(nsIFrame* aFrame) {
173 if (mFollowOOFs) aFrame = GetPlaceholderFrame(aFrame);
174 if (aFrame == mLimiter) return nullptr;
175 if (aFrame) return aFrame->GetParent();
177 return nullptr;
180 nsIFrame* nsFrameIterator::GetParentFrameNotPopup(nsIFrame* aFrame) {
181 if (mFollowOOFs) aFrame = GetPlaceholderFrame(aFrame);
182 if (aFrame == mLimiter) return nullptr;
183 if (aFrame) {
184 nsIFrame* parent = aFrame->GetParent();
185 if (!IsPopupFrame(parent)) return parent;
188 return nullptr;
191 nsIFrame* nsFrameIterator::GetFirstChild(nsIFrame* aFrame) {
192 nsIFrame* result = GetFirstChildInner(aFrame);
193 if (mLockScroll && result && result->IsScrollFrame()) return nullptr;
194 if (result && mFollowOOFs) {
195 result = nsPlaceholderFrame::GetRealFrameFor(result);
197 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
198 result = GetNextSibling(result);
202 return result;
205 nsIFrame* nsFrameIterator::GetLastChild(nsIFrame* aFrame) {
206 nsIFrame* result = GetLastChildInner(aFrame);
207 if (mLockScroll && result && result->IsScrollFrame()) return nullptr;
208 if (result && mFollowOOFs) {
209 result = nsPlaceholderFrame::GetRealFrameFor(result);
211 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
212 result = GetPrevSibling(result);
216 return result;
219 nsIFrame* nsFrameIterator::GetNextSibling(nsIFrame* aFrame) {
220 nsIFrame* result = nullptr;
221 if (mFollowOOFs) aFrame = GetPlaceholderFrame(aFrame);
222 if (aFrame == mLimiter) return nullptr;
223 if (aFrame) {
224 result = GetNextSiblingInner(aFrame);
225 if (result && mFollowOOFs) {
226 result = nsPlaceholderFrame::GetRealFrameFor(result);
227 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
228 result = GetNextSibling(result);
233 return result;
236 nsIFrame* nsFrameIterator::GetPrevSibling(nsIFrame* aFrame) {
237 nsIFrame* result = nullptr;
238 if (mFollowOOFs) aFrame = GetPlaceholderFrame(aFrame);
239 if (aFrame == mLimiter) return nullptr;
240 if (aFrame) {
241 result = GetPrevSiblingInner(aFrame);
242 if (result && mFollowOOFs) {
243 result = nsPlaceholderFrame::GetRealFrameFor(result);
244 if (IsPopupFrame(result) || IsInvokerOpenPopoverFrame(result)) {
245 result = GetPrevSibling(result);
250 return result;
253 nsIFrame* nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) {
254 return mVisual ? aFrame->PrincipalChildList().GetNextVisualFor(nullptr)
255 : aFrame->PrincipalChildList().FirstChild();
258 nsIFrame* nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) {
259 return mVisual ? aFrame->PrincipalChildList().GetPrevVisualFor(nullptr)
260 : aFrame->PrincipalChildList().LastChild();
263 nsIFrame* nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) {
264 if (!mVisual) {
265 return aFrame->GetNextSibling();
267 nsIFrame* parent = GetParentFrame(aFrame);
268 return parent ? parent->PrincipalChildList().GetNextVisualFor(aFrame)
269 : nullptr;
272 nsIFrame* nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
273 if (!mVisual) {
274 return aFrame->GetPrevSibling();
276 nsIFrame* parent = GetParentFrame(aFrame);
277 return parent ? parent->PrincipalChildList().GetPrevVisualFor(aFrame)
278 : nullptr;
281 nsIFrame* nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame) {
282 if (MOZ_LIKELY(!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
283 return aFrame;
285 nsIFrame* placeholder = aFrame->GetPlaceholderFrame();
286 return placeholder ? placeholder : aFrame;
289 bool nsFrameIterator::IsPopupFrame(nsIFrame* aFrame) {
290 // If skipping popup checks, pretend this isn't one.
291 if (mSkipPopupChecks) {
292 return false;
294 return aFrame && aFrame->IsMenuPopupFrame();
297 bool nsFrameIterator::IsInvokerOpenPopoverFrame(nsIFrame* aFrame) {
298 if (const nsIContent* currentContent = aFrame->GetContent()) {
299 if (const auto* popover = Element::FromNode(currentContent)) {
300 return popover && popover->IsPopoverOpen() &&
301 popover->GetPopoverData()->GetInvoker();
304 return false;