Surfin’ Safari

Reporting WebKit Security Bugs

Posted by Sam Weinig on Wednesday, May 7th, 2008 at 6:22 pm

Security is a top priority for the WebKit project. As contributors to the project have grown, it has become apparent that we need a process for safely reporting security vulnerabilities to the WebKit project in addition to the process for reporting vulnerabilities to Apple. Today, we are announcing a new mailing list for this purpose, security@webkit.org. In addition, you can now safely report vulnerabilities over https to our bug tracker, https://bugs.webkit.org, by placing the bug in the Security component. The people privy to the mailing list and the Security component are members of the Security group. It currently includes vendors shipping products that include WebKit, active port owners and trusted security experts. If you are shipping a product that includes WebKit and would like to be notified of security issues, please email security@webkit.org.

CSS Reflections

Posted by Dave Hyatt on Tuesday, April 29th, 2008 at 1:07 pm

WebKit now supports reflections in CSS. Continuing the trend of using adorable baby photos to make features appear more impressive, let me introduce Kate again. :)

A reflection is a replica of the original object with its own specific transform and mask. The box-reflect property can be used to specify the specialized transform and mask that should be used for the replica.

-webkit-box-reflect: <direction> <offset> <mask-box-image>

<direction> can be one of above, below, left or right.
<offset> is a length or percentage that specifies the distance of the reflection from the edge of the original border box (using the direction specified). It can be omitted, in which case it defaults to 0.
<mask-box-image> is a mask-box-image that can be used to overlay the reflection. If omitted, the reflection has no mask.

Reflections will update automatically as the source changes. If you hover over links, you’ll see the hover effect happen in the reflection. If you reflect the <video> element, you will see the video playing in the reflection.

Giving an element a reflection has the effect of creating a stacking context (so it joins opacity, masks and transforms). The reflection is non-interactive, so from the point of view of hit testing, it’s like it isn’t there. The reflection will have no effect on layout (other than being part of a container’s overflow), and can be thought of as similar to box-shadow in this respect.

The example above uses a gradient mask. Here is the sample code:

<img src=”bubbles.jpg” style=”border:5px solid white;-webkit-box-reflect:below 5px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.5, transparent), to(white));”>

CSS Masks

Posted by Dave Hyatt on Thursday, April 24th, 2008 at 11:53 am

WebKit now supports alpha masks in CSS. Masks allow you to overlay the content of a box with a pattern that can be used to knock out portions of that box in the final display. In other words, you can clip to complex shapes based off the alpha of an image.

Here is a snapshot of the Speed Racer movie trailer clipped to the Safari compass icon. This is in fact a mask applied to the <video> element.

We have introduced new properties to provide Web designers with a lot of control over these masks and how they are applied. The new properties are analogous to the background and border-image properties that already exist.

-webkit-mask (background)
-webkit-mask-attachment (background-attachment)
-webkit-mask-clip (background-clip)
-webkit-mask-origin (background-origin)
-webkit-mask-image (background-image)
-webkit-mask-repeat (background-repeat)
-webkit-mask-composite (background-composite)
-webkit-mask-box-image (border-image)

Use of a mask results in a stacking context being created (similar to how opacity and transforms work). The mask will therefore overlay the child and all of its descendants, and at a minimum will knock out everything outside the border box of the object.

From a Web designer’s perspective, think of the mask as being constructed the way the backgrounds and border-image of a box are constructed. Multiple backgrounds are stacking on top of one another (possibly overlapping) with their own tiling and clipping rules. A border-image can then potentially be stretched or tiled over the backgrounds.

The final resultant image built from putting all of the mask images together, tiling them, stretching them, etc., then becomes the mask used to clip the content. Alpha values of 0 in the mask mean that nothing should be drawn. Alpha values of 1 mean the content should display normally. Anything in between ends up partially transparent.

One key difference between mask-box-image and its border-image counterpart is that it doesn’t attempt to fit itself to border widths. It will just render the corners unscaled and tile/stretch itself into the border box without regard for the border itself. This lets you easily use nine-piece-image effects as masks on elements without borders (often image or video elements).

Here are two sample images. The source image that we want to mask and then the image that we will use as the mask.

We can place a mask on the image element simply by doing this:

<img src=”kate.png” style=”-webkit-mask-box-image: url(mask.png) 75 stretch;”>

The result looks like this:

CSS gradients can be used as the mask image source as well. In the following example a linear gradient is used to achieve a fade effect. For example:

<img src=”kate.png” style=”-webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1), to(rgba(0,0,0,0))”>

Masks respect the border-radius curves of an object. We can add a border-radius to the previous example, and have both the gradient fade effect with rounded corners.

<img src=”kate.png” style=”-webkit-border-radius: 10px; -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1), to(rgba(0,0,0,0))”>

SVG images can be used as masks. For example, a partially transparent circle:

can be applied as a mask like so:

<img src=”kate.png” style=”-webkit-mask-image: url(circle.svg)”>

The end result is shown below:

All of the power of the multiple background and border-image syntax is at your disposal when building masks!

As usual leave feedback in the comments and file bugs on any problems you notice at http://bugs.webkit.org/.

WebKit GSoC Students Announced

Posted by Eric Seidel on Monday, April 21st, 2008 at 12:10 pm

Google has released the list of students they will be sponsoring to work on WebKit as part of the Google Summer of Code this year. Congratulations to all of the students. We look forward to working with you closely this summer!

Thank you again to all the great students who applied! Unfortunately we had over twice as many applications as we had funding slots from Google. You’re certainly all welcome to come hack with us in #webkit any time.

Google’s official announcement

CSS Canvas Drawing

Posted by Dave Hyatt on Thursday, April 17th, 2008 at 11:33 am

Currently the set of images you can use from CSS consists of the following:

Bitmap Images (PNG, GIF, JPG)
SVG Images
Gradients

A notable missing ability when compared with explicit DOM content is programmatic drawing into CSS images. The <canvas> element represents a foreground bitmap image that can be drawn into programmatically, but - aside from inefficient hacks involving toDataURL - there hasn’t been any way to draw into the image buffers used by CSS images.

Until now!

In the latest nightlies, you can try out a new feature: the ability to specify named image buffers in CSS and then to draw into them programmatically from JavaScript. Here’s how it works.

background: -webkit-canvas(mycanvas);

Instead of specifying an image URL, you specify a canvas and an identifier to use for that canvas. The following new API on documents can then be used to obtain a drawing context for that canvas.

CanvasRenderingContext getCSSCanvasContext(in DOMString contextType, in DOMString identifier, in long width, in long height);

There is only one CSS canvas for a given global identifier per document. When you obtain the drawing context you also specify the size. The canvas will not be cleared as long as you repeatedly request the same size. Specifying a new size is equivalent to the kind of behavior you’d expect if you resized a <canvas> element, and so the canvas buffer will be cleared.

All objects that observe a CSS canvas of the same name are sharing that canvas. This means that (similar to how animated GIFs work), you can do animations and have them happen in lockstep on all the clients of the canvas. Drawing changes will be propagated to all clients automatically.

Here is an example:

Canvas as Background Image

Introducing CSS Gradients

Posted by Dave Hyatt on Monday, April 14th, 2008 at 12:39 pm

WebKit now supports gradients specified in CSS. There are two types of gradients: linear gradients and radial gradients.

The syntax is as follows:

-webkit-gradient(<type>, <point> [, <radius>]?, <point> [, <radius>]? [, <stop>]*)

The type of a gradient is either linear or radial.

A point is a pair of space-separated values. The syntax supports numbers, percentages or the keywords top, bottom, left and right for point values.

A radius is a number and may only be specified when the gradient type is radial.

A stop is a function, color-stop, that takes two arguments, the stop value (either a percentage or a number between 0 and 1.0), and a color (any valid CSS color). In addition the shorthand functions from and to are supported. These functions only require a color argument and are equivalent to color-stop(0, …) and color-stop(1.0, …) respectively.

Paraphrasing the HTML5 spec and adjusting the language slightly to not be canvas-specific:

“The color of the gradient at each stop is the color specified for that stop. Between each such stop, the colors and the alpha component must be linearly interpolated over the RGBA space without premultiplying the alpha value to find the color to use at that offset. Before the first stop, the color must be the color of the first stop. After the last stop, the color must be the color of the last stop. When there are no stops, the gradient is transparent black.

If multiple stops are added at the same offset on a gradient, they must be placed in the order added, with the first one closest to the start of the gradient, and each subsequent one infinitesimally further along towards the end point (in effect causing all but the first and last stop added at each point to be ignored).”

The points of a linear gradient specify a line. Linear gradients must be rendered such that at and before the starting point the color at offset 0 is used, that at and after the ending point the color at offset 1 is used, and that all points on a line perpendicular to the line that crosses the start and end points have the color at the point where those two lines cross (with the colors coming from the interpolation described above).

If x0 = x1 and y0 = y1, then the linear gradient must paint nothing.

For a radial gradient, the first two arguments represent a start circle with origin (x0, y0) and radius r0, and the next two arguments represent an end circle with origin (x1, y1) and radius r1.

Radial gradients must be rendered by following these steps:

If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing. Abort these steps.

Let x(ω) = (x1-x0)ω + x0

Let y(ω) = (y1-y0)ω + y0

Let r(ω) = (r1-r0)ω + r0

Let the color at ω be the color of the gradient at offset 0.0 for all values of ω less than 0.0, the color at offset 1.0 for all values of ω greater than 1.0, and the color at the given offset for values of ω in the range 0.0 ≤ ω ≤ 1.0

For all values of ω where r(ω) > 0, starting with the value of ω nearest to positive infinity and ending with the value of ω nearest to negative infinity, draw the circumference of the circle with radius r(ω) at position (x(ω), y(ω)), with the color at ω, but only painting on the parts of the surface that have not yet been painted on by earlier circles in this step for this rendering of the gradient.

This effectively creates a cone, touched by the two circles defined in the creation of the gradient, with the part of the cone before the start circle (0.0) using the color of the first offset, the part of the cone after the end circle (1.0) using the color of the last offset, and areas outside the cone untouched by the gradient (transparent black).”

So what exactly is a gradient in CSS? It is an image, usable anywhere that image URLs were used before. That’s right… anywhere. :)

You can use gradients in the following places:

background-image
border-image
list-style-image
content property

Gradients as Backgrounds

When specifying a gradient as a background, the gradient becomes a background tile. If no size is specified, then the gradient will size to the box specified by the background-origin CSS3 property. This value defaults to padding, so you the gradient will be as large as the padding-box. This is equivalent to a specified background-size of 100% in both directions.

If you want to achieve effects like tiling of a vertical gradient using a narrow strip, you should specify background-size to give the gradient tile an explicit size.

Gradients used as backgrounds will respect full page zoom, acquiring sharper resolution as the page is zoomed in.

Background Gradients Example

Border Image Gradients

Gradients can be used as border images. The most sensible use for them is specifying only horizontal or only vertical borders (and splitting the gradients up between the top and bottom or left and right borders).

The size of the gradient image is always the size of the border box.

Border Image Gradient Example

List Bullet Gradients

Gradients can be specified as list bullets. One problem with list bullet gradients is that there is currently no way in WebKit to specify the size of the marker box. Therefore the size of the image cannot be specified. WebKit has therefore chosen a default size based off the current font size of the list item.

List Item Gradients Example

Generated Content Gradients

Gradients can be used inside the content property. The image will fill the available width and height of its containing block. Therefore when using gradients inside ::before and ::after content with a specified size, it is important to set the display type to block or inline-block.

Gradients can also be used to do image replacement, so can be used with the img element in HTML or to replace the contents of other elements like spans and divs.

Generated Content Gradients Example

Final Notes

WebKit now supports a generic architecture for generated images, making it easy to add new generator effects to CSS in the future (lenticular halos, checkerboards, starbursts, etc.). The rules for sizing of these generated images will match whatever is decided for SVG content with no intrinsic size (the two are sharing the same rules right now).

We encourage you to try gradients out and file bugs if you see any unexpected or weird behavior. They will degrade safely in other browsers as long as you use multiple declarations (e.g., specify the image in one declaration and the gradient in a following declaration).

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.

WebKit achieves Acid3 100/100 in public build

Posted by Maciej Stachowiak on Wednesday, March 26th, 2008 at 6:55 pm

UPDATE We now believe we have a full rendering pass (but not necessarily an animation smoothness pass yet). See the bottom of the post for details.

UPDATE The Windows nightly is now available for download. See below for details.

With r31342 WebKit has become the first publicly available rendering engine to achieve 100/100 on Acid3. The final test, test 79, was a brutal torture test of SVG text rendering. Details of the bugs we fixed will follow. Indeed, we found a critical bug in the test itself that would have forced a violation of the SVG 1.1 standard to pass, so until a few hours ago it was not possible to get a valid 100/100. Acid3 test editor Ian Hickson has the details.

Note: this does not indicate a full pass of Acid3. We have a slight glitch in the text rendering that is likely to be fixed soon (patch in progress). Also, the animation is required to be smooth. On typical machines, if you look really closely, you can see a small glitch in the animation on test 26 because 26 is designed to be a performance test. However, we think we are faster than all other browsers on test 26. What constitutes a smooth animation is somewhat subjective.

This is not just a screenshot, you can pull live from SVN and build to see it yourself, and a fresh nightly build is coming soon.

Update:

Thanks to our own Dan Bernstein, as of r31356 we believe we have a pixel-perfect match for the reference rendering.

Get the fresh hot bits of the latest Mac and Windows nightly builds which include the full reference rendering pass.

Extra special bonus update: Alp Toker reports that the Gtk port now gets 100/100, although it does not yet match the reference rendering.

Enabling SVG Animation: Acid3 99/100

Posted by Antti Koivisto on Wednesday, March 26th, 2008 at 5:07 pm

In r31334 we enabled the SVG Animation support that has already been in the engine for a while but has not been enabled by default so far. We also implemented support for the beginElement() and endElement() methods. As a result we now pass the Acid3 test 76.

SVG Animation is a specification that has not been widely implemented so far. Reaching the point where various implementations are truly interoperable will take some more effort.

Get the nightly build and try it out yourself! One test to go.

WebKit hits 98/100 on Acid3

Posted by Eric Seidel on Wednesday, March 26th, 2008 at 10:16 am

We fixed our XML processing in r31316 to stop auto-recovering from invalid byte sequences and instead treat invalid bytes as fatal errors, as required by XML 1.0. To quote the spec:

It is a fatal error if an XML entity is determined (via default, encoding declaration, or higher-level protocol) to be in a certain encoding but contains byte sequences that are not legal in that encoding

Internet Explorer also has this strictness requirement (for XML loaded via XMLHttpRequest), thus we believe this added strictness should not cause any real-world compatibility problems. (IE’s behavior can be confirmed by Hixie’s test.)

Once again, enjoy the pretty picture:
WebKit hits 98/100 on Acid3

or you can grab the latest nightly and try Acid3 yourself!