Bug 181209

Summary: Incorrect handling of line-height on ::first-line
Product: WebKit Reporter: Boris Zbarsky <bzbarsky>
Component: Layout and RenderingAssignee: Nobody <webkit-unassigned>
Status: REOPENED ---    
Severity: Normal CC: ahmad.saleem792, bfulgham, jonlee, karlcow, simon.fraser, webkit-bug-importer, zalan
Priority: P2 Keywords: BrowserCompat, FromImplementor, InRadar, WPTImpact
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
URL: http://wpt.live/css/css-pseudo/first-line-line-height-002.html
Attachments:
Description Flags
Testcase
none
Slightly modified testcase that shows the problem
none
With the '.' inside the span none

Description Boris Zbarsky 2018-01-01 21:06:47 PST
Created attachment 330308 [details]
Testcase

STEPS TO REPRODUCE: Load attached testcase

EXPECTED BEHAVIOR: The two blocks should look identical.

ACTUAL BEHAVIOR: The two blocks do not look identical.

ADDITIONAL INFORMATION:  https://drafts.csswg.org/selectors-3/#first-line says:

   The ::first-line pseudo-element is similar to an inline-level element,
   but with certain restrictions

but in Safari it's not acting like an inline-level element is supposed to in terms of line-height handling.
Comment 1 Boris Zbarsky 2018-01-01 21:10:27 PST
Note that https://drafts.csswg.org/css-pseudo-4/#first-line-styling has the same language about ::first-line being an inline.

See also https://bugs.chromium.org/p/chromium/issues/detail?id=798257 for the corresponding Blink issue.
Comment 2 Jon Lee 2018-01-02 14:19:24 PST
(In reply to Boris Zbarsky from comment #1)
> Note that https://drafts.csswg.org/css-pseudo-4/#first-line-styling has the
> same language about ::first-line being an inline.
> 
> See also https://bugs.chromium.org/p/chromium/issues/detail?id=798257 for
> the corresponding Blink issue.

In STP 46 and Firefox 57 the test case renders correctly. Chrome 63 does not render it correctly. Am I missing something?
Comment 3 Boris Zbarsky 2018-01-02 18:28:23 PST
Created attachment 330364 [details]
Slightly modified testcase that shows the problem

Er, right you are.  When I tried to make the testcase more reliable by using <br> to end the first line, the problem went away in Safari.  Here's a testcase which fails with my font sizes in Safari 11.0.2 and in STP 46.
Comment 4 zalan 2022-11-02 14:28:39 PDT
I think these test cases are incorrect:
The original test case is in standards mode. It makes the root inline box "contentful" through the invisible strut which in turn makes the line tall (taller than line-height: 0px;)
the second test case also triggers a tall (non-zero line height) root inline box through the trailing '.' character (which is still part of the first line).
Comment 5 Boris Zbarsky 2022-12-28 20:45:03 PST
The point is, the two boxes in the testcase should look identical.  Adding the span should not cause a difference in rendering.

As in, both boxes in the second testcase should have a "tall" line, ignoring the 0 line-height.  But only the box with the extra <span> does that.
Comment 6 Boris Zbarsky 2022-12-28 20:47:05 PST
Created attachment 464240 [details]
With the '.' inside the span

Moving the '.' inside the <span> does not change behavior in any way, either in terms of what the standard says to do or what WebKit does (which does not match the standard).
Comment 7 zalan 2022-12-29 08:11:26 PST
(In reply to Boris Zbarsky from comment #6)
> Created attachment 464240 [details]
> With the '.' inside the span
> 
> Moving the '.' inside the <span> does not change behavior in any way, either
It does change the behavior in both Safari(nightly) and Chrome (111.0.5496.0) in non-standards mode. The first line's height collapses to 0px on the second block.

What happens in _standards mode_ in the second block is
<div>
  <span>This is a first line.</span>
  This is a second line.
</div>
with the applied styles of
  span { line-height: 0px; color: purple }
Note that since ::first-line selector does not apply here anymore, we apply "line-height: 0px" only on the inline box triggered by the <span>.

Now this (first)line has 2 inline boxes.
- root inline box (every line has one)
- <span>'s inline box
 
The <span>'s inline box's line height is computed to 0px and the used value is also 0px.
The root inline box's line height is computed to normal and the used value is based on the relevant font metrics.

Both of these inline boxes stretch the line box as they both are considered contentful.
The <span>'s inline box stretches the line with the value of 0px, while
the root inline box stretches the line with the value of whatever the default font size here is.

While the root inline box does not have any content in the example, this is where _standards mode_ steps in.
In _standards mode_ 
1. we put an invisible strut inside every inline box
2. we measure this invisible glyph (zero width)
3. we set the inline box's height based on that measured size
4. we stretch the line box by the heigh of the (root) inline box

see https://www.w3.org/TR/css-inline-3/#inline-height
"To find the layout bounds of an inline box, the UA must first align all the glyphs 
directly contained in the inline box to each other by their dominant baselines. 
(See § 3.3 Baselines of Glyphs and Boxes.) If the inline box contains no glyphs at 
all, or if it contains only glyphs from fallback fonts, it is considered to contain 
a “strut” (an invisible glyph of zero width) with the metrics of the box’s first 
available font."

the simplest example is
<!DOCTYPE html>
<div style="border: solid">tall line<span style="font-size: 100px"></span></div>
vs.
<div style="border: solid">not so tall line<span style="font-size: 100px"></span></div>
where in _standards mode_ the "empty" inline box stretches the line due to this invisible strut. 

So in the last attached test case, 
the first block' first line is going to collapse to 0 as the root inline box's line height is computed to 0.
the second block' first line is _not_ going to collapse to 0 in _standards mode_ because of the root inline box height is computed to > 0 and it stretches the line.
In quirks mode, both the first and the second block's first line collapse to 0 (since we "ignore" the empty root inline box).

>Adding the span should not cause a difference in rendering.
The reason why it does is because the line-height is applied on the root inline box in the first block (div:first-of-type::first-line), while it is only applied on the span's inline box in the second block.
Comment 8 Boris Zbarsky 2022-12-29 08:31:17 PST
Ah, is this about this text:

> Setting line-height on ::first-line affects the fragment of the root inline box that wraps the contents of the first line

in https://drafts.csswg.org/css-pseudo-4/#first-line-styling?

That was not there when this bug was filed.  And it directly contradicts the normative text of https://drafts.csswg.org/selectors-3/#first-line
Comment 9 Karl Dubost 2023-08-15 22:24:57 PDT
The current WPT Test on the combination of ::first-line and line-height
https://wpt.fyi/results/css/css-pseudo/first-line-line-height-002.html

As defined today:
PASS: Gecko
FAIL: WebKit, Blink
Comment 10 Radar WebKit Bug Importer 2023-08-15 22:25:47 PDT
<rdar://problem/113947928>