Gecko's intrinsic size computation for blocks containing floats (was Re: Interop: Floaters and BFC within inline-blocks)

To follow up on this thread [1] and the discussion we had on it at
the face-to-face [2], I was asked to write the heuristics Gecko uses
for computing intrinsic widths (or intrinsic inline-sizes) in the
presence of floats.

The primary case we discussed was computing the max-content size.

To define this, let me define the terms:
 * forced break - one of:
   * the beginning or end of a block
   * a <br>
   * any segment break (CR, LF, CRLF) that is not collapsible per
     http://dev.w3.org/csswg/css-text/#line-break-transform
 * optional break - one of an:
   * optional break point before or after a replaced element
   * optional break point within text
   (which I won't attempt to define further, and I'm actually not
   even sure how our code works correctly for text, since I don't
   see where it considers 'white-space', although it clearly does)

The inline max-content width of a run of text (starting and ending
with a forced break) containing floats is, in Gecko, the sum of:
 * the inline max-content width of the inline content, roughly as
   defined already in css-sizing
 * the inline max-content width contribution of the floats (defined
   below).
This assumes that the floats fit next to the inline content between
the same set of forced breaks as the float's placeholders, and
handles clear within the floats but not relative to inline content.

We compute the inline max-content width contribution of the floats
using the following pseudocode:
  cleared_floats = 0
  uncleared_left_floats = 0
  uncleared_right_floats = 0
  for each float in order:
    if float's 'clear' is not 'none':
      cleared_floats = max(cleared_floats,
                           uncleared_left_floats + uncleared_right_floats)
      if float's 'clear' is not 'right':
        uncleared_left_floats = 0
      if float's 'clear' is not 'left':
        uncleared_right_floats = 0
    if float's 'float' is 'left':
      uncleared_left_floats += intrinsic width of float
    else
      uncleared_right_floats += intrinsic width of float
  return max(cleared_floats, uncleared_left_floats + uncleared_right_floats)

For computing min-content size of a block, which we actually weren't
thinking was problematic, the spec currently specifies that floats
are never assumed to be next to inline content.  In other words, the
spec says that the min-content width of the floats embedded within
inline content and the min-content width of the inline content are
simply merged using max().

This actually isn't what we do, since it breaks the invariant that
min-content width has to be less than or equal to max-content width.
It breaks that invariant in the case of negative margins or negative
text-indent in the inline content, at least given the algorithm
above for computing max-content widths.

Instead, we consider runs of inline content between forced breaks or
optional breaks, but ignore any optional break for which (ignoring
floats):
 * there is no text or replaced inline elements since the previous
   nonignored break
 * the intrinsic inline size of the inline content since the
   previous non-ignored break is negative (which handles the case I
   mentioned above).
The intrinsic min-content width is then the largest of the
min-content widths of these runs of inline content or the largest
min-content width of a float.  (This assumes that the floats are
never next to each other and are never next to inline content, which
is the desired behavior for min-content width.)

Note that trimming of trailing whitespace and addition of
hyphenation space are considered; I simply omitted that description
above to save space.

This fulfills CSS-ACTION-660 [4].

-David

[1] http://lists.w3.org/Archives/Public/www-style/2014Oct/thread.html#msg61
[2] http://logs.csswg.org/irc.w3.org/css/2014-10-27/#e484693 ,
    from 13:30 through 14:21
[3] http://dev.w3.org/csswg/css-sizing/#block-intrinsic
[4] https://www.w3.org/Style/CSS/Tracker/actions/660

-- 
𝄞   L. David Baron                         http://dbaron.org/   𝄂
𝄢   Mozilla                          https://www.mozilla.org/   𝄂
             Before I built a wall I'd ask to know
             What I was walling in or walling out,
             And to whom I was like to give offense.
               - Robert Frost, Mending Wall (1914)

Received on Thursday, 6 November 2014 23:49:42 UTC