mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
361 lines
11 KiB
C++
361 lines
11 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.0 (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.
|
|
*/
|
|
#include "nsBlockBandData.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsIFrameReflow.h"
|
|
#include "nsIStyleContext.h"
|
|
#include "nsVoidArray.h"
|
|
|
|
nsBlockBandData::nsBlockBandData()
|
|
: mSpaceManager(nsnull),
|
|
mSpaceManagerX(0),
|
|
mSpaceManagerY(0),
|
|
mSpace(0, 0)
|
|
{
|
|
mSize = NS_BLOCK_BAND_DATA_TRAPS;
|
|
mTrapezoids = mData;
|
|
}
|
|
|
|
nsBlockBandData::~nsBlockBandData()
|
|
{
|
|
NS_IF_RELEASE(mSpaceManager);
|
|
if (mTrapezoids != mData) {
|
|
delete [] mTrapezoids;
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsBlockBandData::Init(nsISpaceManager* aSpaceManager,
|
|
const nsSize& aSpace)
|
|
{
|
|
NS_PRECONDITION(nsnull != aSpaceManager, "null pointer");
|
|
if (nsnull == aSpaceManager) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
NS_IF_RELEASE(mSpaceManager);
|
|
mSpaceManager = aSpaceManager;
|
|
NS_ADDREF(aSpaceManager);
|
|
aSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY);
|
|
|
|
mSpace = aSpace;
|
|
mFloaters = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
// Get the available reflow space for the current y coordinate. The
|
|
// available space is relative to our coordinate system (0,0) is our
|
|
// upper left corner.
|
|
nsresult
|
|
nsBlockBandData::GetAvailableSpace(nscoord aY, nsRect& aResult)
|
|
{
|
|
// Get the raw band data for the given Y coordinate
|
|
nsresult rv = mSpaceManager->GetBandData(aY, mSpace, *this);
|
|
while (NS_FAILED(rv)) {
|
|
// We need more space for our bands
|
|
if (mTrapezoids != mData) {
|
|
delete [] mTrapezoids;
|
|
}
|
|
PRInt32 newSize = mSize * 2;
|
|
mTrapezoids = new nsBandTrapezoid[newSize];
|
|
if (!mTrapezoids) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
mSize = newSize;
|
|
rv = mSpaceManager->GetBandData(aY, mSpace, *this);
|
|
}
|
|
|
|
// Compute the bounding rect of the available space, i.e. space
|
|
// between any left and right floaters.
|
|
ComputeAvailSpaceRect();
|
|
aResult = mAvailSpace;
|
|
return NS_OK;
|
|
}
|
|
|
|
/**
|
|
* Computes the bounding rect of the available space, i.e. space
|
|
* between any left and right floaters. Uses the current trapezoid
|
|
* data, see nsISpaceManager::GetBandData(). Also updates member
|
|
* data "availSpace".
|
|
*/
|
|
void
|
|
nsBlockBandData::ComputeAvailSpaceRect()
|
|
{
|
|
if (0 == mCount) {
|
|
mAvailSpace.x = 0;
|
|
mAvailSpace.y = 0;
|
|
mAvailSpace.width = 0;
|
|
mAvailSpace.height = 0;
|
|
return;
|
|
}
|
|
|
|
nsBandTrapezoid* trapezoid = mTrapezoids;
|
|
nsBandTrapezoid* rightTrapezoid = nsnull;
|
|
|
|
PRInt32 floaters = 0;
|
|
if (mCount > 1) {
|
|
// If there's more than one trapezoid that means there are floaters
|
|
PRInt32 i;
|
|
|
|
// Examine each trapezoid in the band, counting up the number of
|
|
// left and right floaters. Use the right-most floater to
|
|
// determine where the right edge of the available space is.
|
|
for (i = 0; i < mCount; i++) {
|
|
trapezoid = &mTrapezoids[i];
|
|
if (trapezoid->mState != nsBandTrapezoid::Available) {
|
|
const nsStyleDisplay* display;
|
|
if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
|
|
PRInt32 j, numFrames = trapezoid->mFrames->Count();
|
|
NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
|
|
for (j = 0; j < numFrames; j++) {
|
|
nsIFrame* f = (nsIFrame*) trapezoid->mFrames->ElementAt(j);
|
|
f->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&)display);
|
|
if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
|
|
floaters++;
|
|
}
|
|
else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) {
|
|
floaters++;
|
|
if ((nsnull == rightTrapezoid) && (i > 0)) {
|
|
rightTrapezoid = &mTrapezoids[i - 1];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
trapezoid->mFrame->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&)display);
|
|
if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
|
|
floaters++;
|
|
}
|
|
else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) {
|
|
floaters++;
|
|
if ((nsnull == rightTrapezoid) && (i > 0)) {
|
|
rightTrapezoid = &mTrapezoids[i - 1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (mTrapezoids[0].mState != nsBandTrapezoid::Available) {
|
|
// We have a floater using up all the available space
|
|
floaters = 1;
|
|
}
|
|
mFloaters = floaters;
|
|
|
|
if (nsnull != rightTrapezoid) {
|
|
trapezoid = rightTrapezoid;
|
|
}
|
|
trapezoid->GetRect(mAvailSpace);
|
|
|
|
// When there is no available space, we still need a proper X
|
|
// coordinate to place objects that end up here anyway.
|
|
if (nsBandTrapezoid::Available != trapezoid->mState) {
|
|
const nsStyleDisplay* display;
|
|
if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
|
|
// It's not clear what coordinate to use when there is no
|
|
// available space and the space is multiply occupied...So: If
|
|
// any of the floaters that are a part of the trapezoid are left
|
|
// floaters then we move over to the right edge of the
|
|
// unavaliable space.
|
|
PRInt32 j, numFrames = trapezoid->mFrames->Count();
|
|
NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
|
|
for (j = 0; j < numFrames; j++) {
|
|
nsIFrame* f = (nsIFrame*) trapezoid->mFrames->ElementAt(j);
|
|
f->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&)display);
|
|
if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
|
|
mAvailSpace.x = mAvailSpace.XMost();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
trapezoid->mFrame->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&)display);
|
|
if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
|
|
mAvailSpace.x = mAvailSpace.XMost();
|
|
}
|
|
}
|
|
mAvailSpace.width = 0;
|
|
}
|
|
|
|
// Fixup width
|
|
if (NS_UNCONSTRAINEDSIZE == mSpace.width) {
|
|
mAvailSpace.width = NS_UNCONSTRAINEDSIZE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* See if the given frame should be cleared
|
|
*/
|
|
PRBool
|
|
nsBlockBandData::ShouldClearFrame(nsIFrame* aFrame, PRUint8 aBreakType)
|
|
{
|
|
PRBool result = PR_FALSE;
|
|
const nsStyleDisplay* display;
|
|
nsresult rv = aFrame->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&)display);
|
|
if (NS_SUCCEEDED(rv) && (nsnull != display)) {
|
|
if (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType) {
|
|
result = PR_TRUE;
|
|
}
|
|
else if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
|
|
if (NS_STYLE_CLEAR_LEFT == aBreakType) {
|
|
result = PR_TRUE;
|
|
}
|
|
}
|
|
else if (NS_STYLE_FLOAT_RIGHT == display->mFloats) {
|
|
if (NS_STYLE_CLEAR_RIGHT == aBreakType) {
|
|
result = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// XXX doesn't work because of margins around floaters and because of
|
|
// % margins we can't really re-compute them here (nor would we want
|
|
// too...)
|
|
#if 0
|
|
/**
|
|
* Get the frames YMost, in the space managers "root" coordinate
|
|
* system. Because the floating frame may have been placed in a
|
|
* parent/child frame, we map the coordinates into the space-managers
|
|
* untranslated coordinate system.
|
|
*/
|
|
nscoord
|
|
nsBlockBandData::GetFrameYMost(nsIFrame* aFrame)
|
|
{
|
|
nsIFrame* spaceFrame;
|
|
mSpaceManager->GetFrame(spaceFrame);
|
|
|
|
nsRect r;
|
|
nsPoint p;
|
|
aFrame->GetRect(r);
|
|
nscoord y = r.y;
|
|
nsIFrame* parent;
|
|
aFrame->GetParent(&parent);
|
|
PRBool done = PR_FALSE;
|
|
while (!done && (parent != spaceFrame)) {
|
|
// If parent has a prev-in-flow, check there for equality first
|
|
// before looking upward.
|
|
nsIFrame* parentPrevInFlow;
|
|
parent->GetPrevInFlow(&parentPrevInFlow);
|
|
while (nsnull != parentPrevInFlow) {
|
|
if (parentPrevInFlow == spaceFrame) {
|
|
done = PR_TRUE;
|
|
break;
|
|
}
|
|
parentPrevInFlow->GetPrevInFlow(&parentPrevInFlow);
|
|
}
|
|
|
|
if (!done) {
|
|
parent->GetOrigin(p);
|
|
y += p.y;
|
|
parent->GetParent(&parent);
|
|
}
|
|
}
|
|
|
|
return y + r.height;
|
|
}
|
|
#endif
|
|
|
|
// XXX optimization? use mFloaters to avoid doing anything
|
|
nscoord
|
|
nsBlockBandData::ClearFloaters(nscoord aY, PRUint8 aBreakType)
|
|
{
|
|
for (;;) {
|
|
// Update band information based on target Y before clearing.
|
|
mSpaceManager->GetBandData(aY, mSpace, *this);
|
|
ComputeAvailSpaceRect();
|
|
|
|
// Compute aYS as aY in space-manager "root" coordinates.
|
|
nscoord aYS = aY + mSpaceManagerY;
|
|
|
|
// Find the largest frame YMost for the appropriate floaters in
|
|
// this band.
|
|
nscoord yMost = aYS;
|
|
PRInt32 i;
|
|
for (i = 0; i < mCount; i++) {
|
|
nsBandTrapezoid* trapezoid = &mTrapezoids[i];
|
|
if (nsBandTrapezoid::Available != trapezoid->mState) {
|
|
if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
|
|
PRInt32 fn, numFrames = trapezoid->mFrames->Count();
|
|
NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
|
|
for (fn = 0; fn < numFrames; fn++) {
|
|
nsIFrame* frame = (nsIFrame*) trapezoid->mFrames->ElementAt(fn);
|
|
if (ShouldClearFrame(frame, aBreakType)) {
|
|
nscoord ym = trapezoid->mBottomY + mSpaceManagerY;
|
|
if (ym > yMost) yMost = ym;
|
|
}
|
|
}
|
|
}
|
|
else if (ShouldClearFrame(trapezoid->mFrame, aBreakType)) {
|
|
nscoord ym = trapezoid->mBottomY + mSpaceManagerY;
|
|
if (ym > yMost) yMost = ym;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If yMost is unchanged (aYS) then there were no appropriate
|
|
// floaters in the band. Time to stop clearing.
|
|
if (yMost == aYS) {
|
|
break;
|
|
}
|
|
aY = aY + (yMost - aYS);
|
|
}
|
|
return aY;
|
|
}
|
|
|
|
void
|
|
nsBlockBandData::GetMaxElementSize(nscoord* aWidthResult,
|
|
nscoord* aHeightResult) const
|
|
{
|
|
nsRect r;
|
|
nscoord maxWidth = 0;
|
|
nscoord maxHeight = 0;
|
|
for (PRInt32 i = 0; i < mCount; i++) {
|
|
const nsBandTrapezoid* trap = &mTrapezoids[i];
|
|
if (trap->mState != nsBandTrapezoid::Available) {
|
|
// Get the width of the impacted area and update the maxWidth
|
|
trap->GetRect(r);
|
|
if (r.width > maxWidth) maxWidth = r.width;
|
|
|
|
// Get the total height of the frame to compute the maxHeight,
|
|
// not just the height that is part of this band.
|
|
// XXX vertical margins!
|
|
if (nsBandTrapezoid::OccupiedMultiple == trap->mState) {
|
|
PRInt32 j, numFrames = trap->mFrames->Count();
|
|
NS_ASSERTION(numFrames > 0, "bad trapezoid frame list");
|
|
for (j = 0; j < numFrames; j++) {
|
|
nsIFrame* f = (nsIFrame*) trap->mFrames->ElementAt(j);
|
|
f->GetRect(r);
|
|
if (r.height > maxHeight) maxHeight = r.height;
|
|
}
|
|
} else {
|
|
trap->mFrame->GetRect(r);
|
|
if (r.height > maxHeight) maxHeight = r.height;
|
|
}
|
|
}
|
|
}
|
|
*aWidthResult = maxWidth;
|
|
*aHeightResult = maxHeight;
|
|
}
|