2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* vim:cindent:ts=2:et:sw=2:
|
|
|
|
*
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* This Original Code has been modified by IBM Corporation. Modifications made by IBM
|
|
|
|
* described herein are Copyright (c) International Business Machines Corporation, 2000.
|
|
|
|
* Modifications to Mozilla code or documentation identified per MPL Section 3.3
|
|
|
|
*
|
|
|
|
* Date Modified by Description of modification
|
|
|
|
* 04/20/2000 IBM Corp. OS/2 VisualAge build.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* storage of the frame tree and information about it */
|
|
|
|
|
|
|
|
#include "nscore.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsStyleSet.h"
|
|
|
|
#include "nsCSSFrameConstructor.h"
|
|
|
|
#include "nsStyleContext.h"
|
|
|
|
#include "nsStyleChangeList.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "prthread.h"
|
|
|
|
#include "plhash.h"
|
|
|
|
#include "nsPlaceholderFrame.h"
|
2007-11-12 11:05:42 -08:00
|
|
|
#include "nsContainerFrame.h"
|
2007-10-19 10:41:29 -07:00
|
|
|
#include "nsBlockFrame.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsCSSAnonBoxes.h"
|
|
|
|
#include "nsCSSPseudoElements.h"
|
2012-06-25 12:59:42 -07:00
|
|
|
#ifdef DEBUG
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIStyleRule.h"
|
|
|
|
#endif
|
|
|
|
#include "nsILayoutHistoryState.h"
|
|
|
|
#include "nsPresState.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIScrollableFrame.h"
|
|
|
|
|
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsIDOMHTMLCollection.h"
|
|
|
|
#include "nsIFormControl.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMHTMLFormElement.h"
|
|
|
|
#include "nsIForm.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
|
|
|
#include "nsLayoutErrors.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "nsAutoPtr.h"
|
|
|
|
#include "imgIRequest.h"
|
2009-10-07 20:22:42 -07:00
|
|
|
#include "nsTransitionManager.h"
|
2010-06-18 09:23:05 -07:00
|
|
|
#include "RestyleTracker.h"
|
2011-04-29 16:02:33 -07:00
|
|
|
#include "nsAbsoluteContainingBlock.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsFrameManager.h"
|
2011-05-24 17:19:09 -07:00
|
|
|
#include "nsRuleProcessorData.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-11-13 09:49:26 -08:00
|
|
|
#ifdef ACCESSIBILITY
|
2011-01-27 20:38:14 -08:00
|
|
|
#include "nsAccessibilityService.h"
|
2010-11-13 09:49:26 -08:00
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
//#define NOISY_DEBUG
|
|
|
|
//#define DEBUG_UNDISPLAYED_MAP
|
|
|
|
#else
|
|
|
|
#undef NOISY_DEBUG
|
|
|
|
#undef DEBUG_UNDISPLAYED_MAP
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef NOISY_DEBUG
|
|
|
|
#define NOISY_TRACE(_msg) \
|
|
|
|
printf("%s",_msg);
|
|
|
|
#define NOISY_TRACE_FRAME(_msg,_frame) \
|
|
|
|
printf("%s ",_msg); nsFrame::ListTag(stdout,_frame); printf("\n");
|
|
|
|
#else
|
|
|
|
#define NOISY_TRACE(_msg);
|
|
|
|
#define NOISY_TRACE_FRAME(_msg,_frame);
|
|
|
|
#endif
|
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
using namespace mozilla;
|
2010-06-22 21:46:27 -07:00
|
|
|
using namespace mozilla::dom;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
struct PlaceholderMapEntry : public PLDHashEntryHdr {
|
|
|
|
// key (the out of flow frame) can be obtained through placeholder frame
|
|
|
|
nsPlaceholderFrame *placeholderFrame;
|
|
|
|
};
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2007-03-22 10:30:00 -07:00
|
|
|
PlaceholderMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
|
|
|
|
const void *key)
|
|
|
|
{
|
|
|
|
const PlaceholderMapEntry *entry =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<const PlaceholderMapEntry*>(hdr);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() !=
|
|
|
|
(void*)0xdddddddd,
|
|
|
|
"Dead placeholder in placeholder map");
|
|
|
|
return entry->placeholderFrame->GetOutOfFlowFrame() == key;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PLDHashTableOps PlaceholderMapOps = {
|
|
|
|
PL_DHashAllocTable,
|
|
|
|
PL_DHashFreeTable,
|
|
|
|
PL_DHashVoidPtrKeyStub,
|
|
|
|
PlaceholderMapMatchEntry,
|
|
|
|
PL_DHashMoveEntryStub,
|
|
|
|
PL_DHashClearEntryStub,
|
|
|
|
PL_DHashFinalizeStub,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// XXXldb This seems too complicated for what I think it's doing, and it
|
|
|
|
// should also be using pldhash rather than plhash to use less memory.
|
|
|
|
|
|
|
|
class UndisplayedNode {
|
|
|
|
public:
|
|
|
|
UndisplayedNode(nsIContent* aContent, nsStyleContext* aStyle)
|
|
|
|
: mContent(aContent),
|
|
|
|
mStyle(aStyle),
|
|
|
|
mNext(nsnull)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(UndisplayedNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_HIDDEN ~UndisplayedNode()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(UndisplayedNode);
|
2008-11-02 08:05:14 -08:00
|
|
|
|
|
|
|
// Delete mNext iteratively to avoid blowing up the stack (bug 460461).
|
|
|
|
UndisplayedNode *cur = mNext;
|
|
|
|
while (cur) {
|
|
|
|
UndisplayedNode *next = cur->mNext;
|
|
|
|
cur->mNext = nsnull;
|
|
|
|
delete cur;
|
|
|
|
cur = next;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> mContent;
|
|
|
|
nsRefPtr<nsStyleContext> mStyle;
|
|
|
|
UndisplayedNode* mNext;
|
|
|
|
};
|
|
|
|
|
|
|
|
class nsFrameManagerBase::UndisplayedMap {
|
|
|
|
public:
|
|
|
|
UndisplayedMap(PRUint32 aNumBuckets = 16) NS_HIDDEN;
|
|
|
|
~UndisplayedMap(void) NS_HIDDEN;
|
|
|
|
|
|
|
|
NS_HIDDEN_(UndisplayedNode*) GetFirstNode(nsIContent* aParentContent);
|
|
|
|
|
|
|
|
NS_HIDDEN_(nsresult) AddNodeFor(nsIContent* aParentContent,
|
|
|
|
nsIContent* aChild, nsStyleContext* aStyle);
|
|
|
|
|
|
|
|
NS_HIDDEN_(void) RemoveNodeFor(nsIContent* aParentContent,
|
|
|
|
UndisplayedNode* aNode);
|
|
|
|
|
|
|
|
NS_HIDDEN_(void) RemoveNodesFor(nsIContent* aParentContent);
|
|
|
|
|
|
|
|
// Removes all entries from the hash table
|
|
|
|
NS_HIDDEN_(void) Clear(void);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
NS_HIDDEN_(PLHashEntry**) GetEntryFor(nsIContent* aParentContent);
|
|
|
|
NS_HIDDEN_(void) AppendNodeFor(UndisplayedNode* aNode,
|
|
|
|
nsIContent* aParentContent);
|
|
|
|
|
|
|
|
PLHashTable* mTable;
|
|
|
|
PLHashEntry** mLastLookup;
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsFrameManager::~nsFrameManager()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-02-02 02:06:46 -08:00
|
|
|
nsFrameManager::Init(nsStyleSet* aStyleSet)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-02 02:06:46 -08:00
|
|
|
if (!mPresShell) {
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ERROR("null pres shell");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aStyleSet) {
|
|
|
|
NS_ERROR("null style set");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mStyleSet = aStyleSet;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::Destroy()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mPresShell, "Frame manager already shut down.");
|
|
|
|
|
|
|
|
// Destroy the frame hierarchy.
|
2011-10-17 07:59:28 -07:00
|
|
|
mPresShell->SetIgnoreFrameDestruction(true);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Unregister all placeholders before tearing down the frame tree
|
|
|
|
nsFrameManager::ClearPlaceholderFrameMap();
|
|
|
|
|
|
|
|
if (mRootFrame) {
|
|
|
|
mRootFrame->Destroy();
|
|
|
|
mRootFrame = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete mUndisplayedMap;
|
|
|
|
mUndisplayedMap = nsnull;
|
|
|
|
|
|
|
|
mPresShell = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Placeholder frame functions
|
|
|
|
nsPlaceholderFrame*
|
2012-02-15 01:28:21 -08:00
|
|
|
nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aFrame, "null param unexpected");
|
|
|
|
|
|
|
|
if (mPlaceholderMap.ops) {
|
2007-07-08 00:08:04 -07:00
|
|
|
PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>
|
|
|
|
(PL_DHashTableOperate(const_cast<PLDHashTable*>(&mPlaceholderMap),
|
2007-03-22 10:30:00 -07:00
|
|
|
aFrame, PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
|
|
|
return entry->placeholderFrame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
|
|
|
|
NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
|
|
|
|
"unexpected frame type");
|
|
|
|
if (!mPlaceholderMap.ops) {
|
|
|
|
if (!PL_DHashTableInit(&mPlaceholderMap, &PlaceholderMapOps, nsnull,
|
|
|
|
sizeof(PlaceholderMapEntry), 16)) {
|
|
|
|
mPlaceholderMap.ops = nsnull;
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
2007-07-08 00:08:04 -07:00
|
|
|
PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>(PL_DHashTableOperate(&mPlaceholderMap,
|
2007-03-22 10:30:00 -07:00
|
|
|
aPlaceholderFrame->GetOutOfFlowFrame(),
|
|
|
|
PL_DHASH_ADD));
|
|
|
|
if (!entry)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
|
|
|
|
entry->placeholderFrame = aPlaceholderFrame;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
|
|
|
|
NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
|
|
|
|
"unexpected frame type");
|
|
|
|
|
|
|
|
if (mPlaceholderMap.ops) {
|
|
|
|
PL_DHashTableOperate(&mPlaceholderMap,
|
|
|
|
aPlaceholderFrame->GetOutOfFlowFrame(),
|
|
|
|
PL_DHASH_REMOVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
UnregisterPlaceholders(PLDHashTable* table, PLDHashEntryHdr* hdr,
|
|
|
|
PRUint32 number, void* arg)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
PlaceholderMapEntry* entry = static_cast<PlaceholderMapEntry*>(hdr);
|
2007-03-22 10:30:00 -07:00
|
|
|
entry->placeholderFrame->SetOutOfFlowFrame(nsnull);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::ClearPlaceholderFrameMap()
|
|
|
|
{
|
|
|
|
if (mPlaceholderMap.ops) {
|
|
|
|
PL_DHashTableEnumerate(&mPlaceholderMap, UnregisterPlaceholders, nsnull);
|
|
|
|
PL_DHashTableFinish(&mPlaceholderMap);
|
|
|
|
mPlaceholderMap.ops = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsStyleContext*
|
|
|
|
nsFrameManager::GetUndisplayedContent(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (!aContent || !mUndisplayedMap)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
nsIContent* parent = aContent->GetParent();
|
|
|
|
for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(parent);
|
|
|
|
node; node = node->mNext) {
|
|
|
|
if (node->mContent == aContent)
|
|
|
|
return node->mStyle;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::SetUndisplayedContent(nsIContent* aContent,
|
|
|
|
nsStyleContext* aStyleContext)
|
|
|
|
{
|
2009-10-29 14:17:56 -07:00
|
|
|
NS_PRECONDITION(!aStyleContext->GetPseudo(),
|
2009-05-14 18:40:26 -07:00
|
|
|
"Should only have actual elements here");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG_UNDISPLAYED_MAP
|
|
|
|
static int i = 0;
|
|
|
|
printf("SetUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NS_ASSERTION(!GetUndisplayedContent(aContent),
|
|
|
|
"Already have an undisplayed context entry for aContent");
|
|
|
|
|
|
|
|
if (! mUndisplayedMap) {
|
|
|
|
mUndisplayedMap = new UndisplayedMap;
|
|
|
|
}
|
2011-04-28 22:02:40 -07:00
|
|
|
nsIContent* parent = aContent->GetParent();
|
|
|
|
NS_ASSERTION(parent || (mPresShell && mPresShell->GetDocument() &&
|
|
|
|
mPresShell->GetDocument()->GetRootElement() == aContent),
|
|
|
|
"undisplayed content must have a parent, unless it's the root "
|
|
|
|
"element");
|
|
|
|
mUndisplayedMap->AddNodeFor(parent, aContent, aStyleContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::ChangeUndisplayedContent(nsIContent* aContent,
|
|
|
|
nsStyleContext* aStyleContext)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mUndisplayedMap, "no existing undisplayed content");
|
|
|
|
|
|
|
|
#ifdef DEBUG_UNDISPLAYED_MAP
|
|
|
|
static int i = 0;
|
|
|
|
printf("ChangeUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aContent->GetParent());
|
|
|
|
node; node = node->mNext) {
|
|
|
|
if (node->mContent == aContent) {
|
|
|
|
node->mStyle = aStyleContext;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_NOTREACHED("no existing undisplayed content");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
|
|
|
|
nsIContent* aParentContent)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_UNDISPLAYED_MAP
|
|
|
|
static int i = 0;
|
|
|
|
printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (mUndisplayedMap) {
|
|
|
|
UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
|
|
|
|
while (node) {
|
|
|
|
if (node->mContent == aContent) {
|
|
|
|
mUndisplayedMap->RemoveNodeFor(aParentContent, node);
|
|
|
|
|
|
|
|
#ifdef DEBUG_UNDISPLAYED_MAP
|
|
|
|
printf( "REMOVED!\n");
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
|
|
// make sure that there are no more entries for the same content
|
|
|
|
nsStyleContext *context = GetUndisplayedContent(aContent);
|
|
|
|
NS_ASSERTION(context == nsnull, "Found more undisplayed content data after removal");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
node = node->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_UNDISPLAYED_MAP
|
|
|
|
static int i = 0;
|
|
|
|
printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i++, (void*)aParentContent);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (mUndisplayedMap) {
|
|
|
|
mUndisplayedMap->RemoveNodesFor(aParentContent);
|
|
|
|
}
|
2009-08-07 12:51:25 -07:00
|
|
|
|
|
|
|
// Need to look at aParentContent's content list due to XBL insertions.
|
|
|
|
// Nodes in aParentContent's content list do not have aParentContent as a
|
|
|
|
// parent, but are treated as children of aParentContent. We get access to
|
|
|
|
// the content list via GetXBLChildNodesFor and just ignore any nodes we
|
|
|
|
// don't care about.
|
|
|
|
nsINodeList* list =
|
2011-10-18 03:53:36 -07:00
|
|
|
aParentContent->OwnerDoc()->BindingManager()->GetXBLChildNodesFor(aParentContent);
|
2009-08-07 12:51:25 -07:00
|
|
|
if (list) {
|
|
|
|
PRUint32 length;
|
|
|
|
list->GetLength(&length);
|
|
|
|
for (PRUint32 i = 0; i < length; ++i) {
|
|
|
|
nsIContent* child = list->GetNodeAt(i);
|
|
|
|
if (child->GetParent() != aParentContent) {
|
|
|
|
ClearUndisplayedContentIn(child, child->GetParent());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2011-04-29 16:02:33 -07:00
|
|
|
nsresult
|
|
|
|
nsFrameManager::AppendFrames(nsIFrame* aParentFrame,
|
|
|
|
ChildListID aListID,
|
|
|
|
nsFrameList& aFrameList)
|
|
|
|
{
|
|
|
|
if (aParentFrame->IsAbsoluteContainer() &&
|
|
|
|
aListID == aParentFrame->GetAbsoluteListID()) {
|
|
|
|
return aParentFrame->GetAbsoluteContainingBlock()->
|
|
|
|
AppendFrames(aParentFrame, aListID, aFrameList);
|
|
|
|
} else {
|
|
|
|
return aParentFrame->AppendFrames(aListID, aFrameList);
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsFrameManager::InsertFrames(nsIFrame* aParentFrame,
|
2011-08-24 13:54:30 -07:00
|
|
|
ChildListID aListID,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIFrame* aPrevFrame,
|
2009-07-30 10:23:32 -07:00
|
|
|
nsFrameList& aFrameList)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-11-12 11:05:42 -08:00
|
|
|
NS_PRECONDITION(!aPrevFrame || (!aPrevFrame->GetNextContinuation()
|
2012-01-03 16:44:07 -08:00
|
|
|
|| (aPrevFrame->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))
|
|
|
|
&& !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
|
2007-03-22 10:30:00 -07:00
|
|
|
"aPrevFrame must be the last continuation in its chain!");
|
|
|
|
|
2011-04-29 16:02:33 -07:00
|
|
|
if (aParentFrame->IsAbsoluteContainer() &&
|
|
|
|
aListID == aParentFrame->GetAbsoluteListID()) {
|
|
|
|
return aParentFrame->GetAbsoluteContainingBlock()->
|
|
|
|
InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
|
|
|
|
} else {
|
|
|
|
return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-08-24 13:54:30 -07:00
|
|
|
nsFrameManager::RemoveFrame(ChildListID aListID,
|
2012-07-03 17:24:55 -07:00
|
|
|
nsIFrame* aOldFrame,
|
|
|
|
bool aInvalidate /* = true */)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
bool wasDestroyingFrames = mIsDestroyingFrames;
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsDestroyingFrames = true;
|
2008-12-12 00:25:16 -08:00
|
|
|
|
2012-07-03 17:24:55 -07: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
|
|
|
|
if (aInvalidate) {
|
|
|
|
aOldFrame->InvalidateFrameSubtree();
|
|
|
|
}
|
|
|
|
|
2009-12-23 21:20:41 -08:00
|
|
|
NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
|
|
|
|
// exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
|
|
|
|
aOldFrame->GetType() == nsGkAtoms::textFrame,
|
|
|
|
"Must remove first continuation.");
|
|
|
|
NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
|
|
|
|
GetPlaceholderFrameFor(aOldFrame)),
|
|
|
|
"Must call RemoveFrame on placeholder for out-of-flows.");
|
2011-04-29 16:02:33 -07:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsIFrame* parentFrame = aOldFrame->GetParent();
|
|
|
|
if (parentFrame->IsAbsoluteContainer() &&
|
|
|
|
aListID == parentFrame->GetAbsoluteListID()) {
|
|
|
|
parentFrame->GetAbsoluteContainingBlock()->
|
|
|
|
RemoveFrame(parentFrame, aListID, aOldFrame);
|
|
|
|
} else {
|
|
|
|
rv = parentFrame->RemoveFrame(aListID, aOldFrame);
|
|
|
|
}
|
2008-12-12 00:25:16 -08:00
|
|
|
|
2008-10-12 15:05:04 -07:00
|
|
|
mIsDestroyingFrames = wasDestroyingFrames;
|
2008-12-12 00:25:16 -08:00
|
|
|
|
2008-10-12 15:05:04 -07:00
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
|
|
|
|
{
|
2009-12-23 21:20:41 -08:00
|
|
|
nsIContent* content = aFrame->GetContent();
|
2009-12-29 12:13:54 -08:00
|
|
|
if (content && content->GetPrimaryFrame() == aFrame) {
|
|
|
|
ClearAllUndisplayedContentIn(content);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-25 12:59:42 -07:00
|
|
|
#ifdef DEBUG
|
2007-03-22 10:30:00 -07:00
|
|
|
static void
|
|
|
|
DumpContext(nsIFrame* aFrame, nsStyleContext* aContext)
|
|
|
|
{
|
|
|
|
if (aFrame) {
|
|
|
|
fputs("frame: ", stdout);
|
|
|
|
nsAutoString name;
|
2009-08-20 14:52:48 -07:00
|
|
|
aFrame->GetFrameName(name);
|
|
|
|
fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
|
2007-07-08 00:08:04 -07:00
|
|
|
fprintf(stdout, " (%p)", static_cast<void*>(aFrame));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
if (aContext) {
|
2007-07-08 00:08:04 -07:00
|
|
|
fprintf(stdout, " style: %p ", static_cast<void*>(aContext));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-10-29 14:17:56 -07:00
|
|
|
nsIAtom* pseudoTag = aContext->GetPseudo();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (pseudoTag) {
|
|
|
|
nsAutoString buffer;
|
|
|
|
pseudoTag->ToString(buffer);
|
|
|
|
fputs(NS_LossyConvertUTF16toASCII(buffer).get(), stdout);
|
|
|
|
fputs(" ", stdout);
|
|
|
|
}
|
2009-03-30 11:08:06 -07:00
|
|
|
fputs("{}\n", stdout);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
VerifySameTree(nsStyleContext* aContext1, nsStyleContext* aContext2)
|
|
|
|
{
|
|
|
|
nsStyleContext* top1 = aContext1;
|
|
|
|
nsStyleContext* top2 = aContext2;
|
|
|
|
nsStyleContext* parent;
|
|
|
|
for (;;) {
|
|
|
|
parent = top1->GetParent();
|
|
|
|
if (!parent)
|
|
|
|
break;
|
|
|
|
top1 = parent;
|
|
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
parent = top2->GetParent();
|
|
|
|
if (!parent)
|
|
|
|
break;
|
|
|
|
top2 = parent;
|
|
|
|
}
|
2007-10-08 19:45:10 -07:00
|
|
|
NS_ASSERTION(top1 == top2,
|
|
|
|
"Style contexts are not in the same style context tree");
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
VerifyContextParent(nsPresContext* aPresContext, nsIFrame* aFrame,
|
|
|
|
nsStyleContext* aContext, nsStyleContext* aParentContext)
|
|
|
|
{
|
|
|
|
// get the contexts not provided
|
|
|
|
if (!aContext) {
|
|
|
|
aContext = aFrame->GetStyleContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aParentContext) {
|
|
|
|
// Get the correct parent context from the frame
|
|
|
|
// - if the frame is a placeholder, we get the out of flow frame's context
|
|
|
|
// as the parent context instead of asking the frame
|
|
|
|
|
|
|
|
// get the parent context from the frame (indirectly)
|
2011-09-12 09:08:07 -07:00
|
|
|
nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (providerFrame)
|
|
|
|
aParentContext = providerFrame->GetStyleContext();
|
|
|
|
// aParentContext could still be null
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(aContext, "Failure to get required contexts");
|
|
|
|
nsStyleContext* actualParentContext = aContext->GetParent();
|
|
|
|
|
|
|
|
if (aParentContext) {
|
|
|
|
if (aParentContext != actualParentContext) {
|
|
|
|
DumpContext(aFrame, aContext);
|
|
|
|
if (aContext == aParentContext) {
|
2007-10-08 19:45:10 -07:00
|
|
|
NS_ERROR("Using parent's style context");
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
2007-10-08 19:45:10 -07:00
|
|
|
NS_ERROR("Wrong parent style context");
|
2007-03-22 10:30:00 -07:00
|
|
|
fputs("Wrong parent style context: ", stdout);
|
|
|
|
DumpContext(nsnull, actualParentContext);
|
|
|
|
fputs("should be using: ", stdout);
|
|
|
|
DumpContext(nsnull, aParentContext);
|
|
|
|
VerifySameTree(actualParentContext, aParentContext);
|
|
|
|
fputs("\n", stdout);
|
|
|
|
}
|
|
|
|
}
|
2010-06-08 12:58:26 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (actualParentContext) {
|
2007-10-08 19:45:10 -07:00
|
|
|
NS_ERROR("Have parent context and shouldn't");
|
2007-03-22 10:30:00 -07:00
|
|
|
DumpContext(aFrame, aContext);
|
|
|
|
fputs("Has parent context: ", stdout);
|
|
|
|
DumpContext(nsnull, actualParentContext);
|
|
|
|
fputs("Should be null\n\n", stdout);
|
|
|
|
}
|
|
|
|
}
|
2010-06-08 12:58:26 -07:00
|
|
|
|
|
|
|
nsStyleContext* childStyleIfVisited = aContext->GetStyleIfVisited();
|
2010-06-08 21:03:10 -07:00
|
|
|
// Either childStyleIfVisited has aContext->GetParent()->GetStyleIfVisited()
|
|
|
|
// as the parent or it has a different rulenode from aContext _and_ has
|
|
|
|
// aContext->GetParent() as the parent.
|
2010-06-08 12:58:26 -07:00
|
|
|
if (childStyleIfVisited &&
|
|
|
|
!((childStyleIfVisited->GetRuleNode() != aContext->GetRuleNode() &&
|
|
|
|
childStyleIfVisited->GetParent() == aContext->GetParent()) ||
|
2010-06-08 20:36:17 -07:00
|
|
|
childStyleIfVisited->GetParent() ==
|
|
|
|
aContext->GetParent()->GetStyleIfVisited())) {
|
2010-06-08 12:58:26 -07:00
|
|
|
NS_ERROR("Visited style has wrong parent");
|
|
|
|
DumpContext(aFrame, aContext);
|
|
|
|
fputs("\n", stdout);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
VerifyStyleTree(nsPresContext* aPresContext, nsIFrame* aFrame,
|
|
|
|
nsStyleContext* aParentContext)
|
|
|
|
{
|
|
|
|
nsStyleContext* context = aFrame->GetStyleContext();
|
|
|
|
VerifyContextParent(aPresContext, aFrame, context, nsnull);
|
|
|
|
|
2011-08-24 13:54:29 -07:00
|
|
|
nsIFrame::ChildListIterator lists(aFrame);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
|
|
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
|
|
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
|
|
|
nsIFrame* child = childFrames.get();
|
2012-03-16 10:13:14 -07:00
|
|
|
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
|
|
|
|
// only do frames that are in flow
|
2007-03-22 10:30:00 -07:00
|
|
|
if (nsGkAtoms::placeholderFrame == child->GetType()) {
|
|
|
|
// placeholder: first recurse and verify the out of flow frame,
|
|
|
|
// then verify the placeholder's context
|
|
|
|
nsIFrame* outOfFlowFrame =
|
|
|
|
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
|
|
|
|
|
|
|
|
// recurse to out of flow frame, letting the parent context get resolved
|
2012-03-16 10:13:14 -07:00
|
|
|
do {
|
|
|
|
VerifyStyleTree(aPresContext, outOfFlowFrame, nsnull);
|
|
|
|
} while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// verify placeholder using the parent frame's context as
|
|
|
|
// parent context
|
|
|
|
VerifyContextParent(aPresContext, child, nsnull, nsnull);
|
|
|
|
}
|
|
|
|
else { // regular frame
|
|
|
|
VerifyStyleTree(aPresContext, child, nsnull);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-24 13:54:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// do additional contexts
|
|
|
|
PRInt32 contextIndex = -1;
|
|
|
|
while (1) {
|
|
|
|
nsStyleContext* extraContext = aFrame->GetAdditionalStyleContext(++contextIndex);
|
|
|
|
if (extraContext) {
|
|
|
|
VerifyContextParent(aPresContext, aFrame, extraContext, context);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::DebugVerifyStyleTree(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
if (aFrame) {
|
|
|
|
nsStyleContext* context = aFrame->GetStyleContext();
|
|
|
|
nsStyleContext* parentContext = context->GetParent();
|
|
|
|
VerifyStyleTree(GetPresContext(), aFrame, parentContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
2009-10-07 20:22:42 -07:00
|
|
|
// aContent must be the content for the frame in question, which may be
|
|
|
|
// :before/:after content
|
|
|
|
static void
|
|
|
|
TryStartingTransition(nsPresContext *aPresContext, nsIContent *aContent,
|
|
|
|
nsStyleContext *aOldStyleContext,
|
|
|
|
nsRefPtr<nsStyleContext> *aNewStyleContext /* inout */)
|
|
|
|
{
|
2010-05-14 10:04:51 -07:00
|
|
|
if (!aContent || !aContent->IsElement()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-07 20:22:42 -07:00
|
|
|
// Notify the transition manager, and if it starts a transition,
|
|
|
|
// it will give us back a transition-covering style rule which
|
|
|
|
// we'll use to get *another* style context. We want to ignore
|
|
|
|
// any already-running transitions, but cover up any that we're
|
|
|
|
// currently starting with their start value so we don't start
|
|
|
|
// them again for descendants that inherit that value.
|
|
|
|
nsCOMPtr<nsIStyleRule> coverRule =
|
|
|
|
aPresContext->TransitionManager()->StyleContextChanged(
|
2010-05-14 10:04:51 -07:00
|
|
|
aContent->AsElement(), aOldStyleContext, *aNewStyleContext);
|
2009-10-07 20:22:42 -07:00
|
|
|
if (coverRule) {
|
|
|
|
nsCOMArray<nsIStyleRule> rules;
|
|
|
|
rules.AppendObject(coverRule);
|
2010-04-02 18:58:25 -07:00
|
|
|
*aNewStyleContext = aPresContext->StyleSet()->
|
|
|
|
ResolveStyleByAddingRules(*aNewStyleContext, rules);
|
2009-10-07 20:22:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-22 21:46:27 -07:00
|
|
|
static inline Element*
|
|
|
|
ElementForStyleContext(nsIContent* aParentContent,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsCSSPseudoElements::Type aPseudoType)
|
|
|
|
{
|
|
|
|
// We don't expect XUL tree stuff here.
|
|
|
|
NS_PRECONDITION(aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
|
|
|
|
aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox ||
|
|
|
|
aPseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
|
|
|
|
"Unexpected pseudo");
|
|
|
|
// XXX see the comments about the various element confusion in
|
|
|
|
// ReResolveStyleContext.
|
|
|
|
if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
|
|
|
return aFrame->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter) {
|
|
|
|
NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame,
|
|
|
|
"firstLetter pseudoTag without a nsFirstLetterFrame");
|
|
|
|
nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame);
|
|
|
|
return block->GetContent()->AsElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent* content = aParentContent ? aParentContent : aFrame->GetContent();
|
|
|
|
return content->AsElement();
|
|
|
|
}
|
|
|
|
|
2011-08-11 20:52:21 -07:00
|
|
|
static nsIFrame*
|
|
|
|
GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
// Account for {ib} splits when looking for "prevContinuation". In
|
|
|
|
// particular, for the first-continuation of a part of an {ib} split we
|
|
|
|
// want to use the special prevsibling of the special prevsibling of
|
|
|
|
// aFrame, which should have the same style context as aFrame itself.
|
|
|
|
// In particular, if aFrame is the first continuation of an inline part
|
|
|
|
// of an {ib} split then its special prevsibling is a block, and the
|
|
|
|
// special prevsibling of _that_ is an inline, just like aFrame.
|
|
|
|
// Similarly, if aFrame is the first continuation of a block part of an
|
|
|
|
// {ib} split (an {ib} wrapper block), then its special prevsibling is
|
|
|
|
// an inline and the special prevsibling of that is either another {ib}
|
|
|
|
// wrapper block block or null.
|
|
|
|
nsIFrame *prevContinuation = aFrame->GetPrevContinuation();
|
|
|
|
if (!prevContinuation && (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
|
|
|
|
// We're the first continuation, so we can just get the frame
|
|
|
|
// property directly
|
|
|
|
prevContinuation = static_cast<nsIFrame*>(
|
|
|
|
aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
|
|
|
|
if (prevContinuation) {
|
|
|
|
prevContinuation = static_cast<nsIFrame*>(
|
|
|
|
prevContinuation->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return prevContinuation;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
2010-04-01 23:07:43 -07:00
|
|
|
nsFrameManager::ReparentStyleContext(nsIFrame* aFrame)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-11-07 09:13:00 -08:00
|
|
|
if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
|
2010-08-10 15:04:43 -07:00
|
|
|
// Also reparent the out-of-flow and all its continuations.
|
2007-11-07 09:13:00 -08:00
|
|
|
nsIFrame* outOfFlow =
|
|
|
|
nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
|
|
|
|
NS_ASSERTION(outOfFlow, "no out-of-flow frame");
|
2010-08-10 15:04:43 -07:00
|
|
|
do {
|
|
|
|
ReparentStyleContext(outOfFlow);
|
2011-02-16 05:14:14 -08:00
|
|
|
} while ((outOfFlow = outOfFlow->GetNextContinuation()));
|
2007-11-07 09:13:00 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// DO NOT verify the style tree before reparenting. The frame
|
|
|
|
// tree has already been changed, so this check would just fail.
|
|
|
|
nsStyleContext* oldContext = aFrame->GetStyleContext();
|
|
|
|
// XXXbz can oldContext really ever be null?
|
|
|
|
if (oldContext) {
|
|
|
|
nsRefPtr<nsStyleContext> newContext;
|
2011-09-12 09:08:07 -07:00
|
|
|
nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame();
|
|
|
|
bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsStyleContext* newParentContext = nsnull;
|
2011-09-12 09:08:07 -07:00
|
|
|
nsIFrame* providerChild = nsnull;
|
|
|
|
if (isChild) {
|
2010-04-01 23:07:43 -07:00
|
|
|
ReparentStyleContext(providerFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
newParentContext = providerFrame->GetStyleContext();
|
|
|
|
providerChild = providerFrame;
|
|
|
|
} else if (providerFrame) {
|
|
|
|
newParentContext = providerFrame->GetStyleContext();
|
|
|
|
} else {
|
|
|
|
NS_NOTREACHED("Reparenting something that has no usable parent? "
|
|
|
|
"Shouldn't happen!");
|
|
|
|
}
|
2009-09-18 11:00:21 -07:00
|
|
|
// XXX need to do something here to produce the correct style context for
|
|
|
|
// an IB split whose first inline part is inside a first-line frame.
|
|
|
|
// Currently the first IB anonymous block's style context takes the first
|
|
|
|
// part's style context as parent, which is wrong since first-line style
|
|
|
|
// should not apply to the anonymous block.
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-10-17 07:31:47 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
|
|
// Check that our assumption that continuations of the same
|
|
|
|
// pseudo-type and with the same style context parent have the
|
|
|
|
// same style context is valid before the reresolution. (We need
|
|
|
|
// to check the pseudo-type and style context parent because of
|
|
|
|
// :first-letter and :first-line, where we create styled and
|
|
|
|
// unstyled letter/line frames distinguished by pseudo-type, and
|
|
|
|
// then need to distinguish their descendants based on having
|
|
|
|
// different parents.)
|
|
|
|
nsIFrame *nextContinuation = aFrame->GetNextContinuation();
|
|
|
|
if (nextContinuation) {
|
|
|
|
nsStyleContext *nextContinuationContext =
|
|
|
|
nextContinuation->GetStyleContext();
|
|
|
|
NS_ASSERTION(oldContext == nextContinuationContext ||
|
2009-10-29 14:17:56 -07:00
|
|
|
oldContext->GetPseudo() !=
|
|
|
|
nextContinuationContext->GetPseudo() ||
|
2009-10-17 07:31:47 -07:00
|
|
|
oldContext->GetParent() !=
|
|
|
|
nextContinuationContext->GetParent(),
|
|
|
|
"continuations should have the same style context");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-08-11 20:52:21 -07:00
|
|
|
nsIFrame *prevContinuation =
|
|
|
|
GetPrevContinuationWithPossiblySameStyle(aFrame);
|
2009-10-17 07:31:47 -07:00
|
|
|
nsStyleContext *prevContinuationContext;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool copyFromContinuation =
|
2009-10-17 07:31:47 -07:00
|
|
|
prevContinuation &&
|
|
|
|
(prevContinuationContext = prevContinuation->GetStyleContext())
|
2009-10-29 14:17:56 -07:00
|
|
|
->GetPseudo() == oldContext->GetPseudo() &&
|
2009-10-17 07:31:47 -07:00
|
|
|
prevContinuationContext->GetParent() == newParentContext;
|
|
|
|
if (copyFromContinuation) {
|
|
|
|
// Just use the style context from the frame's previous
|
|
|
|
// continuation (see assertion about aFrame->GetNextContinuation()
|
|
|
|
// above, which we would have previously hit for aFrame's previous
|
|
|
|
// continuation).
|
|
|
|
newContext = prevContinuationContext;
|
|
|
|
} else {
|
2010-06-22 21:46:27 -07:00
|
|
|
nsIFrame* parentFrame = aFrame->GetParent();
|
|
|
|
Element* element =
|
|
|
|
ElementForStyleContext(parentFrame ? parentFrame->GetContent() : nsnull,
|
|
|
|
aFrame,
|
|
|
|
oldContext->GetPseudoType());
|
2010-04-01 23:07:42 -07:00
|
|
|
newContext = mStyleSet->ReparentStyleContext(oldContext,
|
2010-06-22 21:46:27 -07:00
|
|
|
newParentContext,
|
|
|
|
element);
|
2009-10-17 07:31:47 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (newContext) {
|
|
|
|
if (newContext != oldContext) {
|
2009-10-07 20:22:42 -07:00
|
|
|
// We probably don't want to initiate transitions from
|
2010-04-01 23:07:43 -07:00
|
|
|
// ReparentStyleContext, since we call it during frame
|
2009-10-07 20:22:42 -07:00
|
|
|
// construction rather than in response to dynamic changes.
|
|
|
|
// Also see the comment at the start of
|
|
|
|
// nsTransitionManager::ConsiderStartingTransition.
|
|
|
|
#if 0
|
2009-10-17 07:31:47 -07:00
|
|
|
if (!copyFromContinuation) {
|
2010-04-01 23:07:42 -07:00
|
|
|
TryStartingTransition(GetPresContext(), aFrame->GetContent(),
|
2009-10-17 07:31:47 -07:00
|
|
|
oldContext, &newContext);
|
|
|
|
}
|
2009-10-07 20:22:42 -07:00
|
|
|
#endif
|
|
|
|
|
2007-11-07 09:13:00 -08:00
|
|
|
// Make sure to call CalcStyleDifference so that the new context ends
|
|
|
|
// up resolving all the structs the old context resolved.
|
|
|
|
nsChangeHint styleChange = oldContext->CalcStyleDifference(newContext);
|
|
|
|
// The style change is always 0 because we have the same rulenode and
|
|
|
|
// CalcStyleDifference optimizes us away. That's OK, though:
|
|
|
|
// reparenting should never trigger a frame reconstruct, and whenever
|
|
|
|
// it's happening we already plan to reflow and repaint the frames.
|
|
|
|
NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
|
|
|
|
"Our frame tree is likely to be bogus!");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
aFrame->SetStyleContext(newContext);
|
|
|
|
|
2011-08-24 13:54:29 -07:00
|
|
|
nsIFrame::ChildListIterator lists(aFrame);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
|
|
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
|
|
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
|
|
|
nsIFrame* child = childFrames.get();
|
2012-03-16 10:13:14 -07:00
|
|
|
// only do frames that are in flow
|
|
|
|
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
|
2007-11-07 09:13:00 -08:00
|
|
|
child != providerChild) {
|
|
|
|
#ifdef DEBUG
|
2007-03-22 10:30:00 -07:00
|
|
|
if (nsGkAtoms::placeholderFrame == child->GetType()) {
|
|
|
|
nsIFrame* outOfFlowFrame =
|
|
|
|
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
|
|
|
|
NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
|
|
|
|
|
|
|
|
NS_ASSERTION(outOfFlowFrame != providerChild,
|
|
|
|
"Out of flow provider?");
|
|
|
|
}
|
2007-11-07 09:13:00 -08:00
|
|
|
#endif
|
2010-04-01 23:07:43 -07:00
|
|
|
ReparentStyleContext(child);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2011-08-24 13:54:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// If this frame is part of an IB split, then the style context of
|
|
|
|
// the next part of the split might be a child of our style context.
|
|
|
|
// Reparent its style context just in case one of our ancestors
|
|
|
|
// (split or not) hasn't done so already). It's not a problem to
|
|
|
|
// reparent the same frame twice because the "if (newContext !=
|
|
|
|
// oldContext)" check will prevent us from redoing work.
|
|
|
|
if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
|
2009-09-18 11:00:20 -07:00
|
|
|
!aFrame->GetPrevContinuation()) {
|
2010-03-28 18:46:55 -07:00
|
|
|
nsIFrame* sib = static_cast<nsIFrame*>
|
|
|
|
(aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (sib) {
|
2010-04-01 23:07:43 -07:00
|
|
|
ReparentStyleContext(sib);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do additional contexts
|
|
|
|
PRInt32 contextIndex = -1;
|
|
|
|
while (1) {
|
|
|
|
nsStyleContext* oldExtraContext =
|
|
|
|
aFrame->GetAdditionalStyleContext(++contextIndex);
|
|
|
|
if (oldExtraContext) {
|
|
|
|
nsRefPtr<nsStyleContext> newExtraContext;
|
2010-04-01 23:07:42 -07:00
|
|
|
newExtraContext = mStyleSet->ReparentStyleContext(oldExtraContext,
|
2010-06-22 21:46:27 -07:00
|
|
|
newContext,
|
|
|
|
nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (newExtraContext) {
|
2007-11-07 09:13:00 -08:00
|
|
|
if (newExtraContext != oldExtraContext) {
|
|
|
|
// Make sure to call CalcStyleDifference so that the new
|
|
|
|
// context ends up resolving all the structs the old context
|
|
|
|
// resolved.
|
|
|
|
styleChange =
|
|
|
|
oldExtraContext->CalcStyleDifference(newExtraContext);
|
|
|
|
// The style change is always 0 because we have the same
|
|
|
|
// rulenode and CalcStyleDifference optimizes us away. That's
|
|
|
|
// OK, though: reparenting should never trigger a frame
|
|
|
|
// reconstruct, and whenever it's happening we already plan to
|
|
|
|
// reflow and repaint the frames.
|
|
|
|
NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
|
|
|
|
"Our frame tree is likely to be bogus!");
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
VerifyStyleTree(GetPresContext(), aFrame, newParentContext);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsChangeHint
|
|
|
|
CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext,
|
|
|
|
nsIFrame* aFrame, nsIContent* aContent,
|
|
|
|
nsStyleChangeList* aChangeList, nsChangeHint aMinChange,
|
|
|
|
nsChangeHint aChangeToAssume)
|
|
|
|
{
|
|
|
|
nsChangeHint ourChange = aOldContext->CalcStyleDifference(aNewContext);
|
2009-08-10 07:54:21 -07:00
|
|
|
NS_ASSERTION(!(ourChange & nsChangeHint_ReflowFrame) ||
|
|
|
|
(ourChange & nsChangeHint_NeedReflow),
|
|
|
|
"Reflow hint bits set without actually asking for a reflow");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_UpdateHint(ourChange, aChangeToAssume);
|
|
|
|
if (NS_UpdateHint(aMinChange, ourChange)) {
|
2010-12-15 12:26:54 -08:00
|
|
|
if (!(ourChange & nsChangeHint_ReconstructFrame) || aContent) {
|
|
|
|
aChangeList->AppendChange(aFrame, aContent, ourChange);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return aMinChange;
|
|
|
|
}
|
|
|
|
|
2008-12-29 07:07:37 -08:00
|
|
|
/**
|
|
|
|
* Recompute style for aFrame and accumulate changes into aChangeList
|
|
|
|
* given that aMinChange is already accumulated for an ancestor.
|
|
|
|
* aParentContent is the content node used to resolve the parent style
|
|
|
|
* context. This means that, for pseudo-elements, it is the content
|
|
|
|
* that should be used for selector matching (rather than the fake
|
|
|
|
* content node attached to the frame).
|
|
|
|
*/
|
2007-03-22 10:30:00 -07:00
|
|
|
nsChangeHint
|
2008-12-29 07:07:37 -08:00
|
|
|
nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIFrame *aFrame,
|
|
|
|
nsIContent *aParentContent,
|
|
|
|
nsStyleChangeList *aChangeList,
|
2009-07-30 00:55:51 -07:00
|
|
|
nsChangeHint aMinChange,
|
2010-06-18 09:23:05 -07:00
|
|
|
nsRestyleHint aRestyleHint,
|
2010-11-13 09:49:26 -08:00
|
|
|
RestyleTracker& aRestyleTracker,
|
|
|
|
DesiredA11yNotifications aDesiredA11yNotifications,
|
2011-05-24 17:19:09 -07:00
|
|
|
nsTArray<nsIContent*>& aVisibleKidsOfHiddenElement,
|
|
|
|
TreeMatchContext &aTreeMatchContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-08-03 18:22:13 -07:00
|
|
|
if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aMinChange)) {
|
2009-08-10 07:54:21 -07:00
|
|
|
// If aMinChange doesn't include nsChangeHint_NeedDirtyReflow, clear out
|
|
|
|
// all the reflow change bits from it, so that we'll make sure to append a
|
|
|
|
// change to the list for ourselves if we need a reflow. We need this
|
|
|
|
// because the parent may or may not actually end up reflowing us
|
|
|
|
// otherwise.
|
|
|
|
aMinChange = NS_SubtractHint(aMinChange, nsChangeHint_ReflowFrame);
|
|
|
|
} else if (!NS_IsHintSubset(nsChangeHint_ClearDescendantIntrinsics,
|
|
|
|
aMinChange)) {
|
|
|
|
// If aMinChange doesn't include nsChangeHint_ClearDescendantIntrinsics,
|
|
|
|
// clear out the nsChangeHint_ClearAncestorIntrinsics flag, since it's
|
|
|
|
// possible that we had some random ancestor that cleared ancestor
|
|
|
|
// intrinsic widths, but we still need to clear intrinsic widths on frames
|
|
|
|
// that are our ancestors but its descendants.
|
|
|
|
aMinChange =
|
|
|
|
NS_SubtractHint(aMinChange, nsChangeHint_ClearAncestorIntrinsics);
|
2009-08-03 18:22:13 -07:00
|
|
|
}
|
2010-06-18 09:23:05 -07:00
|
|
|
|
2012-02-07 14:52:59 -08:00
|
|
|
// We need to generate a new change list entry for every frame whose style
|
|
|
|
// comparision returns one of these hints. These hints don't automatically
|
|
|
|
// update all their descendant frames.
|
Bug 157681 - Part 2: Optimize positioned frame offset changes by moving the frame as opposed to reflowing it in case we know that the size of the frame will not change; r=dbaron
This patch adds a change hint to signal that one of the offsets on a
frame has been changed. When processing the hint, we do one of the
following things based on the position property of the frame.
* For static frames, we ignore the offset changes completely, as they
will not change the layout.
* For relative positioned frames, this patch refactors the
nsHTMLReflowState::ComputeRelativeOffsets function so that it can be
used from other callers, and it uses that to compute the new relative
offsets, and uses the offsets computed previously to compute the new
position of the frame.
* For absolute positioned frames, we set up a fake parent reflow state
object, and then we create a new reflow state object for the frame in
question. This setup is similar to what nsFrame::BoxReflow does.
Once we have the new reflow state object, we use it to compute the
absolute offsets, and then we use the computed offsets to set the new
position of the frame. The offset computation is similar to what
nsAbsoluteContainingBlock::ReflowAbsoluteFrame does. In some cases
where it is possible for the dimensions of the frame to change based
on the offset changes, we fall back to a full reflow.
2012-06-05 21:53:48 -07:00
|
|
|
aMinChange = NS_SubtractHint(aMinChange, nsChangeHint_NonInherited_Hints);
|
2012-02-07 03:31:47 -08:00
|
|
|
|
2009-01-29 12:39:19 -08:00
|
|
|
// It would be nice if we could make stronger assertions here; they
|
|
|
|
// would let us simplify the ?: expressions below setting |content|
|
|
|
|
// and |pseudoContent| in sensible ways as well as making what
|
|
|
|
// |localContent|, |content|, and |pseudoContent| mean make more
|
|
|
|
// sense. However, we can't, because of frame trees like the one in
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=472353#c14 . Once we
|
|
|
|
// fix bug 242277 we should be able to make this make more sense.
|
|
|
|
NS_ASSERTION(aFrame->GetContent() || !aParentContent ||
|
|
|
|
!aParentContent->GetParent(),
|
|
|
|
"frame must have content (unless at the top of the tree)");
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXXldb get new context from prev-in-flow if possible, to avoid
|
|
|
|
// duplication. (Or should we just let |GetContext| handle that?)
|
|
|
|
// Getting the hint would be nice too, but that's harder.
|
|
|
|
|
|
|
|
// XXXbryner we may be able to avoid some of the refcounting goop here.
|
|
|
|
// We do need a reference to oldContext for the lifetime of this function, and it's possible
|
|
|
|
// that the frame has the last reference to it, so AddRef it here.
|
|
|
|
|
|
|
|
nsChangeHint assumeDifferenceHint = NS_STYLE_HINT_NONE;
|
2007-10-03 19:58:48 -07:00
|
|
|
// XXXbz oldContext should just be an nsRefPtr
|
2007-03-22 10:30:00 -07:00
|
|
|
nsStyleContext* oldContext = aFrame->GetStyleContext();
|
|
|
|
nsStyleSet* styleSet = aPresContext->StyleSet();
|
|
|
|
|
2007-10-03 19:58:48 -07:00
|
|
|
// XXXbz the nsIFrame constructor takes an nsStyleContext, so how
|
|
|
|
// could oldContext be null?
|
2007-03-22 10:30:00 -07:00
|
|
|
if (oldContext) {
|
|
|
|
oldContext->AddRef();
|
2010-11-13 09:49:26 -08:00
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
2011-09-28 23:19:26 -07:00
|
|
|
bool wasFrameVisible = nsIPresShell::IsAccessibilityActive() ?
|
2011-10-17 07:59:28 -07:00
|
|
|
oldContext->GetStyleVisibility()->IsVisible() : false;
|
2010-11-13 09:49:26 -08:00
|
|
|
#endif
|
|
|
|
|
2009-10-29 14:17:56 -07:00
|
|
|
nsIAtom* const pseudoTag = oldContext->GetPseudo();
|
2009-12-10 23:37:40 -08:00
|
|
|
const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType();
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIContent* localContent = aFrame->GetContent();
|
2008-12-29 07:07:37 -08:00
|
|
|
// |content| is the node that we used for rule matching of
|
|
|
|
// normal elements (not pseudo-elements) and for which we generate
|
|
|
|
// framechange hints if we need them.
|
2009-01-29 12:39:19 -08:00
|
|
|
// XXXldb Why does it make sense to use aParentContent? (See
|
|
|
|
// comment above assertion at start of function.)
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIContent* content = localContent ? localContent : aParentContent;
|
|
|
|
|
2010-06-18 09:23:05 -07:00
|
|
|
if (content && content->IsElement()) {
|
2011-11-13 19:24:41 -08:00
|
|
|
content->OwnerDoc()->FlushPendingLinkUpdates();
|
2010-06-18 09:23:05 -07:00
|
|
|
RestyleTracker::RestyleData restyleData;
|
|
|
|
if (aRestyleTracker.GetRestyleData(content->AsElement(), &restyleData)) {
|
|
|
|
if (NS_UpdateHint(aMinChange, restyleData.mChangeHint)) {
|
|
|
|
aChangeList->AppendChange(aFrame, content, restyleData.mChangeHint);
|
|
|
|
}
|
2010-06-18 09:23:05 -07:00
|
|
|
aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint);
|
2010-06-18 09:23:05 -07:00
|
|
|
}
|
|
|
|
}
|
2010-06-18 09:23:05 -07:00
|
|
|
|
|
|
|
nsRestyleHint childRestyleHint = aRestyleHint;
|
|
|
|
|
|
|
|
if (childRestyleHint == eRestyle_Self) {
|
|
|
|
childRestyleHint = nsRestyleHint(0);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsStyleContext* parentContext;
|
|
|
|
nsIFrame* resolvedChild = nsnull;
|
|
|
|
// Get the frame providing the parent style context. If it is a
|
|
|
|
// child, then resolve the provider first.
|
2011-09-12 09:08:07 -07:00
|
|
|
nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame();
|
|
|
|
bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
|
|
|
|
if (!isChild) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (providerFrame)
|
|
|
|
parentContext = providerFrame->GetStyleContext();
|
|
|
|
else
|
|
|
|
parentContext = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
2012-03-12 20:54:15 -07:00
|
|
|
MOZ_ASSERT(providerFrame->GetContent() == aFrame->GetContent(),
|
|
|
|
"Postcondition for GetParentStyleContextFrame() violated. "
|
|
|
|
"That means we need to add the current element to the "
|
|
|
|
"ancestor filter.");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// resolve the provider here (before aFrame below).
|
|
|
|
|
|
|
|
// assumeDifferenceHint forces the parent's change to be also
|
|
|
|
// applied to this frame, no matter what
|
2008-01-10 12:56:49 -08:00
|
|
|
// nsStyleContext::CalcStyleDifference says. CalcStyleDifference
|
2007-03-22 10:30:00 -07:00
|
|
|
// can't be trusted because it assumes any changes to the parent
|
|
|
|
// style context provider will be automatically propagated to
|
|
|
|
// the frame(s) with child style contexts.
|
2009-07-30 00:55:51 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
assumeDifferenceHint = ReResolveStyleContext(aPresContext, providerFrame,
|
2008-12-29 07:07:37 -08:00
|
|
|
aParentContent, aChangeList,
|
2010-06-18 09:23:05 -07:00
|
|
|
aMinChange, aRestyleHint,
|
2010-11-13 09:49:26 -08:00
|
|
|
aRestyleTracker,
|
|
|
|
aDesiredA11yNotifications,
|
2011-05-24 17:19:09 -07:00
|
|
|
aVisibleKidsOfHiddenElement,
|
|
|
|
aTreeMatchContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// The provider's new context becomes the parent context of
|
|
|
|
// aFrame's context.
|
|
|
|
parentContext = providerFrame->GetStyleContext();
|
|
|
|
// Set |resolvedChild| so we don't bother resolving the
|
|
|
|
// provider again.
|
|
|
|
resolvedChild = providerFrame;
|
|
|
|
}
|
2009-10-17 07:31:47 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
|
|
// Check that our assumption that continuations of the same
|
|
|
|
// pseudo-type and with the same style context parent have the
|
|
|
|
// same style context is valid before the reresolution. (We need
|
|
|
|
// to check the pseudo-type and style context parent because of
|
|
|
|
// :first-letter and :first-line, where we create styled and
|
|
|
|
// unstyled letter/line frames distinguished by pseudo-type, and
|
|
|
|
// then need to distinguish their descendants based on having
|
|
|
|
// different parents.)
|
|
|
|
nsIFrame *nextContinuation = aFrame->GetNextContinuation();
|
|
|
|
if (nextContinuation) {
|
|
|
|
nsStyleContext *nextContinuationContext =
|
|
|
|
nextContinuation->GetStyleContext();
|
|
|
|
NS_ASSERTION(oldContext == nextContinuationContext ||
|
2009-10-29 14:17:56 -07:00
|
|
|
oldContext->GetPseudo() !=
|
|
|
|
nextContinuationContext->GetPseudo() ||
|
2009-10-17 07:31:47 -07:00
|
|
|
oldContext->GetParent() !=
|
|
|
|
nextContinuationContext->GetParent(),
|
|
|
|
"continuations should have the same style context");
|
|
|
|
}
|
2011-08-11 20:52:21 -07:00
|
|
|
// And assert the same thing for {ib} splits. See the comments in
|
|
|
|
// GetPrevContinuationWithPossiblySameStyle for an explanation of
|
|
|
|
// why we step two forward in the special sibling chain.
|
|
|
|
if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
|
|
|
|
!aFrame->GetPrevContinuation()) {
|
|
|
|
nsIFrame *nextIBSibling = static_cast<nsIFrame*>(
|
|
|
|
aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
|
|
|
|
if (nextIBSibling) {
|
|
|
|
nextIBSibling = static_cast<nsIFrame*>(
|
|
|
|
nextIBSibling->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
|
|
|
|
}
|
|
|
|
if (nextIBSibling) {
|
|
|
|
nsStyleContext *nextIBSiblingContext =
|
|
|
|
nextIBSibling->GetStyleContext();
|
|
|
|
NS_ASSERTION(oldContext == nextIBSiblingContext ||
|
|
|
|
oldContext->GetPseudo() !=
|
|
|
|
nextIBSiblingContext->GetPseudo() ||
|
|
|
|
oldContext->GetParent() !=
|
|
|
|
nextIBSiblingContext->GetParent(),
|
|
|
|
"continuations should have the same style context");
|
|
|
|
}
|
|
|
|
}
|
2009-10-17 07:31:47 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// do primary context
|
2009-09-11 03:46:36 -07:00
|
|
|
nsRefPtr<nsStyleContext> newContext;
|
2011-08-11 20:52:21 -07:00
|
|
|
nsIFrame *prevContinuation =
|
|
|
|
GetPrevContinuationWithPossiblySameStyle(aFrame);
|
2009-10-17 07:31:47 -07:00
|
|
|
nsStyleContext *prevContinuationContext;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool copyFromContinuation =
|
2009-10-17 07:31:47 -07:00
|
|
|
prevContinuation &&
|
|
|
|
(prevContinuationContext = prevContinuation->GetStyleContext())
|
2009-10-29 14:17:56 -07:00
|
|
|
->GetPseudo() == oldContext->GetPseudo() &&
|
2009-10-17 07:31:47 -07:00
|
|
|
prevContinuationContext->GetParent() == parentContext;
|
|
|
|
if (copyFromContinuation) {
|
|
|
|
// Just use the style context from the frame's previous
|
|
|
|
// continuation (see assertion about aFrame->GetNextContinuation()
|
|
|
|
// above, which we would have previously hit for aFrame's previous
|
|
|
|
// continuation).
|
|
|
|
newContext = prevContinuationContext;
|
|
|
|
}
|
|
|
|
else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(localContent,
|
|
|
|
"non pseudo-element frame without content node");
|
2009-09-11 03:46:36 -07:00
|
|
|
newContext = styleSet->ResolveStyleForNonElement(parentContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-08-11 20:52:21 -07:00
|
|
|
else if (!aRestyleHint && !prevContinuation) {
|
|
|
|
// Unfortunately, if prevContinuation is non-null then we may have
|
|
|
|
// already stolen the restyle tracker entry for this element while
|
|
|
|
// processing prevContinuation. So we don't know whether aRestyleHint
|
|
|
|
// should really be 0 here or whether it should be eRestyle_Self. Be
|
|
|
|
// pessimistic and force an actual reresolve in that situation. The good
|
|
|
|
// news is that in the common case when prevContinuation is non-null we
|
|
|
|
// just used prevContinuationContext anyway and aren't reaching this code
|
|
|
|
// to start with.
|
2010-06-22 21:46:27 -07:00
|
|
|
newContext =
|
|
|
|
styleSet->ReparentStyleContext(oldContext, parentContext,
|
|
|
|
ElementForStyleContext(aParentContent,
|
|
|
|
aFrame,
|
|
|
|
pseudoType));
|
|
|
|
} else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
|
|
|
|
newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag,
|
|
|
|
parentContext);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Element* element = ElementForStyleContext(aParentContent,
|
|
|
|
aFrame,
|
|
|
|
pseudoType);
|
|
|
|
if (pseudoTag) {
|
|
|
|
if (pseudoTag == nsCSSPseudoElements::before ||
|
|
|
|
pseudoTag == nsCSSPseudoElements::after) {
|
|
|
|
// XXX what other pseudos do we need to treat like this?
|
|
|
|
newContext = styleSet->ProbePseudoElementStyle(element,
|
2009-12-10 23:37:40 -08:00
|
|
|
pseudoType,
|
2011-05-24 17:19:09 -07:00
|
|
|
parentContext,
|
|
|
|
aTreeMatchContext);
|
2010-06-22 21:46:27 -07:00
|
|
|
if (!newContext) {
|
|
|
|
// This pseudo should no longer exist; gotta reframe
|
|
|
|
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
|
|
|
|
aChangeList->AppendChange(aFrame, element,
|
|
|
|
nsChangeHint_ReconstructFrame);
|
|
|
|
// We're reframing anyway; just keep the same context
|
|
|
|
newContext = oldContext;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Don't expect XUL tree stuff here, since it needs a comparator and
|
|
|
|
// all.
|
|
|
|
NS_ASSERTION(pseudoType <
|
|
|
|
nsCSSPseudoElements::ePseudo_PseudoElementCount,
|
|
|
|
"Unexpected pseudo type");
|
|
|
|
newContext = styleSet->ResolvePseudoElementStyle(element,
|
|
|
|
pseudoType,
|
|
|
|
parentContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ASSERTION(localContent,
|
|
|
|
"non pseudo-element frame without content node");
|
2011-05-24 17:19:09 -07:00
|
|
|
newContext = styleSet->ResolveStyleFor(element, parentContext,
|
|
|
|
aTreeMatchContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2010-06-18 09:23:05 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(newContext, "failed to get new style context");
|
|
|
|
if (newContext) {
|
|
|
|
if (!parentContext) {
|
2011-04-22 18:36:24 -07:00
|
|
|
if (oldContext->GetRuleNode() == newContext->GetRuleNode() &&
|
|
|
|
oldContext->IsLinkContext() == newContext->IsLinkContext() &&
|
|
|
|
oldContext->RelevantLinkVisited() ==
|
|
|
|
newContext->RelevantLinkVisited()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// We're the root of the style context tree and the new style
|
|
|
|
// context returned has the same rule node. This means that
|
|
|
|
// we can use FindChildWithRules to keep a lot of the old
|
|
|
|
// style contexts around. However, we need to start from the
|
|
|
|
// same root.
|
|
|
|
newContext = oldContext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newContext != oldContext) {
|
2009-10-17 07:31:47 -07:00
|
|
|
if (!copyFromContinuation) {
|
|
|
|
TryStartingTransition(aPresContext, aFrame->GetContent(),
|
|
|
|
oldContext, &newContext);
|
|
|
|
}
|
2009-10-07 20:22:42 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
aMinChange = CaptureChange(oldContext, newContext, aFrame,
|
|
|
|
content, aChangeList, aMinChange,
|
|
|
|
assumeDifferenceHint);
|
|
|
|
if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
|
|
|
|
// if frame gets regenerated, let it keep old context
|
|
|
|
aFrame->SetStyleContext(newContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
oldContext->Release();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ERROR("resolve style context failed");
|
2009-09-11 03:46:36 -07:00
|
|
|
newContext = oldContext; // new context failed, recover...
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-06-18 09:23:05 -07:00
|
|
|
// do additional contexts
|
|
|
|
// XXXbz might be able to avoid selector matching here in some
|
|
|
|
// cases; won't worry about it for now.
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 contextIndex = -1;
|
|
|
|
while (1 == 1) {
|
|
|
|
nsStyleContext* oldExtraContext = nsnull;
|
|
|
|
oldExtraContext = aFrame->GetAdditionalStyleContext(++contextIndex);
|
|
|
|
if (oldExtraContext) {
|
2009-09-11 03:46:36 -07:00
|
|
|
nsRefPtr<nsStyleContext> newExtraContext;
|
2009-10-29 14:17:56 -07:00
|
|
|
nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
|
2009-12-10 23:37:40 -08:00
|
|
|
const nsCSSPseudoElements::Type extraPseudoType =
|
|
|
|
oldExtraContext->GetPseudoType();
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(extraPseudoTag &&
|
|
|
|
extraPseudoTag != nsCSSAnonBoxes::mozNonElement,
|
|
|
|
"extra style context is not pseudo element");
|
2009-12-10 23:37:40 -08:00
|
|
|
if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
|
|
|
|
newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag,
|
|
|
|
newContext);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Don't expect XUL tree stuff here, since it needs a comparator and
|
|
|
|
// all.
|
|
|
|
NS_ASSERTION(extraPseudoType <
|
|
|
|
nsCSSPseudoElements::ePseudo_PseudoElementCount,
|
|
|
|
"Unexpected type");
|
2010-04-30 06:12:06 -07:00
|
|
|
newExtraContext = styleSet->ResolvePseudoElementStyle(content->AsElement(),
|
2009-12-10 23:37:40 -08:00
|
|
|
extraPseudoType,
|
|
|
|
newContext);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
if (newExtraContext) {
|
|
|
|
if (oldExtraContext != newExtraContext) {
|
|
|
|
aMinChange = CaptureChange(oldExtraContext, newExtraContext,
|
|
|
|
aFrame, content, aChangeList,
|
|
|
|
aMinChange, assumeDifferenceHint);
|
|
|
|
if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
|
|
|
|
aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now look for undisplayed child content and pseudos
|
2009-01-16 13:32:09 -08:00
|
|
|
|
|
|
|
// When the root element is display:none, we still construct *some*
|
|
|
|
// frames that have the root element as their mContent, down to the
|
|
|
|
// DocElementContainingBlock.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool checkUndisplayed;
|
2009-01-16 13:32:09 -08:00
|
|
|
nsIContent *undisplayedParent;
|
|
|
|
if (pseudoTag) {
|
|
|
|
checkUndisplayed = aFrame == mPresShell->FrameConstructor()->
|
|
|
|
GetDocElementContainingBlock();
|
|
|
|
undisplayedParent = nsnull;
|
|
|
|
} else {
|
|
|
|
checkUndisplayed = !!localContent;
|
|
|
|
undisplayedParent = localContent;
|
|
|
|
}
|
|
|
|
if (checkUndisplayed && mUndisplayedMap) {
|
2012-03-12 20:54:15 -07:00
|
|
|
UndisplayedNode* undisplayed =
|
|
|
|
mUndisplayedMap->GetFirstNode(undisplayedParent);
|
|
|
|
for (AncestorFilter::AutoAncestorPusher
|
|
|
|
pushAncestor(undisplayed, aTreeMatchContext.mAncestorFilter,
|
|
|
|
undisplayedParent ? undisplayedParent->AsElement()
|
|
|
|
: nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
undisplayed; undisplayed = undisplayed->mNext) {
|
2009-01-16 13:32:09 -08:00
|
|
|
NS_ASSERTION(undisplayedParent ||
|
|
|
|
undisplayed->mContent ==
|
2010-04-30 06:12:05 -07:00
|
|
|
mPresShell->GetDocument()->GetRootElement(),
|
2009-01-16 13:32:09 -08:00
|
|
|
"undisplayed node child of null must be root");
|
2009-10-29 14:17:56 -07:00
|
|
|
NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
|
2009-05-14 18:40:26 -07:00
|
|
|
"Shouldn't have random pseudo style contexts in the "
|
|
|
|
"undisplayed map");
|
2010-06-18 09:23:05 -07:00
|
|
|
nsRestyleHint thisChildHint = childRestyleHint;
|
2010-06-18 09:23:05 -07:00
|
|
|
RestyleTracker::RestyleData undisplayedRestyleData;
|
|
|
|
if (aRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
|
|
|
|
&undisplayedRestyleData)) {
|
2010-06-18 09:23:05 -07:00
|
|
|
thisChildHint =
|
|
|
|
nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
|
|
|
|
}
|
|
|
|
nsRefPtr<nsStyleContext> undisplayedContext;
|
|
|
|
if (thisChildHint) {
|
|
|
|
undisplayedContext =
|
|
|
|
styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
|
2011-05-24 17:19:09 -07:00
|
|
|
newContext,
|
|
|
|
aTreeMatchContext);
|
2010-06-18 09:23:05 -07:00
|
|
|
} else {
|
|
|
|
undisplayedContext =
|
2010-06-22 21:46:27 -07:00
|
|
|
styleSet->ReparentStyleContext(undisplayed->mStyle, newContext,
|
|
|
|
undisplayed->mContent->AsElement());
|
2010-06-18 09:23:05 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
if (undisplayedContext) {
|
|
|
|
const nsStyleDisplay* display = undisplayedContext->GetStyleDisplay();
|
|
|
|
if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
|
2010-04-30 06:12:06 -07:00
|
|
|
NS_ASSERTION(undisplayed->mContent,
|
|
|
|
"Must have undisplayed content");
|
|
|
|
aChangeList->AppendChange(nsnull, undisplayed->mContent,
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_STYLE_HINT_FRAMECHANGE);
|
|
|
|
// The node should be removed from the undisplayed map when
|
|
|
|
// we reframe it.
|
|
|
|
} else {
|
|
|
|
// update the undisplayed node with the new context
|
|
|
|
undisplayed->mStyle = undisplayedContext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 09:23:05 -07:00
|
|
|
// Check whether we might need to create a new ::before frame.
|
|
|
|
// There's no need to do this if we're planning to reframe already
|
|
|
|
// or if we're not forcing restyles on kids.
|
|
|
|
if (!(aMinChange & nsChangeHint_ReconstructFrame) &&
|
|
|
|
childRestyleHint) {
|
2012-05-29 20:45:17 -07:00
|
|
|
// Make sure not to do this for pseudo-frames or frames that
|
|
|
|
// can't have generated content.
|
|
|
|
if (!pseudoTag &&
|
2012-06-11 15:21:35 -07:00
|
|
|
((aFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) ||
|
|
|
|
// Our content insertion frame might have gotten flagged
|
|
|
|
(aFrame->GetContentInsertionFrame()->GetStateBits() &
|
|
|
|
NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Check for a new :before pseudo and an existing :before
|
|
|
|
// frame, but only if the frame is the first continuation.
|
|
|
|
nsIFrame* prevContinuation = aFrame->GetPrevContinuation();
|
|
|
|
if (!prevContinuation) {
|
|
|
|
// Checking for a :before frame is cheaper than getting the
|
|
|
|
// :before style context.
|
|
|
|
if (!nsLayoutUtils::GetBeforeFrame(aFrame) &&
|
|
|
|
nsLayoutUtils::HasPseudoStyle(localContent, newContext,
|
2009-12-10 23:37:40 -08:00
|
|
|
nsCSSPseudoElements::ePseudo_before,
|
2007-03-22 10:30:00 -07:00
|
|
|
aPresContext)) {
|
|
|
|
// Have to create the new :before frame
|
|
|
|
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
|
|
|
|
aChangeList->AppendChange(aFrame, content,
|
|
|
|
nsChangeHint_ReconstructFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 09:23:05 -07:00
|
|
|
// Check whether we might need to create a new ::after frame.
|
|
|
|
// There's no need to do this if we're planning to reframe already
|
|
|
|
// or if we're not forcing restyles on kids.
|
|
|
|
if (!(aMinChange & nsChangeHint_ReconstructFrame) &&
|
|
|
|
childRestyleHint) {
|
2012-05-29 20:45:17 -07:00
|
|
|
// Make sure not to do this for pseudo-frames or frames that
|
|
|
|
// can't have generated content.
|
|
|
|
if (!pseudoTag &&
|
2012-06-11 15:21:35 -07:00
|
|
|
((aFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) ||
|
|
|
|
// Our content insertion frame might have gotten flagged
|
|
|
|
(aFrame->GetContentInsertionFrame()->GetStateBits() &
|
|
|
|
NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Check for new :after content, but only if the frame is the
|
|
|
|
// last continuation.
|
|
|
|
nsIFrame* nextContinuation = aFrame->GetNextContinuation();
|
|
|
|
|
|
|
|
if (!nextContinuation) {
|
|
|
|
// Getting the :after frame is more expensive than getting the pseudo
|
|
|
|
// context, so get the pseudo context first.
|
|
|
|
if (nsLayoutUtils::HasPseudoStyle(localContent, newContext,
|
2009-12-10 23:37:40 -08:00
|
|
|
nsCSSPseudoElements::ePseudo_after,
|
2007-03-22 10:30:00 -07:00
|
|
|
aPresContext) &&
|
|
|
|
!nsLayoutUtils::GetAfterFrame(aFrame)) {
|
|
|
|
// have to create the new :after frame
|
|
|
|
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
|
|
|
|
aChangeList->AppendChange(aFrame, content,
|
|
|
|
nsChangeHint_ReconstructFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-30 00:55:51 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
|
2010-11-13 09:49:26 -08:00
|
|
|
DesiredA11yNotifications kidsDesiredA11yNotification =
|
|
|
|
aDesiredA11yNotifications;
|
|
|
|
#ifdef ACCESSIBILITY
|
2010-12-04 02:07:53 -08:00
|
|
|
A11yNotificationType ourA11yNotification = eDontNotify;
|
2010-11-13 09:49:26 -08:00
|
|
|
// Notify a11y for primary frame only if it's a root frame of visibility
|
|
|
|
// changes or its parent frame was hidden while it stays visible and
|
|
|
|
// it is not inside a {ib} split or is the first frame of {ib} split.
|
2011-07-19 01:30:19 -07:00
|
|
|
if (nsIPresShell::IsAccessibilityActive() &&
|
|
|
|
!aFrame->GetPrevContinuation() &&
|
2010-11-13 09:49:26 -08:00
|
|
|
!nsLayoutUtils::FrameIsNonFirstInIBSplit(aFrame)) {
|
|
|
|
if (aDesiredA11yNotifications == eSendAllNotifications) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isFrameVisible = newContext->GetStyleVisibility()->IsVisible();
|
2010-11-13 09:49:26 -08:00
|
|
|
if (isFrameVisible != wasFrameVisible) {
|
|
|
|
if (isFrameVisible) {
|
|
|
|
// Notify a11y the element (perhaps with its children) was shown.
|
|
|
|
// We don't fall into this case if this element gets or stays shown
|
|
|
|
// while its parent becomes hidden.
|
|
|
|
kidsDesiredA11yNotification = eSkipNotifications;
|
|
|
|
ourA11yNotification = eNotifyShown;
|
|
|
|
} else {
|
|
|
|
// The element is being hidden; its children may stay visible, or
|
|
|
|
// become visible after being hidden previously. If we'll find
|
|
|
|
// visible children then we should notify a11y about that as if
|
|
|
|
// they were inserted into tree. Notify a11y this element was
|
|
|
|
// hidden.
|
|
|
|
kidsDesiredA11yNotification = eNotifyIfShown;
|
|
|
|
ourA11yNotification = eNotifyHidden;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (aDesiredA11yNotifications == eNotifyIfShown &&
|
|
|
|
newContext->GetStyleVisibility()->IsVisible()) {
|
|
|
|
// Notify a11y that element stayed visible while its parent was
|
|
|
|
// hidden.
|
|
|
|
aVisibleKidsOfHiddenElement.AppendElement(aFrame->GetContent());
|
|
|
|
kidsDesiredA11yNotification = eSkipNotifications;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// There is no need to waste time crawling into a frame's children on a frame change.
|
|
|
|
// The act of reconstructing frames will force new style contexts to be resolved on all
|
|
|
|
// of this frame's descendants anyway, so we want to avoid wasting time processing
|
|
|
|
// style contexts that we're just going to throw away anyway. - dwh
|
|
|
|
|
|
|
|
// now do children
|
2011-08-24 13:54:29 -07:00
|
|
|
nsIFrame::ChildListIterator lists(aFrame);
|
2012-03-12 20:54:15 -07:00
|
|
|
for (AncestorFilter::AutoAncestorPusher
|
|
|
|
pushAncestor(!lists.IsDone(),
|
|
|
|
aTreeMatchContext.mAncestorFilter,
|
|
|
|
content && content->IsElement() ? content->AsElement()
|
|
|
|
: nsnull);
|
|
|
|
!lists.IsDone(); lists.Next()) {
|
2011-08-24 13:54:29 -07:00
|
|
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
|
|
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
|
|
|
nsIFrame* child = childFrames.get();
|
2012-03-16 10:13:14 -07:00
|
|
|
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
|
|
|
|
// only do frames that are in flow
|
2007-03-22 10:30:00 -07:00
|
|
|
if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
|
|
|
|
// get out of flow frame and recur there
|
|
|
|
nsIFrame* outOfFlowFrame =
|
|
|
|
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
|
|
|
|
NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
|
|
|
|
NS_ASSERTION(outOfFlowFrame != resolvedChild,
|
|
|
|
"out-of-flow frame not a true descendant");
|
|
|
|
|
|
|
|
// Note that the out-of-flow may not be a geometric descendant of
|
|
|
|
// the frame where we started the reresolve. Therefore, even if
|
|
|
|
// aMinChange already includes nsChangeHint_ReflowFrame we don't
|
|
|
|
// want to pass that on to the out-of-flow reresolve, since that
|
2009-07-27 01:47:02 -07:00
|
|
|
// can lead to the out-of-flow not getting reflowed when it should
|
2007-03-22 10:30:00 -07:00
|
|
|
// be (eg a reresolve starting at <body> that involves reflowing
|
|
|
|
// the <body> would miss reflowing fixed-pos nodes that also need
|
|
|
|
// reflow). In the cases when the out-of-flow _is_ a geometric
|
|
|
|
// descendant of a frame we already have a reflow hint for,
|
|
|
|
// reflow coalescing should keep us from doing the work twice.
|
|
|
|
|
|
|
|
// |nsFrame::GetParentStyleContextFrame| checks being out
|
|
|
|
// of flow so that this works correctly.
|
2010-08-10 15:04:43 -07:00
|
|
|
do {
|
|
|
|
ReResolveStyleContext(aPresContext, outOfFlowFrame,
|
|
|
|
content, aChangeList,
|
|
|
|
NS_SubtractHint(aMinChange,
|
|
|
|
nsChangeHint_ReflowFrame),
|
|
|
|
childRestyleHint,
|
2010-11-13 09:49:26 -08:00
|
|
|
aRestyleTracker,
|
|
|
|
kidsDesiredA11yNotification,
|
2011-05-24 17:19:09 -07:00
|
|
|
aVisibleKidsOfHiddenElement,
|
|
|
|
aTreeMatchContext);
|
2011-02-16 05:14:14 -08:00
|
|
|
} while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// reresolve placeholder's context under the same parent
|
|
|
|
// as the out-of-flow frame
|
|
|
|
ReResolveStyleContext(aPresContext, child, content,
|
2009-07-30 00:55:51 -07:00
|
|
|
aChangeList, aMinChange,
|
2010-06-18 09:23:05 -07:00
|
|
|
childRestyleHint,
|
2010-11-13 09:49:26 -08:00
|
|
|
aRestyleTracker,
|
|
|
|
kidsDesiredA11yNotification,
|
2011-05-24 17:19:09 -07:00
|
|
|
aVisibleKidsOfHiddenElement,
|
|
|
|
aTreeMatchContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else { // regular child frame
|
|
|
|
if (child != resolvedChild) {
|
|
|
|
ReResolveStyleContext(aPresContext, child, content,
|
2009-07-30 00:55:51 -07:00
|
|
|
aChangeList, aMinChange,
|
2010-06-18 09:23:05 -07:00
|
|
|
childRestyleHint,
|
2010-11-13 09:49:26 -08:00
|
|
|
aRestyleTracker,
|
|
|
|
kidsDesiredA11yNotification,
|
2011-05-24 17:19:09 -07:00
|
|
|
aVisibleKidsOfHiddenElement,
|
|
|
|
aTreeMatchContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
|
|
|
NOISY_TRACE_FRAME("child frame already resolved as descendant, skipping",aFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-24 13:54:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXX need to do overflow frames???
|
|
|
|
|
2010-11-13 09:49:26 -08:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
// Send notifications about visibility changes.
|
|
|
|
if (ourA11yNotification == eNotifyShown) {
|
2011-01-27 20:38:14 -08:00
|
|
|
nsAccessibilityService* accService = nsIPresShell::AccService();
|
2010-11-13 09:49:26 -08:00
|
|
|
if (accService) {
|
|
|
|
nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
|
|
|
|
accService->ContentRangeInserted(presShell, content->GetParent(),
|
|
|
|
content,
|
|
|
|
content->GetNextSibling());
|
|
|
|
}
|
|
|
|
} else if (ourA11yNotification == eNotifyHidden) {
|
2011-01-27 20:38:14 -08:00
|
|
|
nsAccessibilityService* accService = nsIPresShell::AccService();
|
2010-11-13 09:49:26 -08:00
|
|
|
if (accService) {
|
|
|
|
nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
accService->ContentRemoved(presShell, content->GetParent(), content);
|
|
|
|
|
|
|
|
// Process children staying shown.
|
|
|
|
PRUint32 visibleContentCount = aVisibleKidsOfHiddenElement.Length();
|
|
|
|
for (PRUint32 idx = 0; idx < visibleContentCount; idx++) {
|
|
|
|
nsIContent* content = aVisibleKidsOfHiddenElement[idx];
|
|
|
|
accService->ContentRangeInserted(presShell, content->GetParent(),
|
|
|
|
content, content->GetNextSibling());
|
|
|
|
}
|
|
|
|
aVisibleKidsOfHiddenElement.Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return aMinChange;
|
|
|
|
}
|
|
|
|
|
2008-02-08 11:52:46 -08:00
|
|
|
void
|
2007-03-22 10:30:00 -07:00
|
|
|
nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
|
|
|
|
nsStyleChangeList *aChangeList,
|
2010-06-18 09:23:05 -07:00
|
|
|
nsChangeHint aMinChange,
|
2010-06-18 09:23:05 -07:00
|
|
|
RestyleTracker& aRestyleTracker,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aRestyleDescendants)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-03-12 20:54:15 -07:00
|
|
|
nsIContent *content = aFrame->GetContent();
|
2008-02-08 11:52:46 -08:00
|
|
|
if (aMinChange) {
|
2012-03-12 20:54:15 -07:00
|
|
|
aChangeList->AppendChange(aFrame, content, aMinChange);
|
2008-02-08 11:52:46 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsChangeHint topLevelChange = aMinChange;
|
|
|
|
|
|
|
|
nsIFrame* frame = aFrame;
|
|
|
|
nsIFrame* frame2 = aFrame;
|
|
|
|
|
|
|
|
NS_ASSERTION(!frame->GetPrevContinuation(), "must start with the first in flow");
|
|
|
|
|
|
|
|
// We want to start with this frame and walk all its next-in-flows,
|
|
|
|
// as well as all its special siblings and their next-in-flows,
|
|
|
|
// reresolving style on all the frames we encounter in this walk.
|
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
FramePropertyTable *propTable = GetPresContext()->PropertyTable();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
TreeMatchContext treeMatchContext(true,
|
2011-05-24 17:19:09 -07:00
|
|
|
nsRuleWalker::eRelevantLinkUnvisited,
|
|
|
|
mPresShell->GetDocument());
|
2012-03-12 20:54:15 -07:00
|
|
|
nsIContent *parent = content ? content->GetParent() : nsnull;
|
|
|
|
Element *parentElement =
|
|
|
|
parent && parent->IsElement() ? parent->AsElement() : nsnull;
|
|
|
|
treeMatchContext.mAncestorFilter.Init(parentElement);
|
2010-11-13 09:49:26 -08:00
|
|
|
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
|
2007-03-22 10:30:00 -07:00
|
|
|
do {
|
|
|
|
// Outer loop over special siblings
|
|
|
|
do {
|
|
|
|
// Inner loop over next-in-flows of the current frame
|
|
|
|
nsChangeHint frameChange =
|
|
|
|
ReResolveStyleContext(GetPresContext(), frame, nsnull,
|
2010-06-18 09:23:05 -07:00
|
|
|
aChangeList, topLevelChange,
|
|
|
|
aRestyleDescendants ?
|
|
|
|
eRestyle_Subtree : eRestyle_Self,
|
2010-11-13 09:49:26 -08:00
|
|
|
aRestyleTracker,
|
|
|
|
eSendAllNotifications,
|
2011-05-24 17:19:09 -07:00
|
|
|
visibleKidsOfHiddenElement,
|
|
|
|
treeMatchContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_UpdateHint(topLevelChange, frameChange);
|
|
|
|
|
|
|
|
if (topLevelChange & nsChangeHint_ReconstructFrame) {
|
|
|
|
// If it's going to cause a framechange, then don't bother
|
|
|
|
// with the continuations or special siblings since they'll be
|
|
|
|
// clobbered by the frame reconstruct anyway.
|
|
|
|
NS_ASSERTION(!frame->GetPrevContinuation(),
|
|
|
|
"continuing frame had more severe impact than first-in-flow");
|
2008-02-08 11:52:46 -08:00
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
frame = frame->GetNextContinuation();
|
|
|
|
} while (frame);
|
|
|
|
|
|
|
|
// Might we have special siblings?
|
|
|
|
if (!(frame2->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
|
|
|
|
// nothing more to do here
|
2008-02-08 11:52:46 -08:00
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
frame2 = static_cast<nsIFrame*>
|
2010-03-28 18:46:55 -07:00
|
|
|
(propTable->Get(frame2, nsIFrame::IBSplitSpecialSibling()));
|
2007-03-22 10:30:00 -07:00
|
|
|
frame = frame2;
|
|
|
|
} while (frame2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Capture state for a given frame.
|
|
|
|
// Accept a content id here, in some cases we may not have content (scroll position)
|
|
|
|
void
|
|
|
|
nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
|
|
|
|
nsILayoutHistoryState* aState,
|
|
|
|
nsIStatefulFrame::SpecialStateID aID)
|
|
|
|
{
|
|
|
|
if (!aFrame || !aState) {
|
|
|
|
NS_WARNING("null frame, or state");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only capture state for stateful frames
|
2009-01-12 11:20:59 -08:00
|
|
|
nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!statefulFrame) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Capture the state, exit early if we get null (nothing to save)
|
|
|
|
nsAutoPtr<nsPresState> frameState;
|
|
|
|
nsresult rv = statefulFrame->SaveState(aID, getter_Transfers(frameState));
|
|
|
|
if (!frameState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the hash key to store the state under
|
|
|
|
// Exit early if we get empty key
|
|
|
|
nsCAutoString stateKey;
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
nsIDocument* doc = content ? content->GetCurrentDoc() : nsnull;
|
|
|
|
rv = nsContentUtils::GenerateStateKey(content, doc, aID, stateKey);
|
|
|
|
if(NS_FAILED(rv) || stateKey.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the state
|
|
|
|
rv = aState->AddState(stateKey, frameState);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// aState owns frameState now.
|
|
|
|
frameState.forget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::CaptureFrameState(nsIFrame* aFrame,
|
|
|
|
nsILayoutHistoryState* aState)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
|
|
|
|
|
|
|
|
CaptureFrameStateFor(aFrame, aState);
|
|
|
|
|
|
|
|
// Now capture state recursively for the frame hierarchy rooted at aFrame
|
2011-08-24 13:54:29 -07:00
|
|
|
nsIFrame::ChildListIterator lists(aFrame);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
|
|
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
|
|
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
2012-05-09 18:27:47 -07:00
|
|
|
nsIFrame* child = childFrames.get();
|
|
|
|
if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
|
|
|
|
// 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);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-08-24 13:54:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Restore state for a given frame.
|
|
|
|
// Accept a content id here, in some cases we may not have content (scroll position)
|
|
|
|
void
|
|
|
|
nsFrameManager::RestoreFrameStateFor(nsIFrame* aFrame,
|
|
|
|
nsILayoutHistoryState* aState,
|
|
|
|
nsIStatefulFrame::SpecialStateID aID)
|
|
|
|
{
|
|
|
|
if (!aFrame || !aState) {
|
|
|
|
NS_WARNING("null frame or state");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-12-03 09:55:14 -08:00
|
|
|
// Only restore state for stateful frames
|
2009-01-12 11:20:59 -08:00
|
|
|
nsIStatefulFrame* statefulFrame = do_QueryFrame(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!statefulFrame) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the hash key the state was stored under
|
|
|
|
// Exit early if we get empty key
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
// If we don't have content, we can't generate a hash
|
|
|
|
// key and there's probably no state information for us.
|
|
|
|
if (!content) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCAutoString stateKey;
|
|
|
|
nsIDocument* doc = content->GetCurrentDoc();
|
|
|
|
nsresult rv = nsContentUtils::GenerateStateKey(content, doc, aID, stateKey);
|
|
|
|
if (NS_FAILED(rv) || stateKey.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the state from the hash
|
|
|
|
nsPresState *frameState;
|
|
|
|
rv = aState->GetState(stateKey, &frameState);
|
|
|
|
if (!frameState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore it
|
|
|
|
rv = statefulFrame->RestoreState(frameState);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we restore ok, remove the state from the state table
|
|
|
|
aState->RemoveState(stateKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
|
|
|
|
nsILayoutHistoryState* aState)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull != aFrame && nsnull != aState, "null parameters passed in");
|
|
|
|
|
|
|
|
RestoreFrameStateFor(aFrame, aState);
|
|
|
|
|
|
|
|
// Now restore state recursively for the frame hierarchy rooted at aFrame
|
2011-08-24 13:54:29 -07:00
|
|
|
nsIFrame::ChildListIterator lists(aFrame);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
|
|
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
|
|
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
|
|
|
RestoreFrameState(childFrames.get(), aState);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-08-24 13:54:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
static PLHashNumber
|
|
|
|
HashKey(void* key)
|
|
|
|
{
|
|
|
|
return NS_PTR_TO_INT32(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRIntn
|
|
|
|
CompareKeys(void* key1, void* key2)
|
|
|
|
{
|
|
|
|
return key1 == key2;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsFrameManagerBase::UndisplayedMap::UndisplayedMap(PRUint32 aNumBuckets)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
|
|
|
|
mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey,
|
|
|
|
(PLHashComparator)CompareKeys,
|
|
|
|
(PLHashComparator)nsnull,
|
|
|
|
nsnull, nsnull);
|
|
|
|
mLastLookup = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap);
|
|
|
|
Clear();
|
|
|
|
PL_HashTableDestroy(mTable);
|
|
|
|
}
|
|
|
|
|
|
|
|
PLHashEntry**
|
|
|
|
nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent* aParentContent)
|
|
|
|
{
|
|
|
|
if (mLastLookup && (aParentContent == (*mLastLookup)->key)) {
|
|
|
|
return mLastLookup;
|
|
|
|
}
|
|
|
|
PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
|
|
|
|
PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, aParentContent);
|
|
|
|
if (*entry) {
|
|
|
|
mLastLookup = entry;
|
|
|
|
}
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
UndisplayedNode*
|
|
|
|
nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
|
|
|
|
{
|
|
|
|
PLHashEntry** entry = GetEntryFor(aParentContent);
|
|
|
|
if (*entry) {
|
|
|
|
return (UndisplayedNode*)((*entry)->value);
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
|
|
|
|
nsIContent* aParentContent)
|
|
|
|
{
|
|
|
|
PLHashEntry** entry = GetEntryFor(aParentContent);
|
|
|
|
if (*entry) {
|
|
|
|
UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
|
|
|
|
while (node->mNext) {
|
|
|
|
if (node->mContent == aNode->mContent) {
|
|
|
|
// We actually need to check this in optimized builds because
|
|
|
|
// there are some callers that do this. See bug 118014, bug
|
|
|
|
// 136704, etc.
|
|
|
|
NS_NOTREACHED("node in map twice");
|
|
|
|
delete aNode;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
node = node->mNext;
|
|
|
|
}
|
|
|
|
node->mNext = aNode;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
|
|
|
|
PL_HashTableRawAdd(mTable, entry, hashCode, aParentContent, aNode);
|
|
|
|
mLastLookup = nsnull; // hashtable may have shifted bucket out from under us
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
|
|
|
|
nsIContent* aChild,
|
|
|
|
nsStyleContext* aStyle)
|
|
|
|
{
|
|
|
|
UndisplayedNode* node = new UndisplayedNode(aChild, aStyle);
|
|
|
|
|
|
|
|
AppendNodeFor(node, aParentContent);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
|
|
|
|
UndisplayedNode* aNode)
|
|
|
|
{
|
|
|
|
PLHashEntry** entry = GetEntryFor(aParentContent);
|
|
|
|
NS_ASSERTION(*entry, "content not in map");
|
|
|
|
if (*entry) {
|
|
|
|
if ((UndisplayedNode*)((*entry)->value) == aNode) { // first node
|
|
|
|
if (aNode->mNext) {
|
|
|
|
(*entry)->value = aNode->mNext;
|
|
|
|
aNode->mNext = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PL_HashTableRawRemove(mTable, entry, *entry);
|
|
|
|
mLastLookup = nsnull; // hashtable may have shifted bucket out from under us
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
|
|
|
|
while (node->mNext) {
|
|
|
|
if (node->mNext == aNode) {
|
|
|
|
node->mNext = aNode->mNext;
|
|
|
|
aNode->mNext = nsnull;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node = node->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete aNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
|
|
|
|
{
|
|
|
|
PLHashEntry** entry = GetEntryFor(aParentContent);
|
|
|
|
NS_ASSERTION(entry, "content not in map");
|
|
|
|
if (*entry) {
|
|
|
|
UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
|
|
|
|
NS_ASSERTION(node, "null node for non-null entry in UndisplayedMap");
|
|
|
|
delete node;
|
|
|
|
PL_HashTableRawRemove(mTable, entry, *entry);
|
|
|
|
mLastLookup = nsnull; // hashtable may have shifted bucket out from under us
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PRIntn
|
2007-03-22 10:30:00 -07:00
|
|
|
RemoveUndisplayedEntry(PLHashEntry* he, PRIntn i, void* arg)
|
|
|
|
{
|
|
|
|
UndisplayedNode* node = (UndisplayedNode*)(he->value);
|
|
|
|
delete node;
|
|
|
|
// Remove and free this entry and continue enumerating
|
|
|
|
return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFrameManagerBase::UndisplayedMap::Clear(void)
|
|
|
|
{
|
|
|
|
mLastLookup = nsnull;
|
|
|
|
PL_HashTableEnumerateEntries(mTable, RemoveUndisplayedEntry, 0);
|
|
|
|
}
|
2012-07-04 08:42:29 -07:00
|
|
|
|
|
|
|
PRUint32 nsFrameManagerBase::sGlobalGenerationNumber;
|