| Index: third_party/WebKit/Source/core/layout/ng/BlockLayout.md
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/BlockLayout.md b/third_party/WebKit/Source/core/layout/ng/BlockLayout.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2357fba2f16ed962afb185c21392a1aa396ccda7
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/layout/ng/BlockLayout.md
|
| @@ -0,0 +1,156 @@
|
| +# Block Layout #
|
| +
|
| +This document can be viewed in formatted form [here](https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/core/layout/ng/BlockLayout.md).
|
| +
|
| +## Floats ##
|
| +
|
| +TODO.
|
| +
|
| +## An introduction to margin collapsing ##
|
| +
|
| +A simple way to think about [margin collapsing](https://www.w3.org/TR/CSS2/box.html#collapsing-margins)
|
| +is that it takes the maximum margin between two elements. For example:
|
| +
|
| +```html
|
| +<!-- The divs below are 20px apart -->
|
| +<div style="margin-bottom: 10px;">Hi</div>
|
| +<div style="margin-top: 20px;">there</div>
|
| +```
|
| +
|
| +This is complicated by _negative_ margins. For example:
|
| +
|
| +```html
|
| +<!-- The divs below are 10px apart -->
|
| +<div style="margin-bottom: 20px;">Hi</div>
|
| +<div style="margin-top: -10px;">there</div>
|
| +
|
| +<!-- The divs below are -20px apart -->
|
| +<div style="margin-bottom: -20px;">Hi</div>
|
| +<div style="margin-top: -10px;">there</div>
|
| +```
|
| +
|
| +The rule here is: `max(pos_margins) + min(neg_margins)`. This rule we'll refer
|
| +to as the _margin collapsing rule_. If this only happened between top level
|
| +elements it would be pretty simple, however consider the following:
|
| +
|
| +```html
|
| +<!-- The top-level divs below are -2px apart -->
|
| +<div style="margin-bottom: 3px">
|
| + <div style="margin-bottom: -5">
|
| + <div style="margin-bottom: 7px">Hi</div>
|
| + </div>
|
| +</div>
|
| +<div style="margin-top: 11px">
|
| + <div style="margin-top: -13px">there</div>
|
| +</div>
|
| +```
|
| +
|
| +In the above example as there isn't **anything** separating the edges of two
|
| +fragments the margins stack together (e.g. no borders or padding). There are
|
| +known as **adjoining margins**. If we apply our formula to the above we get:
|
| +`max(3, 7, 11) + min(-5, -13) = -2`.
|
| +
|
| +A useful concept is a **margin strut**. This is a pair of margins consisting of
|
| +one positive and one negative margin.
|
| +
|
| +A margin strut allows us to keep track of the largest positive and smallest
|
| +negative margin. E.g.
|
| +```cpp
|
| +struct MarginStrut {
|
| + LayoutUnit pos_margin;
|
| + LayoutUnit neg_margin;
|
| +
|
| + void Append(LayoutUnit margin) {
|
| + if (margin < 0)
|
| + neg_margin = std::min(margin, neg_margin);
|
| + else
|
| + pos_margin = std::max(margin, pos_margin);
|
| + }
|
| +
|
| + LayoutUnit Sum() { return pos_margin + neg_margin; }
|
| +}
|
| +```
|
| +
|
| +A naïve algorithm for the adjoining margins case would be to _bubble_ up
|
| +margins. For example each fragment would have a **margin strut** at the
|
| +block-start and block-end edge. If the child fragment was **adjoining** to its
|
| +parent, you simply keep track of the margins by calling `Append` on the margin
|
| +strut. E.g.
|
| +
|
| +```cpp
|
| +// fragment1 is the first child.
|
| +MarginStrut s1 = fragment1.block_start_margin_strut;
|
| +s1.Append(node1.style.margin_start);
|
| +
|
| +builder.SetStartMarginStrut(s1);
|
| +
|
| +// fragment2 is the last child.
|
| +MarginStrut s2 = fragment2.block_end_margin_strut;
|
| +s2.Append(node2.style.margin_start);
|
| +
|
| +builder.SetEndMarginStrut(s2);
|
| +```
|
| +
|
| +When it comes time to collapse the margins you can use the margin collapsing
|
| +rule, e.g.
|
| +```cpp
|
| +MarginStrut s1 = fragment1.block_end_margin_strut;
|
| +MarginStrut s2 = fragment2.block_start_margin_strut;
|
| +LayoutUnit distance =
|
| + std::max(s1.pos_margin, s2.pos_margin) +
|
| + std::min(s1.neg_margin, s2.neg_margin);
|
| +```
|
| +
|
| +This would be pretty simple - however it doesn't work. As we discussed in the
|
| +floats section a _child_ will position _itself_ within the BFC. If we did margin
|
| +collapsing this way we'd create a circular dependency between layout and
|
| +positioning. E.g. we need to perform layout in order to determine the
|
| +block-start margin strut, which would allow us to position the fragment, which
|
| +would allow us to perform layout.
|
| +
|
| +We **invert** the problem. A fragment now only produces an _end_ margin strut.
|
| +The _start_ margin strut becomes an input as well as where the margin strut is
|
| +currently positioned within the BFC. For example:
|
| +
|
| +```cpp
|
| +Fragment* Layout(LogicalOffset bfc_estimate, MarginStrut input_strut) {
|
| + MarginStrut curr_strut = input_strut;
|
| + LogicalOffset curr_bfc_estimate = bfc_estimate;
|
| +
|
| + // We collapse the margin strut which allows us to compute our BFC offset if
|
| + // we have border or padding. I.e. we don't have an adjoining margin.
|
| + if (border_padding.block_start) {
|
| + curr_bfc_estimate += curr_strut.Sum();
|
| + curr_strut = MarginStrut();
|
| +
|
| + fragment_builder.SetBfcOffset(curr_bfc_estimate);
|
| + curr_bfc_estimate += border_padding.block_start;
|
| + }
|
| +
|
| + for (const auto& child : children) {
|
| + curr_strut.Append(child.margins.block_start);
|
| + const auto* fragment = child.Layout(curr_bfc_estimate, curr_strut);
|
| +
|
| + curr_strut = fragment->end_margin_strut;
|
| + curr_strut.Append(child.margins.block_end);
|
| +
|
| + curr_bfc_estimate = fragment->BfcOffset() + fragment->BlockSize();
|
| + }
|
| +
|
| + fragment_builder.SetEndMarginStrut(curr_strut);
|
| +
|
| + return fragment_builder.ToFragment();
|
| +}
|
| +```
|
| +
|
| +It isn't immediately obvious that this works, but if you try and work through an
|
| +example manually, it'll become clearer.
|
| +
|
| +There are lots of different things which can "resolve" the BFC offset of an
|
| +element. For example inline content (text, atomic inlines), border and padding,
|
| +if a child _might_ be affected by clearance.
|
| +
|
| +## Zero block-size fragments ##
|
| +
|
| +TODO.
|
| +
|
|
|