2000-03-31 07:02:06 +00:00
|
|
|
/* -*- 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):
|
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
//
|
|
|
|
// Eric Vaughan
|
|
|
|
// Netscape Communications
|
|
|
|
//
|
|
|
|
// See documentation in associated header file
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "nsBoxLayoutState.h"
|
|
|
|
#include "nsSprocketLayout.h"
|
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIViewManager.h"
|
|
|
|
#include "nsIView.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsHTMLContainerFrame.h"
|
|
|
|
#include "nsBoxFrame.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsHTMLAtoms.h"
|
|
|
|
#include "nsXULAtoms.h"
|
|
|
|
#include "nsBoxFrame.h"
|
|
|
|
|
2000-04-05 00:19:00 +00:00
|
|
|
nsCOMPtr<nsIBoxLayout> nsSprocketLayout::gInstance = new nsSprocketLayout();
|
|
|
|
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
#define DEBUG_SPRING_SIZE 8
|
|
|
|
#define DEBUG_BORDER_SIZE 2
|
|
|
|
#define COIL_SIZE 8
|
|
|
|
|
2000-04-05 00:19:00 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
NS_NewSprocketLayout( nsIPresShell* aPresShell, nsCOMPtr<nsIBoxLayout>& aNewLayout)
|
|
|
|
{
|
|
|
|
// we have not instance variables so just return our static one.
|
|
|
|
aNewLayout = nsSprocketLayout::gInstance;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSprocketLayout::nsSprocketLayout()
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsSprocketLayout::IsHorizontal(nsIBox* aBox) const
|
|
|
|
{
|
|
|
|
nsIFrame* frame = nsnull;
|
|
|
|
aBox->GetFrame(&frame);
|
|
|
|
nsFrameState state;
|
|
|
|
frame->GetFrameState(&state);
|
|
|
|
return state & NS_STATE_IS_HORIZONTAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::GetFrameState(nsIBox* aBox, nsFrameState& aState)
|
|
|
|
{
|
|
|
|
nsIFrame* frame = nsnull;
|
|
|
|
aBox->GetFrame(&frame);
|
|
|
|
frame->GetFrameState(&aState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::SetFrameState(nsIBox* aBox, nsFrameState aState)
|
|
|
|
{
|
|
|
|
nsIFrame* frame = nsnull;
|
|
|
|
aBox->GetFrame(&frame);
|
|
|
|
frame->SetFrameState(aState);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
|
|
|
|
{
|
|
|
|
aState.PushStackMemory();
|
|
|
|
|
|
|
|
// ----- figure out our size ----------
|
|
|
|
nsRect contentRect;
|
|
|
|
aBox->GetContentRect(contentRect);
|
|
|
|
|
|
|
|
// -- make sure we remove our border and padding ----
|
|
|
|
nsRect clientRect;
|
|
|
|
aBox->GetClientRect(clientRect);
|
|
|
|
|
|
|
|
nsRect originalClientRect(clientRect);
|
|
|
|
|
|
|
|
nsFrameState frameState = 0;
|
|
|
|
GetFrameState(aBox, frameState);
|
|
|
|
|
|
|
|
//if (frameState & NS_STATE_CURRENTLY_IN_DEBUG)
|
|
|
|
// printf("In debug\n");
|
|
|
|
|
|
|
|
// ----- build a list of our child desired sizes and computeds sizes ------
|
|
|
|
|
|
|
|
nsBoxSize* boxSizes = nsnull;
|
|
|
|
nsComputedBoxSize* computedBoxSizes = nsnull;
|
|
|
|
|
|
|
|
nscoord maxAscent = 0;
|
|
|
|
aBox->GetAscent(aState, maxAscent);
|
|
|
|
|
|
|
|
nscoord minSize = 0;
|
|
|
|
nscoord maxSize = 0;
|
|
|
|
PRInt32 flexes = 0;
|
|
|
|
PopulateBoxSizes(aBox, aState, boxSizes, computedBoxSizes, minSize, maxSize, flexes);
|
|
|
|
|
|
|
|
nscoord width = clientRect.width;
|
|
|
|
if (!IsHorizontal(aBox))
|
|
|
|
width = clientRect.height;
|
|
|
|
|
2000-04-03 03:55:38 +00:00
|
|
|
ComputeChildSizes(aBox, aState, width, boxSizes, computedBoxSizes);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (IsHorizontal(aBox)) {
|
|
|
|
clientRect.width = width;
|
|
|
|
if (clientRect.height < minSize)
|
|
|
|
clientRect.height = minSize;
|
|
|
|
|
|
|
|
if (frameState & NS_STATE_AUTO_STRETCH) {
|
|
|
|
if (clientRect.height > maxSize)
|
|
|
|
clientRect.height = maxSize;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
clientRect.height = width;
|
|
|
|
if (clientRect.width < minSize)
|
|
|
|
clientRect.width = minSize;
|
|
|
|
|
|
|
|
if (frameState & NS_STATE_AUTO_STRETCH) {
|
|
|
|
if (clientRect.width > maxSize)
|
|
|
|
clientRect.width = maxSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------
|
|
|
|
// layout all children
|
|
|
|
// ----------------------
|
|
|
|
|
|
|
|
PRBool needsRedraw = PR_FALSE;
|
|
|
|
PRBool finished;
|
|
|
|
nscoord passes = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// ok what we want to do if flow each child at the location given in the spring.
|
|
|
|
// unfortunately after flowing a child it might get bigger. We have not control over this
|
|
|
|
// so it the child gets bigger or smaller than we expected we will have to do a 2nd, 3rd, 4th pass to
|
|
|
|
// adjust.
|
|
|
|
|
|
|
|
nscoord x = 0;
|
|
|
|
nscoord y = 0;
|
|
|
|
nsIBox::Halignment halign;
|
|
|
|
nsIBox::Valignment valign;
|
|
|
|
aBox->GetVAlign(valign);
|
|
|
|
aBox->GetHAlign(halign);
|
|
|
|
nscoord origX = 0;
|
|
|
|
nscoord origY = 0;
|
|
|
|
|
|
|
|
PRBool childResized = PR_FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
passes = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_REFLOW
|
|
|
|
if (passes > 0) {
|
|
|
|
AddIndents();
|
|
|
|
printf("ChildResized doing pass: %d\n", passes);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
finished = PR_TRUE;
|
|
|
|
|
|
|
|
x = clientRect.x;
|
|
|
|
y = clientRect.y;
|
|
|
|
|
|
|
|
if (!(frameState & NS_STATE_AUTO_STRETCH)) {
|
|
|
|
if (frameState & NS_STATE_IS_HORIZONTAL) {
|
|
|
|
switch(halign) {
|
|
|
|
case nsBoxFrame::hAlign_Left:
|
|
|
|
x = clientRect.x;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::hAlign_Center:
|
|
|
|
x = clientRect.x + (originalClientRect.width - clientRect.width)/2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::hAlign_Right:
|
|
|
|
x = clientRect.x + (originalClientRect.width - clientRect.width);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch(valign) {
|
|
|
|
case nsBoxFrame::vAlign_Top:
|
|
|
|
case nsBoxFrame::vAlign_BaseLine:
|
|
|
|
y = clientRect.y;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::vAlign_Middle:
|
|
|
|
y = clientRect.y + (originalClientRect.height - clientRect.height)/2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::vAlign_Bottom:
|
|
|
|
y = clientRect.y + (originalClientRect.height - clientRect.height);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
origX = x;
|
|
|
|
origY = y;
|
|
|
|
|
|
|
|
nscoord nextX = x;
|
|
|
|
nscoord nextY = y;
|
|
|
|
|
|
|
|
nsComputedBoxSize* childComputedBoxSize = computedBoxSizes;
|
|
|
|
nsBoxSize* childBoxSize = boxSizes;
|
|
|
|
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
PRInt32 count = 0;
|
|
|
|
while (child)
|
|
|
|
{
|
|
|
|
nscoord width = clientRect.width;
|
|
|
|
nscoord height = clientRect.height;
|
|
|
|
|
|
|
|
nsSize prefSize(0,0);
|
|
|
|
nsSize minSize(0,0);
|
|
|
|
nsSize maxSize(0,0);
|
|
|
|
|
|
|
|
if (!(frameState & NS_STATE_AUTO_STRETCH)) {
|
|
|
|
child->GetPrefSize(aState, prefSize);
|
|
|
|
child->GetMinSize(aState, minSize);
|
|
|
|
child->GetMaxSize(aState, maxSize);
|
|
|
|
nsBox::BoundsCheck(minSize, prefSize, maxSize);
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (width < minSize.width)
|
|
|
|
width = minSize.width;
|
|
|
|
if (height < minSize.height)
|
|
|
|
height = minSize.height;
|
|
|
|
*/
|
|
|
|
AddMargin(child, prefSize);
|
|
|
|
width = prefSize.width > originalClientRect.width ? originalClientRect.width : prefSize.width;
|
|
|
|
height = prefSize.height > originalClientRect.height ? originalClientRect.height : prefSize.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// figure our our child's computed width and height
|
|
|
|
if (frameState & NS_STATE_IS_HORIZONTAL) {
|
|
|
|
width = childComputedBoxSize->size;
|
|
|
|
} else {
|
|
|
|
height = childComputedBoxSize->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
nextX = x;
|
|
|
|
nextY = y;
|
|
|
|
|
|
|
|
nsRect childRect(x, y, width, height);
|
|
|
|
|
|
|
|
if (!childBoxSize->collapsed) {
|
|
|
|
/*
|
|
|
|
if (childRect.width > originalClientRect.width || childRect.height > originalClientRect.height) {
|
|
|
|
if (childRect.width > originalClientRect.width)
|
|
|
|
originalClientRect.width = childRect.width;
|
|
|
|
|
|
|
|
if (childRect.height > originalClientRect.height)
|
|
|
|
originalClientRect.height = childRect.height;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (childRect.width > clientRect.width || childRect.height > clientRect.height) {
|
|
|
|
if (childRect.width > clientRect.width)
|
|
|
|
clientRect.width = childRect.width;
|
|
|
|
|
|
|
|
if (childRect.height > clientRect.height)
|
|
|
|
clientRect.height = childRect.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ComputeChildsNextPosition(aBox, child,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
nextX,
|
|
|
|
nextY,
|
|
|
|
childRect,
|
|
|
|
originalClientRect,
|
|
|
|
childBoxSize->ascent,
|
|
|
|
maxAscent);
|
|
|
|
|
|
|
|
|
|
|
|
childRect.x = x;
|
|
|
|
childRect.y = y;
|
|
|
|
|
|
|
|
nsMargin margin(0,0,0,0);
|
|
|
|
child->GetMargin(margin);
|
|
|
|
|
|
|
|
childRect.Deflate(margin);
|
|
|
|
|
|
|
|
PRBool layout = PR_TRUE;
|
|
|
|
|
|
|
|
if (passes > 0) {
|
|
|
|
layout = PR_FALSE;
|
|
|
|
} else {
|
|
|
|
// always layout if we are dirty or have dirty children
|
|
|
|
PRBool dirty = PR_FALSE;
|
|
|
|
PRBool dirtyChildren = PR_FALSE;
|
|
|
|
child->IsDirty(dirty);
|
|
|
|
child->HasDirtyChildren(dirtyChildren);
|
|
|
|
if (!(dirty || dirtyChildren) && aState.GetLayoutReason() != nsBoxLayoutState::Initial) {
|
|
|
|
layout = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect oldRect(0,0,0,0);
|
|
|
|
child->GetBounds(oldRect);
|
|
|
|
child->SetBounds(aState, childRect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PRBool sizeChanged = (childRect.width != oldRect.width || childRect.height != oldRect.height);
|
|
|
|
|
|
|
|
if (sizeChanged) {
|
|
|
|
nsSize maxSize;
|
|
|
|
child->GetMaxSize(aState, maxSize);
|
|
|
|
|
|
|
|
// make sure the size is in our max size.
|
|
|
|
if (childRect.width > maxSize.width)
|
|
|
|
childRect.width = maxSize.width;
|
|
|
|
|
|
|
|
if (childRect.height > maxSize.height)
|
|
|
|
childRect.height = maxSize.height;
|
|
|
|
|
|
|
|
// set it again
|
|
|
|
child->SetBounds(aState, childRect);
|
|
|
|
|
|
|
|
needsRedraw = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (childBoxSize)
|
|
|
|
if(!childBoxSize->collapsed)
|
|
|
|
child->UnCollapse(aState);
|
|
|
|
|
|
|
|
if (layout || sizeChanged) {
|
|
|
|
child->Layout(aState);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make collapsed children not show up
|
|
|
|
if (childBoxSize && childBoxSize->collapsed) {
|
|
|
|
child->Collapse(aState);
|
|
|
|
} else {
|
|
|
|
// if the child was html it may have changed its rect. Lets look
|
|
|
|
nsRect newChildRect;
|
|
|
|
child->GetBounds(newChildRect);
|
|
|
|
|
|
|
|
if (newChildRect != childRect)
|
|
|
|
{
|
|
|
|
newChildRect.Inflate(margin);
|
|
|
|
childRect.Inflate(margin);
|
|
|
|
|
|
|
|
// ok the child changed size
|
|
|
|
ChildResized(aBox,
|
|
|
|
aState,
|
|
|
|
child,
|
|
|
|
childBoxSize,
|
|
|
|
childComputedBoxSize,
|
|
|
|
boxSizes,
|
|
|
|
computedBoxSizes,
|
|
|
|
childRect,
|
|
|
|
newChildRect,
|
|
|
|
clientRect,
|
|
|
|
flexes,
|
|
|
|
finished);
|
|
|
|
|
|
|
|
childResized = PR_TRUE;
|
|
|
|
|
|
|
|
if (clientRect.width > originalClientRect.width || clientRect.height > originalClientRect.height) {
|
|
|
|
if (clientRect.width > originalClientRect.width)
|
|
|
|
originalClientRect.width = clientRect.width;
|
|
|
|
|
|
|
|
if (clientRect.height > originalClientRect.height)
|
|
|
|
originalClientRect.height = clientRect.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if the child resized then recompute it position.
|
|
|
|
ComputeChildsNextPosition(aBox, child,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
nextX,
|
|
|
|
nextY,
|
|
|
|
newChildRect,
|
|
|
|
originalClientRect,
|
|
|
|
childBoxSize->ascent,
|
|
|
|
maxAscent);
|
|
|
|
|
|
|
|
newChildRect.x = x;
|
|
|
|
newChildRect.y = y;
|
|
|
|
|
|
|
|
newChildRect.Deflate(margin);
|
|
|
|
childRect.Deflate(margin);
|
|
|
|
|
|
|
|
child->SetBounds(aState, newChildRect);
|
|
|
|
|
|
|
|
// if we are the first we don't need to do a second pass
|
|
|
|
if (count == 0)
|
|
|
|
finished = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
x = nextX;
|
|
|
|
y = nextY;
|
|
|
|
}
|
|
|
|
|
|
|
|
childComputedBoxSize = childComputedBoxSize->next;
|
|
|
|
childBoxSize = childBoxSize->next;
|
|
|
|
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
passes++;
|
|
|
|
if (passes > 10) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (PR_FALSE == finished);
|
|
|
|
|
|
|
|
while(boxSizes)
|
|
|
|
{
|
2000-04-05 23:46:48 +00:00
|
|
|
nsBoxSize* toDelete = boxSizes;
|
2000-03-31 07:02:06 +00:00
|
|
|
boxSizes = boxSizes->next;
|
|
|
|
delete toDelete;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(computedBoxSizes)
|
|
|
|
{
|
2000-04-05 23:46:48 +00:00
|
|
|
nsComputedBoxSize* toDelete = computedBoxSizes;
|
2000-03-31 07:02:06 +00:00
|
|
|
computedBoxSizes = computedBoxSizes->next;
|
|
|
|
delete toDelete;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (childResized) {
|
|
|
|
// see if one of our children forced us to get bigger
|
|
|
|
nsRect tmpClientRect(originalClientRect);
|
|
|
|
nsMargin bp(0,0,0,0);
|
|
|
|
aBox->GetBorderAndPadding(bp);
|
|
|
|
tmpClientRect.Inflate(bp);
|
|
|
|
aBox->GetInset(bp);
|
|
|
|
tmpClientRect.Inflate(bp);
|
|
|
|
|
|
|
|
if (tmpClientRect.width > contentRect.width || tmpClientRect.height > contentRect.height)
|
|
|
|
{
|
|
|
|
// if it did reset our bounds.
|
|
|
|
nsRect bounds(0,0,0,0);
|
|
|
|
aBox->GetBounds(bounds);
|
|
|
|
if (tmpClientRect.width > contentRect.width)
|
|
|
|
bounds.width = tmpClientRect.width;
|
|
|
|
|
|
|
|
if (tmpClientRect.height > contentRect.height)
|
|
|
|
bounds.height = tmpClientRect.height;
|
|
|
|
|
|
|
|
aBox->SetBounds(aState, bounds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x = clientRect.x;
|
|
|
|
y = clientRect.y;
|
|
|
|
|
|
|
|
if (!(frameState & NS_STATE_AUTO_STRETCH)) {
|
|
|
|
if (frameState & NS_STATE_IS_HORIZONTAL) {
|
|
|
|
switch(halign) {
|
|
|
|
case nsBoxFrame::hAlign_Left:
|
|
|
|
x = clientRect.x;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::hAlign_Center:
|
|
|
|
x = clientRect.x + (originalClientRect.width - clientRect.width)/2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::hAlign_Right:
|
|
|
|
x = clientRect.x + (originalClientRect.width - clientRect.width);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch(valign) {
|
|
|
|
case nsBoxFrame::vAlign_Top:
|
|
|
|
case nsBoxFrame::vAlign_BaseLine:
|
|
|
|
y = clientRect.y;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::vAlign_Middle:
|
|
|
|
y = clientRect.y + (originalClientRect.height - clientRect.height)/2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::vAlign_Bottom:
|
|
|
|
y = clientRect.y + (originalClientRect.height - clientRect.height);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x != origX || y != origY) {
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
// reposition all our children
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
{
|
|
|
|
nsRect childRect;
|
|
|
|
child->GetBounds(childRect);
|
|
|
|
childRect.x += (x - origX);
|
|
|
|
childRect.y += (y - origY);
|
|
|
|
child->SetBounds(aState, childRect);
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needsRedraw)
|
|
|
|
aBox->Redraw(aState);
|
|
|
|
|
|
|
|
aState.PopStackMemory();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::PopulateBoxSizes(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nsComputedBoxSize*& aComputedBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, PRInt32& aFlexes)
|
|
|
|
{
|
|
|
|
nsFrameState frameState = 0;
|
|
|
|
GetFrameState(aBox, frameState);
|
|
|
|
|
|
|
|
//if (frameState & NS_STATE_CURRENTLY_IN_DEBUG)
|
|
|
|
// printf("In debug\n");
|
|
|
|
|
|
|
|
aMinSize = 0;
|
|
|
|
aMaxSize = NS_INTRINSICSIZE;
|
|
|
|
|
|
|
|
PRBool isHorizontal;
|
|
|
|
|
|
|
|
if (IsHorizontal(aBox))
|
|
|
|
isHorizontal = PR_TRUE;
|
|
|
|
else
|
|
|
|
isHorizontal = PR_FALSE;
|
|
|
|
|
|
|
|
// this is a nice little optimization
|
|
|
|
// it turns out that if we only have 1 flexable child
|
|
|
|
// then it does not matter what its prefered size is
|
|
|
|
// there is nothing to flex it relative. This is great
|
|
|
|
// because we can avoid asking for a preferred size in this
|
|
|
|
// case. Why is this good? Well you might have html inside it
|
|
|
|
// and asking html for its preferred size is rather expensive.
|
|
|
|
// so we can just optimize it out this way.
|
|
|
|
|
|
|
|
// set flexes
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
PRInt32 count = 0;
|
|
|
|
aFlexes = 0;
|
|
|
|
nsBoxSize* currentBox = nsnull;
|
2000-04-05 08:20:24 +00:00
|
|
|
//nsComputedBoxSize* currentComputed = nsnull;
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
while(child)
|
|
|
|
{
|
|
|
|
if (!currentBox) {
|
2000-04-05 23:46:48 +00:00
|
|
|
aBoxSizes = new (aState) nsBoxSize();
|
2000-04-05 08:20:24 +00:00
|
|
|
//aComputedBoxSizes = new (aState) nsComputedBoxSizeSpecial();
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
currentBox = aBoxSizes;
|
2000-04-05 08:20:24 +00:00
|
|
|
//currentComputed = aComputedBoxSizes;
|
2000-03-31 07:02:06 +00:00
|
|
|
} else {
|
2000-04-05 23:46:48 +00:00
|
|
|
currentBox->next = new (aState) nsBoxSize();
|
2000-04-05 08:20:24 +00:00
|
|
|
//currentComputed->next = new (aState) nsComputedBoxSizeSpecial();
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
currentBox = currentBox->next;
|
2000-04-05 08:20:24 +00:00
|
|
|
//currentComputed = currentComputed->next;
|
2000-03-31 07:02:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nscoord flex = 0;
|
|
|
|
child->GetFlex(aState, flex);
|
|
|
|
PRBool collapsed = PR_FALSE;
|
|
|
|
child->IsCollapsed(aState, collapsed);
|
|
|
|
|
|
|
|
currentBox->flex = flex;
|
|
|
|
currentBox->collapsed = collapsed;
|
2000-04-05 08:20:24 +00:00
|
|
|
//currentComputed->resized = PR_FALSE;
|
|
|
|
//currentComputed->size = 0;
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
if (flex > 0)
|
|
|
|
aFlexes++;
|
|
|
|
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get pref, min, max
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
currentBox = aBoxSizes;
|
|
|
|
while(child)
|
|
|
|
{
|
|
|
|
nsSize pref(0,0);
|
|
|
|
nsSize min(0,0);
|
|
|
|
nsSize max(0,0);
|
|
|
|
|
|
|
|
// only one flexible child? Cool we will just make its preferred size
|
|
|
|
// 0 then and not even have to ask for it.
|
|
|
|
//if (flexes != 1) {
|
|
|
|
child->GetPrefSize(aState, pref);
|
|
|
|
child->GetAscent(aState, currentBox->ascent);
|
|
|
|
nsMargin margin;
|
|
|
|
child->GetMargin(margin);
|
|
|
|
currentBox->ascent += margin.top + margin.bottom;
|
|
|
|
//}
|
|
|
|
|
|
|
|
child->GetMinSize(aState, min);
|
|
|
|
child->GetMaxSize(aState, max);
|
|
|
|
nsBox::BoundsCheck(min, pref, max);
|
|
|
|
|
|
|
|
AddMargin(child, pref);
|
|
|
|
AddMargin(child, min);
|
|
|
|
AddMargin(child, max);
|
|
|
|
|
|
|
|
nscoord minWidth = min.width;
|
|
|
|
nscoord maxWidth = max.width;
|
|
|
|
nscoord prefWidth = pref.width;
|
|
|
|
|
|
|
|
if (!isHorizontal) {
|
|
|
|
minWidth = min.height;
|
|
|
|
maxWidth = max.height;
|
|
|
|
prefWidth = pref.height;
|
|
|
|
if (min.width > aMinSize)
|
|
|
|
aMinSize = min.width;
|
|
|
|
|
|
|
|
if (max.width < aMaxSize)
|
|
|
|
aMaxSize = max.width;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (min.height > aMinSize)
|
|
|
|
aMinSize = min.height;
|
|
|
|
|
|
|
|
if (max.height < aMaxSize)
|
|
|
|
aMaxSize = max.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(minWidth <= prefWidth && prefWidth <= maxWidth,"Bad min, pref, max widths!");
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (minWidth > maxWidth)
|
|
|
|
minWidth = maxWidth;
|
|
|
|
|
|
|
|
if (prefWidth > maxWidth)
|
|
|
|
prefWidth = maxWidth;
|
|
|
|
|
|
|
|
if (prefWidth < minWidth)
|
|
|
|
prefWidth = minWidth;
|
|
|
|
*/
|
|
|
|
|
|
|
|
currentBox->pref = prefWidth;
|
|
|
|
currentBox->min = minWidth;
|
|
|
|
currentBox->max = maxWidth;
|
|
|
|
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
currentBox = currentBox->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::ComputeChildsNextPosition(nsIBox* aBox,
|
|
|
|
nsIBox* aChild,
|
|
|
|
nscoord& aCurX,
|
|
|
|
nscoord& aCurY,
|
|
|
|
nscoord& aNextX,
|
|
|
|
nscoord& aNextY,
|
|
|
|
const nsRect& aCurrentChildSize,
|
|
|
|
const nsRect& aBoxRect,
|
|
|
|
nscoord childAscent,
|
|
|
|
nscoord aMaxAscent)
|
|
|
|
{
|
|
|
|
nsFrameState frameState = 0;
|
|
|
|
GetFrameState(aBox, frameState);
|
|
|
|
|
|
|
|
nsIBox::Halignment halign;
|
|
|
|
nsIBox::Valignment valign;
|
|
|
|
aBox->GetVAlign(valign);
|
|
|
|
aBox->GetHAlign(halign);
|
|
|
|
|
|
|
|
if (IsHorizontal(aBox)) {
|
|
|
|
aNextX = aCurX + aCurrentChildSize.width;
|
|
|
|
|
|
|
|
if (frameState & NS_STATE_AUTO_STRETCH) {
|
|
|
|
aCurY = aBoxRect.y;
|
|
|
|
} else {
|
|
|
|
switch (valign)
|
|
|
|
{
|
|
|
|
case nsBoxFrame::vAlign_BaseLine:
|
|
|
|
aCurY = aBoxRect.y + (aMaxAscent - childAscent);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsBoxFrame::vAlign_Top:
|
|
|
|
aCurY = aBoxRect.y;
|
|
|
|
break;
|
|
|
|
case nsBoxFrame::vAlign_Middle:
|
|
|
|
aCurY = aBoxRect.y + (aBoxRect.height/2 - aCurrentChildSize.height/2);
|
|
|
|
break;
|
|
|
|
case nsBoxFrame::vAlign_Bottom:
|
|
|
|
aCurY = aBoxRect.y + aBoxRect.height - aCurrentChildSize.height;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
aNextY = aCurY + aCurrentChildSize.height;
|
|
|
|
if (frameState & NS_STATE_AUTO_STRETCH) {
|
|
|
|
aCurX = aBoxRect.x;
|
|
|
|
} else {
|
|
|
|
switch (halign)
|
|
|
|
{
|
|
|
|
case nsBoxFrame::hAlign_Left:
|
|
|
|
aCurX = aBoxRect.x;
|
|
|
|
break;
|
|
|
|
case nsBoxFrame::hAlign_Center:
|
|
|
|
aCurX = aBoxRect.x + (aBoxRect.width/2 - aCurrentChildSize.width/2);
|
|
|
|
break;
|
|
|
|
case nsBoxFrame::hAlign_Right:
|
|
|
|
aCurX = aBoxRect.x + aBoxRect.width - aCurrentChildSize.width;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::ChildResized(nsIBox* aBox,
|
|
|
|
nsBoxLayoutState& aState,
|
|
|
|
nsIBox* aChild,
|
|
|
|
nsBoxSize* aChildBoxSize,
|
|
|
|
nsComputedBoxSize* aChildComputedSize,
|
|
|
|
nsBoxSize* aBoxSizes,
|
|
|
|
nsComputedBoxSize* aComputedBoxSizes,
|
|
|
|
const nsRect& aChildLayoutRect,
|
|
|
|
nsRect& aChildActualRect,
|
|
|
|
nsRect& aContainingRect,
|
|
|
|
PRInt32 aFlexes,
|
|
|
|
PRBool& aFinished)
|
|
|
|
|
|
|
|
{
|
|
|
|
nsRect childCurrentRect(aChildLayoutRect);
|
|
|
|
|
|
|
|
PRBool isHorizontal = IsHorizontal(aBox);
|
|
|
|
nscoord childLayoutWidth = GET_WIDTH(aChildLayoutRect,isHorizontal);
|
|
|
|
nscoord& childActualWidth = GET_WIDTH(aChildActualRect,isHorizontal);
|
|
|
|
nscoord& containingWidth = GET_WIDTH(aContainingRect,isHorizontal);
|
|
|
|
|
|
|
|
nscoord childLayoutHeight = GET_HEIGHT(aChildLayoutRect,isHorizontal);
|
|
|
|
nscoord& childActualHeight = GET_HEIGHT(aChildActualRect,isHorizontal);
|
|
|
|
nscoord& containingHeight = GET_HEIGHT(aContainingRect,isHorizontal);
|
|
|
|
|
|
|
|
PRBool recompute = PR_FALSE;
|
|
|
|
|
|
|
|
// if we are a horizontal box see if the child will fit inside us.
|
|
|
|
if ( childActualHeight > containingHeight) {
|
|
|
|
// if we are a horizontal box and the the child it bigger than our height
|
|
|
|
|
|
|
|
// ok if the height changed then we need to reflow everyone but us at the new height
|
|
|
|
// so we will set the changed index to be us. And signal that we need a new pass.
|
|
|
|
|
|
|
|
nsSize max(0,0);
|
|
|
|
aChild->GetMaxSize(aState, max);
|
2000-04-05 23:46:48 +00:00
|
|
|
AddMargin(aChild, max);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
if (isHorizontal)
|
|
|
|
childActualHeight = max.height < childActualHeight ? max.height : childActualHeight;
|
|
|
|
else
|
|
|
|
childActualHeight = max.width < childActualHeight ? max.width : childActualHeight;
|
|
|
|
|
|
|
|
// only set if it changes
|
|
|
|
if (childActualHeight > containingHeight) {
|
|
|
|
containingHeight = childActualHeight;
|
|
|
|
|
|
|
|
// remember we do not need to clear the resized list because changing the height of a horizontal box
|
|
|
|
// will not affect the width of any of its children because block flow left to right, top to bottom. Just trust me
|
|
|
|
// on this one.
|
|
|
|
aFinished = PR_FALSE;
|
|
|
|
|
|
|
|
// only recompute if there are flexes.
|
|
|
|
if (aFlexes > 0) {
|
|
|
|
// relayout everything
|
|
|
|
recompute = PR_TRUE;
|
|
|
|
InvalidateComputedSizes(aComputedBoxSizes);
|
|
|
|
nsComputedBoxSize* node = aComputedBoxSizes;
|
|
|
|
|
|
|
|
while(node) {
|
|
|
|
node->resized = PR_FALSE;
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (childActualWidth > childLayoutWidth) {
|
|
|
|
nsSize max(0,0);
|
|
|
|
aChild->GetMaxSize(aState, max);
|
2000-04-05 23:46:48 +00:00
|
|
|
AddMargin(aChild, max);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
// our width now becomes the new size
|
|
|
|
|
|
|
|
if (isHorizontal)
|
|
|
|
childActualWidth = max.width < childActualWidth ? max.width : childActualWidth;
|
|
|
|
else
|
|
|
|
childActualWidth = max.height < childActualWidth ? max.height : childActualWidth;
|
|
|
|
|
|
|
|
if (childActualWidth > childLayoutWidth) {
|
|
|
|
aChildComputedSize->size = childActualWidth;
|
|
|
|
aChildBoxSize->min = childActualWidth;
|
|
|
|
if (aChildBoxSize->pref < childActualWidth)
|
|
|
|
aChildBoxSize->pref = childActualWidth;
|
|
|
|
|
|
|
|
// if we have flexible elements with us then reflex things. Otherwise we can skip doing it.
|
|
|
|
if (aFlexes > 0) {
|
|
|
|
InvalidateComputedSizes(aComputedBoxSizes);
|
|
|
|
|
|
|
|
nsComputedBoxSize* node = aComputedBoxSizes;
|
|
|
|
aChildComputedSize->resized = PR_TRUE;
|
|
|
|
|
|
|
|
while(node) {
|
|
|
|
if (node->resized)
|
|
|
|
node->valid = PR_TRUE;
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
recompute = PR_TRUE;
|
|
|
|
aFinished = PR_FALSE;
|
|
|
|
} else {
|
|
|
|
containingWidth += aChildComputedSize->size - childLayoutWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (recompute)
|
2000-04-03 03:55:38 +00:00
|
|
|
ComputeChildSizes(aBox, aState, containingWidth, aBoxSizes, aComputedBoxSizes);
|
2000-03-31 07:02:06 +00:00
|
|
|
|
|
|
|
if (childCurrentRect != aChildActualRect) {
|
|
|
|
aChild->SetBounds(aState, aChildActualRect);
|
|
|
|
aChild->Layout(aState);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::InvalidateComputedSizes(nsComputedBoxSize* aComputedBoxSizes)
|
|
|
|
{
|
|
|
|
while(aComputedBoxSizes) {
|
|
|
|
aComputedBoxSizes->valid = PR_FALSE;
|
|
|
|
aComputedBoxSizes = aComputedBoxSizes->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-04-03 03:55:38 +00:00
|
|
|
nsSprocketLayout::ComputeChildSizes(nsIBox* aBox,
|
|
|
|
nsBoxLayoutState& aState,
|
2000-03-31 07:02:06 +00:00
|
|
|
nscoord& aGivenSize,
|
|
|
|
nsBoxSize* aBoxSizes,
|
2000-04-05 06:41:27 +00:00
|
|
|
nsComputedBoxSize*& aComputedBoxSizes)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
PRInt32 sizeRemaining = aGivenSize;
|
|
|
|
PRInt32 springConstantsRemaining = 0;
|
|
|
|
|
|
|
|
// ----- calculate the springs constants and the size remaining -----
|
|
|
|
|
2000-04-05 06:41:27 +00:00
|
|
|
if (aBoxSizes && !aComputedBoxSizes)
|
2000-04-05 23:46:48 +00:00
|
|
|
aComputedBoxSizes = new (aState) nsComputedBoxSize();
|
2000-04-05 06:41:27 +00:00
|
|
|
|
2000-03-31 07:02:06 +00:00
|
|
|
nsBoxSize* boxSizes = aBoxSizes;
|
|
|
|
nsComputedBoxSize* computedBoxSizes = aComputedBoxSizes;
|
|
|
|
PRInt32 count = 0;
|
|
|
|
PRInt32 validCount = 0;
|
|
|
|
|
|
|
|
while (boxSizes || computedBoxSizes)
|
|
|
|
{
|
2000-04-05 06:41:27 +00:00
|
|
|
|
2000-03-31 07:02:06 +00:00
|
|
|
NS_ASSERTION(!boxSizes || (boxSizes->min <= boxSizes->pref && boxSizes->pref <= boxSizes->max),"bad pref, min, max size");
|
|
|
|
|
|
|
|
// ignore collapsed children
|
|
|
|
if (boxSizes && boxSizes->collapsed)
|
|
|
|
{
|
|
|
|
computedBoxSizes->valid = PR_TRUE;
|
|
|
|
computedBoxSizes->size = boxSizes->pref;
|
|
|
|
validCount++;
|
|
|
|
} else {
|
|
|
|
if (computedBoxSizes && computedBoxSizes->valid) {
|
|
|
|
sizeRemaining -= computedBoxSizes->size;
|
|
|
|
validCount++;
|
|
|
|
} else {
|
2000-04-05 06:41:27 +00:00
|
|
|
if (boxSizes && computedBoxSizes) {
|
2000-03-31 07:02:06 +00:00
|
|
|
if (boxSizes->flex == 0)
|
|
|
|
{
|
|
|
|
computedBoxSizes->valid = PR_TRUE;
|
|
|
|
computedBoxSizes->size = boxSizes->pref;
|
|
|
|
validCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
springConstantsRemaining += boxSizes->flex;
|
|
|
|
sizeRemaining -= boxSizes->pref;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-05 06:41:27 +00:00
|
|
|
boxSizes = boxSizes->next;
|
|
|
|
|
|
|
|
if (boxSizes && !computedBoxSizes->next)
|
2000-04-05 23:46:48 +00:00
|
|
|
computedBoxSizes->next = new (aState) nsComputedBoxSize();
|
2000-04-05 06:41:27 +00:00
|
|
|
|
2000-03-31 07:02:06 +00:00
|
|
|
computedBoxSizes = computedBoxSizes->next;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// everything accounted for?
|
|
|
|
if (validCount < count)
|
|
|
|
{
|
|
|
|
// ----- Ok we are give a size to fit into so stretch or squeeze to fit
|
|
|
|
// ----- Make sure we look at our min and max size
|
|
|
|
PRBool limit = PR_TRUE;
|
|
|
|
for (int pass=1; PR_TRUE == limit; pass++)
|
|
|
|
{
|
|
|
|
limit = PR_FALSE;
|
|
|
|
boxSizes = aBoxSizes;
|
|
|
|
computedBoxSizes = aComputedBoxSizes;
|
|
|
|
|
|
|
|
while (boxSizes || computedBoxSizes) {
|
|
|
|
|
|
|
|
// ignore collapsed springs
|
|
|
|
|
|
|
|
if (!(boxSizes && boxSizes->collapsed)) {
|
|
|
|
|
|
|
|
nscoord pref = 0;
|
|
|
|
nscoord max = NS_INTRINSICSIZE;
|
|
|
|
nscoord min = 0;
|
|
|
|
nscoord flex = 0;
|
|
|
|
|
|
|
|
if (boxSizes)
|
|
|
|
{
|
|
|
|
pref = boxSizes->pref;
|
|
|
|
min = boxSizes->min;
|
|
|
|
max = boxSizes->max;
|
|
|
|
flex = boxSizes->flex;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----- look at our min and max limits make sure we aren't too small or too big -----
|
|
|
|
if (!(computedBoxSizes && computedBoxSizes->valid)) {
|
|
|
|
PRInt32 newSize = pref + (sizeRemaining*flex/springConstantsRemaining);
|
|
|
|
if (newSize<=min) {
|
|
|
|
|
|
|
|
if (computedBoxSizes) {
|
|
|
|
computedBoxSizes->size = min;
|
|
|
|
computedBoxSizes->valid = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
springConstantsRemaining -= flex;
|
|
|
|
sizeRemaining += pref;
|
|
|
|
sizeRemaining -= min;
|
|
|
|
limit = PR_TRUE;
|
|
|
|
} else if (newSize>=max) {
|
|
|
|
if (computedBoxSizes) {
|
|
|
|
computedBoxSizes->size = max;
|
|
|
|
computedBoxSizes->valid = PR_TRUE;
|
|
|
|
}
|
|
|
|
springConstantsRemaining -= flex;
|
|
|
|
sizeRemaining += pref;
|
|
|
|
sizeRemaining -= max;
|
|
|
|
limit = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boxSizes = boxSizes->next;
|
|
|
|
computedBoxSizes = computedBoxSizes->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---- once we have removed and min and max issues just stretch us out in the remaining space
|
|
|
|
// ---- or shrink us. Depends on the size remaining and the spring constants
|
|
|
|
aGivenSize = 0;
|
|
|
|
boxSizes = aBoxSizes;
|
|
|
|
computedBoxSizes = aComputedBoxSizes;
|
|
|
|
|
|
|
|
while (boxSizes || computedBoxSizes) {
|
|
|
|
|
|
|
|
// ignore collapsed springs
|
|
|
|
if (!(boxSizes && boxSizes->collapsed)) {
|
|
|
|
|
|
|
|
nscoord pref = 0;
|
|
|
|
nscoord flex = 0;
|
|
|
|
if (boxSizes) {
|
|
|
|
pref = boxSizes->pref;
|
|
|
|
flex = boxSizes->flex;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (computedBoxSizes) {
|
|
|
|
if (!computedBoxSizes->valid) {
|
|
|
|
computedBoxSizes->size = pref + flex*sizeRemaining/springConstantsRemaining;
|
|
|
|
computedBoxSizes->valid = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
aGivenSize += computedBoxSizes->size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
boxSizes = boxSizes->next;
|
|
|
|
computedBoxSizes = computedBoxSizes->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
|
|
|
|
{
|
|
|
|
PRBool isHorizontal = IsHorizontal(aBox);
|
|
|
|
|
|
|
|
aSize.width = 0;
|
|
|
|
aSize.height = 0;
|
|
|
|
|
|
|
|
// run through all the children and get there min, max, and preferred sizes
|
|
|
|
// return us the size of the box
|
|
|
|
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
{
|
|
|
|
// ignore collapsed children
|
|
|
|
PRBool isCollapsed = PR_FALSE;
|
|
|
|
child->IsCollapsed(aState, isCollapsed);
|
|
|
|
|
|
|
|
if (!isCollapsed)
|
|
|
|
{
|
|
|
|
nsSize pref(0,0);
|
|
|
|
child->GetPrefSize(aState, pref);
|
|
|
|
AddMargin(child, pref);
|
|
|
|
AddLargestSize(aSize, pref, isHorizontal);
|
|
|
|
}
|
|
|
|
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now add our border and padding and insets
|
|
|
|
AddBorderAndPadding(aBox, aSize);
|
|
|
|
AddInset(aBox, aSize);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
|
|
|
|
{
|
|
|
|
PRBool isHorizontal = IsHorizontal(aBox);
|
|
|
|
|
|
|
|
|
|
|
|
aSize.width = 0;
|
|
|
|
aSize.height = 0;
|
|
|
|
|
|
|
|
// run through all the children and get there min, max, and preferred sizes
|
|
|
|
// return us the size of the box
|
|
|
|
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
{
|
|
|
|
// ignore collapsed children
|
|
|
|
PRBool isCollapsed = PR_FALSE;
|
|
|
|
aBox->IsCollapsed(aState, isCollapsed);
|
|
|
|
|
|
|
|
if (!isCollapsed)
|
|
|
|
{
|
|
|
|
nsSize min(0,0);
|
|
|
|
nsSize pref(0,0);
|
|
|
|
nscoord flex = 0;
|
|
|
|
|
|
|
|
child->GetMinSize(aState, min);
|
|
|
|
child->GetFlex(aState, flex);
|
|
|
|
|
|
|
|
// if the child is not flexible then
|
|
|
|
// its min size is its pref size.
|
|
|
|
if (flex == 0) {
|
|
|
|
child->GetPrefSize(aState, pref);
|
|
|
|
if (isHorizontal)
|
|
|
|
min.width = pref.width;
|
|
|
|
else
|
|
|
|
min.height = pref.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
AddMargin(child, min);
|
|
|
|
AddLargestSize(aSize, min, isHorizontal);
|
|
|
|
}
|
|
|
|
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
}
|
|
|
|
|
|
|
|
// now add our border and padding and insets
|
|
|
|
AddBorderAndPadding(aBox, aSize);
|
|
|
|
AddInset(aBox,aSize);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
|
|
|
|
{
|
|
|
|
|
|
|
|
PRBool isHorizontal = IsHorizontal(aBox);
|
|
|
|
|
|
|
|
|
|
|
|
aSize.width = NS_INTRINSICSIZE;
|
|
|
|
aSize.height = NS_INTRINSICSIZE;
|
|
|
|
|
|
|
|
// run through all the children and get there min, max, and preferred sizes
|
|
|
|
// return us the size of the box
|
|
|
|
|
|
|
|
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
{
|
|
|
|
// ignore collapsed children
|
|
|
|
PRBool isCollapsed = PR_FALSE;
|
|
|
|
aBox->IsCollapsed(aState, isCollapsed);
|
|
|
|
|
|
|
|
if (!isCollapsed)
|
|
|
|
{
|
|
|
|
// if completely redefined don't even ask our child for its size.
|
|
|
|
nsSize max(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
|
|
|
|
child->GetMaxSize(aState, max);
|
|
|
|
|
|
|
|
AddMargin(child, max);
|
|
|
|
AddSmallestSize(aSize, max, isHorizontal);
|
|
|
|
}
|
|
|
|
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// now add our border and padding and insets
|
|
|
|
AddBorderAndPadding(aBox, aSize);
|
|
|
|
AddInset(aBox, aSize);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::GetAscent(nsIBox* aBox, nsBoxLayoutState& aState, nscoord& aAscent)
|
|
|
|
{
|
|
|
|
|
|
|
|
PRBool isHorizontal = IsHorizontal(aBox);
|
|
|
|
|
|
|
|
aAscent = 0;
|
|
|
|
|
|
|
|
// run through all the children and get there min, max, and preferred sizes
|
|
|
|
// return us the size of the box
|
|
|
|
|
|
|
|
nsIBox* child = nsnull;
|
|
|
|
aBox->GetChildBox(&child);
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
{
|
|
|
|
// ignore collapsed children
|
|
|
|
PRBool isCollapsed = PR_FALSE;
|
|
|
|
aBox->IsCollapsed(aState, isCollapsed);
|
|
|
|
|
|
|
|
if (!isCollapsed)
|
|
|
|
{
|
|
|
|
// if completely redefined don't even ask our child for its size.
|
|
|
|
nscoord ascent = 0;
|
|
|
|
child->GetAscent(aState, ascent);
|
|
|
|
|
|
|
|
nsMargin margin;
|
|
|
|
child->GetMargin(margin);
|
|
|
|
ascent += margin.top + margin.bottom;
|
|
|
|
|
|
|
|
if (isHorizontal)
|
|
|
|
{
|
|
|
|
if (ascent > aAscent)
|
|
|
|
aAscent = ascent;
|
|
|
|
} else {
|
|
|
|
if (aAscent == 0)
|
|
|
|
aAscent = ascent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
child->GetNextBox(&child);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::GetFlex(nsIBox* aBox, nsBoxLayoutState& aState, nscoord& aFlex)
|
|
|
|
{
|
|
|
|
return aBox->GetFlex(aState, aFlex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSprocketLayout::IsCollapsed(nsIBox* aBox, nsBoxLayoutState& aState, PRBool& IsCollapsed)
|
|
|
|
{
|
|
|
|
return aBox->IsCollapsed(aState, IsCollapsed);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::SetLargestSize(nsSize& aSize1, const nsSize& aSize2, PRBool aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aSize1.height < aSize2.height)
|
|
|
|
aSize1.height = aSize2.height;
|
|
|
|
} else {
|
|
|
|
if (aSize1.width < aSize2.width)
|
|
|
|
aSize1.width = aSize2.width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::SetSmallestSize(nsSize& aSize1, const nsSize& aSize2, PRBool aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aSize1.height > aSize2.height)
|
|
|
|
aSize1.height = aSize2.height;
|
|
|
|
} else {
|
|
|
|
if (aSize1.width > aSize2.width)
|
|
|
|
aSize1.width = aSize2.width;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::AddLargestSize(nsSize& aSize, const nsSize& aSizeToAdd, PRBool aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aIsHorizontal)
|
|
|
|
AddCoord(aSize.width, aSizeToAdd.width);
|
|
|
|
else
|
|
|
|
AddCoord(aSize.height, aSizeToAdd.height);
|
|
|
|
|
|
|
|
SetLargestSize(aSize, aSizeToAdd, aIsHorizontal);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSprocketLayout::AddCoord(nscoord& aCoord, nscoord aCoordToAdd)
|
|
|
|
{
|
|
|
|
if (aCoord != NS_INTRINSICSIZE)
|
|
|
|
{
|
|
|
|
if (aCoordToAdd == NS_INTRINSICSIZE)
|
|
|
|
aCoord = aCoordToAdd;
|
|
|
|
else
|
|
|
|
aCoord += aCoordToAdd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
|
|
nsSprocketLayout::AddSmallestSize(nsSize& aSize, const nsSize& aSizeToAdd, PRBool aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aIsHorizontal)
|
|
|
|
AddCoord(aSize.width, aSizeToAdd.width);
|
|
|
|
else
|
|
|
|
AddCoord(aSize.height, aSizeToAdd.height);
|
|
|
|
|
|
|
|
SetSmallestSize(aSize, aSizeToAdd, aIsHorizontal);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsSprocketLayout::GetDefaultFlex(PRInt32& aFlex)
|
|
|
|
{
|
|
|
|
aFlex = 0;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-04-05 08:20:24 +00:00
|
|
|
nsBoxSize::Add(const nsSize& minSize,
|
|
|
|
const nsSize& prefSize,
|
|
|
|
const nsSize& maxSize,
|
|
|
|
nscoord aAscent,
|
|
|
|
nscoord aFlex,
|
2000-03-31 07:02:06 +00:00
|
|
|
PRBool aIsHorizontal)
|
|
|
|
{
|
|
|
|
nscoord pref2;
|
|
|
|
nscoord min2;
|
|
|
|
nscoord max2;
|
|
|
|
|
|
|
|
if (aIsHorizontal) {
|
|
|
|
pref2 = prefSize.width;
|
|
|
|
min2 = minSize.width;
|
|
|
|
max2 = maxSize.width;
|
|
|
|
} else {
|
|
|
|
pref2 = prefSize.height;
|
|
|
|
min2 = minSize.height;
|
|
|
|
max2 = maxSize.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (min2 > min)
|
|
|
|
min = min2;
|
|
|
|
|
|
|
|
if (pref2 > pref)
|
|
|
|
pref = pref2;
|
|
|
|
|
|
|
|
if (max2 < max)
|
|
|
|
max = max2;
|
2000-04-05 08:20:24 +00:00
|
|
|
|
|
|
|
flex = aFlex;
|
2000-04-05 23:46:48 +00:00
|
|
|
|
|
|
|
if (!aIsHorizontal) {
|
|
|
|
if (aAscent > ascent)
|
|
|
|
ascent = aAscent;
|
|
|
|
}
|
2000-03-31 07:02:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsBoxSize::Add(const nsMargin& aMargin, PRBool aIsHorizontal)
|
|
|
|
{
|
|
|
|
if (aIsHorizontal) {
|
|
|
|
left += aMargin.left;
|
|
|
|
right += aMargin.right;
|
|
|
|
} else {
|
|
|
|
left += aMargin.top;
|
|
|
|
right += aMargin.bottom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsComputedBoxSize::nsComputedBoxSize()
|
2000-04-03 03:55:38 +00:00
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsComputedBoxSize::Clear()
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
resized = PR_FALSE;
|
|
|
|
valid = PR_FALSE;
|
|
|
|
size = 0;
|
|
|
|
next = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsBoxSize::nsBoxSize()
|
2000-04-03 03:55:38 +00:00
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsBoxSize::Clear()
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
pref = 0;
|
|
|
|
min = 0;
|
|
|
|
max = NS_INTRINSICSIZE;
|
|
|
|
collapsed = PR_FALSE;
|
|
|
|
ascent = 0;
|
|
|
|
left = 0;
|
|
|
|
right = 0;
|
|
|
|
flex = 0;
|
|
|
|
next = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void*
|
2000-04-05 23:46:48 +00:00
|
|
|
nsBoxSize::operator new(size_t sz, nsBoxLayoutState& aState)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
void* mem = 0;
|
|
|
|
aState.AllocateStackMemory(sz,&mem);
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2000-04-05 23:46:48 +00:00
|
|
|
nsBoxSize::operator delete(void* aPtr, size_t sz)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void*
|
2000-04-05 23:46:48 +00:00
|
|
|
nsComputedBoxSize::operator new(size_t sz, nsBoxLayoutState& aState)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
void* mem = 0;
|
|
|
|
aState.AllocateStackMemory(sz,&mem);
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-04-05 23:46:48 +00:00
|
|
|
nsComputedBoxSize::operator delete(void* aPtr, size_t sz)
|
2000-03-31 07:02:06 +00:00
|
|
|
{
|
|
|
|
}
|