зеркало из https://github.com/mozilla/pjs.git
Implement bullets here; implement list renumbering cleanly instead of having the bullets blindly do it (fixes a crash and several pagination bugs)
This commit is contained in:
Родитель
448fdd65d1
Коммит
09c2bd18a7
|
@ -16,7 +16,8 @@
|
|||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsFrameReflowState.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsInlineReflow.h"
|
||||
#include "nsCSSLayout.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIRunaround.h"
|
||||
#include "nsISpaceManager.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsHTMLValue.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
|
||||
//#include "js/jsapi.h"
|
||||
//#include "nsDOMEvent.h"
|
||||
|
@ -46,6 +47,17 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
// XXX These are unfortunate dependencies
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsHTMLImage.h"
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
// 09-15-98: make sure that the outer container of the block (e.g. the
|
||||
// body sets up the outer top margin feed in properly so that the top
|
||||
// margin collapses properly with the body margin. Note that for the
|
||||
|
@ -101,7 +113,110 @@
|
|||
// XXX I don't want mFirstChild, mChildCount, mOverflowList,
|
||||
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class BulletFrame;
|
||||
struct LineData;
|
||||
class nsBlockFrame;
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
// XXX hide this as soon as list bullet code is cleaned up
|
||||
|
||||
struct nsBlockReflowState : public nsFrameReflowState {
|
||||
nsBlockReflowState(nsIPresContext& aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
const nsReflowMetrics& aMetrics,
|
||||
nsISpaceManager* aSpaceManager);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Update the mCurrentBand data based on the current mY position.
|
||||
*/
|
||||
void GetAvailableSpace();
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void PlaceFloater(nsPlaceholderFrame* aFloater);
|
||||
|
||||
void PlaceFloaters(nsVoidArray* aFloaters);
|
||||
|
||||
void ClearFloaters(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsLeftMostChild(nsIFrame* aFrame);
|
||||
|
||||
nsLineLayout mLineLayout;
|
||||
nsInlineReflow* mInlineReflow;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
nsBlockFrame* mBlock;
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
PRBool mInlineReflowPrepared;
|
||||
|
||||
PRUint8 mTextAlign;
|
||||
|
||||
nsSize mStyleSize;
|
||||
|
||||
PRIntn mStyleSizeFlags;
|
||||
|
||||
nscoord mBottomEdge; // maximum Y
|
||||
|
||||
nscoord mBulletPadding;// XXX Get rid of these
|
||||
nscoord mLeftPadding;// XXX Get rid of these
|
||||
|
||||
PRBool mUnconstrainedWidth;
|
||||
PRBool mUnconstrainedHeight;
|
||||
nscoord mY;
|
||||
nscoord mKidXMost;
|
||||
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
LineData* mFreeList;
|
||||
|
||||
nsVoidArray mPendingFloaters;
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
LineData* mCurrentLine;
|
||||
LineData* mPrevLine;
|
||||
|
||||
// The next list ordinal for counting list bullets
|
||||
PRInt32 mNextListOrdinal;
|
||||
|
||||
// XXX what happens if we need more than 12 trapezoids?
|
||||
struct BlockBandData : public nsBandData {
|
||||
// Trapezoids used during band processing
|
||||
nsBandTrapezoid data[12];
|
||||
|
||||
// Bounding rect of available space between any left and right floaters
|
||||
nsRect availSpace;
|
||||
|
||||
BlockBandData() {
|
||||
size = 12;
|
||||
trapezoids = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding rect of the available space, i.e. space
|
||||
* between any left and right floaters Uses the current trapezoid
|
||||
* data, see nsISpaceManager::GetBandData(). Also updates member
|
||||
* data "availSpace".
|
||||
*/
|
||||
void ComputeAvailSpaceRect();
|
||||
};
|
||||
|
||||
BlockBandData mCurrentBand;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockReflowState->AddFloater(aFrame);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
|
@ -183,8 +298,6 @@ public:
|
|||
|
||||
PRBool RemoveChild(LineData* aLines, nsIFrame* aChild);
|
||||
|
||||
nsresult ProcessInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
PRIntn GetSkipSides() const;
|
||||
|
||||
PRBool IsPseudoFrame() const;
|
||||
|
@ -262,6 +375,8 @@ public:
|
|||
|
||||
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
||||
|
||||
void RenumberLists(nsBlockReflowState& aState);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
#endif
|
||||
|
@ -274,11 +389,512 @@ public:
|
|||
nsTextRun* mTextRuns;
|
||||
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsIFrame* mBullet;
|
||||
BulletFrame* mBullet;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A helper content class for bullets. The content class is needed
|
||||
* primarily so that we can resolve style and force the display mode
|
||||
* for the bullet to be inline
|
||||
*/
|
||||
static void
|
||||
MapAttributesInto(nsIHTMLAttributes* aAttributes,
|
||||
nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext)
|
||||
{
|
||||
nsStyleDisplay* display = (nsStyleDisplay*)
|
||||
aContext->GetMutableStyleData(eStyleStruct_Display);
|
||||
display->mDisplay = NS_STYLE_DISPLAY_INLINE;
|
||||
}
|
||||
|
||||
class Bullet : public nsHTMLTagContent {
|
||||
public:
|
||||
Bullet() {
|
||||
mRefCnt = 1;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsSynthetic(PRBool& aResult)
|
||||
{
|
||||
aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const
|
||||
{
|
||||
aMapFunc = &MapAttributesInto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
fprintf(out, "Bullet RefCnt=%d<>\n", mRefCnt);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class BulletFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
virtual ~BulletFrame();
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD Paint(nsIPresContext &aCX,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD ListTag(FILE* out) const;
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
void SetListItemOrdinal(nsBlockReflowState& aBlockState);
|
||||
|
||||
void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aMetrics);
|
||||
|
||||
void GetListItemText(nsIPresContext& aCX,
|
||||
const nsStyleList& aMol,
|
||||
nsString& aResult);
|
||||
|
||||
PRInt32 mOrdinal;
|
||||
nsMargin mPadding;
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
};
|
||||
|
||||
BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BulletFrame::~BulletFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
return nsFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::ListTag(FILE* out) const
|
||||
{
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p", contentIndex, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p ",
|
||||
contentIndex, 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
|
||||
BulletFrame::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(myFont->mFont);
|
||||
fm->GetWidth(text, width);
|
||||
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
|
||||
NS_RELEASE(fm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BulletFrame::SetListItemOrdinal(nsBlockReflowState& aReflowState)
|
||||
{
|
||||
// Assume that the ordinal comes from the block reflow state
|
||||
mOrdinal = aReflowState.mNextListOrdinal;
|
||||
|
||||
// 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);
|
||||
|
||||
aReflowState.mNextListOrdinal = 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
|
||||
BulletFrame::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 (0 == ordinal) {
|
||||
ordinal = 1;
|
||||
}
|
||||
nsAutoString addOn;
|
||||
nsAutoString decStr;
|
||||
decStr.Append(ordinal, 10);
|
||||
const PRUnichar* dp = decStr.GetUnicode();
|
||||
const PRUnichar* end = dp + decStr.Length();
|
||||
|
||||
PRIntn len=decStr.Length();
|
||||
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;
|
||||
}
|
||||
ordinal=(ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
|
||||
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...
|
||||
ordinal = (ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
while (next<=ordinal) // scale up in baseN; exceed current value.
|
||||
{
|
||||
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
|
||||
|
||||
void
|
||||
BulletFrame::GetDesiredSize(nsIPresContext* aCX,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& 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, 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;
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
mPadding.right = bulletSize / 2;
|
||||
}
|
||||
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);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
// Inside bullets need some extra width to get the padding
|
||||
// between the list item and the content that follows.
|
||||
mPadding.right = aMetrics.height / 2; // From old layout engine
|
||||
}
|
||||
|
||||
fm->GetWidth(text, aMetrics.width);
|
||||
aMetrics.width += mPadding.right;
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
// Get the base size
|
||||
GetDesiredSize(&aLineLayout.mPresContext, 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;
|
||||
space->CalcBorderPaddingFor(this, 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;
|
||||
}
|
||||
return NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define LINE_IS_DIRTY 0x1
|
||||
#define LINE_IS_BLOCK 0x2
|
||||
#define LINE_LAST_CONTENT_IS_COMPLETE 0x4
|
||||
|
@ -805,29 +1421,6 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext,
|
|||
mPrevChild = nsnull;
|
||||
mFreeList = nsnull;
|
||||
mPrevLine = nsnull;
|
||||
|
||||
// Setup initial list ordinal value
|
||||
|
||||
// XXX translate the starting value to a css style type and stop
|
||||
// doing this!
|
||||
mNextListOrdinal = -1;
|
||||
nsIContent* blockContent;
|
||||
mBlock->GetContent(blockContent);
|
||||
nsIAtom* tag;
|
||||
blockContent->GetTag(tag);
|
||||
if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
|
||||
(tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
((nsIHTMLContent*)blockContent)->GetAttribute(nsHTMLAtoms::start,
|
||||
value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
mNextListOrdinal = value.GetIntValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(blockContent);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -914,7 +1507,6 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
// XXX temporary
|
||||
if (aIID.Equals(kBlockFrameCID)) {
|
||||
*aInstancePtr = (void*) (this);
|
||||
return NS_OK;
|
||||
|
@ -933,7 +1525,51 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_IMETHODIMP
|
||||
nsBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
||||
{
|
||||
return AppendNewFrames(aPresContext, aChildList);
|
||||
nsresult rv = AppendNewFrames(aPresContext, aChildList);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create list bullet if this is a list-item. Note that this is done
|
||||
// here so that RenumberLists will work (it needs the bullets to
|
||||
// store the bullet numbers).
|
||||
const nsStyleDisplay* styleDisplay;
|
||||
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
Bullet* bullet;
|
||||
NS_NEWXPCOM(bullet, Bullet);
|
||||
if (nsnull == bullet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
mBullet = new BulletFrame(bullet, this);
|
||||
if (nsnull == mBullet) {
|
||||
NS_RELEASE(bullet);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1105,12 +1741,12 @@ nsBlockFrame::FirstChild(nsIFrame*& aFirstChild) const
|
|||
// Reflow methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d",
|
||||
|
@ -1138,6 +1774,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
if (eReflowReason_Initial == state.reason) {
|
||||
RenumberLists(state);
|
||||
if (!DrainOverflowLines()) {
|
||||
rv = InitialReflow(state);
|
||||
}
|
||||
|
@ -1155,6 +1792,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
nsIFrame* target;
|
||||
state.reflowCommand->GetTarget(target);
|
||||
if (this == target) {
|
||||
RenumberLists(state);
|
||||
nsIReflowCommand::ReflowType type;
|
||||
state.reflowCommand->GetType(type);
|
||||
switch (type) {
|
||||
|
@ -1203,47 +1841,59 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ProcessInitialReflow(nsBlockReflowState& aState)
|
||||
void
|
||||
nsBlockFrame::RenumberLists(nsBlockReflowState& aState)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create list bullet on the first reflow
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == aState.mStyleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
nsIHTMLContent* bullet;
|
||||
nsresult rv = NS_NewHTMLBullet(&bullet);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
rv = NS_NewBulletFrame(bullet, this, mBullet);
|
||||
if (NS_OK != rv) {
|
||||
NS_RELEASE(bullet);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aState.mPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aState.mPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
// Setup initial list ordinal value
|
||||
PRInt32 ordinal = 1;
|
||||
nsIHTMLContent* hc;
|
||||
if (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::start, value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
ordinal = value.GetIntValue();
|
||||
if (ordinal <= 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
aState.mNextListOrdinal = ordinal;
|
||||
|
||||
// Get to first-in-flow
|
||||
nsBlockFrame* block = this;
|
||||
while (nsnull != block->mPrevInFlow) {
|
||||
block = (nsBlockFrame*) block->mPrevInFlow;
|
||||
}
|
||||
|
||||
// For each flow-block...
|
||||
while (nsnull != block) {
|
||||
// For each frame in the flow-block...
|
||||
nsIFrame* frame = block->mLines ? block->mLines->mFirstChild : nsnull;
|
||||
while (nsnull != frame) {
|
||||
// If the frame is a list-item and the frame implements our
|
||||
// block frame API then get it's bullet and set the list item
|
||||
// ordinal.
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
||||
// Make certain that the frame isa block-frame in case
|
||||
// something foriegn has crept in.
|
||||
nsBlockFrame* listItem;
|
||||
if (NS_OK == frame->QueryInterface(kBlockFrameCID,
|
||||
(void**) &listItem)) {
|
||||
if (nsnull != listItem->mBullet) {
|
||||
listItem->mBullet->SetListItemOrdinal(aState);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->GetNextSibling(frame);
|
||||
}
|
||||
block = (nsBlockFrame*) block->mNextInFlow;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1567,14 +2217,8 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|||
nsresult
|
||||
nsBlockFrame::InitialReflow(nsBlockReflowState& aState)
|
||||
{
|
||||
// Create synthetic content
|
||||
nsresult rv = ProcessInitialReflow(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generate text-run information
|
||||
rv = FindTextRuns(aState);
|
||||
nsresult rv = FindTextRuns(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsFrameReflowState.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsInlineReflow.h"
|
||||
#include "nsCSSLayout.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIRunaround.h"
|
||||
#include "nsISpaceManager.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsHTMLValue.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
|
||||
//#include "js/jsapi.h"
|
||||
//#include "nsDOMEvent.h"
|
||||
|
@ -46,6 +47,17 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
// XXX These are unfortunate dependencies
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsHTMLImage.h"
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
// 09-15-98: make sure that the outer container of the block (e.g. the
|
||||
// body sets up the outer top margin feed in properly so that the top
|
||||
// margin collapses properly with the body margin. Note that for the
|
||||
|
@ -101,7 +113,110 @@
|
|||
// XXX I don't want mFirstChild, mChildCount, mOverflowList,
|
||||
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class BulletFrame;
|
||||
struct LineData;
|
||||
class nsBlockFrame;
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
// XXX hide this as soon as list bullet code is cleaned up
|
||||
|
||||
struct nsBlockReflowState : public nsFrameReflowState {
|
||||
nsBlockReflowState(nsIPresContext& aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
const nsReflowMetrics& aMetrics,
|
||||
nsISpaceManager* aSpaceManager);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Update the mCurrentBand data based on the current mY position.
|
||||
*/
|
||||
void GetAvailableSpace();
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void PlaceFloater(nsPlaceholderFrame* aFloater);
|
||||
|
||||
void PlaceFloaters(nsVoidArray* aFloaters);
|
||||
|
||||
void ClearFloaters(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsLeftMostChild(nsIFrame* aFrame);
|
||||
|
||||
nsLineLayout mLineLayout;
|
||||
nsInlineReflow* mInlineReflow;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
nsBlockFrame* mBlock;
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
PRBool mInlineReflowPrepared;
|
||||
|
||||
PRUint8 mTextAlign;
|
||||
|
||||
nsSize mStyleSize;
|
||||
|
||||
PRIntn mStyleSizeFlags;
|
||||
|
||||
nscoord mBottomEdge; // maximum Y
|
||||
|
||||
nscoord mBulletPadding;// XXX Get rid of these
|
||||
nscoord mLeftPadding;// XXX Get rid of these
|
||||
|
||||
PRBool mUnconstrainedWidth;
|
||||
PRBool mUnconstrainedHeight;
|
||||
nscoord mY;
|
||||
nscoord mKidXMost;
|
||||
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
LineData* mFreeList;
|
||||
|
||||
nsVoidArray mPendingFloaters;
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
LineData* mCurrentLine;
|
||||
LineData* mPrevLine;
|
||||
|
||||
// The next list ordinal for counting list bullets
|
||||
PRInt32 mNextListOrdinal;
|
||||
|
||||
// XXX what happens if we need more than 12 trapezoids?
|
||||
struct BlockBandData : public nsBandData {
|
||||
// Trapezoids used during band processing
|
||||
nsBandTrapezoid data[12];
|
||||
|
||||
// Bounding rect of available space between any left and right floaters
|
||||
nsRect availSpace;
|
||||
|
||||
BlockBandData() {
|
||||
size = 12;
|
||||
trapezoids = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding rect of the available space, i.e. space
|
||||
* between any left and right floaters Uses the current trapezoid
|
||||
* data, see nsISpaceManager::GetBandData(). Also updates member
|
||||
* data "availSpace".
|
||||
*/
|
||||
void ComputeAvailSpaceRect();
|
||||
};
|
||||
|
||||
BlockBandData mCurrentBand;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockReflowState->AddFloater(aFrame);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
|
@ -183,8 +298,6 @@ public:
|
|||
|
||||
PRBool RemoveChild(LineData* aLines, nsIFrame* aChild);
|
||||
|
||||
nsresult ProcessInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
PRIntn GetSkipSides() const;
|
||||
|
||||
PRBool IsPseudoFrame() const;
|
||||
|
@ -262,6 +375,8 @@ public:
|
|||
|
||||
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
||||
|
||||
void RenumberLists(nsBlockReflowState& aState);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
#endif
|
||||
|
@ -274,11 +389,512 @@ public:
|
|||
nsTextRun* mTextRuns;
|
||||
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsIFrame* mBullet;
|
||||
BulletFrame* mBullet;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A helper content class for bullets. The content class is needed
|
||||
* primarily so that we can resolve style and force the display mode
|
||||
* for the bullet to be inline
|
||||
*/
|
||||
static void
|
||||
MapAttributesInto(nsIHTMLAttributes* aAttributes,
|
||||
nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext)
|
||||
{
|
||||
nsStyleDisplay* display = (nsStyleDisplay*)
|
||||
aContext->GetMutableStyleData(eStyleStruct_Display);
|
||||
display->mDisplay = NS_STYLE_DISPLAY_INLINE;
|
||||
}
|
||||
|
||||
class Bullet : public nsHTMLTagContent {
|
||||
public:
|
||||
Bullet() {
|
||||
mRefCnt = 1;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsSynthetic(PRBool& aResult)
|
||||
{
|
||||
aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const
|
||||
{
|
||||
aMapFunc = &MapAttributesInto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
fprintf(out, "Bullet RefCnt=%d<>\n", mRefCnt);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class BulletFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
virtual ~BulletFrame();
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD Paint(nsIPresContext &aCX,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD ListTag(FILE* out) const;
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
void SetListItemOrdinal(nsBlockReflowState& aBlockState);
|
||||
|
||||
void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aMetrics);
|
||||
|
||||
void GetListItemText(nsIPresContext& aCX,
|
||||
const nsStyleList& aMol,
|
||||
nsString& aResult);
|
||||
|
||||
PRInt32 mOrdinal;
|
||||
nsMargin mPadding;
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
};
|
||||
|
||||
BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BulletFrame::~BulletFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
return nsFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::ListTag(FILE* out) const
|
||||
{
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p", contentIndex, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p ",
|
||||
contentIndex, 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
|
||||
BulletFrame::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(myFont->mFont);
|
||||
fm->GetWidth(text, width);
|
||||
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
|
||||
NS_RELEASE(fm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BulletFrame::SetListItemOrdinal(nsBlockReflowState& aReflowState)
|
||||
{
|
||||
// Assume that the ordinal comes from the block reflow state
|
||||
mOrdinal = aReflowState.mNextListOrdinal;
|
||||
|
||||
// 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);
|
||||
|
||||
aReflowState.mNextListOrdinal = 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
|
||||
BulletFrame::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 (0 == ordinal) {
|
||||
ordinal = 1;
|
||||
}
|
||||
nsAutoString addOn;
|
||||
nsAutoString decStr;
|
||||
decStr.Append(ordinal, 10);
|
||||
const PRUnichar* dp = decStr.GetUnicode();
|
||||
const PRUnichar* end = dp + decStr.Length();
|
||||
|
||||
PRIntn len=decStr.Length();
|
||||
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;
|
||||
}
|
||||
ordinal=(ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
|
||||
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...
|
||||
ordinal = (ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
while (next<=ordinal) // scale up in baseN; exceed current value.
|
||||
{
|
||||
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
|
||||
|
||||
void
|
||||
BulletFrame::GetDesiredSize(nsIPresContext* aCX,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& 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, 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;
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
mPadding.right = bulletSize / 2;
|
||||
}
|
||||
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);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
// Inside bullets need some extra width to get the padding
|
||||
// between the list item and the content that follows.
|
||||
mPadding.right = aMetrics.height / 2; // From old layout engine
|
||||
}
|
||||
|
||||
fm->GetWidth(text, aMetrics.width);
|
||||
aMetrics.width += mPadding.right;
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
// Get the base size
|
||||
GetDesiredSize(&aLineLayout.mPresContext, 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;
|
||||
space->CalcBorderPaddingFor(this, 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;
|
||||
}
|
||||
return NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define LINE_IS_DIRTY 0x1
|
||||
#define LINE_IS_BLOCK 0x2
|
||||
#define LINE_LAST_CONTENT_IS_COMPLETE 0x4
|
||||
|
@ -805,29 +1421,6 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext,
|
|||
mPrevChild = nsnull;
|
||||
mFreeList = nsnull;
|
||||
mPrevLine = nsnull;
|
||||
|
||||
// Setup initial list ordinal value
|
||||
|
||||
// XXX translate the starting value to a css style type and stop
|
||||
// doing this!
|
||||
mNextListOrdinal = -1;
|
||||
nsIContent* blockContent;
|
||||
mBlock->GetContent(blockContent);
|
||||
nsIAtom* tag;
|
||||
blockContent->GetTag(tag);
|
||||
if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
|
||||
(tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
((nsIHTMLContent*)blockContent)->GetAttribute(nsHTMLAtoms::start,
|
||||
value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
mNextListOrdinal = value.GetIntValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(blockContent);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -914,7 +1507,6 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
// XXX temporary
|
||||
if (aIID.Equals(kBlockFrameCID)) {
|
||||
*aInstancePtr = (void*) (this);
|
||||
return NS_OK;
|
||||
|
@ -933,7 +1525,51 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_IMETHODIMP
|
||||
nsBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
||||
{
|
||||
return AppendNewFrames(aPresContext, aChildList);
|
||||
nsresult rv = AppendNewFrames(aPresContext, aChildList);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create list bullet if this is a list-item. Note that this is done
|
||||
// here so that RenumberLists will work (it needs the bullets to
|
||||
// store the bullet numbers).
|
||||
const nsStyleDisplay* styleDisplay;
|
||||
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
Bullet* bullet;
|
||||
NS_NEWXPCOM(bullet, Bullet);
|
||||
if (nsnull == bullet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
mBullet = new BulletFrame(bullet, this);
|
||||
if (nsnull == mBullet) {
|
||||
NS_RELEASE(bullet);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1105,12 +1741,12 @@ nsBlockFrame::FirstChild(nsIFrame*& aFirstChild) const
|
|||
// Reflow methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d",
|
||||
|
@ -1138,6 +1774,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
if (eReflowReason_Initial == state.reason) {
|
||||
RenumberLists(state);
|
||||
if (!DrainOverflowLines()) {
|
||||
rv = InitialReflow(state);
|
||||
}
|
||||
|
@ -1155,6 +1792,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
nsIFrame* target;
|
||||
state.reflowCommand->GetTarget(target);
|
||||
if (this == target) {
|
||||
RenumberLists(state);
|
||||
nsIReflowCommand::ReflowType type;
|
||||
state.reflowCommand->GetType(type);
|
||||
switch (type) {
|
||||
|
@ -1203,47 +1841,59 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ProcessInitialReflow(nsBlockReflowState& aState)
|
||||
void
|
||||
nsBlockFrame::RenumberLists(nsBlockReflowState& aState)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create list bullet on the first reflow
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == aState.mStyleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
nsIHTMLContent* bullet;
|
||||
nsresult rv = NS_NewHTMLBullet(&bullet);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
rv = NS_NewBulletFrame(bullet, this, mBullet);
|
||||
if (NS_OK != rv) {
|
||||
NS_RELEASE(bullet);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aState.mPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aState.mPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
// Setup initial list ordinal value
|
||||
PRInt32 ordinal = 1;
|
||||
nsIHTMLContent* hc;
|
||||
if (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::start, value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
ordinal = value.GetIntValue();
|
||||
if (ordinal <= 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
aState.mNextListOrdinal = ordinal;
|
||||
|
||||
// Get to first-in-flow
|
||||
nsBlockFrame* block = this;
|
||||
while (nsnull != block->mPrevInFlow) {
|
||||
block = (nsBlockFrame*) block->mPrevInFlow;
|
||||
}
|
||||
|
||||
// For each flow-block...
|
||||
while (nsnull != block) {
|
||||
// For each frame in the flow-block...
|
||||
nsIFrame* frame = block->mLines ? block->mLines->mFirstChild : nsnull;
|
||||
while (nsnull != frame) {
|
||||
// If the frame is a list-item and the frame implements our
|
||||
// block frame API then get it's bullet and set the list item
|
||||
// ordinal.
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
||||
// Make certain that the frame isa block-frame in case
|
||||
// something foriegn has crept in.
|
||||
nsBlockFrame* listItem;
|
||||
if (NS_OK == frame->QueryInterface(kBlockFrameCID,
|
||||
(void**) &listItem)) {
|
||||
if (nsnull != listItem->mBullet) {
|
||||
listItem->mBullet->SetListItemOrdinal(aState);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->GetNextSibling(frame);
|
||||
}
|
||||
block = (nsBlockFrame*) block->mNextInFlow;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1567,14 +2217,8 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|||
nsresult
|
||||
nsBlockFrame::InitialReflow(nsBlockReflowState& aState)
|
||||
{
|
||||
// Create synthetic content
|
||||
nsresult rv = ProcessInitialReflow(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generate text-run information
|
||||
rv = FindTextRuns(aState);
|
||||
nsresult rv = FindTextRuns(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsFrameReflowState.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsInlineReflow.h"
|
||||
#include "nsCSSLayout.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIRunaround.h"
|
||||
#include "nsISpaceManager.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsHTMLValue.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
|
||||
//#include "js/jsapi.h"
|
||||
//#include "nsDOMEvent.h"
|
||||
|
@ -46,6 +47,17 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
// XXX These are unfortunate dependencies
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsHTMLImage.h"
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
// 09-15-98: make sure that the outer container of the block (e.g. the
|
||||
// body sets up the outer top margin feed in properly so that the top
|
||||
// margin collapses properly with the body margin. Note that for the
|
||||
|
@ -101,7 +113,110 @@
|
|||
// XXX I don't want mFirstChild, mChildCount, mOverflowList,
|
||||
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class BulletFrame;
|
||||
struct LineData;
|
||||
class nsBlockFrame;
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
// XXX hide this as soon as list bullet code is cleaned up
|
||||
|
||||
struct nsBlockReflowState : public nsFrameReflowState {
|
||||
nsBlockReflowState(nsIPresContext& aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
const nsReflowMetrics& aMetrics,
|
||||
nsISpaceManager* aSpaceManager);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Update the mCurrentBand data based on the current mY position.
|
||||
*/
|
||||
void GetAvailableSpace();
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void PlaceFloater(nsPlaceholderFrame* aFloater);
|
||||
|
||||
void PlaceFloaters(nsVoidArray* aFloaters);
|
||||
|
||||
void ClearFloaters(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsLeftMostChild(nsIFrame* aFrame);
|
||||
|
||||
nsLineLayout mLineLayout;
|
||||
nsInlineReflow* mInlineReflow;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
nsBlockFrame* mBlock;
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
PRBool mInlineReflowPrepared;
|
||||
|
||||
PRUint8 mTextAlign;
|
||||
|
||||
nsSize mStyleSize;
|
||||
|
||||
PRIntn mStyleSizeFlags;
|
||||
|
||||
nscoord mBottomEdge; // maximum Y
|
||||
|
||||
nscoord mBulletPadding;// XXX Get rid of these
|
||||
nscoord mLeftPadding;// XXX Get rid of these
|
||||
|
||||
PRBool mUnconstrainedWidth;
|
||||
PRBool mUnconstrainedHeight;
|
||||
nscoord mY;
|
||||
nscoord mKidXMost;
|
||||
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
LineData* mFreeList;
|
||||
|
||||
nsVoidArray mPendingFloaters;
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
LineData* mCurrentLine;
|
||||
LineData* mPrevLine;
|
||||
|
||||
// The next list ordinal for counting list bullets
|
||||
PRInt32 mNextListOrdinal;
|
||||
|
||||
// XXX what happens if we need more than 12 trapezoids?
|
||||
struct BlockBandData : public nsBandData {
|
||||
// Trapezoids used during band processing
|
||||
nsBandTrapezoid data[12];
|
||||
|
||||
// Bounding rect of available space between any left and right floaters
|
||||
nsRect availSpace;
|
||||
|
||||
BlockBandData() {
|
||||
size = 12;
|
||||
trapezoids = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding rect of the available space, i.e. space
|
||||
* between any left and right floaters Uses the current trapezoid
|
||||
* data, see nsISpaceManager::GetBandData(). Also updates member
|
||||
* data "availSpace".
|
||||
*/
|
||||
void ComputeAvailSpaceRect();
|
||||
};
|
||||
|
||||
BlockBandData mCurrentBand;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockReflowState->AddFloater(aFrame);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
|
@ -183,8 +298,6 @@ public:
|
|||
|
||||
PRBool RemoveChild(LineData* aLines, nsIFrame* aChild);
|
||||
|
||||
nsresult ProcessInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
PRIntn GetSkipSides() const;
|
||||
|
||||
PRBool IsPseudoFrame() const;
|
||||
|
@ -262,6 +375,8 @@ public:
|
|||
|
||||
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
||||
|
||||
void RenumberLists(nsBlockReflowState& aState);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
#endif
|
||||
|
@ -274,11 +389,512 @@ public:
|
|||
nsTextRun* mTextRuns;
|
||||
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsIFrame* mBullet;
|
||||
BulletFrame* mBullet;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A helper content class for bullets. The content class is needed
|
||||
* primarily so that we can resolve style and force the display mode
|
||||
* for the bullet to be inline
|
||||
*/
|
||||
static void
|
||||
MapAttributesInto(nsIHTMLAttributes* aAttributes,
|
||||
nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext)
|
||||
{
|
||||
nsStyleDisplay* display = (nsStyleDisplay*)
|
||||
aContext->GetMutableStyleData(eStyleStruct_Display);
|
||||
display->mDisplay = NS_STYLE_DISPLAY_INLINE;
|
||||
}
|
||||
|
||||
class Bullet : public nsHTMLTagContent {
|
||||
public:
|
||||
Bullet() {
|
||||
mRefCnt = 1;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsSynthetic(PRBool& aResult)
|
||||
{
|
||||
aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const
|
||||
{
|
||||
aMapFunc = &MapAttributesInto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
fprintf(out, "Bullet RefCnt=%d<>\n", mRefCnt);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class BulletFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
virtual ~BulletFrame();
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD Paint(nsIPresContext &aCX,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD ListTag(FILE* out) const;
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
void SetListItemOrdinal(nsBlockReflowState& aBlockState);
|
||||
|
||||
void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aMetrics);
|
||||
|
||||
void GetListItemText(nsIPresContext& aCX,
|
||||
const nsStyleList& aMol,
|
||||
nsString& aResult);
|
||||
|
||||
PRInt32 mOrdinal;
|
||||
nsMargin mPadding;
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
};
|
||||
|
||||
BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BulletFrame::~BulletFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
return nsFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::ListTag(FILE* out) const
|
||||
{
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p", contentIndex, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p ",
|
||||
contentIndex, 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
|
||||
BulletFrame::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(myFont->mFont);
|
||||
fm->GetWidth(text, width);
|
||||
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
|
||||
NS_RELEASE(fm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BulletFrame::SetListItemOrdinal(nsBlockReflowState& aReflowState)
|
||||
{
|
||||
// Assume that the ordinal comes from the block reflow state
|
||||
mOrdinal = aReflowState.mNextListOrdinal;
|
||||
|
||||
// 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);
|
||||
|
||||
aReflowState.mNextListOrdinal = 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
|
||||
BulletFrame::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 (0 == ordinal) {
|
||||
ordinal = 1;
|
||||
}
|
||||
nsAutoString addOn;
|
||||
nsAutoString decStr;
|
||||
decStr.Append(ordinal, 10);
|
||||
const PRUnichar* dp = decStr.GetUnicode();
|
||||
const PRUnichar* end = dp + decStr.Length();
|
||||
|
||||
PRIntn len=decStr.Length();
|
||||
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;
|
||||
}
|
||||
ordinal=(ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
|
||||
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...
|
||||
ordinal = (ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
while (next<=ordinal) // scale up in baseN; exceed current value.
|
||||
{
|
||||
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
|
||||
|
||||
void
|
||||
BulletFrame::GetDesiredSize(nsIPresContext* aCX,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& 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, 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;
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
mPadding.right = bulletSize / 2;
|
||||
}
|
||||
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);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
// Inside bullets need some extra width to get the padding
|
||||
// between the list item and the content that follows.
|
||||
mPadding.right = aMetrics.height / 2; // From old layout engine
|
||||
}
|
||||
|
||||
fm->GetWidth(text, aMetrics.width);
|
||||
aMetrics.width += mPadding.right;
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
// Get the base size
|
||||
GetDesiredSize(&aLineLayout.mPresContext, 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;
|
||||
space->CalcBorderPaddingFor(this, 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;
|
||||
}
|
||||
return NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define LINE_IS_DIRTY 0x1
|
||||
#define LINE_IS_BLOCK 0x2
|
||||
#define LINE_LAST_CONTENT_IS_COMPLETE 0x4
|
||||
|
@ -805,29 +1421,6 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext,
|
|||
mPrevChild = nsnull;
|
||||
mFreeList = nsnull;
|
||||
mPrevLine = nsnull;
|
||||
|
||||
// Setup initial list ordinal value
|
||||
|
||||
// XXX translate the starting value to a css style type and stop
|
||||
// doing this!
|
||||
mNextListOrdinal = -1;
|
||||
nsIContent* blockContent;
|
||||
mBlock->GetContent(blockContent);
|
||||
nsIAtom* tag;
|
||||
blockContent->GetTag(tag);
|
||||
if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
|
||||
(tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
((nsIHTMLContent*)blockContent)->GetAttribute(nsHTMLAtoms::start,
|
||||
value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
mNextListOrdinal = value.GetIntValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(blockContent);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -914,7 +1507,6 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
// XXX temporary
|
||||
if (aIID.Equals(kBlockFrameCID)) {
|
||||
*aInstancePtr = (void*) (this);
|
||||
return NS_OK;
|
||||
|
@ -933,7 +1525,51 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_IMETHODIMP
|
||||
nsBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
||||
{
|
||||
return AppendNewFrames(aPresContext, aChildList);
|
||||
nsresult rv = AppendNewFrames(aPresContext, aChildList);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create list bullet if this is a list-item. Note that this is done
|
||||
// here so that RenumberLists will work (it needs the bullets to
|
||||
// store the bullet numbers).
|
||||
const nsStyleDisplay* styleDisplay;
|
||||
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
Bullet* bullet;
|
||||
NS_NEWXPCOM(bullet, Bullet);
|
||||
if (nsnull == bullet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
mBullet = new BulletFrame(bullet, this);
|
||||
if (nsnull == mBullet) {
|
||||
NS_RELEASE(bullet);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1105,12 +1741,12 @@ nsBlockFrame::FirstChild(nsIFrame*& aFirstChild) const
|
|||
// Reflow methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d",
|
||||
|
@ -1138,6 +1774,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
if (eReflowReason_Initial == state.reason) {
|
||||
RenumberLists(state);
|
||||
if (!DrainOverflowLines()) {
|
||||
rv = InitialReflow(state);
|
||||
}
|
||||
|
@ -1155,6 +1792,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
nsIFrame* target;
|
||||
state.reflowCommand->GetTarget(target);
|
||||
if (this == target) {
|
||||
RenumberLists(state);
|
||||
nsIReflowCommand::ReflowType type;
|
||||
state.reflowCommand->GetType(type);
|
||||
switch (type) {
|
||||
|
@ -1203,47 +1841,59 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ProcessInitialReflow(nsBlockReflowState& aState)
|
||||
void
|
||||
nsBlockFrame::RenumberLists(nsBlockReflowState& aState)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create list bullet on the first reflow
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == aState.mStyleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
nsIHTMLContent* bullet;
|
||||
nsresult rv = NS_NewHTMLBullet(&bullet);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
rv = NS_NewBulletFrame(bullet, this, mBullet);
|
||||
if (NS_OK != rv) {
|
||||
NS_RELEASE(bullet);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aState.mPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aState.mPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
// Setup initial list ordinal value
|
||||
PRInt32 ordinal = 1;
|
||||
nsIHTMLContent* hc;
|
||||
if (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::start, value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
ordinal = value.GetIntValue();
|
||||
if (ordinal <= 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
aState.mNextListOrdinal = ordinal;
|
||||
|
||||
// Get to first-in-flow
|
||||
nsBlockFrame* block = this;
|
||||
while (nsnull != block->mPrevInFlow) {
|
||||
block = (nsBlockFrame*) block->mPrevInFlow;
|
||||
}
|
||||
|
||||
// For each flow-block...
|
||||
while (nsnull != block) {
|
||||
// For each frame in the flow-block...
|
||||
nsIFrame* frame = block->mLines ? block->mLines->mFirstChild : nsnull;
|
||||
while (nsnull != frame) {
|
||||
// If the frame is a list-item and the frame implements our
|
||||
// block frame API then get it's bullet and set the list item
|
||||
// ordinal.
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
||||
// Make certain that the frame isa block-frame in case
|
||||
// something foriegn has crept in.
|
||||
nsBlockFrame* listItem;
|
||||
if (NS_OK == frame->QueryInterface(kBlockFrameCID,
|
||||
(void**) &listItem)) {
|
||||
if (nsnull != listItem->mBullet) {
|
||||
listItem->mBullet->SetListItemOrdinal(aState);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->GetNextSibling(frame);
|
||||
}
|
||||
block = (nsBlockFrame*) block->mNextInFlow;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1567,14 +2217,8 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|||
nsresult
|
||||
nsBlockFrame::InitialReflow(nsBlockReflowState& aState)
|
||||
{
|
||||
// Create synthetic content
|
||||
nsresult rv = ProcessInitialReflow(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generate text-run information
|
||||
rv = FindTextRuns(aState);
|
||||
nsresult rv = FindTextRuns(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsFrameReflowState.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsInlineReflow.h"
|
||||
#include "nsCSSLayout.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIRunaround.h"
|
||||
#include "nsISpaceManager.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsHTMLValue.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
|
||||
//#include "js/jsapi.h"
|
||||
//#include "nsDOMEvent.h"
|
||||
|
@ -46,6 +47,17 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
// XXX These are unfortunate dependencies
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsHTMLImage.h"
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
// 09-15-98: make sure that the outer container of the block (e.g. the
|
||||
// body sets up the outer top margin feed in properly so that the top
|
||||
// margin collapses properly with the body margin. Note that for the
|
||||
|
@ -101,7 +113,110 @@
|
|||
// XXX I don't want mFirstChild, mChildCount, mOverflowList,
|
||||
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class BulletFrame;
|
||||
struct LineData;
|
||||
class nsBlockFrame;
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
// XXX hide this as soon as list bullet code is cleaned up
|
||||
|
||||
struct nsBlockReflowState : public nsFrameReflowState {
|
||||
nsBlockReflowState(nsIPresContext& aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
const nsReflowMetrics& aMetrics,
|
||||
nsISpaceManager* aSpaceManager);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Update the mCurrentBand data based on the current mY position.
|
||||
*/
|
||||
void GetAvailableSpace();
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void PlaceFloater(nsPlaceholderFrame* aFloater);
|
||||
|
||||
void PlaceFloaters(nsVoidArray* aFloaters);
|
||||
|
||||
void ClearFloaters(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsLeftMostChild(nsIFrame* aFrame);
|
||||
|
||||
nsLineLayout mLineLayout;
|
||||
nsInlineReflow* mInlineReflow;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
nsBlockFrame* mBlock;
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
PRBool mInlineReflowPrepared;
|
||||
|
||||
PRUint8 mTextAlign;
|
||||
|
||||
nsSize mStyleSize;
|
||||
|
||||
PRIntn mStyleSizeFlags;
|
||||
|
||||
nscoord mBottomEdge; // maximum Y
|
||||
|
||||
nscoord mBulletPadding;// XXX Get rid of these
|
||||
nscoord mLeftPadding;// XXX Get rid of these
|
||||
|
||||
PRBool mUnconstrainedWidth;
|
||||
PRBool mUnconstrainedHeight;
|
||||
nscoord mY;
|
||||
nscoord mKidXMost;
|
||||
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
LineData* mFreeList;
|
||||
|
||||
nsVoidArray mPendingFloaters;
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
LineData* mCurrentLine;
|
||||
LineData* mPrevLine;
|
||||
|
||||
// The next list ordinal for counting list bullets
|
||||
PRInt32 mNextListOrdinal;
|
||||
|
||||
// XXX what happens if we need more than 12 trapezoids?
|
||||
struct BlockBandData : public nsBandData {
|
||||
// Trapezoids used during band processing
|
||||
nsBandTrapezoid data[12];
|
||||
|
||||
// Bounding rect of available space between any left and right floaters
|
||||
nsRect availSpace;
|
||||
|
||||
BlockBandData() {
|
||||
size = 12;
|
||||
trapezoids = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding rect of the available space, i.e. space
|
||||
* between any left and right floaters Uses the current trapezoid
|
||||
* data, see nsISpaceManager::GetBandData(). Also updates member
|
||||
* data "availSpace".
|
||||
*/
|
||||
void ComputeAvailSpaceRect();
|
||||
};
|
||||
|
||||
BlockBandData mCurrentBand;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockReflowState->AddFloater(aFrame);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
|
@ -183,8 +298,6 @@ public:
|
|||
|
||||
PRBool RemoveChild(LineData* aLines, nsIFrame* aChild);
|
||||
|
||||
nsresult ProcessInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
PRIntn GetSkipSides() const;
|
||||
|
||||
PRBool IsPseudoFrame() const;
|
||||
|
@ -262,6 +375,8 @@ public:
|
|||
|
||||
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
||||
|
||||
void RenumberLists(nsBlockReflowState& aState);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
#endif
|
||||
|
@ -274,11 +389,512 @@ public:
|
|||
nsTextRun* mTextRuns;
|
||||
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsIFrame* mBullet;
|
||||
BulletFrame* mBullet;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A helper content class for bullets. The content class is needed
|
||||
* primarily so that we can resolve style and force the display mode
|
||||
* for the bullet to be inline
|
||||
*/
|
||||
static void
|
||||
MapAttributesInto(nsIHTMLAttributes* aAttributes,
|
||||
nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext)
|
||||
{
|
||||
nsStyleDisplay* display = (nsStyleDisplay*)
|
||||
aContext->GetMutableStyleData(eStyleStruct_Display);
|
||||
display->mDisplay = NS_STYLE_DISPLAY_INLINE;
|
||||
}
|
||||
|
||||
class Bullet : public nsHTMLTagContent {
|
||||
public:
|
||||
Bullet() {
|
||||
mRefCnt = 1;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsSynthetic(PRBool& aResult)
|
||||
{
|
||||
aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const
|
||||
{
|
||||
aMapFunc = &MapAttributesInto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
fprintf(out, "Bullet RefCnt=%d<>\n", mRefCnt);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class BulletFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
virtual ~BulletFrame();
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD Paint(nsIPresContext &aCX,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD ListTag(FILE* out) const;
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
void SetListItemOrdinal(nsBlockReflowState& aBlockState);
|
||||
|
||||
void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aMetrics);
|
||||
|
||||
void GetListItemText(nsIPresContext& aCX,
|
||||
const nsStyleList& aMol,
|
||||
nsString& aResult);
|
||||
|
||||
PRInt32 mOrdinal;
|
||||
nsMargin mPadding;
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
};
|
||||
|
||||
BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BulletFrame::~BulletFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
return nsFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::ListTag(FILE* out) const
|
||||
{
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p", contentIndex, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p ",
|
||||
contentIndex, 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
|
||||
BulletFrame::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(myFont->mFont);
|
||||
fm->GetWidth(text, width);
|
||||
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
|
||||
NS_RELEASE(fm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BulletFrame::SetListItemOrdinal(nsBlockReflowState& aReflowState)
|
||||
{
|
||||
// Assume that the ordinal comes from the block reflow state
|
||||
mOrdinal = aReflowState.mNextListOrdinal;
|
||||
|
||||
// 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);
|
||||
|
||||
aReflowState.mNextListOrdinal = 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
|
||||
BulletFrame::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 (0 == ordinal) {
|
||||
ordinal = 1;
|
||||
}
|
||||
nsAutoString addOn;
|
||||
nsAutoString decStr;
|
||||
decStr.Append(ordinal, 10);
|
||||
const PRUnichar* dp = decStr.GetUnicode();
|
||||
const PRUnichar* end = dp + decStr.Length();
|
||||
|
||||
PRIntn len=decStr.Length();
|
||||
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;
|
||||
}
|
||||
ordinal=(ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
|
||||
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...
|
||||
ordinal = (ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
while (next<=ordinal) // scale up in baseN; exceed current value.
|
||||
{
|
||||
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
|
||||
|
||||
void
|
||||
BulletFrame::GetDesiredSize(nsIPresContext* aCX,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& 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, 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;
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
mPadding.right = bulletSize / 2;
|
||||
}
|
||||
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);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
// Inside bullets need some extra width to get the padding
|
||||
// between the list item and the content that follows.
|
||||
mPadding.right = aMetrics.height / 2; // From old layout engine
|
||||
}
|
||||
|
||||
fm->GetWidth(text, aMetrics.width);
|
||||
aMetrics.width += mPadding.right;
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
// Get the base size
|
||||
GetDesiredSize(&aLineLayout.mPresContext, 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;
|
||||
space->CalcBorderPaddingFor(this, 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;
|
||||
}
|
||||
return NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define LINE_IS_DIRTY 0x1
|
||||
#define LINE_IS_BLOCK 0x2
|
||||
#define LINE_LAST_CONTENT_IS_COMPLETE 0x4
|
||||
|
@ -805,29 +1421,6 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext,
|
|||
mPrevChild = nsnull;
|
||||
mFreeList = nsnull;
|
||||
mPrevLine = nsnull;
|
||||
|
||||
// Setup initial list ordinal value
|
||||
|
||||
// XXX translate the starting value to a css style type and stop
|
||||
// doing this!
|
||||
mNextListOrdinal = -1;
|
||||
nsIContent* blockContent;
|
||||
mBlock->GetContent(blockContent);
|
||||
nsIAtom* tag;
|
||||
blockContent->GetTag(tag);
|
||||
if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
|
||||
(tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
((nsIHTMLContent*)blockContent)->GetAttribute(nsHTMLAtoms::start,
|
||||
value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
mNextListOrdinal = value.GetIntValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(blockContent);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -914,7 +1507,6 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
// XXX temporary
|
||||
if (aIID.Equals(kBlockFrameCID)) {
|
||||
*aInstancePtr = (void*) (this);
|
||||
return NS_OK;
|
||||
|
@ -933,7 +1525,51 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_IMETHODIMP
|
||||
nsBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
||||
{
|
||||
return AppendNewFrames(aPresContext, aChildList);
|
||||
nsresult rv = AppendNewFrames(aPresContext, aChildList);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create list bullet if this is a list-item. Note that this is done
|
||||
// here so that RenumberLists will work (it needs the bullets to
|
||||
// store the bullet numbers).
|
||||
const nsStyleDisplay* styleDisplay;
|
||||
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
Bullet* bullet;
|
||||
NS_NEWXPCOM(bullet, Bullet);
|
||||
if (nsnull == bullet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
mBullet = new BulletFrame(bullet, this);
|
||||
if (nsnull == mBullet) {
|
||||
NS_RELEASE(bullet);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1105,12 +1741,12 @@ nsBlockFrame::FirstChild(nsIFrame*& aFirstChild) const
|
|||
// Reflow methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d",
|
||||
|
@ -1138,6 +1774,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
if (eReflowReason_Initial == state.reason) {
|
||||
RenumberLists(state);
|
||||
if (!DrainOverflowLines()) {
|
||||
rv = InitialReflow(state);
|
||||
}
|
||||
|
@ -1155,6 +1792,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
nsIFrame* target;
|
||||
state.reflowCommand->GetTarget(target);
|
||||
if (this == target) {
|
||||
RenumberLists(state);
|
||||
nsIReflowCommand::ReflowType type;
|
||||
state.reflowCommand->GetType(type);
|
||||
switch (type) {
|
||||
|
@ -1203,47 +1841,59 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ProcessInitialReflow(nsBlockReflowState& aState)
|
||||
void
|
||||
nsBlockFrame::RenumberLists(nsBlockReflowState& aState)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create list bullet on the first reflow
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == aState.mStyleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
nsIHTMLContent* bullet;
|
||||
nsresult rv = NS_NewHTMLBullet(&bullet);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
rv = NS_NewBulletFrame(bullet, this, mBullet);
|
||||
if (NS_OK != rv) {
|
||||
NS_RELEASE(bullet);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aState.mPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aState.mPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
// Setup initial list ordinal value
|
||||
PRInt32 ordinal = 1;
|
||||
nsIHTMLContent* hc;
|
||||
if (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::start, value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
ordinal = value.GetIntValue();
|
||||
if (ordinal <= 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
aState.mNextListOrdinal = ordinal;
|
||||
|
||||
// Get to first-in-flow
|
||||
nsBlockFrame* block = this;
|
||||
while (nsnull != block->mPrevInFlow) {
|
||||
block = (nsBlockFrame*) block->mPrevInFlow;
|
||||
}
|
||||
|
||||
// For each flow-block...
|
||||
while (nsnull != block) {
|
||||
// For each frame in the flow-block...
|
||||
nsIFrame* frame = block->mLines ? block->mLines->mFirstChild : nsnull;
|
||||
while (nsnull != frame) {
|
||||
// If the frame is a list-item and the frame implements our
|
||||
// block frame API then get it's bullet and set the list item
|
||||
// ordinal.
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
||||
// Make certain that the frame isa block-frame in case
|
||||
// something foriegn has crept in.
|
||||
nsBlockFrame* listItem;
|
||||
if (NS_OK == frame->QueryInterface(kBlockFrameCID,
|
||||
(void**) &listItem)) {
|
||||
if (nsnull != listItem->mBullet) {
|
||||
listItem->mBullet->SetListItemOrdinal(aState);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->GetNextSibling(frame);
|
||||
}
|
||||
block = (nsBlockFrame*) block->mNextInFlow;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1567,14 +2217,8 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|||
nsresult
|
||||
nsBlockFrame::InitialReflow(nsBlockReflowState& aState)
|
||||
{
|
||||
// Create synthetic content
|
||||
nsresult rv = ProcessInitialReflow(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generate text-run information
|
||||
rv = FindTextRuns(aState);
|
||||
nsresult rv = FindTextRuns(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsFrameReflowState.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsInlineReflow.h"
|
||||
#include "nsCSSLayout.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIRunaround.h"
|
||||
#include "nsISpaceManager.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsHTMLValue.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
|
||||
//#include "js/jsapi.h"
|
||||
//#include "nsDOMEvent.h"
|
||||
|
@ -46,6 +47,17 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
// XXX These are unfortunate dependencies
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsHTMLImage.h"
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
// 09-15-98: make sure that the outer container of the block (e.g. the
|
||||
// body sets up the outer top margin feed in properly so that the top
|
||||
// margin collapses properly with the body margin. Note that for the
|
||||
|
@ -101,7 +113,110 @@
|
|||
// XXX I don't want mFirstChild, mChildCount, mOverflowList,
|
||||
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class BulletFrame;
|
||||
struct LineData;
|
||||
class nsBlockFrame;
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
// XXX hide this as soon as list bullet code is cleaned up
|
||||
|
||||
struct nsBlockReflowState : public nsFrameReflowState {
|
||||
nsBlockReflowState(nsIPresContext& aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
const nsReflowMetrics& aMetrics,
|
||||
nsISpaceManager* aSpaceManager);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Update the mCurrentBand data based on the current mY position.
|
||||
*/
|
||||
void GetAvailableSpace();
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void PlaceFloater(nsPlaceholderFrame* aFloater);
|
||||
|
||||
void PlaceFloaters(nsVoidArray* aFloaters);
|
||||
|
||||
void ClearFloaters(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsLeftMostChild(nsIFrame* aFrame);
|
||||
|
||||
nsLineLayout mLineLayout;
|
||||
nsInlineReflow* mInlineReflow;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
nsBlockFrame* mBlock;
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
PRBool mInlineReflowPrepared;
|
||||
|
||||
PRUint8 mTextAlign;
|
||||
|
||||
nsSize mStyleSize;
|
||||
|
||||
PRIntn mStyleSizeFlags;
|
||||
|
||||
nscoord mBottomEdge; // maximum Y
|
||||
|
||||
nscoord mBulletPadding;// XXX Get rid of these
|
||||
nscoord mLeftPadding;// XXX Get rid of these
|
||||
|
||||
PRBool mUnconstrainedWidth;
|
||||
PRBool mUnconstrainedHeight;
|
||||
nscoord mY;
|
||||
nscoord mKidXMost;
|
||||
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
LineData* mFreeList;
|
||||
|
||||
nsVoidArray mPendingFloaters;
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
LineData* mCurrentLine;
|
||||
LineData* mPrevLine;
|
||||
|
||||
// The next list ordinal for counting list bullets
|
||||
PRInt32 mNextListOrdinal;
|
||||
|
||||
// XXX what happens if we need more than 12 trapezoids?
|
||||
struct BlockBandData : public nsBandData {
|
||||
// Trapezoids used during band processing
|
||||
nsBandTrapezoid data[12];
|
||||
|
||||
// Bounding rect of available space between any left and right floaters
|
||||
nsRect availSpace;
|
||||
|
||||
BlockBandData() {
|
||||
size = 12;
|
||||
trapezoids = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding rect of the available space, i.e. space
|
||||
* between any left and right floaters Uses the current trapezoid
|
||||
* data, see nsISpaceManager::GetBandData(). Also updates member
|
||||
* data "availSpace".
|
||||
*/
|
||||
void ComputeAvailSpaceRect();
|
||||
};
|
||||
|
||||
BlockBandData mCurrentBand;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockReflowState->AddFloater(aFrame);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
|
@ -183,8 +298,6 @@ public:
|
|||
|
||||
PRBool RemoveChild(LineData* aLines, nsIFrame* aChild);
|
||||
|
||||
nsresult ProcessInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
PRIntn GetSkipSides() const;
|
||||
|
||||
PRBool IsPseudoFrame() const;
|
||||
|
@ -262,6 +375,8 @@ public:
|
|||
|
||||
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
||||
|
||||
void RenumberLists(nsBlockReflowState& aState);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
#endif
|
||||
|
@ -274,11 +389,512 @@ public:
|
|||
nsTextRun* mTextRuns;
|
||||
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsIFrame* mBullet;
|
||||
BulletFrame* mBullet;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A helper content class for bullets. The content class is needed
|
||||
* primarily so that we can resolve style and force the display mode
|
||||
* for the bullet to be inline
|
||||
*/
|
||||
static void
|
||||
MapAttributesInto(nsIHTMLAttributes* aAttributes,
|
||||
nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext)
|
||||
{
|
||||
nsStyleDisplay* display = (nsStyleDisplay*)
|
||||
aContext->GetMutableStyleData(eStyleStruct_Display);
|
||||
display->mDisplay = NS_STYLE_DISPLAY_INLINE;
|
||||
}
|
||||
|
||||
class Bullet : public nsHTMLTagContent {
|
||||
public:
|
||||
Bullet() {
|
||||
mRefCnt = 1;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsSynthetic(PRBool& aResult)
|
||||
{
|
||||
aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const
|
||||
{
|
||||
aMapFunc = &MapAttributesInto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
fprintf(out, "Bullet RefCnt=%d<>\n", mRefCnt);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class BulletFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
virtual ~BulletFrame();
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD Paint(nsIPresContext &aCX,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD ListTag(FILE* out) const;
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
void SetListItemOrdinal(nsBlockReflowState& aBlockState);
|
||||
|
||||
void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aMetrics);
|
||||
|
||||
void GetListItemText(nsIPresContext& aCX,
|
||||
const nsStyleList& aMol,
|
||||
nsString& aResult);
|
||||
|
||||
PRInt32 mOrdinal;
|
||||
nsMargin mPadding;
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
};
|
||||
|
||||
BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BulletFrame::~BulletFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
return nsFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::ListTag(FILE* out) const
|
||||
{
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p", contentIndex, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p ",
|
||||
contentIndex, 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
|
||||
BulletFrame::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(myFont->mFont);
|
||||
fm->GetWidth(text, width);
|
||||
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
|
||||
NS_RELEASE(fm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BulletFrame::SetListItemOrdinal(nsBlockReflowState& aReflowState)
|
||||
{
|
||||
// Assume that the ordinal comes from the block reflow state
|
||||
mOrdinal = aReflowState.mNextListOrdinal;
|
||||
|
||||
// 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);
|
||||
|
||||
aReflowState.mNextListOrdinal = 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
|
||||
BulletFrame::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 (0 == ordinal) {
|
||||
ordinal = 1;
|
||||
}
|
||||
nsAutoString addOn;
|
||||
nsAutoString decStr;
|
||||
decStr.Append(ordinal, 10);
|
||||
const PRUnichar* dp = decStr.GetUnicode();
|
||||
const PRUnichar* end = dp + decStr.Length();
|
||||
|
||||
PRIntn len=decStr.Length();
|
||||
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;
|
||||
}
|
||||
ordinal=(ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
|
||||
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...
|
||||
ordinal = (ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
while (next<=ordinal) // scale up in baseN; exceed current value.
|
||||
{
|
||||
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
|
||||
|
||||
void
|
||||
BulletFrame::GetDesiredSize(nsIPresContext* aCX,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& 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, 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;
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
mPadding.right = bulletSize / 2;
|
||||
}
|
||||
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);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
// Inside bullets need some extra width to get the padding
|
||||
// between the list item and the content that follows.
|
||||
mPadding.right = aMetrics.height / 2; // From old layout engine
|
||||
}
|
||||
|
||||
fm->GetWidth(text, aMetrics.width);
|
||||
aMetrics.width += mPadding.right;
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
// Get the base size
|
||||
GetDesiredSize(&aLineLayout.mPresContext, 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;
|
||||
space->CalcBorderPaddingFor(this, 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;
|
||||
}
|
||||
return NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define LINE_IS_DIRTY 0x1
|
||||
#define LINE_IS_BLOCK 0x2
|
||||
#define LINE_LAST_CONTENT_IS_COMPLETE 0x4
|
||||
|
@ -805,29 +1421,6 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext,
|
|||
mPrevChild = nsnull;
|
||||
mFreeList = nsnull;
|
||||
mPrevLine = nsnull;
|
||||
|
||||
// Setup initial list ordinal value
|
||||
|
||||
// XXX translate the starting value to a css style type and stop
|
||||
// doing this!
|
||||
mNextListOrdinal = -1;
|
||||
nsIContent* blockContent;
|
||||
mBlock->GetContent(blockContent);
|
||||
nsIAtom* tag;
|
||||
blockContent->GetTag(tag);
|
||||
if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
|
||||
(tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
((nsIHTMLContent*)blockContent)->GetAttribute(nsHTMLAtoms::start,
|
||||
value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
mNextListOrdinal = value.GetIntValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(blockContent);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -914,7 +1507,6 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
// XXX temporary
|
||||
if (aIID.Equals(kBlockFrameCID)) {
|
||||
*aInstancePtr = (void*) (this);
|
||||
return NS_OK;
|
||||
|
@ -933,7 +1525,51 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_IMETHODIMP
|
||||
nsBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
||||
{
|
||||
return AppendNewFrames(aPresContext, aChildList);
|
||||
nsresult rv = AppendNewFrames(aPresContext, aChildList);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create list bullet if this is a list-item. Note that this is done
|
||||
// here so that RenumberLists will work (it needs the bullets to
|
||||
// store the bullet numbers).
|
||||
const nsStyleDisplay* styleDisplay;
|
||||
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
Bullet* bullet;
|
||||
NS_NEWXPCOM(bullet, Bullet);
|
||||
if (nsnull == bullet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
mBullet = new BulletFrame(bullet, this);
|
||||
if (nsnull == mBullet) {
|
||||
NS_RELEASE(bullet);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1105,12 +1741,12 @@ nsBlockFrame::FirstChild(nsIFrame*& aFirstChild) const
|
|||
// Reflow methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d",
|
||||
|
@ -1138,6 +1774,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
if (eReflowReason_Initial == state.reason) {
|
||||
RenumberLists(state);
|
||||
if (!DrainOverflowLines()) {
|
||||
rv = InitialReflow(state);
|
||||
}
|
||||
|
@ -1155,6 +1792,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
nsIFrame* target;
|
||||
state.reflowCommand->GetTarget(target);
|
||||
if (this == target) {
|
||||
RenumberLists(state);
|
||||
nsIReflowCommand::ReflowType type;
|
||||
state.reflowCommand->GetType(type);
|
||||
switch (type) {
|
||||
|
@ -1203,47 +1841,59 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ProcessInitialReflow(nsBlockReflowState& aState)
|
||||
void
|
||||
nsBlockFrame::RenumberLists(nsBlockReflowState& aState)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create list bullet on the first reflow
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == aState.mStyleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
nsIHTMLContent* bullet;
|
||||
nsresult rv = NS_NewHTMLBullet(&bullet);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
rv = NS_NewBulletFrame(bullet, this, mBullet);
|
||||
if (NS_OK != rv) {
|
||||
NS_RELEASE(bullet);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aState.mPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aState.mPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
// Setup initial list ordinal value
|
||||
PRInt32 ordinal = 1;
|
||||
nsIHTMLContent* hc;
|
||||
if (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::start, value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
ordinal = value.GetIntValue();
|
||||
if (ordinal <= 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
aState.mNextListOrdinal = ordinal;
|
||||
|
||||
// Get to first-in-flow
|
||||
nsBlockFrame* block = this;
|
||||
while (nsnull != block->mPrevInFlow) {
|
||||
block = (nsBlockFrame*) block->mPrevInFlow;
|
||||
}
|
||||
|
||||
// For each flow-block...
|
||||
while (nsnull != block) {
|
||||
// For each frame in the flow-block...
|
||||
nsIFrame* frame = block->mLines ? block->mLines->mFirstChild : nsnull;
|
||||
while (nsnull != frame) {
|
||||
// If the frame is a list-item and the frame implements our
|
||||
// block frame API then get it's bullet and set the list item
|
||||
// ordinal.
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
||||
// Make certain that the frame isa block-frame in case
|
||||
// something foriegn has crept in.
|
||||
nsBlockFrame* listItem;
|
||||
if (NS_OK == frame->QueryInterface(kBlockFrameCID,
|
||||
(void**) &listItem)) {
|
||||
if (nsnull != listItem->mBullet) {
|
||||
listItem->mBullet->SetListItemOrdinal(aState);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->GetNextSibling(frame);
|
||||
}
|
||||
block = (nsBlockFrame*) block->mNextInFlow;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1567,14 +2217,8 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|||
nsresult
|
||||
nsBlockFrame::InitialReflow(nsBlockReflowState& aState)
|
||||
{
|
||||
// Create synthetic content
|
||||
nsresult rv = ProcessInitialReflow(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generate text-run information
|
||||
rv = FindTextRuns(aState);
|
||||
nsresult rv = FindTextRuns(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsHTMLContainerFrame.h"
|
||||
#include "nsFrameReflowState.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsInlineReflow.h"
|
||||
#include "nsCSSLayout.h"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIRunaround.h"
|
||||
#include "nsISpaceManager.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
|
@ -38,7 +40,6 @@
|
|||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsHTMLValue.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
|
||||
//#include "js/jsapi.h"
|
||||
//#include "nsDOMEvent.h"
|
||||
|
@ -46,6 +47,17 @@
|
|||
|
||||
#include "prprf.h"
|
||||
|
||||
// XXX These are unfortunate dependencies
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsHTMLImage.h"
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
||||
|
||||
// 09-15-98: make sure that the outer container of the block (e.g. the
|
||||
// body sets up the outer top margin feed in properly so that the top
|
||||
// margin collapses properly with the body margin. Note that for the
|
||||
|
@ -101,7 +113,110 @@
|
|||
// XXX I don't want mFirstChild, mChildCount, mOverflowList,
|
||||
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class BulletFrame;
|
||||
struct LineData;
|
||||
class nsBlockFrame;
|
||||
|
||||
/* 52b33130-0b99-11d2-932e-00805f8add32 */
|
||||
#define NS_BLOCK_FRAME_CID \
|
||||
{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
// XXX hide this as soon as list bullet code is cleaned up
|
||||
|
||||
struct nsBlockReflowState : public nsFrameReflowState {
|
||||
nsBlockReflowState(nsIPresContext& aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
const nsReflowMetrics& aMetrics,
|
||||
nsISpaceManager* aSpaceManager);
|
||||
|
||||
~nsBlockReflowState();
|
||||
|
||||
/**
|
||||
* Update the mCurrentBand data based on the current mY position.
|
||||
*/
|
||||
void GetAvailableSpace();
|
||||
|
||||
void AddFloater(nsPlaceholderFrame* aPlaceholderFrame);
|
||||
|
||||
void PlaceFloater(nsPlaceholderFrame* aFloater);
|
||||
|
||||
void PlaceFloaters(nsVoidArray* aFloaters);
|
||||
|
||||
void ClearFloaters(PRUint8 aBreakType);
|
||||
|
||||
PRBool IsLeftMostChild(nsIFrame* aFrame);
|
||||
|
||||
nsLineLayout mLineLayout;
|
||||
nsInlineReflow* mInlineReflow;
|
||||
|
||||
nsISpaceManager* mSpaceManager;
|
||||
nsBlockFrame* mBlock;
|
||||
nsBlockFrame* mNextInFlow;
|
||||
|
||||
PRBool mInlineReflowPrepared;
|
||||
|
||||
PRUint8 mTextAlign;
|
||||
|
||||
nsSize mStyleSize;
|
||||
|
||||
PRIntn mStyleSizeFlags;
|
||||
|
||||
nscoord mBottomEdge; // maximum Y
|
||||
|
||||
nscoord mBulletPadding;// XXX Get rid of these
|
||||
nscoord mLeftPadding;// XXX Get rid of these
|
||||
|
||||
PRBool mUnconstrainedWidth;
|
||||
PRBool mUnconstrainedHeight;
|
||||
nscoord mY;
|
||||
nscoord mKidXMost;
|
||||
|
||||
nsIFrame* mPrevChild;
|
||||
|
||||
LineData* mFreeList;
|
||||
|
||||
nsVoidArray mPendingFloaters;
|
||||
nscoord mSpaceManagerX, mSpaceManagerY;
|
||||
|
||||
LineData* mCurrentLine;
|
||||
LineData* mPrevLine;
|
||||
|
||||
// The next list ordinal for counting list bullets
|
||||
PRInt32 mNextListOrdinal;
|
||||
|
||||
// XXX what happens if we need more than 12 trapezoids?
|
||||
struct BlockBandData : public nsBandData {
|
||||
// Trapezoids used during band processing
|
||||
nsBandTrapezoid data[12];
|
||||
|
||||
// Bounding rect of available space between any left and right floaters
|
||||
nsRect availSpace;
|
||||
|
||||
BlockBandData() {
|
||||
size = 12;
|
||||
trapezoids = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding rect of the available space, i.e. space
|
||||
* between any left and right floaters Uses the current trapezoid
|
||||
* data, see nsISpaceManager::GetBandData(). Also updates member
|
||||
* data "availSpace".
|
||||
*/
|
||||
void ComputeAvailSpaceRect();
|
||||
};
|
||||
|
||||
BlockBandData mCurrentBand;
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
void
|
||||
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
||||
{
|
||||
mBlockReflowState->AddFloater(aFrame);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define nsBlockFrameSuper nsHTMLContainerFrame
|
||||
|
||||
|
@ -183,8 +298,6 @@ public:
|
|||
|
||||
PRBool RemoveChild(LineData* aLines, nsIFrame* aChild);
|
||||
|
||||
nsresult ProcessInitialReflow(nsBlockReflowState& aState);
|
||||
|
||||
PRIntn GetSkipSides() const;
|
||||
|
||||
PRBool IsPseudoFrame() const;
|
||||
|
@ -262,6 +375,8 @@ public:
|
|||
|
||||
nsresult AppendNewFrames(nsIPresContext& aPresContext, nsIFrame*);
|
||||
|
||||
void RenumberLists(nsBlockReflowState& aState);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PRBool IsChild(nsIFrame* aFrame);
|
||||
#endif
|
||||
|
@ -274,11 +389,512 @@ public:
|
|||
nsTextRun* mTextRuns;
|
||||
|
||||
// For list-item frames, this is the bullet frame.
|
||||
nsIFrame* mBullet;
|
||||
BulletFrame* mBullet;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A helper content class for bullets. The content class is needed
|
||||
* primarily so that we can resolve style and force the display mode
|
||||
* for the bullet to be inline
|
||||
*/
|
||||
static void
|
||||
MapAttributesInto(nsIHTMLAttributes* aAttributes,
|
||||
nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext)
|
||||
{
|
||||
nsStyleDisplay* display = (nsStyleDisplay*)
|
||||
aContext->GetMutableStyleData(eStyleStruct_Display);
|
||||
display->mDisplay = NS_STYLE_DISPLAY_INLINE;
|
||||
}
|
||||
|
||||
class Bullet : public nsHTMLTagContent {
|
||||
public:
|
||||
Bullet() {
|
||||
mRefCnt = 1;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsSynthetic(PRBool& aResult)
|
||||
{
|
||||
aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const
|
||||
{
|
||||
aMapFunc = &MapAttributesInto;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
fprintf(out, "Bullet RefCnt=%d<>\n", mRefCnt);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class BulletFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
virtual ~BulletFrame();
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD Paint(nsIPresContext &aCX,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_IMETHOD ListTag(FILE* out) const;
|
||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
void SetListItemOrdinal(nsBlockReflowState& aBlockState);
|
||||
|
||||
void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aMetrics);
|
||||
|
||||
void GetListItemText(nsIPresContext& aCX,
|
||||
const nsStyleList& aMol,
|
||||
nsString& aResult);
|
||||
|
||||
PRInt32 mOrdinal;
|
||||
nsMargin mPadding;
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
};
|
||||
|
||||
BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BulletFrame::~BulletFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
return nsFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::ListTag(FILE* out) const
|
||||
{
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p", contentIndex, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BulletFrame::List(FILE* out, PRInt32 aIndent) const
|
||||
{
|
||||
PRInt32 i;
|
||||
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||
PRInt32 contentIndex;
|
||||
GetContentIndex(contentIndex);
|
||||
fprintf(out, "Bullet(%d)@%p ",
|
||||
contentIndex, 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
|
||||
BulletFrame::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(myFont->mFont);
|
||||
fm->GetWidth(text, width);
|
||||
aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width);
|
||||
NS_RELEASE(fm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BulletFrame::SetListItemOrdinal(nsBlockReflowState& aReflowState)
|
||||
{
|
||||
// Assume that the ordinal comes from the block reflow state
|
||||
mOrdinal = aReflowState.mNextListOrdinal;
|
||||
|
||||
// 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);
|
||||
|
||||
aReflowState.mNextListOrdinal = 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
|
||||
BulletFrame::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 (0 == ordinal) {
|
||||
ordinal = 1;
|
||||
}
|
||||
nsAutoString addOn;
|
||||
nsAutoString decStr;
|
||||
decStr.Append(ordinal, 10);
|
||||
const PRUnichar* dp = decStr.GetUnicode();
|
||||
const PRUnichar* end = dp + decStr.Length();
|
||||
|
||||
PRIntn len=decStr.Length();
|
||||
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;
|
||||
}
|
||||
ordinal=(ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
|
||||
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...
|
||||
ordinal = (ordinal < 0) ? -ordinal : ordinal;
|
||||
if (ordinal < 0) {
|
||||
// XXX max negative int
|
||||
break;
|
||||
}
|
||||
while (next<=ordinal) // scale up in baseN; exceed current value.
|
||||
{
|
||||
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
|
||||
|
||||
void
|
||||
BulletFrame::GetDesiredSize(nsIPresContext* aCX,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& 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, 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;
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
mPadding.right = bulletSize / 2;
|
||||
}
|
||||
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);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) {
|
||||
// Inside bullets need some extra width to get the padding
|
||||
// between the list item and the content that follows.
|
||||
mPadding.right = aMetrics.height / 2; // From old layout engine
|
||||
}
|
||||
|
||||
fm->GetWidth(text, aMetrics.width);
|
||||
aMetrics.width += mPadding.right;
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::InlineReflow(nsLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
// Get the base size
|
||||
GetDesiredSize(&aLineLayout.mPresContext, 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;
|
||||
space->CalcBorderPaddingFor(this, 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;
|
||||
}
|
||||
return NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BulletFrame::FindTextRuns(nsLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#define LINE_IS_DIRTY 0x1
|
||||
#define LINE_IS_BLOCK 0x2
|
||||
#define LINE_LAST_CONTENT_IS_COMPLETE 0x4
|
||||
|
@ -805,29 +1421,6 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext,
|
|||
mPrevChild = nsnull;
|
||||
mFreeList = nsnull;
|
||||
mPrevLine = nsnull;
|
||||
|
||||
// Setup initial list ordinal value
|
||||
|
||||
// XXX translate the starting value to a css style type and stop
|
||||
// doing this!
|
||||
mNextListOrdinal = -1;
|
||||
nsIContent* blockContent;
|
||||
mBlock->GetContent(blockContent);
|
||||
nsIAtom* tag;
|
||||
blockContent->GetTag(tag);
|
||||
if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) ||
|
||||
(tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
((nsIHTMLContent*)blockContent)->GetAttribute(nsHTMLAtoms::start,
|
||||
value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
mNextListOrdinal = value.GetIntValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(blockContent);
|
||||
}
|
||||
|
||||
nsBlockReflowState::~nsBlockReflowState()
|
||||
|
@ -914,7 +1507,6 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
// XXX temporary
|
||||
if (aIID.Equals(kBlockFrameCID)) {
|
||||
*aInstancePtr = (void*) (this);
|
||||
return NS_OK;
|
||||
|
@ -933,7 +1525,51 @@ nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_IMETHODIMP
|
||||
nsBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
||||
{
|
||||
return AppendNewFrames(aPresContext, aChildList);
|
||||
nsresult rv = AppendNewFrames(aPresContext, aChildList);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create list bullet if this is a list-item. Note that this is done
|
||||
// here so that RenumberLists will work (it needs the bullets to
|
||||
// store the bullet numbers).
|
||||
const nsStyleDisplay* styleDisplay;
|
||||
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
Bullet* bullet;
|
||||
NS_NEWXPCOM(bullet, Bullet);
|
||||
if (nsnull == bullet) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
mBullet = new BulletFrame(bullet, this);
|
||||
if (nsnull == mBullet) {
|
||||
NS_RELEASE(bullet);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1105,12 +1741,12 @@ nsBlockFrame::FirstChild(nsIFrame*& aFirstChild) const
|
|||
// Reflow methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
||||
nsISpaceManager* aSpaceManager,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState,
|
||||
nsRect& aDesiredRect,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d",
|
||||
|
@ -1138,6 +1774,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
if (eReflowReason_Initial == state.reason) {
|
||||
RenumberLists(state);
|
||||
if (!DrainOverflowLines()) {
|
||||
rv = InitialReflow(state);
|
||||
}
|
||||
|
@ -1155,6 +1792,7 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
nsIFrame* target;
|
||||
state.reflowCommand->GetTarget(target);
|
||||
if (this == target) {
|
||||
RenumberLists(state);
|
||||
nsIReflowCommand::ReflowType type;
|
||||
state.reflowCommand->GetType(type);
|
||||
switch (type) {
|
||||
|
@ -1203,47 +1841,59 @@ nsBlockFrame::ReflowAround(nsIPresContext& aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::ProcessInitialReflow(nsBlockReflowState& aState)
|
||||
void
|
||||
nsBlockFrame::RenumberLists(nsBlockReflowState& aState)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create list bullet on the first reflow
|
||||
if ((nsnull == mPrevInFlow) &&
|
||||
(NS_STYLE_DISPLAY_LIST_ITEM == aState.mStyleDisplay->mDisplay) &&
|
||||
(nsnull == mBullet)) {
|
||||
// Create synthetic bullet content object. Note that we don't add
|
||||
// the content object to the content tree so that the DOM can't
|
||||
// find it.
|
||||
nsIHTMLContent* bullet;
|
||||
nsresult rv = NS_NewHTMLBullet(&bullet);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Create bullet frame
|
||||
rv = NS_NewBulletFrame(bullet, this, mBullet);
|
||||
if (NS_OK != rv) {
|
||||
NS_RELEASE(bullet);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolve style for the bullet frame
|
||||
nsIStyleContext* kidSC;
|
||||
kidSC = aState.mPresContext.ResolveStyleContextFor(bullet, this);
|
||||
mBullet->SetStyleContext(&aState.mPresContext, kidSC);
|
||||
NS_RELEASE(kidSC);
|
||||
NS_RELEASE(bullet);
|
||||
|
||||
// If the list bullet frame should be positioned inside then add
|
||||
// it to the flow now.
|
||||
const nsStyleList* styleList;
|
||||
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
||||
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
||||
InsertNewFrame(this, mBullet, nsnull);
|
||||
// Setup initial list ordinal value
|
||||
PRInt32 ordinal = 1;
|
||||
nsIHTMLContent* hc;
|
||||
if (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc)) {
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::start, value)) {
|
||||
if (eHTMLUnit_Integer == value.GetUnit()) {
|
||||
ordinal = value.GetIntValue();
|
||||
if (ordinal <= 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
aState.mNextListOrdinal = ordinal;
|
||||
|
||||
// Get to first-in-flow
|
||||
nsBlockFrame* block = this;
|
||||
while (nsnull != block->mPrevInFlow) {
|
||||
block = (nsBlockFrame*) block->mPrevInFlow;
|
||||
}
|
||||
|
||||
// For each flow-block...
|
||||
while (nsnull != block) {
|
||||
// For each frame in the flow-block...
|
||||
nsIFrame* frame = block->mLines ? block->mLines->mFirstChild : nsnull;
|
||||
while (nsnull != frame) {
|
||||
// If the frame is a list-item and the frame implements our
|
||||
// block frame API then get it's bullet and set the list item
|
||||
// ordinal.
|
||||
const nsStyleDisplay* display;
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
||||
// Make certain that the frame isa block-frame in case
|
||||
// something foriegn has crept in.
|
||||
nsBlockFrame* listItem;
|
||||
if (NS_OK == frame->QueryInterface(kBlockFrameCID,
|
||||
(void**) &listItem)) {
|
||||
if (nsnull != listItem->mBullet) {
|
||||
listItem->mBullet->SetListItemOrdinal(aState);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->GetNextSibling(frame);
|
||||
}
|
||||
block = (nsBlockFrame*) block->mNextInFlow;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1567,14 +2217,8 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext,
|
|||
nsresult
|
||||
nsBlockFrame::InitialReflow(nsBlockReflowState& aState)
|
||||
{
|
||||
// Create synthetic content
|
||||
nsresult rv = ProcessInitialReflow(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generate text-run information
|
||||
rv = FindTextRuns(aState);
|
||||
nsresult rv = FindTextRuns(aState);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче