Files
Mozilla/mozilla/layout/xul/base/src/nsMonumentLayout.cpp
morse%netscape.com b3a5a9b468 fix bug 44351, crash in cookie viewer and signon viewer, r=evaughan
git-svn-id: svn://10.0.0.236/trunk@73893 18797224-902f-48f8-a5cc-f745e15eee43
2000-07-08 23:40:06 +00:00

676 lines
15 KiB
C++

/* -*- 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.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
//
// Eric Vaughan
// Netscape Communications
//
// See documentation in associated header file
//
#include "nsMonumentLayout.h"
#include "nsBoxLayoutState.h"
#include "nsIBox.h"
#include "nsIScrollableFrame.h"
#include "nsBox.h"
// ----- Monument Iterator -----
nsLayoutIterator::nsLayoutIterator(nsIBox* aBox):mBox(nsnull),mStartBox(aBox),mParentCount(0)
{
}
void
nsLayoutIterator::Reset()
{
mBox = nsnull;
}
PRBool
nsLayoutIterator::GetNextLayout(nsIBoxLayout** aLayout, PRBool aSearchChildren)
{
if (mBox == nsnull) {
mBox = mStartBox;
} else {
if (aSearchChildren) {
mParents[mParentCount++] = mBox;
NS_ASSERTION(mParentCount < PARENT_STACK_SIZE, "Stack overflow!!");
mBox->GetChildBox(&mBox);
} else {
mBox->GetNextBox(&mBox);
}
}
return DigDeep(aLayout, aSearchChildren);
}
PRBool
nsLayoutIterator::DigDeep(nsIBoxLayout** aLayout, PRBool aSearchChildren)
{
// if our box is null. See if we have any parents on the stack
// if so pop them off and continue.
if (!mBox) {
if (mParentCount > 0) {
mBox = mParents[--mParentCount];
mBox->GetNextBox(&mBox);
return DigDeep(aLayout, aSearchChildren);
}
*aLayout = nsnull;
return PR_FALSE;
}
// if its a scrollframe. Then continue down into the scrolled frame
nsresult rv = NS_OK;
nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(mBox, &rv);
if (scrollFrame) {
nsIFrame* scrolledFrame = nsnull;
scrollFrame->GetScrolledFrame(nsnull, scrolledFrame);
NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
mParents[mParentCount++] = mBox;
NS_ASSERTION(mParentCount < PARENT_STACK_SIZE, "Stack overflow!!");
nsCOMPtr<nsIBox> b = do_QueryInterface(scrolledFrame);
mBox = b;
}
// get the layout manager
nsCOMPtr<nsIBoxLayout> layout;
mBox->GetLayoutManager(getter_AddRefs(layout));
// if we are supposed to search our children. And the layout manager
// was null. Then dig into the children.
if (aSearchChildren && !layout)
{
mParents[mParentCount++] = mBox;
NS_ASSERTION(mParentCount < PARENT_STACK_SIZE, "Stack overflow!!");
mBox->GetChildBox(&mBox);
return DigDeep(aLayout, aSearchChildren);
}
*aLayout = layout;
NS_IF_ADDREF(*aLayout);
if (layout)
return PR_TRUE;
else
return PR_FALSE;
}
// ---- Monument Iterator -----
nsMonumentIterator::nsMonumentIterator(nsIBox* aBox):nsLayoutIterator(aBox)
{
}
PRBool
nsMonumentIterator::GetNextMonument(nsIMonument** aMonument, PRBool aSearchChildren)
{
nsCOMPtr<nsIBoxLayout> layout;
while(GetNextLayout(getter_AddRefs(layout), aSearchChildren)) {
if (layout)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMonument> monument = do_QueryInterface(layout, &rv);
*aMonument = monument;
if (monument) {
NS_IF_ADDREF(*aMonument);
return PR_TRUE;
}
}
}
return PR_FALSE;
}
PRBool
nsMonumentIterator::GetNextObelisk(nsObeliskLayout** aObelisk, PRBool aSearchChildren)
{
nsCOMPtr<nsIMonument> monument;
PRBool searchChildren = aSearchChildren;
while(GetNextMonument(getter_AddRefs(monument), searchChildren)) {
searchChildren = aSearchChildren;
if (monument)
{
*aObelisk = nsnull;
monument->CastToObelisk(aObelisk);
if (*aObelisk) {
return PR_TRUE;
}
// ok we found another grid. Don't enter it.
nsGridLayout* grid = nsnull;
monument->CastToGrid(&grid);
if (grid) {
searchChildren = PR_FALSE;
}
}
}
*aObelisk = nsnull;
return PR_FALSE;
}
//------ nsInfoListNodeImpl ----
nsBoxSizeListNodeImpl::~nsBoxSizeListNodeImpl()
{
}
void
nsBoxSizeListNodeImpl::Release(nsBoxLayoutState& aState)
{
delete this;
}
void
nsBoxSizeListNodeImpl::Desecrate(nsBoxLayoutState& aState)
{
if (mParent)
mParent->Desecrate(aState);
}
void
nsBoxSizeListNodeImpl::MarkDirty(nsBoxLayoutState& aState)
{
if (mBox)
mBox->MarkDirty(aState);
}
void nsBoxSizeListNodeImpl::SetNext(nsBoxLayoutState& aState, nsBoxSizeList* aNext)
{
mNext = aNext;
}
void nsBoxSizeListNodeImpl::SetAdjacent(nsBoxLayoutState& aState, nsBoxSizeList* aNext)
{
mAdjacent = aNext;
}
void
nsBoxSizeListNodeImpl::Append(nsBoxLayoutState& aState, nsBoxSizeList* aChild)
{
NS_ERROR("Attept at append to a leaf");
}
nsBoxSizeListNodeImpl::nsBoxSizeListNodeImpl(nsIBox* aBox):mNext(nsnull),
mParent(nsnull),
mAdjacent(nsnull),
mBox(aBox),
mRefCount(0),
mIsSet(PR_FALSE)
{
}
nsBoxSizeList*
nsBoxSizeListNodeImpl::GetAt(PRInt32 aIndex)
{
nsBoxSizeList* node = this;
PRInt32 count = 0;
while(node)
{
if (count == aIndex)
return node;
node = node->GetAdjacent();
count++;
}
return nsnull;
}
nsBoxSizeList*
nsBoxSizeListNodeImpl::Get(nsIBox* aBox)
{
nsBoxSizeList* node = this;
while(node)
{
if (node->GetBox() == aBox)
return node;
node = node->GetNext();
}
return nsnull;
}
//------ nsInfoListImpl2 ----
nsBoxSizeListImpl::nsBoxSizeListImpl(nsIBox* aBox):nsBoxSizeListNodeImpl(aBox),
mFirst(nsnull),
mLast(nsnull),
mCount(0),
mListener(nsnull),
mListenerBox(nsnull)
{
}
nsBoxSizeListImpl::~nsBoxSizeListImpl()
{
}
void
nsBoxSizeListImpl::Release(nsBoxLayoutState& aState)
{
if (mListener) {
mListener->WillBeDestroyed(mListenerBox, aState, *this);
}
nsBoxSizeList* list = mFirst;
while(list)
{
nsBoxSizeList* toRelease = list;
list = list->GetNext();
toRelease->SetParent(nsnull);
}
if (mAdjacent)
mAdjacent->Release(aState);
delete this;
}
void
nsBoxSizeListImpl::Clear(nsBoxLayoutState& aState)
{
nsBoxSizeList* list = mFirst;
while(list)
{
nsBoxSizeList* toRelease = list;
list = list->GetNext();
toRelease->Release(aState);
}
mFirst = nsnull;
mLast = nsnull;
}
void
nsBoxSizeListImpl::Append(nsBoxLayoutState& aState, nsBoxSizeList* aChild)
{
if (!mFirst)
mFirst = aChild;
else
mLast->SetNext(aState, aChild);
mLast = aChild;
mLast->SetNext(aState, nsnull);
aChild->SetParent(this);
}
void
nsBoxSizeListImpl::Desecrate(nsBoxLayoutState& aState)
{
if (mIsSet) {
mIsSet = PR_FALSE;
if (mListener)
mListener->Desecrated(mListenerBox, aState, *this);
nsBoxSizeListNodeImpl::Desecrate(aState);
}
}
void
nsBoxSizeListImpl::MarkDirty(nsBoxLayoutState& aState)
{
nsBoxSizeList* child = mFirst;
while(child)
{
child->MarkDirty(aState);
child = child->GetNext();
}
nsBoxSizeListNodeImpl::MarkDirty(aState);
}
PRBool
nsBoxSizeListImpl::SetListener(nsIBox* aBox, nsBoxSizeListener& aListener)
{
if (mListener)
return PR_FALSE;
mListener = &aListener;
mListenerBox = aBox;
return PR_TRUE;
}
void
nsBoxSizeListImpl::RemoveListener()
{
mListener = nsnull;
mListenerBox = nsnull;
}
nsBoxSize
nsBoxSizeListImpl::GetBoxSize(nsBoxLayoutState& aState, PRBool aIsHorizontal)
{
if (!mIsSet) {
mIsSet = PR_TRUE;
mBoxSize.Clear();
nsBoxSizeList* node = mFirst;
while(node) {
nsBoxSize size = node->GetBoxSize(aState, aIsHorizontal);
if (size.pref > mBoxSize.pref)
mBoxSize.pref = size.pref;
if (size.min > mBoxSize.min)
mBoxSize.min = size.min;
if (mBoxSize.max != NS_INTRINSICSIZE)
if (size.max == NS_INTRINSICSIZE)
mBoxSize.max = size.max;
else
mBoxSize.max += size.max;
mBoxSize.flex = size.flex;
mBoxSize.ascent = size.ascent;
node = node->GetNext();
}
}
return mBoxSize;
}
nsBoxSize
nsBoxSizeListNodeImpl::GetBoxSize(nsBoxLayoutState& aState, PRBool aIsHorizontal)
{
nsBoxSize size;
nsSize pref(0,0);
nsSize min(0,0);
nsSize max(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
nscoord ascent = 0;
nscoord flex = 0;
if (!mBox)
return size;
mBox->GetPrefSize(aState, pref);
mBox->GetMinSize(aState, min);
mBox->GetMaxSize(aState, max);
mBox->GetAscent(aState, ascent);
mBox->GetFlex(aState, flex);
nsBox::AddMargin(mBox, pref);
size.Add(min, pref, max, ascent, flex, !aIsHorizontal);
return size;
}
// ------ nsMonumentLayout ------
nsMonumentLayout::nsMonumentLayout(nsIPresShell* aPresShell):nsSprocketLayout()
{
}
NS_IMETHODIMP
nsMonumentLayout::CastToTemple(nsTempleLayout** aTemple)
{
*aTemple = nsnull;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsMonumentLayout::CastToObelisk(nsObeliskLayout** aObelisk)
{
*aObelisk = nsnull;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsMonumentLayout::CastToGrid(nsGridLayout** aGrid)
{
*aGrid = nsnull;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsMonumentLayout::GetParentMonument(nsIBox* aBox, nsCOMPtr<nsIBox>& aParentBox, nsIMonument** aParentMonument)
{
// go up and find our parent monument. Skip and non monument
// parents.
nsCOMPtr<nsIBoxLayout> layout;
nsCOMPtr<nsIMonument> parentMonument;
nsresult rv = NS_OK;
*aParentMonument = nsnull;
aBox->GetParentBox(&aBox);
while (aBox) {
aBox->GetLayoutManager(getter_AddRefs(layout));
parentMonument = do_QueryInterface(layout, &rv);
if (NS_SUCCEEDED(rv) && parentMonument) {
aParentBox = aBox;
*aParentMonument = parentMonument.get();
NS_IF_ADDREF(*aParentMonument);
return rv;
}
aBox->GetParentBox(&aBox);
}
aParentBox = nsnull;
*aParentMonument = nsnull;
return rv;
}
NS_IMETHODIMP
nsMonumentLayout::GetOtherMonuments(nsIBox* aBox, nsBoxSizeList** aList)
{
nsCOMPtr<nsIMonument> parent;
nsCOMPtr<nsIBox> parentBox;
GetParentMonument(aBox, parentBox, getter_AddRefs(parent));
return parent->GetOtherMonumentsAt(parentBox, 0, aList, this);
}
/**
* Get the monuments in the other temple at the give monument index
*/
NS_IMETHODIMP
nsMonumentLayout::GetOtherMonumentsAt(nsIBox* aBox, PRInt32 aIndexOfObelisk, nsBoxSizeList** aList, nsMonumentLayout* aRequestor)
{
nsresult rv = NS_OK;
PRInt32 index = -1;
nsIBox* child = nsnull;
aBox->GetChildBox(&child);
PRInt32 count = 0;
while(child)
{
nsCOMPtr<nsIBox> childBox = child;
nsCOMPtr<nsIScrollableFrame> scrollFrame = do_QueryInterface(child, &rv);
if (scrollFrame) {
nsIFrame* childFrame = nsnull;
scrollFrame->GetScrolledFrame(nsnull, childFrame);
if (!childFrame)
return NS_ERROR_FAILURE;
childBox = do_QueryInterface(childFrame);
}
nsCOMPtr<nsIBoxLayout> layout;
childBox->GetLayoutManager(getter_AddRefs(layout));
// only all monuments
nsCOMPtr<nsIMonument> monument = do_QueryInterface(layout, &rv);
if (NS_SUCCEEDED(rv) && monument)
{
if (layout == aRequestor) {
index = count;
break;
}
count++;
}
child->GetNextBox(&child);
}
NS_ASSERTION(index != -1,"Error can't find requestor!!");
aIndexOfObelisk += index;
nsCOMPtr<nsIMonument> parent;
nsCOMPtr<nsIBox> parentBox;
GetParentMonument(aBox, parentBox, getter_AddRefs(parent));
parent->GetOtherMonumentsAt(parentBox, aIndexOfObelisk, aList, this);
return NS_OK;
}
NS_IMETHODIMP
nsMonumentLayout::GetOtherTemple(nsIBox* aBox, nsTempleLayout** aTemple, nsIBox** aTempleBox, nsMonumentLayout* aRequestor)
{
nsCOMPtr<nsIMonument> parent;
nsCOMPtr<nsIBox> parentBox;
GetParentMonument(aBox, parentBox, getter_AddRefs(parent));
parent->GetOtherTemple(parentBox, aTemple, aTempleBox, this);
return NS_OK;
}
NS_IMETHODIMP
nsMonumentLayout::GetMonumentsAt(nsIBox* aBox, PRInt32 aMonumentIndex, nsBoxSizeList** aList)
{
nsBoxLayoutState state((nsIPresContext*)nsnull);
nsBoxSizeList* list = nsnull;
GetMonumentList(aBox, state, &list);
// create an info list for the given column.
PRInt32 count = 0;
while(list) {
if (count == aMonumentIndex)
{
*aList = list;
return NS_OK;
}
list = list->GetAdjacent();
count++;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsMonumentLayout::BuildBoxSizeList(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSize*& aFirst, nsBoxSize*& aLast, PRBool aIsHorizontal)
{
aFirst = aLast = new (aState) nsBoxSize();
nsSize pref(0,0);
nsSize min(0,0);
nsSize max(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
nscoord flex = 0;
nscoord ascent = 0;
aBox->GetPrefSize(aState, pref);
aBox->GetMinSize(aState, min);
aBox->GetMaxSize(aState, max);
aBox->GetAscent(aState, ascent);
aBox->GetFlex(aState, flex);
nsBox::BoundsCheck(min, pref, max);
nsMargin borderPadding(0,0,0,0);
aBox->GetBorderAndPadding(borderPadding);
nsMargin margin(0,0,0,0);
aBox->GetMargin(margin);
aFirst->Add(min, pref, max, ascent, flex, aIsHorizontal);
aFirst->Add(borderPadding,aIsHorizontal);
aFirst->Add(margin,aIsHorizontal);
return NS_OK;
}
NS_IMETHODIMP
nsMonumentLayout::GetMonumentList(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSizeList** aList)
{
nsIBox* child = nsnull;
aBox->GetChildBox(&child);
nsBoxSizeList* last = nsnull;
while(child)
{
nsBoxSizeList* newOne = new nsBoxSizeListNodeImpl(child);
if (*aList == nsnull)
*aList = last = newOne;
else {
last->SetAdjacent(aState, newOne);
last = newOne;
}
child->GetNextBox(&child);
}
return NS_OK;
}
NS_IMETHODIMP
nsMonumentLayout::EnscriptionChanged(nsBoxLayoutState& aState, PRInt32 aIndex)
{
NS_ERROR("Should Never be Called!");
return NS_OK;
}
NS_IMETHODIMP
nsMonumentLayout::DesecrateMonuments(nsIBox* aBox, nsBoxLayoutState& aState)
{
NS_ERROR("Should Never be Called!");
return NS_OK;
}
PRInt32
nsMonumentLayout::GetIndexOfChild(nsIBox* aBox, nsIBox* aChild)
{
nsIBox* child = nsnull;
aBox->GetChildBox(&child);
PRInt32 count = 0;
while(child)
{
if (child == aChild) {
return count;
}
child->GetNextBox(&child);
count++;
}
return -1;
}
NS_IMPL_ADDREF_INHERITED(nsMonumentLayout, nsBoxLayout);
NS_IMPL_RELEASE_INHERITED(nsMonumentLayout, nsBoxLayout);
NS_INTERFACE_MAP_BEGIN(nsMonumentLayout)
NS_INTERFACE_MAP_ENTRY(nsIMonument)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMonument)
NS_INTERFACE_MAP_END_INHERITING(nsBoxLayout)