Bug 263359 part 3: resolve paragraph on encountering <br> or embedded block elements

This commit is contained in:
Simon Montagu 2011-03-24 11:28:44 +02:00
Родитель c29305f3ee
Коммит ec7706761d
2 изменённых файлов: 80 добавлений и 18 удалений

Просмотреть файл

@ -317,6 +317,7 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
mLogicalFrames.Clear();
mContentToFrameIndex.Clear();
mBuffer.SetLength(0);
mEmbeddingStack.Clear();
nsPresContext *presContext = aBlockFrame->PresContext();
@ -361,7 +362,7 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
mPrevFrame = nsnull;
// handle bidi-override being set on the block itself before calling
// InitLogicalArray.
// TraverseFrames.
const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
PRUnichar ch = 0;
if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
@ -374,22 +375,23 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
if (ch != 0) {
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mBuffer.Append(ch);
mEmbeddingStack.AppendElement(ch);
}
}
mPrevContent = nsnull;
for (nsBlockFrame* block = aBlockFrame; block;
block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
InitLogicalArray(block->GetFirstChild(nsnull));
TraverseFrames(aBlockFrame, block->GetFirstChild(nsnull));
}
if (ch != 0) {
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mBuffer.Append(kPDF);
mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
}
// XXX: TODO: Handle preformatted text ('\n')
mBuffer.ReplaceChar("\t\r\n", kSpace);
// Resolve final paragraph
ResolveParagraph(aBlockFrame);
return mSuccess;
}
@ -404,6 +406,9 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
mSuccess = NS_OK;
return;
}
// XXX: TODO: Handle preformatted text ('\n')
mBuffer.ReplaceChar("\t\r\n", kSpace);
PRInt32 runCount;
PRUint8 embeddingLevel = mParaLevel;
@ -587,13 +592,13 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
fragmentLength -= temp;
if (frame && fragmentLength <= 0) {
// If the frame is at the end of a run, split all ancestor inlines that
// need splitting.
// If the frame is at the end of a run, and this is not the end of our
// paragrah, split all ancestor inlines that need splitting.
// To determine whether we're at the end of the run, we check that we've
// finished processing the current run, and that the current frame
// doesn't have a fluid continuation (it could have a fluid continuation
// of zero length, so testing runLength alone is not sufficient).
if (runLength <= 0 && !frame->GetNextInFlow()) {
if (numRun + 1 < runCount && runLength <= 0 && !frame->GetNextInFlow()) {
nsIFrame* child = frame;
nsIFrame* parent = frame->GetParent();
// As long as we're on the last sibling, the parent doesn't have to be split.
@ -641,13 +646,24 @@ PRBool IsBidiLeaf(nsIFrame* aFrame) {
}
void
nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
nsIFrame* aCurrentFrame)
{
if (!aCurrentFrame)
return;
for (nsIFrame* childFrame = aCurrentFrame; childFrame;
childFrame = childFrame->GetNextSibling()) {
nsIFrame* childFrame = aCurrentFrame;
do {
/*
* It's important to get the next sibling and next continuation *before*
* handling the frame: If we encounter a forced paragraph break and call
* ResolveParagraph within this loop, doing GetNextSibling and
* GetNextContinuation after that could return a bidi continuation that had
* just been split from the original childFrame and we would process it
* twice.
*/
nsIFrame* nextSibling = childFrame->GetNextSibling();
PRBool isLastFrame = !childFrame->GetNextContinuation();
// If the real frame for a placeholder is a first letter frame, we need to
// drill down into it and include its contents in Bidi resolution.
@ -691,6 +707,7 @@ nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
if (ch != 0 && !frame->GetPrevContinuation()) {
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mBuffer.Append(ch);
mEmbeddingStack.AppendElement(ch);
}
}
@ -716,26 +733,66 @@ nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
} else if (nsGkAtoms::brFrame == frameType) {
// break frame -- append line separator
mBuffer.Append(kLineSeparator);
ResolveParagraphWithinBlock(aBlockFrame);
} else {
// other frame type -- see the Unicode Bidi Algorithm:
// "...inline objects (such as graphics) are treated as if they are ...
// U+FFFC"
mBuffer.Append(kObjectSubstitute);
if (!frame->GetStyleContext()->GetStyleDisplay()->IsInlineOutside()) {
// if it is not inline, end the paragraph
ResolveParagraphWithinBlock(aBlockFrame);
}
}
}
else {
// For a non-leaf frame, recurse into TraverseFrames
nsIFrame* kid = frame->GetFirstChild(nsnull);
InitLogicalArray(kid);
TraverseFrames(aBlockFrame, kid);
}
// If the element is attributed by dir, indicate direction pop (add PDF frame)
if (ch != 0 && !frame->GetNextContinuation()) {
if (ch != 0 && isLastFrame) {
// Add a dummy frame pointer representing a bidi control code after the
// last frame of an element specifying embedding or override
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mBuffer.Append(kPDF);
mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
}
} // for
childFrame = nextSibling;
} while (childFrame);
}
void
nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame)
{
nsIPresShell* shell;
nsStyleContext* styleContext;
if (mEmbeddingStack.Length() > 0) {
shell = aBlockFrame->PresContext()->PresShell();
styleContext = aBlockFrame->GetStyleContext();
// pop all embeddings and overrides
for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
mBuffer.Append(kPDF);
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
}
}
ResolveParagraph(aBlockFrame);
// Clear the frame array and paragraph buffer, and restore the stored
// embeddings and overrides
mLogicalFrames.Clear();
mContentToFrameIndex.Clear();
mBuffer.SetLength(0);
if (mEmbeddingStack.Length() > 0) {
for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
mBuffer.Append(mEmbeddingStack[i]);
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
}
}
}
void

Просмотреть файл

@ -176,6 +176,7 @@ public:
*/
nsresult Resolve(nsBlockFrame* aBlockFrame);
void ResolveParagraph(nsBlockFrame* aBlockFrame);
void ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame);
/**
* Reorder this line using Bidi engine.
@ -363,11 +364,14 @@ private:
nscoord* aWidth /* may be null */);
/**
* Set up an array of the frames after splitting frames so that each frame has
* consistent directionality. At this point the frames are still in logical
* order
* Traverse the child frames of the block element and:
* Set up an array of the frames in logical order
* Create a string containing the text content of all the frames
* If we encounter content that requires us to split the element into more
* than one paragraph for bidi resolution, resolve the paragraph up to that
* point.
*/
void InitLogicalArray(nsIFrame* aCurrentFrame);
void TraverseFrames(nsBlockFrame* aBlockFrame, nsIFrame* aCurrentFrame);
/**
* Initialize the logically-ordered array of frames
@ -507,7 +511,8 @@ private:
PRUint32 aSrcLength,
PRUnichar* aDest);
nsAutoString mBuffer;
nsString mBuffer;
nsTArray<PRUnichar> mEmbeddingStack;
nsTArray<nsIFrame*> mLogicalFrames;
nsTArray<nsIFrame*> mVisualFrames;
nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;