@@ -493,7 +493,7 @@ Breaking and Fragmentation {#breaking-and-fragmentation}
493
493
<pre class="idl">
494
494
interface ChildBreakToken {
495
495
readonly attribute BreakType breakType;
496
- readonly attribute Box box ;
496
+ readonly attribute LayoutChild child ;
497
497
};
498
498
499
499
interface BreakToken {
@@ -519,62 +519,160 @@ A subsequent {{Fragment}} is produced by using the previous {{Fragment}}'s {{Fra
519
519
This tells the <a>child layout</a> to produce a {{Fragment}} starting at the point encoded in the
520
520
{{ChildBreakToken}} .
521
521
522
- When returning a list of {{Fragment}} s from the <a>current layout</a> the list of {{Fragment}} s must
523
- have a contiguous set of {{Fragment/breakToken}} s.
524
-
525
522
<div class="example">
526
- TODO: add example showing non-contiguous set of fragments.
527
- </div>
523
+ This example shows a simple inline layout which places child fragments in the inline direction. It
524
+ places each of its on a line, aligning their dominant baselines.
528
525
529
- <div class="example">
530
- This example shows how to use a previous {{Fragment}} 's {{Fragment/breakToken}} to produce the next
531
- {{Fragment}} in the sequence.
526
+ This example also demonstrates using the previous {{Fragment/breakToken}} of a {{Fragment}} to
527
+ produce the next fragment for the {{LayoutChild}} .
528
+
529
+ It also demonstrates using the {{BreakToken}} to respect the {{ConstraintSpace}} 's
530
+ {{ConstraintSpace/blockFragmentationType}} , it resumes it layout from the previous {{BreakToken}} .
531
+ It returns a {{FragmentResultOptions}} with a {{FragmentResultOptions/breakToken}} which is used to
532
+ resume the layout.
532
533
533
534
<pre class="lang-javascript">
534
- registerLayout('fragmenting ' , class {
535
- *layout(space, children, styleMap, breakToken) {
535
+ registerLayout('basic-inline ' , class extends Layout {
536
+ static inputProperties = super.inputProperties;
536
537
537
- // ... snip ...
538
+ *layout(constraintSpace, children, styleMap, breakToken) {
539
+ // Resolve our inline size.
540
+ const inlineSize = resolveInlineSize(constraintSpace, styleMap);
538
541
539
- const fragments = [];
540
- let breakToken = null;
541
- for (let child of children) {
542
- // This do-while loop will keep producing fragments for a child box
543
- // until it cannot produce any more.
544
- do {
545
- // ... snip ... (setting up child constraint space).
542
+ // Determine our (inner) available size.
543
+ const bordersAndPadding =
544
+ resolveBordersAndPadding(constraintSpace, styleMap);
545
+ const scrollbarSize = resolveScrollbarSize(constraintSpace, styleMap);
546
+ const availableInlineSize = inlineSize -
547
+ bordersAndPadding.inlineStart -
548
+ bordersAndPadding.inlineEnd -
549
+ scrollbarSize.inline;
546
550
547
- let fragment = yield child.doLayout(childSpace, breakToken);
548
- breakToken = fragment.breakToken;
551
+ const availableBlockSize = resolveBlockSize(constraintSpace, styleMap) -
552
+ bordersAndPadding.blockStart -
553
+ bordersAndPadding.blockEnd -
554
+ scrollbarSize.block;
549
555
550
- fragments.push(fragment);
551
- } while (breakToken);
552
- }
556
+ const childFragments = [];
557
+ let maxInlineSize = 0;
553
558
554
- // ... snip ...
559
+ let currentLine = [];
560
+ let usedInlineSize = 0;
561
+ let maxBaseline = 0;
555
562
556
- }
557
- });
558
- </pre>
559
- </div>
563
+ let lineOffset = 0;
564
+ let maxLineBlockSize = 0;
560
565
561
- <div class="example">
562
- This example shows how to use resume a layout given a breakToken.
566
+ // Just a small little function which will update the above variables.
567
+ const nextLine = function() {
568
+ if (usedInlineSize > maxInlineSize) {
569
+ maxInlineSize = usedInlineSize;
570
+ }
563
571
564
- <pre class="lang-javascript">
565
- registerLayout('fragmenting' , class {
566
- *layout(space, children, styleMap, breakToken) {
567
- const fragments = [];
572
+ currentLine = [];
573
+ usedInlineSize = 0;
574
+ maxBaseline = 0;
568
575
569
- // Produce the next fragment in the sequence if we have a breakToken.
576
+ lineOffset += maxLineBlockSize;
577
+ maxLineBlockSize = 0;
578
+ }
579
+
580
+ let childBreakToken = null;
570
581
if (breakToken) {
571
- for (let childBreakToken of breakToken.childBreakTokens) {
572
- let fragment = yield childBreakToken.box.doLayout(
573
- childSpace, childBreakToken);
582
+ childBreakToken = breakToken.childBreakTokens[0] ;
583
+
584
+ // Remove all the children we have already produced fragments for.
585
+ children.splice(0, children.indexOf(childBreakToken.child));
586
+ }
587
+
588
+ let child = children.shift();
589
+ while (child) {
590
+ // Make sure we actually have space on the current line.
591
+ if (usedInlineSize > availableInlineSize) {
592
+ nextLine();
593
+ }
594
+
595
+ // The constraint space here will have the inline size of the
596
+ // remaining space on the line.
597
+ const remainingInlineSize = availableInlineSize - usedInlineSize;
598
+ const constraintSpace = new ConstraintSpace({
599
+ inlineSize: availableInlineSize - usedInlineSize,
600
+ blockSize: availableBlockSize,
601
+ percentageInlineSize: availableInlineSize,
602
+ inlineShrinkToFit: true,
603
+ });
604
+
605
+ const fragment = yield child.doLayout(constraintSpace,
606
+ childBreakToken);
607
+ childFragments.push(fragment);
608
+
609
+ // Check if there is still space on the current line.
610
+ if (fragment.inlineSize > remainingInlineSize) {
611
+ nextLine();
612
+
613
+ // Check if we have gone over the block fragmentation limit.
614
+ if (constraintSpace.blockFragmentationType != 'none' &&
615
+ lineOffset > constraintSpace.blockSize) {
616
+ break;
617
+ }
618
+ }
619
+
620
+ // Insert fragment on the current line.
621
+ currentLine.push(fragment);
622
+ fragment.inlineOffset = usedInlineSize;
623
+
624
+ if (fragment.dominantBaseline > maxBaseline) {
625
+ maxBaseline = fragment.dominantBaseline;
626
+ }
627
+
628
+ // Go through each of the fragments on the line and update their
629
+ // block offsets.
630
+ for (let fragmentOnLine of currentLine) {
631
+ fragmentOnLine.blockOffset = lineOffset +
632
+ maxBaseline - fragmentOnLine.dominantBaseline;
633
+
634
+ const lineBlockSize =
635
+ fragmentOnLine.blockOffset + fragmentOnLine.blockSize;
636
+ if (maxLineBlockSize < lineBlockSize) {
637
+ maxLineBlockSize = lineBlockSize;
638
+ }
639
+ }
574
640
575
- fragments.push(fragment);
641
+ if (fragment.breakToken) {
642
+ childBreakToken = fragment.breakToken;
643
+ } else {
644
+ // If a fragment doesn't have a break token, we move onto the
645
+ // next child.
646
+ child = children.shift();
647
+ childBreakToken = null;
576
648
}
577
649
}
650
+
651
+ // Determine our block size.
652
+ nextLine();
653
+ const blockOverflowSize = lineOffset +
654
+ bordersAndPadding.blockStart +
655
+ bordersAndPadding.blockEnd;
656
+ const blockSize = resolveBlockSize(constraintSpace,
657
+ styleMap,
658
+ blockOverflowSize);
659
+
660
+ // Return our fragment.
661
+ const result = {
662
+ inlineSize: inlineSize,
663
+ blockSize: blockSize,
664
+ inlineOverflowSize: maxInlineSize,
665
+ blockOverflowSize: blockOverflowSize,
666
+ childFragments: childFragments,
667
+ }
668
+
669
+ if (childBreakToken) {
670
+ result.breakToken = {
671
+ childBreakTokens: [childBreakToken] ,
672
+ };
673
+ }
674
+
675
+ return result;
578
676
}
579
677
});
580
678
</pre>
@@ -969,7 +1067,7 @@ context</a> for a given |box|, |constraintSpace|, |children| and an optional |br
969
1067
- The <a>border box</a> <a>inline size</a> is set to |fragmentResult|'s
970
1068
{{FragmentResultOptions/inlineSize}} .
971
1069
972
- - The <a>border box</a> <a>block size</a> is set to |fragmentRequest |'s
1070
+ - The <a>border box</a> <a>block size</a> is set to |fragmentResult |'s
973
1071
{{FragmentResultOptions/blockSize}} .
974
1072
975
1073
- The <a>inline overflow size</a> is set to |fragmentResult|'s
0 commit comments