在Web平台上构建一个专业的设计工具

我们希望一个未来设计工具是这样的:任何人在任何地点,都能轻易的使用它,并获取到由它生产的内容。于是我们创建了Figma,它作为一种基于浏览器的云服务,可以提供协作设计的功能。当我们开始着手做Figma的时候,我们明白这是一个挑战。要完成这个挑战,我们需要提供一种接近原始的编辑体验,只有这样,设计师们才会接受这个工具,并在任何地方使用它进行工作。

完成这个真的很难。最后我们基本是是在浏览器内部构建了一个新的浏览器。

之所以难,是因为Web并没有被设计为一个通用的计算平台。它主要为处理文档而生,它上面绑了一整套用于开发应用的东西。这些东西通常为特定的场景,使用特定的API,而没有提供一种通用的,可以用来实现各种东西的接口。比如:

  • css有很多花哨的文本布局算法,但是不能自定义布局算法,并且也不能分析文本的布局过程,所以文本的布局算法也不能被用在其他算法之中。
  • 所有浏览器都提供了高性能的gpu合成器,但是在Web平台上,没有任何方式能接触到渲染算法,所以就不能改变合成器的工作方式来添加性能分析、或者自定义混合模式的功能。
  • 浏览器内嵌了高度优化的图片解析器,这个解析器可以在UI线程之外工作,并用上最新的硬件特性。但是没有API可以传参数到这些解析器里来实现例如“处理EXIF方向”,或“在使用drawImage和getImageData这种方法时避免触碰到显示颜色的空间“这种功能。

Web平台通用底层接口的缺失的问题现在开始改变了,因为WebGL和asm.js这种技术可以让开发者绕过浏览器,直接与硬件对话。技术进步最终使基于Web平台的高性能图形应用成为可能。开发者不需要等待web平台添加他们需要的额外的特性,他们可以自己构建这些特性!

Emscripten

我们的编辑器是用C++写的,然后用emscripten这个跨平台编译器编译成了JavaScript。emscripten编译出一种叫asm.js的javascript子集,它提供了一种让Javascript JITs生产可预测的,经过压缩的机器代码的方式,并且它已经被所有现代浏览器广泛支持了。它有以下的优点:

  • 我们完全自己控制内存布局,并且可以用小的32位浮点数,有时甚至是字节,而不是js的64位双精度浮点数。这对像我们这种需要使用巨量数据的app来说至关重要。
  • 构建出来的代码完全控制内存分配,这可以避免GC导致的卡顿,来使应用更容易达到60帧。所有的C++对象都在一个预先分配的保留范围内,所以Js的GC永远不会介入。
  • 生成的代码通过LLVM先进的优化器预先优化过。这和专门的C++模板结合起来,生成了高效率的代码,比原生的性能高了2倍或更多 。
  • 所有的asm.js代码都不需要再次优化,所以JITs可以预先编译它,并提供可预测的性能。而常规的Js代码依靠JIT进行优化,所以同一段代码的性能表现在之后可能差别很大。

这不是说emscripten是完美的。跟任何的新技术一样,前进的道路是磕磕碰碰的。问我们来说一个大问题是,有些浏览器设置不能为emscription分配大量的连续内存地址。最糟糕的例子是Windows上的32位Chrome,在它上面,有时我们甚至不能分配一个256M的TypedArray,因为ASLR把内存地址分段了。这个问题现在已经解决了。

还有一个妙招有帮助,就是使用堆外的,大资源比如图片或者buffer碎片的引用。我们有一个叫做IndirectBuffer的内部API来代表一个外部的TypedArray,并让它在C++内可用。把大的内存分配移到主堆之外减少了长时间会话中的内存碎片化情况,并在有限制的32位浏览器中允许我们使用更多 的内存,并允许我们突破64位浏览器的31位TypedAray尺寸限制。

现在对asm.js的支持已经很好了,但还有一些更令人激动的改变正在到来。WebAssembly是一实现asm.js二进制形式的一种成果,这可以大法减少asm.js代码的解析时间,并且所有浏览器都准备实现它。目前使用多线成的唯一形式是使用web worker,并通过post message来传递消息,但正在到来的可共享TypedArray标准将使多线程之间共享内存变为现实。

渲染

我们实现了自己的渲染引擎,来确保内容被快速渲染,并在多个平台之间保持一致性。浏览器有令人惊叹的图形实现,我们一开始并没打算自己做一个渲染引擎。没有了底层的可以获取到浏览器Render Tree的API,可选的就只有HTML、SVG或者2D Canvas了。但是因为以下原因,他们都不能满足我们的需求:

  • HTML和SVG有很多包袱,由于要获取DOM的原因,通常比2d Canvas慢很多。这通常是为滚动而不是缩放进行的优化,几何图形在每次缩放改变的时候通常要重画。
  • Gpu加速没有任何保障,并且很多东西依然是在CPU上渲染的,这在特定情景下非常慢。
  • 在HTML和SVG上,对遮罩、模糊和混合模式的支持在不同浏览器之间差异非常大,并且通常不抗锯齿或者在高DPI显示器上分辨率太低。
  • 2D canvas API是一种立即模式的API而不是保留模式的API,所以每一帧都要将所有集合形状重新上传到显卡。这是一种没有必要的浪费,并且是潜在的性能瓶颈。
  • 在不同浏览器上的文本布局不一致,甚至在不同平台上的同一个浏览器也可能不一致。
  • 我们想添加例如“angular gradients"这样不被任何渲染API支持的特性。

与其尝试让其中一种变的可用,我们用WebGl从头实现了所有东西。我们的渲染器是一个高度优化的Tile-based架构的引擎,它支持遮罩,模糊,抖动角度,混合模式,嵌套层透明等等特性。所有的渲染都是在GPU上完成的,并且完全抗锯齿。深入代码,特别像是一个浏览器内部的浏览器。我们有自己的DOM,自己的合成器,自己的文本布局引擎,我们正在考虑添加一个像浏览器用来渲染HTML用的渲染树。

浏览器

Web平台的能力仍然在追赶原生平台,不幸的是还有几个缺口在那。虽然我们没有填补那些巨大缺口的资源,但是我还在它仍然有意义的时候填补了我能填的东西。

在我去Figma工作之前,高DPI的自定义鼠标在web平台是完全坏的。我得一个个修复Chrome,Firefox和WebKit因为他们坏的方式还不一样。到目前位置还没有一种统一的方式来解决这个问题,但是至少现在有可能了。

我也修复了几个很糟的性能和可用性bug来让我们的产品变的更好。Web平台有时让人感到受挫,但浏览器不是一个黑盒,通常要修复一些Web上恼人问题的代价只是花费一个下午在调试浏览器的代码上,一天来聚焦某个补丁,或者几个月来等待新的版本。

依然有一些Web平台上能做的事情来让Figma变的更好:

  • 我们最大的痛点在于接触不到字形轮廓和“kerning tables",到目前位置没有任何方法能解决。我们的主要关注点之一在于指纹,战士这场战斗已经输了。我们希望能获取到字体数据,在用户同意类似我们协议的时候,类似隐私条款API。Chrome目前正有一项正在推进的提案来解决这个问题,但是其他浏览器什么时候能解决确忘不到头。
  • 我们想添加公共的剪切板格式,比如.ai,.pdf等,但是Web平台根本做不到。唯一的剪切格式只是text/plain或者text/html。我们的Figma剪切格式是拥有二进制数据注释的text/html格式。
  • 对我们来说的另一个问题是缺乏对触控板手势的支持。Chrome添加了一个少有人知的花招,触控板能发送wheel event伴随ctrl键按下,并且调用preventDefault来允许页面处理它。这使Figma的缩放给人原生的体验。我尝试将它添加到FireFox上,但是被卡住了 。在Safari上的触控导致缩放行为会让用户感觉很困惑,但有没办法阻止。

你可能感兴趣的:(前端,html5,javascript,chrome,webkit)