зеркало из https://github.com/mozilla/gecko-dev.git
Reworked to be more css compliant; factored compatability logic out of nsInlineFrame into here
This commit is contained in:
Родитель
606ea6edd9
Коммит
beadfcb37c
|
@ -180,6 +180,27 @@ nsLineLayout::~nsLineLayout()
|
|||
PRBool
|
||||
nsLineLayout::InStrictMode()
|
||||
{
|
||||
// XXX For now this is always part of the build until harishd lands
|
||||
// the dtd auto-detect code...
|
||||
#if 1
|
||||
static PRBool forceStrictMode = PR_FALSE;
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
if (getenv("GECKO_FORCE_STRICT_MODE")) {
|
||||
forceStrictMode = PR_TRUE;
|
||||
}
|
||||
firstTime = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (forceStrictMode) {
|
||||
mKnowStrictMode = PR_TRUE;
|
||||
mInStrictMode = PR_TRUE;
|
||||
return mInStrictMode;
|
||||
}
|
||||
#endif
|
||||
if (!mKnowStrictMode) {
|
||||
mKnowStrictMode = PR_TRUE;
|
||||
mInStrictMode = PR_TRUE;
|
||||
|
@ -482,6 +503,7 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
|||
psd->mLeftEdge = aLeftEdge;
|
||||
psd->mX = aLeftEdge;
|
||||
psd->mRightEdge = aRightEdge;
|
||||
psd->mZeroEffectiveSpanBox = PR_FALSE;
|
||||
|
||||
const nsStyleText* styleText;
|
||||
aSpanReflowState->frame->GetStyleData(eStyleStruct_Text,
|
||||
|
@ -508,8 +530,7 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
|||
void
|
||||
nsLineLayout::EndSpan(nsIFrame* aFrame,
|
||||
nsSize& aSizeResult,
|
||||
nsSize* aMaxElementSize,
|
||||
PRBool* aHaveAtLeastOneNonEmptyTextFrame)
|
||||
nsSize* aMaxElementSize)
|
||||
{
|
||||
NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span");
|
||||
#ifdef NOISY_REFLOW
|
||||
|
@ -522,13 +543,11 @@ nsLineLayout::EndSpan(nsIFrame* aFrame,
|
|||
nscoord maxHeight = 0;
|
||||
nscoord maxElementWidth = 0;
|
||||
nscoord maxElementHeight = 0;
|
||||
PRBool haveAtLeastOneNonEmptyTextFrame = PR_FALSE;
|
||||
if (nsnull != psd->mLastFrame) {
|
||||
width = psd->mX - psd->mLeftEdge;
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nsnull != pfd) {
|
||||
if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height;
|
||||
if (pfd->mIsNonEmptyTextFrame) haveAtLeastOneNonEmptyTextFrame = PR_TRUE;
|
||||
|
||||
// Compute max-element-size if necessary
|
||||
if (aMaxElementSize) {
|
||||
|
@ -560,9 +579,6 @@ nsLineLayout::EndSpan(nsIFrame* aFrame,
|
|||
aMaxElementSize->height = maxElementHeight;
|
||||
}
|
||||
}
|
||||
if (aHaveAtLeastOneNonEmptyTextFrame) {
|
||||
*aHaveAtLeastOneNonEmptyTextFrame = haveAtLeastOneNonEmptyTextFrame;
|
||||
}
|
||||
|
||||
mSpanDepth--;
|
||||
mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out!
|
||||
|
@ -891,7 +907,8 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
// the floater.
|
||||
nsIAtom* frameType;
|
||||
aFrame->GetFrameType(&frameType);
|
||||
pfd->mIsNonEmptyTextFrame = 0;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
if (frameType) {
|
||||
if (frameType == nsLayoutAtoms::placeholderFrame) {
|
||||
nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame();
|
||||
|
@ -920,6 +937,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
}
|
||||
else if (frameType == nsLayoutAtoms::textFrame) {
|
||||
// Note non-empty text-frames for inline frame compatability hackery
|
||||
pfd->mIsTextFrame = PR_TRUE;
|
||||
if (metrics.width) {
|
||||
pfd->mIsNonEmptyTextFrame = PR_TRUE;
|
||||
}
|
||||
|
@ -1295,6 +1313,9 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
|||
pfd->mRelativePos = PR_FALSE;
|
||||
pfd->mAscent = aMetrics.ascent;
|
||||
pfd->mDescent = aMetrics.descent;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
|
||||
// Note: y value will be updated during vertical alignment
|
||||
aFrame->GetRect(pfd->mBounds);
|
||||
pfd->mCombinedArea = aMetrics.mCombinedArea;
|
||||
|
@ -1373,18 +1394,20 @@ nsLineLayout::VerticalAlignFrames(nsRect& aLineBoxResult,
|
|||
|
||||
// It's possible that the line-height isn't tall enough because of
|
||||
// the blocks minimum line-height.
|
||||
if (0 != lineHeight) {
|
||||
// If line contains nothing but empty boxes that have no height
|
||||
// then don't apply the min-line-height.
|
||||
//
|
||||
// Note: This is how we hide lines that contain nothing but
|
||||
// compressed whitespace.
|
||||
if (lineHeight < mMinLineHeight) {
|
||||
// Apply half of the extra space to the top of the line as top
|
||||
// leading
|
||||
nscoord extra = mMinLineHeight - lineHeight;
|
||||
baselineY += extra / 2;
|
||||
lineHeight = mMinLineHeight;
|
||||
if (!psd->mZeroEffectiveSpanBox) {
|
||||
if (0 != lineHeight) {
|
||||
// If line contains nothing but empty boxes that have no height
|
||||
// then don't apply the min-line-height.
|
||||
//
|
||||
// Note: This is how we hide lines that contain nothing but
|
||||
// compressed whitespace.
|
||||
if (lineHeight < mMinLineHeight) {
|
||||
// Apply half of the extra space to the top of the line as top
|
||||
// leading
|
||||
nscoord extra = mMinLineHeight - lineHeight;
|
||||
baselineY += extra / 2;
|
||||
lineHeight = mMinLineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1565,9 +1588,50 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
(const nsStyleStruct*&)parentFont);
|
||||
nsIRenderingContext* rc = mBlockReflowState->rendContext;
|
||||
rc->SetFont(parentFont->mFont);
|
||||
nsIFontMetrics* fm;
|
||||
rc->GetFontMetrics(fm);
|
||||
nsCOMPtr<nsIFontMetrics> fm;
|
||||
rc->GetFontMetrics(*getter_AddRefs(fm));
|
||||
|
||||
// Compute the span's mZeroEffectiveSpanBox flag. Pre-mode shuts
|
||||
// down most of this behavior.
|
||||
PRBool zeroEffectiveSpanBox = PR_FALSE;
|
||||
PRBool preMode = (mStyleText->mWhiteSpace == NS_STYLE_WHITESPACE_PRE) ||
|
||||
(mStyleText->mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP);
|
||||
if (!preMode && !InStrictMode() &&
|
||||
((psd == mRootSpan) ||
|
||||
((0 == parentPFD->mBorderPadding.top) &&
|
||||
(0 == parentPFD->mBorderPadding.right) &&
|
||||
(0 == parentPFD->mBorderPadding.bottom) &&
|
||||
(0 == parentPFD->mBorderPadding.left) &&
|
||||
(0 == parentPFD->mMargin.top) &&
|
||||
(0 == parentPFD->mMargin.right) &&
|
||||
(0 == parentPFD->mMargin.bottom) &&
|
||||
(0 == parentPFD->mMargin.left)))) {
|
||||
// This code handles an issue with compatability with non-css
|
||||
// conformant browsers. In particular, there are some cases
|
||||
// where the font-size and line-height for a span must be
|
||||
// ignored and instead the span must *act* as if it were zero
|
||||
// sized. In general, if the span contains any non-compressed
|
||||
// text or contains another span which contains non-compressed
|
||||
// text, then we don't use this logic.
|
||||
zeroEffectiveSpanBox = PR_TRUE;
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nsnull != pfd) {
|
||||
if (pfd->mIsNonEmptyTextFrame) {
|
||||
zeroEffectiveSpanBox = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
PerSpanData* frameSpan = pfd->mSpan;
|
||||
if (frameSpan) {
|
||||
if (!frameSpan->mZeroEffectiveSpanBox) {
|
||||
// Propogate prescence of non-empty text outward
|
||||
zeroEffectiveSpanBox = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pfd = pfd->mNext;
|
||||
}
|
||||
}
|
||||
psd->mZeroEffectiveSpanBox = zeroEffectiveSpanBox;
|
||||
|
||||
// Setup baselineY, minY, and maxY
|
||||
nscoord baselineY, minY, maxY;
|
||||
|
@ -1581,61 +1645,58 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
baselineY = minY = maxY = 0;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
nsFrame::ListTag(stdout, parentFrame);
|
||||
printf(": pass1 valign frames: topEdge=%d minLineHeight=%d\n",
|
||||
mTopEdge, mMinLineHeight);
|
||||
#endif
|
||||
}
|
||||
else if (0 != parentPFD->mBounds.height) {
|
||||
// Compute the logical height for this span. Also compute the top
|
||||
// leading.
|
||||
nscoord logicalHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, parentFrame);
|
||||
nscoord contentHeight = parentPFD->mBounds.height -
|
||||
parentPFD->mBorderPadding.top - parentPFD->mBorderPadding.bottom;
|
||||
if (logicalHeight > 0) {
|
||||
nscoord leading = logicalHeight - contentHeight;
|
||||
psd->mTopLeading = leading / 2;
|
||||
psd->mBottomLeading = leading - psd->mTopLeading;
|
||||
}
|
||||
else {
|
||||
psd->mTopLeading = 0;
|
||||
psd->mBottomLeading = 0;
|
||||
logicalHeight = contentHeight;
|
||||
}
|
||||
psd->mLogicalHeight = logicalHeight;
|
||||
|
||||
// The initial values for the min and max Y values are in the spans
|
||||
// coordinate space, and cover the logical height of the span. If
|
||||
// there are child frames in this span that stick out of this area
|
||||
// then the minY and maxY are updated by the amount of logical
|
||||
// height that is outside this range.
|
||||
minY = parentPFD->mBorderPadding.top - psd->mTopLeading;
|
||||
maxY = minY + psd->mLogicalHeight;
|
||||
|
||||
// This is the distance from the top edge of the parents visual
|
||||
// box to the baseline.
|
||||
nscoord parentAscent;
|
||||
fm->GetMaxAscent(parentAscent);
|
||||
baselineY = parentAscent + parentPFD->mBorderPadding.top;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
nsFrame::ListTag(stdout, parentFrame);
|
||||
printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d\n",
|
||||
baselineY, logicalHeight, psd->mTopLeading,
|
||||
parentPFD->mBounds.height,
|
||||
parentPFD->mBorderPadding.top, parentPFD->mBorderPadding.bottom);
|
||||
printf(": pass1 valign frames: topEdge=%d minLineHeight=%d zeroEffectiveSpanBox=%s\n",
|
||||
mTopEdge, mMinLineHeight,
|
||||
zeroEffectiveSpanBox ? "yes" : "no");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// When a span container is zero height it means that all of its
|
||||
// kids are zero height as well.
|
||||
baselineY = minY = maxY = 0;
|
||||
psd->mTopLeading = 0;
|
||||
psd->mBottomLeading = 0;
|
||||
psd->mLogicalHeight = 0;
|
||||
if (zeroEffectiveSpanBox) {
|
||||
// When the span-box is to be ignored, zero out all the initial
|
||||
// values so that the span doesn't impact the final line
|
||||
// height. The contents of the span can impact the final line
|
||||
// height.
|
||||
psd->mTopLeading = 0;
|
||||
psd->mBottomLeading = 0;
|
||||
psd->mLogicalHeight = 0;
|
||||
parentPFD->mAscent = 0;
|
||||
parentPFD->mBounds.height = 0;
|
||||
baselineY = minY = maxY = 0;
|
||||
}
|
||||
else {
|
||||
// Compute the logical height for this span. The logical height
|
||||
// is based on the line-height value, not the font-size. Also
|
||||
// compute the top leading.
|
||||
nscoord logicalHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, rc, parentFrame);
|
||||
nscoord contentHeight = parentPFD->mBounds.height -
|
||||
parentPFD->mBorderPadding.top - parentPFD->mBorderPadding.bottom;
|
||||
nscoord leading = logicalHeight - contentHeight;
|
||||
psd->mTopLeading = leading / 2;
|
||||
psd->mBottomLeading = leading - psd->mTopLeading;
|
||||
psd->mLogicalHeight = logicalHeight;
|
||||
|
||||
// The initial values for the min and max Y values are in the spans
|
||||
// coordinate space, and cover the logical height of the span. If
|
||||
// there are child frames in this span that stick out of this area
|
||||
// then the minY and maxY are updated by the amount of logical
|
||||
// height that is outside this range.
|
||||
minY = parentPFD->mBorderPadding.top - psd->mTopLeading;
|
||||
maxY = minY + psd->mLogicalHeight;
|
||||
|
||||
// This is the distance from the top edge of the parents visual
|
||||
// box to the baseline. The span already computed this for us,
|
||||
// so just use it.
|
||||
baselineY = parentPFD->mAscent;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ==> [empty line]\n");
|
||||
nsFrame::ListTag(stdout, parentFrame);
|
||||
printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d zeroEffectiveSpanBox=%s\n",
|
||||
baselineY, psd->mLogicalHeight, psd->mTopLeading,
|
||||
parentPFD->mBounds.height,
|
||||
parentPFD->mBorderPadding.top, parentPFD->mBorderPadding.bottom,
|
||||
zeroEffectiveSpanBox ? "yes" : "no");
|
||||
#endif
|
||||
// return;
|
||||
}
|
||||
|
||||
nscoord maxTopBoxHeight = 0;
|
||||
|
@ -1671,6 +1732,16 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
nsFrame::ListTag(stdout, frame);
|
||||
printf("\n");
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(": verticalAlignUnit=%d (enum == %d)\n",
|
||||
verticalAlignUnit,
|
||||
((eStyleUnit_Enumerated == verticalAlignUnit)
|
||||
? textStyle->mVerticalAlign.GetIntValue()
|
||||
: -1));
|
||||
#endif
|
||||
|
||||
PRUint8 verticalAlignEnum;
|
||||
nscoord parentAscent, parentDescent, parentXHeight;
|
||||
nscoord parentSuperscript, parentSubscript;
|
||||
|
@ -1821,7 +1892,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
// Similar to a length value (eStyleUnit_Coord) except that the
|
||||
// percentage is a function of the elements line-height value.
|
||||
elementLineHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, frame);
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, rc, frame);
|
||||
percentOffset = nscoord(
|
||||
textStyle->mVerticalAlign.GetPercentValue() * elementLineHeight
|
||||
);
|
||||
|
@ -1837,39 +1908,84 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
break;
|
||||
}
|
||||
|
||||
// Update minY/maxY for frames that we just placed
|
||||
// Update minY/maxY for frames that we just placed. Do not factor
|
||||
// text into the equation.
|
||||
if (pfd->mVerticalAlign == VALIGN_OTHER) {
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
// plus their already computed min-Y and max-Y values for
|
||||
// computing yTop and yBottom.
|
||||
yTop = pfd->mBounds.y + frameSpan->mMinY;
|
||||
yBottom = pfd->mBounds.y + frameSpan->mMaxY;
|
||||
}
|
||||
else {
|
||||
yTop = pfd->mBounds.y - pfd->mMargin.top;
|
||||
yBottom = yTop + logicalHeight;
|
||||
}
|
||||
if (yTop < minY) minY = yTop;
|
||||
if (yBottom > maxY) maxY = yBottom;
|
||||
// Text frames do not contribute to the min/max Y values for the
|
||||
// line (instead their parent frame's font-size contributes).
|
||||
if (!pfd->mIsTextFrame) {
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
// plus their already computed min-Y and max-Y values for
|
||||
// computing yTop and yBottom.
|
||||
yTop = pfd->mBounds.y + frameSpan->mMinY;
|
||||
yBottom = pfd->mBounds.y + frameSpan->mMaxY;
|
||||
}
|
||||
else {
|
||||
yTop = pfd->mBounds.y - pfd->mMargin.top;
|
||||
yBottom = yTop + logicalHeight;
|
||||
}
|
||||
if (yTop < minY) minY = yTop;
|
||||
if (yBottom > maxY) maxY = yBottom;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(": raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
|
||||
pfd->mAscent, pfd->mDescent, pfd->mBounds.height,
|
||||
pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
|
||||
logicalHeight,
|
||||
pfd->mSpan ? topLeading : 0,
|
||||
pfd->mBounds.y, minY, maxY);
|
||||
printf(" raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
|
||||
pfd->mAscent, pfd->mDescent, pfd->mBounds.height,
|
||||
pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
|
||||
logicalHeight,
|
||||
pfd->mSpan ? topLeading : 0,
|
||||
pfd->mBounds.y, minY, maxY);
|
||||
#endif
|
||||
}
|
||||
if (psd != mRootSpan) {
|
||||
frame->SetRect(pfd->mBounds);
|
||||
}
|
||||
}
|
||||
pfd = pfd->mNext;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
|
||||
// Factor in the minimum line-height when handling the root-span for
|
||||
// the block.
|
||||
if (psd == mRootSpan) {
|
||||
// If this span's width is non-zero then it can't possibly be a
|
||||
// line that contains nothing but zero width items. Therefore we
|
||||
// should factor in the block element's minimum line-height (as
|
||||
// defined in section 10.8.1 of the css2 spec).
|
||||
if (psd->mZeroEffectiveSpanBox) {
|
||||
// Leave minY/maxY values untouched
|
||||
}
|
||||
else {
|
||||
if ((psd->mX != psd->mLeftEdge) || preMode) {
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ==> adjusting min/maxY: currentValues: %d,%d", minY, maxY);
|
||||
#endif
|
||||
nscoord minimumLineHeight = mMinLineHeight;
|
||||
nscoord fontAscent, fontHeight;
|
||||
fm->GetMaxAscent(fontAscent);
|
||||
fm->GetHeight(fontHeight);
|
||||
nscoord leading = minimumLineHeight - fontHeight;
|
||||
nscoord yTop = -fontAscent - leading/2;
|
||||
nscoord yBottom = yTop + minimumLineHeight;
|
||||
if (yTop < minY) minY = yTop;
|
||||
if (yBottom > maxY) maxY = yBottom;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" new values: %d,%d\n", minY, maxY);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// XXX issues:
|
||||
// [1] BR's on empty lines stop working
|
||||
// [2] May not honor css2's notion of handling empty elements
|
||||
// [3] blank lines in a pre-section ("\n") (handled with preMode)
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ==> zapping min/maxY: currentValues: %d,%d newValues: 0,0\n",
|
||||
minY, maxY);
|
||||
#endif
|
||||
minY = maxY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
psd->mMinY = minY;
|
||||
psd->mMaxY = maxY;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
|
|
|
@ -75,8 +75,7 @@ public:
|
|||
nscoord aRightEdge);
|
||||
|
||||
void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult,
|
||||
nsSize* aMaxElementSize,
|
||||
PRBool* aHaveAtLeastOneNonEmptyTextFrame);
|
||||
nsSize* aMaxElementSize);
|
||||
|
||||
PRBool InStrictMode();
|
||||
|
||||
|
@ -272,6 +271,7 @@ protected:
|
|||
|
||||
// Other state we use
|
||||
PRUint8 mVerticalAlign;
|
||||
PRBool mIsTextFrame;
|
||||
PRBool mIsNonEmptyTextFrame;
|
||||
};
|
||||
PerFrameData mFrameDataBuf[NS_LINELAYOUT_NUM_FRAMES];
|
||||
|
@ -294,6 +294,7 @@ public:
|
|||
PRBool mNoWrap;
|
||||
PRUint8 mDirection;
|
||||
PRBool mChangedFrameDirection;
|
||||
PRBool mZeroEffectiveSpanBox;
|
||||
|
||||
nscoord mLeftEdge;
|
||||
nscoord mX;
|
||||
|
|
|
@ -180,6 +180,27 @@ nsLineLayout::~nsLineLayout()
|
|||
PRBool
|
||||
nsLineLayout::InStrictMode()
|
||||
{
|
||||
// XXX For now this is always part of the build until harishd lands
|
||||
// the dtd auto-detect code...
|
||||
#if 1
|
||||
static PRBool forceStrictMode = PR_FALSE;
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
if (getenv("GECKO_FORCE_STRICT_MODE")) {
|
||||
forceStrictMode = PR_TRUE;
|
||||
}
|
||||
firstTime = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (forceStrictMode) {
|
||||
mKnowStrictMode = PR_TRUE;
|
||||
mInStrictMode = PR_TRUE;
|
||||
return mInStrictMode;
|
||||
}
|
||||
#endif
|
||||
if (!mKnowStrictMode) {
|
||||
mKnowStrictMode = PR_TRUE;
|
||||
mInStrictMode = PR_TRUE;
|
||||
|
@ -482,6 +503,7 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
|||
psd->mLeftEdge = aLeftEdge;
|
||||
psd->mX = aLeftEdge;
|
||||
psd->mRightEdge = aRightEdge;
|
||||
psd->mZeroEffectiveSpanBox = PR_FALSE;
|
||||
|
||||
const nsStyleText* styleText;
|
||||
aSpanReflowState->frame->GetStyleData(eStyleStruct_Text,
|
||||
|
@ -508,8 +530,7 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
|||
void
|
||||
nsLineLayout::EndSpan(nsIFrame* aFrame,
|
||||
nsSize& aSizeResult,
|
||||
nsSize* aMaxElementSize,
|
||||
PRBool* aHaveAtLeastOneNonEmptyTextFrame)
|
||||
nsSize* aMaxElementSize)
|
||||
{
|
||||
NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span");
|
||||
#ifdef NOISY_REFLOW
|
||||
|
@ -522,13 +543,11 @@ nsLineLayout::EndSpan(nsIFrame* aFrame,
|
|||
nscoord maxHeight = 0;
|
||||
nscoord maxElementWidth = 0;
|
||||
nscoord maxElementHeight = 0;
|
||||
PRBool haveAtLeastOneNonEmptyTextFrame = PR_FALSE;
|
||||
if (nsnull != psd->mLastFrame) {
|
||||
width = psd->mX - psd->mLeftEdge;
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nsnull != pfd) {
|
||||
if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height;
|
||||
if (pfd->mIsNonEmptyTextFrame) haveAtLeastOneNonEmptyTextFrame = PR_TRUE;
|
||||
|
||||
// Compute max-element-size if necessary
|
||||
if (aMaxElementSize) {
|
||||
|
@ -560,9 +579,6 @@ nsLineLayout::EndSpan(nsIFrame* aFrame,
|
|||
aMaxElementSize->height = maxElementHeight;
|
||||
}
|
||||
}
|
||||
if (aHaveAtLeastOneNonEmptyTextFrame) {
|
||||
*aHaveAtLeastOneNonEmptyTextFrame = haveAtLeastOneNonEmptyTextFrame;
|
||||
}
|
||||
|
||||
mSpanDepth--;
|
||||
mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out!
|
||||
|
@ -891,7 +907,8 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
// the floater.
|
||||
nsIAtom* frameType;
|
||||
aFrame->GetFrameType(&frameType);
|
||||
pfd->mIsNonEmptyTextFrame = 0;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
if (frameType) {
|
||||
if (frameType == nsLayoutAtoms::placeholderFrame) {
|
||||
nsIFrame* outOfFlowFrame = ((nsPlaceholderFrame*)aFrame)->GetOutOfFlowFrame();
|
||||
|
@ -920,6 +937,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
}
|
||||
else if (frameType == nsLayoutAtoms::textFrame) {
|
||||
// Note non-empty text-frames for inline frame compatability hackery
|
||||
pfd->mIsTextFrame = PR_TRUE;
|
||||
if (metrics.width) {
|
||||
pfd->mIsNonEmptyTextFrame = PR_TRUE;
|
||||
}
|
||||
|
@ -1295,6 +1313,9 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
|||
pfd->mRelativePos = PR_FALSE;
|
||||
pfd->mAscent = aMetrics.ascent;
|
||||
pfd->mDescent = aMetrics.descent;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
|
||||
// Note: y value will be updated during vertical alignment
|
||||
aFrame->GetRect(pfd->mBounds);
|
||||
pfd->mCombinedArea = aMetrics.mCombinedArea;
|
||||
|
@ -1373,18 +1394,20 @@ nsLineLayout::VerticalAlignFrames(nsRect& aLineBoxResult,
|
|||
|
||||
// It's possible that the line-height isn't tall enough because of
|
||||
// the blocks minimum line-height.
|
||||
if (0 != lineHeight) {
|
||||
// If line contains nothing but empty boxes that have no height
|
||||
// then don't apply the min-line-height.
|
||||
//
|
||||
// Note: This is how we hide lines that contain nothing but
|
||||
// compressed whitespace.
|
||||
if (lineHeight < mMinLineHeight) {
|
||||
// Apply half of the extra space to the top of the line as top
|
||||
// leading
|
||||
nscoord extra = mMinLineHeight - lineHeight;
|
||||
baselineY += extra / 2;
|
||||
lineHeight = mMinLineHeight;
|
||||
if (!psd->mZeroEffectiveSpanBox) {
|
||||
if (0 != lineHeight) {
|
||||
// If line contains nothing but empty boxes that have no height
|
||||
// then don't apply the min-line-height.
|
||||
//
|
||||
// Note: This is how we hide lines that contain nothing but
|
||||
// compressed whitespace.
|
||||
if (lineHeight < mMinLineHeight) {
|
||||
// Apply half of the extra space to the top of the line as top
|
||||
// leading
|
||||
nscoord extra = mMinLineHeight - lineHeight;
|
||||
baselineY += extra / 2;
|
||||
lineHeight = mMinLineHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1565,9 +1588,50 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
(const nsStyleStruct*&)parentFont);
|
||||
nsIRenderingContext* rc = mBlockReflowState->rendContext;
|
||||
rc->SetFont(parentFont->mFont);
|
||||
nsIFontMetrics* fm;
|
||||
rc->GetFontMetrics(fm);
|
||||
nsCOMPtr<nsIFontMetrics> fm;
|
||||
rc->GetFontMetrics(*getter_AddRefs(fm));
|
||||
|
||||
// Compute the span's mZeroEffectiveSpanBox flag. Pre-mode shuts
|
||||
// down most of this behavior.
|
||||
PRBool zeroEffectiveSpanBox = PR_FALSE;
|
||||
PRBool preMode = (mStyleText->mWhiteSpace == NS_STYLE_WHITESPACE_PRE) ||
|
||||
(mStyleText->mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP);
|
||||
if (!preMode && !InStrictMode() &&
|
||||
((psd == mRootSpan) ||
|
||||
((0 == parentPFD->mBorderPadding.top) &&
|
||||
(0 == parentPFD->mBorderPadding.right) &&
|
||||
(0 == parentPFD->mBorderPadding.bottom) &&
|
||||
(0 == parentPFD->mBorderPadding.left) &&
|
||||
(0 == parentPFD->mMargin.top) &&
|
||||
(0 == parentPFD->mMargin.right) &&
|
||||
(0 == parentPFD->mMargin.bottom) &&
|
||||
(0 == parentPFD->mMargin.left)))) {
|
||||
// This code handles an issue with compatability with non-css
|
||||
// conformant browsers. In particular, there are some cases
|
||||
// where the font-size and line-height for a span must be
|
||||
// ignored and instead the span must *act* as if it were zero
|
||||
// sized. In general, if the span contains any non-compressed
|
||||
// text or contains another span which contains non-compressed
|
||||
// text, then we don't use this logic.
|
||||
zeroEffectiveSpanBox = PR_TRUE;
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nsnull != pfd) {
|
||||
if (pfd->mIsNonEmptyTextFrame) {
|
||||
zeroEffectiveSpanBox = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
PerSpanData* frameSpan = pfd->mSpan;
|
||||
if (frameSpan) {
|
||||
if (!frameSpan->mZeroEffectiveSpanBox) {
|
||||
// Propogate prescence of non-empty text outward
|
||||
zeroEffectiveSpanBox = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pfd = pfd->mNext;
|
||||
}
|
||||
}
|
||||
psd->mZeroEffectiveSpanBox = zeroEffectiveSpanBox;
|
||||
|
||||
// Setup baselineY, minY, and maxY
|
||||
nscoord baselineY, minY, maxY;
|
||||
|
@ -1581,61 +1645,58 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
baselineY = minY = maxY = 0;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
nsFrame::ListTag(stdout, parentFrame);
|
||||
printf(": pass1 valign frames: topEdge=%d minLineHeight=%d\n",
|
||||
mTopEdge, mMinLineHeight);
|
||||
#endif
|
||||
}
|
||||
else if (0 != parentPFD->mBounds.height) {
|
||||
// Compute the logical height for this span. Also compute the top
|
||||
// leading.
|
||||
nscoord logicalHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, parentFrame);
|
||||
nscoord contentHeight = parentPFD->mBounds.height -
|
||||
parentPFD->mBorderPadding.top - parentPFD->mBorderPadding.bottom;
|
||||
if (logicalHeight > 0) {
|
||||
nscoord leading = logicalHeight - contentHeight;
|
||||
psd->mTopLeading = leading / 2;
|
||||
psd->mBottomLeading = leading - psd->mTopLeading;
|
||||
}
|
||||
else {
|
||||
psd->mTopLeading = 0;
|
||||
psd->mBottomLeading = 0;
|
||||
logicalHeight = contentHeight;
|
||||
}
|
||||
psd->mLogicalHeight = logicalHeight;
|
||||
|
||||
// The initial values for the min and max Y values are in the spans
|
||||
// coordinate space, and cover the logical height of the span. If
|
||||
// there are child frames in this span that stick out of this area
|
||||
// then the minY and maxY are updated by the amount of logical
|
||||
// height that is outside this range.
|
||||
minY = parentPFD->mBorderPadding.top - psd->mTopLeading;
|
||||
maxY = minY + psd->mLogicalHeight;
|
||||
|
||||
// This is the distance from the top edge of the parents visual
|
||||
// box to the baseline.
|
||||
nscoord parentAscent;
|
||||
fm->GetMaxAscent(parentAscent);
|
||||
baselineY = parentAscent + parentPFD->mBorderPadding.top;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
nsFrame::ListTag(stdout, parentFrame);
|
||||
printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d\n",
|
||||
baselineY, logicalHeight, psd->mTopLeading,
|
||||
parentPFD->mBounds.height,
|
||||
parentPFD->mBorderPadding.top, parentPFD->mBorderPadding.bottom);
|
||||
printf(": pass1 valign frames: topEdge=%d minLineHeight=%d zeroEffectiveSpanBox=%s\n",
|
||||
mTopEdge, mMinLineHeight,
|
||||
zeroEffectiveSpanBox ? "yes" : "no");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// When a span container is zero height it means that all of its
|
||||
// kids are zero height as well.
|
||||
baselineY = minY = maxY = 0;
|
||||
psd->mTopLeading = 0;
|
||||
psd->mBottomLeading = 0;
|
||||
psd->mLogicalHeight = 0;
|
||||
if (zeroEffectiveSpanBox) {
|
||||
// When the span-box is to be ignored, zero out all the initial
|
||||
// values so that the span doesn't impact the final line
|
||||
// height. The contents of the span can impact the final line
|
||||
// height.
|
||||
psd->mTopLeading = 0;
|
||||
psd->mBottomLeading = 0;
|
||||
psd->mLogicalHeight = 0;
|
||||
parentPFD->mAscent = 0;
|
||||
parentPFD->mBounds.height = 0;
|
||||
baselineY = minY = maxY = 0;
|
||||
}
|
||||
else {
|
||||
// Compute the logical height for this span. The logical height
|
||||
// is based on the line-height value, not the font-size. Also
|
||||
// compute the top leading.
|
||||
nscoord logicalHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, rc, parentFrame);
|
||||
nscoord contentHeight = parentPFD->mBounds.height -
|
||||
parentPFD->mBorderPadding.top - parentPFD->mBorderPadding.bottom;
|
||||
nscoord leading = logicalHeight - contentHeight;
|
||||
psd->mTopLeading = leading / 2;
|
||||
psd->mBottomLeading = leading - psd->mTopLeading;
|
||||
psd->mLogicalHeight = logicalHeight;
|
||||
|
||||
// The initial values for the min and max Y values are in the spans
|
||||
// coordinate space, and cover the logical height of the span. If
|
||||
// there are child frames in this span that stick out of this area
|
||||
// then the minY and maxY are updated by the amount of logical
|
||||
// height that is outside this range.
|
||||
minY = parentPFD->mBorderPadding.top - psd->mTopLeading;
|
||||
maxY = minY + psd->mLogicalHeight;
|
||||
|
||||
// This is the distance from the top edge of the parents visual
|
||||
// box to the baseline. The span already computed this for us,
|
||||
// so just use it.
|
||||
baselineY = parentPFD->mAscent;
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ==> [empty line]\n");
|
||||
nsFrame::ListTag(stdout, parentFrame);
|
||||
printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d zeroEffectiveSpanBox=%s\n",
|
||||
baselineY, psd->mLogicalHeight, psd->mTopLeading,
|
||||
parentPFD->mBounds.height,
|
||||
parentPFD->mBorderPadding.top, parentPFD->mBorderPadding.bottom,
|
||||
zeroEffectiveSpanBox ? "yes" : "no");
|
||||
#endif
|
||||
// return;
|
||||
}
|
||||
|
||||
nscoord maxTopBoxHeight = 0;
|
||||
|
@ -1671,6 +1732,16 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
nsFrame::ListTag(stdout, frame);
|
||||
printf("\n");
|
||||
}
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(": verticalAlignUnit=%d (enum == %d)\n",
|
||||
verticalAlignUnit,
|
||||
((eStyleUnit_Enumerated == verticalAlignUnit)
|
||||
? textStyle->mVerticalAlign.GetIntValue()
|
||||
: -1));
|
||||
#endif
|
||||
|
||||
PRUint8 verticalAlignEnum;
|
||||
nscoord parentAscent, parentDescent, parentXHeight;
|
||||
nscoord parentSuperscript, parentSubscript;
|
||||
|
@ -1821,7 +1892,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
// Similar to a length value (eStyleUnit_Coord) except that the
|
||||
// percentage is a function of the elements line-height value.
|
||||
elementLineHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, frame);
|
||||
nsHTMLReflowState::CalcLineHeight(mPresContext, rc, frame);
|
||||
percentOffset = nscoord(
|
||||
textStyle->mVerticalAlign.GetPercentValue() * elementLineHeight
|
||||
);
|
||||
|
@ -1837,39 +1908,84 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
break;
|
||||
}
|
||||
|
||||
// Update minY/maxY for frames that we just placed
|
||||
// Update minY/maxY for frames that we just placed. Do not factor
|
||||
// text into the equation.
|
||||
if (pfd->mVerticalAlign == VALIGN_OTHER) {
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
// plus their already computed min-Y and max-Y values for
|
||||
// computing yTop and yBottom.
|
||||
yTop = pfd->mBounds.y + frameSpan->mMinY;
|
||||
yBottom = pfd->mBounds.y + frameSpan->mMaxY;
|
||||
}
|
||||
else {
|
||||
yTop = pfd->mBounds.y - pfd->mMargin.top;
|
||||
yBottom = yTop + logicalHeight;
|
||||
}
|
||||
if (yTop < minY) minY = yTop;
|
||||
if (yBottom > maxY) maxY = yBottom;
|
||||
// Text frames do not contribute to the min/max Y values for the
|
||||
// line (instead their parent frame's font-size contributes).
|
||||
if (!pfd->mIsTextFrame) {
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
// plus their already computed min-Y and max-Y values for
|
||||
// computing yTop and yBottom.
|
||||
yTop = pfd->mBounds.y + frameSpan->mMinY;
|
||||
yBottom = pfd->mBounds.y + frameSpan->mMaxY;
|
||||
}
|
||||
else {
|
||||
yTop = pfd->mBounds.y - pfd->mMargin.top;
|
||||
yBottom = yTop + logicalHeight;
|
||||
}
|
||||
if (yTop < minY) minY = yTop;
|
||||
if (yBottom > maxY) maxY = yBottom;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ");
|
||||
nsFrame::ListTag(stdout, frame);
|
||||
printf(": raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
|
||||
pfd->mAscent, pfd->mDescent, pfd->mBounds.height,
|
||||
pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
|
||||
logicalHeight,
|
||||
pfd->mSpan ? topLeading : 0,
|
||||
pfd->mBounds.y, minY, maxY);
|
||||
printf(" raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n",
|
||||
pfd->mAscent, pfd->mDescent, pfd->mBounds.height,
|
||||
pfd->mBorderPadding.top, pfd->mBorderPadding.bottom,
|
||||
logicalHeight,
|
||||
pfd->mSpan ? topLeading : 0,
|
||||
pfd->mBounds.y, minY, maxY);
|
||||
#endif
|
||||
}
|
||||
if (psd != mRootSpan) {
|
||||
frame->SetRect(pfd->mBounds);
|
||||
}
|
||||
}
|
||||
pfd = pfd->mNext;
|
||||
}
|
||||
NS_RELEASE(fm);
|
||||
|
||||
// Factor in the minimum line-height when handling the root-span for
|
||||
// the block.
|
||||
if (psd == mRootSpan) {
|
||||
// If this span's width is non-zero then it can't possibly be a
|
||||
// line that contains nothing but zero width items. Therefore we
|
||||
// should factor in the block element's minimum line-height (as
|
||||
// defined in section 10.8.1 of the css2 spec).
|
||||
if (psd->mZeroEffectiveSpanBox) {
|
||||
// Leave minY/maxY values untouched
|
||||
}
|
||||
else {
|
||||
if ((psd->mX != psd->mLeftEdge) || preMode) {
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ==> adjusting min/maxY: currentValues: %d,%d", minY, maxY);
|
||||
#endif
|
||||
nscoord minimumLineHeight = mMinLineHeight;
|
||||
nscoord fontAscent, fontHeight;
|
||||
fm->GetMaxAscent(fontAscent);
|
||||
fm->GetHeight(fontHeight);
|
||||
nscoord leading = minimumLineHeight - fontHeight;
|
||||
nscoord yTop = -fontAscent - leading/2;
|
||||
nscoord yBottom = yTop + minimumLineHeight;
|
||||
if (yTop < minY) minY = yTop;
|
||||
if (yBottom > maxY) maxY = yBottom;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" new values: %d,%d\n", minY, maxY);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// XXX issues:
|
||||
// [1] BR's on empty lines stop working
|
||||
// [2] May not honor css2's notion of handling empty elements
|
||||
// [3] blank lines in a pre-section ("\n") (handled with preMode)
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
printf(" ==> zapping min/maxY: currentValues: %d,%d newValues: 0,0\n",
|
||||
minY, maxY);
|
||||
#endif
|
||||
minY = maxY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
psd->mMinY = minY;
|
||||
psd->mMaxY = maxY;
|
||||
#ifdef NOISY_VERTICAL_ALIGN
|
||||
|
|
|
@ -75,8 +75,7 @@ public:
|
|||
nscoord aRightEdge);
|
||||
|
||||
void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult,
|
||||
nsSize* aMaxElementSize,
|
||||
PRBool* aHaveAtLeastOneNonEmptyTextFrame);
|
||||
nsSize* aMaxElementSize);
|
||||
|
||||
PRBool InStrictMode();
|
||||
|
||||
|
@ -272,6 +271,7 @@ protected:
|
|||
|
||||
// Other state we use
|
||||
PRUint8 mVerticalAlign;
|
||||
PRBool mIsTextFrame;
|
||||
PRBool mIsNonEmptyTextFrame;
|
||||
};
|
||||
PerFrameData mFrameDataBuf[NS_LINELAYOUT_NUM_FRAMES];
|
||||
|
@ -294,6 +294,7 @@ public:
|
|||
PRBool mNoWrap;
|
||||
PRUint8 mDirection;
|
||||
PRBool mChangedFrameDirection;
|
||||
PRBool mZeroEffectiveSpanBox;
|
||||
|
||||
nscoord mLeftEdge;
|
||||
nscoord mX;
|
||||
|
|
Загрузка…
Ссылка в новой задаче