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:
Emilio Cobos Álvarez
2025-04-06 23:58:48 +00:00
parent acde9612b2
commit 1008751221
3 changed files with 33 additions and 11 deletions

View File

@@ -31,13 +31,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=578771
ce.focus();
synthesizeMouse(elem, 5, 5, {clickCount: 2 });
ok(elem.selectionStart == 0 && elem.selectionEnd == 7,
" Double-clicking on another " + elemTag + " works correctly");
is(elem.selectionStart, 0, `${elemTag} selectionStart after double-click`);
is(elem.selectionEnd, 7, `${elemTag} selectionEnd after double-click`);
ce.focus();
synthesizeMouse(elem, 5, 5, {clickCount: 3 });
ok(elem.selectionStart == 0 && elem.selectionEnd == 14,
"Triple-clicking on another " + elemTag + " works correctly");
is(elem.selectionStart, 0, `${elemTag} selectionStart after triple-click`);
is(elem.selectionEnd, 14, `${elemTag} selectionEnd after triple-click`);
}
// Avoid platform selection differences
SimpleTest.waitForFocus(function() {

View File

@@ -4615,6 +4615,10 @@ nsresult nsIFrame::GetDataForTableSelection(
}
static bool IsEditingHost(const nsIFrame* aFrame) {
if (aFrame->Style()->GetPseudoType() ==
PseudoStyleType::mozTextControlEditingRoot) {
return true;
}
nsIContent* content = aFrame->GetContent();
return content && content->IsEditingHost();
}
@@ -4666,8 +4670,6 @@ bool nsIFrame::ShouldHaveLineIfEmpty() const {
break;
case PseudoStyleType::scrolledContent:
return GetParent()->ShouldHaveLineIfEmpty();
case PseudoStyleType::mozTextControlEditingRoot:
return true;
case PseudoStyleType::buttonContent:
// HTML quirk.
return GetContent()->IsHTMLElement(nsGkAtoms::input);
@@ -5460,6 +5462,22 @@ struct MOZ_STACK_CLASS FrameContentRange {
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
static FrameContentRange GetRangeForFrame(const nsIFrame* aFrame) {
nsIContent* content = aFrame->GetContent();
@@ -5486,7 +5504,7 @@ static FrameContentRange GetRangeForFrame(const nsIFrame* aFrame) {
MOZ_ASSERT(!content->IsBeingRemoved());
nsIContent* parent = content->GetParent();
if (aFrame->IsBlockOutside() || !parent) {
if (IsRelevantBlockFrame(aFrame) || !parent) {
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
// first/last child of such frames is the real block frame we're
// looking for.
if ((aFrame->IsBlockOutside() &&
if ((IsRelevantBlockFrame(aFrame) &&
!aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) ||
aFrame->IsBrFrame()) {
nsIContent* content = aFrame->GetContent();
@@ -9427,7 +9445,7 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
nsIFrame* frame = this;
nsContentAndOffset blockFrameOrBR;
blockFrameOrBR.mContent = nullptr;
bool reachedLimit = frame->IsBlockOutside() || IsEditingHost(frame);
bool reachedLimit = IsRelevantBlockFrame(frame) || IsEditingHost(frame);
auto traverse = [&aPos](nsIFrame* current) {
return aPos->mDirection == eDirPrevious ? current->GetPrevSibling()
@@ -9463,7 +9481,8 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
break;
}
frame = parent;
reachedLimit = frame && (frame->IsBlockOutside() || IsEditingHost(frame));
reachedLimit =
frame && (IsRelevantBlockFrame(frame) || IsEditingHost(frame));
}
if (reachedLimit) { // no "stop frame" found

View File

@@ -5,6 +5,7 @@
<style>
body { margin: 0; font: 16px/1 sans-serif; }
code { display: inline-block }
#d code { overflow: auto }
</style>
<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
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>
SimpleTest.waitForExplicitFinish();
@@ -25,7 +28,7 @@ line <span>by</span> line</pre>
}
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");
{