diff --git a/mozilla/layout/generic/nsBlockReflowContext.cpp b/mozilla/layout/generic/nsBlockReflowContext.cpp
new file mode 100644
index 00000000000..e0c15a823e6
--- /dev/null
+++ b/mozilla/layout/generic/nsBlockReflowContext.cpp
@@ -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 inside 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 inside 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;
+}
diff --git a/mozilla/layout/generic/nsBlockReflowContext.h b/mozilla/layout/generic/nsBlockReflowContext.h
new file mode 100644
index 00000000000..58ddd2279d9
--- /dev/null
+++ b/mozilla/layout/generic/nsBlockReflowContext.h
@@ -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___ */
diff --git a/mozilla/layout/generic/nsBulletFrame.cpp b/mozilla/layout/generic/nsBulletFrame.cpp
new file mode 100644
index 00000000000..e7455208697
--- /dev/null
+++ b/mozilla/layout/generic/nsBulletFrame.cpp
@@ -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;
+}
diff --git a/mozilla/layout/generic/nsBulletFrame.h b/mozilla/layout/generic/nsBulletFrame.h
new file mode 100644
index 00000000000..37b8930918e
--- /dev/null
+++ b/mozilla/layout/generic/nsBulletFrame.h
@@ -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___ */
diff --git a/mozilla/layout/generic/nsLineBox.cpp b/mozilla/layout/generic/nsLineBox.cpp
new file mode 100644
index 00000000000..617a9585b2f
--- /dev/null
+++ b/mozilla/layout/generic/nsLineBox.cpp
@@ -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);
+ }
+ }
+}
diff --git a/mozilla/layout/generic/nsLineBox.h b/mozilla/layout/generic/nsLineBox.h
new file mode 100644
index 00000000000..a39dbc065dc
--- /dev/null
+++ b/mozilla/layout/generic/nsLineBox.h
@@ -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___ */
diff --git a/mozilla/layout/html/base/src/nsBlockReflowContext.cpp b/mozilla/layout/html/base/src/nsBlockReflowContext.cpp
new file mode 100644
index 00000000000..e0c15a823e6
--- /dev/null
+++ b/mozilla/layout/html/base/src/nsBlockReflowContext.cpp
@@ -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 inside 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 inside 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;
+}
diff --git a/mozilla/layout/html/base/src/nsBlockReflowContext.h b/mozilla/layout/html/base/src/nsBlockReflowContext.h
new file mode 100644
index 00000000000..58ddd2279d9
--- /dev/null
+++ b/mozilla/layout/html/base/src/nsBlockReflowContext.h
@@ -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___ */
diff --git a/mozilla/layout/html/base/src/nsBulletFrame.cpp b/mozilla/layout/html/base/src/nsBulletFrame.cpp
new file mode 100644
index 00000000000..e7455208697
--- /dev/null
+++ b/mozilla/layout/html/base/src/nsBulletFrame.cpp
@@ -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;
+}
diff --git a/mozilla/layout/html/base/src/nsBulletFrame.h b/mozilla/layout/html/base/src/nsBulletFrame.h
new file mode 100644
index 00000000000..37b8930918e
--- /dev/null
+++ b/mozilla/layout/html/base/src/nsBulletFrame.h
@@ -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___ */
diff --git a/mozilla/layout/html/base/src/nsLineBox.cpp b/mozilla/layout/html/base/src/nsLineBox.cpp
new file mode 100644
index 00000000000..617a9585b2f
--- /dev/null
+++ b/mozilla/layout/html/base/src/nsLineBox.cpp
@@ -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);
+ }
+ }
+}
diff --git a/mozilla/layout/html/base/src/nsLineBox.h b/mozilla/layout/html/base/src/nsLineBox.h
new file mode 100644
index 00000000000..a39dbc065dc
--- /dev/null
+++ b/mozilla/layout/html/base/src/nsLineBox.h
@@ -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___ */