Bug 1584173 [wpt PR 19325] - Update interfaces/fullscreen.idl, a=testonly
[gecko.git] / layout / base / nsFrameManager.cpp
blob623d95de5d69a259b2f4f2f06eb4c50fcb1cfd6a
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 /* storage of the frame tree and information about it */
9 #include "nsFrameManager.h"
11 #include "nscore.h"
12 #include "nsCOMPtr.h"
13 #include "plhash.h"
14 #include "nsPlaceholderFrame.h"
15 #include "nsGkAtoms.h"
16 #include "nsILayoutHistoryState.h"
17 #include "mozilla/PresShell.h"
18 #include "mozilla/PresState.h"
19 #include "mozilla/ComputedStyle.h"
20 #include "mozilla/dom/Element.h"
21 #include "mozilla/dom/Document.h"
23 #include "nsError.h"
24 #include "nsAbsoluteContainingBlock.h"
25 #include "ChildIterator.h"
27 #include "GeckoProfiler.h"
28 #include "nsIStatefulFrame.h"
29 #include "nsContainerFrame.h"
30 #include "nsWindowSizes.h"
32 #include "mozilla/MemoryReporting.h"
34 // #define DEBUG_UNDISPLAYED_MAP
35 // #define DEBUG_DISPLAY_CONTENTS_MAP
37 using namespace mozilla;
38 using namespace mozilla::dom;
40 //----------------------------------------------------------------------
42 nsFrameManager::~nsFrameManager() {
43 NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
46 void nsFrameManager::Destroy() {
47 NS_ASSERTION(mPresShell, "Frame manager already shut down.");
49 // Destroy the frame hierarchy.
50 mPresShell->SetIgnoreFrameDestruction(true);
52 if (mRootFrame) {
53 mRootFrame->Destroy();
54 mRootFrame = nullptr;
57 mPresShell = nullptr;
60 //----------------------------------------------------------------------
61 void nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
62 ChildListID aListID,
63 nsFrameList& aFrameList) {
64 if (aParentFrame->IsAbsoluteContainer() &&
65 aListID == aParentFrame->GetAbsoluteListID()) {
66 aParentFrame->GetAbsoluteContainingBlock()->AppendFrames(
67 aParentFrame, aListID, aFrameList);
68 } else {
69 aParentFrame->AppendFrames(aListID, aFrameList);
73 void nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
74 ChildListID aListID, nsIFrame* aPrevFrame,
75 nsFrameList& aFrameList) {
76 MOZ_ASSERT(
77 !aPrevFrame ||
78 (!aPrevFrame->GetNextContinuation() ||
79 (((aPrevFrame->GetNextContinuation()->GetStateBits() &
80 NS_FRAME_IS_OVERFLOW_CONTAINER)) &&
81 !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))),
82 "aPrevFrame must be the last continuation in its chain!");
84 if (aParentFrame->IsAbsoluteContainer() &&
85 aListID == aParentFrame->GetAbsoluteListID()) {
86 aParentFrame->GetAbsoluteContainingBlock()->InsertFrames(
87 aParentFrame, aListID, aPrevFrame, aFrameList);
88 } else {
89 aParentFrame->InsertFrames(aListID, aPrevFrame, nullptr, aFrameList);
93 void nsFrameManager::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) {
94 // In case the reflow doesn't invalidate anything since it just leaves
95 // a gap where the old frame was, we invalidate it here. (This is
96 // reasonably likely to happen when removing a last child in a way
97 // that doesn't change the size of the parent.)
98 // This has to sure to invalidate the entire overflow rect; this
99 // is important in the presence of absolute positioning
100 aOldFrame->InvalidateFrameForRemoval();
102 NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
103 // exception for
104 // nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
105 aOldFrame->IsTextFrame(),
106 "Must remove first continuation.");
107 NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
108 aOldFrame->GetPlaceholderFrame()),
109 "Must call RemoveFrame on placeholder for out-of-flows.");
110 nsContainerFrame* parentFrame = aOldFrame->GetParent();
111 if (parentFrame->IsAbsoluteContainer() &&
112 aListID == parentFrame->GetAbsoluteListID()) {
113 parentFrame->GetAbsoluteContainingBlock()->RemoveFrame(parentFrame, aListID,
114 aOldFrame);
115 } else {
116 parentFrame->RemoveFrame(aListID, aOldFrame);
120 //----------------------------------------------------------------------
122 // Capture state for a given frame.
123 // Accept a content id here, in some cases we may not have content (scroll
124 // position)
125 void nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
126 nsILayoutHistoryState* aState) {
127 if (!aFrame || !aState) {
128 NS_WARNING("null frame, or state");
129 return;
132 // Only capture state for stateful frames
133 nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
134 if (!statefulFrame) {
135 return;
138 // Capture the state, exit early if we get null (nothing to save)
139 UniquePtr<PresState> frameState = statefulFrame->SaveState();
140 if (!frameState) {
141 return;
144 // Generate the hash key to store the state under
145 // Exit early if we get empty key
146 nsAutoCString stateKey;
147 nsIContent* content = aFrame->GetContent();
148 Document* doc = content ? content->GetUncomposedDoc() : nullptr;
149 statefulFrame->GenerateStateKey(content, doc, stateKey);
150 if (stateKey.IsEmpty()) {
151 return;
154 // Store the state. aState owns frameState now.
155 aState->AddState(stateKey, std::move(frameState));
158 void nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
159 nsILayoutHistoryState* aState) {
160 MOZ_ASSERT(nullptr != aFrame && nullptr != aState,
161 "null parameters passed in");
163 CaptureFrameStateFor(aFrame, aState);
165 // Now capture state recursively for the frame hierarchy rooted at aFrame
166 nsIFrame::ChildListIterator lists(aFrame);
167 for (; !lists.IsDone(); lists.Next()) {
168 nsFrameList::Enumerator childFrames(lists.CurrentList());
169 for (; !childFrames.AtEnd(); childFrames.Next()) {
170 nsIFrame* child = childFrames.get();
171 if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
172 // We'll pick it up when we get to its placeholder
173 continue;
175 // Make sure to walk through placeholders as needed, so that we
176 // save state for out-of-flows which may not be our descendants
177 // themselves but whose placeholders are our descendants.
178 CaptureFrameState(nsPlaceholderFrame::GetRealFrameFor(child), aState);
183 // Restore state for a given frame.
184 // Accept a content id here, in some cases we may not have content (scroll
185 // position)
186 void nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
187 nsILayoutHistoryState* aState) {
188 if (!aFrame || !aState) {
189 NS_WARNING("null frame or state");
190 return;
193 // Only restore state for stateful frames
194 nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
195 if (!statefulFrame) {
196 return;
199 // Generate the hash key the state was stored under
200 // Exit early if we get empty key
201 nsIContent* content = aFrame->GetContent();
202 // If we don't have content, we can't generate a hash
203 // key and there's probably no state information for us.
204 if (!content) {
205 return;
208 nsAutoCString stateKey;
209 Document* doc = content->GetUncomposedDoc();
210 statefulFrame->GenerateStateKey(content, doc, stateKey);
211 if (stateKey.IsEmpty()) {
212 return;
215 // Get the state from the hash
216 PresState* frameState = aState->GetState(stateKey);
217 if (!frameState) {
218 return;
221 // Restore it
222 nsresult rv = statefulFrame->RestoreState(frameState);
223 if (NS_FAILED(rv)) {
224 return;
227 // If we restore ok, remove the state from the state table
228 aState->RemoveState(stateKey);
231 void nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
232 nsILayoutHistoryState* aState) {
233 MOZ_ASSERT(nullptr != aFrame && nullptr != aState,
234 "null parameters passed in");
236 RestoreFrameStateFor(aFrame, aState);
238 // Now restore state recursively for the frame hierarchy rooted at aFrame
239 nsIFrame::ChildListIterator lists(aFrame);
240 for (; !lists.IsDone(); lists.Next()) {
241 nsFrameList::Enumerator childFrames(lists.CurrentList());
242 for (; !childFrames.AtEnd(); childFrames.Next()) {
243 RestoreFrameState(childFrames.get(), aState);
248 void nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const {
249 aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);