2017-10-27 20:33:53 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2012-05-21 15:12:37 +04:00
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
2017-08-17 00:10:56 +03:00
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2006-03-30 09:56:38 +04:00
|
|
|
|
|
|
|
/* storage of the frame tree and information about it */
|
|
|
|
|
2018-03-07 02:59:36 +03:00
|
|
|
#include "nsFrameManager.h"
|
|
|
|
|
2001-08-14 11:59:59 +04:00
|
|
|
#include "nscore.h"
|
1999-08-04 07:39:34 +04:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "plhash.h"
|
|
|
|
#include "nsPlaceholderFrame.h"
|
2007-01-30 03:06:41 +03:00
|
|
|
#include "nsGkAtoms.h"
|
1999-08-31 18:35:50 +04:00
|
|
|
#include "nsILayoutHistoryState.h"
|
2019-04-16 10:25:10 +03:00
|
|
|
#include "mozilla/PresShell.h"
|
2018-03-02 21:18:35 +03:00
|
|
|
#include "mozilla/PresState.h"
|
2018-03-22 21:20:41 +03:00
|
|
|
#include "mozilla/ComputedStyle.h"
|
2013-08-20 02:55:18 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
1999-08-04 07:39:34 +04:00
|
|
|
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2011-04-30 03:02:33 +04:00
|
|
|
#include "nsAbsoluteContainingBlock.h"
|
2013-05-02 02:50:08 +04:00
|
|
|
#include "ChildIterator.h"
|
2001-05-30 15:26:21 +04:00
|
|
|
|
2013-03-18 18:25:50 +04:00
|
|
|
#include "GeckoProfiler.h"
|
2013-08-20 02:55:18 +04:00
|
|
|
#include "nsIStatefulFrame.h"
|
2014-05-25 02:20:39 +04:00
|
|
|
#include "nsContainerFrame.h"
|
2018-03-28 02:44:49 +03:00
|
|
|
#include "nsWindowSizes.h"
|
Landing of SVG_20020806_BRANCH, Bug 182533. Refactoring of SVG backend, new GDI+ and Libart rendering
backends, text support on Windows (GDI+), rudimentary text support on Linux (libart/freetype2), presentation
attributes, lots of bug fixes (see bug 182533 for dependency list).
Not part of default build; code is #ifdef'ed out.
r=sicking, sr=jst for dom and htmlparser changes
r=bsmedberg, sr=tor for config changes
r=dbaron, sr=bzbarsky for content and layout changes
r=tor, sr=bzbarsky for gfx changes
2004-02-07 15:39:26 +03:00
|
|
|
|
2018-02-22 15:19:50 +03:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
|
|
|
|
2017-03-19 22:19:06 +03:00
|
|
|
// #define DEBUG_UNDISPLAYED_MAP
|
|
|
|
// #define DEBUG_DISPLAY_CONTENTS_MAP
|
2000-09-13 02:47:09 +04:00
|
|
|
|
2010-03-29 05:46:55 +04:00
|
|
|
using namespace mozilla;
|
2010-06-23 08:46:27 +04:00
|
|
|
using namespace mozilla::dom;
|
1999-08-04 07:39:34 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2004-02-24 00:29:06 +03:00
|
|
|
nsFrameManager::~nsFrameManager() {
|
|
|
|
NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
|
1999-08-04 07:39:34 +04:00
|
|
|
}
|
|
|
|
|
2004-02-24 00:29:06 +03:00
|
|
|
void nsFrameManager::Destroy() {
|
2001-03-06 04:46:03 +03:00
|
|
|
NS_ASSERTION(mPresShell, "Frame manager already shut down.");
|
|
|
|
|
2004-08-24 22:50:29 +04:00
|
|
|
// Destroy the frame hierarchy.
|
2011-10-17 18:59:28 +04:00
|
|
|
mPresShell->SetIgnoreFrameDestruction(true);
|
2002-03-10 09:47:42 +03:00
|
|
|
|
1999-10-19 02:20:37 +04:00
|
|
|
if (mRootFrame) {
|
2006-04-10 04:16:29 +04:00
|
|
|
mRootFrame->Destroy();
|
2012-07-30 18:20:58 +04:00
|
|
|
mRootFrame = nullptr;
|
1999-10-19 02:20:37 +04:00
|
|
|
}
|
2017-03-19 22:19:06 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mPresShell = nullptr;
|
1999-10-19 02:20:37 +04:00
|
|
|
}
|
|
|
|
|
1999-10-02 08:25:29 +04:00
|
|
|
//----------------------------------------------------------------------
|
2014-05-25 02:20:40 +04:00
|
|
|
void nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
|
|
|
|
ChildListID aListID,
|
|
|
|
nsFrameList& aFrameList) {
|
2011-04-30 03:02:33 +04:00
|
|
|
if (aParentFrame->IsAbsoluteContainer() &&
|
|
|
|
aListID == aParentFrame->GetAbsoluteListID()) {
|
2014-05-28 23:36:58 +04:00
|
|
|
aParentFrame->GetAbsoluteContainingBlock()->AppendFrames(
|
|
|
|
aParentFrame, aListID, aFrameList);
|
2011-04-30 03:02:33 +04:00
|
|
|
} else {
|
2014-05-28 23:36:58 +04:00
|
|
|
aParentFrame->AppendFrames(aListID, aFrameList);
|
2011-04-30 03:02:33 +04:00
|
|
|
}
|
|
|
|
}
|
1999-10-02 08:25:29 +04:00
|
|
|
|
2014-05-25 02:20:40 +04:00
|
|
|
void nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
|
|
|
|
ChildListID aListID, nsIFrame* aPrevFrame,
|
|
|
|
nsFrameList& aFrameList) {
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(
|
|
|
|
!aPrevFrame ||
|
|
|
|
(!aPrevFrame->GetNextContinuation() ||
|
2020-06-25 18:39:32 +03:00
|
|
|
(aPrevFrame->GetNextContinuation()->HasAnyStateBits(
|
|
|
|
NS_FRAME_IS_OVERFLOW_CONTAINER) &&
|
|
|
|
!aPrevFrame->HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER))),
|
2018-04-28 22:50:58 +03:00
|
|
|
"aPrevFrame must be the last continuation in its chain!");
|
2001-03-09 06:29:00 +03:00
|
|
|
|
2011-04-30 03:02:33 +04:00
|
|
|
if (aParentFrame->IsAbsoluteContainer() &&
|
|
|
|
aListID == aParentFrame->GetAbsoluteListID()) {
|
2014-05-28 23:36:58 +04:00
|
|
|
aParentFrame->GetAbsoluteContainingBlock()->InsertFrames(
|
|
|
|
aParentFrame, aListID, aPrevFrame, aFrameList);
|
2011-04-30 03:02:33 +04:00
|
|
|
} else {
|
2019-07-18 02:34:45 +03:00
|
|
|
aParentFrame->InsertFrames(aListID, aPrevFrame, nullptr, aFrameList);
|
2011-04-30 03:02:33 +04:00
|
|
|
}
|
1999-08-04 07:39:34 +04:00
|
|
|
}
|
|
|
|
|
2011-08-25 00:54:30 +04:00
|
|
|
void nsFrameManager::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) {
|
2012-08-29 09:48:45 +04:00
|
|
|
// In case the reflow doesn't invalidate anything since it just leaves
|
|
|
|
// a gap where the old frame was, we invalidate it here. (This is
|
|
|
|
// reasonably likely to happen when removing a last child in a way
|
|
|
|
// that doesn't change the size of the parent.)
|
|
|
|
// This has to sure to invalidate the entire overflow rect; this
|
|
|
|
// is important in the presence of absolute positioning
|
|
|
|
aOldFrame->InvalidateFrameForRemoval();
|
|
|
|
|
2009-12-24 08:20:41 +03:00
|
|
|
NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
|
|
|
|
// exception for
|
|
|
|
// nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
|
2017-04-30 18:30:08 +03:00
|
|
|
aOldFrame->IsTextFrame(),
|
2009-12-24 08:20:41 +03:00
|
|
|
"Must remove first continuation.");
|
2020-06-25 18:39:32 +03:00
|
|
|
NS_ASSERTION(!(aOldFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
|
2017-05-31 22:29:49 +03:00
|
|
|
aOldFrame->GetPlaceholderFrame()),
|
2009-12-24 08:20:41 +03:00
|
|
|
"Must call RemoveFrame on placeholder for out-of-flows.");
|
2014-05-25 02:20:40 +04:00
|
|
|
nsContainerFrame* parentFrame = aOldFrame->GetParent();
|
2011-04-30 03:02:33 +04:00
|
|
|
if (parentFrame->IsAbsoluteContainer() &&
|
|
|
|
aListID == parentFrame->GetAbsoluteListID()) {
|
|
|
|
parentFrame->GetAbsoluteContainingBlock()->RemoveFrame(parentFrame, aListID,
|
|
|
|
aOldFrame);
|
|
|
|
} else {
|
2014-05-28 23:36:58 +04:00
|
|
|
parentFrame->RemoveFrame(aListID, aOldFrame);
|
2011-04-30 03:02:33 +04:00
|
|
|
}
|
1999-08-04 07:39:34 +04:00
|
|
|
}
|
|
|
|
|
1999-08-06 00:17:44 +04:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2000-06-15 04:35:46 +04:00
|
|
|
// Capture state for a given frame.
|
|
|
|
// Accept a content id here, in some cases we may not have content (scroll
|
|
|
|
// position)
|
2004-02-24 00:29:06 +03:00
|
|
|
void nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
|
2012-11-15 10:40:17 +04:00
|
|
|
nsILayoutHistoryState* aState) {
|
2004-02-24 00:29:06 +03:00
|
|
|
if (!aFrame || !aState) {
|
|
|
|
NS_WARNING("null frame, or state");
|
|
|
|
return;
|
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// Only capture state for stateful frames
|
2009-01-12 22:20:59 +03:00
|
|
|
nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
|
2001-05-30 15:26:21 +04:00
|
|
|
if (!statefulFrame) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
2001-05-30 15:26:21 +04:00
|
|
|
}
|
2000-06-15 04:35:46 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// Capture the state, exit early if we get null (nothing to save)
|
2018-03-02 21:18:35 +03:00
|
|
|
UniquePtr<PresState> frameState = statefulFrame->SaveState();
|
2001-05-30 15:26:21 +04:00
|
|
|
if (!frameState) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
2001-05-30 15:26:21 +04:00
|
|
|
}
|
2000-06-15 04:35:46 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// Generate the hash key to store the state under
|
|
|
|
// Exit early if we get empty key
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString stateKey;
|
2005-01-15 20:47:23 +03:00
|
|
|
nsIContent* content = aFrame->GetContent();
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = content ? content->GetUncomposedDoc() : nullptr;
|
2019-07-01 10:20:04 +03:00
|
|
|
statefulFrame->GenerateStateKey(content, doc, stateKey);
|
|
|
|
if (stateKey.IsEmpty()) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
1999-08-31 18:35:50 +04:00
|
|
|
}
|
|
|
|
|
2013-07-24 11:38:13 +04:00
|
|
|
// Store the state. aState owns frameState now.
|
2018-05-30 22:15:35 +03:00
|
|
|
aState->AddState(stateKey, std::move(frameState));
|
1999-10-23 05:43:49 +04:00
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
|
2004-02-24 00:29:06 +03:00
|
|
|
void nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
|
|
|
|
nsILayoutHistoryState* aState) {
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(nullptr != aFrame && nullptr != aState,
|
|
|
|
"null parameters passed in");
|
1999-08-31 18:35:50 +04:00
|
|
|
|
2004-02-24 00:29:06 +03:00
|
|
|
CaptureFrameStateFor(aFrame, aState);
|
1999-10-23 05:43:49 +04:00
|
|
|
|
|
|
|
// Now capture state recursively for the frame hierarchy rooted at aFrame
|
2020-05-19 15:37:37 +03:00
|
|
|
for (const auto& childList : aFrame->ChildLists()) {
|
2020-05-18 04:17:15 +03:00
|
|
|
for (nsIFrame* child : childList.mList) {
|
2020-06-25 18:39:32 +03:00
|
|
|
if (child->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
|
2012-05-10 05:27:47 +04:00
|
|
|
// We'll pick it up when we get to its placeholder
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Make sure to walk through placeholders as needed, so that we
|
|
|
|
// save state for out-of-flows which may not be our descendants
|
|
|
|
// themselves but whose placeholders are our descendants.
|
|
|
|
CaptureFrameState(nsPlaceholderFrame::GetRealFrameFor(child), aState);
|
1999-10-23 05:43:49 +04:00
|
|
|
}
|
2011-08-25 00:54:29 +04:00
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
}
|
|
|
|
|
2000-06-15 04:35:46 +04:00
|
|
|
// Restore state for a given frame.
|
|
|
|
// Accept a content id here, in some cases we may not have content (scroll
|
|
|
|
// position)
|
2004-02-24 00:29:06 +03:00
|
|
|
void nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
|
2012-11-15 10:40:17 +04:00
|
|
|
nsILayoutHistoryState* aState) {
|
2004-02-24 00:29:06 +03:00
|
|
|
if (!aFrame || !aState) {
|
|
|
|
NS_WARNING("null frame or state");
|
|
|
|
return;
|
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
|
2008-12-03 20:55:14 +03:00
|
|
|
// Only restore state for stateful frames
|
2009-01-12 22:20:59 +03:00
|
|
|
nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
|
2001-05-30 15:26:21 +04:00
|
|
|
if (!statefulFrame) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
2001-05-30 15:26:21 +04:00
|
|
|
}
|
2000-06-15 04:35:46 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// Generate the hash key the state was stored under
|
|
|
|
// Exit early if we get empty key
|
2003-06-29 07:43:05 +04:00
|
|
|
nsIContent* content = aFrame->GetContent();
|
2001-09-29 21:50:15 +04:00
|
|
|
// If we don't have content, we can't generate a hash
|
|
|
|
// key and there's probably no state information for us.
|
|
|
|
if (!content) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
2001-09-29 21:50:15 +04:00
|
|
|
}
|
2000-06-15 04:35:46 +04:00
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString stateKey;
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = content->GetUncomposedDoc();
|
2019-07-01 10:20:04 +03:00
|
|
|
statefulFrame->GenerateStateKey(content, doc, stateKey);
|
|
|
|
if (stateKey.IsEmpty()) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
2001-05-30 15:26:21 +04:00
|
|
|
}
|
2000-06-15 04:35:46 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// Get the state from the hash
|
2018-03-02 21:18:35 +03:00
|
|
|
PresState* frameState = aState->GetState(stateKey);
|
2001-05-30 15:26:21 +04:00
|
|
|
if (!frameState) {
|
2004-02-24 00:29:06 +03:00
|
|
|
return;
|
2001-05-30 15:26:21 +04:00
|
|
|
}
|
2000-06-15 04:35:46 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// Restore it
|
2019-07-01 10:20:04 +03:00
|
|
|
nsresult rv = statefulFrame->RestoreState(frameState);
|
2004-02-24 00:29:06 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return;
|
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
|
2001-05-30 15:26:21 +04:00
|
|
|
// If we restore ok, remove the state from the state table
|
2004-02-24 00:29:06 +03:00
|
|
|
aState->RemoveState(stateKey);
|
1999-10-23 05:43:49 +04:00
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
|
2004-02-24 00:29:06 +03:00
|
|
|
void nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
|
|
|
|
nsILayoutHistoryState* aState) {
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(nullptr != aFrame && nullptr != aState,
|
|
|
|
"null parameters passed in");
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2004-02-24 00:29:06 +03:00
|
|
|
RestoreFrameStateFor(aFrame, aState);
|
1999-10-23 05:43:49 +04:00
|
|
|
|
|
|
|
// Now restore state recursively for the frame hierarchy rooted at aFrame
|
2020-05-19 15:37:37 +03:00
|
|
|
for (const auto& childList : aFrame->ChildLists()) {
|
2020-05-18 04:17:15 +03:00
|
|
|
for (nsIFrame* child : childList.mList) {
|
|
|
|
RestoreFrameState(child, aState);
|
1999-10-23 05:43:49 +04:00
|
|
|
}
|
2011-08-25 00:54:29 +04:00
|
|
|
}
|
1999-08-31 18:35:50 +04:00
|
|
|
}
|
|
|
|
|
2018-02-22 15:19:50 +03:00
|
|
|
void nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const {
|
|
|
|
aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);
|
|
|
|
}
|