Bug 1143570 - Part 1: Use an nsBlockInFlowLineIterator to determine whether a BR frame is visible or not; r=roc

This commit is contained in:
Ehsan Akhgari 2015-05-11 13:36:56 -04:00
parent 29d8e53169
commit 1b9af9fc20
2 changed files with 87 additions and 10 deletions

View File

@ -49,7 +49,8 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/EncodingUtils.h"
#include "nsComputedDOMStyle.h"
#include "nsContainerFrame.h"
#include "nsBlockFrame.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -324,7 +325,45 @@ nsDocumentEncoder::IncludeInContext(nsINode *aNode)
static
bool
IsInvisibleBreak(nsINode *aNode) {
LineHasNonEmptyContentWorker(nsIFrame* aFrame)
{
// Look for non-empty frames, but ignore inline and br frames.
// For inline frames, descend into the children, if any.
if (aFrame->GetType() == nsGkAtoms::inlineFrame) {
nsIFrame* child = aFrame->GetFirstPrincipalChild();
while (child) {
if (LineHasNonEmptyContentWorker(child)) {
return true;
}
child = child->GetNextSibling();
}
} else {
if (aFrame->GetType() != nsGkAtoms::brFrame &&
!aFrame->IsEmpty()) {
return true;
}
}
return false;
}
static
bool
LineHasNonEmptyContent(nsLineBox* aLine)
{
int32_t count = aLine->GetChildCount();
for (nsIFrame* frame = aLine->mFirstChild; count > 0;
--count, frame = frame->GetNextSibling()) {
if (LineHasNonEmptyContentWorker(frame)) {
return true;
}
}
return false;
}
static
bool
IsInvisibleBreak(nsINode *aNode)
{
if (!aNode->IsElement() || !aNode->IsEditable()) {
return false;
}
@ -333,14 +372,36 @@ IsInvisibleBreak(nsINode *aNode) {
return false;
}
// If the BRFrame has caused a visible line break, it should have a next
// sibling, or otherwise no siblings (or immediately after a br) and a
// non-zero height.
bool visible = frame->GetNextSibling() ||
((!frame->GetPrevSibling() ||
frame->GetPrevSibling()->GetType() == nsGkAtoms::brFrame) &&
frame->GetRect().Height() != 0);
return !visible;
nsContainerFrame* f = frame->GetParent();
while (f && f->IsFrameOfType(nsBox::eLineParticipant)) {
f = f->GetParent();
}
nsBlockFrame* blockAncestor = do_QueryFrame(f);
if (!blockAncestor) {
// The container frame doesn't support line breaking.
return false;
}
bool valid = false;
nsBlockInFlowLineIterator iter(blockAncestor, frame, &valid);
if (!valid) {
return false;
}
bool lineNonEmpty = LineHasNonEmptyContent(iter.GetLine());
while (iter.Next()) {
auto currentLine = iter.GetLine();
// Completely skip empty lines.
if (!currentLine->IsEmpty()) {
// If we come across an inline line, the BR has caused a visible line break.
if (currentLine->IsInline()) {
return false;
}
}
}
return lineNonEmpty;
}
nsresult

View File

@ -28,6 +28,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=116083
<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-line" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
<div data-result="foo&#10;bar&#10;baz&#10;qux"><div>foo<br></div><span>bar<br>baz<br>qux</span></div>
<div data-result="foo&#10;bar&#10;baz&#10;qux" contenteditable><div>foo<br></div><span>bar<br>baz<br>qux</span></div>
<div data-result="foo&#10;&#10;"><div>foo</div><span><br></span></div>
<div data-result="foo&#10;&#10;" contenteditable><div>foo</div><span><br></span></div>
<div data-result="foo&#10;&#10;bar"><div>foo</div><span><br></span><div>bar</div></div>
<div data-result="foo&#10;&#10;bar" contenteditable><div>foo</div><span><br></span><div>bar</div></div>
<div data-result="foo&#10;bar&#10;"><div>foo</div><span>bar<br></span></div>
<div data-result="foo&#10;bar" contenteditable><div>foo</div><span>bar<br></span></div>
<div data-result="foo&#10;bar&#10;baz"><div>foo</div><span>bar<br></span><div>baz</div></div>
<div data-result="foo&#10;bar&#10;baz" contenteditable><div>foo</div><span>bar<br></span><div>baz</div></div>
<div data-result="&#10;&#10;foo"><div><br><br><div>foo</div></div></div>
<div data-result="&#10;&#10;foo" contenteditable><div><br><br><div>foo</div></div></div>
<div data-result="foo&#10;bar"><div>foo<br>bar</div></div>
<div data-result="foo&#10;bar" contenteditable><div>foo<br>bar</div></div>
<div data-result="foo&#10;bar&#10;"><div>foo<br>bar<br></div></div>
<div data-result="foo&#10;bar" contenteditable><div>foo<br>bar<br></div></div>
<div data-result="&#10;foo bar&#10;">foo bar</div>
</div>
<script type="application/javascript">