2020-05-24

Toy-Browser-...

写在前面

  • implementation of a toy-browser 🙆
  • 最末篇:浏览器的绘制,完结 toy-browser ✊
  • DOM with Position

第一步:绘制单个元素

  • 绘制需要依赖一个图形环境

  • 这里采用 npm package – images

  • 绘制先在一个 viewport 上进行

  • 暂时只处理绘制属性:background-color

  • render1.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    const images = require('images')

    function render(viewport, element) {
    if (element.style) {
    const img = images(element.style.width, element.style.height)

    if (element.style["background-color"]) {
    let color = element.style["background-color"] || "rgb(0,0,0)"
    color.match(/rgb\((\d+),(\d+),(\d+)\)/)
    // .fill(red, green, blue[, alpha])
    img.fill(Number(RegExp.$1), Number(RegExp.$2), Number(RegExp.$3), 1)
    viewport.draw(img, element.style.left || 0, element.style.top || 0)
    }
    }
    }

    module.exports = render
  • client.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    // ... some code

    void async function () {

    // ... some code

    let dom = parser.parseHTML(response.body)

    let viewport = images(800, 600)

    // 绘制 cls1 元素点,rgb(0, 255, 0)
    render(viewport, dom.children[0].children[3].children[1].children[3])

    viewport.save("viewport.jpg")
    }()
  • 运行结果

    • 运行结果
  • render1.js 完整代码-点击一下

第二步:绘制 DOM

  • 递归调用子元素的绘制方法完成 DOM 树的构建

  • render2.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const images = require('images')

    function render(viewport, element) {
    if (element.style) {

    // some code

    }

    if (element.children) {
    for (let child of element.children) {
    render(viewport, child)
    }
    }

    }

    module.exports = render
  • 忽略一些不需要绘制的节点

  • 实际浏览器中,文字绘制是难点,需要依赖字体库,这里忽略

  • 实际浏览器中,还会对一些图层做 compositing,这里忽略

  • server.js 将response Content-Type 设置为 text/html

    1
    2
    3
    4
    5
    6

    // some code

    res.writeHead(200, { 'Content-Type': 'text/html' });

    // some code
  • 运行结果

    • 运行结果

写在后面