зеркало из https://github.com/mozilla/pjs.git
Bug 263359 part 4: resolve paragraph on encountering line breaks in preformatted elements. r=roc
This commit is contained in:
Родитель
ef694e6aea
Коммит
7f6b363f1e
|
@ -0,0 +1,14 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.body.offsetHeight;
|
||||
document.body.appendChild(document.createTextNode('Y'));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body style="white-space: pre;" onload="boom();">
ٌ</body>
|
||||
</html>
|
|
@ -329,5 +329,6 @@ load 629908-1.html
|
|||
load 635329.html
|
||||
== 640272.html 640272-ref.html
|
||||
load 645193.html
|
||||
load 650475.xhtml
|
||||
load 650489.xhtml
|
||||
load 653133-1.html
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "nsContainerFrame.h"
|
||||
#include "nsFirstLetterFrame.h"
|
||||
#include "gfxUnicodeProperties.h"
|
||||
#include "nsTextFrame.h"
|
||||
|
||||
#undef NOISY_BIDI
|
||||
#undef REALLY_NOISY_BIDI
|
||||
|
@ -164,22 +165,31 @@ SplitInlineAncestors(nsIFrame* aFrame)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Convert bidi continuations to fluid continuations for a frame and all of its
|
||||
// inline ancestors.
|
||||
static void
|
||||
MakeContinuationFluid(nsIFrame* aFrame, nsIFrame* aNext)
|
||||
{
|
||||
NS_ASSERTION (!aFrame->GetNextInFlow() || aFrame->GetNextInFlow() == aNext,
|
||||
"next-in-flow is not next continuation!");
|
||||
aFrame->SetNextInFlow(aNext);
|
||||
|
||||
NS_ASSERTION (!aNext->GetPrevInFlow() || aNext->GetPrevInFlow() == aFrame,
|
||||
"prev-in-flow is not prev continuation!");
|
||||
aNext->SetPrevInFlow(aFrame);
|
||||
}
|
||||
|
||||
// If aFrame is the last child of its parent, convert bidi continuations to
|
||||
// fluid continuations for all of its inline ancestors.
|
||||
static void
|
||||
JoinInlineAncestors(nsIFrame* aFrame)
|
||||
{
|
||||
nsIFrame* frame = aFrame;
|
||||
if (aFrame->GetNextSibling()) {
|
||||
return;
|
||||
}
|
||||
nsIFrame* frame = aFrame->GetParent();
|
||||
while (frame && IsBidiSplittable(frame)) {
|
||||
nsIFrame* next = frame->GetNextContinuation();
|
||||
if (next) {
|
||||
NS_ASSERTION (!frame->GetNextInFlow() || frame->GetNextInFlow() == next,
|
||||
"next-in-flow is not next continuation!");
|
||||
frame->SetNextInFlow(next);
|
||||
|
||||
NS_ASSERTION (!next->GetPrevInFlow() || next->GetPrevInFlow() == frame,
|
||||
"prev-in-flow is not prev continuation!");
|
||||
next->SetPrevInFlow(frame);
|
||||
MakeContinuationFluid(frame, next);
|
||||
}
|
||||
// Join the parent only as long as we're its last child.
|
||||
if (frame->GetNextSibling())
|
||||
|
@ -189,8 +199,9 @@ JoinInlineAncestors(nsIFrame* aFrame)
|
|||
}
|
||||
|
||||
static nsresult
|
||||
CreateBidiContinuation(nsIFrame* aFrame,
|
||||
nsIFrame** aNewFrame)
|
||||
CreateContinuation(nsIFrame* aFrame,
|
||||
nsIFrame** aNewFrame,
|
||||
PRBool aIsFluid)
|
||||
{
|
||||
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
||||
NS_PRECONDITION(aFrame, "null ptr");
|
||||
|
@ -199,10 +210,10 @@ CreateBidiContinuation(nsIFrame* aFrame,
|
|||
|
||||
nsPresContext *presContext = aFrame->PresContext();
|
||||
nsIPresShell *presShell = presContext->PresShell();
|
||||
NS_ASSERTION(presShell, "PresShell must be set on PresContext before calling nsBidiPresUtils::CreateBidiContinuation");
|
||||
NS_ASSERTION(presShell, "PresShell must be set on PresContext before calling nsBidiPresUtils::CreateContinuation");
|
||||
|
||||
nsIFrame* parent = aFrame->GetParent();
|
||||
NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateBidiContinuation");
|
||||
NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateContinuation");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -213,12 +224,12 @@ CreateBidiContinuation(nsIFrame* aFrame,
|
|||
parent->GetStyleDisplay()->IsFloating()) {
|
||||
nsFirstLetterFrame* letterFrame = do_QueryFrame(parent);
|
||||
rv = letterFrame->CreateContinuationForFloatingParent(presContext, aFrame,
|
||||
aNewFrame, PR_FALSE);
|
||||
aNewFrame, aIsFluid);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = presShell->FrameConstructor()->
|
||||
CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, PR_FALSE);
|
||||
CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, aIsFluid);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -230,11 +241,13 @@ CreateBidiContinuation(nsIFrame* aFrame,
|
|||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Split inline ancestor frames
|
||||
rv = SplitInlineAncestors(aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
||||
if (!aIsFluid) {
|
||||
// Split inline ancestor frames
|
||||
rv = SplitInlineAncestors(aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -285,7 +298,7 @@ AdvanceLineIteratorToFrame(nsIFrame* aFrame,
|
|||
*
|
||||
* Walk through the descendants of aBlockFrame and build:
|
||||
* * mLogicalFrames: an nsTArray of nsIFrame* pointers in logical order
|
||||
* * mBuffer: an nsAutoString containing a representation of
|
||||
* * mBuffer: an nsString containing a representation of
|
||||
* the content of the frames.
|
||||
* In the case of text frames, this is the actual text context of the
|
||||
* frames, but some other elements are represented in a symbolic form which
|
||||
|
@ -383,6 +396,7 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
|
|||
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
|
||||
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
|
||||
mBuffer.Append(kPDF);
|
||||
NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
|
||||
mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
|
||||
}
|
||||
|
||||
|
@ -400,7 +414,6 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
|
|||
mSuccess = NS_OK;
|
||||
return;
|
||||
}
|
||||
// XXX: TODO: Handle preformatted text ('\n')
|
||||
mBuffer.ReplaceChar("\t\r\n", kSpace);
|
||||
|
||||
PRInt32 runCount;
|
||||
|
@ -553,12 +566,17 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
|
|||
*/
|
||||
PRInt32 newIndex = frameIndex;
|
||||
do {
|
||||
} while (mLogicalFrames[++newIndex] == NS_BIDI_CONTROL_FRAME);
|
||||
RemoveBidiContinuation(frame, frameIndex, newIndex, lineOffset);
|
||||
} else if (runLength == fragmentLength) {
|
||||
} while (++newIndex < frameCount &&
|
||||
mLogicalFrames[newIndex] == NS_BIDI_CONTROL_FRAME);
|
||||
if (newIndex < frameCount) {
|
||||
RemoveBidiContinuation(frame, frameIndex, newIndex, lineOffset);
|
||||
}
|
||||
} else if (runLength == fragmentLength &&
|
||||
numRun + 1 < runCount) {
|
||||
/*
|
||||
* The directional run ends at the end of the frame. Make sure that
|
||||
* the next frame is a non-fluid continuation
|
||||
* If the directional run ends at the end of the frame, and this is
|
||||
* not the end of our paragraph, make sure that the next frame is a
|
||||
* non-fluid continuation
|
||||
*/
|
||||
nsIFrame* next = frame->GetNextInFlow();
|
||||
if (next) {
|
||||
|
@ -607,12 +625,11 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
|
|||
if (parent && IsBidiSplittable(parent))
|
||||
SplitInlineAncestors(child);
|
||||
}
|
||||
else if (!frame->GetNextSibling()) {
|
||||
// We're not at an end of a run, and |frame| is the last child of its parent.
|
||||
// If its ancestors happen to have bidi continuations, convert them into
|
||||
// fluid continuations.
|
||||
nsIFrame* parent = frame->GetParent();
|
||||
JoinInlineAncestors(parent);
|
||||
else {
|
||||
// We're not at an end of a run. If |frame| is the last child of its
|
||||
// parent, and its ancestors happen to have bidi continuations, convert
|
||||
// them into fluid continuations.
|
||||
JoinInlineAncestors(frame);
|
||||
}
|
||||
}
|
||||
} // for
|
||||
|
@ -721,7 +738,117 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
|
|||
if (nsGkAtoms::textFrame == frameType) {
|
||||
if (content != mPrevContent) {
|
||||
mPrevContent = content;
|
||||
content->AppendTextTo(mBuffer);
|
||||
if (!frame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
|
||||
content->AppendTextTo(mBuffer);
|
||||
} else {
|
||||
/*
|
||||
* For preformatted text we have to do bidi resolution on each line
|
||||
* separately.
|
||||
*/
|
||||
nsAutoString text;
|
||||
content->AppendTextTo(text);
|
||||
nsIFrame* next;
|
||||
do {
|
||||
next = nsnull;
|
||||
|
||||
PRInt32 start, end;
|
||||
frame->GetOffsets(start, end);
|
||||
PRInt32 endLine = text.FindCharInSet(NS_LITERAL_STRING("\n\r"),
|
||||
start);
|
||||
if (endLine == -1) {
|
||||
/*
|
||||
* If there is no newline in the frame, just save the text and
|
||||
* do bidi resolution later
|
||||
*/
|
||||
mBuffer.Append(Substring(text, start));
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a newline in the frame, break the frame after the
|
||||
* newline, do bidi resolution and repeat until the end of the
|
||||
* element.
|
||||
*/
|
||||
++endLine;
|
||||
|
||||
/*
|
||||
* If the frame ends before the new line, save the text and move
|
||||
* into the next continuation
|
||||
*/
|
||||
while (end < endLine) {
|
||||
mBuffer.Append(Substring(text, start, end - start));
|
||||
frame = frame->GetNextContinuation();
|
||||
NS_ASSERTION(frame, "Premature end of continuation chain");
|
||||
frame->GetOffsets(start, end);
|
||||
mLogicalFrames.AppendElement(frame);
|
||||
AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
|
||||
mLinePerFrame.AppendElement(aLineIter->GetLine().get());
|
||||
|
||||
/*
|
||||
* If we have already overshot the saved next-sibling while
|
||||
* scanning the frame's continuations, advance it.
|
||||
*/
|
||||
if (frame == nextSibling) {
|
||||
nextSibling = frame->GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
mBuffer.Append(Substring(text, start, endLine - start));
|
||||
|
||||
PRBool createdContinuation = PR_FALSE;
|
||||
if (PRUint32(endLine) < text.Length()) {
|
||||
/*
|
||||
* Timing is everything here: if the frame already has a bidi
|
||||
* continuation, we need to make the continuation fluid *before*
|
||||
* resetting the length of the current frame. Otherwise
|
||||
* nsTextFrame::SetLength won't set the continuation frame's
|
||||
* text offsets correctly.
|
||||
*
|
||||
* On the other hand, if the frame doesn't have a continuation,
|
||||
* we need to create one *after* resetting the length, or
|
||||
* CreateContinuingFrame will complain that there is no more
|
||||
* content for the continuation.
|
||||
*/
|
||||
next = frame->GetNextInFlow();
|
||||
if (!next) {
|
||||
// If the frame already has a bidi continuation, make it fluid
|
||||
next = frame->GetNextContinuation();
|
||||
if (next) {
|
||||
MakeContinuationFluid(frame, next);
|
||||
JoinInlineAncestors(frame);
|
||||
}
|
||||
}
|
||||
|
||||
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
|
||||
textFrame->SetLength(endLine - start, nsnull);
|
||||
|
||||
if (!next) {
|
||||
// If the frame has no next in flow, create one.
|
||||
CreateContinuation(frame, &next, PR_TRUE);
|
||||
createdContinuation = PR_TRUE;
|
||||
}
|
||||
}
|
||||
ResolveParagraphWithinBlock(aBlockFrame);
|
||||
|
||||
if (!nextSibling && !createdContinuation) {
|
||||
break;
|
||||
} else if (next) {
|
||||
frame = next;
|
||||
mLogicalFrames.AppendElement(frame);
|
||||
AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
|
||||
mLinePerFrame.AppendElement(aLineIter->GetLine().get());
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have already overshot the saved next-sibling while
|
||||
* scanning the frame's continuations, advance it.
|
||||
*/
|
||||
if (frame && frame == nextSibling) {
|
||||
nextSibling = frame->GetNextSibling();
|
||||
}
|
||||
|
||||
} while (next);
|
||||
}
|
||||
}
|
||||
} else if (nsGkAtoms::brFrame == frameType) {
|
||||
// break frame -- append line separator
|
||||
|
@ -751,6 +878,7 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
|
|||
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
|
||||
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
|
||||
mBuffer.Append(kPDF);
|
||||
NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
|
||||
mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
|
||||
}
|
||||
childFrame = nextSibling;
|
||||
|
@ -1237,7 +1365,7 @@ nsBidiPresUtils::EnsureBidiContinuation(nsIFrame* aFrame,
|
|||
NS_PRECONDITION(aFrame, "aFrame is null");
|
||||
|
||||
aFrame->AdjustOffsetsForBidi(aStart, aEnd);
|
||||
mSuccess = CreateBidiContinuation(aFrame, aNewFrame);
|
||||
mSuccess = CreateContinuation(aFrame, aNewFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1269,14 +1397,7 @@ nsBidiPresUtils::RemoveBidiContinuation(nsIFrame* aFrame,
|
|||
while (frame) {
|
||||
nsIFrame* prev = frame->GetPrevContinuation();
|
||||
if (prev) {
|
||||
NS_ASSERTION (!frame->GetPrevInFlow() || frame->GetPrevInFlow() == prev,
|
||||
"prev-in-flow is not prev continuation!");
|
||||
frame->SetPrevInFlow(prev);
|
||||
|
||||
NS_ASSERTION (!prev->GetNextInFlow() || prev->GetNextInFlow() == frame,
|
||||
"next-in-flow is not next continuation!");
|
||||
prev->SetNextInFlow(frame);
|
||||
|
||||
MakeContinuationFluid(prev, frame);
|
||||
frame = frame->GetParent();
|
||||
} else {
|
||||
break;
|
||||
|
|
|
@ -332,6 +332,7 @@ _TEST_FILES += \
|
|||
test_bug588174.html \
|
||||
test_bug607529.html \
|
||||
file_bug607529.html \
|
||||
test_bug644768.html \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=644768
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 644768</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="test()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=644768">Mozilla Bug 644768</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<!-- test text is
|
||||
== زادروزها ==
|
||||
* [[۱۳۰۷]]
|
||||
-->
|
||||
<textarea id="testInput" dir="rtl" cols="80" rows="25">
|
||||
|
||||
== زادروزها ==
|
||||
* [[۱۳۰۷]]</textarea>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 644768 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test() {
|
||||
var textInput = $("testInput");
|
||||
var s1, s2, equal, str1, str2;
|
||||
|
||||
textInput.focus();
|
||||
s1 = snapshotWindow(window);
|
||||
|
||||
synthesizeKey("VK_UP", { });
|
||||
synthesizeKey("VK_UP", { });
|
||||
synthesizeKey("VK_UP", { });
|
||||
synthesizeKey("VK_DELETE", { });
|
||||
synthesizeKey("VK_ENTER", { });
|
||||
s2 = snapshotWindow(window);
|
||||
|
||||
[equal, str1, str2] = compareSnapshots(s1, s2, true);
|
||||
ok(equal, "newline before bidi text shouldn't change direction: expected " +
|
||||
str1 + " but got " + str2);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
Загрузка…
Ссылка в новой задаче