DEV Community

Murahashi [Matt] Kenichi
Murahashi [Matt] Kenichi

Posted on

3 1

Let's build browser engine! in typescript vol11 Build Layout tree

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())
  );
});
Enter fullscreen mode Exit fullscreen mode
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];
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
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),
      []
    )
  );
});
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

references

series

Image of Datadog

How to Diagram Your Cloud Architecture

Cloud architecture diagrams provide critical visibility into the resources in your environment and how they’re connected. In our latest eBook, AWS Solution Architects Jason Mimick and James Wenzel walk through best practices on how to build effective and professional diagrams.

Download the Free eBook

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay