Surfin' Safari

Scenes from an Acid Test

Posted by Maciej Stachowiak on Thursday, March 27th, 2008 at 11:44 pm

In our earlier Acid3 post, I mentioned that the final test we passed, test 79, was super tough. This test covered many details of SVG text layout and font support. To pass it, we had to fix many bugs. Unless you are a hardocore standards geek you may not find all these details exciting, but since we talked a bit about our other recent fixes, I thought I’d tell the story. This subtest was originally contributed by Cameron McCormack.

Bug 1: DOM Support for the altGlyph element

I started on test 79 as a weekend hacking lark. While I have hacked a little on the SVG code, it wasn’t my top area of expertise, and I hadn’t looked at the text layout code at all, so I figured it would be an interesting learning experience. Little did I know that we’d end up racing to fix it.

The first failure we saw on test 79 was that getNumberOfCharacters on an SVG <text> element gave an answer that was off by one. The test hinted that this could be due to improper handling of UTF-16 (something covered in the SVG 1.1 Errata). However, on further study, I realized that our UTF-16 handling was right, but the <text> element contained an <altGlyph> element which we did not recognize, and therefore, according to SVG rules, did not render. For those who are new to text layout, a “glyph” refers to a particular symbol that will be drawn on the screen – most often every character has its own glyph, but it can get more complicated than that.

So, as a first step, in r31240 I made <altGlyph> fully recognized by the engine and allowed it to render initially as a <tspan> element. That’s sort of SVG’s equivalent of an HTML <span>, it just renders its text contents.

After landing the fix, I saw that the code testing character positions got a bad position for character 2.

Interlude: Modified Test Case

At this point, I realized that we’d probably get a lot of bad positions, and it would help to see all the problems at one go, instead of one at a time. Acid3 only reports the first failure on any given test. So I saved off a local copy, hacked it to report every failure on test 79, and changed it to test the spaces between characters instead of the character positions. Any error in measuring one character would propagate to all subsequent characters, so it was more useful to look at the differences in positions (“advances” in typography lingo). This immediately made it obvious that by far the most common failure was failure to support multi-character glyphs in SVG Fonts correctly.

Bug 2: Multi-character Glyphs

SVG has a feature to allow specification of glyphs that match more than one character. You can use this to do things like create ligatures. For example, it is common for proportional fonts to include a special glyph for the combination “fi”, since those letters can look nicer if drawn together in a special way.

We had the basics of code to support this. However, the problem was that our code only measured one character at a time. There was no way for the font code to decide to pick a glyph for more than one character because it only saw one at a time, and there was no way for it to report back how many characters a glyph matched. So even though the drawing code sort of got this right, the metrics were based on one-character glyphs. In r31310 I fixed this.

Interlude: Studying the Test Case

After this fix, I studied the test case to classify the remaining failures. I realized there was probably more than one bug, and if I documented them other people could help, or just continue the bug for me if I did not have time.

I found four separate remaining bugs: incorrect priority of SVG glyph matching (it picked the longest match instead of the first), failure to consider the xml:lang attribute in glyph matching, failure to support explicit kerning pairs, and failure to render the actual alternate glyph selected by altGlyph.

Bugs 3 & 4: Glyph Selection

After studying the SVG spec for text, I realized that the data structure we were using for glyph selection was not right. SVG fonts require you to pick the first glyph that matches, in the order in which they are specified, with a number of different rules in addition to text (you have to consider language and the multiple forms of Arabic characters for instance). We just had a hashtable of glyphs, and looked for a candidate by checking possible character runs from longest to shortest. That matched in the wrong priority, and did not properly handle lang at all.

I decided to change the GlyphMap to an n-ary trie (or “prefix tree”), with a vector of possible glyphs at each node, and a hashtable for child nodes. I also stored a “priority” value based on the position of the glyph in the tree. To do lookup, I would walk the trie one character at a time based on available characters, collecting all the glyphs found at each level. Next, the glyphs are sorted by priority. Finally, this vector of candidate glyphs is scanned to find the first that matches the additional constraints such as Arabic form.

Opera Brings its “A” Game

Making a fancy new data structure was a fair bit more complicated than my last two fixes, so I was hacking on this for a couple of days. On Wednesday morning, I heard that Opera was going to announce an Acid3 score of 98/100. The WebKit developers who had been noodling on Acid3 realized that we had fixes in progress for most of the remaining issues, and could likely pass the test by the end of the day, and get it out there.

At this point, I would like to commend the Opera developers for their achievement. At the time they posted the 100/100 screenshot, we had no idea there was a bug in test 79, and hoped at best to be the first to release a 100/100 public build, and both our teams could get some credit and positive exposure. It was not until we were fixing the very last bug in our code that we spotted the bug in the test, as you’ll see below.

Anyway, once we realized it was game on and Opera was much further ahead than we expected, we decided to complete our fixes. Eric fixed handling of charset encoding errors in XML, Antti got two SMIL test fixes in, and I cleaned this patch up, made a regression test, and landed it in r31324 and r31325. (We have a policy that every fix has to come with an automated regression test, no matter how much we’d like to rush – this is so we can move faster in the long run, by having a comprehensive regression test suite that will catch mistakes. Even with all that I had a bit of a commit oops but the team caught it right away, thus the two revisions.)

Bug 5: altGlyph Rendering

At this point, I had a problem. Niko, who had originally written the SVG font and text code, was busy with school, and I’d just learned all about the SVG text system by fixing these bugs, so I was the top expert and sort of on the hook. But there were two bugs left on these test, and neither was trivial to fix. I decided to split the remaining work with rendering master Dave Hyatt. I asked him to take on the altGlyph fix while I took care of kerning.

It turned out there were actually two different problems here. The altGlyph lookup was by ID, but somehow the glyph element wasn’t getting into the id map. With help from Darin and others on the team, Hyatt managed to figure out that we were handling the “id” attribute improperly for the SVG <glyph> element.

The second problem was actually choosing the alternate glyph and using it for metrics and rendering. This turned out to be simpler than it might seem, as it could be handled almost entirely in the SVG font machinery.

You can see the gory details of Hyatt’s fix in r31338. I helped him out with the test case for this, and for a while he thought his code was broken because I sent him a test that showed red boxes when it passes. Kids, never do this in your browser tests. Green for pass, red for fail.

Bug 6: Kerning

The final bug was support for kerning. It was pretty easy to add support to the SVG DOM for the <hkern> element, and to build up a vector of kerning pairs. What was tricky was storing enough info to decide when a kerning pair applied, and the match algorithm to help determine applicability. Kerning pairs can be specified in two ways in the SVG spec, by Unicode value or glyph name.

Darin was looking over my shoulder as I was reading the spec, because I hoped for his help on part of this, the matching algorithm. It was at this point we realized the test had a bug. It had an <hkern> element with a u1 attribute of “EE”, and expected that kerning to apply. But that’s neither a comma-separated sequence of characters nor a Unicode range, which is the syntax the SVG 1.1 spec for <hkern> elements requires. This meant that you couldn’t possibly pass this test without violating the SVG spec. I let Acid3 editor Ian Hickson know right away, and confirmed the error with Cameron, the original author of test 79. While they mulled over how to fix the test (Ian has been very responsive to fixing the few errors that crept into this very complex test), Darin and I continued to work on the final bug.

At last, we managed to pass around the glyph info and apply the matching correctly. We decided to handle the full complexity of the SVG spec for this, even though we could have cut corners just to pass the test, since it didn’t test every possible form of kerning pair. In the meantime, Ian had fixed the bug in the test and blogged about it. At last I saw the 100/100 on my screen for the first time. Everyone egged me on to commit but I insisted on getting the patch reviewed and creating a regression test, cause on WebKit that is how we roll. Finally with r31342 we had a score of 100/100, available to the public. And the rest is history.

By Way of Contrast

As you can see, this test was pretty rigorous, and we did a lot of hard work to make it pass. We fixed a lot of bugs, ranging from basic to obscure and easy to advanced. We didn’t have code just lying around that got us most of the way there.

Not all of the tests on Acid3 were equally stringent. Tests 75 and 76 are SVG Animation tests, contributed by Erik Dahlström. We had the beginnings of an implementation of this feature, but it was fairly incomplete and we had it disabled with ifdefs, and had chosen not to ship it in past releases. We believe in incremental development of new features, so we were prepared to turn it on and fix the bugs needed to pass the tests. We thought this would take a lot of extra work. To our surprise, it turned out that the first few of the changes we made on top of the old code were enough to pass the two SVG animation tests.

Antti checked these fixes in, but we don’t think our pre-existing incomplete implementation is truly satisfactory, and it probably wouldn’t be a good idea to ship it as-is in a major public release. We’re not yet satisfied with this code, but it’s a good step forward for our open development trunk.

Thanks

In the end, the main thing that surprised me about Acid3 was how fun it was. Back when Acid2 was all the rage, Hyatt did pretty much all the fixes himself, so the rest of us didn’t have a chance to get into the spirit as much. But Acid3, and the slightly silly competitive atmosphere around it makes Web standards fun.

Web standards can often seem boring compared to super fast performace, whizzy new features, and even the basic Web compatibility work of making sites work properly. Interoperability is critical to the Web as an open platform, but it can be difficult to explain to regular users why it’s so important. The Acid tests make web standards fun, for browser developers, for Web designers, and for regular users. Whatever the intrinsic value of the tests may be, I think we should all thank Ian Hickson and all the test contributors.

I’d also like to thank Opera for giving us some serious competition and making this a real horse race. We have huge respect for their developers and all the work they do on Web standards.

29 Responses to “Scenes from an Acid Test”

  1. andrew.hedges Says:

    Regardless of the sour grapes from the Mozilla team (link below), I think it’s great that you WebKit guys have pursued this goal with such zeal. I’m sure it’s beyond even what the Acid3 test designers hoped for that both WebKit and Opera got through the test so fast. Awesome work!

    http://blog.mozilla.com/rob-sayre/2008/03/26/acid3-is-basically-worthless/

  2. Karl Says:

    The way I look at it is this: Safari will be better browser for all the bug fixes made to score 100/100 than it would if these fixes weren’t made. One can debate the worth of Acid3, but I think the above statement is solid.

  3. The_Decryptor Says:

    I’ve wanted SMIL support in more user agents for a while, if the Acid3 test causes the browsers I use every day (Safari and Firefox) to get SMIL support, then the test is worth it for me.

  4. ahruman Says:

    “For example, it is common for proportional fonts to include a special glyph for the combination “fi”, since those letters can look nicer if drawn together in a special way.”

    Yes… now if only WebKit could manage this for HTML.

  5. Fyrd Says:

    Great story, thanks for sharing with us!

  6. dak Says:

    Congratulations to both the WebKit and Opera teams, and a big thanks to Ian and everyone who contributed to the Acid3 test. The past week has been quite exciting watching the race unfold. Most importantly, at the end of the day the real winner is web standards. I hope unimplemented standards on every browser are approached with the same zeal we’ve seen from WebKit and Opera these past few weeks.

  7. tconrad Says:

    Thanks for the detailed write up. Really inspiring — this is what the “browser wars” should be about. Congrats to both the Opera and WebKit teams.

  8. eAi Says:

    Well done. Roll on Acid4, hopefully with some CSS3 tests :)

  9. dstorey Says:

    Thanks for the kind words on Opera. Our little Geek Olympics sprint race has been fun. While the rendering and DOM bugs are of more interest to me, it’ll be great to see which of us passes the performance test first and releases a official release first. I was expecting it to be more of a marathon than a sprint when the test was first released.

    Good luck on the further work on SVG animation. As someone that works on CSS3 a lot, one great thing about the test was that it made WebKit add the nth* selectors, which I really missed in Safari and Firefox, and made Opera add HSLA and RGBA.

    I look forward to ACID 4, and hope SVG as a background-image and much of the Background and borders CSS3 module get into that test, providing the spec becomes mature enough.

  10. Nicholas Shanks Says:

    @dstorey: I too have been waiting a long time for the nth-* selectors. I would have been happy with just ‘odd’ and ‘even’ support for the forward-parsing ones (i.e. not nth-last-*) so I could zebra stripe my tables without classes. I am very grateful that the whole CSS3 selectors module is now implemented!

    I would like to see Acid4 wait a while (at least until IE has caught up) so that we can have a more meaningful race, and so the Opera and WebKit teams can get their breath back and work on more important, but less fun stuff. When it comes, the only CSS3 module I think is ready for inclusion at the moment, beyond what has already been tested, is Media Queries. I think Acid tests 1-3 tested enough CSS for the time being. I think Acid4 should concentrate on error recovery as defined in HTML5, object fallback and general dealing with the real web. Bread and butter interoperability, and not obscure spec edge cases or even SVG/SMIL, are the most important things we should be testing.

  11. IOOI Says:

    Really nice work, Congratulations! But that was just a sprint like dstorey says. The real challenge is here when it comes to SVG:

    http://www.w3.org/Graphics/SVG/Test/

    especially the “full” test suite has a lot of stuff that doesn’t work yet:

    http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-index.html

    I personally miss the incomplete tref/xlink support most like visible in this example:

    http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-tref-01-b.html

    But now I need to counter the first “but”: You doing really, really great work with webkit! I am really happy that SVG support is already that far, soon I’ll be able to use it for real.

  12. jah Says:

    While you guys should be commended for your work on Acid3, one worries that all this hacking comes at the expense of leaving security holes open (http://security.itworld.com/5013/mac-hacked-first-in-contest-080327/page_1.html)

    Now I don’t know if that was a Safari or Webkit exploit, but I want to Webkit to be the most secure renderer as well as the most standards compliant.

    Cheers

  13. Maciej Stachowiak Says:

    @IOOI

    We have the SVG 1.1 test suite as part of our regression tests, and while we do not pass all cases, we are actively striving to improve. In fact, our Acid3 work has already made quite a few more of the text test cases pass.

    @jah

    We tend to be pretty good at turning around security fixes. It’s not an either-or.

  14. jah Says:

    @Maciej Stachowiak

    That’s great to hear. It would be cool if you guys maybe did a blog post regarding your attitude/opinions to security issues, and how you go about trying to stop exploits in the first place, rather than having to patch them up after the fact. Cheers

  15. timofonic Says:

    The Rob Sayre’s blog Did put at the end of the blog entry “P.P.S. — Shameful!” with the following link:

    http://trac.webkit.org/projects/webkit/changeset/31322

    What about that? It looks like the Mozilla guy considered it an evil workaround and considered it cheating. But well, I’m sure Opera maybe it can have more “cheating” considering it’s Closed Source.

    So this is avoided generally? What’s the policy about the use of workarounds on the WebKit engine?

  16. Brad Says:

    I get 94 now (big pause at 66). Error console has this:

    Resource interpreted as stylesheet but transferred with MIME type text/html. http://acid3.acidtests.org/empty.css
    Resource interpreted as document but transferred with MIME type image/png. http://acid3.acidtests.org/empty.png

    By the way, its kind of annoying that the error console clears with every page now, unlike the old JavaScript console.

  17. Dave Hyatt Says:

    @timofonic: See Hixie’s latest blog post. The Ahem antialiasing hack has been backed out of our tree, and the Acid 3 test has been amended to not depend on Ahem glyphs being adjacent to the border of the test.

  18. Dave Hyatt Says:

    @timofonic: It’s also worth noting that the hack in question was not needed to pass the test (since we passed in 3 out of 4 rendering modes on Mac, and in those same three rendering modes plus GDI mode on Windows), so really Robert Sayre was just trying to blow up an unimportant checkin to be sensational. His post is just sour grapes as far as I’m concerned.

  19. timofonic Says:

    @Dave Hyatt: Thanks a lot for making this more clear. I’m more happy with WebKit now and less with Mozilla developers, I don’t respect a developer that uses sensationalism for trying to stain the reputation of “competitors”.

  20. giromide Says:

    Acid3 is not fluff. Performance should be stressed in a browser, even as internet pipes to homes and businesses slowly get fatter. I’m glad to see from posts above that Opera and WebKit are devoted to reliability as well.

    Forgive this question as I am a very big n00b in the realm of real hardcore web programming, but is HTML5 meant to supplant the domination of Adobe Flash? When I walk through the web, looking at the more “immersive” pages out there, I can’t help but think all the standards and built-in browser abilities in the world won’t completely supplant what Flash can do.

  21. dngnta Says:

    I actually think Javascript+SVG could replace a lot of what Flash is being used for today (interactive vector graphics, Flash animations and games. Flash videos can be replaced with the HTML5 video tags, although that’s not as important IMHO). Flash has several shortcomings, the most egregious of them being the fact that there still isn’t a 64-bit version of the Flash plugin, making Flash all but unusable on 64-bit platforms with 64-bit browsers.

    Not to mention that JS+SVG is open while Flash is not. But even the practical reasons are unfavorable for Flash.

  22. Bakuryuuha Says:

    You guys do such an awesome job. Congratulations on your 100/100 victory.

    By the way, I don’t know if this is an issue you guys have come across or not … but running the latest r31436 nightly build, I could only get a 94/100 score for a while … until I realized that I had the Adobe-installed SVG plugin (NPSVG3Carbon found in /Library/Internet Plug-ins/). Once I removed that, I got 100/100. You might want to consider disabling that plug-in automatically if it interferes with Safari/Webkit’s rendering, or at least throw up a user warning that they have it installed and give an option to disable. I’m running on iBook G4 with OS 10.4.11.

    Anyway, keep up the good work. Webkit is just getting better and better!

  23. Brad Says:

    “until I realized that I had the Adobe-installed SVG plugin (NPSVG3Carbon found in /Library/Internet Plug-ins/). Once I removed that, I got 100/100″

    So that’s what it was!!! I get 100 now too!

  24. Sebastian Says:

    I upgraded the relevant bug entry :)

  25. foniksonik Says:

    Great Work Webkit Team! You’ve accomplished more than I’d ever hoped…. I’ll be putting all these new features through their paces soon enough.

    @dngnta && @giromide re: flash

    As a web designer/developer/director I can tell you that Flash will be king of interactive for quite some time. There’s a lot you can and will be able to do with scripting SVG… but it will take a long time to get up to the level that Flash is capable of.

    As an example, I created a demo of an optics system that allows you to modify focus across multiple fields of depth. The demo I created uses papervision 3D library to create a panoramic video surface in 360 degrees, which is layered on top of with a video stream object which is then tesselated and bitmap cached multiple times, as in there is one stream but many copies, which is then masked and blurred dynamically and adjustable using a slider control. The net effect of this is that you can pan around the video stream in 360 degrees and adjust the slider to bring several different fields of depth into focus as the slider moves from left to right, with nearest objects in focus when slider is all the way to the left, farthest in focus when all the way to the right.

    All of this is again accomplished with a single video stream and the ability to clone it’s bitmap data to multiple viewports/instances and apply various masks and effects to the clones rather than the original.

    This would not be easily achievable in OpenGL, much less script + SVG… but in Flash it was more a limitation of imagination rather than technical considerations.

  26. jeffr Says:

    This is really awesome. A very inspirational story that all developer teams should learn from. Did Steve Jobs have any comment about this milestone, by the way?

  27. Black Bloke Says:

    Will SVG images ever be clickable and draggable in Safari/Webkit? I mean in the same way that almost all other images file types are: e.g. JPG, GIF, PNG, etc.

    Or perhaps the ability is there already and I’ve only missed it?

  28. Zach Says:

    Wow! Nice fricken work optimizing Javascript. That’s awesome.

    I’ve got this little canvas demo where you watch circles smash into smaller circles (or the impatient can grab a circle and manually smash it into the other circles). Here’s the default:

    http://tech.no.logi.es/woodshop/momentum6.php

    With the latest Webkit build I can totally crank up the smashing into even smaller bits:

    http://tech.no.logi.es/woodshop/momentum6.php?webkit=1

    Try that link in the new webkit build vs Safari vs Firefox. Pretty apparent difference.

  29. Zach Says:

    Sorry, the above was meant to be a comment on the squirrelfish blog entry… d’oh