Bug 1958639 - Ignore anonymous boxes and NAC for paragraph selection code. r=masayuki
The inner block of a scroller for example (::-moz-scrolled-content) shouldn't be considered a line break. Same for scrollbar nodes, we don't want to break on scrollbars (or native anonymous content in general), since we can't position the caret and such there anyways. Differential Revision: https://phabricator.services.mozilla.com/D244519
This commit is contained in:
@@ -31,13 +31,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=578771
|
|||||||
ce.focus();
|
ce.focus();
|
||||||
|
|
||||||
synthesizeMouse(elem, 5, 5, {clickCount: 2 });
|
synthesizeMouse(elem, 5, 5, {clickCount: 2 });
|
||||||
ok(elem.selectionStart == 0 && elem.selectionEnd == 7,
|
is(elem.selectionStart, 0, `${elemTag} selectionStart after double-click`);
|
||||||
" Double-clicking on another " + elemTag + " works correctly");
|
is(elem.selectionEnd, 7, `${elemTag} selectionEnd after double-click`);
|
||||||
|
|
||||||
ce.focus();
|
ce.focus();
|
||||||
synthesizeMouse(elem, 5, 5, {clickCount: 3 });
|
synthesizeMouse(elem, 5, 5, {clickCount: 3 });
|
||||||
ok(elem.selectionStart == 0 && elem.selectionEnd == 14,
|
is(elem.selectionStart, 0, `${elemTag} selectionStart after triple-click`);
|
||||||
"Triple-clicking on another " + elemTag + " works correctly");
|
is(elem.selectionEnd, 14, `${elemTag} selectionEnd after triple-click`);
|
||||||
}
|
}
|
||||||
// Avoid platform selection differences
|
// Avoid platform selection differences
|
||||||
SimpleTest.waitForFocus(function() {
|
SimpleTest.waitForFocus(function() {
|
||||||
|
|||||||
@@ -4615,6 +4615,10 @@ nsresult nsIFrame::GetDataForTableSelection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool IsEditingHost(const nsIFrame* aFrame) {
|
static bool IsEditingHost(const nsIFrame* aFrame) {
|
||||||
|
if (aFrame->Style()->GetPseudoType() ==
|
||||||
|
PseudoStyleType::mozTextControlEditingRoot) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
nsIContent* content = aFrame->GetContent();
|
nsIContent* content = aFrame->GetContent();
|
||||||
return content && content->IsEditingHost();
|
return content && content->IsEditingHost();
|
||||||
}
|
}
|
||||||
@@ -4666,8 +4670,6 @@ bool nsIFrame::ShouldHaveLineIfEmpty() const {
|
|||||||
break;
|
break;
|
||||||
case PseudoStyleType::scrolledContent:
|
case PseudoStyleType::scrolledContent:
|
||||||
return GetParent()->ShouldHaveLineIfEmpty();
|
return GetParent()->ShouldHaveLineIfEmpty();
|
||||||
case PseudoStyleType::mozTextControlEditingRoot:
|
|
||||||
return true;
|
|
||||||
case PseudoStyleType::buttonContent:
|
case PseudoStyleType::buttonContent:
|
||||||
// HTML quirk.
|
// HTML quirk.
|
||||||
return GetContent()->IsHTMLElement(nsGkAtoms::input);
|
return GetContent()->IsHTMLElement(nsGkAtoms::input);
|
||||||
@@ -5460,6 +5462,22 @@ struct MOZ_STACK_CLASS FrameContentRange {
|
|||||||
int32_t end;
|
int32_t end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool IsRelevantBlockFrame(const nsIFrame* aFrame) {
|
||||||
|
if (!aFrame->IsBlockOutside()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (aFrame->Style()->IsAnonBox()) {
|
||||||
|
// This helps skipping things like ::-moz-scrolled-content on an
|
||||||
|
// inline-block.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (aFrame->GetContent()->IsInNativeAnonymousSubtree()) {
|
||||||
|
// This helps skipping things like scrollbar parts.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve the content offsets of a frame
|
// Retrieve the content offsets of a frame
|
||||||
static FrameContentRange GetRangeForFrame(const nsIFrame* aFrame) {
|
static FrameContentRange GetRangeForFrame(const nsIFrame* aFrame) {
|
||||||
nsIContent* content = aFrame->GetContent();
|
nsIContent* content = aFrame->GetContent();
|
||||||
@@ -5486,7 +5504,7 @@ static FrameContentRange GetRangeForFrame(const nsIFrame* aFrame) {
|
|||||||
|
|
||||||
MOZ_ASSERT(!content->IsBeingRemoved());
|
MOZ_ASSERT(!content->IsBeingRemoved());
|
||||||
nsIContent* parent = content->GetParent();
|
nsIContent* parent = content->GetParent();
|
||||||
if (aFrame->IsBlockOutside() || !parent) {
|
if (IsRelevantBlockFrame(aFrame) || !parent) {
|
||||||
return FrameContentRange(content, 0, content->GetChildCount());
|
return FrameContentRange(content, 0, content->GetChildCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9385,7 +9403,7 @@ static nsContentAndOffset FindLineBreakingFrame(nsIFrame* aFrame,
|
|||||||
// the content of the inline frames they were created from. The
|
// the content of the inline frames they were created from. The
|
||||||
// first/last child of such frames is the real block frame we're
|
// first/last child of such frames is the real block frame we're
|
||||||
// looking for.
|
// looking for.
|
||||||
if ((aFrame->IsBlockOutside() &&
|
if ((IsRelevantBlockFrame(aFrame) &&
|
||||||
!aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) ||
|
!aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) ||
|
||||||
aFrame->IsBrFrame()) {
|
aFrame->IsBrFrame()) {
|
||||||
nsIContent* content = aFrame->GetContent();
|
nsIContent* content = aFrame->GetContent();
|
||||||
@@ -9427,7 +9445,7 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
|
|||||||
nsIFrame* frame = this;
|
nsIFrame* frame = this;
|
||||||
nsContentAndOffset blockFrameOrBR;
|
nsContentAndOffset blockFrameOrBR;
|
||||||
blockFrameOrBR.mContent = nullptr;
|
blockFrameOrBR.mContent = nullptr;
|
||||||
bool reachedLimit = frame->IsBlockOutside() || IsEditingHost(frame);
|
bool reachedLimit = IsRelevantBlockFrame(frame) || IsEditingHost(frame);
|
||||||
|
|
||||||
auto traverse = [&aPos](nsIFrame* current) {
|
auto traverse = [&aPos](nsIFrame* current) {
|
||||||
return aPos->mDirection == eDirPrevious ? current->GetPrevSibling()
|
return aPos->mDirection == eDirPrevious ? current->GetPrevSibling()
|
||||||
@@ -9463,7 +9481,8 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
frame = parent;
|
frame = parent;
|
||||||
reachedLimit = frame && (frame->IsBlockOutside() || IsEditingHost(frame));
|
reachedLimit =
|
||||||
|
frame && (IsRelevantBlockFrame(frame) || IsEditingHost(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reachedLimit) { // no "stop frame" found
|
if (reachedLimit) { // no "stop frame" found
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<style>
|
<style>
|
||||||
body { margin: 0; font: 16px/1 sans-serif; }
|
body { margin: 0; font: 16px/1 sans-serif; }
|
||||||
code { display: inline-block }
|
code { display: inline-block }
|
||||||
|
#d code { overflow: auto }
|
||||||
</style>
|
</style>
|
||||||
<p id="a">Some <code>code</code> with <span>text</span> with <code>code</code> in it</p>
|
<p id="a">Some <code>code</code> with <span>text</span> with <code>code</code> in it</p>
|
||||||
|
|
||||||
@@ -15,6 +16,8 @@ some <span>more</span> code <span>with</span> pre-formatted
|
|||||||
whitespace <span>that</span> should be selected
|
whitespace <span>that</span> should be selected
|
||||||
line <span>by</span> line</pre>
|
line <span>by</span> line</pre>
|
||||||
|
|
||||||
|
<p id="d">Some <code>code</code> with <span>text</span> with <code>code</code> in <span>it</span></p>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
@@ -25,7 +28,7 @@ line <span>by</span> line</pre>
|
|||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForFocus(function () {
|
SimpleTest.waitForFocus(function () {
|
||||||
for (let child of document.querySelectorAll("#a span, #a code"))
|
for (let child of document.querySelectorAll(":is(#a, #d) :is(span, code)"))
|
||||||
testTripleClick(child, "Some code with text with code in it");
|
testTripleClick(child, "Some code with text with code in it");
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user