Commit d865ee70 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[LayoutNG] Add Baseline section to inline layout README.md

BUG=636993
TBR=eae@chromium.org
NOTRY=true

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: Ibdf9bc40c3fc1a523405bfb8406a437d892a59dc
Reviewed-on: https://chromium-review.googlesource.com/580047
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488285}
parent a8dc61c1
# LayoutNG Inline Layout # # LayoutNG Inline Layout #
This directory contains the inline layout implementation This directory contains the inline layout implementation
of Blink's new layout engine "LayoutNG". of Blink's new layout engine "LayoutNG".
This README can be viewed in formatted form [here](https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/core/layout/ng/inline/README.md). This README can be viewed in formatted form [here](https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/core/layout/ng/inline/README.md).
Other parts of LayoutNG is explained [here](../README.md). Other parts of LayoutNG is explained [here](../README.md).
## High level overview ## ## High level overview ##
Inline layout is performed in the following phases: Inline layout is performed in the following phases:
1. Pre-layout. 1. Pre-layout.
2. Line breaking. 2. Line breaking.
3. Line box construction. 3. Line box construction.
This is similar to [CSS Text Processing Order of Operations], This is similar to [CSS Text Processing Order of Operations],
but not exactly the same, but not exactly the same,
because the spec prioritizes the simple description than being accurate. because the spec prioritizes the simple description than being accurate.
[CSS Text Processing Order of Operations]: https://drafts.csswg.org/css-text-3/#order [CSS Text Processing Order of Operations]: https://drafts.csswg.org/css-text-3/#order
### Pre-layout ### ### Pre-layout ###
For inline layout there is a pre-layout pass that prepares the internal data For inline layout there is a pre-layout pass that prepares the internal data
structures needed to perform line layout. structures needed to perform line layout.
The pre-layout pass, triggered by calling `NGInlineNode::PrepareLayout()`, has The pre-layout pass, triggered by calling `NGInlineNode::PrepareLayout()`, has
three separate steps or stages that are executed in order: three separate steps or stages that are executed in order:
- `CollectInlines`: Performs a depth-first scan of the container collecting - `CollectInlines`: Performs a depth-first scan of the container collecting
all non-atomic inlines and `TextNodes`s. Atomic inlines are represented as a all non-atomic inlines and `TextNodes`s. Atomic inlines are represented as a
unicode object replacement character but are otherwise skipped. unicode object replacement character but are otherwise skipped.
Each non-atomic inline and `TextNodes` is fed to a Each non-atomic inline and `TextNodes` is fed to a
[NGInlineItemsBuilder](ng_inline_items_builder.h) instance which collects [NGInlineItemsBuilder](ng_inline_items_builder.h) instance which collects
the text content for all non-atomic inlines in the container. the text content for all non-atomic inlines in the container.
During this process white-space is collapsed and normalized according to CSS During this process white-space is collapsed and normalized according to CSS
white-space processing rules. white-space processing rules.
The CSS [text-transform] is already applied in LayoutObject tree. The CSS [text-transform] is already applied in LayoutObject tree.
The plan is to implement in this phase when LayoutNG builds the tree from DOM. The plan is to implement in this phase when LayoutNG builds the tree from DOM.
- `SegmentText`: Performs BiDi segmentation and resolution. - `SegmentText`: Performs BiDi segmentation and resolution.
See [Bidirectional text] below. See [Bidirectional text] below.
- `ShapeText`: Shapes the resolved BiDi runs using HarfBuzz. - `ShapeText`: Shapes the resolved BiDi runs using HarfBuzz.
TODO(eae): Fill out TODO(eae): Fill out
[text-transform]: https://drafts.csswg.org/css-text-3/#propdef-text-transform [text-transform]: https://drafts.csswg.org/css-text-3/#propdef-text-transform
[NGInlineItem]: ng_inline_item.h ### Line Breaking ###
### Line Breaking ### [NGLineBreaker] takes a list of [NGInlineItem],
measure them, break into lines, and
[NGLineBreaker] takes a list of [NGInlineItem], produces a list of [NGInlineItemResult] for each line.
measure them, break into lines, and
produces a list of [NGInlineItemResult] for each line. [NGInlineItemResult] keeps several information
needed during the line box construction,
[NGInlineItemResult] keeps several information such as inline size and [ShapeResult],
needed during the line box construction, though the inline position is recomputed later
such as inline size and [ShapeResult], because [Bidirectional text] may change it.
though the inline position is recomputed later
because [Bidirectional text] may change it. This phase:
1. Measures each item.
This phase: 2. Breaks text [NGInlineItem] into multiple [NGInlineItemResult].
1. Measures each item. The core logic of this part is implemented in [ShapingLineBreaker].
2. Breaks text [NGInlineItem] into multiple [NGInlineItemResult]. 3. Computes inline size of borders/margins/paddings.
The core logic of this part is implemented in [ShapingLineBreaker]. The block size of borders/margins/paddings are ignored
3. Computes inline size of borders/margins/paddings. for inline non-replaced elements, but
The block size of borders/margins/paddings are ignored the inline size affects layout, and hence line breaking.
for inline non-replaced elements, but See [CSS Calculating widths and margins] for more details.
the inline size affects layout, and hence line breaking. 4. Determines which item can fit in the line.
See [CSS Calculating widths and margins] for more details. 5. Determines the break opportunities between items.
4. Determines which item can fit in the line. If an item overflows, and there were no break opportunity before it,
5. Determines the break opportunities between items. the item before must also overflow.
If an item overflows, and there were no break opportunity before it,
the item before must also overflow. [ShapingLineBreaker] is... TODO(kojii): fill out.
[ShapingLineBreaker] is... TODO(kojii): fill out. [CSS Calculating widths and margins]: https://drafts.csswg.org/css2/visudet.html#Computing_widths_and_margins
[CSS Calculating widths and margins]: https://drafts.csswg.org/css2/visudet.html#Computing_widths_and_margins ### Line Box Construction ###
[NGInlineItemResult]: ng_inline_item_result.h `NGInlineLayoutAlgorithm::CreateLine()` takes a list of [NGInlineItemResult] and
[NGLineBreaker]: ng_line_breaker.h produces [NGPhysicalLineBoxFragment] for each line.
[ShapeResult]: ../../../platform/fonts/shaping/ShapeResult.h
[ShapingLineBreaker]: ../../../platform/fonts/shaping/ShapingLineBreaker.h Lines are then wrapped in an anonymous [NGPhysicalBoxFragment]
so that one [NGInlineNode] has one corresponding fragment.
### Line Box Construction ###
This phase consists of following sub-phases:
`NGInlineLayoutAlgorithm::CreateLine()` takes a list of [NGInlineItemResult] and
produces [NGPhysicalLineBoxFragment] for each line. 1. Bidirectional reordering:
Reorder the list of [NGInlineItemResult]
Lines are then wrapped in an anonymous [NGPhysicalBoxFragment] according to [UAX#9 Reordering Resolved Levels].
so that one [NGInlineNode] has one corresponding fragment. See [Bidirectional text] below.
This phase consists of following sub-phases: After this point forward, the list of [NGInlineItemResult] is
in _visual order_; which is from [line-left] to [line-right].
1. Bidirectional reordering: The block direction is still logical,
Reorder the list of [NGInlineItemResult] but the inline direction is physical.
according to [UAX#9 Reordering Resolved Levels].
See [Bidirectional text] below. 2. Create a [NGPhysicalFragment] for each [NGInlineItemResult]
in visual ([line-left] to [line-right]) order,
After this point forward, the list of [NGInlineItemResult] is and place them into [NGPhysicalLineBoxFragment].
in _visual order_; which is from [line-left] to [line-right].
The block direction is still logical, 1. A text item produces a [NGPhysicalTextFragment].
but the inline direction is physical. 2. An open-tag item pushes a new stack entry of [NGInlineBoxState],
and a close-tag item pops a stack entry.
2. Create a [NGPhysicalFragment] for each [NGInlineItemResult] Performs operations that require the size of the inline box,
in visual ([line-left] to [line-right]) order, or ancestor boxes.
and place them into [NGPhysicalLineBoxFragment]. See [Inline Box Tree] below.
1. A text item produces a [NGPhysicalTextFragment]. The inline size of each item was already determined by [NGLineBreaker],
2. An open-tag item pushes a new stack entry of [NGInlineBoxState], but the inline position is recomputed
and a close-tag item pops a stack entry. because BiDi reordering may have changed it.
Performs operations that require the size of the inline box,
or ancestor boxes. In block direction, [NGPhysicalFragment] is placed
See [Inline Box Tree] below. as if the baseline is at 0.
This is adjusted later, possibly multiple times.
The inline size of each item was already determined by [NGLineBreaker], See [Inline Box Tree] and the post-process below.
but the inline position is recomputed
because BiDi reordering may have changed it. 3. Post-process the constructed line box.
This includes:
In block direction, [NGPhysicalFragment] is placed 1. Process all pending operations in [Inline Box Tree].
as if the baseline is at 0. 2. Moves the baseline to the correct position
This is adjusted later, possibly multiple times. based on the height of the line box.
See [Inline Box Tree] and the post-process below. 3. Applies the CSS [text-align] property.
3. Post-process the constructed line box. [line-left]: https://drafts.csswg.org/css-writing-modes-3/#line-left
This includes: [line-right]: https://drafts.csswg.org/css-writing-modes-3/#line-right
1. Process all pending operations in [Inline Box Tree]. [text-align]: https://drafts.csswg.org/css-text-3/#propdef-text-align
2. Moves the baseline to the correct position
based on the height of the line box. ### Inline Box Tree ###
3. Applies the CSS [text-align] property. [Inline Box Tree]: #inline-box-tree
[line-left]: https://drafts.csswg.org/css-writing-modes-3/#line-left A flat list structure is suitable for many inline operations,
[line-right]: https://drafts.csswg.org/css-writing-modes-3/#line-right but some operations require an inline box tree structure.
[text-align]: https://drafts.csswg.org/css-text-3/#propdef-text-align A stack of [NGInlineBoxState] is constructed
from a list of [NGInlineItemResult] to represent the box tree structure.
[NGInlineNode]: ng_inline_node.h
[NGInlineLayoutAlgorithm]: ng_inlineLlayout_algorithm.h This stack:
[NGPhysicalBoxFragment]: ../ng_physical_box_fragment.h 1. Caches common values for an inline box.
[NGPhysicalFragment]: ../ng_physical_fragment.h For instance, the primary font metrics do not change within an inline box.
[NGPhysicalLineBoxFragment]: ng_physical_line_box_fragment.h 2. Computes the height of an inline box.
[NGPhysicalTextFragment]: ng_physical_text_fragment.h The [height of inline, non-replaced elements depends on the content area],
but CSS doesn't define how to compute the content area.
### Inline Box Tree ### 3. Creates [NGPhysicalBoxFragment]s when needed.
[Inline Box Tree]: #inline-box-tree CSS doesn't define when an inline box should have a box,
but existing implementations are interoperable that
A flat list structure is suitable for many inline operations, there should be a box when it has borders.
but some operations require an inline box tree structure. Also, background should have a box if it is not empty.
A stack of [NGInlineBoxState] is constructed Other cases are where paint or scroller will need a box.
from a list of [NGInlineItemResult] to represent the box tree structure. 4. Applies [vertical-align] to shift baselines.
Some values are applicable immediately.
This stack: Some values need the size of the box, or the parent box.
1. Caches common values for an inline box. Some values need the size of the root inline box.
For instance, the primary font metrics do not change within an inline box. Depends on the value,
2. Computes the height of an inline box. the operation is queued to the appropriate stack entry.
The [height of inline, non-replaced elements depends on the content area],
but CSS doesn't define how to compute the content area. Because of index-based operations to the list of [NGInlineItemResult],
3. Creates [NGPhysicalBoxFragment]s when needed. the list is append-only during the process.
CSS doesn't define when an inline box should have a box, When all operations are done,
but existing implementations are interoperable that `OnEndPlaceItems()` turns the list into the final fragment tree structure.
there should be a box when it has borders.
Also, background should have a box if it is not empty. [height of inline, non-replaced elements depends on the content area]: https://drafts.csswg.org/css2/visudet.html#inline-non-replaced
Other cases are where paint or scroller will need a box. [vertical-align]: https://drafts.csswg.org/css2/visudet.html#propdef-vertical-align
4. Applies [vertical-align] to shift baselines.
Some values are applicable immediately. ## Miscellaneous topics ##
Some values need the size of the box, or the parent box.
Some values need the size of the root inline box. ### Baseline ###
Depends on the value,
the operation is queued to the appropriate stack entry. Computing baselines in LayoutNG goes the following process.
Because of index-based operations to the list of [NGInlineItemResult], 1. Users of baseline should request what kind and type of the baseline
the list is append-only during the process. they need by calling [NGConstraintSpaceBuilder]`::AddBaselineRequest()`.
When all operations are done, 2. Call [NGLayoutInputNode]`::Layout()`,
`OnEndPlaceItems()` turns the list into the final fragment tree structure. that calls appropriate layout algorithm.
3. Each layout algorithm computes baseline according to the requests.
[height of inline, non-replaced elements depends on the content area]: https://drafts.csswg.org/css2/visudet.html#inline-non-replaced 4. Users retrieve the result by [NGPhysicalBoxFragment]`::Baseline()`,
[vertical-align]: https://drafts.csswg.org/css2/visudet.html#propdef-vertical-align or by higher level functions such as [NGBoxFragment]`::BaselineMetrics()`.
[NGInlineBoxState]: ng_inline_box_state.h Algorithms are responsible
for checking [NGConstraintSpace]`::BaselineRequests()`,
### <a name="bidi"></a>Bidirectional Text ### computing requested baselines, and
[Bidirectional Text]: #bidi calling [NGFragmentBuilder]`::AddBaseline()`
to add them to [NGPhysicalBoxFragment].
[UAX#9 Unicode Bidirectional Algorithm] defines
processing algorithm for bidirectional text. [NGBaselineRequest] consists of [NGBaselineAlgorithmType] and [FontBaseline].
The core logic is implemented in [NGBidiParagraph], In most normal cases,
which is a thin wrapper for [ICU BiDi]. algorithms should decide which box should provide the baseline
for the specified [NGBaselineAlgorithmType] and delegate to it.
In a bird's‐eye view, it consists of two parts:
[FontBaseline] currently has only two baseline types,
1. Before line breaking: Segmenting text and resolve embedding levels alphabetic and ideographic,
as defined in [UAX#9 Resolving Embedding Levels]. and they are hard coded to derive from the CSS [writing-mode] property today.
The core logic uses [ICU BiDi] `ubidi_getLogicalRun()` function. We plan to support more baseline types,
and allow authors to specify the baseline type,
This is part of the Pre-layout phase above. as defined in the CSS [dominant-baseline] property in future.
2. After line breaking: Reorder text [NGPhysicalLineBoxFragment] and [NGPhysicalTextFragment] should be
as defined in [UAX#9 Reordering Resolved Levels]. responsible for computing different baseline types from font metrics.
The core logic uses [ICU BiDi] `ubidi_reorderVisual()` function. [dominant-baseline]: https://drafts.csswg.org/css-inline/#dominant-baseline-property
[writing-mode]: https://drafts.csswg.org/css-writing-modes-3/#propdef-writing-mode
This is part of the Line Box Construction phase above.
### <a name="bidi"></a>Bidirectional Text ###
[Bidirectional Text]: #bidi
[ICU BiDi]: http://userguide.icu-project.org/transforms/bidi
[UAX#9 Unicode Bidirectional Algorithm]: http://unicode.org/reports/tr9/ [UAX#9 Unicode Bidirectional Algorithm] defines
[UAX#9 Resolving Embedding Levels]: http://www.unicode.org/reports/tr9/#Resolving_Embedding_Levels processing algorithm for bidirectional text.
[UAX#9 Reordering Resolved Levels]: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
The core logic is implemented in [NGBidiParagraph],
[NGBidiParagraph]: ng_bidi_paragraph.h which is a thin wrapper for [ICU BiDi].
In a bird's‐eye view, it consists of two parts:
1. Before line breaking: Segmenting text and resolve embedding levels
as defined in [UAX#9 Resolving Embedding Levels].
The core logic uses [ICU BiDi] `ubidi_getLogicalRun()` function.
This is part of the Pre-layout phase above.
2. After line breaking: Reorder text
as defined in [UAX#9 Reordering Resolved Levels].
The core logic uses [ICU BiDi] `ubidi_reorderVisual()` function.
This is part of the Line Box Construction phase above.
[ICU BiDi]: http://userguide.icu-project.org/transforms/bidi
[UAX#9 Unicode Bidirectional Algorithm]: http://unicode.org/reports/tr9/
[UAX#9 Resolving Embedding Levels]: http://www.unicode.org/reports/tr9/#Resolving_Embedding_Levels
[UAX#9 Reordering Resolved Levels]: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
[FontBaseline]: ../../../platform/fonts/FontBaseline.h
[NGBaselineAlgorithmType]: ng_baseline.h
[NGBaselineRequest]: ng_baseline.h
[NGBidiParagraph]: ng_bidi_paragraph.h
[NGBoxFragment]: ../ng_box_fragment.h
[NGConstraintSpace]: ../ng_constraint_space_builder.h
[NGConstraintSpaceBuilder]: ../ng_constraint_space_builder.h
[NGFragmentBuilder]: ../ng_fragment_builder.h
[NGInlineBoxState]: ng_inline_box_state.h
[NGInlineItem]: ng_inline_item.h
[NGInlineItemResult]: ng_inline_item_result.h
[NGInlineNode]: ng_inline_node.h
[NGInlineLayoutAlgorithm]: ng_inlineLlayout_algorithm.h
[NGLayoutInputNode]: ../ng_layout_input_node.h
[NGLineBreaker]: ng_line_breaker.h
[NGPhysicalBoxFragment]: ../ng_physical_box_fragment.h
[NGPhysicalFragment]: ../ng_physical_fragment.h
[NGPhysicalLineBoxFragment]: ng_physical_line_box_fragment.h
[NGPhysicalTextFragment]: ng_physical_text_fragment.h
[ShapeResult]: ../../../platform/fonts/shaping/ShapeResult.h
[ShapingLineBreaker]: ../../../platform/fonts/shaping/ShapingLineBreaker.h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment