Bug 1896210 Part 1 - Minor format tweak for LayoutOverview.md. r=layout-reviewers,emilio

Drop backslashes because escaping quote, double-quote, etc. is not needed in
markdown. Indent fix for lists.

Differential Revision: https://phabricator.services.mozilla.com/D210096
This commit is contained in:
Ting-Yu Lin 2024-05-17 23:22:06 +00:00
parent e270f922bd
commit 457d0008fc

View file

@ -1,3 +1,5 @@
<!-- -*- mode: Markdown; fill-column: 72; -*- -->
# Layout Overview # Layout Overview
Much of the layout code deals with operations on the frame tree (or Much of the layout code deals with operations on the frame tree (or
@ -5,9 +7,9 @@ rendering tree). In the frame tree, each node represents a rectangle
(or, for SVG, other shapes). The frame tree has a shape similar to the (or, for SVG, other shapes). The frame tree has a shape similar to the
content tree, since many content nodes have one corresponding frame, content tree, since many content nodes have one corresponding frame,
though it differs in a few ways, since some content nodes have more than though it differs in a few ways, since some content nodes have more than
one frame or don\'t have any frames at all. When elements are one frame or don't have any frames at all. When elements are
display:none in CSS or undisplayed for certain other reasons, they display:none in CSS or undisplayed for certain other reasons, they
won\'t have any frames. When elements are broken across lines or pages, won't have any frames. When elements are broken across lines or pages,
they have multiple frames; elements may also have multiple frames when they have multiple frames; elements may also have multiple frames when
multiple frames nested inside each other are needed to display a single multiple frames nested inside each other are needed to display a single
element (for example, a table, a table cell, or many types of form element (for example, a table, a table cell, or many types of form
@ -43,7 +45,7 @@ There were a number of cases where this rule was violated in the past
and we stored important data in the frame tree; however, most (though and we stored important data in the frame tree; however, most (though
not quite all) such cases are now fixed. not quite all) such cases are now fixed.
The rectangle represented by the frame is what CSS calls the element\'s The rectangle represented by the frame is what CSS calls the element's
border box. This is the outside edge of the border (or the inside edge border box. This is the outside edge of the border (or the inside edge
of the margin). The margin lives outside the border; and the padding of the margin). The margin lives outside the border; and the padding
lives inside the border. In addition to nsIFrame::GetRect, we also have lives inside the border. In addition to nsIFrame::GetRect, we also have
@ -61,7 +63,7 @@ optimizations: it is a rectangle covering all of the area that might be
painted when the frame and all of its descendants paint. The scrollable painted when the frame and all of its descendants paint. The scrollable
overflow represents the area that the user should be able to scroll to overflow represents the area that the user should be able to scroll to
to see the frame and all of its descendants. In some cases differences to see the frame and all of its descendants. In some cases differences
between the frame\'s rect and its overflow happen because of descendants between the frame's rect and its overflow happen because of descendants
that stick out of the frame; in other cases they occur because of some that stick out of the frame; in other cases they occur because of some
characteristic of the frame itself. The two overflow areas are similar, characteristic of the frame itself. The two overflow areas are similar,
but there are differences: for example, margins are part of scrollable but there are differences: for example, margins are part of scrollable
@ -86,7 +88,7 @@ the continuations of the span are siblings (since they are both children
of the paragraph), but the continuations of the link are not siblings of the paragraph), but the continuations of the link are not siblings
(since each continuation of the link is descended from a different (since each continuation of the link is descended from a different
continuation of the span). Traversing the entire frame tree does **not** continuation of the span). Traversing the entire frame tree does **not**
require explicit traversal of any frames\' continuations-list, since all require explicit traversal of any frames' continuations-list, since all
of the continuations are descendants of the element containing the of the continuations are descendants of the element containing the
break. break.
@ -99,11 +101,11 @@ nsIFrame::GetNextInFlow and nsIFrame::GetPrevInFlow traverse only the
fluid continuations and do not cross fixed continuation boundaries. fluid continuations and do not cross fixed continuation boundaries.
If an inline frame has non-inline children, then we split the original If an inline frame has non-inline children, then we split the original
inline frame into parts. The original inline\'s children are distributed inline frame into parts. The original inline's children are distributed
into these parts like so: The children of the original inline are into these parts like so: The children of the original inline are
grouped into runs of inline and non-inline, and runs of inline get an grouped into runs of inline and non-inline, and runs of inline get an
inline parent, while runs of non-inline get an anonymous block parent. inline parent, while runs of non-inline get an anonymous block parent.
We call this \'ib-splitting\' or \'block-inside-inline splitting\'. This We call this "ib-splitting" or "block-inside-inline splitting." This
splitting proceeds recursively up the frame tree until all non-inlines splitting proceeds recursively up the frame tree until all non-inlines
inside inlines are ancestors of a block frame with anonymous block inside inlines are ancestors of a block frame with anonymous block
wrappers in between. This splitting maintains the relative order between wrappers in between. This splitting maintains the relative order between
@ -143,16 +145,14 @@ descriptions at the top that show up in DXR):
contains frame classes for the XUL box model and for various XUL contains frame classes for the XUL box model and for various XUL
widgets widgets
Bugzilla: Bugzilla: all of the components whose names begin with "Layout" in the
"Core" product.
- All of the components whose names begin with \"Layout\" in the
\"Core\" product
Further documentation: Further documentation:
- Talk: [Introduction to graphics/layout - Talk: [Introduction to graphics/layout
architecture](https://air.mozilla.org/introduction-to-graphics-layout-architecture/) architecture](https://air.mozilla.org/introduction-to-graphics-layout-architecture/)
(Robert O\'Callahan, 2014-04-18) (Robert O'Callahan, 2014-04-18)
- Talk: [Layout and - Talk: [Layout and
Styles](https://air.mozilla.org/bz-layout-and-styles/) (Boris Styles](https://air.mozilla.org/bz-layout-and-styles/) (Boris
Zbarsky, 2014-10-14) Zbarsky, 2014-10-14)
@ -162,9 +162,9 @@ Further documentation:
Frame construction is the process of creating frames. This is done when Frame construction is the process of creating frames. This is done when
styles change in ways that require frames to be created or recreated or styles change in ways that require frames to be created or recreated or
when nodes are inserted into the document. The content tree and the when nodes are inserted into the document. The content tree and the
frame tree don\'t have quite the same shape, and the frame construction frame tree don't have quite the same shape, and the frame construction
process does some of the work of creating the right shape for the frame process does some of the work of creating the right shape for the frame
tree. It handles the aspects of creating the right shape that don\'t tree. It handles the aspects of creating the right shape that don't
depend on layout information. So for example, frame construction handles depend on layout information. So for example, frame construction handles
the work needed to implement [table anonymous the work needed to implement [table anonymous
objects](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) but objects](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) but
@ -189,13 +189,12 @@ frame constructor either fixes up the list of frame construction items
so that the resulting frame tree would be valid or throws away the list so that the resulting frame tree would be valid or throws away the list
of frame construction items and requests the destruction and re-creation of frame construction items and requests the destruction and re-creation
of the frame for the parent element so that it has a chance to create a of the frame for the parent element so that it has a chance to create a
list of frame construction items that it `<em>`{=html}can`</em>`{=html} list of frame construction items that it _can_ fix up.
fix up.
Once the frame constructor has a list of frame construction items and an Once the frame constructor has a list of frame construction items and an
insertion point that would lead to a valid frame tree, it goes ahead and insertion point that would lead to a valid frame tree, it goes ahead and
creates frames based on those items. Creation of a non-leaf frame creates frames based on those items. Creation of a non-leaf frame
recursively attempts to create frames for the children of that frame\'s recursively attempts to create frames for the children of that frame's
element, so in effect frames are created in a depth-first traversal of element, so in effect frames are created in a depth-first traversal of
the content tree. the content tree.
@ -226,8 +225,8 @@ types.
Reflow is the process of computing the positions and sizes of frames. Reflow is the process of computing the positions and sizes of frames.
(After all, frames represent rectangles, and at some point we need to (After all, frames represent rectangles, and at some point we need to
figure out exactly \*what\* rectangle.) Reflow is done recursively, with figure out exactly **what** rectangle.) Reflow is done recursively, with
each frame\'s Reflow method calling the Reflow methods on that frame\'s each frame's Reflow method calling the Reflow methods on that frame's
descendants. descendants.
In many cases, the correct results are defined by CSS specifications In many cases, the correct results are defined by CSS specifications
@ -241,12 +240,12 @@ written in terms of constraints, whereas our layout code consists of
algorithms optimized for incremental recomputation. algorithms optimized for incremental recomputation.
The reflow generally starts from the root of the frame tree, though some The reflow generally starts from the root of the frame tree, though some
other types of frame can act as \"reflow roots\" and start a reflow from other types of frame can act as "reflow roots" and start a reflow from
them (nsTextControlFrame is one example; see the them (nsTextControlFrame is one example; see the
[NS\_FRAME\_REFLOW\_ROOT](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_REFLOW_ROOT&redirect=true) [NS_FRAME_REFLOW_ROOT](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_REFLOW_ROOT&redirect=true)
frame state bit). Reflow roots must obey the invariant that a change frame state bit). Reflow roots must obey the invariant that a change
inside one of their descendants never changes their rect or overflow inside one of their descendants never changes their rect or overflow
areas (though currently scrollbars are reflow roots but don\'t quite areas (though currently scrollbars are reflow roots but don't quite
obey this invariant). obey this invariant).
In many cases, we want to reflow a part of the frame tree, and we want In many cases, we want to reflow a part of the frame tree, and we want
@ -256,12 +255,12 @@ of work we need to redo to be proportional to the amount of content. We
also want to efficiently handle a series of changes to the same content. also want to efficiently handle a series of changes to the same content.
To do this, we maintain two bits on frames: To do this, we maintain two bits on frames:
[NS\_FRAME\_IS\_DIRTY](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_IS_DIRTY&redirect=true) [NS_FRAME_IS_DIRTY](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_IS_DIRTY&redirect=true)
indicates that a frame and all of its descendants require reflow. indicates that a frame and all of its descendants require reflow.
[NS\_FRAME\_HAS\_DIRTY\_CHILDREN](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_HAS_DIRTY_CHILDREN&redirect=true) [NS_FRAME_HAS_DIRTY_CHILDREN](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_HAS_DIRTY_CHILDREN&redirect=true)
indicates that a frame has a descendant that is dirty or has had a indicates that a frame has a descendant that is dirty or has had a
descendant removed (i.e., that it has a child that has descendant removed (i.e., that it has a child that has
NS\_FRAME\_IS\_DIRTY or NS\_FRAME\_HAS\_DIRTY\_CHILDREN or it had a NS_FRAME_IS_DIRTY or NS_FRAME_HAS_DIRTY_CHILDREN or it had a
child removed). These bits allow coalescing of multiple updates; this child removed). These bits allow coalescing of multiple updates; this
coalescing is done in PresShell, which tracks the set of reflow roots coalescing is done in PresShell, which tracks the set of reflow roots
that require reflow. The bits are set during calls to that require reflow. The bits are set during calls to
@ -304,13 +303,13 @@ intrinsic size methods called GetMinSize, GetPrefSize, and GetMaxSize
method called Layout. In many cases these methods defer some of the method called Layout. In many cases these methods defer some of the
computation to a separate object called a layout manager. computation to a separate object called a layout manager.
When an individual frame\'s Reflow method is called, most of the input When an individual frame's Reflow method is called, most of the input
is provided on an object called ReflowInput and the output is filled in is provided on an object called ReflowInput and the output is filled in
to an object called ReflowOutput. After reflow, the caller (usually the to an object called ReflowOutput. After reflow, the caller (usually the
parent) is responsible for setting the frame\'s size based on the parent) is responsible for setting the frame's size based on the
metrics reported. (This can make some computations during reflow metrics reported. (This can make some computations during reflow
difficult, since the new size is found in either the reflow state or the difficult, since the new size is found in either the reflow state or the
metrics, but the frame\'s size is still the old size. However, it\'s metrics, but the frame's size is still the old size. However, it's
useful for invalidating the correct areas that need to be repainted.) useful for invalidating the correct areas that need to be repainted.)
One major difference worth noting is that in XUL layout, the size of the One major difference worth noting is that in XUL layout, the size of the
@ -333,7 +332,7 @@ print-preview, and multicolumn layout.
To render a DOM node, represented as `nsIContent` object, Gecko creates To render a DOM node, represented as `nsIContent` object, Gecko creates
zero or more frames (`nsIFrame` objects). Each frame represents a zero or more frames (`nsIFrame` objects). Each frame represents a
rectangular area usually corresponding to the node\'s CSS box as rectangular area usually corresponding to the node's CSS box as
described by the CSS specs. Simple elements are often representable with described by the CSS specs. Simple elements are often representable with
exactly one frame, but sometimes an element needs to be represented with exactly one frame, but sometimes an element needs to be represented with
more than one frame. For example, text breaking across lines: more than one frame. For example, text breaking across lines:
@ -342,7 +341,7 @@ more than one frame. For example, text breaking across lines:
AAA xxxxxxx AAA xxxxxxx
The A element is a single DOM node but obviously a single rectangular The A element is a single DOM node but obviously a single rectangular
frame isn\'t going to represent its layout precisely. frame isn't going to represent its layout precisely.
Similarly, consider text breaking across pages: Similarly, consider text breaking across pages:
@ -372,9 +371,9 @@ fully laid out within the constraints assigned (e.g., when inline text
will not fit within a particular width constraint, or when a block will not fit within a particular width constraint, or when a block
cannot be laid out within a particular height constraint). cannot be laid out within a particular height constraint).
Continuation frames created during reflow are called \"fluid\" Continuation frames created during reflow are called "fluid"
continuations (or \"in-flows\"). Other continuation frames (currently, continuations (or "in-flows"). Other continuation frames (currently,
those created during bidi resolution), are, in contrast, \"non-fluid\". those created during bidi resolution), are, in contrast, "non-fluid".
The `NS_FRAME_IS_FLUID_CONTINUATION` state bit indicates whether a The `NS_FRAME_IS_FLUID_CONTINUATION` state bit indicates whether a
continuation frame is fluid or not. continuation frame is fluid or not.
@ -408,7 +407,7 @@ content element:
with the same inline element, separated by line breaks, or by with the same inline element, separated by line breaks, or by
changes in text direction changes in text direction
- `nsTableColFrame` creates non-fluid continuations for itself if it - `nsTableColFrame` creates non-fluid continuations for itself if it
has span=\"N\" and N \> 1 has span="N" and N > 1
- If a block frame is a multi-column container and has - If a block frame is a multi-column container and has
`column-span:all` children, it creates multiple `nsColumnSetFrame` `column-span:all` children, it creates multiple `nsColumnSetFrame`
children, which are linked together as non-fluid continuations. children, which are linked together as non-fluid continuations.
@ -422,10 +421,10 @@ content element:
Sometimes the content of a frame needs to break across pages even though Sometimes the content of a frame needs to break across pages even though
the frame itself is complete. This usually happens if an element with the frame itself is complete. This usually happens if an element with
fixed height has overflow that doesn\'t fit on one page. In this case, fixed height has overflow that doesn't fit on one page. In this case,
the completed frame is \"overflow incomplete\", and special the completed frame is "overflow incomplete", and special
continuations are created to hold its overflow. These continuations are continuations are created to hold its overflow. These continuations are
called \"overflow containers\". They are invisible, and are kept on a called "overflow containers". They are invisible, and are kept on a
special list in their parent. See documentation in special list in their parent. See documentation in
[nsContainerFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsContainerFrame.h) [nsContainerFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsContainerFrame.h)
and example trees in [bug 379349 comment and example trees in [bug 379349 comment
@ -447,26 +446,26 @@ to traverse next-continuation links. All continuations are reachable by
traversing the `GetNextSibling` links from the result of `GetFirstChild` traversing the `GetNextSibling` links from the result of `GetFirstChild`
for all child lists. for all child lists.
Second, the following property holds: Second, the following property holds: consider two frames F1 and F2
where F1's next-continuation is F2 and their respective parent frames
- Consider two frames F1 and F2 where F1\'s next-continuation is F2 are P1 and P2. Then either P1's next continuation is P2, or P1 == P2,
and their respective parent frames are P1 and P2. Then either P1\'s because P is responsible for breaking F1 and F2.
next continuation is P2, or P1 == P2, because P is responsible for
breaking F1 and F2.
In other words, continuations are sometimes siblings of each other, and In other words, continuations are sometimes siblings of each other, and
sometimes not. If their parent content was broken at the same point, sometimes not. If their parent content was broken at the same point,
then they are not siblings, since they are children of different then they are not siblings, since they are children of different
continuations of the parent. So in the frame tree for the markup continuations of the parent. So in the frame tree for the markup
` <p>This is <b><i>some <br/>text</i></b>.</p>` ```html
<p>This is <b><i>some<br/>text</i></b>.</p>
```
the two continuations for the `b` element are siblings (unless the line the two continuations for the `b` element are siblings (unless the line
break is also a page break), but the two continuations for the `i` break is also a page break), but the two continuations for the `i`
element are not. element are not.
There is an exception to that property when F1 is a first-in-flow float There is an exception to that property when F1 is a first-in-flow float
placeholder. In that case F2\'s parent will be the next-in-flow of F1\'s placeholder. In that case F2's parent will be the next-in-flow of F1's
containing block. containing block.
### Reflow statuses ### Reflow statuses
@ -474,14 +473,14 @@ containing block.
The aStatus argument of Reflow reflects that. `IsComplete()` means that The aStatus argument of Reflow reflects that. `IsComplete()` means that
we reflowed all the content and no more next-in-flows are needed. At we reflowed all the content and no more next-in-flows are needed. At
that point there may still be next in flows, but the parent will delete that point there may still be next in flows, but the parent will delete
them. `IsIncomplete()` means \"some content did not fit in this frame\". them. `IsIncomplete()` means "some content did not fit in this frame".
`IsOverflowIncomplete()` means that the frame is itself complete, but `IsOverflowIncomplete()` means that the frame is itself complete, but
some of its content didn\'t fit: this triggers the creation of overflow some of its content didn't fit: this triggers the creation of overflow
containers for the frame\'s continuations. `IsIncomplete()` and containers for the frame's continuations. `IsIncomplete()` and
`NextInFlowNeedsReflow()` means \"some content did not fit in this frame `NextInFlowNeedsReflow()` means "some content did not fit in this frame
AND it must be reflowed\". These values are defined and documented in AND it must be reflowed". These values are defined and documented in
[nsIFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.h) [nsIFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.h)
(search for \"Reflow status\"). (search for "Reflow status").
### Dynamic Reflow Considerations ### Dynamic Reflow Considerations
@ -489,17 +488,17 @@ When we reflow a frame F with fluid continuations, two things can
happen: happen:
- Some child frames do not fit in the passed-in width or height - Some child frames do not fit in the passed-in width or height
constraint. These frames must be \"pushed\" to F\'s next-in-flow. If constraint. These frames must be "pushed" to F's next-in-flow. If
F has no next-in-flow, we must create one under F\'s parent\'s F has no next-in-flow, we must create one under F's parent's
next-in-flow \-\-- or if F\'s parent is managing the breaking of F, next-in-flow --- or if F's parent is managing the breaking of F,
then we create F\'s next in flow directly under F\'s parent. If F is then we create F's next in flow directly under F's parent. If F is
a block, it pushes overflowing child frames to its \"overflow\" a block, it pushes overflowing child frames to its "overflow"
child list and forces F\'s next in flow to be reflowed. When we child list and forces F's next in flow to be reflowed. When we
reflow a block, we pull the child frames from the prev-in-flow\'s reflow a block, we pull the child frames from the prev-in-flow's
overflow list into the current frame. overflow list into the current frame.
- All child frames fit in the passed-in width or height constraint. - All child frames fit in the passed-in width or height constraint.
Then child frames must be \"pulled\" from F\'s next-in-flow to fill Then child frames must be "pulled" from F's next-in-flow to fill
in the available space. If F\'s next-in-flow becomes empty, we may in the available space. If F's next-in-flow becomes empty, we may
be able to delete it. be able to delete it.
In both of these situations we might end up with a frame F containing In both of these situations we might end up with a frame F containing
@ -510,17 +509,16 @@ P3, P1 has child F1 and P3 has child F2, but P2 has no F child.
A strategy for avoiding these issues is this: When pulling a frame F2 A strategy for avoiding these issues is this: When pulling a frame F2
from parent P2 to prev-in-flow P1, if F2 is a breakable container, then: from parent P2 to prev-in-flow P1, if F2 is a breakable container, then:
- If F2 has no prev-in-flow F1 in P1, then create a new primary frame - If F2 has no prev-in-flow F1 in P1, then create a new primary frame F1
F1 in P1 for F2\'s content, with F2 as its next-in-flow. in P1 for F2's content, with F2 as its next-in-flow.
- Pull children from F2 to F1 until F2 is empty or we run out of - Pull children from F2 to F1 until F2 is empty or we run out of space.
space. If F2 goes empty, pull from the next non-empty next-in-flow. If F2 goes empty, pull from the next non-empty next-in-flow. Empty
Empty continuations with no next-in-flows can be deleted. continuations with no next-in-flows can be deleted.
When pushing a frame F1 from parent P1 to P2, where F1 has a When pushing a frame F1 from parent P1 to P2, where F1 has a
next-in-flow F2 (which must be a child of P2): next-in-flow F2 (which must be a child of P2):
- Merge F2 into F1 by moving all F2\'s children into F1, then deleting - Merge F2 into F1 by moving all F2's children into F1, then deleting F2
F2
For inline frames F, we have our own custom strategy that coalesces For inline frames F, we have our own custom strategy that coalesces
adjacent inline frames. This need not change. adjacent inline frames. This need not change.