← the effing blog

Effing 0.44.0: chrome-plated

We've brought canvas text and layout in line with Chrome, and now check it against references generated from Chrome itself.

Effing 0.44.0 is out, and it’s all about @effing/canvas. The last two releases moved canvas onto @effing/skia and handed text layout to Skia’s paragraph engine, making text render faster and hold still under scale animations, and letting opacity and filters apply to an element as a whole. This one uses that foundation to make what renderReactElement() draws match what Chrome draws for the same markup, usually to within a pixel.

Chrome as the reference

Until now, the canvas comparison tests mostly checked against satori, which is a loose reference for text. 0.44.0 checks against references generated from Chrome instead: each test fixture is laid out in a real Chrome with the same fonts, and canvas has to reproduce the boxes, lines and baselines it ends up with. The references are committed, so the tests themselves don’t need a browser. Where canvas still differs, the test says how, and fails once the difference goes away.

What changes

With Chrome as the yardstick, a lot of small differences surfaced and got fixed. The broad strokes:

  • Line heights match Chrome. A normal line box now includes the font’s line gap, so some text gets a little taller, and explicit line heights place their baselines by Chrome’s rules too.
  • Text keeps its width. Text that can’t wrap no longer shrinks below its widest word, so it stays centered and overflows on both sides, as in a browser, instead of running off to the right.
  • <br /> is a real line break. It used to be laid out as a flex item of its own. It now breaks the line inside the text around it.
  • Shadows parse as CSS does. boxShadow and textShadow take lists, colors in any position and the usual units, and inset shadows and spreads now work. drop-shadow() blurs as CSS defines it.
  • Fonts behave like @font-face. Any weight from 1 to 1000 works, font collections load every face, and a font registered under a system font’s name replaces that family outright.
  • Finer typography. Soft hyphens show a hyphen when a line breaks at them, justified text spreads around CJK characters and no-break spaces, and clamped lines are justified before they’re cut.

Filtered draws, including blurred shadows, are also a lot faster.

Upgrading

Bump your @effing/* packages to 0.44.0. Most renders will look the same or shift by a pixel here and there, but a few changes are worth checking for:

  • Text with line-height: normal can get taller, so findLargestUsableFontSize() may pick a smaller size than before.
  • A row of text items that can’t fit now overflows its container instead of squeezing the text. Give an item minWidth: 0 or overflow: "hidden" to let it shrink.
  • drop-shadow() blurs twice as much as before. Halve the blur length for the old look.
  • Register every font style you use under a system font’s name, since the styles you leave out are now synthesized rather than taken from the system font.

The full per-package changelogs are in the release PR.