atom-archive / xray

An experimental next-generation Electron-based text editor
MIT License
8.48k stars 236 forks source link

Strategy for rendering glyphs via WebGL #6

Closed MaxGraey closed 6 years ago

MaxGraey commented 6 years ago

Hi everyone. I very glad to see project like that and Xi. And I very interesting which strategy you choose for hi-quality rendering of glyphs.

There many solutions for that. Which is the most preferable for your goals?

1. Rendering via precomputed multichannel signed distance fields. I Think this is fastest approach

msdf

With LCD subpixel antialiased shader.

2. Rendering via analytic arc approximation sdf like glyphy

3. Vector textures. Paper

4. Loop-Blinn curve-filling technique (Patented). Or variation of this technique without AA via partial derivations like in pathfinder's approach

5. Something new?

nathansobo commented 6 years ago

Hi @MaxGraey, thanks for your interest. We're not doing anything as fancy as the techniques you mention. We're currently rasterizing glyphs via HTML 5 canvas to populate a texture atlas, which we map to simple quads in the editor. Since we aren't rendering a 3d environment, we only need the fonts at a single size, or potentially a handful of sizes if we eventually allow varying font sizes for headings or something. Xi takes the same approach, with the original inspiration being the Alacritty terminal emulator.

We rasterize up to 4 different variants of each glyph, each at a 1/4 subpixel position. In our tests, this is sufficient to make our text indistinguishable from the normal CPU-based rendering for monospaced fonts. For variable-width fonts, we suffer from our lack of kerning, but since we're a code editor we're not going to worry about that.

We're currently not doing any text shaping, so scripts that require complex text layout such as Brahmic and Arabic don't work yet. We tried running everything through HarfBuzz, but the performance overhead was prohibitive. For Arabic, we should be able to use the technique described here, but we've decided to defer support since we'd also need to determine cursor positions in the transformed text. To support Brahmic scripts, we may need to resort to rendering entire strings via the canvas and also use HTML for shaping. In the Electron use case, we could also use platform-specific text shaping APIs if they outperform Harfbuzz, but we want to start with approaches that will work on the web. Again, we're focused on being a code editor, so we're imagining most instances of non-Latin text to be inside of comments or strings. Performance for the most common cases while editing code is our priority.

Anyway, hope this clarified things! Thanks again for your interest.

MaxGraey commented 6 years ago

Thanks for explanation. Very informative! But I have several questions

We rasterize up to 4 different variants of each glyph, each at a 1/4 subpixel position

But with SDF you can do without this and store just one and you can scale it for any font size without memory overhead. This technique use many games and frameworks (Qt and libgdx for example). With SDF you can easily and cheap do shadowing and outlining, morphing and many other great manipulations.

By the way. Some people prefer scale web view's viewport.

HarfBuzz can't manage bidirectional texts. Do you have plans to integrate FriBidi?

nathansobo commented 6 years ago

My main concern with SDF is fidelity of the rendered glyphs. By using canvas we can ensure glyphs are rendered exactly as the user expects on every platform, which is extremely important for a text editor. Memory footprint seems very manageable so far.

We do have plans to support bidi text, though the specific library we’ll use remains an open question.

MaxGraey commented 6 years ago

Ok, thanks for the clarification!