DEV Community

Murahashi [Matt] Kenichi
Murahashi [Matt] Kenichi

Posted on • Edited on

2

Let's build browser engine! in typescript vol2 Display Command

// node_modules/.bin/ts-node example/display-command.ts | display

import * as Jimp from "jimp";

import { Rect } from "../src/layout";
import { Canvas, DisplayCommand } from "../src/painting";
import { Color } from "../src/css";
const black = new Color(0, 0, 0, 255);

const canvas = Canvas.Create(200, 100);
canvas.paintItem(new DisplayCommand.SolidColor(black, new Rect(10, 20, 30, 30)));

Jimp.create(canvas.width, canvas.height)
  .then((value: Jimp) => {
    let buffer = value.bitmap.data;
    for (let i = 0; i < canvas.pixels.length; i++) {
      buffer[i * 4] = canvas.pixels[i].r;
      buffer[i * 4 + 1] = canvas.pixels[i].g;
      buffer[i * 4 + 2] = canvas.pixels[i].b;
      buffer[i * 4 + 3] = canvas.pixels[i].a;
    }
    return value.getBufferAsync(Jimp.MIME_PNG);
  })
  .then((value: Buffer) => {
    process.stdout.write(value);
  })
  .catch((error: Error) => {
    console.error(error);
  });
Enter fullscreen mode Exit fullscreen mode


import { Rect } from "../src/layout";

test("rect", () => {
  expect(new Rect(1, 2, 3, 4).height).toBe(4);
});
Enter fullscreen mode Exit fullscreen mode
export class Rect {
  x: number;
  y: number;
  width: number;
  height: number;

  constructor(x: number, y: number, width: number, height: number) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
  }
}
Enter fullscreen mode Exit fullscreen mode
import { Canvas, DisplayCommand } from "../src/painting";
import { Color } from "../src/css";
import { Rect } from "../src/layout";

const white = new Color(255, 255, 255, 255);
const black = new Color(0, 0, 0, 255);

test("solid color", () => {
  expect(new DisplayCommand.SolidColor(white, new Rect(0, 0, 0, 0)).format).toEqual(
    DisplayCommand.Format.SolidColor
  );
});

test("canvas paint item", () => {
  const canvas = Canvas.Create(2, 3);
  canvas.paintItem(new DisplayCommand.SolidColor(black, new Rect(0, 0, 1, 1)));
  expect(canvas.pixels).toEqual([black, white, white, white, white, white]);
});
Enter fullscreen mode Exit fullscreen mode
import { Color } from "./css";
import { Rect } from "./layout";
const mathClamp = require("math-clamp");

export class Canvas {
  // snip

  paintItem(item: DisplayCommand) {
    switch (item.format) {
      case DisplayCommand.Format.SolidColor:
        const rect = item.rect;
        const color = item.color;
        let x0 = mathClamp(rect.x, 0.0, this.width);
        let y0 = mathClamp(rect.y, 0.0, this.height);
        let x1 = mathClamp(rect.x + rect.width, 0.0, this.width);
        let y1 = mathClamp(rect.y + rect.height, 0.0, this.height);
        for (let y = y0; y < y1; y++) {
          for (let x = x0; x < x1; x++) {
            // TODO: alpha compositing with existing pixel
            this.pixels[x + y * this.width] = color;
          }
        }
    }
  }
}

export namespace DisplayCommand {
  export enum Format {
    SolidColor
  }

  export class SolidColor {
    readonly format = Format.SolidColor;
    color: Color;
    rect: Rect;
    constructor(color: Color, rect: Rect) {
      this.color = color;
      this.rect = rect;
    }
  }
}

export type DisplayCommand = DisplayCommand.SolidColor;
Enter fullscreen mode Exit fullscreen mode

It works!

references

series

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

👋 Kindness is contagious

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

Okay