|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "My 2020 browser retrospective (and 2021 prospective)" |
| 4 | +categories: posts |
| 5 | +description: "A quick retrospective on the browser-related things I worked on in 2020, and what I have planned for 2021." |
| 6 | +--- |
| 7 | + |
| 8 | +{: .no_toc} |
| 9 | +#### Table of contents |
| 10 | +1. TOC |
| 11 | +{:toc} |
| 12 | + |
| 13 | +<hr style="margin-bottom: 15px;" /> |
| 14 | + |
| 15 | +I spent much of 2020 working on web browsers (mainly [Kosmonaut](https://github.com/twilco/kosmonaut) and WebKit). Here's a little write-up about how that was, and what I have planned for |
| 16 | +the future. |
| 17 | + |
| 18 | +### Kosmonaut in 2020 |
| 19 | + |
| 20 | +One year ago today, I was finishing the first implementation of [block layout](https://github.com/twilco/kosmonaut/commit/f3041f0b7e986b7a0be26b34870489cfaeb3e830) and [display-list generation](https://github.com/twilco/kosmonaut/commit/fedf68029e4ad9ea8bf4b96611b8738a347402f2). In terms of LoC, Kosmonaut hasn't grown much — from 7.5k LoC then to |
| 21 | +20k now. However, there are some pretty neat improvements wrapped up in that 12.5k LoC increase: |
| 22 | + |
| 23 | +* Layout-tree dump{% fn %} snapshot based testing |
| 24 | +* Partial support{% fn %} for [abstract box layout](https://drafts.csswg.org/css-writing-modes-4/#abstract-layout) with the `writing-mode` and `direction` properties |
| 25 | +* Support for arbitrary scale factors, e.g. for HiDPI screens |
| 26 | +* OpenGL-based box painting and text rendering (though text rendering is not yet hooked into layout) |
| 27 | + |
| 28 | +Three months ago, I ventured out to rewrite Kosmonaut's layout engine, as I had made a mess of it in my first pass at |
| 29 | +implementing abstract box layout. The result is [this PR](https://github.com/twilco/kosmonaut/pull/14), merged today, |
| 30 | +that ended up being a rewrite of...a lot of things. Some highlights from that PR include: |
| 31 | + |
| 32 | +* Proper representation of many spec-level concepts, such as [text runs](https://drafts.csswg.org/css-display/#text-run), [formatting contexts](https://drafts.csswg.org/css-display/#formatting-context), various types of boxes, and more. |
| 33 | +* Much cleaner layout tree dump output. [Before](https://github.com/twilco/kosmonaut/blob/a6b7138b2c95714af8ce3a446e2f4b40b2d67950/tests/layout/snapshots/lib__layout__tests__rainbow_divs_baseline.snap) vs. [after](https://github.com/twilco/kosmonaut/blob/82cf7ef53e67e0c33ea8812e486fe8d867a82da9/tests/layout/snapshots/lib__layout__tests__rainbow_divs_baseline.snap) |
| 34 | +* A _much_ cleaner HiDPI scaling implementation. The TLDR of this is that scaling used to be done in layout, which required passing a `scale_factor` everywhere and applying it in exactly the right places. The [new implementation](https://github.com/twilco/kosmonaut/commit/15f76d68617bf3e846b8405d000b1b9e17dafd72) scales the viewport size down before layout and scales everything else up just before painting, making things far more simple and less prone to bugs. |
| 35 | + |
| 36 | +There's a fair amount of cleanup I'd like to do following the landing of this PR, but it's a big step forward and |
| 37 | +I'm really happy with how it turned out. |
| 38 | + |
| 39 | +One of the reasons this took so long is because I spent quite a long time trying out various designs and subsequently |
| 40 | +throwing them out. One thing I really wanted to do with this PR was to enforce certain spec-level constraints with |
| 41 | +the type system. To give a concrete example, [take this snippet from the CSS Display spec](https://drafts.csswg.org/css-display/#block-container) regarding block containers: |
| 42 | + |
| 43 | +> A block container either contains only inline-level boxes participating in an inline formatting context, or contains only block-level boxes participating in a block formatting context. |
| 44 | +
|
| 45 | +I had experimented with a design that looked like this: |
| 46 | + |
| 47 | +{% highlight rust %} |
| 48 | +pub struct BlockContainer {} |
| 49 | +pub struct BlockLevelBlockContainer { |
| 50 | + children: Vec<BlockLevelBox> |
| 51 | +} |
| 52 | +pub struct InlineLevelBlockContainer { |
| 53 | + children: Vec<InlineLevelBox> |
| 54 | +} |
| 55 | + |
| 56 | +impl BlockContainer { |
| 57 | + pub fn new(...) -> BlockContainer {} |
| 58 | + |
| 59 | + pub fn add_block_level_child( |
| 60 | + blb: BlockLevelBox |
| 61 | + ) -> BlockLevelBlockContainer {} |
| 62 | + |
| 63 | + pub fn add_inline_level_child( |
| 64 | + ilb: InlineLevelBox |
| 65 | + ) -> InlineLevelBlockContainer {} |
| 66 | +} |
| 67 | +{% endhighlight %} |
| 68 | + |
| 69 | +The idea is that you could only get a `BlockLevelBlockContainer` or `InlineLevelBlockContainer` by calling one of |
| 70 | +these `add_{block, inline}_level_child` methods (i.e. neither of these structs have `new` methods), ensuring at compile-time |
| 71 | +that the quoted spec invariant is upheld. |
| 72 | + |
| 73 | +However, this proved to to be awkward for a number of reasons, and I scrapped the idea in favor of a less restrictive API |
| 74 | +that technically allows these rules to be broken. I would like to revisit this someday, as allowing users to encode |
| 75 | +rules via the type system (and making it ergonomic to do so) is something Rust is good at. |
| 76 | + |
| 77 | +### WebKit in 2020 |
| 78 | + |
| 79 | +Kosmonaut was not the only browser I worked on in 2020 — this year also saw the beginning of my contributions to WebKit. |
| 80 | +I landed [13 patches](https://github.com/WebKit/WebKit/search?q=author%3Atwilco&type=commits), and worked on quite a few |
| 81 | +others I didn't push across the finish line. Here are some highlights: |
| 82 | + |
| 83 | +* Various bug fixes and improvements to WebKit's CSS variables implementation. I have a blog post in the works describing these in more detail, so stay tuned. |
| 84 | +* Fixed a bug that caused `::selection` pseudoelement styles to not be applied to elements with direct anonymous parents, such as text nodes. [[commit]](9d06f52c2c04b24605af1bb19eed43ad03a6d9c4) |
| 85 | +* Per spec, ignore order when parsing `<inset>` and `<color>` values for the `box-shadow` property. [[commit]](https://github.com/WebKit/WebKit/commit/b1876da3f1ce3bed2a8c779e5716927ce9d85438) |
| 86 | + |
| 87 | +In the second half of the year I really felt like I was getting into a groove in working on WebKit, so I'm excited to get |
| 88 | +back to it. |
| 89 | + |
| 90 | +### My plans for 2021 |
| 91 | + |
| 92 | +2021 has arrived! Here are some things I'd like to complete in Kosmonaut soon: |
| 93 | + |
| 94 | +* Parse and expand the most common CSS shorthands — `margin`, `border`, `padding`, etc. Kosmonaut currently only understands longhands, which is quickly becoming inconvenient. |
| 95 | +* Add the ability to load styles from `<link href="...">` and `<style></style>` tags. Currently, loading HTML and CSS in Kosmonaut requires passing all files individually via the `—files` flag, which is inconvenient (are you noticing a trend?). |
| 96 | +* [Handle `display: none` boxes](https://github.com/twilco/kosmonaut/blob/82cf7ef53e67e0c33ea8812e486fe8d867a82da9/src/layout/flow/block.rs#L358) |
| 97 | +* Further improve support for abstract box layout. Concretely, this means making `writing-mode: {sideways-lr, sideways-rl, vertical-rl}` and permutations with `direction: {ltr, rtl}` work. I don't think this will be all that hard. Calculation of [block start coordinates](https://github.com/twilco/kosmonaut/blob/82cf7ef53e67e0c33ea8812e486fe8d867a82da9/src/layout/flow/block.rs#L528) and [inline start coordinates](https://github.com/twilco/kosmonaut/blob/82cf7ef53e67e0c33ea8812e486fe8d867a82da9/src/layout/flow/block.rs#L533) will have to change, and maybe a few other things. |
| 98 | +* A basic implementation of [inline layout](https://drafts.csswg.org/css-inline-3/), followed by some polish of Kosmonaut's existing OpenGL text rendering. |
| 99 | + |
| 100 | +After this list, I'm not really sure what will come next for Kosmonaut. I think it would be a fun minigame to start tackling the [Acid2 test](https://en.wikipedia.org/wiki/Acid2) and/or [some web platform tests](https://github.com/web-platform-tests/wpt). |
| 101 | + |
| 102 | +I've taken a break from WebKit recently to push Kosmonaut's layout rewrite across the finish line, but want to get back to it soon. I have been pondering about an experiment I'd like to try regarding my work in WebKit, so stay tuned for information on that — I'll be posting about it here. |
| 103 | + |
| 104 | +--- |
| 105 | + |
| 106 | +{% footnotes %} |
| 107 | + {% fnbody %} |
| 108 | +<a href="https://github.com/twilco/kosmonaut/blob/82cf7ef53e67e0c33ea8812e486fe8d867a82da9/tests/layout/directional/snapshots/lib__layout__directional__ltr_vertical_lr_block_boxes_top_left_right_mbp_applied_physically.snap">Here's what a layout dump looks like. </a> |
| 109 | + {% endfnbody %} |
| 110 | + {% fnbody %} |
| 111 | +The specifics of what "partial support" means are documented <a href="https://github.com/twilco/kosmonaut/blob/e50b640e467a630776a3a3c910839176da98f868/README.md#f1">here</a>. |
| 112 | + {% endfnbody %} |
| 113 | +{% endfootnotes %} |
| 114 | + |
0 commit comments