Canvas API 实施

Canvas API implementation

我最近开始了解 javascript 的幕后工作原理,并了解到(在 chrome 的上下文中)v8 引擎和网络 APIs是不同的。以下是我对 canvas API 的一些具体问题:

  1. 为什么我们每次要访问给定 canvas 的像素时都需要使用 getImageData()?由于 canvas 是基于像素的,难道不应该有一个像素数组供 canvas API 在您每次在其上绘制时操作,这将使它静态可用吗?
  2. 有没有办法了解具体的 API 是如何实现的?例如——ctx.fillRect() 是如何在内部完成的?我尝试通过更改特定像素颜色来手动执行此操作,但事实证明速度要慢得多。也许是因为我是在 javascript 中做的,而它通常是在 C++ 内部完成的?由于实现是在他们自己的源代码中,所以没有办法找到吗?

我可能混淆了很多概念,因为我仍然不太了解 web API 或 v8 是如何工作的,因此欢迎任何澄清。

Why do we need to use getImageData() every time we want to access the pixels of a given canvas? Since canvas is pixel-based, shouldn't there be a pixel array that the canvas API manipulates every time you draw on it, which would make it statically available?

你是对的,它本可以这样做,甚至 active discussions 直接访问像素缓冲区,允许零拷贝读写操作。
然而在最初的设计中,认为有必要将像素缓冲区与当前上下文执行完全分离。这允许例如具有基于 GPU 的实现,其中所有绘图都由 GPU 执行,并且后备缓冲区存储在 GPU 的内存中,因此脚本无法访问。
还要注意的是,大多数实现使用双缓冲,在前缓冲区和后缓冲区之间交换,以避免撕裂。

Is there a way to understand how specific APIs are implemented? For instance—how is ctx.fillRect() done internally?

您可以随时尝试浏览资源,Chrome 非常方便 https://source.chromium.org/, Firefox has https://searchfox.org 然而对于 Canvas 2D API,关于真正看哪里的事情有点复杂。 每个浏览器确实至少有一个渲染引擎,在这个引擎中将存在所有 API 包装器,然后它将调用另一个图形引擎,该引擎将生成图形。
在基于 Chromium 的浏览器中,渲染引擎被称为 Blink,图形引擎被称为 Skia,在 Safari 中它们使用 WebKit(Blink 从中分叉)和 Core Graphics,而在 Firefox 中,IIRC Gecko 使用基于平台(Cairo、Core Graphics 或 Skia)的各种渲染和图形引擎,因此在该浏览器中查找实际图形操作的位置并不那么容易。
为了增加一些乐趣,所有这些图形引擎都将支持“软件渲染”(CPU) 路径或“硬件加速”(GPU) 路径。

但是为了帮助您开始您的旅程,blink 的 fillRect() 实现从这里开始:https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc;l=1075


注意:JavaScript 引擎(例如 v8)在所有这件事上几乎没有作用。