Archive for the ‘Mozilla’ Category

Bug 130078 Landed

I landed bug 130078 a few days ago. Bug 130078 is about removing platform specific widgets (or windows) from the content area of the browser. These widgets cause us a lot of problems and there really is no need for them. It was a significant limitation in our core architecture that is now fixed. Removing these widgets has many benefits: it will allow the hardware acceleration work that is going on to proceed more smoothly, it gets us a lot of incremental performance improvements in different areas, and allows us more flexibility in drawing the browser chrome with the browser content and other areas. For example, it lets extension and chrome authors layer arbitrary chrome elements over content IFRAMEs and they can even apply any CSS effect to content IFRAMEs.

We’ve actually been removing widgets from Gecko for over a decade now. Back in 1999 (I’m told) native widgets for most form controls were removed from Gecko. Last year Robert O’Callahan removed widgets from scrolled areas and IFRAMEs in content documents. Then recently Jim Mathies merged the two widgets we had at the top of every window (on the Windows platform) into one so that we could draw in the titlebar. And finally bug 130078 removed widgets from root content documents, so there is only one widget left (on Windows at least), and we need to keep that one unless we want it to be a text based browser.

I’ve been working on this for quite a while, but Robert O’Callahan has been laying the groundwork for this change for years now and has done a huge amount of the work needed for bug 130078. He may be a little jealous that I got to finally push the changesets that kill this bug after he has been wanting to kill it for such a long time now. I also couldn’t have done it without the help of Karl Tomlinson, Mats Palmgren, Jeff Muizelaar, Bas Schouten, Jim Mathies, Chris Jones, Oleg Romashin, Kyle Huey and others that I’m probably forgetting.

Advertisements

Lazy frame construction recently landed on mozilla-central. To explain what this means and how this improves things we need some background. Each node in the DOM tree of a webpage has a frame created for it that is used to determine where on the page the node is drawn and its size. A frame corresponds closely to the concept of a box from the CSS spec. We used to create frames for DOM nodes eagerly; that is as soon as a node was inserted into the document we would create a frame for it. But this can create wasted effort in many situations. For example if a script inserts a large number of nodes into the DOM we would create a frame for each node when it is inserted. But with lazy frame construction we can process all those nodes at once in a big batch, saving overhead. Furthermore the time it takes to create those frames no longer blocks that script, so the script can go and do what it needs to and the frames will get created when they are needed. There are other situations where a script would insert nodes into the document and remove them immediately, so there is no need to ever create a frame for these as they would never be painted on screen.

So now when a node is inserted into a document the node is flagged for needing a frame created for it, and then the next time the refresh driver notifies (currently at 20 ms intervals) the frame is created. The refresh driver is also what drives reflow of webpages and CSS & SVG animations.

Let’s look at two examples where lazy frame construction helps.

In this example we insert 80000 div elements and then we flush all pending layout to time how long it takes before the changes made by the script are done and visible to the user. The script can continue executing without flushing layout, but we do it here to measure how long the actual work takes.

var stime = new Date();
var container = document.getElementById("container");
var lastchild = document.getElementById("lastchild");
for (var i = 0; i < 80000; i++) {
  var div = document.createElement("div");
  container.insertBefore(div, lastchild);
}
document.documentElement.offsetLeft; // flush layout
var now = new Date();
var millisecondselapsed = (now.getTime() - stime.getTime());

With lazy frame construction we are able to process the insertion of all 80000 div elements in one operation, saving the overhead of 80000 different inserts. In a build without lazy frame construction I get an average time of 1358 ms, with lazy frame construction I get 777 ms.

This example comes from a real webpage. We append a div and then set “div.style.position = ‘absolute’;”, and repeat that 2000 times, and then we flush all pending layout to time how long it takes before the changes made by the script are done and visible to the user.

var stime = new Date();
var container = document.getElementById("container2");
for (var i = 0; i < 2000; i++) {
  var div = document.createElement("div");
  container.appendChild(div);
  div.style.position = "absolute";
}
document.documentElement.offsetLeft; // flush layout
var now = new Date();
var millisecondselapsed = (now.getTime() - stime.getTime());

With lazy frame construction we don’t even bother creating the frame for the div until after the position has been set to absolute, so we don’t waste any effort. In a build without lazy frame construction I get an average time of 4730 ms, with lazy frame construction I get 130 ms.