diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 14032ed317f..ab2496dc210 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -69,6 +69,7 @@ #include "nsIDOMHTMLDocument.h" #include "nsLayoutUtils.h" #include "nsINameSpaceManager.h" +#include "nsBlockFrame.h" #include "gfxContext.h" @@ -106,7 +107,7 @@ enum ePathTypes{ struct InlineBackgroundData { InlineBackgroundData() - : mFrame(nsnull) + : mFrame(nsnull), mBlockFrame(nsnull) { } @@ -117,18 +118,64 @@ struct InlineBackgroundData void Reset() { mBoundingBox.SetRect(0,0,0,0); - mContinuationPoint = mUnbrokenWidth = 0; - mFrame = nsnull; + mContinuationPoint = mLineContinuationPoint = mUnbrokenWidth = 0; + mFrame = mBlockFrame = nsnull; } nsRect GetContinuousRect(nsIFrame* aFrame) { SetFrame(aFrame); + nscoord x; + if (mBidiEnabled) { + x = mLineContinuationPoint; + + // Scan continuations on the same line as aFrame and accumulate the widths + // of frames that are to the left (if this is an LTR block) or right + // (if it's RTL) of the current one. + PRBool isRtlBlock = (mBlockFrame->GetStyleVisibility()->mDirection == + NS_STYLE_DIRECTION_RTL); + nscoord curOffset = aFrame->GetOffsetTo(mBlockFrame).x; + + nsIFrame* inlineFrame = aFrame->GetPrevContinuation(); + // If the continuation is fluid we know inlineFrame is not on the same line. + // If it's not fluid, we need to test furhter to be sure. + while (inlineFrame && !inlineFrame->GetNextInFlow() && + AreOnSameLine(aFrame, inlineFrame)) { + nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x; + if((isRtlBlock && frameXOffset >= curOffset) || + (!isRtlBlock && frameXOffset < curOffset)) { + x += inlineFrame->GetSize().width; + } + inlineFrame = inlineFrame->GetPrevContinuation(); + } + + inlineFrame = aFrame->GetNextContinuation(); + while (inlineFrame && !inlineFrame->GetPrevInFlow() && + AreOnSameLine(aFrame, inlineFrame)) { + nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x; + if((isRtlBlock && frameXOffset >= curOffset) || + (!isRtlBlock && frameXOffset < curOffset)) { + x += inlineFrame->GetSize().width; + } + inlineFrame = inlineFrame->GetNextContinuation(); + } + if (isRtlBlock) { + // aFrame itself is also to the right of its left edge, so add its width. + x += aFrame->GetSize().width; + // x is now the distance from the left edge of aFrame to the right edge + // of the unbroken content. Change it to indicate the distance from the + // left edge of the unbroken content to the left edge of aFrame. + x = mUnbrokenWidth - x; + } + } else { + x = mContinuationPoint; + } + // Assume background-origin: border and return a rect with offsets // relative to (0,0). If we have a different background-origin, // then our rect should be deflated appropriately by our caller. - return nsRect(-mContinuationPoint, 0, mUnbrokenWidth, mFrame->GetSize().height); + return nsRect(-x, 0, mUnbrokenWidth, mFrame->GetSize().height); } nsRect GetBoundingRect(nsIFrame* aFrame) @@ -153,6 +200,10 @@ protected: nscoord mUnbrokenWidth; nsRect mBoundingBox; + PRBool mBidiEnabled; + nsBlockFrame* mBlockFrame; + nscoord mLineContinuationPoint; + void SetFrame(nsIFrame* aFrame) { NS_PRECONDITION(aFrame, "Need a frame"); @@ -170,6 +221,12 @@ protected: // point before we cache the new frame. mContinuationPoint += mFrame->GetSize().width; + // If this a new line, update mLineContinuationPoint. + if (mBidiEnabled && + (aFrame->GetPrevInFlow() || !AreOnSameLine(mFrame, aFrame))) { + mLineContinuationPoint = mContinuationPoint; + } + mFrame = aFrame; } @@ -198,6 +255,29 @@ protected: } mFrame = aFrame; + + mBidiEnabled = aFrame->PresContext()->BidiEnabled(); + if (mBidiEnabled) { + // Find the containing block frame + nsIFrame* frame = aFrame; + nsresult rv = NS_ERROR_FAILURE; + while (frame && + frame->IsFrameOfType(nsIFrame::eLineParticipant) && + NS_FAILED(rv)) { + frame = frame->GetParent(); + rv = frame->QueryInterface(kBlockFrameCID, (void**)&mBlockFrame); + } + NS_ASSERTION(NS_SUCCEEDED(rv) && mBlockFrame, "Cannot find containing block."); + + mLineContinuationPoint = mContinuationPoint; + } + } + + PRBool AreOnSameLine(nsIFrame* aFrame1, nsIFrame* aFrame2) { + // Assumes that aFrame1 and aFrame2 are both decsendants of mBlockFrame. + nsBlockInFlowLineIterator it1(mBlockFrame, aFrame1); + nsBlockInFlowLineIterator it2(mBlockFrame, aFrame2); + return it1.GetLine() == it2.GetLine(); } };