Skip to content

Commit 279e805

Browse files
committed
use concrete types when iterating children
this is way nicer when checking the type of the child item with the language server, and makes it more visible what kinds of types the JIT has to juggle, and is more portable to zig unions!
1 parent 313fd34 commit 279e805

6 files changed

Lines changed: 65 additions & 66 deletions

File tree

src/api.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import '#register-default-environment';
22
import {HTMLElement, TextNode} from './dom.ts';
33
import {DeclaredStyle, getOriginStyle, computeElementStyle} from './style.ts';
44
import {fonts, FontFace, createFaceFromTables, createFaceFromTablesSync, onLoadWalkerTextNodeForFonts, onLoadWalkerElementForFonts} from './text-font.ts';
5-
import {generateBlockContainer, layoutBlockLevelBox, BlockContainer} from './layout-flow.ts';
5+
import {generateBlockContainer, layoutBlockLevelBox} from './layout-flow.ts';
66
import HtmlPaintBackend from './paint-html.ts';
77
import SvgPaintBackend from './paint-svg.ts';
88
import CanvasPaintBackend from './paint-canvas.ts';
@@ -16,6 +16,7 @@ import type {Canvas, CanvasRenderingContext2D} from './paint-canvas.ts';
1616

1717
import type {Style} from './style.ts';
1818
import type {Image} from './layout-image.ts';
19+
import type {BlockContainer} from './layout-flow.ts';
1920

2021
export {environment} from './environment.ts';
2122

@@ -222,7 +223,7 @@ export function staticLayoutContribution(box: BlockContainer): number {
222223
intrinsicSize = Math.max(intrinsicSize, line.width);
223224
}
224225
// TODO: floats
225-
} else if (box.isBlockContainerOfBlocks()) {
226+
} else {
226227
for (const child of box.children) {
227228
if (child.isBlockContainer()) {
228229
intrinsicSize = Math.max(intrinsicSize, staticLayoutContribution(child));
@@ -231,8 +232,6 @@ export function staticLayoutContribution(box: BlockContainer): number {
231232
intrinsicSize = Math.max(intrinsicSize, child.getBorderArea().inlineSize);
232233
}
233234
}
234-
} else {
235-
throw new Error(`Unknown box type: ${box.id}`);
236235
}
237236

238237
const containingBlock = box.getContainingBlock();

src/layout-box.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
Inline,
99
IfcInline,
1010
BlockContainer,
11+
BlockContainerBase,
1112
BlockContainerOfInlines,
1213
BlockContainerOfBlocks,
1314
ReplacedBox
@@ -39,7 +40,7 @@ export abstract class RenderItem {
3940
this.style = style;
4041
}
4142

42-
isBlockContainer(): this is BlockContainer {
43+
isBlockContainer(): this is BlockContainerBase {
4344
return false;
4445
}
4546

@@ -843,7 +844,7 @@ export function postlayout(root: BlockContainer) {
843844
child.postlayoutPostorder();
844845
}
845846
}
846-
} else if (box.isBlockContainerOfInlines()) {
847+
} else {
847848
stack.push(box.ifc);
848849
}
849850
}

src/layout-flow.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export class BlockFormattingContext {
108108
this.hypotheticals = EMPTY_MAP;
109109
}
110110

111-
collapseStart(box: FormattingBox) {
111+
collapseStart(box: BlockLevel) {
112112
const containingBlock = box.getContainingBlock();
113113
const marginBlockStart = box.style.getMarginBlockStart(containingBlock);
114114
let floatBottom = 0;
@@ -222,7 +222,7 @@ export class BlockFormattingContext {
222222
this.last = 'end';
223223
}
224224

225-
boxAtomic(box: FormattingBox) {
225+
boxAtomic(box: BlockLevel) {
226226
const containingBlock = box.getContainingBlock();
227227
const marginBlockEnd = box.style.getMarginBlockEnd(containingBlock);
228228
assumePx(marginBlockEnd);
@@ -343,7 +343,7 @@ export class BlockFormattingContext {
343343
}
344344

345345
class FloatSide {
346-
items: FormattingBox[];
346+
items: BlockLevel[];
347347
// Moving shelf area (stretches to infinity in the block direction)
348348
shelfBlockOffset: number;
349349
shelfTrackIndex: number;
@@ -469,7 +469,7 @@ class FloatSide {
469469
}
470470
}
471471

472-
placeFloat(box: FormattingBox, vacancy: IfcVacancy, cbLineLeft: number, cbLineRight: number) {
472+
placeFloat(box: BlockLevel, vacancy: IfcVacancy, cbLineLeft: number, cbLineRight: number) {
473473
if (box.style.float === 'none') {
474474
throw new Error('Tried to place float:none');
475475
}
@@ -563,7 +563,7 @@ export class FloatContext {
563563
bfc: BlockFormattingContext;
564564
leftFloats: FloatSide;
565565
rightFloats: FloatSide;
566-
misfits: FormattingBox[];
566+
misfits: BlockLevel[];
567567

568568
constructor(bfc: BlockFormattingContext, blockOffset: number) {
569569
this.bfc = bfc;
@@ -586,7 +586,7 @@ export class FloatContext {
586586
return new IfcVacancy(leftOffset, rightOffset, blockOffset, inlineSize, 0, 0);
587587
}
588588

589-
getVacancyForBox(box: FormattingBox, lineWidth: number) {
589+
getVacancyForBox(box: BlockLevel, lineWidth: number) {
590590
const float = box.style.float;
591591
const floats = float === 'left' ? this.leftFloats : this.rightFloats;
592592
const oppositeFloats = float === 'left' ? this.rightFloats : this.leftFloats;
@@ -656,7 +656,7 @@ export class FloatContext {
656656
return this.getVacancyForLine(blockOffset, blockSize);
657657
}
658658

659-
placeFloat(lineWidth: number, lineIsEmpty: boolean, box: FormattingBox) {
659+
placeFloat(lineWidth: number, lineIsEmpty: boolean, box: BlockLevel) {
660660
if (box.style.float === 'none') {
661661
throw new Error('Attempted to place float: none');
662662
}
@@ -728,7 +728,9 @@ export class FloatContext {
728728
}
729729
}
730730

731-
export abstract class BlockContainer extends FormattingBox {
731+
export type BlockContainer = BlockContainerOfInlines | BlockContainerOfBlocks;
732+
733+
export abstract class BlockContainerBase extends FormattingBox {
732734
static ATTRS = {
733735
...FormattingBox.ATTRS,
734736
isInline: Box.BITS.isInline,
@@ -769,7 +771,7 @@ export abstract class BlockContainer extends FormattingBox {
769771
return {blockStart, lineLeft, lineRight};
770772
}
771773

772-
isBlockContainer(): this is BlockContainer {
774+
isBlockContainer(): this is BlockContainerBase {
773775
return true;
774776
}
775777

@@ -818,7 +820,7 @@ export abstract class BlockContainer extends FormattingBox {
818820
}
819821
}
820822

821-
export class BlockContainerOfInlines extends BlockContainer {
823+
export class BlockContainerOfInlines extends BlockContainerBase {
822824
ifc: IfcInline;
823825

824826
constructor(style: Style, ifc: IfcInline, attrs: number) {
@@ -839,7 +841,7 @@ export class BlockContainerOfInlines extends BlockContainer {
839841

840842
export type BlockLevel = BlockContainer | ReplacedBox;
841843

842-
export class BlockContainerOfBlocks extends BlockContainer {
844+
export class BlockContainerOfBlocks extends BlockContainerBase {
843845
children: BlockLevel[];
844846

845847
constructor(style: Style, children: BlockLevel[], attrs: number) {
@@ -853,9 +855,9 @@ export class BlockContainerOfBlocks extends BlockContainer {
853855
}
854856

855857
// §10.3.3
856-
function doInlineBoxModelForBlockBox(box: FormattingBox) {
858+
function doInlineBoxModelForBlockBox(box: BlockLevel) {
857859
const containingBlock = box.getContainingBlock();
858-
const cInlineSize = containingBlock.inlineSizeForPotentiallyOrthogonal(box);
860+
const cInlineSize = box.getContainingBlock().inlineSizeForPotentiallyOrthogonal(box);
859861
const inlineSize = box.getDefiniteInnerInlineSize(containingBlock);
860862
let marginLineLeft = box.style.getMarginLineLeft(containingBlock);
861863
let marginLineRight = box.style.getMarginLineRight(containingBlock);
@@ -959,8 +961,6 @@ function layoutBlockBoxInner(box: BlockContainer, ctx: LayoutContext) {
959961
}
960962
} else if (box.isBlockContainerOfBlocks()) {
961963
for (const child of box.children) layoutBlockLevelBox(child, cctx);
962-
} else {
963-
throw new Error(`Unknown box type: ${box.id}`);
964964
}
965965

966966
if (establishedBfc) {
@@ -1001,11 +1001,11 @@ export function layoutBlockLevelBox(box: BlockLevel, ctx: LayoutContext) {
10011001
}
10021002
}
10031003

1004-
function doInlineBoxModelForFloatBox(box: FormattingBox, inlineSize: number) {
1004+
function doInlineBoxModelForFloatBox(box: BlockLevel, inlineSize: number) {
10051005
box.setInlineOuterSize(inlineSize);
10061006
}
10071007

1008-
function doBlockBoxModelForFloatBox(box: FormattingBox) {
1008+
function doBlockBoxModelForFloatBox(box: BlockLevel) {
10091009
const size = box.getDefiniteInnerBlockSize();
10101010
if (size !== undefined) box.setBlockSize(size);
10111011
}
@@ -1038,7 +1038,7 @@ export function layoutContribution(
10381038
for (const child of box.children) {
10391039
isize = Math.max(isize, layoutContribution(child, mode));
10401040
}
1041-
} else if (box.isBlockContainerOfInlines()) {
1041+
} else {
10421042
if (box.ifc.shouldLayoutContent()) {
10431043
isize = box.ifc.paragraph.contribution(mode);
10441044
}
@@ -1553,7 +1553,7 @@ function mapTree(
15531553
child = new Break(childEl.style);
15541554
} else if (childEl.style.display.outer === 'block') {
15551555
if (childEl.style.isOutOfFlow()) {
1556-
child = generateFormattingBox(childEl);
1556+
child = generateBlockBox(childEl);
15571557
} else {
15581558
bail = true;
15591559
}
@@ -1562,7 +1562,7 @@ function mapTree(
15621562
childEl.style.display.inner === 'flow-root' ||
15631563
childEl.tagName === 'img'
15641564
) {
1565-
child = generateFormattingBox(childEl);
1565+
child = generateBlockBox(childEl);
15661566
} else {
15671567
[bail, child] = mapTree(childEl, text, path, level + 1);
15681568
}
@@ -1599,7 +1599,7 @@ function generateInlineBox(
15991599

16001600
if (target instanceof HTMLElement && target.style.display.outer === 'block') {
16011601
++path[path.length - 1];
1602-
return [true, generateFormattingBox(target)];
1602+
return [true, generateBlockBox(target)];
16031603
}
16041604

16051605
return mapTree(el, text, path, 0);
@@ -1615,7 +1615,7 @@ function wrapInBlockContainer(parentEl: HTMLElement, inlines: InlineLevel[], tex
16151615
return new BlockContainerOfInlines(anonStyle, ifc, attrs);
16161616
}
16171617

1618-
function generateFormattingBox(el: HTMLElement): BlockLevel {
1618+
function generateBlockBox(el: HTMLElement): BlockLevel {
16191619
if (el.tagName === 'img') {
16201620
const box = new ReplacedBox(el.style, el.attrs.src ?? "");
16211621
el.boxes.push(box);
@@ -1642,7 +1642,7 @@ export function generateBlockContainer(el: HTMLElement): BlockContainer {
16421642
el.style.display.inner === 'flow-root' ||
16431643
el.parent && writingModeInlineAxis(el) !== writingModeInlineAxis(el.parent)
16441644
) {
1645-
attrs |= BlockContainer.ATTRS.isBfcRoot;
1645+
attrs |= BlockContainerBase.ATTRS.isBfcRoot;
16461646
}
16471647

16481648
if (enableLogging) attrs |= Box.ATTRS.enableLogging;
@@ -1654,7 +1654,7 @@ export function generateBlockContainer(el: HTMLElement): BlockContainer {
16541654
if (child.tagName === 'br') {
16551655
inlines.push(new Break(child.style));
16561656
} else if (child.style.display.outer === 'block') {
1657-
const block = generateFormattingBox(child);
1657+
const block = generateBlockBox(child);
16581658

16591659
if (block.style.isOutOfFlow()) {
16601660
inlines.push(block);
@@ -1672,7 +1672,7 @@ export function generateBlockContainer(el: HTMLElement): BlockContainer {
16721672
child.style.display.inner === 'flow-root' || // inline-block
16731673
child.tagName === 'img'
16741674
) {
1675-
inlines.push(generateFormattingBox(child));
1675+
inlines.push(generateBlockBox(child));
16761676
} else {
16771677
const path: number[] = [];
16781678
let more, box;
@@ -1704,7 +1704,7 @@ export function generateBlockContainer(el: HTMLElement): BlockContainer {
17041704
}
17051705

17061706
if (el.style.display.outer === 'inline') {
1707-
attrs |= BlockContainer.ATTRS.isInline;
1707+
attrs |= BlockContainerBase.ATTRS.isInline;
17081708
}
17091709

17101710
let box;

0 commit comments

Comments
 (0)