Implement justification methods

This commit is contained in:
kipp%netscape.com 1998-10-27 16:52:10 +00:00
parent a6731c54fe
commit ad7b8e1864
6 changed files with 442 additions and 33 deletions

View File

@ -74,6 +74,10 @@ public:
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace);
NS_IMETHOD TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth);
virtual PRIntn GetSkipSides() const;
@ -283,6 +287,159 @@ nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout)
return rv;
}
// XXX This code is *almost* identical to the code in
// nsInlineReflow::JustifyFrames; factor it somehow
NS_IMETHODIMP
nsInlineFrame::AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace)
{
if (0 >= aExtraSpace) {
aUsedSpace = 0;
return NS_OK;
}
struct AdjustData {
nsIFrame* frame;
PRBool splittable;
nsRect bounds;
};
const int NUM_AD = 50;
AdjustData adjustMem[NUM_AD];
AdjustData* ad0 = adjustMem;
AdjustData* end = ad0 + NUM_AD;
AdjustData* ad = ad0;
PRInt32 numAD = NUM_AD;
// Gather up raw data for justification
nsIFrame* frame = mFirstChild;
PRInt32 fixed = 0;
PRInt32 total = 0;
nscoord fixedWidth = 0;
for (; nsnull != frame; ad++, total++) {
// Grow temporary storage if we have to
if (ad == end) {
AdjustData* newAD = new AdjustData[numAD + numAD];
if (nsnull == newAD) {
if (ad0 != adjustMem) {
delete [] ad0;
}
aUsedSpace = 0;
return NS_OK;
}
nsCRT::memcpy(newAD, ad0, sizeof(AdjustData) * numAD);
ad = newAD + (ad - ad0);
if (ad0 != adjustMem) {
delete [] ad0;
}
ad0 = newAD;
end = ad0 + numAD;
numAD = numAD + numAD;
}
// Record info about the frame
ad->frame = frame;
frame->GetRect(ad->bounds);
nsSplittableType isSplittable = NS_FRAME_NOT_SPLITTABLE;
frame->IsSplittable(isSplittable);
if ((0 == ad->bounds.width) ||
NS_FRAME_IS_NOT_SPLITTABLE(isSplittable)) {
ad->splittable = PR_FALSE;
fixed++;
fixedWidth += ad->bounds.width;
}
else {
ad->splittable = PR_TRUE;
}
// Advance to the next frame
frame->GetNextSibling(frame);
}
nscoord totalUsed = 0;
nscoord variableWidth = mRect.width - fixedWidth;
if (variableWidth > 0) {
// Each variable width frame gets a portion of the available extra
// space that is proportional to the space it takes in the
// line. The extra space is given to the frame by updating its
// position and size. The frame is responsible for adjusting the
// position of its contents on its own (during rendering).
PRInt32 i, splittable = total - fixed;
nscoord extraSpace = aExtraSpace;
nscoord remainingExtra = extraSpace;
nscoord dx = 0;
float lineWidth = float(mRect.width);
ad = ad0;
for (i = 0; i < total; i++, ad++) {
nsIFrame* frame = ad->frame;
nsIHTMLReflow* ihr;
if (NS_OK == frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr)) {
nsRect r;
if (ad->splittable && (ad->bounds.width > 0)) {
float pctOfLine = float(ad->bounds.width) / lineWidth;
nscoord extra = nscoord(pctOfLine * extraSpace);
if (--splittable == 0) {
extra = remainingExtra;
}
if (0 != extra) {
nscoord used;
ihr->AdjustFrameSize(extra, used);
if (used < extra) {
frame->ListTag(); printf(": extra=%d used=%d\n", extra, used);
}
totalUsed += used;
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
dx += used;
remainingExtra -= used;
}
else if (0 != dx) {
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
}
}
else if (0 != dx) {
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
}
}
}
}
mRect.width += totalUsed;
aUsedSpace = totalUsed;
if (ad0 != adjustMem) {
delete [] ad0;
}
return NS_OK;
}
NS_IMETHODIMP
nsInlineFrame::TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth)
{
nsIFrame* lastFrame = LastFrame(mFirstChild);
if (nsnull == lastFrame) {
aDeltaWidth = 0;
}
else {
nsIHTMLReflow* ihr;
if (NS_OK == lastFrame->QueryInterface(kIHTMLReflowIID, (void**)&ihr)) {
ihr->TrimTrailingWhiteSpace(aPresContext, aRC, aDeltaWidth);
if (0 != aDeltaWidth) {
mRect.width -= aDeltaWidth;
}
}
else {
aDeltaWidth = 0;
}
}
return NS_OK;
}
nsresult
nsInlineFrame::InsertNewFrame(nsIPresContext& aPresContext,
nsIFrame* aNewFrame,

View File

@ -50,29 +50,25 @@ public:
mColumn = 0;
mSkipLeadingWS = PR_TRUE;
mBRFrame = nsnull;
#ifdef NS_DEBUG
mPlacedFrames.Clear();
#endif
ForgetWordFrames();
}
// Add to the placed-frame count
#ifdef NS_DEBUG
void AddPlacedFrame(nsIFrame* aFrame) {
mTotalPlacedFrames++;
mPlacedFrames.AppendElement(aFrame);
}
#else
void AddPlacedFrame() {
mTotalPlacedFrames++;
}
#endif
// Get the placed-frame count
PRInt32 GetPlacedFrames() const {
return mTotalPlacedFrames;
}
const nsVoidArray& PlacedFrames() const {
return mPlacedFrames;
}
void SetBRFrame(nsIFrame* aFrame) {
mBRFrame = aFrame;
}
@ -180,9 +176,7 @@ protected:
nsIFrame* mBRFrame;
PRInt32 mTotalPlacedFrames;
#ifdef NS_DEBUG
nsVoidArray mPlacedFrames;
#endif
nsVoidArray mWordFrames;

View File

@ -74,6 +74,10 @@ public:
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace);
NS_IMETHOD TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth);
virtual PRIntn GetSkipSides() const;
@ -283,6 +287,159 @@ nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout)
return rv;
}
// XXX This code is *almost* identical to the code in
// nsInlineReflow::JustifyFrames; factor it somehow
NS_IMETHODIMP
nsInlineFrame::AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace)
{
if (0 >= aExtraSpace) {
aUsedSpace = 0;
return NS_OK;
}
struct AdjustData {
nsIFrame* frame;
PRBool splittable;
nsRect bounds;
};
const int NUM_AD = 50;
AdjustData adjustMem[NUM_AD];
AdjustData* ad0 = adjustMem;
AdjustData* end = ad0 + NUM_AD;
AdjustData* ad = ad0;
PRInt32 numAD = NUM_AD;
// Gather up raw data for justification
nsIFrame* frame = mFirstChild;
PRInt32 fixed = 0;
PRInt32 total = 0;
nscoord fixedWidth = 0;
for (; nsnull != frame; ad++, total++) {
// Grow temporary storage if we have to
if (ad == end) {
AdjustData* newAD = new AdjustData[numAD + numAD];
if (nsnull == newAD) {
if (ad0 != adjustMem) {
delete [] ad0;
}
aUsedSpace = 0;
return NS_OK;
}
nsCRT::memcpy(newAD, ad0, sizeof(AdjustData) * numAD);
ad = newAD + (ad - ad0);
if (ad0 != adjustMem) {
delete [] ad0;
}
ad0 = newAD;
end = ad0 + numAD;
numAD = numAD + numAD;
}
// Record info about the frame
ad->frame = frame;
frame->GetRect(ad->bounds);
nsSplittableType isSplittable = NS_FRAME_NOT_SPLITTABLE;
frame->IsSplittable(isSplittable);
if ((0 == ad->bounds.width) ||
NS_FRAME_IS_NOT_SPLITTABLE(isSplittable)) {
ad->splittable = PR_FALSE;
fixed++;
fixedWidth += ad->bounds.width;
}
else {
ad->splittable = PR_TRUE;
}
// Advance to the next frame
frame->GetNextSibling(frame);
}
nscoord totalUsed = 0;
nscoord variableWidth = mRect.width - fixedWidth;
if (variableWidth > 0) {
// Each variable width frame gets a portion of the available extra
// space that is proportional to the space it takes in the
// line. The extra space is given to the frame by updating its
// position and size. The frame is responsible for adjusting the
// position of its contents on its own (during rendering).
PRInt32 i, splittable = total - fixed;
nscoord extraSpace = aExtraSpace;
nscoord remainingExtra = extraSpace;
nscoord dx = 0;
float lineWidth = float(mRect.width);
ad = ad0;
for (i = 0; i < total; i++, ad++) {
nsIFrame* frame = ad->frame;
nsIHTMLReflow* ihr;
if (NS_OK == frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr)) {
nsRect r;
if (ad->splittable && (ad->bounds.width > 0)) {
float pctOfLine = float(ad->bounds.width) / lineWidth;
nscoord extra = nscoord(pctOfLine * extraSpace);
if (--splittable == 0) {
extra = remainingExtra;
}
if (0 != extra) {
nscoord used;
ihr->AdjustFrameSize(extra, used);
if (used < extra) {
frame->ListTag(); printf(": extra=%d used=%d\n", extra, used);
}
totalUsed += used;
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
dx += used;
remainingExtra -= used;
}
else if (0 != dx) {
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
}
}
else if (0 != dx) {
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
}
}
}
}
mRect.width += totalUsed;
aUsedSpace = totalUsed;
if (ad0 != adjustMem) {
delete [] ad0;
}
return NS_OK;
}
NS_IMETHODIMP
nsInlineFrame::TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth)
{
nsIFrame* lastFrame = LastFrame(mFirstChild);
if (nsnull == lastFrame) {
aDeltaWidth = 0;
}
else {
nsIHTMLReflow* ihr;
if (NS_OK == lastFrame->QueryInterface(kIHTMLReflowIID, (void**)&ihr)) {
ihr->TrimTrailingWhiteSpace(aPresContext, aRC, aDeltaWidth);
if (0 != aDeltaWidth) {
mRect.width -= aDeltaWidth;
}
}
else {
aDeltaWidth = 0;
}
}
return NS_OK;
}
nsresult
nsInlineFrame::InsertNewFrame(nsIPresContext& aPresContext,
nsIFrame* aNewFrame,

View File

@ -880,8 +880,24 @@ nsInlineReflow::VerticalAlignFrames(nsRect& aLineBox,
}
void
nsInlineReflow::HorizontalAlignFrames(const nsRect& aLineBox)
nsInlineReflow::HorizontalAlignFrames(nsRect& aLineBox, PRBool aIsLastLine)
{
// Before we start, trim any trailing whitespace off of the last
// frame in the line.
nscoord deltaWidth;
PerFrameData* pfd = mFrameDataBase + (mFrameNum - 1);
if (pfd->mBounds.width > 0) {
nsIFrame* frame = pfd->mFrame;
nsIHTMLReflow* ihr;
if (NS_OK == frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr)) {
ihr->TrimTrailingWhiteSpace(mPresContext,
*mOuterReflowState.rendContext,
deltaWidth);
aLineBox.width -= deltaWidth;
pfd->mBounds.width -= deltaWidth;
}
}
const nsStyleText* styleText = mOuterReflowState.mStyleText;
nscoord maxWidth = mRightEdge - mLeftEdge;
if (aLineBox.width < maxWidth) {
@ -900,24 +916,38 @@ nsInlineReflow::HorizontalAlignFrames(const nsRect& aLineBox)
break;
case NS_STYLE_TEXT_ALIGN_LEFT:
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
// Default layout has everything aligned left
return;
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
// If this is not the last line then go ahead and justify the
// frames in the line. If it is the last line then if the
// direction is right-to-left then we right-align the frames.
if (!aIsLastLine) {
JustifyFrames(maxWidth, aLineBox);
return;
}
else if (NS_STYLE_DIRECTION_RTL == mOuterReflowState.mDirection) {
// right align the frames
dx = maxWidth - aLineBox.width;
}
break;
case NS_STYLE_TEXT_ALIGN_CENTER:
dx = (maxWidth - aLineBox.width) / 2;
break;
}
// Position children
PerFrameData* pfd = mFrameDataBase;
PerFrameData* end = pfd + mFrameNum;
nsPoint origin;
for (; pfd < end; pfd++) {
nsIFrame* kid = pfd->mFrame;;
kid->GetOrigin(origin);
kid->MoveTo(origin.x + dx, origin.y);
kid->GetNextSibling(kid);
if (0 != dx) {
// Position children
pfd = mFrameDataBase;
PerFrameData* end = pfd + mFrameNum;
nsPoint origin;
for (; pfd < end; pfd++) {
nsIFrame* kid = pfd->mFrame;;
kid->GetOrigin(origin);
kid->MoveTo(origin.x + dx, origin.y);
kid->GetNextSibling(kid);
}
}
}
}
@ -1032,3 +1062,75 @@ nsInlineReflow::CalcLineHeightFor(nsIPresContext& aPresContext,
return lineHeight;
}
void
nsInlineReflow::JustifyFrames(nscoord aMaxWidth, nsRect& aLineBox)
{
// Gather up raw data for justification
PRInt32 i, n = mFrameNum;
PerFrameData* pfd = mFrameDataBase;
PRInt32 fixed = 0;
nscoord fixedWidth = 0;
for (i = 0; i < n; i++, pfd++) {
nsIFrame* frame = pfd->mFrame;
nsSplittableType isSplittable = NS_FRAME_NOT_SPLITTABLE;
frame->IsSplittable(isSplittable);
if ((0 == pfd->mBounds.width) ||
NS_FRAME_IS_NOT_SPLITTABLE(isSplittable)) {
pfd->mSplittable = PR_FALSE;
fixed++;
fixedWidth += pfd->mBounds.width;
}
else {
pfd->mSplittable = PR_TRUE;
}
}
nscoord variableWidth = aLineBox.width - fixedWidth;
if (variableWidth > 0) {
// Each variable width frame gets a portion of the available extra
// space that is proportional to the space it takes in the
// line. The extra space is given to the frame by updating its
// position and size. The frame is responsible for adjusting the
// position of its contents on its own (during rendering).
PRInt32 splittable = n - fixed;
nscoord extraSpace = aMaxWidth - aLineBox.width;
nscoord remainingExtra = extraSpace;
nscoord dx = 0;
float lineWidth = float(aLineBox.width);
pfd = mFrameDataBase;
for (i = 0; i < n; i++, pfd++) {
nsRect r;
nsIFrame* frame = pfd->mFrame;
nsIHTMLReflow* ihr;
if (NS_OK == frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr)) {
if (pfd->mSplittable && (pfd->mBounds.width > 0)) {
float pctOfLine = float(pfd->mBounds.width) / lineWidth;
nscoord extra = nscoord(pctOfLine * extraSpace);
if (--splittable == 0) {
extra = remainingExtra;
}
if (0 != extra) {
nscoord used;
ihr->AdjustFrameSize(extra, used);
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
dx += extra;
}
else if (0 != dx) {
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
}
remainingExtra -= extra;
}
else if (0 != dx) {
frame->GetRect(r);
r.x += dx;
frame->SetRect(r);
}
}
}
}
}

View File

@ -60,7 +60,8 @@ public:
nscoord& aMaxAscent,
nscoord& aMaxDescent);
void HorizontalAlignFrames(const nsRect& aLineBox);
void HorizontalAlignFrames(nsRect& aLineBox,
PRBool aIsLastLine = PR_FALSE);
void RelativePositionFrames();
@ -138,6 +139,8 @@ protected:
void UpdateFrames();
void JustifyFrames(nscoord aMaxWidth, nsRect& aLineBox);
// The outer frame that contains the frames that we reflow.
nsHTMLContainerFrame* mOuterFrame;
nsISpaceManager* mSpaceManager;
@ -165,6 +168,8 @@ protected:
nsRect mBounds;
nsSize mMaxElementSize;
PRBool mSplittable;
};
PerFrameData* mFrameData;

View File

@ -50,29 +50,25 @@ public:
mColumn = 0;
mSkipLeadingWS = PR_TRUE;
mBRFrame = nsnull;
#ifdef NS_DEBUG
mPlacedFrames.Clear();
#endif
ForgetWordFrames();
}
// Add to the placed-frame count
#ifdef NS_DEBUG
void AddPlacedFrame(nsIFrame* aFrame) {
mTotalPlacedFrames++;
mPlacedFrames.AppendElement(aFrame);
}
#else
void AddPlacedFrame() {
mTotalPlacedFrames++;
}
#endif
// Get the placed-frame count
PRInt32 GetPlacedFrames() const {
return mTotalPlacedFrames;
}
const nsVoidArray& PlacedFrames() const {
return mPlacedFrames;
}
void SetBRFrame(nsIFrame* aFrame) {
mBRFrame = aFrame;
}
@ -180,9 +176,7 @@ protected:
nsIFrame* mBRFrame;
PRInt32 mTotalPlacedFrames;
#ifdef NS_DEBUG
nsVoidArray mPlacedFrames;
#endif
nsVoidArray mWordFrames;