There’s a comparison that I was pointed at today showing the difference between a number of different modern encoders. The Theora 1.1 demo on that page looked particularly bad, so I decided to investigate.

I downloaded and compiled the latest versions of libogg, libvorbis and libtheora from I ran the encoder example (as the other test did), but discovered that it does support two-pass encoding, contrary to what was stated on the other test’s page. I ran a few different two-pass encodes (including one with soft rates), but didn’t get a lot of variability between results. Overall, however, my newly re-encoded version is significantly better than the one on the other page.

It appears that the Theora 1.1 version is at least as good as the XviD encoding, but at a smaller bitrate. It’s not as crisp as x264, but I’m not sure I’d notice the difference.

Source (via saintdevelopment):

Theora 1.1 (2939kbps):

./encoder_example -o touhou.theora.ogg --two-pass -V 2931 stream.y4m

XviD (3127kbps,via saintdevelopment):

x264 (2951kbps, via saintdevelopment):

Just so it’s clear: all of the results on this page with the exception of the Theora 1.1.1 screenshot, are taken from Saint Development’s codec comparison. The images in the comparison are from frame 700 in the final video (extracted in PNG format using mplayer as described by the test).

Read full post

IE6 has been getting a bad rap lately. France and Germany are both warning their citizens not to use it. The recent intrusions at Google were purported to be caused by holes in IE6. Even Microsoft is warning users to steer clear of it.

To get an idea of who’s given up on testing against this ancient browser, I’ve been running around browsing with IE6 in a VM. From what I’ve seen so far, it’s not getting a lot of love.

I’m pretty happy about this: as more and more sites break in IE6, it drives more people to browsers that don’t suck like Chrome or Firefox. It’s the last part of the browser death spiral: completely busted on the new and exciting sites.

The web browsing experience is pretty poor overall. Many sites serve transparent PNG files to the browser, which often render with miscolored backgrounds. Elements gain random padding, throwing nicely formatted designs for a loop. Other elements that are shrink-wrapped in other browsers sometimes end up with extremely large widths.

Note: I tried not to test sites too deeply- I figured that deeply nested screens will occasionally break in modern browsers too.


Facebook is the first site I visited. I figured that this would be the site most likely to regularly test against IE6. It’s clear that they do some testing: the interface works reasonably well overall, with only a few small glitches that might annoy a user.

The most glaring issue happens when you click the “more” link on the left. The UI gets kicked down to the bottom of the screen. Looks like a classic IE float bug:

The setting popup menu occasionally gets itself into a state where it pops as you mouseover the popup part of it, becoming entirely useless (it also random gains padding from time to time):


Twitter’s site is pretty simple, but it’s obviously not been tested in IE6. The CSS image sprites they use as controls on each tweet are totally busted:

Google Reader

Google reader is a rich application and works reasonably well in IE6. Lots of little formatting issues: buttons that are cut off, icons that float in the wrong place, stuff pushed down a line. Overall, still usable, albeit slow:


FriendFeed’s audience is probably not using IE6 and I imagine that they don’t put a lot of work into testing it. Many of the sidebar links don’t work and it sends transparent PNGs to IE6, which happily poops all over them:


An up-and-coming Twitter client, Brizzly looks pretty stellar in modern browsers. The front page is a bit mangled in IE6, however:

When you try to log in, it’s pretty obvious that IE6 isn’t in their plans:

Final thoughts

There’s a pretty big part of the web that still works in IE6, but a lot of the popular sites are getting pretty buggy in IE6. If your startup decides that it’s not worth supporting IE6, I wouldn’t blame you. IE6 is rockin’ a 13% market share on StatCounter and it’ll likely drop down to 4-5% by the end of next year.

Is it worth all the trouble to support IE6 for me? It depends. I’m not going to worry about fixing every little visual glitch in IE6. I’ll probably start sending down transparent PNGs to everything, even if the images don’t look great in IE6. If some bit of functionality breaks in IE6, I’ll repair it to the point where it works well enough to get the job done.

Full support for IE6? No thanks.

Read full post

It looks like the Chrome team has finally re-enabled extensions on Mac again (hat-tip to MG Siegler) in the latest dev channel build. You can’t update from the “About Google Chrome” screen yet, but you can grab the latest build and install it directly.

Even better, they are now allowing Mac users to install extensions directly from extension pages (warning: shameless self-promotion link).

Extensions are working well. They’ve turned on the browser action menus, so the various extensions that I’ve installed all work properly.

Bookmark sync is enabled as well, but I haven’t seen where the bookmarks are supposed to show up in Google Docs.

I’ve really missed having extensions for this last month; getting them back made my day!

Read full post

We’re in the process of launching our new publisher integration feature at DotSpots and needed to gain an understanding of how browsers deal with “third-party cookies”, or cookies that are set on domains that differ from the top-level domain.

Each of the major browsers, Firefox, Chrome, Safari, Opera and Internet Explorer have their own quirks about how cookies are accepted, which vary wildly depending on whether they were set by a top-level page, or a page in a third-party iframe.

Executive summary: Based on this study of browsers, the ideal method of storing information in iframes is a combination of localStorage for modern browsers and persistent cookies with a privacy policy for downlevel IE and Firefox versions. The default privacy settings are permissive enough on most of the old browsers to make this approach feasible. Earlier Safari versions that don’t support localStorage are out-of-luck, but the market share is too small to worry about.

These are the browsers I tested:

  • Firefox Default (checked ‘accept third-party cookies’)
  • Firefox (unchecked ‘accept third-party cookies’)
  • Chrome Default (allow all cookies)
  • Chrome (accept cookies only from sites I visit)
  • Safari Default (only from sites I visit)
  • Safari (accept cookies always)
  • Opera Default (accept cookies)
  • Opera (only from the site I visit)
  • IE6 Default
  • IE7 Default
  • IE8 Default

All browsers that support localStorage support setting and retrieving storage values from any frame. This includes Firefox, Chrome, Safari and IE8. HTML5 localStorage is by far the most reliable way to store information at this time for browsers that support it. There is one small difference: in Firefox, blocking all cookies will also block localStorage. In Chrome and Safari, blocking cookies does not block localStorage.

Chrome and Safari are based on the same WebKit engine and, as expected, share the same cookie policies for the same modes. Chrome defaults to the more permissive ‘Allow all cookies’ setting, while Safari defaults to ‘Allow Cookies from Sites I Visit’. When third-party cookies are disabled, frames can read cookies set by top-level pages but not write them.

Firefox defaults to a permissive mode in which cookies can be set and retrieved from all locations. Unlike WebKit browsers, disallowing third-party cookies means that a third-party iframe cannot read or write cookies at all.

Opera also defaults to permissive mode. In “accept cookies only from the site I visit” mode, it behaves the same way as Firefox does when third-party cookies are disallowed.

Internet Explorer is a bit finicky about privacy. If you add a basic privacy policy header to your responses, cookies will be accepted from iframes. Without the policy, most cookies can’t be set or retrieved in iframes at all (the exception is that iframes can read session cookies set at the top level). The following P3P header is sufficient to fix cookies in iframes.


To configure the header in Apache, you can use a simple mod_header line:

Header append P3P "CP=\"CAO PSA OUR\""

For those interested, here is a breakdown of cookie handling by browser and mode. Unlike cookies, HTML5 localStorage has no known limitations, so it has been omitted from the following charts:

WebKit, Allow All Cookies (Chrome default):

Set / Can be read Top level Iframe
Top level X X
Iframe X X

WebKit, Only From Sites I Visit (Safari default):

Set / Can be read Top level Iframe
Top level X X

Firefox, default:

Set / Can be read Top level Iframe
Top level X X
Iframe X X

Firefox, unchecked ‘accept third-party cookies’:

Set / Can be read Top level Iframe
Top level X

Opera, default:

Set / Can be read Top level Iframe
Top level X X
Iframe X X

Opera, Only From Sites I Visit:

Set / Can be read Top level Iframe
Top level X

IE6/IE7/IE8 default mode, without Privacy policy:

Set / Can be read Top level Iframe
Top level X *

* session cookies set by the top-level page may be read by iframes, but persistent cookies may not

IE6/IE7/IE8 default mode, with Privacy policy:

Set / Can be read Top level Iframe
Top level X X
Iframe X X
Read full post

I previously discussed using as a transport last year, but there wasn’t enough information and theory in the previous post to implement your own transport. I’ll fill in the gaps a bit more here to help developers looking to implement this themselves. You can also see the implementation we’re using at DotSpots in the gwt-rpc-plus project: Cross­Domain­Frame­ and Cross­Domain­Frame­Transport­

The process of making a request is described below. Note that you can inspect the HTML and HTTP traffic on my blog to see how our DotSpots plugin performs the cross-domain requests.

  1. Create the iframe and form to post. In IE, we use ActiveXObject as previously discussed to work around the machine-gun navigation sounds. You’ll need to stash a reference to the ActiveXObject somewhere where IE won’t garbage collect it.

    if ("ActiveXObject" in window) {
        var doc = new ActiveXObject("htmlfile");;
        doc.write("<html><body><iframe id='iframe'></iframe></body></html>");
        var iframe = doc.getElementById('iframe');
    } else {
        var doc = document;
        var iframe = doc.createElement('iframe');
    var form = doc.createElement('form');
  2. Set the the iframe’s name to a globally unique request ID. Using a unique request ID is very important, as two frames with the same name in Safari will result in one of them being set to a random name. = requestId; = requestId;
  3. POST the form to the endpoint, including the unique request ID and URL on the host domain. You can usually use /favicon.ico as a local path to return to. This is what gets posted by the DotSpots plugin on my blog:

    data=... (truncated JSON data)
  4. At this point, the iframe is now in a different security domain, so onload events won’t fire and window name is inaccessible.

  5. The server generates code to set the window name and redirect back to the original domain. Since the iframe is in a different security domain, the parent page won’t be able to tell that it was loaded. We redirect this iframe back to the URL requested once we’ve set the name.

    <script>'wnr-0-8908858(truncated JSON data)';
  6. The browser redirects back. When it gets back to the other domain’s favicon, onload will successfully fire and the previously set by the server will be accessible. As multiple onload and onreadystatechange events might occur during the request/response process, you should always check the for the appropriate prefix.

  7. Clean up the iframe and form. Remove the iframe and form after the request completes, but do this after a short delay. If you remove the iframe immediately after onload fires, the Firefox loading throbber will continue to animate indefinitely.

If you are considering using a transport like this for your own project, you should also consider using postMessage for uplevel browsers that support it. There are two HTTP requests required for, adding a fair bit of latency to each cross-domain request. Using postMessage reduces the number of requests to one, cutting the round-trip latency by 50%.

Your server responses when using postMessage should look like this instead:

window.parent.postMessage('wnr-0-8908858(truncated JSON data)', '*');

If you’re using GWT, all of this work is already done for you in our open-source library, gwt-rpc-plus. We’ve tested it against all of the current desktop browsers (all the way back to IE6) and the mobile browsers too (Android and iPhone).

Read full post