Coverage Report

Created: 2018-09-25 14:53

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