diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp new file mode 100644 index 000000000000..6dcc26726a4d --- /dev/null +++ b/layout/base/nsFrameManager.cpp @@ -0,0 +1,444 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsIFrameManager.h" +#include "nsIFrame.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIStyleSet.h" +#include "nsCOMPtr.h" +#include "plhash.h" +#include "nsDST.h" +#include "nsPlaceholderFrame.h" +#ifdef NS_DEBUG +#include "nsLayoutAtoms.h" +#endif + +//---------------------------------------------------------------------- + +static PLHashNumber +HashKey(void* key) +{ + return (PLHashNumber)key; +} + +static PRIntn +CompareKeys(void* key1, void* key2) +{ + return key1 == key2; +} + +// Thin veneer around an NSPR hash table. Provides a map from a key that's +// a pointer to a value that's also a pointer. +class FrameHashTable { +public: + FrameHashTable(PRUint32 aNumBuckets = 16); + ~FrameHashTable(); + + // Gets the value associated with the specified key + void* Get(void* aKey); + + // Creates an association between the key and value. Returns the previous + // value associated with the key, or NULL if there was none + void* Put(void* aKey, void* aValue); + + // Removes association for the key, and returns its associated value + void* Remove(void* aKey); + + // Removes all entries from the hash table + void Clear(); + +#ifdef NS_DEBUG + void Dump(FILE* fp); +#endif + +protected: + PLHashTable* mTable; +}; + +FrameHashTable::FrameHashTable(PRUint32 aNumBuckets) +{ + mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey, + (PLHashComparator)CompareKeys, + (PLHashComparator)nsnull, + nsnull, nsnull); +} + +FrameHashTable::~FrameHashTable() +{ + PL_HashTableDestroy(mTable); +} + +void* +FrameHashTable::Get(void* aKey) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + if (nsnull != he) { + return he->value; + } + return nsnull; +} + +void* +FrameHashTable::Put(void* aKey, void* aData) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + if (nsnull != he) { + void* oldValue = he->value; + he->value = aData; + return oldValue; + } + PL_HashTableRawAdd(mTable, hep, hashCode, aKey, aData); + return nsnull; +} + +void* +FrameHashTable::Remove(void* aKey) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + void* oldValue = nsnull; + if (nsnull != he) { + oldValue = he->value; + PL_HashTableRawRemove(mTable, hep, he); + } + return oldValue; +} + +static PRIntn +RemoveEntry(PLHashEntry* he, PRIntn i, void* arg) +{ + // Remove and free this entry and continue enumerating + return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT; +} + +void +FrameHashTable::Clear() +{ + PL_HashTableEnumerateEntries(mTable, RemoveEntry, 0); +} + +#ifdef NS_DEBUG +static PRIntn +EnumEntries(PLHashEntry* he, PRIntn i, void* arg) +{ + // Continue enumerating + return HT_ENUMERATE_NEXT; +} + +void +FrameHashTable::Dump(FILE* fp) +{ + PL_HashTableDump(mTable, EnumEntries, fp); +} +#endif + +//---------------------------------------------------------------------- + +class FrameManager : public nsIFrameManager +{ +public: + FrameManager(); + virtual ~FrameManager(); + + NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFrameManager + NS_IMETHOD Init(nsIPresShell* aPresShell); + + // Primary frame functions + NS_IMETHOD GetPrimaryFrameFor(nsIContent* aContent, + nsIFrame** aPrimaryFrame) const; + NS_IMETHOD SetPrimaryFrameFor(nsIContent* aContent, + nsIFrame* aPrimaryFrame); + NS_IMETHOD ClearPrimaryFrameMap(); + + // Placeholder frame functions + NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame** aPlaceholderFrame) const; + NS_IMETHOD SetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame* aPlaceholderFrame); + NS_IMETHOD ClearPlaceholderFrameMap(); + + // Functions for manipulating the frame model + NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aFrameList); + NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList); + NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame); + NS_IMETHOD ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame); + +private: + nsIPresShell* mPresShell; // weak link + nsDST* mPrimaryFrameMap; + FrameHashTable* mPlaceholderMap; +}; + +//---------------------------------------------------------------------- + +NS_LAYOUT nsresult +NS_NewFrameManager(nsIFrameManager** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + FrameManager* it = new FrameManager; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(nsIFrameManager::GetIID(), (void **)aInstancePtrResult); +} + +FrameManager::FrameManager() +{ +} + +NS_IMPL_ADDREF(FrameManager) +NS_IMPL_RELEASE(FrameManager) + +FrameManager::~FrameManager() +{ + delete mPrimaryFrameMap; + delete mPlaceholderMap; +} + +nsresult +FrameManager::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (aIID.Equals(GetIID())) { + *aInstancePtr = (void*)(nsIFrameManager*)this; + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMETHODIMP +FrameManager::Init(nsIPresShell* aPresShell) +{ + mPresShell = aPresShell; + return NS_OK; +} + +// Primary frame functions +NS_IMETHODIMP +FrameManager::GetPrimaryFrameFor(nsIContent* aContent, + nsIFrame** aResult) const +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + NS_PRECONDITION(nsnull != aContent, "no content object"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + + if (nsnull == mPrimaryFrameMap) { + *aResult = nsnull; + } else { + *aResult = (nsIFrame*)mPrimaryFrameMap->Search(aContent); + if (!*aResult) { + nsCOMPtr styleSet; + nsCOMPtr presContext; + + // Give the frame construction code the opportunity to return the + // frame that maps the content object + mPresShell->GetStyleSet(getter_AddRefs(styleSet)); + mPresShell->GetPresContext(getter_AddRefs(presContext)); + styleSet->FindPrimaryFrameFor(presContext, aContent, aResult); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::SetPrimaryFrameFor(nsIContent* aContent, + nsIFrame* aPrimaryFrame) +{ + NS_PRECONDITION(aContent, "no content object"); + + // If aPrimaryFrame is NULL, then remove the mapping + if (!aPrimaryFrame) { + if (mPrimaryFrameMap) { + mPrimaryFrameMap->Remove(aContent); + } + } else { + // Create a new DST if necessary + if (!mPrimaryFrameMap) { + mPrimaryFrameMap = new nsDST; + if (!mPrimaryFrameMap) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + // Add a mapping to the hash table + nsIFrame* oldPrimaryFrame; + + oldPrimaryFrame = (nsIFrame*)mPrimaryFrameMap->Insert(aContent, (void*)aPrimaryFrame); +#ifdef NS_DEBUG + if (oldPrimaryFrame && (oldPrimaryFrame != aPrimaryFrame)) { + NS_WARNING("overwriting current primary frame"); + } +#endif + } + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::ClearPrimaryFrameMap() +{ + if (mPrimaryFrameMap) { + mPrimaryFrameMap->Clear(); + } + return NS_OK; +} + +// Placeholder frame functions +NS_IMETHODIMP +FrameManager::GetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame** aResult) const +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + NS_PRECONDITION(nsnull != aFrame, "no frame"); + if ((nsnull == aResult) || (nsnull == aFrame)) { + return NS_ERROR_NULL_POINTER; + } + + if (nsnull == mPlaceholderMap) { + *aResult = nsnull; + } else { + *aResult = (nsIFrame*)mPlaceholderMap->Get(aFrame); + } + + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::SetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame* aPlaceholderFrame) +{ + NS_PRECONDITION(aFrame, "no frame"); +#ifdef NS_DEBUG + // Verify that the placeholder frame is of the correct type + if (aPlaceholderFrame) { + nsIAtom* frameType; + + aPlaceholderFrame->GetFrameType(&frameType); + NS_PRECONDITION(nsLayoutAtoms::placeholderFrame == frameType, "unexpected frame type"); + NS_IF_RELEASE(frameType); + } +#endif + + // If aPlaceholderFrame is NULL, then remove the mapping + if (!aPlaceholderFrame) { + if (mPlaceholderMap) { + mPlaceholderMap->Remove(aFrame); + } + } else { + // Create a new hash table if necessary + if (!mPlaceholderMap) { + mPlaceholderMap = new FrameHashTable; + if (!mPlaceholderMap) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + // Add a mapping to the hash table + mPlaceholderMap->Put(aFrame, (void*)aPlaceholderFrame); + } + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::ClearPlaceholderFrameMap() +{ + if (mPlaceholderMap) { + mPlaceholderMap->Clear(); + } + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aFrameList) +{ + return aParentFrame->AppendFrames(aPresContext, aPresShell, aListName, + aFrameList); +} + +NS_IMETHODIMP +FrameManager::InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) +{ + return aParentFrame->InsertFrames(aPresContext, aPresShell, aListName, + aPrevFrame, aFrameList); +} + +NS_IMETHODIMP +FrameManager::RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame) +{ + return aParentFrame->RemoveFrame(aPresContext, aPresShell, aListName, + aOldFrame); +} + +NS_IMETHODIMP +FrameManager::ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame) +{ + return aParentFrame->ReplaceFrame(aPresContext, aPresShell, aListName, + aOldFrame, aNewFrame); +} + diff --git a/layout/base/public/nsIFrameManager.h b/layout/base/public/nsIFrameManager.h new file mode 100644 index 000000000000..3bb4016a68a4 --- /dev/null +++ b/layout/base/public/nsIFrameManager.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsIFrameManager_h___ +#define nsIFrameManager_h___ + +#include "nslayout.h" +#include "nsISupports.h" + +class nsIAtom; +class nsIContent; +class nsIFrame; +class nsIPresContext; +class nsIPresShell; + +#define NS_IFRAMEMANAGER_IID \ +{ 0xa6cf9107, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +/** + * Frame manager interface. The frame manager serves two purposes: + *
  • provides a serice for mapping from content to frame and from out-of-flow + * frame to placeholder frame + *
  • handles structural modifications to the frame model. If the frame model + * lock can be acquired, then the changes are processed immediately; otherwise, + * they're queued and processed later + */ +class nsIFrameManager : public nsISupports { +public: + static const nsIID& GetIID() {static nsIID iid = NS_IFRAMEMANAGER_IID; return iid;} + + // Initialization + NS_IMETHOD Init(nsIPresShell* aPresShell) = 0; + + // Primary frame functions + NS_IMETHOD GetPrimaryFrameFor(nsIContent* aContent, + nsIFrame** aPrimaryFrame) const = 0; + NS_IMETHOD SetPrimaryFrameFor(nsIContent* aContent, + nsIFrame* aPrimaryFrame) = 0; + NS_IMETHOD ClearPrimaryFrameMap() = 0; + + // Placeholder frame functions + NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame** aPlaceholderFrame) const = 0; + NS_IMETHOD SetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame* aPlaceholderFrame) = 0; + NS_IMETHOD ClearPlaceholderFrameMap() = 0; + + // Functions for manipulating the frame model + NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aFrameList) = 0; + NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) = 0; + NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame) = 0; + NS_IMETHOD ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame) = 0; +}; + +/** + * Create a frame manager. Upon success, call Init() before attempting to + * use it. + */ +extern NS_LAYOUT nsresult + NS_NewFrameManager(nsIFrameManager** aInstancePtrResult); + +#endif /* nsIFrameManager_h___ */ diff --git a/layout/html/base/src/nsFrameManager.cpp b/layout/html/base/src/nsFrameManager.cpp new file mode 100644 index 000000000000..6dcc26726a4d --- /dev/null +++ b/layout/html/base/src/nsFrameManager.cpp @@ -0,0 +1,444 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsIFrameManager.h" +#include "nsIFrame.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIStyleSet.h" +#include "nsCOMPtr.h" +#include "plhash.h" +#include "nsDST.h" +#include "nsPlaceholderFrame.h" +#ifdef NS_DEBUG +#include "nsLayoutAtoms.h" +#endif + +//---------------------------------------------------------------------- + +static PLHashNumber +HashKey(void* key) +{ + return (PLHashNumber)key; +} + +static PRIntn +CompareKeys(void* key1, void* key2) +{ + return key1 == key2; +} + +// Thin veneer around an NSPR hash table. Provides a map from a key that's +// a pointer to a value that's also a pointer. +class FrameHashTable { +public: + FrameHashTable(PRUint32 aNumBuckets = 16); + ~FrameHashTable(); + + // Gets the value associated with the specified key + void* Get(void* aKey); + + // Creates an association between the key and value. Returns the previous + // value associated with the key, or NULL if there was none + void* Put(void* aKey, void* aValue); + + // Removes association for the key, and returns its associated value + void* Remove(void* aKey); + + // Removes all entries from the hash table + void Clear(); + +#ifdef NS_DEBUG + void Dump(FILE* fp); +#endif + +protected: + PLHashTable* mTable; +}; + +FrameHashTable::FrameHashTable(PRUint32 aNumBuckets) +{ + mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey, + (PLHashComparator)CompareKeys, + (PLHashComparator)nsnull, + nsnull, nsnull); +} + +FrameHashTable::~FrameHashTable() +{ + PL_HashTableDestroy(mTable); +} + +void* +FrameHashTable::Get(void* aKey) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + if (nsnull != he) { + return he->value; + } + return nsnull; +} + +void* +FrameHashTable::Put(void* aKey, void* aData) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + if (nsnull != he) { + void* oldValue = he->value; + he->value = aData; + return oldValue; + } + PL_HashTableRawAdd(mTable, hep, hashCode, aKey, aData); + return nsnull; +} + +void* +FrameHashTable::Remove(void* aKey) +{ + PRInt32 hashCode = (PRInt32) aKey; + PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey); + PLHashEntry* he = *hep; + void* oldValue = nsnull; + if (nsnull != he) { + oldValue = he->value; + PL_HashTableRawRemove(mTable, hep, he); + } + return oldValue; +} + +static PRIntn +RemoveEntry(PLHashEntry* he, PRIntn i, void* arg) +{ + // Remove and free this entry and continue enumerating + return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT; +} + +void +FrameHashTable::Clear() +{ + PL_HashTableEnumerateEntries(mTable, RemoveEntry, 0); +} + +#ifdef NS_DEBUG +static PRIntn +EnumEntries(PLHashEntry* he, PRIntn i, void* arg) +{ + // Continue enumerating + return HT_ENUMERATE_NEXT; +} + +void +FrameHashTable::Dump(FILE* fp) +{ + PL_HashTableDump(mTable, EnumEntries, fp); +} +#endif + +//---------------------------------------------------------------------- + +class FrameManager : public nsIFrameManager +{ +public: + FrameManager(); + virtual ~FrameManager(); + + NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFrameManager + NS_IMETHOD Init(nsIPresShell* aPresShell); + + // Primary frame functions + NS_IMETHOD GetPrimaryFrameFor(nsIContent* aContent, + nsIFrame** aPrimaryFrame) const; + NS_IMETHOD SetPrimaryFrameFor(nsIContent* aContent, + nsIFrame* aPrimaryFrame); + NS_IMETHOD ClearPrimaryFrameMap(); + + // Placeholder frame functions + NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame** aPlaceholderFrame) const; + NS_IMETHOD SetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame* aPlaceholderFrame); + NS_IMETHOD ClearPlaceholderFrameMap(); + + // Functions for manipulating the frame model + NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aFrameList); + NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList); + NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame); + NS_IMETHOD ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame); + +private: + nsIPresShell* mPresShell; // weak link + nsDST* mPrimaryFrameMap; + FrameHashTable* mPlaceholderMap; +}; + +//---------------------------------------------------------------------- + +NS_LAYOUT nsresult +NS_NewFrameManager(nsIFrameManager** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + FrameManager* it = new FrameManager; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + return it->QueryInterface(nsIFrameManager::GetIID(), (void **)aInstancePtrResult); +} + +FrameManager::FrameManager() +{ +} + +NS_IMPL_ADDREF(FrameManager) +NS_IMPL_RELEASE(FrameManager) + +FrameManager::~FrameManager() +{ + delete mPrimaryFrameMap; + delete mPlaceholderMap; +} + +nsresult +FrameManager::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (aIID.Equals(GetIID())) { + *aInstancePtr = (void*)(nsIFrameManager*)this; + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMETHODIMP +FrameManager::Init(nsIPresShell* aPresShell) +{ + mPresShell = aPresShell; + return NS_OK; +} + +// Primary frame functions +NS_IMETHODIMP +FrameManager::GetPrimaryFrameFor(nsIContent* aContent, + nsIFrame** aResult) const +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + NS_PRECONDITION(nsnull != aContent, "no content object"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } + + if (nsnull == mPrimaryFrameMap) { + *aResult = nsnull; + } else { + *aResult = (nsIFrame*)mPrimaryFrameMap->Search(aContent); + if (!*aResult) { + nsCOMPtr styleSet; + nsCOMPtr presContext; + + // Give the frame construction code the opportunity to return the + // frame that maps the content object + mPresShell->GetStyleSet(getter_AddRefs(styleSet)); + mPresShell->GetPresContext(getter_AddRefs(presContext)); + styleSet->FindPrimaryFrameFor(presContext, aContent, aResult); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::SetPrimaryFrameFor(nsIContent* aContent, + nsIFrame* aPrimaryFrame) +{ + NS_PRECONDITION(aContent, "no content object"); + + // If aPrimaryFrame is NULL, then remove the mapping + if (!aPrimaryFrame) { + if (mPrimaryFrameMap) { + mPrimaryFrameMap->Remove(aContent); + } + } else { + // Create a new DST if necessary + if (!mPrimaryFrameMap) { + mPrimaryFrameMap = new nsDST; + if (!mPrimaryFrameMap) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + // Add a mapping to the hash table + nsIFrame* oldPrimaryFrame; + + oldPrimaryFrame = (nsIFrame*)mPrimaryFrameMap->Insert(aContent, (void*)aPrimaryFrame); +#ifdef NS_DEBUG + if (oldPrimaryFrame && (oldPrimaryFrame != aPrimaryFrame)) { + NS_WARNING("overwriting current primary frame"); + } +#endif + } + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::ClearPrimaryFrameMap() +{ + if (mPrimaryFrameMap) { + mPrimaryFrameMap->Clear(); + } + return NS_OK; +} + +// Placeholder frame functions +NS_IMETHODIMP +FrameManager::GetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame** aResult) const +{ + NS_PRECONDITION(nsnull != aResult, "null ptr"); + NS_PRECONDITION(nsnull != aFrame, "no frame"); + if ((nsnull == aResult) || (nsnull == aFrame)) { + return NS_ERROR_NULL_POINTER; + } + + if (nsnull == mPlaceholderMap) { + *aResult = nsnull; + } else { + *aResult = (nsIFrame*)mPlaceholderMap->Get(aFrame); + } + + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::SetPlaceholderFrameFor(nsIFrame* aFrame, + nsIFrame* aPlaceholderFrame) +{ + NS_PRECONDITION(aFrame, "no frame"); +#ifdef NS_DEBUG + // Verify that the placeholder frame is of the correct type + if (aPlaceholderFrame) { + nsIAtom* frameType; + + aPlaceholderFrame->GetFrameType(&frameType); + NS_PRECONDITION(nsLayoutAtoms::placeholderFrame == frameType, "unexpected frame type"); + NS_IF_RELEASE(frameType); + } +#endif + + // If aPlaceholderFrame is NULL, then remove the mapping + if (!aPlaceholderFrame) { + if (mPlaceholderMap) { + mPlaceholderMap->Remove(aFrame); + } + } else { + // Create a new hash table if necessary + if (!mPlaceholderMap) { + mPlaceholderMap = new FrameHashTable; + if (!mPlaceholderMap) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + // Add a mapping to the hash table + mPlaceholderMap->Put(aFrame, (void*)aPlaceholderFrame); + } + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::ClearPlaceholderFrameMap() +{ + if (mPlaceholderMap) { + mPlaceholderMap->Clear(); + } + return NS_OK; +} + +NS_IMETHODIMP +FrameManager::AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aFrameList) +{ + return aParentFrame->AppendFrames(aPresContext, aPresShell, aListName, + aFrameList); +} + +NS_IMETHODIMP +FrameManager::InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) +{ + return aParentFrame->InsertFrames(aPresContext, aPresShell, aListName, + aPrevFrame, aFrameList); +} + +NS_IMETHODIMP +FrameManager::RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame) +{ + return aParentFrame->RemoveFrame(aPresContext, aPresShell, aListName, + aOldFrame); +} + +NS_IMETHODIMP +FrameManager::ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIFrame* aParentFrame, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame) +{ + return aParentFrame->ReplaceFrame(aPresContext, aPresShell, aListName, + aOldFrame, aNewFrame); +} +