Bug 1562057: Change size-contained & empty select elements to have the same inline-size. r=TYLin

Per the css-contain specification, size contained elements must be sized as if
they were empty. Up until now, we've been handling that by just using "0" as
the intrinsic size of some components, but that doesn't actually match the size
of a "true" empty select, which has some nonzero width from:
 (a) the default inline-axis padding on the display frame (added in a rule for
     the ::-moz-display-comboboxcontrol-frame pseudo, in forms.css).

 (b) the width (inline-size) of the display frame's "placeholder" space
     character, which has a small intrinsic width (but which really only exists
     for *block-axis* sizing and alignment, when no option is selected from
     the dropdown).

This patch addresses issue (a) by explicitly adding the display frame's
inline-axis padding to size-contained elements, and it addresses issue (b) by
changing to use a zero-width space character in empty select elements.

So: as of this patch, size-contained select elements are getting a little wider
(to address (a)), and empty select elements are also getting a little skinnier
(to address (b)), and they'll end up being the same width.

(I chose U+FEFF "zero-width non-breaking-space" since we were previously using
a non-breaking space character. I'm not sure if the non-breaking aspect matters,
but I figured I'd preserve that to be on the safe side.)

Differential Revision: https://phabricator.services.mozilla.com/D48791

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Daniel Holbert 2019-10-11 16:51:41 +00:00
parent 0f977493e1
commit c0534692fd
7 changed files with 157 additions and 17 deletions

View File

@ -719,9 +719,16 @@ nscoord nsComboboxControlFrame::GetIntrinsicISize(
const bool isContainSize = StyleDisplay()->IsContainSize();
nscoord displayISize = 0;
if (MOZ_LIKELY(mDisplayFrame) && !isContainSize) {
displayISize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
mDisplayFrame, aType);
if (MOZ_LIKELY(mDisplayFrame)) {
if (isContainSize) {
// Note: the "h" in "hPadding" here really means "inline-axis".
// Its struct uses "h" prefixes for historical reasons, but they're all
// for the inline-axis, not (necessarily) the horizontal axis.
displayISize = mDisplayFrame->IntrinsicISizeOffsets().hPadding;
} else {
displayISize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
mDisplayFrame, aType);
}
}
if (mDropdownFrame) {
@ -988,9 +995,16 @@ void nsComboboxControlFrame::HandleRedisplayTextEvent() {
void nsComboboxControlFrame::ActuallyDisplayText(bool aNotify) {
RefPtr<nsTextNode> displayContent = mDisplayContent;
if (mDisplayedOptionTextOrPreview.IsEmpty()) {
// Have to use a non-breaking space for line-block-size calculations
// to be right
static const char16_t space = 0xA0;
// Have to use a space character of some sort for line-block-size
// calculations to be right. Also, the space character must be zero-width
// in order for the the inline-size calculations to be consistent between
// size-contained comboboxes vs. empty comboboxes.
//
// XXXdholbert Does this space need to be "non-breaking"? I'm not sure
// if it matters, but we previously had a comment here (added in 2002)
// saying "Have to use a non-breaking space for line-height calculations
// to be right". So I'll stick with a non-breaking space for now...
static const char16_t space = 0xFEFF;
displayContent->SetText(&space, 1, aNotify);
} else {
displayContent->SetText(mDisplayedOptionTextOrPreview, aNotify);

View File

@ -36,7 +36,7 @@ fuzzy-if(webrender&&winWidget,0-24,0-2) == contain-size-inline-flex-001.html con
== contain-size-multicol-002.html contain-size-multicol-002-ref.html
== contain-size-multicol-003.html contain-size-multicol-003-ref.html
fuzzy-if(Android,0-4,0-4) == contain-size-select-elem-001.html contain-size-select-elem-001-ref.html # bug 1480862
fails-if(!gtkWidget) == contain-size-select-elem-002.html contain-size-select-elem-002-ref.html # bug 1562057
== contain-size-select-elem-002.html contain-size-select-elem-002-ref.html
== contain-size-select-elem-003.html contain-size-select-elem-003-ref.html
== contain-size-select-elem-004.html contain-size-select-elem-004-ref.html
== contain-size-select-elem-005.html contain-size-select-elem-005-ref.html

View File

@ -1,3 +0,0 @@
[contain-size-select-001.html]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1562057

View File

@ -1,3 +0,0 @@
[contain-size-select-002.html]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1562057

View File

@ -1,4 +0,0 @@
[contain-size-select-elem-002.html]
expected:
if os == "linux": PASS
FAIL

View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Reference for sizing of select elements, with wide vs. empty option selected</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<style>
select {
color: transparent;
margin: 1px;
}
div.customBorder > select {
/* This class is to let us test select elements *without* native theming
(for browsers that have both native and non-native controls): */
border: 3px solid black;
}
</style>
</head>
<body>
<div>
<select>
<option>some wide option</option>
</select>
<br>
<select>
<option>some wide option</option>
</select>
<br>
<select>
<option>some wide option</option>
</select>
<br>
<select>
<option>some wide option</option>
</select>
</div>
<!-- This is the same as above, but now with a custom border on the
select elements: -->
<div class="customBorder">
<select>
<option>some wide option</option>
</select>
<br>
<select>
<option>some wide option</option>
</select>
<br>
<select>
<option>some wide option</option>
</select>
<br>
<select>
<option>some wide option</option>
</select>
</div>
</body>
</html>

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test for sizing of select elements, with wide vs. empty option selected</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#list-box">
<link rel="match" href="select-sizing-001-ref.html">
<style>
select {
color: transparent;
margin: 1px;
}
div.customBorder > select {
/* This class is to let us test select elements *without* native theming
(for browsers that have both native and non-native controls): */
border: 3px solid black;
}
</style>
</head>
<body>
<div>
<!-- Wide thing is 2nd, and not selected: -->
<select>
<option></option>
<option>some wide option</option>
</select>
<br>
<!-- Wide thing is 2nd, and selected: -->
<select>
<option></option>
<option selected>some wide option</option>
</select>
<br>
<!-- Wide thing is 1st, and selected (implicitly): -->
<select>
<option>some wide option</option>
<option></option>
</select>
<br>
<!-- Wide thing is 1st, and not selected: -->
<select>
<option>some wide option</option>
<option selected></option>
</select>
</div>
<!-- This is the same as above, but now with a custom border on the
select elements: -->
<div class="customBorder">
<!-- Wide thing is 2nd, and not selected: -->
<select>
<option></option>
<option>some wide option</option>
</select>
<br>
<!-- Wide thing is 2nd, and selected: -->
<select>
<option></option>
<option selected>some wide option</option>
</select>
<br>
<!-- Wide thing is 1st, and selected (implicitly): -->
<select>
<option>some wide option</option>
<option></option>
</select>
<br>
<!-- Wide thing is 1st, and not selected: -->
<select>
<option>some wide option</option>
<option selected></option>
</select>
</div>
</body>
</html>