I'm not sure, which method I have to keep node balance.
test("LayoutBox#getInlineContainer anonymous block", () => {
const layoutBoxAnonymousBlock = new LayoutBox(
new Dimensions(
new Rect(1, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.AnonymousBlock(),
[]
);
expect(layoutBoxAnonymousBlock.getInlineContainer()).toEqual(layoutBoxAnonymousBlock);
});
test("LayoutBox#getInlineContainer inline node", () => {
const layoutBoxInlineNode = new LayoutBox(
new Dimensions(
new Rect(1, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.InlineNode(oneStyledNode),
[]
);
expect(layoutBoxInlineNode.getInlineContainer()).toEqual(layoutBoxInlineNode);
});
test("LayoutBox#getInlineContainer block node 1", () => {
const layoutBoxAnonymousBlock = new LayoutBox(
new Dimensions(
new Rect(1, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.AnonymousBlock(),
[]
);
const layoutBoxBlockNode = new LayoutBox(
new Dimensions(
new Rect(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.BlockNode(oneStyledNode),
[layoutBoxAnonymousBlock]
);
expect(layoutBoxBlockNode.getInlineContainer()).toEqual(layoutBoxAnonymousBlock);
});
test("LayoutBox#getInlineContainer block node 2", () => {
const layoutBoxBlockNode = new LayoutBox(
new Dimensions(
new Rect(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.BlockNode(oneStyledNode),
[]
);
expect(layoutBoxBlockNode.getInlineContainer()).toEqual(
LayoutBox.Create(new BoxType.AnonymousBlock())
);
});
export class LayoutBox {
(snip)
// NOTE: This may modify this.children :trollface:
getInlineContainer(): LayoutBox {
switch (this.boxType.format) {
case BoxType.Format.AnonymousBlock:
case BoxType.Format.InlineNode:
return this;
case BoxType.Format.BlockNode:
if (
this.children.length === 0 ||
this.children[this.children.length - 1].boxType.format !== BoxType.Format.AnonymousBlock
) {
this.children.push(LayoutBox.Create(new BoxType.AnonymousBlock()));
}
return this.children[this.children.length - 1];
}
}
}
test("buildLayoutTree 1", () => {
const displayNone = new StyledNode(
elem("no mean", new Map([["id", "target"]]), []),
new Map([["display", new CssValue.Keyword("none")]]),
[]
);
expect(() => {
buildLayoutTree(displayNone);
}).toThrow();
});
test("buildLayoutTree 2", () => {
const displayBlock = new StyledNode(
elem("no mean", new Map([["id", "target"]]), []),
new Map([["display", new CssValue.Keyword("block")]]),
[]
);
expect(buildLayoutTree(displayBlock)).toEqual(
LayoutBox.Create(new BoxType.BlockNode(displayBlock))
);
});
test("buildLayoutTree 3", () => {
const displayInline = new StyledNode(
elem("no mean", new Map([["id", "target"]]), []),
new Map([["display", new CssValue.Keyword("no mean")]]),
[]
);
expect(buildLayoutTree(displayInline)).toEqual(
LayoutBox.Create(new BoxType.InlineNode(displayInline))
);
});
test("buildLayoutTree 4", () => {
const childDisplayBlock = new StyledNode(
elem("no mean", new Map([["id", "target2"]]), []),
new Map([["display", new CssValue.Keyword("block")]]),
[]
);
const displayBlock = new StyledNode(
elem("no mean", new Map([["id", "target"]]), []),
new Map([["display", new CssValue.Keyword("block")]]),
[childDisplayBlock]
);
expect(buildLayoutTree(displayBlock)).toEqual(
new LayoutBox(
new Dimensions(
new Rect(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.BlockNode(displayBlock),
[LayoutBox.Create(new BoxType.BlockNode(childDisplayBlock))]
)
);
});
test("buildLayoutTree 5", () => {
const childDisplayInline = new StyledNode(
elem("no mean", new Map([["id", "target2"]]), []),
new Map([["display", new CssValue.Keyword("no mean")]]),
[]
);
const displayBlock = new StyledNode(
elem("no mean", new Map([["id", "target"]]), []),
new Map([["display", new CssValue.Keyword("block")]]),
[childDisplayInline]
);
expect(buildLayoutTree(displayBlock)).toEqual(
new LayoutBox(
new Dimensions(
new Rect(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.BlockNode(displayBlock),
[
new LayoutBox(
new Dimensions(
new Rect(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.AnonymousBlock(),
[LayoutBox.Create(new BoxType.InlineNode(childDisplayInline))]
)
]
)
);
});
test("buildLayoutTree 6", () => {
const childDisplayNone = new StyledNode(
elem("no mean", new Map([["id", "target2"]]), []),
new Map([["display", new CssValue.Keyword("none")]]),
[]
);
const displayBlock = new StyledNode(
elem("no mean", new Map([["id", "target"]]), []),
new Map([["display", new CssValue.Keyword("block")]]),
[childDisplayNone]
);
expect(buildLayoutTree(displayBlock)).toEqual(
new LayoutBox(
new Dimensions(
new Rect(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0),
new EdgeSizes(0, 0, 0, 0)
),
new BoxType.BlockNode(displayBlock),
[]
)
);
});
export function buildLayoutTree(styleNode: StyledNode): LayoutBox {
let root: LayoutBox;
switch (styleNode.display()) {
case Display.None: // NOTE: I'm not sure "Uncovered Line"
throw Error("Root node has display: none.");
case Display.Block:
root = LayoutBox.Create(new BoxType.BlockNode(styleNode));
break;
case Display.Inline:
root = LayoutBox.Create(new BoxType.InlineNode(styleNode));
break;
default:
/* istanbul ignore next */
throw Error("never");
}
for (const child of styleNode.children) {
switch (child.display()) {
case Display.Inline:
root.getInlineContainer().children.push(buildLayoutTree(child));
break;
case Display.Block:
root.children.push(buildLayoutTree(child));
break;
case Display.None:
// do nothing
break;
}
}
return root;
}
references
- Let's build a browser engine! Part 1: Getting started
- mbrubeck/robinson
- sanemat/js-toy-engine
- sanemat/ts-toy-engine
series
- Let's build browser engine! in typescript vol0 Toy browser engine
- Let's build browser engine! in typescript vol1 Canvas with Color
- Let's build browser engine! in typescript vol2 Display Command
- Let's build browser engine! in typescript vol3 Layout Box, Dimensions
- Let's build browser engine! in typescript vol4 Layout Tree to Display List
- Let's build browser engine! in typescript vol5 DOM Shortcut
- Let's build browser engine! in typescript vol6 CSS Shortcut
- Let's build browser engine! in typescript vol7 Selector matching
- Let's build browser engine! in typescript vol8 Specificity
- Let's build browser engine! in typescript vol9 DOM and Rules to Style tree
- Let's build browser engine! in typescript vol10 style display
- Let's build browser engine! in typescript vol11 Build Layout tree
Top comments (0)