git-svn-id: svn://10.0.0.236/trunk@15521 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kipp%netscape.com
1998-12-01 16:13:49 +00:00
parent a0c58ff4a6
commit 0bbef0f75e
12 changed files with 3002 additions and 0 deletions

View File

@@ -0,0 +1,407 @@
/* -*- 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 "nsBlockReflowContext.h"
#include "nsFrameReflowState.h"
#include "nsLineLayout.h"
#include "nsHTMLIIDs.h"
#include "nsISpaceManager.h"
#include "nsIFontMetrics.h"
#include "nsIPresContext.h"
#include "nsIStyleContext.h"
#include "nsHTMLContainerFrame.h"
nsBlockReflowContext::nsBlockReflowContext(nsIPresContext& aPresContext,
nsLineLayout& aLineLayout,
nsFrameReflowState& aParentRS)
: mPresContext(aPresContext),
mLineLayout(aLineLayout),
mOuterReflowState(aParentRS),
mMetrics(aParentRS.mComputeMaxElementSize ? &mMaxElementSize : nsnull)
{
mRunInFrame = nsnull;
mCompactMarginWidth = 0;
mSpacing = nsnull;
}
void
nsBlockReflowContext::ComputeMarginsFor(nsIPresContext& aPresContext,
nsIFrame* aFrame,
const nsStyleSpacing* aSpacing,
const nsFrameReflowState& aParentRS,
nsMargin& aResult)
{
// XXX pass in mSpacing to ComputeMarginFor
nsHTMLReflowState::ComputeMarginFor(aFrame, &aParentRS, aResult);
// Compute auto top/bottom margin values
nsStyleUnit topUnit = aSpacing->mMargin.GetTopUnit();
nsStyleUnit bottomUnit = aSpacing->mMargin.GetBottomUnit();
nscoord fontHeight = 0;
if ((eStyleUnit_Auto == topUnit) || (eStyleUnit_Auto == bottomUnit)) {
// XXX Use the font for the frame, not the default font???
const nsFont& defaultFont = aPresContext.GetDefaultFont();
nsIFontMetrics* fm = aPresContext.GetMetricsFor(defaultFont);
fm->GetHeight(fontHeight);
NS_RELEASE(fm);
}
// For auto margins use the font height computed above
if (eStyleUnit_Auto == topUnit) {
aResult.top = fontHeight;
}
if (eStyleUnit_Auto == bottomUnit) {
aResult.bottom = fontHeight;
}
}
nsresult
nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame, const nsRect& aSpace)
{
nsReflowStatus reflowStatus;
mFrame = aFrame;
mSpace = aSpace;
// Compute the margins (including auto margins)
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)mSpacing);
ComputeMarginsFor(mPresContext, aFrame, mSpacing, mOuterReflowState,
mMargin);
// Compute x/y coordinate where reflow will begin. Use the rules
// from 10.3.3 to determine what to apply. At this point in the
// reflow auto left/right margins will have a zero value.
nscoord x = aSpace.x + mMargin.left;
nscoord y = aSpace.y;
mX = x;
mY = y;
nsSize availSize(aSpace.width, aSpace.height);
if (NS_UNCONSTRAINEDSIZE != aSpace.width) {
availSize.width -= mMargin.left;
}
if (NS_UNCONSTRAINEDSIZE != aSpace.height) {
availSize.height -= mMargin.top + mMargin.bottom;
}
// Get reflow reason set correctly. It's possible that a child was
// created and then it was decided that it could not be reflowed
// (for example, a block frame that isn't at the start of a
// line). In this case the reason will be wrong so we need to check
// the frame state.
nsReflowReason reason = eReflowReason_Resize;
nsFrameState state;
aFrame->GetFrameState(state);
if (NS_FRAME_FIRST_REFLOW & state) {
reason = eReflowReason_Initial;
}
else if (mOuterReflowState.mNextRCFrame == aFrame) {
reason = eReflowReason_Incremental;
// Make sure we only incrementally reflow once
// XXX caller should do this, yes?
mOuterReflowState.mNextRCFrame = nsnull;
}
// Setup reflow state for reflowing the frame
nsHTMLReflowState reflowState(mPresContext, aFrame, mOuterReflowState,
availSize);
reflowState.lineLayout = nsnull;
reflowState.mRunInFrame = mRunInFrame;
reflowState.mCompactMarginWidth = mCompactMarginWidth;
reflowState.reason = reason;
mLineLayout.SetUnderstandsWhiteSpace(PR_FALSE);
// Let frame know that we are reflowing it
nsIHTMLReflow* htmlReflow;
nsresult rv = aFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
if (!NS_SUCCEEDED(rv)) {
return rv;
}
htmlReflow->WillReflow(mPresContext);
// Adjust spacemanager coordinate system for the frame. The
// spacemanager coordinates are <b>inside</b> the callers
// border+padding, but the x/y coordinates are not (recall that
// frame coordinates are relative to the parents origin and that the
// parents border/padding is <b>inside</b> the parent
// frame. Therefore we have to subtract out the parents
// border+padding before translating.
nscoord tx = x - mOuterReflowState.mBorderPadding.left;
nscoord ty = y - mOuterReflowState.mBorderPadding.top;
aFrame->MoveTo(x, y);
mOuterReflowState.spaceManager->Translate(tx, ty);
htmlReflow->Reflow(mPresContext, mMetrics, reflowState, reflowStatus);
mOuterReflowState.spaceManager->Translate(-tx, -ty);
aFrame->GetFrameState(state);
if (0 == (NS_FRAME_OUTSIDE_CHILDREN & state)) {
// Provide combined area for child that doesn't have any
mMetrics.mCombinedArea.x = 0;
mMetrics.mCombinedArea.y = 0;
mMetrics.mCombinedArea.width = mMetrics.width;
mMetrics.mCombinedArea.height = mMetrics.height;
}
// Now that frame has been reflowed at least one time make sure that
// the NS_FRAME_FIRST_REFLOW bit is cleared so that never give it an
// initial reflow reason again.
if (eReflowReason_Initial == reason) {
aFrame->SetFrameState(state & ~NS_FRAME_FIRST_REFLOW);
}
if (!NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
// If frame is complete and has a next-in-flow, we need to delete
// them now. Do not do this when a break-before is signaled because
// the frame is going to get reflowed again (and may end up wanting
// a next-in-flow where it ends up).
if (NS_FRAME_IS_COMPLETE(reflowStatus)) {
nsIFrame* kidNextInFlow;
aFrame->GetNextInFlow(kidNextInFlow);
if (nsnull != kidNextInFlow) {
// Remove all of the childs next-in-flows. Make sure that we ask
// the right parent to do the removal (it's possible that the
// parent is not this because we are executing pullup code)
/* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
nsHTMLContainerFrame* parent;
aFrame->GetGeometricParent((nsIFrame*&) parent);
parent->DeleteChildsNextInFlow(mPresContext, aFrame);
}
}
}
return reflowStatus;
}
/**
* The CSS2 spec, section 8.3.1 defines margin collapsing to apply to
* vertical margins of block boxes. And the spec also indicates that
* this should be done for two or more adjacent vertical margins. It
* also indicates that the margins collapse between boxes that are
* next to each other or nested.
*/
void
nsBlockReflowContext::CollapseMargins(const nsMargin& aMargin,
nscoord aCarriedOutTopMargin,
nscoord aCarriedOutBottomMargin,
nscoord aFrameHeight,
nscoord aPrevBottomMargin,
nscoord& aTopMarginResult,
nscoord& aBottomMarginResult)
{
// Compute the collapsed top margin value. The top margin value is a
// 3 way margin collapse. First we collapse the carried out top
// margin with the block frames top margin (this is a CSS2 "nested"
// collapse). Then we collapse that value with the previous bottom
// margin (because the collapsed margin is adjacent to the previous
// bottom margin).
nscoord carriedTopMargin = aCarriedOutTopMargin;
nscoord topMargin = aMargin.top;
topMargin = MaxMargin(topMargin, carriedTopMargin);
topMargin = MaxMargin(topMargin, aPrevBottomMargin);
// Compute the collapsed bottom margin value. The bottom margin
// value is a 2 way margin collapse. Collapse the carried out bottom
// margin with the block frames bottom margin (this is a CSS2
// "nested" collapse).
nscoord carriedBottomMargin = aCarriedOutBottomMargin;
nscoord bottomMargin = aMargin.bottom;
bottomMargin = MaxMargin(bottomMargin, carriedBottomMargin);
// If the block line is empty then we collapse the top and bottom
// margin values (because the margins are adjacent).
if (0 == aFrameHeight) {
nscoord collapsedMargin = MaxMargin(topMargin, bottomMargin);
topMargin = 0;
bottomMargin = collapsedMargin;
}
aTopMarginResult = topMargin;
aBottomMarginResult = bottomMargin;
}
/**
* Attempt to place the block frame within the available space. If
* it fits, apply horizontal positioning (CSS 10.3.3), collapse
* margins (CSS2 8.3.1). Also apply relative positioning.
*/
PRBool
nsBlockReflowContext::PlaceBlock(PRBool aForceFit, PRBool aApplyTopMargin,
nscoord aPrevBottomMargin,
nsRect& aInFlowBounds,
nsRect& aCombinedRect)
{
// Compute collapsed margin value
CollapseMargins(mMargin, mMetrics.mCarriedOutTopMargin,
mMetrics.mCarriedOutBottomMargin,
mMetrics.height, aPrevBottomMargin,
mTopMargin, mBottomMargin);
// See if the block will fit in the available space
PRBool fits;
if (0 == mMetrics.height) {
// Empty blocks do not have anything special done to them and they
// always fit.
nsRect r(mX, mY, 0, 0);
mFrame->SetRect(r);
aInFlowBounds = r;
aCombinedRect = r;
fits = PR_TRUE;
}
else {
nscoord x = mX;
nscoord y = mY;
// Apply top margin unless it's going to be carried out.
if (aApplyTopMargin) {
y += mTopMargin;
}
// Position block horizontally according to CSS2 10.3.3
if (NS_UNCONSTRAINEDSIZE != mSpace.width) {
// XXX left/right block margins should be applied right here.
// Because of the issue with floaters and block-left/right
// margins this code is not yet complete. This code may need to
// move to before reflowing the frame instead of after (because
// of floater positioning).
nscoord remainder = mSpace.XMost() - (x + mMetrics.width);
if (remainder >= 0) {
// The block frame didn't use all of the available space. Apply
// auto margins.
const nsStyleSpacing* spacing = mSpacing;
if (nsnull != mSpacing) {
nsStyleUnit leftUnit = mSpacing->mMargin.GetLeftUnit();
nsStyleUnit rightUnit = mSpacing->mMargin.GetRightUnit();
if (eStyleUnit_Auto == leftUnit) {
if (eStyleUnit_Auto == rightUnit) {
// When both margins are auto, we center the block
x += remainder / 2;
}
else {
x += remainder;
}
}
else if (eStyleUnit_Auto != rightUnit) {
// When neither margin is auto then text-align applies
const nsStyleText* styleText = mOuterReflowState.mStyleText;
switch (styleText->mTextAlign) {
case NS_STYLE_TEXT_ALIGN_DEFAULT:
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
if (NS_STYLE_DIRECTION_RTL == mOuterReflowState.mDirection) {
// When given a default alignment, and a right-to-left
// direction, right align the frame.
x += remainder;
}
break;
case NS_STYLE_TEXT_ALIGN_RIGHT:
x += remainder;
break;
case NS_STYLE_TEXT_ALIGN_CENTER:
x += remainder / 2;
break;
}
}
}
}
else {
// XXX Handle over-constrained case by forcing the appropriate
// margin to be auto
}
}
// See if the frame fit. If its the first frame then it always
// fits.
if (aForceFit || (y + mMetrics.height <= mSpace.YMost())) {
fits = PR_TRUE;
// Update the in-flow bounding box's bounds
aInFlowBounds.SetRect(x, y, mMetrics.width, mMetrics.height);
// Apply CSS relative positioning to update x,y coordinates
const nsStylePosition* stylePos;
mFrame->GetStyleData(eStyleStruct_Position,
(const nsStyleStruct*&)stylePos);
if (NS_STYLE_POSITION_RELATIVE == stylePos->mPosition) {
ComputeRelativePosition(mFrame, stylePos, x, y);
}
// Compute combined-rect in callers coordinate system. The value
// returned in the reflow metrics is relative to the child
// frame.
aCombinedRect.x = mMetrics.mCombinedArea.x + x;
aCombinedRect.y = mMetrics.mCombinedArea.y + y;
aCombinedRect.width = mMetrics.mCombinedArea.width;
aCombinedRect.height = mMetrics.mCombinedArea.height;
// Now place the frame
mFrame->SetRect(nsRect(x, y, mMetrics.width, mMetrics.height));
// If the block frame ended up moving then we need to slide
// anything inside of it that impacts the space manager
// (otherwise the impacted space in the space manager will be
// out of sync with where the frames really are).
nscoord dx = x - mX;
nscoord dy = y - mY;
if ((0 != dx) || (0 != dy)) {
nsIHTMLReflow* htmlReflow;
nsresult rv;
rv = mFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
if (NS_SUCCEEDED(rv)) {
// If the child has any floaters that impact the space manager,
// slide them now
htmlReflow->MoveInSpaceManager(mPresContext,
mOuterReflowState.spaceManager,
dx, dy);
}
}
}
else {
fits = PR_FALSE;
}
}
return fits;
}
void
nsBlockReflowContext::ComputeRelativePosition(nsIFrame* aFrame,
const nsStylePosition* aStylePos,
nscoord& aX, nscoord& aY)
{
nscoord dx = 0;
switch (aStylePos->mLeftOffset.GetUnit()) {
case eStyleUnit_Percent:
printf("XXX: not yet implemented: % relative position\n");
case eStyleUnit_Auto:
break;
case eStyleUnit_Coord:
dx = aStylePos->mLeftOffset.GetCoordValue();
break;
}
aX += dx;
nscoord dy = 0;
switch (aStylePos->mTopOffset.GetUnit()) {
case eStyleUnit_Percent:
printf("XXX: not yet implemented: % relative position\n");
case eStyleUnit_Auto:
break;
case eStyleUnit_Coord:
dy = aStylePos->mTopOffset.GetCoordValue();
break;
}
aY += dy;
}

View File

@@ -0,0 +1,129 @@
/* -*- 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.
*/
#ifndef nsBlockReflowContext_h___
#define nsBlockReflowContext_h___
#include "nsIHTMLReflow.h"
class nsBlockFrame;
class nsFrameReflowState;
class nsIFrame;
class nsIPresContext;
class nsLineLayout;
struct nsStylePosition;
struct nsStyleSpacing;
/**
* An encapsulation of the state and algorithm for reflowing block frames.
*/
class nsBlockReflowContext {
public:
nsBlockReflowContext(nsIPresContext& aPresContext,
nsLineLayout& aLineLayout,
nsFrameReflowState& aParentRS);
~nsBlockReflowContext() { }
void SetRunInFrame(nsBlockFrame* aRunInFrame) {
mRunInFrame = aRunInFrame;
}
void SetCompactMarginWidth(nscoord aCompactMarginWidth) {
mCompactMarginWidth = aCompactMarginWidth;
}
nsresult ReflowBlock(nsIFrame* aFrame, const nsRect& aSpace);
PRBool PlaceBlock(PRBool aForceFit, PRBool aApplyTopMargin,
nscoord aPrevBottomMargin,
nsRect& aInFlowBounds,
nsRect& aCombinedRect);
nscoord GetCollapsedTopMargin() const {
return mTopMargin;
}
nscoord GetCollapsedBottomMargin() const {
return mBottomMargin;
}
nscoord GetCarriedOutTopMargin() const {
return mMetrics.mCarriedOutTopMargin;
}
nscoord GetCarriedOutBottomMargin() const {
return mMetrics.mCarriedOutBottomMargin;
}
const nsSize& GetMaxElementSize() const {
return mMaxElementSize;
}
static void ComputeMarginsFor(nsIPresContext& aPresContext,
nsIFrame* aFrame,
const nsStyleSpacing* aSpacing,
const nsFrameReflowState& aParentRS,
nsMargin& aResult);
static void CollapseMargins(const nsMargin& aMargin,
nscoord aCarriedOutTopMargin,
nscoord aCarriedOutBottomMargin,
nscoord aFrameHeight,
nscoord aPrevBottomMargin,
nscoord& aTopMarginResult,
nscoord& aBottomMarginResult);
static nscoord MaxMargin(nscoord a, nscoord b) {
if (a < 0) {
if (b < 0) {
if (a < b) return a;
return b;
}
return b + a;
}
else if (b < 0) {
return a + b;
}
if (a > b) return a;
return b;
}
static void ComputeRelativePosition(nsIFrame* aFrame,
const nsStylePosition* aStylePos,
nscoord& aX, nscoord& aY);
protected:
nsIPresContext& mPresContext;
nsLineLayout& mLineLayout;
nsFrameReflowState& mOuterReflowState;
nsIFrame* mFrame;
nsBlockFrame* mRunInFrame;
nscoord mCompactMarginWidth;
nsRect mSpace;
const nsStyleSpacing* mSpacing;
nsMargin mMargin;
nscoord mX, mY;
nsHTMLReflowMetrics mMetrics;
nscoord mTopMargin;
nscoord mBottomMargin;
nsSize mMaxElementSize;
};
#endif /* nsBlockReflowContext_h___ */

View File

@@ -0,0 +1,433 @@
/* -*- 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 "nsBulletFrame.h"
#include "nsHTMLAtoms.h"
#include "nsHTMLIIDs.h"
#include "nsHTMLParts.h"
#include "nsHTMLValue.h"
#include "nsHTMLContainerFrame.h"
#include "nsIFontMetrics.h"
#include "nsIHTMLContent.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsIReflowCommand.h"
#include "nsIRenderingContext.h"
#include "prprf.h"
nsBulletFrame::nsBulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsFrame(aContent, aParentFrame)
{
}
nsBulletFrame::~nsBulletFrame()
{
}
NS_IMETHODIMP
nsBulletFrame::DeleteFrame(nsIPresContext& aPresContext)
{
// Release image loader first so that its refcnt can go to zero
mImageLoader.DestroyLoader();
return nsFrame::DeleteFrame(aPresContext);
}
NS_IMETHODIMP
nsBulletFrame::GetFrameName(nsString& aResult) const
{
return MakeFrameName("Bullet", aResult);
}
NS_IMETHODIMP
nsBulletFrame::List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter) const
{
PRInt32 i;
for (i = aIndent; --i >= 0; ) fputs(" ", out);
fprintf(out, "Bullet(%d)@%p ", ContentIndexInContainer(this), this);
nsIView* view;
GetView(view);
if (nsnull != view) {
fprintf(out, " [view=%p]", view);
}
out << mRect;
if (0 != mState) {
fprintf(out, " [state=%08x]", mState);
}
fputs("<>\n", out);
return NS_OK;
}
NS_METHOD
nsBulletFrame::Paint(nsIPresContext& aCX,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
const nsStyleDisplay* disp =
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
nscoord width;
if (disp->mVisible) {
const nsStyleList* myList =
(const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List);
if (myList->mListStyleImage.Length() > 0) {
nsIImage* image = mImageLoader.GetImage();
if (nsnull == image) {
if (!mImageLoader.GetLoadImageFailed()) {
// No image yet
return NS_OK;
}
}
else {
nsRect innerArea(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
aRenderingContext.DrawImage(image, innerArea);
return NS_OK;
}
}
const nsStyleFont* myFont =
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
const nsStyleColor* myColor =
(const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
nsIFontMetrics* fm;
aRenderingContext.SetColor(myColor->mColor);
nsAutoString text;
switch (myList->mListStyleType) {
case NS_STYLE_LIST_STYLE_NONE:
break;
default:
case NS_STYLE_LIST_STYLE_BASIC:
case NS_STYLE_LIST_STYLE_DISC:
aRenderingContext.FillEllipse(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
break;
case NS_STYLE_LIST_STYLE_CIRCLE:
aRenderingContext.DrawEllipse(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
break;
case NS_STYLE_LIST_STYLE_SQUARE:
aRenderingContext.FillRect(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
break;
case NS_STYLE_LIST_STYLE_DECIMAL:
case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
fm = aCX.GetMetricsFor(myFont->mFont);
GetListItemText(aCX, *myList, text);
aRenderingContext.SetFont(fm);
aRenderingContext.GetWidth(text, width);
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
NS_RELEASE(fm);
break;
}
}
return NS_OK;
}
PRInt32
nsBulletFrame::SetListItemOrdinal(PRInt32 aNextOrdinal)
{
// Assume that the ordinal comes from the block reflow state
mOrdinal = aNextOrdinal;
// Try to get value directly from the list-item, if it specifies a
// value attribute. Note: we do this with our parent's content
// because our parent is the list-item.
nsHTMLValue value;
nsIContent* parentContent;
mContentParent->GetContent(parentContent);
nsIHTMLContent* hc;
if (NS_OK == parentContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
if (NS_CONTENT_ATTR_HAS_VALUE ==
hc->GetAttribute(nsHTMLAtoms::value, value)) {
if (eHTMLUnit_Integer == value.GetUnit()) {
// Use ordinal specified by the value attribute
mOrdinal = value.GetIntValue();
if (mOrdinal <= 0) {
mOrdinal = 1;
}
}
}
NS_RELEASE(hc);
}
NS_RELEASE(parentContent);
return mOrdinal + 1;
}
static const char* gLowerRomanCharsA = "ixcm";
static const char* gUpperRomanCharsA = "IXCM";
static const char* gLowerRomanCharsB = "vld?";
static const char* gUpperRomanCharsB = "VLD?";
static const char* gLowerAlphaChars = "abcdefghijklmnopqrstuvwxyz";
static const char* gUpperAlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// XXX change roman/alpha to use unsigned math so that maxint and
// maxnegint will work
void
nsBulletFrame::GetListItemText(nsIPresContext& aCX,
const nsStyleList& aListStyle,
nsString& result)
{
PRInt32 ordinal = mOrdinal;
char cbuf[40];
switch (aListStyle.mListStyleType) {
case NS_STYLE_LIST_STYLE_DECIMAL:
PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
result.Append(cbuf);
break;
case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
{
if (ordinal <= 0) {
ordinal = 1;
}
nsAutoString addOn, decStr;
decStr.Append(ordinal, 10);
PRIntn len = decStr.Length();
const PRUnichar* dp = decStr.GetUnicode();
const PRUnichar* end = dp + len;
PRIntn romanPos = len;
PRIntn n;
const char* achars;
const char* bchars;
if (aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_LOWER_ROMAN) {
achars = gLowerRomanCharsA;
bchars = gLowerRomanCharsB;
}
else {
achars = gUpperRomanCharsA;
bchars = gUpperRomanCharsB;
}
for (; dp < end; dp++) {
romanPos--;
addOn.SetLength(0);
switch(*dp) {
case '3': addOn.Append(achars[romanPos]);
case '2': addOn.Append(achars[romanPos]);
case '1': addOn.Append(achars[romanPos]);
break;
case '4':
addOn.Append(achars[romanPos]);
// FALLTHROUGH
case '5': case '6':
case '7': case '8':
addOn.Append(bchars[romanPos]);
for(n=0;n<(*dp-'5');n++) {
addOn.Append(achars[romanPos]);
}
break;
case '9':
addOn.Append(achars[romanPos]);
addOn.Append(achars[romanPos+1]);
break;
default:
break;
}
result.Append(addOn);
}
}
break;
case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
{
PRInt32 anOffset = -1;
PRInt32 aBase = 26;
PRInt32 ndex=0;
PRInt32 root=1;
PRInt32 next=aBase;
PRInt32 expn=1;
const char* chars =
(aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_LOWER_ALPHA)
? gLowerAlphaChars : gUpperAlphaChars;
// must be positive here...
if (ordinal <= 0) {
ordinal = 1;
}
ordinal--; // a == 0
// scale up in baseN; exceed current value.
while (next<=ordinal) {
root=next;
next*=aBase;
expn++;
}
while (0!=(expn--)) {
ndex = ((root<=ordinal) && (0!=root)) ? (ordinal/root): 0;
ordinal %= root;
if (root>1)
result.Append(chars[ndex+anOffset]);
else
result.Append(chars[ndex]);
root /= aBase;
}
}
break;
}
result.Append(".");
}
#define MIN_BULLET_SIZE 5 // from laytext.c
static nsresult
UpdateBulletCB(nsIPresContext& aPresContext, nsIFrame* aFrame, PRIntn aStatus)
{
nsresult rv = NS_OK;
if (NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE & aStatus) {
// Now that the size is available, trigger a reflow of the bullet
// frame.
nsIPresShell* shell;
shell = aPresContext.GetShell();
if (nsnull != shell) {
nsIReflowCommand* cmd;
rv = NS_NewHTMLReflowCommand(&cmd, aFrame,
nsIReflowCommand::ContentChanged);
if (NS_OK == rv) {
shell->EnterReflowLock();
shell->AppendReflowCommand(cmd);
NS_RELEASE(cmd);
shell->ExitReflowLock();
}
NS_RELEASE(shell);
}
}
return rv;
}
void
nsBulletFrame::GetDesiredSize(nsIPresContext* aCX,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics)
{
const nsStyleList* myList =
(const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List);
nscoord ascent;
if (myList->mListStyleImage.Length() > 0) {
mImageLoader.SetURL(myList->mListStyleImage);
mImageLoader.GetDesiredSize(aCX, aReflowState, this, UpdateBulletCB,
aMetrics);
if (!mImageLoader.GetLoadImageFailed()) {
nsHTMLContainerFrame::CreateViewForFrame(*aCX, this, mStyleContext,
PR_FALSE);
aMetrics.ascent = aMetrics.height;
aMetrics.descent = 0;
return;
}
}
const nsStyleFont* myFont =
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
nsIFontMetrics* fm = aCX->GetMetricsFor(myFont->mFont);
nscoord bulletSize;
float p2t;
float t2p;
nsAutoString text;
switch (myList->mListStyleType) {
case NS_STYLE_LIST_STYLE_NONE:
aMetrics.width = 0;
aMetrics.height = 0;
aMetrics.ascent = 0;
aMetrics.descent = 0;
break;
default:
case NS_STYLE_LIST_STYLE_DISC:
case NS_STYLE_LIST_STYLE_CIRCLE:
case NS_STYLE_LIST_STYLE_BASIC:
case NS_STYLE_LIST_STYLE_SQUARE:
t2p = aCX->GetTwipsToPixels();
fm->GetMaxAscent(ascent);
bulletSize = NSTwipsToIntPixels(
(nscoord)NSToIntRound(0.8f * (float(ascent) / 2.0f)), t2p);
if (bulletSize < 1) {
bulletSize = MIN_BULLET_SIZE;
}
p2t = aCX->GetPixelsToTwips();
bulletSize = NSIntPixelsToTwips(bulletSize, p2t);
mPadding.bottom = ascent / 8;
aMetrics.width = mPadding.right + bulletSize;
aMetrics.height = mPadding.bottom + bulletSize;
aMetrics.ascent = mPadding.bottom + bulletSize;
aMetrics.descent = 0;
break;
case NS_STYLE_LIST_STYLE_DECIMAL:
case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
GetListItemText(*aCX, *myList, text);
fm->GetHeight(aMetrics.height);
aReflowState.rendContext->SetFont(fm);
aReflowState.rendContext->GetWidth(text, aMetrics.width);
aMetrics.width += mPadding.right;
fm->GetMaxAscent(aMetrics.ascent);
fm->GetMaxDescent(aMetrics.descent);
break;
}
NS_RELEASE(fm);
}
NS_IMETHODIMP
nsBulletFrame::Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
// Get the base size
GetDesiredSize(&aPresContext, aReflowState, aMetrics);
// Add in the border and padding; split the top/bottom between the
// ascent and descent to make things look nice
const nsStyleSpacing* space =(const nsStyleSpacing*)
mStyleContext->GetStyleData(eStyleStruct_Spacing);
nsMargin borderPadding;
nsHTMLReflowState::ComputeBorderPaddingFor(this,
aReflowState.parentReflowState,
borderPadding);
aMetrics.width += borderPadding.left + borderPadding.right;
aMetrics.height += borderPadding.top + borderPadding.bottom;
aMetrics.ascent += borderPadding.top;
aMetrics.descent += borderPadding.bottom;
if (nsnull != aMetrics.maxElementSize) {
aMetrics.maxElementSize->width = aMetrics.width;
aMetrics.maxElementSize->height = aMetrics.height;
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}

View File

@@ -0,0 +1,65 @@
/* -*- 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.
*/
#ifndef nsBulletFrame_h___
#define nsBulletFrame_h___
#include "nsHTMLImage.h"
#include "nsIStyleContext.h"
/**
* A simple class that manages the layout and rendering of html bullets.
* This class also supports the CSS list-style properties.
*/
class nsBulletFrame : public nsFrame {
public:
nsBulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
virtual ~nsBulletFrame();
// nsIFrame
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
NS_IMETHOD Paint(nsIPresContext &aCX,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect);
NS_IMETHOD GetFrameName(nsString& aResult) const;
NS_IMETHOD List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter) const;
// nsIHTMLReflow
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
// nsBulletFrame
PRInt32 SetListItemOrdinal(PRInt32 aNextOrdinal);
protected:
void GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics);
void GetListItemText(nsIPresContext& aCX,
const nsStyleList& aStyleList,
nsString& aResult);
PRInt32 mOrdinal;
nsMargin mPadding;
nsHTMLImageLoader mImageLoader;
};
#endif /* nsBulletFrame_h___ */

View File

@@ -0,0 +1,275 @@
/* -*- 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 "nsLineBox.h"
#include "nsISpaceManager.h"
#include "prprf.h"
nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRUint16 flags)
{
mFirstChild = aFrame;
mChildCount = aCount;
mState = LINE_IS_DIRTY | LINE_NEED_DID_REFLOW | flags;
mFloaters = nsnull;
mNext = nsnull;
mBounds.SetRect(0,0,0,0);
mCombinedArea.SetRect(0,0,0,0);
mCarriedOutTopMargin = 0;
mCarriedOutBottomMargin = 0;
mBreakType = NS_STYLE_CLEAR_NONE;
}
nsLineBox::~nsLineBox()
{
if (nsnull != mFloaters) {
delete mFloaters;
}
}
static void
ListFloaters(FILE* out, PRInt32 aIndent, nsVoidArray* aFloaters)
{
PRInt32 j, i, n = aFloaters->Count();
for (i = 0; i < n; i++) {
for (j = aIndent; --j >= 0; ) fputs(" ", out);
nsPlaceholderFrame* ph = (nsPlaceholderFrame*) aFloaters->ElementAt(i);
if (nsnull != ph) {
fprintf(out, "placeholder@%p\n", ph);
nsIFrame* frame = ph->GetAnchoredItem();
if (nsnull != frame) {
frame->List(out, aIndent + 1, nsnull);
}
}
}
}
char*
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
{
PR_snprintf(aBuf, aBufSize, "%s,%s",
(mState & LINE_IS_DIRTY) ? "dirty" : "clean",
(mState & LINE_IS_BLOCK) ? "block" : "inline");
return aBuf;
}
void
nsLineBox::List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter,
PRBool aOutputMe) const
{
PRInt32 i;
if (aOutputMe) {
for (i = aIndent; --i >= 0; ) fputs(" ", out);
char cbuf[100];
fprintf(out, "line %p: count=%d state=%s ",
this, ChildCount(), StateToString(cbuf, sizeof(cbuf)));
if (0 != mCarriedOutTopMargin) {
fprintf(out, "tm=%d ", mCarriedOutTopMargin);
}
if (0 != mCarriedOutBottomMargin) {
fprintf(out, "bm=%d ", mCarriedOutBottomMargin);
}
out << mBounds;
fprintf(out, " ca=");
out << mCombinedArea;
fprintf(out, " <\n");
}
nsIFrame* frame = mFirstChild;
PRInt32 n = ChildCount();
while (--n >= 0) {
frame->List(out, aIndent + 1, aFilter);
frame->GetNextSibling(frame);
}
if (aOutputMe) {
for (i = aIndent; --i >= 0; ) fputs(" ", out);
if (nsnull != mFloaters) {
fputs("> floaters <\n", out);
ListFloaters(out, aIndent + 1, mFloaters);
for (i = aIndent; --i >= 0; ) fputs(" ", out);
}
fputs(">\n", out);
}
}
nsIFrame*
nsLineBox::LastChild() const
{
nsIFrame* frame = mFirstChild;
PRInt32 n = ChildCount() - 1;
while (--n >= 0) {
frame->GetNextSibling(frame);
}
return frame;
}
PRBool
nsLineBox::IsLastChild(nsIFrame* aFrame) const
{
nsIFrame* lastFrame = LastChild();
return aFrame == lastFrame;
}
PRBool
nsLineBox::Contains(nsIFrame* aFrame) const
{
PRInt32 n = ChildCount();
nsIFrame* frame = mFirstChild;
while (--n >= 0) {
if (frame == aFrame) {
return PR_TRUE;
}
frame->GetNextSibling(frame);
}
return PR_FALSE;
}
#if 0
static PRInt32
LengthOf(nsIFrame* aFrame)
{
PRInt32 result = 0;
while (nsnull != aFrame) {
result++;
aFrame->GetNextSibling(aFrame);
}
return result;
}
void
nsLineBox::Verify()
{
nsIFrame* lastFrame = LastChild();
if (nsnull != lastFrame) {
nsIFrame* nextInFlow;
lastFrame->GetNextInFlow(nextInFlow);
if (nsnull != mNext) {
nsIFrame* nextSibling;
lastFrame->GetNextSibling(nextSibling);
NS_ASSERTION(mNext->mFirstChild == nextSibling, "bad line list");
}
}
PRInt32 len = LengthOf(mFirstChild);
NS_ASSERTION(len >= ChildCount(), "bad mChildCount");
}
static void
VerifyLines(nsLineBox* aLine)
{
while (nsnull != aLine) {
aLine->Verify();
aLine = aLine->mNext;
}
}
static void
VerifyChildCount(nsLineBox* aLines, PRBool aEmptyOK = PR_FALSE)
{
if (nsnull != aLines) {
PRInt32 childCount = LengthOf(aLines->mFirstChild);
PRInt32 sum = 0;
nsLineBox* line = aLines;
while (nsnull != line) {
if (!aEmptyOK) {
NS_ASSERTION(0 != line->ChildCount(), "empty line left in line list");
}
sum += line->ChildCount();
line = line->mNext;
}
if (sum != childCount) {
printf("Bad sibling list/line mChildCount's\n");
nsLineBox* line = aLines;
while (nsnull != line) {
line->List(stdout, 1);
if (nsnull != line->mNext) {
nsIFrame* lastFrame = line->LastChild();
if (nsnull != lastFrame) {
nsIFrame* nextSibling;
lastFrame->GetNextSibling(nextSibling);
if (line->mNext->mFirstChild != nextSibling) {
printf(" [list broken: nextSibling=%p mNext->mFirstChild=%p]\n",
nextSibling, line->mNext->mFirstChild);
}
}
}
line = line->mNext;
}
NS_ASSERTION(sum == childCount, "bad sibling list/line mChildCount's");
}
}
}
#endif
void
nsLineBox::DeleteLineList(nsIPresContext& aPresContext, nsLineBox* aLine)
{
if (nsnull != aLine) {
// Delete our child frames before doing anything else. In particular
// we do all of this before our base class releases it's hold on the
// view.
for (nsIFrame* child = aLine->mFirstChild; child; ) {
nsIFrame* nextChild;
child->GetNextSibling(nextChild);
child->DeleteFrame(aPresContext);
child = nextChild;
}
while (nsnull != aLine) {
nsLineBox* next = aLine->mNext;
delete aLine;
aLine = next;
}
}
}
nsLineBox*
nsLineBox::LastLine(nsLineBox* aLine)
{
if (nsnull != aLine) {
while (nsnull != aLine->mNext) {
aLine = aLine->mNext;
}
}
return aLine;
}
nsLineBox*
nsLineBox::FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame)
{
while (nsnull != aLine) {
if (aLine->Contains(aFrame)) {
return aLine;
}
aLine = aLine->mNext;
}
return nsnull;
}
void
nsLineBox::UnplaceFloaters(nsISpaceManager* aSpaceManager)
{
if (nsnull != mFloaters) {
PRInt32 i, n = mFloaters->Count();
for (i = 0; i < n; i++) {
nsPlaceholderFrame* pf = (nsPlaceholderFrame*) mFloaters->ElementAt(i);
nsIFrame* floater = pf->GetAnchoredItem();
aSpaceManager->RemoveRegion(floater);
}
}
}

View File

@@ -0,0 +1,192 @@
/* -*- 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.
*/
#ifndef nsLineBox_h___
#define nsLineBox_h___
#include "nsVoidArray.h"
#include "nsPlaceholderFrame.h"
// bits in nsLineBox.mFlags
#define LINE_IS_DIRTY 0x1
#define LINE_IS_BLOCK 0x2
#define LINE_NEED_DID_REFLOW 0x8
#define LINE_TOP_MARGIN_IS_AUTO 0x10
#define LINE_BOTTOM_MARGIN_IS_AUTO 0x20
#define LINE_OUTSIDE_CHILDREN 0x40
class nsISpaceManager;
class nsLineBox;
/**
* A list of block lines
*/
class nsLineBoxList {
public:
protected:
nsLineBox* mLines;
};
/**
* The nsLineBox class represents a horizontal line of frames. It contains
* enough state to support incremental reflow of the frames, event handling
* for the frames, and rendering of the frames.
*/
class nsLineBox {
public:
nscoord GetCarriedOutTopMargin() const {
return mCarriedOutTopMargin;
}
nscoord GetCarriedOutBottomMargin() const {
return mCarriedOutBottomMargin;
}
nscoord GetCarriedOutMarginFlags() const {
return 0;/* XXX write me */
}
nscoord GetHeight() const { return mBounds.height; }
//----------------------------------------------------------------------
// XXX old junk
nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRUint16 flags);
~nsLineBox();
static void DeleteLineList(nsIPresContext& aPresContext, nsLineBox* aLine);
static nsLineBox* LastLine(nsLineBox* aLine);
static nsLineBox* FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame);
void List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter,
PRBool aOutputMe) const;
PRInt32 ChildCount() const {
return PRInt32(mChildCount);
}
nsIFrame* LastChild() const;
PRBool IsLastChild(nsIFrame* aFrame) const;
PRBool IsBlock() const {
return 0 != (LINE_IS_BLOCK & mState);
}
void SetIsBlock() {
mState |= LINE_IS_BLOCK;
}
void ClearIsBlock() {
mState &= ~LINE_IS_BLOCK;
}
void SetIsBlock(PRBool aValue) {
if (aValue) {
SetIsBlock();
}
else {
ClearIsBlock();
}
}
void MarkDirty() {
mState |= LINE_IS_DIRTY;
}
void ClearDirty() {
mState &= ~LINE_IS_DIRTY;
}
void SetNeedDidReflow() {
mState |= LINE_NEED_DID_REFLOW;
}
void ClearNeedDidReflow() {
mState &= ~LINE_NEED_DID_REFLOW;
}
PRBool NeedsDidReflow() {
return 0 != (LINE_NEED_DID_REFLOW & mState);
}
PRBool IsDirty() const {
return 0 != (LINE_IS_DIRTY & mState);
}
void SetOutsideChildren() {
mState |= LINE_OUTSIDE_CHILDREN;
}
void ClearOutsideChildren() {
mState &= ~LINE_OUTSIDE_CHILDREN;
}
PRBool OutsideChildren() const {
return 0 != (LINE_OUTSIDE_CHILDREN & mState);
}
PRUint16 GetState() const { return mState; }
char* StateToString(char* aBuf, PRInt32 aBufSize) const;
PRBool Contains(nsIFrame* aFrame) const;
// XXX ick
void SetMarginFlags(PRUintn aFlags) {
mState &= ~(LINE_TOP_MARGIN_IS_AUTO|LINE_BOTTOM_MARGIN_IS_AUTO);
if (NS_CARRIED_TOP_MARGIN_IS_AUTO & aFlags) {
mState |= LINE_TOP_MARGIN_IS_AUTO;
}
if (NS_CARRIED_BOTTOM_MARGIN_IS_AUTO & aFlags) {
mState |= LINE_BOTTOM_MARGIN_IS_AUTO;
}
}
PRUintn GetMarginFlags() {
return ((LINE_TOP_MARGIN_IS_AUTO & mState)
? NS_CARRIED_TOP_MARGIN_IS_AUTO : 0) |
((LINE_BOTTOM_MARGIN_IS_AUTO & mState) ?
NS_CARRIED_BOTTOM_MARGIN_IS_AUTO : 0);
}
void UnplaceFloaters(nsISpaceManager* aSpaceManager);
#ifdef NS_DEBUG
void Verify();
#endif
//XXX protected:
nsIFrame* mFirstChild;
PRUint16 mChildCount;
PRUint16 mState;
PRUint8 mBreakType;
nsRect mBounds;
nsRect mCombinedArea;
nscoord mCarriedOutTopMargin;/* XXX switch to 16 bits */
nscoord mCarriedOutBottomMargin;/* XXX switch to 16 bits */
nsVoidArray* mFloaters;
nsLineBox* mNext;
protected:
};
#endif /* nsLineBox_h___ */

View File

@@ -0,0 +1,407 @@
/* -*- 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 "nsBlockReflowContext.h"
#include "nsFrameReflowState.h"
#include "nsLineLayout.h"
#include "nsHTMLIIDs.h"
#include "nsISpaceManager.h"
#include "nsIFontMetrics.h"
#include "nsIPresContext.h"
#include "nsIStyleContext.h"
#include "nsHTMLContainerFrame.h"
nsBlockReflowContext::nsBlockReflowContext(nsIPresContext& aPresContext,
nsLineLayout& aLineLayout,
nsFrameReflowState& aParentRS)
: mPresContext(aPresContext),
mLineLayout(aLineLayout),
mOuterReflowState(aParentRS),
mMetrics(aParentRS.mComputeMaxElementSize ? &mMaxElementSize : nsnull)
{
mRunInFrame = nsnull;
mCompactMarginWidth = 0;
mSpacing = nsnull;
}
void
nsBlockReflowContext::ComputeMarginsFor(nsIPresContext& aPresContext,
nsIFrame* aFrame,
const nsStyleSpacing* aSpacing,
const nsFrameReflowState& aParentRS,
nsMargin& aResult)
{
// XXX pass in mSpacing to ComputeMarginFor
nsHTMLReflowState::ComputeMarginFor(aFrame, &aParentRS, aResult);
// Compute auto top/bottom margin values
nsStyleUnit topUnit = aSpacing->mMargin.GetTopUnit();
nsStyleUnit bottomUnit = aSpacing->mMargin.GetBottomUnit();
nscoord fontHeight = 0;
if ((eStyleUnit_Auto == topUnit) || (eStyleUnit_Auto == bottomUnit)) {
// XXX Use the font for the frame, not the default font???
const nsFont& defaultFont = aPresContext.GetDefaultFont();
nsIFontMetrics* fm = aPresContext.GetMetricsFor(defaultFont);
fm->GetHeight(fontHeight);
NS_RELEASE(fm);
}
// For auto margins use the font height computed above
if (eStyleUnit_Auto == topUnit) {
aResult.top = fontHeight;
}
if (eStyleUnit_Auto == bottomUnit) {
aResult.bottom = fontHeight;
}
}
nsresult
nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame, const nsRect& aSpace)
{
nsReflowStatus reflowStatus;
mFrame = aFrame;
mSpace = aSpace;
// Compute the margins (including auto margins)
aFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)mSpacing);
ComputeMarginsFor(mPresContext, aFrame, mSpacing, mOuterReflowState,
mMargin);
// Compute x/y coordinate where reflow will begin. Use the rules
// from 10.3.3 to determine what to apply. At this point in the
// reflow auto left/right margins will have a zero value.
nscoord x = aSpace.x + mMargin.left;
nscoord y = aSpace.y;
mX = x;
mY = y;
nsSize availSize(aSpace.width, aSpace.height);
if (NS_UNCONSTRAINEDSIZE != aSpace.width) {
availSize.width -= mMargin.left;
}
if (NS_UNCONSTRAINEDSIZE != aSpace.height) {
availSize.height -= mMargin.top + mMargin.bottom;
}
// Get reflow reason set correctly. It's possible that a child was
// created and then it was decided that it could not be reflowed
// (for example, a block frame that isn't at the start of a
// line). In this case the reason will be wrong so we need to check
// the frame state.
nsReflowReason reason = eReflowReason_Resize;
nsFrameState state;
aFrame->GetFrameState(state);
if (NS_FRAME_FIRST_REFLOW & state) {
reason = eReflowReason_Initial;
}
else if (mOuterReflowState.mNextRCFrame == aFrame) {
reason = eReflowReason_Incremental;
// Make sure we only incrementally reflow once
// XXX caller should do this, yes?
mOuterReflowState.mNextRCFrame = nsnull;
}
// Setup reflow state for reflowing the frame
nsHTMLReflowState reflowState(mPresContext, aFrame, mOuterReflowState,
availSize);
reflowState.lineLayout = nsnull;
reflowState.mRunInFrame = mRunInFrame;
reflowState.mCompactMarginWidth = mCompactMarginWidth;
reflowState.reason = reason;
mLineLayout.SetUnderstandsWhiteSpace(PR_FALSE);
// Let frame know that we are reflowing it
nsIHTMLReflow* htmlReflow;
nsresult rv = aFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
if (!NS_SUCCEEDED(rv)) {
return rv;
}
htmlReflow->WillReflow(mPresContext);
// Adjust spacemanager coordinate system for the frame. The
// spacemanager coordinates are <b>inside</b> the callers
// border+padding, but the x/y coordinates are not (recall that
// frame coordinates are relative to the parents origin and that the
// parents border/padding is <b>inside</b> the parent
// frame. Therefore we have to subtract out the parents
// border+padding before translating.
nscoord tx = x - mOuterReflowState.mBorderPadding.left;
nscoord ty = y - mOuterReflowState.mBorderPadding.top;
aFrame->MoveTo(x, y);
mOuterReflowState.spaceManager->Translate(tx, ty);
htmlReflow->Reflow(mPresContext, mMetrics, reflowState, reflowStatus);
mOuterReflowState.spaceManager->Translate(-tx, -ty);
aFrame->GetFrameState(state);
if (0 == (NS_FRAME_OUTSIDE_CHILDREN & state)) {
// Provide combined area for child that doesn't have any
mMetrics.mCombinedArea.x = 0;
mMetrics.mCombinedArea.y = 0;
mMetrics.mCombinedArea.width = mMetrics.width;
mMetrics.mCombinedArea.height = mMetrics.height;
}
// Now that frame has been reflowed at least one time make sure that
// the NS_FRAME_FIRST_REFLOW bit is cleared so that never give it an
// initial reflow reason again.
if (eReflowReason_Initial == reason) {
aFrame->SetFrameState(state & ~NS_FRAME_FIRST_REFLOW);
}
if (!NS_INLINE_IS_BREAK_BEFORE(reflowStatus)) {
// If frame is complete and has a next-in-flow, we need to delete
// them now. Do not do this when a break-before is signaled because
// the frame is going to get reflowed again (and may end up wanting
// a next-in-flow where it ends up).
if (NS_FRAME_IS_COMPLETE(reflowStatus)) {
nsIFrame* kidNextInFlow;
aFrame->GetNextInFlow(kidNextInFlow);
if (nsnull != kidNextInFlow) {
// Remove all of the childs next-in-flows. Make sure that we ask
// the right parent to do the removal (it's possible that the
// parent is not this because we are executing pullup code)
/* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
nsHTMLContainerFrame* parent;
aFrame->GetGeometricParent((nsIFrame*&) parent);
parent->DeleteChildsNextInFlow(mPresContext, aFrame);
}
}
}
return reflowStatus;
}
/**
* The CSS2 spec, section 8.3.1 defines margin collapsing to apply to
* vertical margins of block boxes. And the spec also indicates that
* this should be done for two or more adjacent vertical margins. It
* also indicates that the margins collapse between boxes that are
* next to each other or nested.
*/
void
nsBlockReflowContext::CollapseMargins(const nsMargin& aMargin,
nscoord aCarriedOutTopMargin,
nscoord aCarriedOutBottomMargin,
nscoord aFrameHeight,
nscoord aPrevBottomMargin,
nscoord& aTopMarginResult,
nscoord& aBottomMarginResult)
{
// Compute the collapsed top margin value. The top margin value is a
// 3 way margin collapse. First we collapse the carried out top
// margin with the block frames top margin (this is a CSS2 "nested"
// collapse). Then we collapse that value with the previous bottom
// margin (because the collapsed margin is adjacent to the previous
// bottom margin).
nscoord carriedTopMargin = aCarriedOutTopMargin;
nscoord topMargin = aMargin.top;
topMargin = MaxMargin(topMargin, carriedTopMargin);
topMargin = MaxMargin(topMargin, aPrevBottomMargin);
// Compute the collapsed bottom margin value. The bottom margin
// value is a 2 way margin collapse. Collapse the carried out bottom
// margin with the block frames bottom margin (this is a CSS2
// "nested" collapse).
nscoord carriedBottomMargin = aCarriedOutBottomMargin;
nscoord bottomMargin = aMargin.bottom;
bottomMargin = MaxMargin(bottomMargin, carriedBottomMargin);
// If the block line is empty then we collapse the top and bottom
// margin values (because the margins are adjacent).
if (0 == aFrameHeight) {
nscoord collapsedMargin = MaxMargin(topMargin, bottomMargin);
topMargin = 0;
bottomMargin = collapsedMargin;
}
aTopMarginResult = topMargin;
aBottomMarginResult = bottomMargin;
}
/**
* Attempt to place the block frame within the available space. If
* it fits, apply horizontal positioning (CSS 10.3.3), collapse
* margins (CSS2 8.3.1). Also apply relative positioning.
*/
PRBool
nsBlockReflowContext::PlaceBlock(PRBool aForceFit, PRBool aApplyTopMargin,
nscoord aPrevBottomMargin,
nsRect& aInFlowBounds,
nsRect& aCombinedRect)
{
// Compute collapsed margin value
CollapseMargins(mMargin, mMetrics.mCarriedOutTopMargin,
mMetrics.mCarriedOutBottomMargin,
mMetrics.height, aPrevBottomMargin,
mTopMargin, mBottomMargin);
// See if the block will fit in the available space
PRBool fits;
if (0 == mMetrics.height) {
// Empty blocks do not have anything special done to them and they
// always fit.
nsRect r(mX, mY, 0, 0);
mFrame->SetRect(r);
aInFlowBounds = r;
aCombinedRect = r;
fits = PR_TRUE;
}
else {
nscoord x = mX;
nscoord y = mY;
// Apply top margin unless it's going to be carried out.
if (aApplyTopMargin) {
y += mTopMargin;
}
// Position block horizontally according to CSS2 10.3.3
if (NS_UNCONSTRAINEDSIZE != mSpace.width) {
// XXX left/right block margins should be applied right here.
// Because of the issue with floaters and block-left/right
// margins this code is not yet complete. This code may need to
// move to before reflowing the frame instead of after (because
// of floater positioning).
nscoord remainder = mSpace.XMost() - (x + mMetrics.width);
if (remainder >= 0) {
// The block frame didn't use all of the available space. Apply
// auto margins.
const nsStyleSpacing* spacing = mSpacing;
if (nsnull != mSpacing) {
nsStyleUnit leftUnit = mSpacing->mMargin.GetLeftUnit();
nsStyleUnit rightUnit = mSpacing->mMargin.GetRightUnit();
if (eStyleUnit_Auto == leftUnit) {
if (eStyleUnit_Auto == rightUnit) {
// When both margins are auto, we center the block
x += remainder / 2;
}
else {
x += remainder;
}
}
else if (eStyleUnit_Auto != rightUnit) {
// When neither margin is auto then text-align applies
const nsStyleText* styleText = mOuterReflowState.mStyleText;
switch (styleText->mTextAlign) {
case NS_STYLE_TEXT_ALIGN_DEFAULT:
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
if (NS_STYLE_DIRECTION_RTL == mOuterReflowState.mDirection) {
// When given a default alignment, and a right-to-left
// direction, right align the frame.
x += remainder;
}
break;
case NS_STYLE_TEXT_ALIGN_RIGHT:
x += remainder;
break;
case NS_STYLE_TEXT_ALIGN_CENTER:
x += remainder / 2;
break;
}
}
}
}
else {
// XXX Handle over-constrained case by forcing the appropriate
// margin to be auto
}
}
// See if the frame fit. If its the first frame then it always
// fits.
if (aForceFit || (y + mMetrics.height <= mSpace.YMost())) {
fits = PR_TRUE;
// Update the in-flow bounding box's bounds
aInFlowBounds.SetRect(x, y, mMetrics.width, mMetrics.height);
// Apply CSS relative positioning to update x,y coordinates
const nsStylePosition* stylePos;
mFrame->GetStyleData(eStyleStruct_Position,
(const nsStyleStruct*&)stylePos);
if (NS_STYLE_POSITION_RELATIVE == stylePos->mPosition) {
ComputeRelativePosition(mFrame, stylePos, x, y);
}
// Compute combined-rect in callers coordinate system. The value
// returned in the reflow metrics is relative to the child
// frame.
aCombinedRect.x = mMetrics.mCombinedArea.x + x;
aCombinedRect.y = mMetrics.mCombinedArea.y + y;
aCombinedRect.width = mMetrics.mCombinedArea.width;
aCombinedRect.height = mMetrics.mCombinedArea.height;
// Now place the frame
mFrame->SetRect(nsRect(x, y, mMetrics.width, mMetrics.height));
// If the block frame ended up moving then we need to slide
// anything inside of it that impacts the space manager
// (otherwise the impacted space in the space manager will be
// out of sync with where the frames really are).
nscoord dx = x - mX;
nscoord dy = y - mY;
if ((0 != dx) || (0 != dy)) {
nsIHTMLReflow* htmlReflow;
nsresult rv;
rv = mFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow);
if (NS_SUCCEEDED(rv)) {
// If the child has any floaters that impact the space manager,
// slide them now
htmlReflow->MoveInSpaceManager(mPresContext,
mOuterReflowState.spaceManager,
dx, dy);
}
}
}
else {
fits = PR_FALSE;
}
}
return fits;
}
void
nsBlockReflowContext::ComputeRelativePosition(nsIFrame* aFrame,
const nsStylePosition* aStylePos,
nscoord& aX, nscoord& aY)
{
nscoord dx = 0;
switch (aStylePos->mLeftOffset.GetUnit()) {
case eStyleUnit_Percent:
printf("XXX: not yet implemented: % relative position\n");
case eStyleUnit_Auto:
break;
case eStyleUnit_Coord:
dx = aStylePos->mLeftOffset.GetCoordValue();
break;
}
aX += dx;
nscoord dy = 0;
switch (aStylePos->mTopOffset.GetUnit()) {
case eStyleUnit_Percent:
printf("XXX: not yet implemented: % relative position\n");
case eStyleUnit_Auto:
break;
case eStyleUnit_Coord:
dy = aStylePos->mTopOffset.GetCoordValue();
break;
}
aY += dy;
}

View File

@@ -0,0 +1,129 @@
/* -*- 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.
*/
#ifndef nsBlockReflowContext_h___
#define nsBlockReflowContext_h___
#include "nsIHTMLReflow.h"
class nsBlockFrame;
class nsFrameReflowState;
class nsIFrame;
class nsIPresContext;
class nsLineLayout;
struct nsStylePosition;
struct nsStyleSpacing;
/**
* An encapsulation of the state and algorithm for reflowing block frames.
*/
class nsBlockReflowContext {
public:
nsBlockReflowContext(nsIPresContext& aPresContext,
nsLineLayout& aLineLayout,
nsFrameReflowState& aParentRS);
~nsBlockReflowContext() { }
void SetRunInFrame(nsBlockFrame* aRunInFrame) {
mRunInFrame = aRunInFrame;
}
void SetCompactMarginWidth(nscoord aCompactMarginWidth) {
mCompactMarginWidth = aCompactMarginWidth;
}
nsresult ReflowBlock(nsIFrame* aFrame, const nsRect& aSpace);
PRBool PlaceBlock(PRBool aForceFit, PRBool aApplyTopMargin,
nscoord aPrevBottomMargin,
nsRect& aInFlowBounds,
nsRect& aCombinedRect);
nscoord GetCollapsedTopMargin() const {
return mTopMargin;
}
nscoord GetCollapsedBottomMargin() const {
return mBottomMargin;
}
nscoord GetCarriedOutTopMargin() const {
return mMetrics.mCarriedOutTopMargin;
}
nscoord GetCarriedOutBottomMargin() const {
return mMetrics.mCarriedOutBottomMargin;
}
const nsSize& GetMaxElementSize() const {
return mMaxElementSize;
}
static void ComputeMarginsFor(nsIPresContext& aPresContext,
nsIFrame* aFrame,
const nsStyleSpacing* aSpacing,
const nsFrameReflowState& aParentRS,
nsMargin& aResult);
static void CollapseMargins(const nsMargin& aMargin,
nscoord aCarriedOutTopMargin,
nscoord aCarriedOutBottomMargin,
nscoord aFrameHeight,
nscoord aPrevBottomMargin,
nscoord& aTopMarginResult,
nscoord& aBottomMarginResult);
static nscoord MaxMargin(nscoord a, nscoord b) {
if (a < 0) {
if (b < 0) {
if (a < b) return a;
return b;
}
return b + a;
}
else if (b < 0) {
return a + b;
}
if (a > b) return a;
return b;
}
static void ComputeRelativePosition(nsIFrame* aFrame,
const nsStylePosition* aStylePos,
nscoord& aX, nscoord& aY);
protected:
nsIPresContext& mPresContext;
nsLineLayout& mLineLayout;
nsFrameReflowState& mOuterReflowState;
nsIFrame* mFrame;
nsBlockFrame* mRunInFrame;
nscoord mCompactMarginWidth;
nsRect mSpace;
const nsStyleSpacing* mSpacing;
nsMargin mMargin;
nscoord mX, mY;
nsHTMLReflowMetrics mMetrics;
nscoord mTopMargin;
nscoord mBottomMargin;
nsSize mMaxElementSize;
};
#endif /* nsBlockReflowContext_h___ */

View File

@@ -0,0 +1,433 @@
/* -*- 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 "nsBulletFrame.h"
#include "nsHTMLAtoms.h"
#include "nsHTMLIIDs.h"
#include "nsHTMLParts.h"
#include "nsHTMLValue.h"
#include "nsHTMLContainerFrame.h"
#include "nsIFontMetrics.h"
#include "nsIHTMLContent.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsIReflowCommand.h"
#include "nsIRenderingContext.h"
#include "prprf.h"
nsBulletFrame::nsBulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
: nsFrame(aContent, aParentFrame)
{
}
nsBulletFrame::~nsBulletFrame()
{
}
NS_IMETHODIMP
nsBulletFrame::DeleteFrame(nsIPresContext& aPresContext)
{
// Release image loader first so that its refcnt can go to zero
mImageLoader.DestroyLoader();
return nsFrame::DeleteFrame(aPresContext);
}
NS_IMETHODIMP
nsBulletFrame::GetFrameName(nsString& aResult) const
{
return MakeFrameName("Bullet", aResult);
}
NS_IMETHODIMP
nsBulletFrame::List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter) const
{
PRInt32 i;
for (i = aIndent; --i >= 0; ) fputs(" ", out);
fprintf(out, "Bullet(%d)@%p ", ContentIndexInContainer(this), this);
nsIView* view;
GetView(view);
if (nsnull != view) {
fprintf(out, " [view=%p]", view);
}
out << mRect;
if (0 != mState) {
fprintf(out, " [state=%08x]", mState);
}
fputs("<>\n", out);
return NS_OK;
}
NS_METHOD
nsBulletFrame::Paint(nsIPresContext& aCX,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
const nsStyleDisplay* disp =
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
nscoord width;
if (disp->mVisible) {
const nsStyleList* myList =
(const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List);
if (myList->mListStyleImage.Length() > 0) {
nsIImage* image = mImageLoader.GetImage();
if (nsnull == image) {
if (!mImageLoader.GetLoadImageFailed()) {
// No image yet
return NS_OK;
}
}
else {
nsRect innerArea(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
aRenderingContext.DrawImage(image, innerArea);
return NS_OK;
}
}
const nsStyleFont* myFont =
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
const nsStyleColor* myColor =
(const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
nsIFontMetrics* fm;
aRenderingContext.SetColor(myColor->mColor);
nsAutoString text;
switch (myList->mListStyleType) {
case NS_STYLE_LIST_STYLE_NONE:
break;
default:
case NS_STYLE_LIST_STYLE_BASIC:
case NS_STYLE_LIST_STYLE_DISC:
aRenderingContext.FillEllipse(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
break;
case NS_STYLE_LIST_STYLE_CIRCLE:
aRenderingContext.DrawEllipse(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
break;
case NS_STYLE_LIST_STYLE_SQUARE:
aRenderingContext.FillRect(mPadding.left, mPadding.top,
mRect.width - (mPadding.left + mPadding.right),
mRect.height - (mPadding.top + mPadding.bottom));
break;
case NS_STYLE_LIST_STYLE_DECIMAL:
case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
fm = aCX.GetMetricsFor(myFont->mFont);
GetListItemText(aCX, *myList, text);
aRenderingContext.SetFont(fm);
aRenderingContext.GetWidth(text, width);
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
NS_RELEASE(fm);
break;
}
}
return NS_OK;
}
PRInt32
nsBulletFrame::SetListItemOrdinal(PRInt32 aNextOrdinal)
{
// Assume that the ordinal comes from the block reflow state
mOrdinal = aNextOrdinal;
// Try to get value directly from the list-item, if it specifies a
// value attribute. Note: we do this with our parent's content
// because our parent is the list-item.
nsHTMLValue value;
nsIContent* parentContent;
mContentParent->GetContent(parentContent);
nsIHTMLContent* hc;
if (NS_OK == parentContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
if (NS_CONTENT_ATTR_HAS_VALUE ==
hc->GetAttribute(nsHTMLAtoms::value, value)) {
if (eHTMLUnit_Integer == value.GetUnit()) {
// Use ordinal specified by the value attribute
mOrdinal = value.GetIntValue();
if (mOrdinal <= 0) {
mOrdinal = 1;
}
}
}
NS_RELEASE(hc);
}
NS_RELEASE(parentContent);
return mOrdinal + 1;
}
static const char* gLowerRomanCharsA = "ixcm";
static const char* gUpperRomanCharsA = "IXCM";
static const char* gLowerRomanCharsB = "vld?";
static const char* gUpperRomanCharsB = "VLD?";
static const char* gLowerAlphaChars = "abcdefghijklmnopqrstuvwxyz";
static const char* gUpperAlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// XXX change roman/alpha to use unsigned math so that maxint and
// maxnegint will work
void
nsBulletFrame::GetListItemText(nsIPresContext& aCX,
const nsStyleList& aListStyle,
nsString& result)
{
PRInt32 ordinal = mOrdinal;
char cbuf[40];
switch (aListStyle.mListStyleType) {
case NS_STYLE_LIST_STYLE_DECIMAL:
PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
result.Append(cbuf);
break;
case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
{
if (ordinal <= 0) {
ordinal = 1;
}
nsAutoString addOn, decStr;
decStr.Append(ordinal, 10);
PRIntn len = decStr.Length();
const PRUnichar* dp = decStr.GetUnicode();
const PRUnichar* end = dp + len;
PRIntn romanPos = len;
PRIntn n;
const char* achars;
const char* bchars;
if (aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_LOWER_ROMAN) {
achars = gLowerRomanCharsA;
bchars = gLowerRomanCharsB;
}
else {
achars = gUpperRomanCharsA;
bchars = gUpperRomanCharsB;
}
for (; dp < end; dp++) {
romanPos--;
addOn.SetLength(0);
switch(*dp) {
case '3': addOn.Append(achars[romanPos]);
case '2': addOn.Append(achars[romanPos]);
case '1': addOn.Append(achars[romanPos]);
break;
case '4':
addOn.Append(achars[romanPos]);
// FALLTHROUGH
case '5': case '6':
case '7': case '8':
addOn.Append(bchars[romanPos]);
for(n=0;n<(*dp-'5');n++) {
addOn.Append(achars[romanPos]);
}
break;
case '9':
addOn.Append(achars[romanPos]);
addOn.Append(achars[romanPos+1]);
break;
default:
break;
}
result.Append(addOn);
}
}
break;
case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
{
PRInt32 anOffset = -1;
PRInt32 aBase = 26;
PRInt32 ndex=0;
PRInt32 root=1;
PRInt32 next=aBase;
PRInt32 expn=1;
const char* chars =
(aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_LOWER_ALPHA)
? gLowerAlphaChars : gUpperAlphaChars;
// must be positive here...
if (ordinal <= 0) {
ordinal = 1;
}
ordinal--; // a == 0
// scale up in baseN; exceed current value.
while (next<=ordinal) {
root=next;
next*=aBase;
expn++;
}
while (0!=(expn--)) {
ndex = ((root<=ordinal) && (0!=root)) ? (ordinal/root): 0;
ordinal %= root;
if (root>1)
result.Append(chars[ndex+anOffset]);
else
result.Append(chars[ndex]);
root /= aBase;
}
}
break;
}
result.Append(".");
}
#define MIN_BULLET_SIZE 5 // from laytext.c
static nsresult
UpdateBulletCB(nsIPresContext& aPresContext, nsIFrame* aFrame, PRIntn aStatus)
{
nsresult rv = NS_OK;
if (NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE & aStatus) {
// Now that the size is available, trigger a reflow of the bullet
// frame.
nsIPresShell* shell;
shell = aPresContext.GetShell();
if (nsnull != shell) {
nsIReflowCommand* cmd;
rv = NS_NewHTMLReflowCommand(&cmd, aFrame,
nsIReflowCommand::ContentChanged);
if (NS_OK == rv) {
shell->EnterReflowLock();
shell->AppendReflowCommand(cmd);
NS_RELEASE(cmd);
shell->ExitReflowLock();
}
NS_RELEASE(shell);
}
}
return rv;
}
void
nsBulletFrame::GetDesiredSize(nsIPresContext* aCX,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics)
{
const nsStyleList* myList =
(const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List);
nscoord ascent;
if (myList->mListStyleImage.Length() > 0) {
mImageLoader.SetURL(myList->mListStyleImage);
mImageLoader.GetDesiredSize(aCX, aReflowState, this, UpdateBulletCB,
aMetrics);
if (!mImageLoader.GetLoadImageFailed()) {
nsHTMLContainerFrame::CreateViewForFrame(*aCX, this, mStyleContext,
PR_FALSE);
aMetrics.ascent = aMetrics.height;
aMetrics.descent = 0;
return;
}
}
const nsStyleFont* myFont =
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
nsIFontMetrics* fm = aCX->GetMetricsFor(myFont->mFont);
nscoord bulletSize;
float p2t;
float t2p;
nsAutoString text;
switch (myList->mListStyleType) {
case NS_STYLE_LIST_STYLE_NONE:
aMetrics.width = 0;
aMetrics.height = 0;
aMetrics.ascent = 0;
aMetrics.descent = 0;
break;
default:
case NS_STYLE_LIST_STYLE_DISC:
case NS_STYLE_LIST_STYLE_CIRCLE:
case NS_STYLE_LIST_STYLE_BASIC:
case NS_STYLE_LIST_STYLE_SQUARE:
t2p = aCX->GetTwipsToPixels();
fm->GetMaxAscent(ascent);
bulletSize = NSTwipsToIntPixels(
(nscoord)NSToIntRound(0.8f * (float(ascent) / 2.0f)), t2p);
if (bulletSize < 1) {
bulletSize = MIN_BULLET_SIZE;
}
p2t = aCX->GetPixelsToTwips();
bulletSize = NSIntPixelsToTwips(bulletSize, p2t);
mPadding.bottom = ascent / 8;
aMetrics.width = mPadding.right + bulletSize;
aMetrics.height = mPadding.bottom + bulletSize;
aMetrics.ascent = mPadding.bottom + bulletSize;
aMetrics.descent = 0;
break;
case NS_STYLE_LIST_STYLE_DECIMAL:
case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
GetListItemText(*aCX, *myList, text);
fm->GetHeight(aMetrics.height);
aReflowState.rendContext->SetFont(fm);
aReflowState.rendContext->GetWidth(text, aMetrics.width);
aMetrics.width += mPadding.right;
fm->GetMaxAscent(aMetrics.ascent);
fm->GetMaxDescent(aMetrics.descent);
break;
}
NS_RELEASE(fm);
}
NS_IMETHODIMP
nsBulletFrame::Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
// Get the base size
GetDesiredSize(&aPresContext, aReflowState, aMetrics);
// Add in the border and padding; split the top/bottom between the
// ascent and descent to make things look nice
const nsStyleSpacing* space =(const nsStyleSpacing*)
mStyleContext->GetStyleData(eStyleStruct_Spacing);
nsMargin borderPadding;
nsHTMLReflowState::ComputeBorderPaddingFor(this,
aReflowState.parentReflowState,
borderPadding);
aMetrics.width += borderPadding.left + borderPadding.right;
aMetrics.height += borderPadding.top + borderPadding.bottom;
aMetrics.ascent += borderPadding.top;
aMetrics.descent += borderPadding.bottom;
if (nsnull != aMetrics.maxElementSize) {
aMetrics.maxElementSize->width = aMetrics.width;
aMetrics.maxElementSize->height = aMetrics.height;
}
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}

View File

@@ -0,0 +1,65 @@
/* -*- 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.
*/
#ifndef nsBulletFrame_h___
#define nsBulletFrame_h___
#include "nsHTMLImage.h"
#include "nsIStyleContext.h"
/**
* A simple class that manages the layout and rendering of html bullets.
* This class also supports the CSS list-style properties.
*/
class nsBulletFrame : public nsFrame {
public:
nsBulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
virtual ~nsBulletFrame();
// nsIFrame
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
NS_IMETHOD Paint(nsIPresContext &aCX,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect);
NS_IMETHOD GetFrameName(nsString& aResult) const;
NS_IMETHOD List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter) const;
// nsIHTMLReflow
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
// nsBulletFrame
PRInt32 SetListItemOrdinal(PRInt32 aNextOrdinal);
protected:
void GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics);
void GetListItemText(nsIPresContext& aCX,
const nsStyleList& aStyleList,
nsString& aResult);
PRInt32 mOrdinal;
nsMargin mPadding;
nsHTMLImageLoader mImageLoader;
};
#endif /* nsBulletFrame_h___ */

View File

@@ -0,0 +1,275 @@
/* -*- 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 "nsLineBox.h"
#include "nsISpaceManager.h"
#include "prprf.h"
nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRUint16 flags)
{
mFirstChild = aFrame;
mChildCount = aCount;
mState = LINE_IS_DIRTY | LINE_NEED_DID_REFLOW | flags;
mFloaters = nsnull;
mNext = nsnull;
mBounds.SetRect(0,0,0,0);
mCombinedArea.SetRect(0,0,0,0);
mCarriedOutTopMargin = 0;
mCarriedOutBottomMargin = 0;
mBreakType = NS_STYLE_CLEAR_NONE;
}
nsLineBox::~nsLineBox()
{
if (nsnull != mFloaters) {
delete mFloaters;
}
}
static void
ListFloaters(FILE* out, PRInt32 aIndent, nsVoidArray* aFloaters)
{
PRInt32 j, i, n = aFloaters->Count();
for (i = 0; i < n; i++) {
for (j = aIndent; --j >= 0; ) fputs(" ", out);
nsPlaceholderFrame* ph = (nsPlaceholderFrame*) aFloaters->ElementAt(i);
if (nsnull != ph) {
fprintf(out, "placeholder@%p\n", ph);
nsIFrame* frame = ph->GetAnchoredItem();
if (nsnull != frame) {
frame->List(out, aIndent + 1, nsnull);
}
}
}
}
char*
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
{
PR_snprintf(aBuf, aBufSize, "%s,%s",
(mState & LINE_IS_DIRTY) ? "dirty" : "clean",
(mState & LINE_IS_BLOCK) ? "block" : "inline");
return aBuf;
}
void
nsLineBox::List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter,
PRBool aOutputMe) const
{
PRInt32 i;
if (aOutputMe) {
for (i = aIndent; --i >= 0; ) fputs(" ", out);
char cbuf[100];
fprintf(out, "line %p: count=%d state=%s ",
this, ChildCount(), StateToString(cbuf, sizeof(cbuf)));
if (0 != mCarriedOutTopMargin) {
fprintf(out, "tm=%d ", mCarriedOutTopMargin);
}
if (0 != mCarriedOutBottomMargin) {
fprintf(out, "bm=%d ", mCarriedOutBottomMargin);
}
out << mBounds;
fprintf(out, " ca=");
out << mCombinedArea;
fprintf(out, " <\n");
}
nsIFrame* frame = mFirstChild;
PRInt32 n = ChildCount();
while (--n >= 0) {
frame->List(out, aIndent + 1, aFilter);
frame->GetNextSibling(frame);
}
if (aOutputMe) {
for (i = aIndent; --i >= 0; ) fputs(" ", out);
if (nsnull != mFloaters) {
fputs("> floaters <\n", out);
ListFloaters(out, aIndent + 1, mFloaters);
for (i = aIndent; --i >= 0; ) fputs(" ", out);
}
fputs(">\n", out);
}
}
nsIFrame*
nsLineBox::LastChild() const
{
nsIFrame* frame = mFirstChild;
PRInt32 n = ChildCount() - 1;
while (--n >= 0) {
frame->GetNextSibling(frame);
}
return frame;
}
PRBool
nsLineBox::IsLastChild(nsIFrame* aFrame) const
{
nsIFrame* lastFrame = LastChild();
return aFrame == lastFrame;
}
PRBool
nsLineBox::Contains(nsIFrame* aFrame) const
{
PRInt32 n = ChildCount();
nsIFrame* frame = mFirstChild;
while (--n >= 0) {
if (frame == aFrame) {
return PR_TRUE;
}
frame->GetNextSibling(frame);
}
return PR_FALSE;
}
#if 0
static PRInt32
LengthOf(nsIFrame* aFrame)
{
PRInt32 result = 0;
while (nsnull != aFrame) {
result++;
aFrame->GetNextSibling(aFrame);
}
return result;
}
void
nsLineBox::Verify()
{
nsIFrame* lastFrame = LastChild();
if (nsnull != lastFrame) {
nsIFrame* nextInFlow;
lastFrame->GetNextInFlow(nextInFlow);
if (nsnull != mNext) {
nsIFrame* nextSibling;
lastFrame->GetNextSibling(nextSibling);
NS_ASSERTION(mNext->mFirstChild == nextSibling, "bad line list");
}
}
PRInt32 len = LengthOf(mFirstChild);
NS_ASSERTION(len >= ChildCount(), "bad mChildCount");
}
static void
VerifyLines(nsLineBox* aLine)
{
while (nsnull != aLine) {
aLine->Verify();
aLine = aLine->mNext;
}
}
static void
VerifyChildCount(nsLineBox* aLines, PRBool aEmptyOK = PR_FALSE)
{
if (nsnull != aLines) {
PRInt32 childCount = LengthOf(aLines->mFirstChild);
PRInt32 sum = 0;
nsLineBox* line = aLines;
while (nsnull != line) {
if (!aEmptyOK) {
NS_ASSERTION(0 != line->ChildCount(), "empty line left in line list");
}
sum += line->ChildCount();
line = line->mNext;
}
if (sum != childCount) {
printf("Bad sibling list/line mChildCount's\n");
nsLineBox* line = aLines;
while (nsnull != line) {
line->List(stdout, 1);
if (nsnull != line->mNext) {
nsIFrame* lastFrame = line->LastChild();
if (nsnull != lastFrame) {
nsIFrame* nextSibling;
lastFrame->GetNextSibling(nextSibling);
if (line->mNext->mFirstChild != nextSibling) {
printf(" [list broken: nextSibling=%p mNext->mFirstChild=%p]\n",
nextSibling, line->mNext->mFirstChild);
}
}
}
line = line->mNext;
}
NS_ASSERTION(sum == childCount, "bad sibling list/line mChildCount's");
}
}
}
#endif
void
nsLineBox::DeleteLineList(nsIPresContext& aPresContext, nsLineBox* aLine)
{
if (nsnull != aLine) {
// Delete our child frames before doing anything else. In particular
// we do all of this before our base class releases it's hold on the
// view.
for (nsIFrame* child = aLine->mFirstChild; child; ) {
nsIFrame* nextChild;
child->GetNextSibling(nextChild);
child->DeleteFrame(aPresContext);
child = nextChild;
}
while (nsnull != aLine) {
nsLineBox* next = aLine->mNext;
delete aLine;
aLine = next;
}
}
}
nsLineBox*
nsLineBox::LastLine(nsLineBox* aLine)
{
if (nsnull != aLine) {
while (nsnull != aLine->mNext) {
aLine = aLine->mNext;
}
}
return aLine;
}
nsLineBox*
nsLineBox::FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame)
{
while (nsnull != aLine) {
if (aLine->Contains(aFrame)) {
return aLine;
}
aLine = aLine->mNext;
}
return nsnull;
}
void
nsLineBox::UnplaceFloaters(nsISpaceManager* aSpaceManager)
{
if (nsnull != mFloaters) {
PRInt32 i, n = mFloaters->Count();
for (i = 0; i < n; i++) {
nsPlaceholderFrame* pf = (nsPlaceholderFrame*) mFloaters->ElementAt(i);
nsIFrame* floater = pf->GetAnchoredItem();
aSpaceManager->RemoveRegion(floater);
}
}
}

View File

@@ -0,0 +1,192 @@
/* -*- 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.
*/
#ifndef nsLineBox_h___
#define nsLineBox_h___
#include "nsVoidArray.h"
#include "nsPlaceholderFrame.h"
// bits in nsLineBox.mFlags
#define LINE_IS_DIRTY 0x1
#define LINE_IS_BLOCK 0x2
#define LINE_NEED_DID_REFLOW 0x8
#define LINE_TOP_MARGIN_IS_AUTO 0x10
#define LINE_BOTTOM_MARGIN_IS_AUTO 0x20
#define LINE_OUTSIDE_CHILDREN 0x40
class nsISpaceManager;
class nsLineBox;
/**
* A list of block lines
*/
class nsLineBoxList {
public:
protected:
nsLineBox* mLines;
};
/**
* The nsLineBox class represents a horizontal line of frames. It contains
* enough state to support incremental reflow of the frames, event handling
* for the frames, and rendering of the frames.
*/
class nsLineBox {
public:
nscoord GetCarriedOutTopMargin() const {
return mCarriedOutTopMargin;
}
nscoord GetCarriedOutBottomMargin() const {
return mCarriedOutBottomMargin;
}
nscoord GetCarriedOutMarginFlags() const {
return 0;/* XXX write me */
}
nscoord GetHeight() const { return mBounds.height; }
//----------------------------------------------------------------------
// XXX old junk
nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRUint16 flags);
~nsLineBox();
static void DeleteLineList(nsIPresContext& aPresContext, nsLineBox* aLine);
static nsLineBox* LastLine(nsLineBox* aLine);
static nsLineBox* FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame);
void List(FILE* out, PRInt32 aIndent, nsIListFilter *aFilter,
PRBool aOutputMe) const;
PRInt32 ChildCount() const {
return PRInt32(mChildCount);
}
nsIFrame* LastChild() const;
PRBool IsLastChild(nsIFrame* aFrame) const;
PRBool IsBlock() const {
return 0 != (LINE_IS_BLOCK & mState);
}
void SetIsBlock() {
mState |= LINE_IS_BLOCK;
}
void ClearIsBlock() {
mState &= ~LINE_IS_BLOCK;
}
void SetIsBlock(PRBool aValue) {
if (aValue) {
SetIsBlock();
}
else {
ClearIsBlock();
}
}
void MarkDirty() {
mState |= LINE_IS_DIRTY;
}
void ClearDirty() {
mState &= ~LINE_IS_DIRTY;
}
void SetNeedDidReflow() {
mState |= LINE_NEED_DID_REFLOW;
}
void ClearNeedDidReflow() {
mState &= ~LINE_NEED_DID_REFLOW;
}
PRBool NeedsDidReflow() {
return 0 != (LINE_NEED_DID_REFLOW & mState);
}
PRBool IsDirty() const {
return 0 != (LINE_IS_DIRTY & mState);
}
void SetOutsideChildren() {
mState |= LINE_OUTSIDE_CHILDREN;
}
void ClearOutsideChildren() {
mState &= ~LINE_OUTSIDE_CHILDREN;
}
PRBool OutsideChildren() const {
return 0 != (LINE_OUTSIDE_CHILDREN & mState);
}
PRUint16 GetState() const { return mState; }
char* StateToString(char* aBuf, PRInt32 aBufSize) const;
PRBool Contains(nsIFrame* aFrame) const;
// XXX ick
void SetMarginFlags(PRUintn aFlags) {
mState &= ~(LINE_TOP_MARGIN_IS_AUTO|LINE_BOTTOM_MARGIN_IS_AUTO);
if (NS_CARRIED_TOP_MARGIN_IS_AUTO & aFlags) {
mState |= LINE_TOP_MARGIN_IS_AUTO;
}
if (NS_CARRIED_BOTTOM_MARGIN_IS_AUTO & aFlags) {
mState |= LINE_BOTTOM_MARGIN_IS_AUTO;
}
}
PRUintn GetMarginFlags() {
return ((LINE_TOP_MARGIN_IS_AUTO & mState)
? NS_CARRIED_TOP_MARGIN_IS_AUTO : 0) |
((LINE_BOTTOM_MARGIN_IS_AUTO & mState) ?
NS_CARRIED_BOTTOM_MARGIN_IS_AUTO : 0);
}
void UnplaceFloaters(nsISpaceManager* aSpaceManager);
#ifdef NS_DEBUG
void Verify();
#endif
//XXX protected:
nsIFrame* mFirstChild;
PRUint16 mChildCount;
PRUint16 mState;
PRUint8 mBreakType;
nsRect mBounds;
nsRect mCombinedArea;
nscoord mCarriedOutTopMargin;/* XXX switch to 16 bits */
nscoord mCarriedOutBottomMargin;/* XXX switch to 16 bits */
nsVoidArray* mFloaters;
nsLineBox* mNext;
protected:
};
#endif /* nsLineBox_h___ */