Commit 80c08c3f authored by Hayato Ito's avatar Hayato Ito Committed by Commit Bot

Format renderer/core/dom/README.md

Format renderer/core/dom/README.md by prettier.

BUG: 742715
TBR=kochi
NOTRY=true

Change-Id: Ib67571d3490a64681ef32f2bfcc47578e7282012
Reviewed-on: https://chromium-review.googlesource.com/1123975
Commit-Queue: Hayato Ito <hayato@chromium.org>
Reviewed-by: default avatarTakayoshi Kochi <kochi@chromium.org>
Reviewed-by: default avatarHayato Ito <hayato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572105}
parent 018fd4a1
......@@ -6,32 +6,34 @@ Author: hayato@chromium.org
The `Source/core/dom` directory contains the implementation of [DOM].
[DOM]: https://dom.spec.whatwg.org/
[DOM Standard]: https://dom.spec.whatwg.org/
[dom]: https://dom.spec.whatwg.org/
[dom standard]: https://dom.spec.whatwg.org/
Basically, this directory should contain only a file which is related to [DOM Standard].
However, for historical reasons, `Source/core/dom` directory has been used
as if it were *misc* directory. As a result, unfortunately, this directory
Basically, this directory should contain only a file which is related to [DOM
Standard]. However, for historical reasons, `Source/core/dom` directory has been
used as if it were _misc_ directory. As a result, unfortunately, this directory
contains a lot of files which are not directly related to DOM.
Please don't add unrelated files to this directory any more. We are trying to
organize the files so that developers wouldn't get confused at seeing this
directory.
- See the [spreadsheet](https://docs.google.com/spreadsheets/d/1OydPU6r8CTj8HC4D9_gVkriJETu1Egcw2RlajYcw3FM/edit?usp=sharing), as a rough plan to organize Source/core/dom files.
- See the
[spreadsheet](https://docs.google.com/spreadsheets/d/1OydPU6r8CTj8HC4D9_gVkriJETu1Egcw2RlajYcw3FM/edit?usp=sharing),
as a rough plan to organize Source/core/dom files.
The classification in the spreadsheet might be wrong. Please update the spreadsheet, and move files if you can,
if you know more appropriate places for each file.
The classification in the spreadsheet might be wrong. Please update the
spreadsheet, and move files if you can, if you know more appropriate places
for each file.
- See [crbug.com/738794](http://crbug.com/738794) for tracking our efforts.
# Node and Node Tree
In this README, we draw a tree in left-to-right direction. `A` is the root of the tree.
In this README, we draw a tree in left-to-right direction. `A` is the root of
the tree.
``` text
```text
A
├───B
├───C
......@@ -40,30 +42,35 @@ A
└───F
```
`Node` is a base class of all kinds of nodes in a node tree. Each `Node` has
following 3 pointers (but not limited to):
`Node` is a base class of all kinds of nodes in a node tree. Each `Node` has following 3 pointers (but not limited to):
- `parent_or_shadow_host_node_`: Points to the parent (or the shadow host if it is a shadow root; explained later)
- `parent_or_shadow_host_node_`: Points to the parent (or the shadow host if it
is a shadow root; explained later)
- `previous_`: Points to the previous sibling
- `next_`: Points to the next sibling
`ContainerNode`, from which `Element` extends, has additional pointers for its child:
`ContainerNode`, from which `Element` extends, has additional pointers for its
child:
- `first_child_`: The meaning is obvious.
- `last_child_`: Nit.
That means:
- Siblings are stored as a linked list. It takes O(N) to access a parent's n-th child.
- Siblings are stored as a linked list. It takes O(N) to access a parent's n-th
child.
- Parent can't tell how many children it has in O(1).
Further info:
- `Node`, `ContainerNode`
# C++11 range-based for loops for traversing a tree
You can traverse a tree manually:
``` c++
```c++
// In C++
// Traverse a children.
......@@ -82,48 +89,53 @@ void foo(const Node& node) {
}
```
However, traversing a tree in this way might be error-prone.
Instead, you can use `NodeTraversal` and `ElementTraversal`. They provides a C++11's range-based for loops, such as:
However, traversing a tree in this way might be error-prone. Instead, you can
use `NodeTraversal` and `ElementTraversal`. They provides a C++11's range-based
for loops, such as:
``` c++
```c++
// In C++
for (Node& child : NodeTraversal::childrenOf(parent) {
...
}
```
e.g. Given a parent *A*, this traverses *B*, *C*, and *F* in this order.
e.g. Given a parent _A_, this traverses _B_, _C_, and _F_ in this order.
``` c++
```c++
// In C++
for (Node& node : NodeTraversal::startsAt(root)) {
...
}
```
e.g. Given the root *A*, this traverses *A*, *B*, *C*, *D*, *E*, and *F* in this order.
e.g. Given the root _A_, this traverses _A_, _B_, _C_, _D_, _E_, and _F_ in this
order.
There are several other useful range-based for loops for each purpose.
The cost of using range-based for loops is zero because everything can be inlined.
There are several other useful range-based for loops for each purpose. The cost
of using range-based for loops is zero because everything can be inlined.
Further info:
- `NodeTraversal` and `ElementTraversal` (more type-safe version)
- The [CL](https://codereview.chromium.org/642973003), which introduced these range-based for loops.
- The [CL](https://codereview.chromium.org/642973003), which introduced these
range-based for loops.
# Shadow Tree
A **shadow tree** is a node tree whose root is a `ShadowRoot`.
From web developer's perspective, a shadow root can be created by calling `element.attachShadow{ ... }` API.
The *element* here is called a **shadow host**, or just a **host** if the context is clear.
A **shadow tree** is a node tree whose root is a `ShadowRoot`. From web
developer's perspective, a shadow root can be created by calling
`element.attachShadow{ ... }` API. The _element_ here is called a **shadow
host**, or just a **host** if the context is clear.
- A shadow root is always attached to another node tree through its host. A shadow tree is therefore never alone.
- The node tree of a shadow root’s host is sometimes referred to as the **light tree**.
- A shadow root is always attached to another node tree through its host. A
shadow tree is therefore never alone.
- The node tree of a shadow root’s host is sometimes referred to as the **light
tree**.
For example, given the example node tree:
``` text
```text
A
├───B
├───C
......@@ -132,26 +144,27 @@ A
└───F
```
Web developers can create a shadow root, and manipulate the shadow tree in the following way:
Web developers can create a shadow root, and manipulate the shadow tree in the
following way:
``` javascript
```javascript
// In JavaScript
const b = document.querySelector('#B');
const shadowRoot = b.attachShadow({ mode: 'open'} )
const shadowRoot = b.attachShadow({ mode: 'open' });
const sb = document.createElement('div');
shadowRoot.appendChild(sb);
```
The resulting shadow tree would be:
``` text
```text
shadowRoot
└── sb
```
The *shadowRoot* has one child, *sb*. This shadow tree is being *attached* to B:
The _shadowRoot_ has one child, _sb_. This shadow tree is being _attached_ to B:
``` text
```text
A
└── B
├──/shadowRoot
......@@ -162,24 +175,26 @@ A
└── F
```
In this README, a notation (`──/`) is used to represent a *shadowhost-shadowroot* relationship, in a **composed tree**.
A composed tree will be explained later. A *shadowhost-shadowroot* is 1:1 relationship.
Though a shadow root has always a corresponding shadow host element, a light tree and a shadow tree should be considered separately, from a node tree's perspective. (`──/`) is *NOT* a parent-child relationship in a node tree.
In this README, a notation (`──/`) is used to represent a
_shadowhost-shadowroot_ relationship, in a **composed tree**. A composed tree
will be explained later. A _shadowhost-shadowroot_ is 1:1 relationship.
For example, even though *B* *hosts* the shadow tree, *shadowRoot* is not considered as a *child* of *B*.
The means the following traversal:
Though a shadow root has always a corresponding shadow host element, a light
tree and a shadow tree should be considered separately, from a node tree's
perspective. (`──/`) is _NOT_ a parent-child relationship in a node tree.
For example, even though _B_ _hosts_ the shadow tree, _shadowRoot_ is not
considered as a _child_ of _B_. The means the following traversal:
``` c++
```c++
// In C++
for (Node& node : NodeTraversal::startsAt(A)) {
...
}
```
traverses only *A*, *B*, *C*, *D*, *E* and *F* nodes. It never visits *shadowRoot* nor *sb*.
NodeTraversal never cross a shadow boundary, `──/`.
traverses only _A_, _B_, _C_, _D_, _E_ and _F_ nodes. It never visits
_shadowRoot_ nor _sb_. NodeTraversal never cross a shadow boundary, `──/`.
Further info:
......@@ -188,35 +203,41 @@ Further info:
# TreeScope
`Document` and `ShadowRoot` are always the root of a node tree.
Both`Document` and `ShadowRoot` implements `TreeScope`.
`Document` and `ShadowRoot` are always the root of a node tree. Both`Document`
and `ShadowRoot` implements `TreeScope`.
`TreeScope` maintains a lot of information about the underlying tree for efficiency.
For example, TreeScope has a *id-to-element* mapping, as [`TreeOrderedMap`](./TreeOrderedMap.h), so that `querySelector('#foo')` can find an element whose id attribute is "foo" in O(1).
In other words, `root.querySelector('#foo')` can be slow if that is used in a node tree whose root is not `TreeScope`.
`TreeScope` maintains a lot of information about the underlying tree for
efficiency. For example, TreeScope has a _id-to-element_ mapping, as
[`TreeOrderedMap`](./TreeOrderedMap.h), so that `querySelector('#foo')` can find
an element whose id attribute is "foo" in O(1). In other words,
`root.querySelector('#foo')` can be slow if that is used in a node tree whose
root is not `TreeScope`.
Each `Node` has `tree_scope_` pointer, which points to:
- The root node: if the node's root is either Document or ShadowRoot.
- [owner document](https://dom.spec.whatwg.org/#concept-node-documentOwnerDocument), otherwise.
- [owner document](https://dom.spec.whatwg.org/#concept-node-documentOwnerDocument),
otherwise.
The means `tree_scope_` pointer is always non-null (except for while in a DOM mutation),
but it doesn't always point to the node's root.
The means `tree_scope_` pointer is always non-null (except for while in a DOM
mutation), but it doesn't always point to the node's root.
Since each node doesn't have a pointer which *always* points to the root,
`Node::getRootNode(...)` may take O(N) if the node is neither in a document tree nor in a shadow tree.
If the node is in TreeScope (`Node#IsInTreeScope()` can tell it), we can get the root in O(1).
Since each node doesn't have a pointer which _always_ points to the root,
`Node::getRootNode(...)` may take O(N) if the node is neither in a document tree
nor in a shadow tree. If the node is in TreeScope (`Node#IsInTreeScope()` can
tell it), we can get the root in O(1).
Each node has flags, which is updated in DOM mutation, so that we can tell whether the node is in a
document tree, in a shadow tree, or in none of them, by using
`Node::IsInDocumentTree()` and/or `Node::IsInShadowTree()`.
Each node has flags, which is updated in DOM mutation, so that we can tell
whether the node is in a document tree, in a shadow tree, or in none of them, by
using `Node::IsInDocumentTree()` and/or `Node::IsInShadowTree()`.
If you want to add new features to `Document`, `Document` might be a wrong place to add.
Instead, please consider to add functionality to `TreeScope`. We want to treat a document tree and a shadow tree equally as much as possible.
If you want to add new features to `Document`, `Document` might be a wrong place
to add. Instead, please consider to add functionality to `TreeScope`. We want to
treat a document tree and a shadow tree equally as much as possible.
## Example
``` text
```text
document
└── a1
├──/shadowRoot1
......@@ -232,12 +253,14 @@ document-fragment
└── b3
```
- Here, there are 4 node trees; The root node of each tree is *document*, *shadowRoot1*, *document-fragment*, and *shadowRoot2*.
- Suppose that each node is created by `document.createElement(...)` (except for Document and ShadowRoot).
That means each node's **owner document** is *document*.
- Here, there are 4 node trees; The root node of each tree is _document_,
_shadowRoot1_, _document-fragment_, and _shadowRoot2_.
- Suppose that each node is created by `document.createElement(...)` (except for
Document and ShadowRoot). That means each node's **owner document** is
_document_.
| node | node's root | node's `_tree_scope` points to: |
|-------------------|--------------------------|---------------------------------|
| ----------------- | ------------------------ | ------------------------------- |
| document | document (self) | document (self) |
| a1 | document | document |
| a2 | document | document |
......@@ -258,11 +281,11 @@ Further Info:
# Composed Tree (a tree of node trees)
In the previous picture, you might think that more than one node trees, a document tree and a shadow tree, were *connected* to each other. That is *true* in some sense.
The following is a more complex example:
In the previous picture, you might think that more than one node trees, a
document tree and a shadow tree, were _connected_ to each other. That is _true_
in some sense. The following is a more complex example:
``` text
```text
document
├── a1 (host)
│ ├──/shadowRoot1
......@@ -290,12 +313,12 @@ document
└── f2
```
If you see this carefully, you can notice that this *composed tree* is composed of 6 node trees; 1 document tree and 5 shadow trees:
If you see this carefully, you can notice that this _composed tree_ is composed
of 6 node trees; 1 document tree and 5 shadow trees:
- document tree
``` text
```text
document
├── a1 (host)
│ └── a2 (host)
......@@ -307,14 +330,14 @@ If you see this carefully, you can notice that this *composed tree* is composed
- shadow tree 1
``` text
```text
shadowRoot1
└── b1
```
- shadow tree 2
``` text
```text
shadowRoot2
├── c1
│ ├── c2
......@@ -324,7 +347,7 @@ If you see this carefully, you can notice that this *composed tree* is composed
- shadow tree 3
``` text
```text
shadowRoot3
└── d1
├── d2
......@@ -334,7 +357,7 @@ If you see this carefully, you can notice that this *composed tree* is composed
- shadow tree 4
``` text
```text
shadowRoot4
├── e1
└── e2
......@@ -342,15 +365,16 @@ If you see this carefully, you can notice that this *composed tree* is composed
- shadow tree 5
``` text
```text
shadowRoot5
├── f1
└── f2
```
If we consider each *node tree* as *node* of a *super-tree*, we can draw a super-tree as such:
If we consider each _node tree_ as _node_ of a _super-tree_, we can draw a
super-tree as such:
``` text
```text
document
├── shadowRoot1
├── shadowRoot2
......@@ -359,10 +383,12 @@ document
└── shadowRoot5
```
Here, a root node is used as a representative of each node tree; A root node and a node tree itself can be sometimes exchangeable in explanations.
Here, a root node is used as a representative of each node tree; A root node and
a node tree itself can be sometimes exchangeable in explanations.
We call this kind of a *super-tree* (*a tree of node trees*) a **composed tree**.
The concept of a *composed tree* is very useful to understand how Shadow DOM's encapsulation works.
We call this kind of a _super-tree_ (_a tree of node trees_) a **composed
tree**. The concept of a _composed tree_ is very useful to understand how Shadow
DOM's encapsulation works.
[DOM Standard] defines the following terminologies:
......@@ -376,17 +402,18 @@ The concept of a *composed tree* is very useful to understand how Shadow DOM's e
For example,
- *d1*'s *shadow-including ancestor nodes* are *shadowRoot3*, *a6*, *a5*, and *document*
- *d1*'s *shadow-including descendant nodes* are *d2*, *d3*, *shadowRoot4*, *e1*, *e2*, *d4*, *shadowRoot5*, *f1*, and *f2*.
- _d1_'s _shadow-including ancestor nodes_ are _shadowRoot3_, _a6_, _a5_, and
_document_
- _d1_'s _shadow-including descendant nodes_ are _d2_, _d3_, _shadowRoot4_,
_e1_, _e2_, _d4_, _shadowRoot5_, _f1_, and _f2_.
To honor Shadow DOM's encapsulation, we have a concept of *visibility relationship* between two nodes.
To honor Shadow DOM's encapsulation, we have a concept of _visibility
relationship_ between two nodes.
In the following table, "`-`" means that "node *A* is *visible* from node *B*".
In the following table, "`-`" means that "node _A_ is _visible_ from node _B_".
| *A* \ *B* | document | a1 | a2 | b1 | c1 | d1 | d2 | e1 | f1 |
|-----------|----------|--------|--------|--------|--------|--------|--------|--------|--------|
| _A_ \ _B_ | document | a1 | a2 | b1 | c1 | d1 | d2 | e1 | f1 |
| --------- | -------- | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ |
| document | - | - | - | - | - | - | - | - | - |
| a1 | - | - | - | - | - | - | - | - | - |
| a2 | - | - | - | - | - | - | - | - | - |
......@@ -397,22 +424,27 @@ In the following table, "`-`" means that "node *A* is *visible* from node *B*".
| e1 | hidden | hidden | hidden | hidden | hidden | hidden | hidden | - | hidden |
| f1 | hidden | hidden | hidden | hidden | hidden | hidden | hidden | hidden | - |
For example, *document* is *visible* from any nodes.
For example, _document_ is _visible_ from any nodes.
To understand *visibility relationship* easily, here is a rule of thumb:
To understand _visibility relationship_ easily, here is a rule of thumb:
- If node *B* can reach node *A* by traversing an *edge* (in the first picture of this section), recursively, *A* is visible from *B*.
- However, an *edge* of (`──/`) ( *shadowhost-shadowroot* relationship) is one-directional:
- If node _B_ can reach node _A_ by traversing an _edge_ (in the first picture
of this section), recursively, _A_ is visible from _B_.
- However, an _edge_ of (`──/`) ( _shadowhost-shadowroot_ relationship) is
one-directional:
- From a shadow root to the shadow host -> Okay
- From a shadow host to the shadow root -> Forbidden
In other words, a node in an *inner tree* can see a node in an *outer tree* in a composed tree, but the opposite is not true.
In other words, a node in an _inner tree_ can see a node in an _outer tree_ in a
composed tree, but the opposite is not true.
We have designed (or re-designed) a bunch of Web-facing APIs to honor this basic principle.
If you add a new API to the web platform and Blink, please consider this rule and don't *leak* a node which should be hidden to web developers.
We have designed (or re-designed) a bunch of Web-facing APIs to honor this basic
principle. If you add a new API to the web platform and Blink, please consider
this rule and don't _leak_ a node which should be hidden to web developers.
Warning: Unfortunately, a *composed tree* had a different meaning in the past; it was used to specify a *flat tree* (which will be explained later).
If you find a wrong usage of a composed tree in Blink, please fix it.
Warning: Unfortunately, a _composed tree_ had a different meaning in the past;
it was used to specify a _flat tree_ (which will be explained later). If you
find a wrong usage of a composed tree in Blink, please fix it.
Further Info:
......@@ -423,22 +455,24 @@ Further Info:
# Flat tree
A composed tree itself can't be rendered *as is*. From the rendering's
perspective, Blink has to construct a *layout tree*, which would be used as an input to
the *paint phase*. A layout tree is a tree whose node is `LayoutObject`, which
points to `Node` in a node tree, plus additional calculated layout information.
A composed tree itself can't be rendered _as is_. From the rendering's
perspective, Blink has to construct a _layout tree_, which would be used as an
input to the _paint phase_. A layout tree is a tree whose node is
`LayoutObject`, which points to `Node` in a node tree, plus additional
calculated layout information.
Before the Web Platform got Shadow DOM, the structure of a layout tree is almost
*similar* to the structure of a document tree; where only one node tree,
*document tree*, is being involved there.
_similar_ to the structure of a document tree; where only one node tree,
_document tree_, is being involved there.
Since the Web Platform got Shadow DOM, we now have a composed tree which is composed of multiple node
trees, instead of a single node tree. That means We have to *flatten* the composed tree to the one node tree, called
a *flat tree*, from which a layout tree is constructed.
Since the Web Platform got Shadow DOM, we now have a composed tree which is
composed of multiple node trees, instead of a single node tree. That means We
have to _flatten_ the composed tree to the one node tree, called a _flat tree_,
from which a layout tree is constructed.
For example, given the following composed tree,
``` text
```text
document
├── a1 (host)
│ ├──/shadowRoot1
......@@ -464,13 +498,12 @@ document
└──/shadowRoot5
├── f1
└── f2
```
This composed tree would be flattened into the following *flat tree* (assuming there are not `<slot>` elements there):
This composed tree would be flattened into the following _flat tree_ (assuming
there are not `<slot>` elements there):
``` text
```text
document
├── a1 (host)
│ └── b1
......@@ -486,19 +519,23 @@ document
└── f2
```
We can't explain the exact algorithm how to flatten a composed tree into a flat tree until I explain the concept of *slots* and *node distribution*
If we are ignoring the effect of `<slot>`, we can have the following simple definition. A flat tree can be defined as:
We can't explain the exact algorithm how to flatten a composed tree into a flat
tree until I explain the concept of _slots_ and _node distribution_ If we are
ignoring the effect of `<slot>`, we can have the following simple definition. A
flat tree can be defined as:
- A root of a flat tree: *document*
- Given node *A* which is in a flat tree, its children are defined, recursively, as follows:
- If *A* is a shadow host, its shadow root's children
- Otherwise, *A*'s children
- A root of a flat tree: _document_
- Given node _A_ which is in a flat tree, its children are defined, recursively,
as follows:
- If _A_ is a shadow host, its shadow root's children
- Otherwise, _A_'s children
# Distribution and slots
TODO(hayato): Explain.
In the meantime, please see [Incremental Shadow DOM](https://docs.google.com/document/d/1R9J8CVaSub_nbaVQwwm3NjCoZye4feJ7ft7tVe5QerM/edit?usp=sharing).
In the meantime, please see
[Incremental Shadow DOM](https://docs.google.com/document/d/1R9J8CVaSub_nbaVQwwm3NjCoZye4feJ7ft7tVe5QerM/edit?usp=sharing).
# FlatTreeTraversal
......
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