diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index 14739e78cd70..6b6151663b28 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -842,6 +842,29 @@ nsBidiPresUtils::IsLeftOrRightMost(nsIFrame* aFrame, (isLTR ? !firstFrameState->mHasContOnNextLines : !firstFrameState->mHasContOnPrevLines); + if ((aIsLeftMost || aIsRightMost) && + (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) { + // For ib splits, don't treat the first part as endmost or the + // last part as startmost. + if (nsLayoutUtils::FrameIsInFirstPartOfIBSplit(aFrame)) { + // We are not endmost + if (isLTR) { + aIsRightMost = PR_FALSE; + } else { + aIsLeftMost = PR_FALSE; + } + } else { + NS_ASSERTION(nsLayoutUtils::FrameIsInLastPartOfIBSplit(aFrame), + "How did that happen?"); + // We are not startmost + if (isLTR) { + aIsLeftMost = PR_FALSE; + } else { + aIsRightMost = PR_FALSE; + } + } + } + // Reduce number of remaining frames of the continuation chain on the line. firstFrameState->mFrameCount--; } @@ -964,7 +987,8 @@ nsBidiPresUtils::RepositionInlineFrames(nsIFrame* aFirstChild) const // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines // have been reflowed, which is required for GetUsedMargin/Border/Padding nsMargin margin = aFirstChild->GetUsedMargin(); - if (!aFirstChild->GetPrevContinuation()) + if (!aFirstChild->GetPrevContinuation() && + !nsLayoutUtils::FrameIsInLastPartOfIBSplit(aFirstChild)) leftSpace = isLTR ? margin.left : margin.right; nscoord left = aFirstChild->GetPosition().x - leftSpace; diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 0c4791afc1a2..41cf17fa2c5d 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -499,9 +499,9 @@ SetFrameIsSpecial(nsIFrame* aFrame, nsIFrame* aSpecialSibling) } if (aSpecialSibling) { - // We should be the first-in-flow - NS_ASSERTION(!aFrame->GetPrevInFlow(), - "assigning special sibling to other than first-in-flow!"); + // We should be the first continuation + NS_ASSERTION(!aFrame->GetPrevContinuation(), + "assigning special sibling to other than first continuation!"); // Store the "special sibling" (if we were given one) with the // first frame in the flow. diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index c853fc78b857..ea2a5563a39d 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1004,6 +1004,26 @@ public: * @param aFrame The nsIFrame object, which uses text fragment data. */ static nsTextFragment* GetTextFragmentForPrinting(const nsIFrame* aFrame); + + /** + * Return whether aFrame is an inline frame in the first part of an {ib} + * split. + */ + static PRBool FrameIsInFirstPartOfIBSplit(const nsIFrame* aFrame) { + return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) && + !aFrame->GetFirstContinuation()-> + GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling); + } + + /** + * Return whether aFrame is an inline frame in the last part of an {ib} + * split. + */ + static PRBool FrameIsInLastPartOfIBSplit(const nsIFrame* aFrame) { + return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) && + !aFrame->GetFirstContinuation()-> + GetProperty(nsGkAtoms::IBSplitSpecialSibling); + } }; class nsAutoDisableGetUsedXAssertions diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 9bcb3d1fa766..3b8a7c27fb09 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -1,3 +1,4 @@ + /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -410,7 +411,10 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, nsLineLayout* lineLayout = aReflowState.mLineLayout; PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection); nscoord leftEdge = 0; - if (nsnull == GetPrevContinuation()) { + // Don't offset by our start borderpadding if we have a prev continuation or + // if we're in the last part of an {ib} split. + if (!GetPrevContinuation() && + !nsLayoutUtils::FrameIsInLastPartOfIBSplit(this)) { leftEdge = ltr ? aReflowState.mComputedBorderPadding.left : aReflowState.mComputedBorderPadding.right; } @@ -557,12 +561,28 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, // whitespace in an inline element don't affect the line-height. aMetrics.width = lineLayout->EndSpan(this); - // Compute final width - if (nsnull == GetPrevContinuation()) { + // Compute final width. + + // Make sure to not include our start border and padding if we have a prev + // continuation or if we're in the last part of an {ib} split. + if (!GetPrevContinuation() && + !nsLayoutUtils::FrameIsInLastPartOfIBSplit(this)) { aMetrics.width += ltr ? aReflowState.mComputedBorderPadding.left : aReflowState.mComputedBorderPadding.right; } - if (NS_FRAME_IS_COMPLETE(aStatus) && (!GetNextContinuation() || GetNextInFlow())) { + + /* + * We want to only apply the end border and padding if we're the last + * continuation and not in the first part of an {ib} split. To be the last + * continuation we have to be complete (so that we won't get a next-in-flow) + * and have no non-fluid continuations. + * + * FIXME the check for non-fluid continuations is not quite correct in the + * code (though the comment above describes it correctly); see bug 492469. + */ + if (NS_FRAME_IS_COMPLETE(aStatus) && + (!GetNextContinuation() || GetNextInFlow()) && + !nsLayoutUtils::FrameIsInFirstPartOfIBSplit(this)) { aMetrics.width += ltr ? aReflowState.mComputedBorderPadding.right : aReflowState.mComputedBorderPadding.left; } @@ -791,6 +811,28 @@ nsInlineFrame::GetSkipSides() const // edge border render. } } + + if (GetStateBits() & NS_FRAME_IS_SPECIAL) { + // The first part of an {ib} split should always skip the "end" side (as + // determined by this frame's direction) and the last part of such a split + // should alwas skip the "start" side. But figuring out which part of the + // split we are involves getting our first continuation, which might be + // expensive. So don't bother if we already have the relevant bits set. + PRBool ltr = (NS_STYLE_DIRECTION_LTR == GetStyleVisibility()->mDirection); + PRIntn startBit = (1 << (ltr ? NS_SIDE_LEFT : NS_SIDE_RIGHT)); + PRIntn endBit = (1 << (ltr ? NS_SIDE_RIGHT : NS_SIDE_LEFT)); + if (((startBit | endBit) & skip) != (startBit | endBit)) { + // We're missing one of the skip bits, so check whether we need to set it. + if (nsLayoutUtils::FrameIsInFirstPartOfIBSplit(this)) { + skip |= endBit; + } else { + NS_ASSERTION(nsLayoutUtils::FrameIsInLastPartOfIBSplit(this), + "How did that happen?"); + skip |= startBit; + } + } + } + return skip; } diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 54af04469213..f27ff4a4522e 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -1089,8 +1089,13 @@ nsLineLayout::ApplyStartMargin(PerFrameData* pfd, // XXXwaterson probably not the right way to get this; e.g., embeddings, etc. PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection); - // Only apply start-margin on the first-in flow for inline frames - if (pfd->mFrame->GetPrevContinuation()) { + // Only apply start-margin on the first-in flow for inline frames, + // and make sure to not apply it to the last part of an ib split. + // Note that the ib special sibling annotations only live on the + // first continuation, but we don't want to apply the start margin + // for later continuations anyway. + if (pfd->mFrame->GetPrevContinuation() || + nsLayoutUtils::FrameIsInLastPartOfIBSplit(pfd->mFrame)) { // Zero this out so that when we compute the max-element-width of // the frame we will properly avoid adding in the starting margin. if (ltr) @@ -1156,11 +1161,23 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd, // XXXwaterson this is probably not exactly right; e.g., embeddings, etc. PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection); - if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) || (pfd->mFrame->GetNextContinuation() && !pfd->mFrame->GetNextInFlow())) + /* + * We want to only apply the end margin if we're the last continuation and + * not in the first part of an {ib} split. In all other cases we want to + * zero it out. That means zeroing it out if any of these conditions hold: + * 1) The frame is not complete (in this case it will get a next-in-flow) + * 2) The frame is complete but has a non-fluid continuation. Note that if + * it has a fluid continuation, that continuation will get destroyed + * later, so we don't want to drop the end-margin in that case. + * // FIXME: bug 492469 + * 3) The frame is in the first part of an {ib} split. + * + * However, none of that applies if this is a letter frame (XXXbz why?) + */ + if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) || + (pfd->mFrame->GetNextContinuation() && !pfd->mFrame->GetNextInFlow()) || + nsLayoutUtils::FrameIsInFirstPartOfIBSplit(pfd->mFrame)) && !pfd->GetFlag(PFD_ISLETTERFRAME)) { - // Only apply end margin for the last-in-flow. Zero this out so - // that when we compute the max-element-width of the frame we - // will properly avoid adding in the end margin. if (ltr) pfd->mMargin.right = 0; else diff --git a/layout/reftests/inline-borderpadding/left-ltr-ref.html b/layout/reftests/inline-borderpadding/left-ltr-ref.html new file mode 100644 index 000000000000..b56b5c0a710b --- /dev/null +++ b/layout/reftests/inline-borderpadding/left-ltr-ref.html @@ -0,0 +1,10 @@ + + +
+