Skip to content

Commit cdab670

Browse files
committed
[css-layout-api] Define how to generate a fragment.
1 parent 32c81e1 commit cdab670

File tree

1 file changed

+189
-45
lines changed

1 file changed

+189
-45
lines changed

css-layout-api/Overview.bs

+189-45
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ urlPrefix: https://tc39.github.io/ecma262/#sec-; type: dfn;
4343
text: TypeError
4444
</pre>
4545

46+
<!--
47+
TODO
48+
- Fix layout invalidation section.
49+
- Add painting behaviour section.
50+
- Fix examples.
51+
- Add utility functions.
52+
- Define invalid fragment.
53+
- Layout instance on box is incorrect.
54+
-->
55+
4656
Introduction {#intro}
4757
=====================
4858

@@ -99,6 +109,10 @@ href="https://www.w3.org/TR/CSS2/visuren.html#dis-pos-flo">CSS 2.1 Section 9.7</
99109
contain an additional row, with ''inline-layout()'' in the "Specified Value" column and ''layout()''
100110
in the "Computed Value" column.
101111

112+
A <a>layout API container</a> has a <dfn>layout instance</dfn>, initially this is set to null. This
113+
is an instance of the author defined layout class (see [[#registering-layout]]). If the <a>box</a>'s
114+
<a>computed value</a> of 'display' changes, this must be reset to null.
115+
102116
Layout API Model and Terminology {#layout-api-model-and-terminology}
103117
====================================================================
104118

@@ -117,7 +131,7 @@ Layout Children {#layout-children}
117131

118132
<pre class='idl'>
119133
interface LayoutChild {
120-
FragmentRequestToken doLayout(ConstraintSpace space, ChildBreakToken breakToken);
134+
FragmentRequest doLayout(ConstraintSpace space, ChildBreakToken breakToken);
121135
};
122136

123137
interface InlineLayoutChild : LayoutChild {
@@ -339,6 +353,9 @@ interface ConstraintSpace {
339353
readonly attribute double percentageInlineSize;
340354
readonly attribute double percentageBlockSize;
341355

356+
readonly attribute boolean inlineOverflow;
357+
readonly attribute boolean blockOverflow;
358+
342359
readonly attribute BlockFragmentationType blockFragmentationType;
343360
};
344361

@@ -556,6 +573,19 @@ registerLayout('fragmenting', class {
556573
</pre>
557574
</div>
558575

576+
Utility Functions {#utility-functions}
577+
--------------------------------------
578+
579+
<pre class='idl'>
580+
partial interface LayoutWorkletGlobalScope {
581+
resolveInlineSize();
582+
resolveBlockSize();
583+
584+
resolveBordersAndPadding();
585+
resolveScrollbarSize();
586+
};
587+
</pre>
588+
559589
Layout {#layout}
560590
================
561591

@@ -735,7 +765,7 @@ Layout Engine {#layout-engine}
735765
------------------------------
736766

737767
<pre class="idl">
738-
interface FragmentRequestToken {
768+
interface FragmentRequest {
739769
// Has internal slots:
740770
// [[layoutChild]] - The layout child to generate the fragment for.
741771
// [[constraintSpace]] - The constraint space to perform layout in.
@@ -749,10 +779,10 @@ engines.
749779

750780
When an author invokes the {{LayoutChild/doLayout()}} method on a {{LayoutChild}} the user-agent
751781
doesn't synchronously generate a {{Fragment}} to return to the author's code. Instead it returns a
752-
{{FragmentRequestToken}}. This is a completely opaque object to the author but contains internal
753-
slots which encapsulates the {{Box/doLayout()}} method call.
782+
{{FragmentRequest}}. This is a completely opaque object to the author but contains internal
783+
slots which encapsulates the {{LayoutChild/doLayout()}} method call.
754784

755-
When a {{FragmentRequestToken}}(s) are yielded from a layout generator object the user-agent's
785+
When a {{FragmentRequest}}(s) are yielded from a layout generator object the user-agent's
756786
layout engine may run the algorithm asynchronously with other work, and/or on a different thread of
757787
execution. When {{Fragment}}(s) have been produced by the engine, the user-agent will 'tick' the
758788
generator object with the resulting {{Fragment}}(s).
@@ -775,7 +805,7 @@ class LayoutEngine {
775805
});
776806
}
777807

778-
// This function takes a FragmentRequestToken and calls the appropriate layout
808+
// This function takes a FragmentRequest and calls the appropriate layout
779809
// algorithm to generate the a Fragment.
780810
layoutFragment(fragmentRequest) {
781811
const box = fragmentRequest.box;
@@ -806,61 +836,175 @@ class LayoutEngine {
806836
</pre>
807837
</div>
808838

809-
TODO explain parallel layout + {{FragmentRequestToken}}, etc.
839+
TODO explain parallel layout + {{FragmentRequest}}, etc.
810840

811-
Performing layout {#performing-layout}
841+
Performing Layout {#performing-layout}
812842
--------------------------------------
813843

814844
<pre class='idl'>
815-
dictionary LayoutResult {
816-
double inlineSize;
817-
double blockSize;
818-
sequence&lt;Fragment> fragments;
819-
BreakToken breakToken;
820-
double baseline;
845+
// This is the final return value from the author defined layout() method.
846+
dictionary FragmentResultOptions {
847+
double inlineSize = 0;
848+
double blockSize = 0;
849+
double inlineOverflowSize = null;
850+
double blockOverflowSize = null;
851+
sequence&lt;Fragment> childFragments = [];
852+
BreakTokenOptions breakToken = null;
853+
double dominantBaseline = null;
821854
};
822855
</pre>
823856

824-
{{LayoutClass/layout()}} is invoked by the user agent when <a>generate a layout</a> for a <a>box</a>.
857+
When the user agent wants to <dfn>generate a layout API fragment</dfn> of a <a>layout API formatting
858+
context</a> for a given |box|, |constraintSpace|, |children| and an optional |breakToken| it
859+
<em>must</em> run the following steps:
860+
861+
1. If the <a>layout valid flag</a> for the |box| is <a>layout-valid</a> the user agent
862+
<em>may</em> use a fragment from a previous invocation of this algorithm if the |box|,
863+
|constraintSpace|, |children| and optional |breakToken| are the same. If so it <em>may</em>
864+
abort all these steps and use the cached fragment.
865+
866+
Issue: The above is too limiting wrt. the layout valid flag. Need to separate out the produce
867+
the fragment step, with the cache invalidation.
868+
869+
Note: The user agent for implementation reasons may also continue with all these steps in this
870+
case. It can do this every frame, or multiple times per frame.
871+
872+
2. Let |layoutFunction| be the <<layout()>> or <<inline-layout()>> for the <a>computed value</a>
873+
of 'display' on the |box|.
874+
875+
3. Let |name| be the first argument of the |layoutFunction|.
876+
877+
4. Let |workletGlobalScope| be a {{LayoutWorkletGlobalScope}} from the list of <a>worklet's
878+
WorkletGlobalScopes</a> from the layout {{Worklet}}.
879+
880+
The user agent <em>may</em> also <a>create a WorkletGlobalScope</a> given the layout
881+
{{Worklet}} and use that.
882+
883+
Note: The user agent <em>may</em> use any policy for which {{LayoutWorkletGlobalScope}} to
884+
select or create. It may use a single {{LayoutWorkletGlobalScope}} or multiple and
885+
randomly assign between them.
886+
887+
5. Let |definition| be the result of looking up |name| on the |workletGlobalScope|'s <a>layout
888+
name to layout definition map</a>.
889+
890+
If |definition| does not exist, let the fragment output be an <a>invalid fragment</a> and
891+
abort all these steps.
892+
893+
6. Let |layoutInstance| be the result of looking up the <a>layout instance</a> on the |box|. If
894+
|layoutInstance| is null run the following substeps.
895+
896+
1. If the <a>layout class constructor valid flag</a> on |definition| is false, let the
897+
fragment output be an <a>invalid fragment</a> and abort all these steps.
898+
899+
2. Let |layoutCtor| be the <a>layout class constructor</a> on |definition|.
900+
901+
3. Let |layoutInstance| be the result of <a>Construct</a>(|layoutCtor|).
902+
903+
If <a>Construct</a> throws an exception, set the |definition|'s <a>layout class
904+
constructor valid flag</a> to false, let the fragment output be an <a>invalid
905+
fragment</a> and abort all these steps.
906+
907+
4. Set <a>layout instance</a> on |box| to |layoutInstance|.
908+
909+
Note: <a>Layout instance</a> will be set to null whenever the <a>computed style</a> of
910+
'display' on |box| changes.
911+
912+
7. Let |layoutGeneratorFunction| be the result of looking up the <a>layout generator
913+
function</a>.
914+
915+
8. Let |inputProperties| be the result of looking up |name| on the associated <a>document</a>'s
916+
<a>layout name to input properties map</a>.
917+
918+
9. Let |styleMap| be a new {{StylePropertyMapReadOnly}} populated with <em>only</em> the
919+
<a>computed value</a>'s for properties listed in |inputProperties|.
920+
921+
10. Let |layoutGenerator| be the result of <a>Call</a>(|layoutGeneratorFunction|,
922+
|layoutInstance|, «|constraintSpace|, |children|, |styleMap|, |breakToken|»).
923+
924+
12. Let |childFragmentResults| be «» (the empty list).
925+
926+
11. Let |nextResult| be the result of calling <a>Invoke</a>(<code>next</code>,
927+
|layoutGenerator|, |childFragmentResults|).
928+
929+
12. Perform the following substeps until the result of <a>Get</a>(|nextResult|,
930+
<code>"done"</code>) is <code>true</code>.
931+
932+
1. Set |childFragmentResults| be «» (the empty list).
933+
934+
2. Let |fragmentRequests| be the result of <a>Get</a>(|nextResult|, <code>"value"</code>).
935+
936+
3. For each |fragmentRequest| in |fragmentRequests| perform the following substeps:
937+
938+
1. Let |layoutChild| be result of looking up the internal slot
939+
<code>\[[layoutChild]]</code> on |fragmentRequest|.
940+
941+
2. Let |childConstraintSpace| be the result of looking up the internal slot
942+
<code>\[[childConstraintSpace]]</code> on |fragmentRequest|.
943+
944+
3. Let |childBreakToken| be the result of looking up the internal slot
945+
<code>\[[childBreakToken]]</code> on |fragmentRequest|.
946+
947+
4. Let |childFragmentResult| be the result of invoking <a>generate a fragment</a> with
948+
the arguments |layoutChild|, |childConstraintSpace|, |childBreakToken|.
949+
950+
The user agent <em>may</em> perform this step <a>in parallel</a>.
951+
952+
5. Append |childFragmentResult| to |childFragmentResults|.
953+
954+
4. Let |nextResult| be the result of calling <a>Invoke</a>(<code>next</code>,
955+
|layoutGenerator|, |childFragmentResults|).
956+
957+
13. Let |fragmentResult| be the result of calling <a>Get</a>(|nextResult|,
958+
<code>"value"</code>).
959+
960+
14. Let |fragment| be a <a>fragment</a> with the following properties:
961+
962+
- The <a>border box</a> <a>inline size</a> is set to |fragmentResult|'s
963+
{{FragmentResultOptions/inlineSize}}.
964+
965+
- The <a>border box</a> <a>block size</a> is set to |fragmentRequest|'s
966+
{{FragmentResultOptions/blockSize}}.
967+
968+
- The <a>inline overflow size</a> is set to |fragmentResult|'s
969+
{{FragmentResultOptions/inlineOverflowSize}} if not null, otherwise it is set to
970+
{{FragmentResultOptions/inlineSize}}.
971+
972+
- The <a>block overflow size</a> is set to |fragmentResult|'s
973+
{{FragmentResultOptions/blockOverflowSize}} if not null, otherwise it is set to
974+
{{FragmentResultOptions/blockSize}}.
825975

826-
The user agent passes in:
827-
- The current children for the <a>box</a>, with only {{LayoutClass/childInputProperties}} on
828-
{{Box/styleMap}}
829-
- The available space defined by a {{ConstraintSpace}}
830-
- The computed style of the <a>box</a>, with only {{LayoutClass/inputProperties}}
831-
- The {{BreakToken}} if any, for where the <a>box</a> was last fragmented.
976+
If the |constraintSpace|'s {{ConstraintSpace/inlineOverflow}} is <code>false</code> and
977+
the <a>inline overflow size</a> is greater than the <a>inline size</a> and the <a>computed
978+
value</a> for <a>inline</a> 'overflow' is ''auto'' then set |constraintSpace|'s
979+
{{ConstraintSpace/inlineOverflow}} to <code>true</code>.
832980

833-
The author defined code should produce a {{LayoutResult}}.
981+
If the |constraintSpace|'s {{ConstraintSpace/blockOverflow}} is <code>false</code> and the
982+
<a>block overflow size</a> is greater than the <a>block size</a> and the <a>computed
983+
value</a> for <a>block</a> 'overflow' is ''auto'' then set |constraintSpace|'s
984+
{{ConstraintSpace/blockOverflow}} to <code>true</code>.
834985

835-
The {{LayoutResult}} consists of:
836-
- A {{LayoutResult/minContent}} which represents the fragment's <a>min-content inline-size
837-
contribution</a>.
838-
- A {{LayoutResult/maxContent}} which represents the fragment's <a>max-content inline-size
839-
contribution</a>.
840-
- A {{LayoutResult/width}} which represents the fragment's resulting width.
841-
- A {{LayoutResult/height}} which represents the fragment's resulting height.
842-
- A list of {{LayoutResult/fragments}} which represents the fragment's direct child fragments.
843-
- A list of {{LayoutResult/unpositionedFragments}} which represents the fragment's children which
844-
should be positioned by a parent fragment.
845-
- A {{LayoutResult/breakToken}} which represents where the current layout's box last broke.
846-
- A {{LayoutResult/baseline}} which represents the baseline of the fragment.
986+
If either {{ConstraintSpace/inlineOverflow}} or {{ConstraintSpace/blockOverflow}} were set
987+
in the above steps, restart this algorithm with the updated |constraintSpace|.
847988

848-
Issue: Write the following into the algorithm.
989+
Note: In a future level of the specification there may be a way to more efficiently abort
990+
a layout given a "scroll trigger line" on the constraint space.
849991

850-
If any {{Fragment}}s appear in both the list of {{LayoutResult/fragments}} or the list of
851-
{{LayoutResult/unpositionedFragments}} the user agent should throw an error.
992+
- The children fragments of the |fragment| is set from |fragmentResult|'s
993+
{{FragmentResultOptions/childFragments}}. The ordering <em>is</em> important as this is
994+
dictates their paint order (described in [[#layout-api-containers]]). Their position
995+
relative to the <a>border box</a> of the |fragment| should be based off the author
996+
specified {{Fragment/inlineOffset}} and {{Fragment/blockOffset}}.
852997

853-
The user agent should check that a consistent set of {{Fragment}}s generated from a {{LayoutChild}}
854-
is returned in either the list of {{LayoutResult/fragments}} or
855-
{{LayoutResult/unpositionedFragments}}. (Consistent being that a {{Fragment/breakToken}} from one
856-
{{Fragment}} was used to generate another {{Fragment}} in the set).
998+
- The <a>fragmentation break</a> is set to |fragmentResult|'s
999+
{{FragmentResultOptions/breakToken}}.
8571000

858-
If any {{Fragment}}s appear more than once, the user agent should throw an error.
1001+
- The <a>dominant baseline</a> is set to |fragmentResult|'s
1002+
{{FragmentResultOptions/dominantBaseline}} if not null, otherwise it is set to:
1003+
- The {{Fragment/dominantBaseline}} of the first child fragment if present.
8591004

860-
When the user agent wants to <dfn>generate a layout</dfn> of a <<layout()>> or <<inline-layout()>>
861-
for a box it <em>must</em> run the following steps:
1005+
- The {{FragmentResultOptions/blockSize}} of the fragment.
8621006

863-
Issue: TODO specify these steps.
1007+
15. Return |fragment|.
8641008

8651009
Examples {#examples}
8661010
====================

0 commit comments

Comments
 (0)