Tuesday 22 January 2008
Subpixel Layout And Rendering
John Resig has discovered that Gecko does subpixel layout and rounds coordinates to device pixels for rendering.
He's right that in some sense, when you have to render a CSS layout to a screen with discrete pixels, all the options are imperfect and browsers are choosing different imperfect options. However I think we need to explain the big picture a little better.
Gecko intentionally supports subpixel layout because for high resolution output devices, especially printers but also high-DPI screens that will become more common, one CSS "px" should be mapped to many device pixels, so you can in fact do sub-CSS-pixel rendering. For those devices, rounding layout units to CSS pixels is actually throwing away information and giving you a strictly worse layout than Gecko will give. For example, try printing John's example in FF3 beta. You should see that in the printout (or generated PDF), no rounding has occurred and each child DIV looks identical.
Because we think this is important and we don't want layout to vary unnecessarily across devices, we do subpixel layout on all devices. When we have to draw to a regular-DPI screen, we then have to round the edges of drawn objects to the nearest screen pixel. This explains the results John sees. Note that our approach of rounding at drawing time is optimal for avoiding gross layout changes due to rounding; it limits the impact of rounding to moving object edges by one pixel in some direction. It avoids gross layout changes like IE moving a DIV to the next line, or Safari leaving a 2px strip vacant at the end of the line. Thus I believe our approach is better than the alternatives in important ways.
The preceding paragraph is actually a slight oversimplification. We do have to do some rounding during layout simply due to the fact that computer arithmetic has limited precision. So during layout we round measurements to the nearest 1/60th of a CSS pixel. This number was chosen so that common fractions of a CSS pixel can be represented exactly --- for gory details, check out the great "units" bug and my comments about its landing. Note that rounding to 1/60th of a CSS pixel is far more benign than rounding to CSS pixels; 1/60th of a CSS pixel is approximately 1/5760th of an inch, not something most people are going to worry about!
In practice, we have seen very few Web compatibility issues caused by this scheme. Web authors should just not worry about the rounding we do, and should not attempt to round coordinates themselves. The new getBoundingClientRect and getClientRects APIs in FF3 can return fractional coordinates, just go with the flow. Feel free to position elements at those fractional boundaries, they will line up visually. If you insist on consistent rendering down to the pixel, then the only way to go is to specify px values for everything, including line-heights, and avoid percentage units. Or better still, use SVG. Or a PNG.
Comments
http://antigrain.com/research/font_rasterization/index.html
Whereas with fonts, it's acceptable to have a little blur - but with CSS box borders it's not acceptable.
Before I go track down a regression range, any idea if that's filed already?
Jon: actually that reminds me --- we do use horizontal subpixel offsets for text rendering on Mac and GTK. We have to round vertical offsets for tricky reasons to do with underlines. And yes, in theory we could have subpixel rendering of everything, but it wouldn't look good since we don't want fringing on horizontal or vertical object edges and there are hardly any other kinds of edges in most Web content.
Sometimes people will complain about fringing when the real problem is that they don't have an RGB panel, it may be BGR or vertically oriented. Use the display control widget to set the correct pixel orientation for your monitor. If this is set wrong fringing will be visible.
Look at the bottom of this page and you can see microscope photos of subpixel rendering.
http://en.wikipedia.org/wiki/Subpixel_rendering
Click on the photos and they get bigger.
Note that the OPLC uses PenTile.
Screen of the first problem
http://phoenix.nox.googlepages.com/Fx3B2008012104Columns.png