Bug 1634543 - Fix caret baseline of a block with only empty lines. r=jfkthame

Even with the fix above, we get the caret baseline wrong because the
line is non-empty, but the baseline is all the way to the top.

Maybe an alternative to this would be to move the line-height hack to
the beginning of layout but that sounds a bit more fishy.

Otherwise we should do this more often, I suspect. I added one test that
fails because of nsInlineFrame... Anyhow probably follow-up material?

Depends on D73362

Differential Revision: https://phabricator.services.mozilla.com/D73363
This commit is contained in:
Emilio Cobos Álvarez 2020-05-01 14:34:11 +00:00
parent 8903f8bdd0
commit 50168d214b
8 changed files with 129 additions and 2 deletions

View File

@ -0,0 +1,20 @@
<!doctype html>
<html class="reftest-wait">
<title>Reference</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
div {
outline: 3px solid blue;
}
</style>
<div contenteditable="true" spellcheck="false"><br></div>
<script>
SimpleTest.waitForFocus(function() {
document.querySelector('[contenteditable="true"]').focus();
requestAnimationFrame(function() {
requestAnimationFrame(function() {
document.documentElement.removeAttribute("class");
});
});
});
</script>

View File

@ -0,0 +1,25 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret is correctly position for block whose only child is an abspos pseudo</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
div:focus {
outline: 3px solid blue;
}
div::before {
content: "";
/* This is the point of the test */
position: absolute;
}
</style>
<div contenteditable="true" spellcheck="false"></div>
<script>
SimpleTest.waitForFocus(function() {
document.querySelector('[contenteditable="true"]').focus();
requestAnimationFrame(function() {
requestAnimationFrame(function() {
document.documentElement.removeAttribute("class");
});
});
});
</script>

View File

@ -0,0 +1,24 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret is correctly position for block whose only child is an abspos span</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
div:focus {
outline: 3px solid blue;
}
span {
/* This is the point of the test */
position: absolute;
}
</style>
<div contenteditable="true" spellcheck="false"><span></span></div>
<script>
SimpleTest.waitForFocus(function() {
document.querySelector('[contenteditable="true"]').focus();
requestAnimationFrame(function() {
requestAnimationFrame(function() {
document.documentElement.removeAttribute("class");
});
});
});
</script>

View File

@ -0,0 +1,20 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret is correctly position for block whose only child is an empty span</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
div:focus {
outline: 3px solid blue;
}
</style>
<div contenteditable="true" spellcheck="false"><span></span></div>
<script>
SimpleTest.waitForFocus(function() {
document.querySelector('[contenteditable="true"]').focus();
requestAnimationFrame(function() {
requestAnimationFrame(function() {
document.documentElement.removeAttribute("class");
});
});
});
</script>

View File

@ -0,0 +1,23 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret is correctly position for block whose only child is an empty pseudo</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
div:focus {
outline: 3px solid blue;
}
div::before {
content: "";
}
</style>
<div contenteditable="true" spellcheck="false"></div>
<script>
SimpleTest.waitForFocus(function() {
document.querySelector('[contenteditable="true"]').focus();
requestAnimationFrame(function() {
requestAnimationFrame(function() {
document.documentElement.removeAttribute("class");
});
});
});
</script>

View File

@ -356,6 +356,11 @@ support-files =
bug1591282-1-ref.html
bug1611661.html
bug1611661-ref.html
bug1634543-1.html
bug1634543-1-ref.html
bug1634543-2.html
bug1634543-3.html
bug1634543-4.html
image_rgrg-256x256.png
input-invalid-ref.html
input-maxlength-invalid-change.html

View File

@ -262,6 +262,13 @@ var tests = [
[ 'bug1524266-1.html' , 'bug1524266-1-ref.html' ] ,
// Checks that the caret isn't occluded by children background content.
[ 'bug1591282-1.html' , 'bug1591282-1-ref.html' ] ,
// Caret on contenteditable with abspos and / or empty content.
[ 'bug1634543-1.html' , 'bug1634543-1-ref.html' ] ,
[ 'bug1634543-2.html' , 'bug1634543-1-ref.html' ] ,
// TODO(emilio): This fails because nsInlineFrame::GetCaretBaseline doesn't
// return one line-height for an empty inline, and it probably should..
// [ 'bug1634543-3.html' , 'bug1634543-1-ref.html' ] ,
[ 'bug1634543-4.html' , 'bug1634543-1-ref.html' ] ,
function() {SpecialPowers.pushPrefEnv({'clear': [['layout.accessiblecaret.enabled_on_touch']]}, nextTest);} ,
function() {SpecialPowers.pushPrefEnv({'set': [['accessibility.browsewithcaret', true]]}, nextTest);} ,
[ 'bug1529492-1.html' , 'bug1529492-1-ref.html' ] ,

View File

@ -625,10 +625,13 @@ nscoord nsBlockFrame::GetCaretBaseline() const {
if (!mLines.empty()) {
ConstLineIterator line = LinesBegin();
const nsLineBox* firstLine = line;
if (firstLine->GetChildCount()) {
return bp.top + firstLine->mFirstChild->GetCaretBaseline();
for (nsIFrame* f = firstLine->mFirstChild; f; f = f->GetNextInFlow()) {
if (!f->IsEmpty()) {
return bp.top + f->GetCaretBaseline();
}
}
}
float inflation = nsLayoutUtils::FontSizeInflationFor(this);
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetFontMetricsForFrame(this, inflation);