About me

Mozillian. Open Source enthusiast. Loves Programming Languages.

Content

CSS transitions for dynamically created DOM elements

CSS transitions are awesome. You can use them to easily animate the transition of one or multiple CSS properties from a given state to another. But how does that work if your element has just been created and inserted into the DOM dynamically?

Let’s take a look at this simple example:

div {
  /* ... */
  transition: opacity 500ms;
}
var elem = document.createElement("div");
document.body.appendChild(elem);

// Make the element fully transparent.
elem.style.opacity = 0;

// Fade it in.
elem.style.opacity = 1;

We dynamically insert a new <div> element into the DOM with its initial opacity set to zero. Subsequently we want it to fade to full opacity. This - as you might have guessed - does of course not work that way.

How about a timeout?

It is clear that we somehow need to make sure the initial state with zero opacity is “applied” before trying to fade in:

var elem = document.createElement("div");
document.body.appendChild(elem);

// Make the element fully transparent.
elem.style.opacity = 0;

// Make sure the initial opacity value is applied.
setTimeout(function () {
  // Fade it in.
  elem.style.opacity = 1;
}, 0);

This is only marginally better. It seems to work with Webkit and Opera (and maybe even IE) but not in Firefox (in 99% of the cases). Using setTimeout() is a little too much overhead and nobody guarantees you that the style has really been applied after some milliseconds. It may be unsupported and unreliable, we need something better.

getComputedStyle to the rescue

There is another way to apply the element’s current style that even works synchronously:

var elem = document.createElement("div");
document.body.appendChild(elem);

// Make the element fully transparent.
elem.style.opacity = 0;

// Make sure the initial state is applied.
window.getComputedStyle(elem).opacity;

// Fade it in.
elem.style.opacity = 1;

Although it looks like we only query the current opacity value, getComputedStyle() in combination with accessing a property value actually flushes all pending style changes and forces the layout engine to compute our <div>’s current state. This workaround works in all major browsers and does not yield different results like the setTimeout() approach.

Snappy: Fixing new tab page performance regressions

As you probably already know, Firefox 13 introduced a neat new feature - the new tab page. We replaced the old blank page with a list of thumbnails of recently visited sites. While the feature itself works great for many people it has definitely made opening new tabs a little more noisy.

Do not show loading indicators

As we are now loading a real (although local) page, there are loading indicators when opening a new tab. The throbber starts to spin and the tab title changes to “Connecting…” until the page has loaded. That is a lot of unnecessary noise.

In bug 716108 (Firefox 17) we removed loading indicators for newly opened tabs. No spinning throbber, no flickering tab label. It only is a very subtle change but the whole action of opening a new tab feels a lot smoother again.

Preload new tab pages in the background

If you happen to have a slower machine you will notice that loading the new tab page takes a little while. It is a normal HTML (and partly XUL) page that we need to parse and render. As all tabs start out with a blank docShell you will first see a white canvas that then is replaced by “about:newtab”. As a last step all thumbnails will be loaded and drawn progressively.

Opening a new tab is a very frequent action so it should feel snappy and not get in your way at all. As optimizing the parsing and rendering stages any further is more than a non-trivial task I came up with a little trick in bug 753448. The idea is to preload the new tab page in the background so it has already loaded when users open a new tab. All we now have to do is switch docShells and the new tab page gets shown instantly.

You can give it a try as it landed in yesterday’s Nightly (2012-08-14). Just go to “about:config” and set “browser.newtab.preload” to “true”. This option is not yet enabled by default as we first have to figure out some minor talos regressions until it is ready for prime time.

Are we small, yet?

Lately, Asa Dotzler posted to dev.apps.firefox regarding the download size of Firefox:

This evening I noticed that my full win32 mar update for Firefox was 21MB. That caused me to look at what our full win32 installer size was. I was a bit surprised to see it’s up to 17MB. When we shipped Firefox 1, our Windows installer build was 4.7MB. […]

Firefox 12 is a 16.1 MB download. Firefox 4 was a 12.0 MB download. Firefox 3.6 was a 7.7 MB download.

In less than three years we’ve more than doubled in size. (fuller chart here http://grab.by/cSHA)

While there’s no doubt that adding new features and supporting new platforms are good reasons for increasing the build size it’s definitely a metric that impacts users. It hits them the hardest when downloading Firefox the first time, especially with slow internet connections. It still hits them every time we provide application updates.

To better illustrate the steady growth over the last few years I created http://www.arewesmallyet.com/. It’s updated daily, shows differences between nightly builds and links to the corresponding changelog if one would like to investigate the cause of increasing build sizes.

While this surely isn’t the most important battle we have right now I hope this will turn out useful to anyone willing to pick this up and tackle some build size optimizations.

GitHub: https://github.com/ttaubert/arewesmallyet

One year at Mozilla

You may already know the story of how I became a Firefox contributor. Back in early April of 2011, having volunteered full-time for three months (a rather short time compared to other core contributors), I was given the opportunity to start as a paid contributor working for Mozilla.

Over the year I met a lot of great people and had the chance to visit our awesome offices in Mountain View, San Francisco and soon Toronto. I attended JSConf.eu, MozCamp and FOSDEM, with the JSDay yet to come.

But Mozilla isn’t about traveling or attending conferences. It’s about passion for open source, passion for the open web. Working for a non-profit, where decisions are driven by reason and mission, is something that not many software engineers will ever experience in their whole professional career. That’s only one of the reasons I’m really glad to be a part of the global Mozilla community.

Inspired by Lucas Rocha I’ll end this post with some neat statistics about my contributions to the Mozilla project (we Germans love statistics):

I fixed 223 bugs and reviewed patches for 116. I pushed 417 changesets, 110 of them being merges between trees. I changed roughly 1367 files (31862 insertions(+), 19081 deletions(-)).

Fighting DocShell and DOMWindow leaks

In my post Leak hunting in browser-chrome mochitests I wrote about the measures we were considering to prevent regressing efforts to get rid of leaks in Firefox. Now that bug 683953 has landed we finally have a way to detect the leakage of whole DocShells and DOMWindows for the lifetime of the browser when running the browser-chrome mochitest suite.

How does it work?

While our browser-chrome mochitest suite runs we parse stdout to track starting and ending tests as well as the creation and removal of DocShells and DOMWindows. Just before the test suite shuts down we schedule a precise GC and wait until it’s completed. Any DOMWindows and DocShells still active are now counted as leaks and assigned to the tests that created them. Additionally we collect the URLs of DOMWindows to help debugging a bit.

How does this prevent new leaks?

We implemented a threshold of (currently) 130 leaks that must not be exceeded. If a test run leaks more than the limit we configured it goes orange and the patch should be backed out from the tree. These are the current numbers:

Linux (64): 116 (116) leaks
OS X (64): 79 (89) leaks
Windows (XP): 120 (118) leaks

Additionally, I filed bug 730797 to integrate these leaks statistics into our Talos infrastructure. So the leak count for each push will be recorded and compared to previous runs to make sure the numbers don’t regress. As the leak numbers differ quite heavily between OSes it makes sense to apply a custom threshold per OS, this will be implemented in bug 730800.

Why is there even a threshold?

First, there are DocShells and DOMWindows that are intentionally kept alive until the browser closes. Second, it’s nearly impossible to bring all these leaks down to “zero” at once. It’s a list of bugs that have to be addressed and we will slowly decrease the threshold to approach “zaroo”.

Thanks to Dão who has been doing great work in bug 658738 discovering all those leaks manually, which in the first place gave me the idea of automating it.

Help us test the New Tab Page!

Over the last weeks we worked hard on getting the New Tab Page into Firefox. It’s not quite ready yet but we need your help testing it. We enabled it by default on Nightly and decided to give it a week on Aurora to get feedback from those users as well.

Nightly: http://nightly.mozilla.org/
Aurora: https://www.mozilla.org/en-US/firefox/aurora/

We’ll disable it for Aurora again on February 16th (next Thursday). If you liked the feature and want it back then just set the preference ‘browser.newtab.url’ to ‘about:newtab’, ‘browser.newtabpage.enabled’ to ‘true’ and restart the browser. You can easily file bugs using the following link:

https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=General

Please make sure you don’t report a duplicate bug and check the dependencies of the original New Tab Page bug before filing – bug 455553.

How I became a Firefox contributor

December 2009. I’ve been a freelancer for quite some time now and decided to dedicate some weeks to something that always fascinated me: contributing to a big open source project. I started some smaller open source projects in the past (like Video4Linux.Net and ViGedit+) and contributed every so often to Gentoo and the Linux kernel. I’ve always been a great fan of the open source movement and I felt that it’s time to give back some love.

I made a list of all the things that interested me and that I could possibly contribute to. Besides having things like Linux, ReactOS and Wine on the list I picked “Firefox” because it simply has been a loyal companion for years. I think I’ve used it first in version 1.5 and it was one of the most valuable tools that helped me to earn money, get my everyday work done and the most trivial: just browse and experience the web.

Some weeks before that I switched to Firefox 4.0 beta3/4 because that included the first version of Panorama (Tab Groups / TabCandy) that worked on Linux. I loved this feature but noticed that it was in an early stage and needed some fixes. I set up a Firefox build environment, went through Bugzilla to find open bugs, nagged people on IRC and was totally overwhelmed by the warm welcome and the appreciation of my work. This was something I did not at all experience when trying to contribute to other open source projects. Finally, the Panorama team and me managed to get this feature into shape and land it in Firefox 4, yay!

Long story short, I’m now a full-time contributor and love what I’m doing.

Firefox Add-on: Websockets for IRCCloud

If you don’t know IRCCloud, check it out. It’s become a very important tool for my every day work and I really don’t want to miss it. The one thing I never liked about it is that is currently uses a Flash fallback if it detects that the browser doesn’t support the WebSocket API.

The Firefox WebSocket API is currently prefixed (called MozWebSocket) and that’s why even with the newest Firefox you’re forced to use the Flash fallback. They even check for MozWebSocket and explicitly don’t use it if detected. As I didn’t quite understand the reasons behind that I decided to write an add-on that convinces IRCCloud to use native WebSockets in Firefox. Works good so far. I hope that’ll encourage the IRCCloud guys to think about using it again.

Add-on: https://addons.mozilla.org/en-US/firefox/addon/websockets-for-irccloud/
Source: https://github.com/ttaubert/irccloud-websockets

Firefox Add-on: Facebook Auto-Logout

While talking to a friend of mine recently I got to know that he really dislikes that Facebook hides the Logout link in a sub-menu. He told me that he even uses a separate browser only for Facebook because he is very well aware of Facebook’s business model relying on tracking users wherever they are (this is not a big issue for me because I’m very happy with Ghostery).

A quick search revealed that there seem to be lot more users than I expected that would find an auto-logout of Facebook very useful. If not for privacy issues it’s also quite useful if someone else uses your computer and wants to post weird status updates.

So I wrote a Firefox add-on that logs the user out of Facebook when quitting Firefox or after a configurable amount of time has passed since he last closed a Facebook page (and there’s no active tab). It removes all cookies belonging to facebook.com so even tracking should not be an issue anymore (unless Facebook implements alternative tracking techniques).

Add-on: https://addons.mozilla.org/en-US/firefox/addon/facebook-auto-logout/
Source: https://github.com/ttaubert/facebook-auto-logout

Leak hunting in browser-chrome mochitests

Some weeks (even months) ago Dão Gottwald started the hunt for leaked DOMWindows and DocShells while running our browser-chrome mochitest suite (see bug 658738). That means that there are some expensive objects whose lifetimes are longer than they should be – they are kept alive until the test runner shuts down. Sometimes these are caused by only a little typo in the test and sometimes they unveil bigger problems in the core.

Dão has done some great work so far, fixed lots of those leaks and also pointed out patches that introduced new leaks. Inspired by his script that parses the mochitest build log and lists all leaked URIs I wrote a Python script that additionally assigns those URIs to the tests that created these DOMWindows and DocShells. I filed bug 683953 to automatically have those statistics at the end of each mochitest run. Here is an example:

TEST-INFO | leaked 15 DOMWindows and/or DocShells

[browser/components/sessionstore/test/browser/browser_589246.js]
  5x [about:blank]
  4x [chrome://browser/content/browser.xul]
  1x docShells

[browser/devtools/styleinspector/test/browser/styleinspector.js]
  2x [chrome://browser/content/csshtmltree.xhtml]
  1x [data:text/html,basic%20style%20inspector%20tests]
  1x [about:blank]
  1x docShells

This would definitely be very helpful as you don’t have to parse a build log manually after the test run finished. It would also allow us to fail (in a far future where all leaks are fixed) when we detect that the current patch would introduce a new leak.

Another approach would be to have an API that allows to check whether a given object should be regarded as “alive” or “dead”. This is what bug 633670 is about. Every test would need to check if the DOMWindows, DocShells and other objects created by it are still considered alive after it has finished. One problem with this is that we would have to run GC after each test to determine an object’s lifetime – which would negatively affect the overall mochitest suite runtime.

No matter which solution (or maybe a combination of both or something completely different) will make it – we definitely need some kind of better leak detection than we currently have. Many of us are not aware that they are accidentally introducing new leaks with new patches they write. Manually checking for new leaks after each push is a real waste of time and shouldn’t be necessary.

Recent posts

Disclaimer

The opinions expressed here are my own and do not necessarily represent those of current or past employers.