зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1615142 - Fix triple-click selection on pre-formatted text. r=mats
We need to check for terminal new-lines on ourselves before looking at our next sibling frame. Differential Revision: https://phabricator.services.mozilla.com/D62766 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
4108cae997
Коммит
712d386afe
|
@ -183,8 +183,8 @@ struct nsBoxLayoutMetrics {
|
|||
};
|
||||
|
||||
struct nsContentAndOffset {
|
||||
nsIContent* mContent;
|
||||
int32_t mOffset;
|
||||
nsIContent* mContent = nullptr;
|
||||
int32_t mOffset = 0;
|
||||
};
|
||||
|
||||
// Some Misc #defines
|
||||
|
@ -8461,21 +8461,39 @@ nsIFrame::CaretPosition nsIFrame::GetExtremeCaretPosition(bool aStart) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// If this is a preformatted text frame, see if it ends with a newline
|
||||
static nsContentAndOffset FindLineBreakInText(nsIFrame* aFrame,
|
||||
nsDirection aDirection) {
|
||||
nsContentAndOffset result;
|
||||
|
||||
if (aFrame->IsGeneratedContentFrame() ||
|
||||
!aFrame->HasSignificantTerminalNewline()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t startOffset, endOffset;
|
||||
aFrame->GetOffsets(startOffset, endOffset);
|
||||
result.mContent = aFrame->GetContent();
|
||||
result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find the first (or last) descendant of the given frame
|
||||
// which is either a block-level frame or a BRFrame, or some other kind of break
|
||||
// which stops the line.
|
||||
static nsContentAndOffset FindLineBreakingFrame(nsIFrame* aFrame,
|
||||
nsDirection aDirection) {
|
||||
nsContentAndOffset result;
|
||||
result.mContent = nullptr;
|
||||
result.mOffset = 0;
|
||||
|
||||
if (aFrame->IsGeneratedContentFrame()) return result;
|
||||
if (aFrame->IsGeneratedContentFrame()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Treat form controls as inline leaves
|
||||
// XXX we really need a way to determine whether a frame is inline-level
|
||||
nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
|
||||
if (fcf) return result;
|
||||
if (nsIFormControlFrame* fcf = do_QueryFrame(aFrame)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check the frame itself
|
||||
// Fall through block-in-inline split frames because their mContent is
|
||||
|
@ -8497,12 +8515,8 @@ static nsContentAndOffset FindLineBreakingFrame(nsIFrame* aFrame,
|
|||
return result;
|
||||
}
|
||||
|
||||
// If this is a preformatted text frame, see if it ends with a newline
|
||||
if (aFrame->HasSignificantTerminalNewline()) {
|
||||
int32_t startOffset, endOffset;
|
||||
aFrame->GetOffsets(startOffset, endOffset);
|
||||
result.mContent = aFrame->GetContent();
|
||||
result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
|
||||
result = FindLineBreakInText(aFrame, aDirection);
|
||||
if (result.mContent) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -8570,6 +8584,10 @@ nsresult nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct* aPos) {
|
|||
reachedBlockAncestor = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Try to find our own line-break before looking at our siblings.
|
||||
blockFrameOrBR = FindLineBreakInText(frame, eDirNext);
|
||||
|
||||
nsIFrame* sibling = frame->GetNextSibling();
|
||||
while (sibling && !blockFrameOrBR.mContent) {
|
||||
blockFrameOrBR = FindLineBreakingFrame(sibling, eDirNext);
|
||||
|
|
|
@ -10,31 +10,52 @@
|
|||
|
||||
<p id="b">Here's <span>some</span> <code><span>code</span><br><span>broken</span></code> with <span>text</span> with <code><span>code</span><br><span>broken</span></code> in <span>it and such</span> and so on</p>
|
||||
|
||||
<pre id="c">Here's some text and
|
||||
some <span>more</span> code <span>with</span> pre-formatted
|
||||
whitespace <span>that</span> should be selected
|
||||
line <span>by</span> line</pre>
|
||||
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function testTripleClick(elem, expectation) {
|
||||
window.getSelection().removeAllRanges();
|
||||
synthesizeMouse(elem, 5, 5, { clickCount: 3 });
|
||||
is(window.getSelection().toString(), expectation);
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(function () {
|
||||
for (let child of document.querySelectorAll("#a span, #a code")) {
|
||||
synthesizeMouse(child, 5, 5, { clickCount: 3 });
|
||||
is(window.getSelection().toString(), "Some code with text with code in it");
|
||||
window.getSelection().removeAllRanges();
|
||||
for (let child of document.querySelectorAll("#a span, #a code"))
|
||||
testTripleClick(child, "Some code with text with code in it");
|
||||
|
||||
{
|
||||
let spans = document.querySelectorAll("#b span");
|
||||
let expectations = [
|
||||
"Here's some code", // First span, at the beginning of the text.
|
||||
"Here's some code", // Top span in the inline-block, before break.
|
||||
"broken with text with code", // Bottom span in inline-block, after break
|
||||
"broken with text with code", // Center of the text.
|
||||
"broken with text with code", // Top span in the second inline-block, before break.
|
||||
"broken in it and such and so on", // Bottom span in the second inline-block, after break.
|
||||
"broken in it and such and so on", // Last span, at the end of the text.
|
||||
];
|
||||
is(spans.length, expectations.length);
|
||||
for (let i = 0; i < expectations.length; ++i)
|
||||
testTripleClick(spans[i], expectations[i]);
|
||||
}
|
||||
|
||||
let spans = document.querySelectorAll("#b span");
|
||||
let expectations = [
|
||||
"Here's some code", // First span, at the beginning of the text.
|
||||
"Here's some code", // Top span in the inline-block, before break.
|
||||
"broken with text with code", // Bottom span in inline-block, after break
|
||||
"broken with text with code", // Center of the text.
|
||||
"broken with text with code", // Top span in the second inline-block, before break.
|
||||
"broken in it and such and so on", // Bottom span in the second inline-block, after break.
|
||||
"broken in it and such and so on", // Last span, at the end of the text.
|
||||
|
||||
];
|
||||
is(spans.length, expectations.length);
|
||||
for (let i = 0; i < expectations.length; ++i) {
|
||||
synthesizeMouse(spans[i], 5, 5, { clickCount: 3 });
|
||||
is(window.getSelection().toString(), expectations[i]);
|
||||
window.getSelection().removeAllRanges();
|
||||
{
|
||||
testTripleClick(document.getElementById("c"), "Here's some text and");
|
||||
let spans = document.querySelectorAll("#c span");
|
||||
let expectations = [
|
||||
"some more code with pre-formatted",
|
||||
"some more code with pre-formatted",
|
||||
"whitespace that should be selected",
|
||||
"line by line",
|
||||
];
|
||||
is(spans.length, expectations.length);
|
||||
for (let i = 0; i < expectations.length; ++i)
|
||||
testTripleClick(spans[i], expectations[i]);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
|
|
Загрузка…
Ссылка в новой задаче