Merge m-c -> e10s.
authorDan Witte <dwitte@mozilla.com>
Wed, 18 Aug 2010 10:16:15 -0700
changeset 51334 5b653aa2a171274be17f5c9cedef966de8813413
parent 51333 0f96e7356ba364b923733b65594aafe6dccde7fc (current diff)
parent 50822 9ef027bf21208bd0a4df2e8a4004669ea8928abd (diff)
child 51335 718efba8384b19f88371e4132d91dba7412a2845
push id15277
push userdwitte@mozilla.com
push dateTue, 24 Aug 2010 04:18:33 +0000
treeherdermozilla-central@49dc8d6901a7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c -> e10s.
browser/themes/gnomestripe/browser/tabview/tabview-16.png
browser/themes/pinstripe/browser/tabview/tabview-16.png
browser/themes/winstripe/browser/tabview/tabview-16.png
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/base/src/nsFrameLoader.cpp
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
content/media/test/test_autobuffer.html
content/media/test/test_autobuffer2.html
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
layout/reftests/svg/smil/restart/reset-5.svg
toolkit/locales/en-US/chrome/mozapps/extensions/errors.dtd
toolkit/mozapps/extensions/amInstallTrigger.cpp
toolkit/mozapps/extensions/amInstallTrigger.h
toolkit/mozapps/extensions/content/errors.xul
toolkit/mozapps/extensions/test/addons/test_bug511091/icon.png
toolkit/mozapps/extensions/test/addons/test_bug511091/install.rdf
toolkit/mozapps/extensions/test/addons/test_bug542391_3/install.rdf
toolkit/mozapps/extensions/test/unit/test_bug511091.js
toolkit/mozapps/extensions/test/unit/test_bug542391.js
widget/public/Makefile.in
widget/public/nsGUIEvent.h
widget/src/android/AndroidBridge.cpp
widget/src/android/nsWindow.cpp
--- a/accessible/src/base/nsTextAttrs.cpp
+++ b/accessible/src/base/nsTextAttrs.cpp
@@ -460,19 +460,20 @@ nsFontSizeTextAttr::Format(const nscoord
   // Convert from nscoord to pt.
   //
   // Note: according to IA2, "The conversion doesn't have to be exact.
   // The intent is to give the user a feel for the size of the text."
   // 
   // ATK does not specify a unit and will likely follow IA2 here.
   //
   // XXX todo: consider sharing this code with layout module? (bug 474621)
-  float inches = static_cast<float>(aValue) /
-    static_cast<float>(mDC->AppUnitsPerInch());
-  int pts = static_cast<int>(inches * 72 + .5); // 72 pts per inch
+  float px =
+    NSAppUnitsToFloatPixels(aValue, nsIDeviceContext::AppUnitsPerCSSPixel());
+  // Each pt is 4/3 of a CSS pixel.
+  int pts = NS_lround(px*3/4);
 
   nsAutoString value;
   value.AppendInt(pts);
   value.Append(NS_LITERAL_STRING("pt"));
   aFormattedValue = value;
 }
 
 nscoord
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2355,20 +2355,21 @@ function losslessDecodeURI(aURI) {
                          encodeURIComponent);
     } catch (e) {}
 
   // Encode invisible characters (line and paragraph separator,
   // object replacement character) (bug 452979)
   value = value.replace(/[\v\x0c\x1c\x1d\x1e\x1f\u2028\u2029\ufffc]/g,
                         encodeURIComponent);
 
-  // Encode default ignorable characters. (bug 546013)
+  // Encode default ignorable characters (bug 546013)
+  // except ZWNJ (U+200C) and ZWJ (U+200D) (bug 582186).
   // This includes all bidirectional formatting characters.
   // (RFC 3987 sections 3.2 and 4.1 paragraph 6)
-  value = value.replace(/[\u00ad\u034f\u115f-\u1160\u17b4-\u17b5\u180b-\u180d\u200b-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]/g,
+  value = value.replace(/[\u00ad\u034f\u115f-\u1160\u17b4-\u17b5\u180b-\u180d\u200b\u200e-\u200f\u202a-\u202e\u2060-\u206f\u3164\ufe00-\ufe0f\ufeff\uffa0\ufff0-\ufff8]|\ud834[\udd73-\udd7a]|[\udb40-\udb43][\udc00-\udfff]/g,
                         encodeURIComponent);
   return value;
 }
 
 function UpdateUrlbarSearchSplitterState()
 {
   var splitter = document.getElementById("urlbar-search-splitter");
   var urlbar = document.getElementById("urlbar-container");
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -105,44 +105,43 @@
 # All sets except for popupsets (commands, keys, stringbundles and broadcasters) *must* go into the
 # browser-sets.inc file for sharing with hiddenWindow.xul.
 #include browser-sets.inc
 
   <popupset id="mainPopupSet">
     <menupopup id="tabContextMenu"
                onpopupshowing="if (event.target == this) TabContextMenu.updateContextMenu(this);"
                onpopuphidden="if (event.target == this) TabContextMenu.contextTab = null;">
-      <menu id="context_tabViewMenu" class="menu-iconic" label="&moveTabTo.label;"
-            accesskey="&moveTabTo.accesskey;">
-        <menupopup id="context_tabViewMenuPopup" 
-                   onpopupshowing="if (event.target == this) TabView.updateContextMenu(TabContextMenu.contextTab, this);">
-          <menuitem label="&createNewGroup.label;" 
-                    accesskey="&createNewGroup.accesskey;" 
-                    oncommand="TabView.moveTabTo(TabContextMenu.contextTab, null);" />
-          <menuitem id="context_namedGroups" label="&namedGroups.label;" 
-                    disabled="true" />
-        </menupopup>
-      </menu>
-      <menuseparator/>
       <menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
                 oncommand="gBrowser.reloadTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_reloadAllTabs" label="&reloadAllTabs.label;" accesskey="&reloadAllTabs.accesskey;"
                 tbattr="tabbrowser-multiple"
                 oncommand="gBrowser.reloadAllTabs();"/>
       <menuseparator/>
       <menuitem id="context_openTabInWindow" label="&openTabInNewWindow.label;"
                 accesskey="&openTabInNewWindow.accesskey;"
                 tbattr="tabbrowser-multiple"
                 oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
       <menuitem id="context_pinTab" label="&pinTab.label;"
                 accesskey="&pinTab.accesskey;"
                 oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
                 accesskey="&unpinTab.accesskey;"
                 oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
+      <menu id="context_tabViewMenu" label="&moveToGroup.label;"
+            accesskey="&moveToGroup.accesskey;">
+        <menupopup id="context_tabViewMenuPopup" 
+                   onpopupshowing="if (event.target == this) TabView.updateContextMenu(TabContextMenu.contextTab, this);">
+          <menuitem label="&moveToNewGroup.label;" 
+                    accesskey="&moveToNewGroup.accesskey;" 
+                    oncommand="TabView.moveTabTo(TabContextMenu.contextTab, null);"/>
+          <menuitem id="context_namedGroups" label="&namedGroups.label;" 
+                    disabled="true"/>
+        </menupopup>
+      </menu>
       <menuseparator/>
       <menuitem id="context_bookmarkTab"
                 label="&bookmarkThisTab.label;"
                 accesskey="&bookmarkThisTab.accesskey;"
                 oncommand="BookmarkThisTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_bookmarkAllTabs"
                 label="&bookmarkAllTabs.label;"
                 accesskey="&bookmarkAllTabs.accesskey;"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -83,18 +83,23 @@
                 onget="return this.tabContainer.contextMenu;"/>
 
       <field name="tabContainer" readonly="true">
         document.getElementById(this.getAttribute("tabcontainer"));
       </field>
       <field name="tabs" readonly="true">
         this.tabContainer.childNodes;
       </field>
-      <property name="visibleTabs" readonly="true"
-                onget="return Array.filter(this.tabs, function(tab) !tab.hidden);"/>
+      <property name="visibleTabs" readonly="true">
+        <getter><![CDATA[
+          return Array.filter(this.tabs, function(tab) {
+            return !tab.hidden && this._removingTabs.indexOf(tab) == -1;
+          }, this);
+        ]]></getter>
+      </property>
       <field name="mURIFixup" readonly="true">
         Components.classes["@mozilla.org/docshell/urifixup;1"]
                   .getService(Components.interfaces.nsIURIFixup);
       </field>
       <field name="mFaviconService" readonly="true">
         Components.classes["@mozilla.org/browser/favicon-service;1"]
                   .getService(Components.interfaces.nsIFaviconService);
       </field>
@@ -1582,27 +1587,25 @@
 
             if (aTab.owner &&
                 this._removingTabs.indexOf(aTab.owner) == -1 &&
                 Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
               this.selectedTab = aTab.owner;
               return;
             }
 
-            let removing = this._removingTabs;
-            function keepRemaining(tab) {
-              // A tab remains only if it's not being removed nor blurred
-              return removing.indexOf(tab) == -1 && tab != aTab;
+            // Switch to a visible tab unless there aren't any others remaining
+            let remainingTabs = this.visibleTabs;
+            let numTabs = remainingTabs.length;
+            if (numTabs == 0 || numTabs == 1 && remainingTabs[0] == aTab) {
+              remainingTabs = Array.filter(this.tabs, function(tab) {
+                return this._removingTabs.indexOf(tab) == -1;
+              }, this);
             }
 
-            // Switch to a visible tab unless there aren't any remaining
-            let remainingTabs = this.visibleTabs.filter(keepRemaining);
-            if (remainingTabs.length == 0)
-              remainingTabs = Array.filter(this.tabs, keepRemaining);
-
             // Try to find a remaining tab that comes after the given tab
             var tab = aTab;
             do {
               tab = tab.nextSibling;
             } while (tab && remainingTabs.indexOf(tab) == -1);
 
             if (!tab) {
               tab = aTab;
@@ -1813,17 +1816,18 @@
         ]]>
         </body>
       </method>
 
       <method name="hideTab">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
-          if (!aTab.hidden && !aTab.pinned && !aTab.selected) {
+          if (!aTab.hidden && !aTab.pinned && !aTab.selected &&
+              this._removingTabs.indexOf(aTab) == -1) {
             aTab.hidden = true;
             let event = document.createEvent("Events");
             event.initEvent("TabHide", true, false);
             aTab.dispatchEvent(event);
           }
         ]]>
         </body>
       </method>
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -131,27 +131,29 @@ endif
                  browser_bug520538.js \
                  browser_bug521216.js \
                  browser_bug537474.js \
                  browser_bug550565.js \
                  browser_bug553455.js \
                  browser_bug555224.js \
                  browser_bug555767.js \
                  browser_bug556061.js \
+                 browser_bug561623.js \
                  browser_bug562649.js \
                  browser_bug563588.js \
                  browser_bug577121.js \
                  browser_bug580956.js \
                  browser_bug581242.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_discovery.js \
                  browser_drag.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
+                 browser_hide_removing.js \
                  browser_inspector_initialization.js \
                  browser_inspector_treeSelection.js \
                  browser_inspector_highlighter.js \
                  browser_inspector_stylePanel.js \
                  browser_inspector_iframeTest.js \
                  browser_inspector_scrolling.js \
                  browser_pageInfo.js \
                  browser_page_style_menu.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug561623.js
@@ -0,0 +1,29 @@
+function test() {
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function () {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+    let doc = gBrowser.contentDocument;
+    let tooltip = document.getElementById("aHTMLTooltip");
+    let i = doc.getElementById("i");
+
+    ok(!FillInHTMLTooltip(i),
+       "No tooltip should be shown when @title is null");
+
+    i.title = "foo";
+    ok(FillInHTMLTooltip(i),
+       "A tooltip should be shown when @title is not the empty string");
+
+    i.pattern = "bar";
+    ok(FillInHTMLTooltip(i),
+       "A tooltip should be shown when @title is not the empty string");
+
+    gBrowser.removeCurrentTab();
+    finish();
+  }, true);
+
+  content.location = 
+    "data:text/html,<!DOCTYPE html><html><body><input id='i'></body></html>";
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_hide_removing.js
@@ -0,0 +1,68 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is tabbrowser hide removing tab test.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Edward Lee <edilee@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Bug 587922: tabs don't get removed if they're hidden
+
+function test() {
+  waitForExplicitFinish();
+
+  // Add a tab that will get removed and hidden
+  let testTab = gBrowser.addTab("about:blank", {skipAnimation: true});
+  is(gBrowser.visibleTabs.length, 2, "just added a tab, so 2 tabs");
+  gBrowser.selectedTab = testTab;
+
+  let numVisBeforeHide, numVisAfterHide;
+  gBrowser.tabContainer.addEventListener("TabSelect", function() {
+    gBrowser.tabContainer.removeEventListener("TabSelect", arguments.callee, false);
+
+    // While the next tab is being selected, hide the removing tab
+    numVisBeforeHide = gBrowser.visibleTabs.length;
+    gBrowser.hideTab(testTab);
+    numVisAfterHide = gBrowser.visibleTabs.length;
+  }, false);
+  gBrowser.removeTab(testTab, {animate: true});
+
+  // Make sure the tab gets removed at the end of the animation by polling
+  (function checkRemoved() setTimeout(function() {
+    if (gBrowser.tabs.length != 1)
+      return checkRemoved();
+
+    is(numVisBeforeHide, 1, "animated remove has in 1 tab left");
+    is(numVisAfterHide, 1, "hiding a removing tab is also has 1 tab");
+    finish();
+  }, 50))();
+}
--- a/browser/components/sessionstore/test/browser/browser_463206.js
+++ b/browser/components/sessionstore/test/browser/browser_463206.js
@@ -75,18 +75,19 @@ function test() {
       let win = tab2.linkedBrowser.contentWindow;
       isnot(doc.getElementById("out1").value,
             win.frames[1].document.getElementById("out1").value,
             "text isn't reused for frames");
       isnot(doc.getElementsByName("1|#out2")[0].value, "",
             "text containing | and # is correctly restored");
       is(win.frames[1].document.getElementById("out2").value, "",
             "id prefixes can't be faked");
-      isnot(win.frames[0].frames[1].document.getElementById("in1").value, "",
-            "id prefixes aren't mixed up");
+      // Disabled for now, Bug 588077
+      // isnot(win.frames[0].frames[1].document.getElementById("in1").value, "",
+      //       "id prefixes aren't mixed up");
       is(win.frames[1].frames[0].document.getElementById("in1").value, "",
             "id prefixes aren't mixed up");
       
       // clean up
       gBrowser.removeTab(tab2);
       gBrowser.removeTab(tab);
       
       finish();
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-4.0b4pre
+4.0b5pre
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -7,33 +7,33 @@
 <!ENTITY mainWindow.titlemodifier "&brandFullName;">
 <!-- LOCALIZATION NOTE (mainWindow.titlemodifiermenuseparator): DONT_TRANSLATE -->
 <!ENTITY mainWindow.titlemodifiermenuseparator " - ">
 <!-- LOCALIZATION NOTE (mainWindow.titlePrivateBrowsingSuffix): This will be appended to the window's title
                                                                 inside the private browsing mode -->
 <!ENTITY mainWindow.titlePrivateBrowsingSuffix "(Private Browsing)">
 
 <!-- Tab context menu -->
-<!ENTITY  moveTabTo.label                    "Move This Tab To…">
-<!ENTITY  moveTabTo.accesskey                "M">
-<!ENTITY  createNewGroup.label               "Create New Group">
-<!ENTITY  createNewGroup.accesskey           "C">
-<!ENTITY  namedGroups.label                  "Named Groups">
 <!ENTITY  reloadTab.label                    "Reload Tab">
 <!ENTITY  reloadTab.accesskey                "R">
 <!ENTITY  reloadAllTabs.label                "Reload All Tabs">
 <!ENTITY  reloadAllTabs.accesskey            "A">
 <!ENTITY  closeOtherTabs.label               "Close Other Tabs">
 <!ENTITY  closeOtherTabs.accesskey           "o">
 <!ENTITY  openTabInNewWindow.label           "Open in a New Window">
 <!ENTITY  openTabInNewWindow.accesskey       "W">
 <!ENTITY  pinTab.label                       "Make into App Tab">
 <!ENTITY  pinTab.accesskey                   "p">
 <!ENTITY  unpinTab.label                     "Make into Normal Tab">
 <!ENTITY  unpinTab.accesskey                 "k">
+<!ENTITY  moveToGroup.label                  "Move to Group">
+<!ENTITY  moveToGroup.accesskey              "M">
+<!ENTITY  moveToNewGroup.label               "New Group">
+<!ENTITY  moveToNewGroup.accesskey           "N">
+<!ENTITY  namedGroups.label                  "Named Groups">
 <!ENTITY  bookmarkThisTab.label              "Bookmark This Tab">
 <!ENTITY  bookmarkThisTab.accesskey          "B">
 <!ENTITY  bookmarkAllTabs.label              "Bookmark All Tabs…">
 <!ENTITY  bookmarkAllTabs.accesskey          "T">
 <!ENTITY  undoCloseTab.label                 "Undo Close Tab">
 <!ENTITY  undoCloseTab.accesskey             "U">
 <!ENTITY  closeTab.label                     "Close Tab">
 <!ENTITY  closeTab.accesskey                 "c">
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1522,17 +1522,13 @@ listitem.style-section {
   color: black;
   font-weight: bold;
 }
 
 panel[dimmed="true"] {
   opacity: 0.5;
 }
 
-/* Tab Context Menu */
-#context_tabViewMenu {
-  list-style-image: url(chrome://browser/skin/tabview/tabview-16.png);
-}
+/* Tab view context menu */
 
 #context_tabViewMenuPopup > menuitem.group {
-  padding-left: 40px;
+  -moz-padding-start: 40px;
 }
-
--- a/browser/themes/gnomestripe/browser/jar.mn
+++ b/browser/themes/gnomestripe/browser/jar.mn
@@ -72,17 +72,16 @@ browser.jar:
   skin/classic/browser/tabbrowser/progress-pulsing.png (tabbrowser/progress-pulsing.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
   skin/classic/browser/tabview/edit.png               (tabview/edit.png)
   skin/classic/browser/tabview/new-tab.png            (tabview/new-tab.png)
   skin/classic/browser/tabview/tabview.css            (tabview/tabview.css)
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png            (tabview/tabview.png)
-  skin/classic/browser/tabview/tabview-16.png         (tabview/tabview-16.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-merge.png
   skin/classic/browser/sync-mobileIcon.png
deleted file mode 100644
index 87e7e3f73326b7a30e0ed547f209196d8c2c6102..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
index 6ed2a4edca6fd873cb2b9e929f77012a07e91f06..cc8ea8830b0220d6b6c7e5a034e34b677be14de3
GIT binary patch
literal 593
zc$@)I0<QguP)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igb`
z3>F#IO$wm^00GfSL_t(2&y|v~ZWJ*PhQG0Ay?YmLbSV<)8k!XJNkJ3QQ3i>IDiReP
zyg(j+CqSa*4N{~-DIy+#IuuETM6(q{o7?r;rigEqmT4?|^lAS8AJew2@SoMTtq8z!
zxqNAiIRh*(mA(QwrSt{B81oTGDW$J{-+$Kvo>^<(TWiTV10W*A7@4N&mx!RM?*OK0
znr6^@Z|b_nTAQDO(=^F23<jWS8UTi2FkRQ7MF!SdR8^jWWx}IwRRBT=vkwjq4!RJ+
zEOT2`Rk2#FewRtxV7j}zI|ShJ^75$by4T}4R?fMhX__I%SdHUY-{0R~h)7;67H^F)
z)BgVc#p&tk4*@tlJp8a+E<dSiiZKrB_4-xUb#Fol=MN7LBan7>c4CZC`@TQFy}kXc
z#rSd4G_7-v&1S>R&CPS~{R{8C+uhxDIcIXtgb+w69nT*3_Vz~aJ#}4&zV9nlrLODX
zz27D+B9cQ0QrGo3gT@$BQq9)d?cJ&>#+W(floF;qD1dV=m4>s{(lkx1s%jhYc10p0
zIOoy~o}8Rqr<9J0rj4rpOeuYfF+LNK9!NQ76%k{MxxTu(dR#}&xdK|il)w51r~qH4
fW<bjMS46@;Hk#99eefeV00000NkvXXu0mjfn!f`i
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -154,17 +154,17 @@ toolbarbutton.chevron {
 toolbarbutton.chevron > .toolbarbutton-text {
   display: none;
 }
 
 toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
-/* ----- BOOKMARK BUTTONS ----- */	
+/* ----- BOOKMARK BUTTONS ----- */
 
 toolbarbutton.bookmark-item {
   font-weight: bold;
   color: #222;
   border: 0;
   -moz-border-radius: 100%;
   padding: 0 8px;
   margin: 0 0 1px;
@@ -267,33 +267,33 @@ toolbarbutton.bookmark-item > menupopup 
   background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat;
 }
 
 .bookmarks-toolbar-customize {
   max-width: 15em !important;
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
 }
 
-/* ----- BOOKMARK MENUS ----- */	
+/* ----- BOOKMARK MENUS ----- */
 
 .bookmark-item > .menu-iconic-left > .menu-iconic-icon {
   width: 16px;
   height: 16px;
 }
 
 #bookmarksToolbarFolderMenu,
 #BMB_bookmarksToolbarFolderMenu {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
 }
 
 #BMB_unsortedBookmarksFolderMenu {
   list-style-image: url("chrome://browser/skin/places/unfiledBookmarks.png");
 }
 
-/* ----- PRIMARY TOOLBAR BUTTONS ----- */	
+/* ----- PRIMARY TOOLBAR BUTTONS ----- */
 
 .toolbarbutton-1,
 #restore-button,
 toolbarbutton[type="menu-button"] > .toolbarbutton-menubutton-button,
 toolbarbutton[type="menu-button"] > .toolbarbutton-menubutton-dropmarker {
   margin: 0;
   -moz-box-orient: vertical;
   padding: 0 3px;
@@ -2105,21 +2105,18 @@ listitem.style-section {
   font-weight: bold;
 }
 
 panel[dimmed="true"] {
   opacity: 0.5;
 }
 
 /* Sync */
+
 #sync-status-button.statusbarpanel-iconic {
   padding: 0 5px;
 }
 
-/* Tab Context Menu */
-#context_tabViewMenu {
-  list-style-image: url(chrome://browser/skin/tabview/tabview-16.png);
-}
+/* Tab view context menu */
 
 #context_tabViewMenuPopup > menuitem.group {
-  padding-left: 40px;
+  -moz-padding-start: 40px;
 }
-
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -113,17 +113,16 @@ browser.jar:
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabbrowser/tab-bkgnd.png                          (tabbrowser/tab-bkgnd.png)
   skin/classic/browser/tabview/edit-light.png               (tabview/edit-light.png)
   skin/classic/browser/tabview/edit.png                     (tabview/edit.png)
   skin/classic/browser/tabview/new-tab.png                  (tabview/new-tab.png)
   skin/classic/browser/tabview/tabview.css                  (tabview/tabview.css)
   skin/classic/browser/tabview/stack-expander.png           (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png                  (tabview/tabview.png)
-  skin/classic/browser/tabview/tabview-16.png               (tabview/tabview-16.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-merge.png
   skin/classic/browser/sync-mobileIcon.png
--- a/browser/themes/pinstripe/browser/places/editBookmarkOverlay.css
+++ b/browser/themes/pinstripe/browser/places/editBookmarkOverlay.css
@@ -49,44 +49,44 @@
   display: -moz-box;
 }
 
 .folder-icon {
   list-style-image: url("chrome://global/skin/tree/folder.png") !important;
 }
 
 .menulist-icon {
-	margin: 0 !important;
+  margin: 0 !important;
 }
 
 /**** expanders ****/
 
 .expander-up,
 .expander-down {
   -moz-appearance: none;
   margin: 0;
   margin-left: 8px;
   padding: 0;
   min-width: 0;
 }
 
 .expander-up {
-	list-style-image: url("chrome://browser/skin/places/expander-open.png") !important;
+  list-style-image: url("chrome://browser/skin/places/expander-open.png") !important;
 }
 
 .expander-down {
-	list-style-image: url("chrome://browser/skin/places/expander-closed.png") !important;
+  list-style-image: url("chrome://browser/skin/places/expander-closed.png") !important;
 }
 
 .expander-down:hover:active {
-	list-style-image: url("chrome://browser/skin/places/expander-closed-active.png") !important;
+  list-style-image: url("chrome://browser/skin/places/expander-closed-active.png") !important;
 }
 
 .expander-up:hover:active {
-	list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
+  list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
 }
 
 #editBookmarkPanelContent {
   min-width: 23em;
 }
 
 #editBMPanel_folderTree {
   margin: 6px 4px 0 4px;
@@ -161,17 +161,17 @@
  * so that only the tag being edited is shown in the
  * popup.
  */
 #editBMPanel_tagsField #treecolAutoCompleteValue {
   visibility: collapse;
 }
 
 
-/* ----- BOOKMARK PANEL DROPDOWN MENU ITEMS ----- */	
+/* ----- BOOKMARK PANEL DROPDOWN MENU ITEMS ----- */
 
 #editBMPanel_folderMenuList[selectedIndex="0"],
 #editBMPanel_toolbarFolderItem {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;  
 }
 
 #editBMPanel_folderMenuList[selectedIndex="1"],
 #editBMPanel_bmRootItem {
--- a/browser/themes/pinstripe/browser/preferences/preferences.css
+++ b/browser/themes/pinstripe/browser/preferences/preferences.css
@@ -47,81 +47,81 @@
 .paneSelector {
   list-style-image: url("chrome://browser/skin/preferences/Options.png");
 }
 
 /* ----- GENERAL BUTTON ----- */
 
 radio[pane=paneGeneral],
 radio[pane=paneMain] {
-	-moz-image-region: rect(0px, 32px, 32px, 0px)
+  -moz-image-region: rect(0px, 32px, 32px, 0px);
 } 
 radio[pane=paneGeneral]:active,
 radio[pane=paneMain]:active:hover {
-	-moz-image-region: rect(32px, 32px, 64px, 0px)
+  -moz-image-region: rect(32px, 32px, 64px, 0px);
 }
 
 /* ----- TABS BUTTON ----- */
 
 radio[pane=paneTabs] {
-	-moz-image-region: rect(0px, 64px, 32px, 32px);
+  -moz-image-region: rect(0px, 64px, 32px, 32px);
 }
 
 radio[pane=paneTabs]:active:hover {
-	-moz-image-region: rect(32px, 64px, 64px, 32px);
+  -moz-image-region: rect(32px, 64px, 64px, 32px);
 }
 
 /* ----- CONTENT BUTTON ----- */
 
 radio[pane=paneContent] {
-	-moz-image-region: rect(0px, 96px, 32px, 64px);
+  -moz-image-region: rect(0px, 96px, 32px, 64px);
 }
 
 radio[pane=paneContent]:active:hover {
-	-moz-image-region: rect(32px, 96px, 64px, 64px);
+  -moz-image-region: rect(32px, 96px, 64px, 64px);
 }
 
 /* ----- APPLICATIONS BUTTON ----- */
 
 radio[pane=paneApplications] {
-	-moz-image-region: rect(0px, 128px, 32px, 96px);
+  -moz-image-region: rect(0px, 128px, 32px, 96px);
 }
 
 radio[pane=paneApplications]:active:hover {
-	-moz-image-region: rect(32px, 128px, 64px, 96px);
+  -moz-image-region: rect(32px, 128px, 64px, 96px);
 }
 
 /* ----- PRIVACY BUTTON ----- */
 
 radio[pane=panePrivacy] {
-	-moz-image-region: rect(0px, 160px, 32px, 128px);
+  -moz-image-region: rect(0px, 160px, 32px, 128px);
 }
 
 radio[pane=panePrivacy]:active:hover {
-	-moz-image-region: rect(32px, 160px, 64px, 128px);
+  -moz-image-region: rect(32px, 160px, 64px, 128px);
 }
 
 /* ----- SECURITY BUTTON ----- */
 
 radio[pane=paneSecurity] {
-	-moz-image-region: rect(0px, 192px, 32px, 160px);
+  -moz-image-region: rect(0px, 192px, 32px, 160px);
 }
 
 radio[pane=paneSecurity]:active:hover {
-	-moz-image-region: rect(32px, 192px, 64px, 160px);
+  -moz-image-region: rect(32px, 192px, 64px, 160px);
 }
 
 /* ----- ADVANCED BUTTON ----- */
 
 radio[pane=paneAdvanced] {
-	-moz-image-region: rect(0px, 224px, 32px, 192px);
+  -moz-image-region: rect(0px, 224px, 32px, 192px);
 }
 
 radio[pane=paneAdvanced]:active:hover {
-	-moz-image-region: rect(32px, 224px, 64px, 192px);
+  -moz-image-region: rect(32px, 224px, 64px, 192px);
 }
 
 %ifdef MOZ_SERVICES_SYNC
 /* ----- SYNC BUTTON ----- */
 
 radio[pane=paneSync] {
   list-style-image: url("chrome://browser/skin/preferences/Options-sync.png");
 }
@@ -206,17 +206,17 @@ caption {
   margin: 0 8px;
 }
 
 #privacyPrefs {
   padding: 0 4px;
 }
 
 #privacyPrefs > tabpanels {
-  padding: 18px 10px 10px 10px;
+  padding: 18px 10px 10px;
 }
 
 #OCSPDialogPane {
   font: message-box !important;
 }
 
 /**
  * Privacy Pane
deleted file mode 100644
index 87e7e3f73326b7a30e0ed547f209196d8c2c6102..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -12,17 +12,17 @@
   .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) {
     background-image: -moz-linear-gradient(rgba(255,255,255,.7), @toolbarHighlight@ 30%),
                       -moz-linear-gradient(@customToolbarColor@, @customToolbarColor@);
   }
 }
 
 @media all and (-moz-windows-compositor) {
   #main-window:not(:-moz-lwtheme) {
-    -moz-appearance: -moz-win-glass;
+    -moz-appearance: -moz-win-borderless-glass;
     background: transparent;
   }
 
   /* the new titlebar requires this, or content will be clipped at the top of the screen. */
   #main-window[sizemode="maximized"][chromemargin^="0,"] {
     margin-top: 8px;
   }
 
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1810,17 +1810,13 @@ listitem.style-section {
   color: black;
   font-weight: bold;
 }
 
 panel[dimmed="true"] {
   opacity: 0.5;
 }
 
-/* Tab Context Menu */
-#context_tabViewMenu {
-  list-style-image: url(chrome://browser/skin/tabview/tabview-16.png);
-}
+/* Tab view context menu */
 
 #context_tabViewMenuPopup > menuitem.group {
-  padding-left: 40px;
+  -moz-padding-start: 40px;
 }
-
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -91,17 +91,16 @@ browser.jar:
         skin/classic/browser/tabbrowser/tab-arrow-left.png                      (tabbrowser/tab-arrow-left.png)
         skin/classic/browser/tabbrowser/tabDragIndicator.png                    (tabbrowser/tabDragIndicator.png)
         skin/classic/browser/tabview/edit-light.png                 (tabview/edit-light.png)
         skin/classic/browser/tabview/edit.png                       (tabview/edit.png)
         skin/classic/browser/tabview/new-tab.png                    (tabview/new-tab.png)
         skin/classic/browser/tabview/tabview.css                    (tabview/tabview.css)
         skin/classic/browser/tabview/stack-expander.png             (tabview/stack-expander.png)
         skin/classic/browser/tabview/tabview.png                    (tabview/tabview.png)
-        skin/classic/browser/tabview/tabview-16.png                  (tabview/tabview-16.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/sync-16-throbber.png
         skin/classic/browser/sync-16.png
         skin/classic/browser/sync-32.png
         skin/classic/browser/sync-bg.png
         skin/classic/browser/sync-desktopIcon.png
         skin/classic/browser/sync-merge.png
         skin/classic/browser/sync-mobileIcon.png
@@ -206,17 +205,16 @@ browser.jar:
         skin/classic/aero/browser/tabbrowser/tab-arrow-left.png                 (tabbrowser/tab-arrow-left.png)
         skin/classic/aero/browser/tabbrowser/tabDragIndicator.png               (tabbrowser/tabDragIndicator.png)
         skin/classic/aero/browser/tabview/edit-light.png             (tabview/edit-light.png)
         skin/classic/aero/browser/tabview/edit.png                   (tabview/edit.png)
         skin/classic/aero/browser/tabview/new-tab.png                (tabview/new-tab.png)
         skin/classic/aero/browser/tabview/tabview.css                (tabview/tabview.css)
         skin/classic/aero/browser/tabview/stack-expander.png         (tabview/stack-expander.png)
         skin/classic/aero/browser/tabview/tabview.png                (tabview/tabview.png)
-        skin/classic/aero/browser/tabview/tabview-16.png             (tabview/tabview-16.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/sync-16-throbber.png
         skin/classic/aero/browser/sync-16.png
         skin/classic/aero/browser/sync-32.png
         skin/classic/aero/browser/sync-bg.png
         skin/classic/aero/browser/sync-desktopIcon.png
         skin/classic/aero/browser/sync-merge.png
         skin/classic/aero/browser/sync-mobileIcon.png
--- a/browser/themes/winstripe/browser/preferences/preferences.css
+++ b/browser/themes/winstripe/browser/preferences/preferences.css
@@ -40,69 +40,69 @@
 
 /* Global Styles */
 #BrowserPreferences radio[pane] {
   list-style-image: url("chrome://browser/skin/preferences/Options.png"); 
   padding: 5px 3px 1px;
 }
 
 radio[pane=paneMain] {
-	-moz-image-region: rect(0px, 32px,  32px, 0px)
+  -moz-image-region: rect(0, 32px,  32px, 0);
 }
-radio[pane=paneMain]:hover, 
-radio[pane=paneMain][selected="true"]  {
-	-moz-image-region: rect(32px, 32px,  64px, 0px)
+radio[pane=paneMain]:hover,
+radio[pane=paneMain][selected="true"] {
+  -moz-image-region: rect(32px, 32px,  64px, 0);
 }
 
 radio[pane=paneTabs] {
-	-moz-image-region: rect(0px, 64px, 32px, 32px)
+  -moz-image-region: rect(0, 64px, 32px, 32px);
 }
-radio[pane=paneTabs]:hover, 
+radio[pane=paneTabs]:hover,
 radio[pane=paneTabs][selected="true"] {
-	-moz-image-region: rect(32px, 64px, 64px, 32px)
+  -moz-image-region: rect(32px, 64px, 64px, 32px);
 }
 
 radio[pane=paneContent] {
-	-moz-image-region: rect(0px, 96px,  32px, 64px)
+  -moz-image-region: rect(0, 96px,  32px, 64px);
 }
-radio[pane=paneContent]:hover, 
-radio[pane=paneContent][selected="true"]  {
-	-moz-image-region: rect(32px, 96px,  64px, 64px)
+radio[pane=paneContent]:hover,
+radio[pane=paneContent][selected="true"] {
+  -moz-image-region: rect(32px, 96px,  64px, 64px);
 }
 
 radio[pane=paneApplications] {
-	-moz-image-region: rect(0px, 128px,  32px, 96px)
+  -moz-image-region: rect(0, 128px,  32px, 96px);
 }
-radio[pane=paneApplications]:hover, 
-radio[pane=paneApplications][selected="true"]  {
-	-moz-image-region: rect(32px, 128px,  64px, 96px)
+radio[pane=paneApplications]:hover,
+radio[pane=paneApplications][selected="true"] {
+  -moz-image-region: rect(32px, 128px,  64px, 96px);
 }
 
 radio[pane=panePrivacy] {
-	-moz-image-region: rect(0px, 160px,  32px, 128px)
+  -moz-image-region: rect(0, 160px,  32px, 128px);
 }
-radio[pane=panePrivacy]:hover, 
-radio[pane=panePrivacy][selected="true"]  {
-	-moz-image-region: rect(32px, 160px,  64px, 128px)
+radio[pane=panePrivacy]:hover,
+radio[pane=panePrivacy][selected="true"] {
+  -moz-image-region: rect(32px, 160px,  64px, 128px);
 }
 
 radio[pane=paneSecurity] {
-	-moz-image-region: rect(0px, 192px,  32px, 160px)
+  -moz-image-region: rect(0, 192px,  32px, 160px);
 }
-radio[pane=paneSecurity]:hover, 
-radio[pane=paneSecurity][selected="true"]  {
-	-moz-image-region: rect(32px, 192px,  64px, 160px)
+radio[pane=paneSecurity]:hover,
+radio[pane=paneSecurity][selected="true"] {
+  -moz-image-region: rect(32px, 192px,  64px, 160px);
 }
 
 radio[pane=paneAdvanced] {
-	-moz-image-region: rect(0px, 224px, 32px, 192px)
+  -moz-image-region: rect(0, 224px, 32px, 192px);
 }
-radio[pane=paneAdvanced]:hover, 
+radio[pane=paneAdvanced]:hover,
 radio[pane=paneAdvanced][selected="true"] {
-	-moz-image-region: rect(32px, 224px, 64px, 192px)
+  -moz-image-region: rect(32px, 224px, 64px, 192px);
 }
 
 %ifdef MOZ_SERVICES_SYNC
 radio[pane=paneSync] {
   list-style-image: url("chrome://browser/skin/preferences/Options-sync.png") !important;
 }
 %endif
 
@@ -125,49 +125,49 @@ radio[pane=paneSync] {
 
 .inline-link:not(:focus) {
   outline: 1px dotted transparent;
 }
 
 /* Modeless Window Dialogs */
 .windowDialog,
 .windowDialog prefpane {
-  padding: 0px;
+  padding: 0;
 }
 
 .contentPane {
-  margin: 9px 8px 5px 8px;
+  margin: 9px 8px 5px;
 }
 
 .actionButtons {
-  margin: 0px 3px 6px 3px !important;
+  margin: 0 3px 6px !important;
 }
 
 /* Cookies Manager */
 #cookiesChildren::-moz-tree-image(domainCol) {
   width: 16px;
   height: 16px;
-  margin: 0px 2px;
+  margin: 0 2px;
   list-style-image: url("chrome://global/skin/icons/folder-item.png") !important;
-  -moz-image-region: rect(0px, 16px, 16px, 0px);
+  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 #cookiesChildren::-moz-tree-image(domainCol, container) {
-  -moz-image-region: rect(0px, 32px, 16px, 16px);
+  -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #cookiesChildren::-moz-tree-image(domainCol, container, open) {
   -moz-image-region: rect(16px, 32px, 32px, 16px);
 }
 
 #cookieInfoBox {
   border: 1px solid ThreeDShadow;
-  -moz-border-radius: 0px;
+  -moz-border-radius: 0;
   margin: 4px;
-  padding: 0px;
+  padding: 0;
 }
 
 /* Advanced Pane */
 
 /* Adding padding-bottom prevents the bottom of the tabpanel from being cutoff
    when browser.preferences.animateFadeIn = true */
 #advancedPrefs {
   padding-bottom: 8px;
deleted file mode 100644
index 87e7e3f73326b7a30e0ed547f209196d8c2c6102..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.pl.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-2.0b4pre
+2.0b5pre
--- a/configure.in
+++ b/configure.in
@@ -65,17 +65,16 @@ dnl ====================================
 AC_PREREQ(2.13)
 AC_INIT(config/config.mk)
 AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf)
 AC_CANONICAL_SYSTEM
 TARGET_CPU="${target_cpu}"
 TARGET_VENDOR="${target_vendor}"
 TARGET_OS="${target_os}"
 
-
 MOZ_DEB_TIMESTAMP=`date +"%a, %d  %b %Y %T %z"   2>&1` 
 AC_SUBST(MOZ_DEB_TIMESTAMP)
 
 dnl ========================================================
 dnl =
 dnl = Don't change the following two lines.  Doing so breaks:
 dnl =
 dnl = CFLAGS="-foo" ./configure
@@ -5279,17 +5278,17 @@ dnl ====================================
 if test "$MOZ_ENABLE_QT"
 then
     MOZ_ARG_WITH_STRING(qtdir,
     [  --with-qtdir=\$dir       Specify Qt directory ],
     [ QTDIR=$withval])
 
     if test -z "$QTDIR"; then
         PKG_CHECK_MODULES(MOZ_QT, QtGui QtNetwork QtCore QtOpenGL)
-        AC_CHECK_PROGS(HOST_MOC, moc, "")
+        AC_CHECK_PROGS(HOST_MOC, $MOC moc, "")
     else
         MOZ_QT_LIBS="-L$QTDIR/lib/ -lQtGui -lQtNetwork -lQtCore -lQtDBus -lQtXml -lQtOpenGL"
 
         MOZ_QT_CFLAGS="-DQT_SHARED"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/Qt"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtGui"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtCore"
@@ -8060,16 +8059,20 @@ fi
 if test -n "$MOZ_ENABLE_LIBXUL" -a -n "$BUILD_STATIC_LIBS"; then
 	AC_MSG_ERROR([--enable-libxul is not compatible with --enable-static])
 fi
 
 if test -n "$MOZ_IPC" -a -z "$MOZ_ENABLE_LIBXUL"; then
     AC_MSG_ERROR([--enable-ipc requires --enable-libxul])
 fi
 
+if test -z "$MOZ_ENABLE_LIBXUL" -a -n "$MOZ_OMNIJAR"; then
+    AC_MSG_ERROR([Omnijar packaging is incompatible with --disable-libxul. Please either --enable-libxul or --enable-chrome-format=jar|flat|symlink]);
+fi
+
 AC_SUBST(LIBXUL_LIBS)
 
 if test -n "$MOZ_ENABLE_LIBXUL"; then
     XPCOM_LIBS="$LIBXUL_LIBS"
     AC_DEFINE(MOZ_ENABLE_LIBXUL)
 else
     if test -n "$BUILD_STATIC_LIBS"; then
         AC_DEFINE(MOZ_STATIC_BUILD)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1671,16 +1671,33 @@ public:
   /**
    * Determine whether a content node is focused or not,
    *
    * @param aContent the content node to check
    * @return true if the content node is focused, false otherwise.
    */
   static PRBool IsFocusedContent(nsIContent *aContent);
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  static void SetActiveFrameLoader(nsFrameLoader *aFrameLoader)
+  {
+    sActiveFrameLoader = aFrameLoader;
+  }
+
+  static void ClearActiveFrameLoader(const nsFrameLoader *aFrameLoader)
+  {
+    if (sActiveFrameLoader == aFrameLoader)
+      sActiveFrameLoader = nsnull;
+  }
+
+  static already_AddRefed<nsFrameLoader> GetActiveFrameLoader();
+#endif
+#endif
+
 private:
 
   static PRBool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
 
@@ -1760,16 +1777,22 @@ private:
   static PRUint32 sRemovableScriptBlockerCount;
   static nsCOMArray<nsIRunnable>* sBlockedScriptRunners;
   static PRUint32 sRunnersCountAtFirstBlocker;
   static PRUint32 sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static PRBool sIsHandlingKeyBoardEvent;
+
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  static nsFrameLoader *sActiveFrameLoader;
+#endif
+#endif
 };
 
 #define NS_HOLD_JS_OBJECTS(obj, clazz)                                         \
   nsContentUtils::HoldJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz),        \
                                 &NS_CYCLE_COLLECTION_NAME(clazz))
 
 #define NS_DROP_JS_OBJECTS(obj, clazz)                                         \
   nsContentUtils::DropJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz))
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -99,32 +99,33 @@ class nsIDOMUserDataHandler;
 template<class E> class nsCOMArray;
 class nsIDocumentObserver;
 class nsBindingManager;
 class nsIDOMNodeList;
 class mozAutoSubtreeModified;
 struct JSObject;
 class nsFrameLoader;
 class nsIBoxObject;
+class imgIRequest;
 
 namespace mozilla {
 namespace css {
 class Loader;
 } // namespace css
 
 namespace dom {
 class Link;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 
 #define NS_IDOCUMENT_IID      \
-{ 0xb2274bc3, 0x4a1c, 0x4e64, \
-  { 0x8d, 0xe4, 0x3b, 0xc6, 0x50, 0x28, 0x84, 0x38 } }
+{ 0x0218352e, 0x9ddf, 0x43b0, \
+  { 0xb6, 0x1d, 0xd3, 0x1a, 0x47, 0x7a, 0xfd, 0x89 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Document states
 
 // RTL locale: specific to the XUL localedir attribute
 #define NS_DOCUMENT_STATE_RTL_LOCALE              (1 << 0)
@@ -1420,16 +1421,40 @@ public:
   virtual Element* LookupImageElement(const nsAString& aElementId) = 0;
 
   void ScheduleBeforePaintEvent();
   void BeforePaintEventFiring()
   {
     mHavePendingPaint = PR_FALSE;
   }
 
+  // This returns true when the document tree is being teared down.
+  PRBool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; }
+
+  /*
+   * Image Tracking
+   *
+   * Style and content images register their imgIRequests with their document
+   * so that the document can efficiently tell all descendant images when they
+   * are and are not visible. When an image is on-screen, we want to call
+   * LockImage() on it so that it doesn't do things like discarding frame data
+   * to save memory. The PresShell informs the document whether its images
+   * should be locked or not via SetImageLockingState().
+   *
+   * See bug 512260.
+   */
+
+  // Add/Remove images from the document image tracker
+  virtual nsresult AddImage(imgIRequest* aImage) = 0;
+  virtual nsresult RemoveImage(imgIRequest* aImage) = 0;
+
+  // Makes the images on this document locked/unlocked. By default, the locking
+  // state is unlocked/false.
+  virtual nsresult SetImageLockingState(PRBool aLocked) = 0;
+
 protected:
   ~nsIDocument()
   {
     // XXX The cleanup of mNodeInfoManager (calling DropDocumentReference and
     //     releasing it) happens in the nsDocument destructor. We'd prefer to
     //     do it here but nsNodeInfoManager is a concrete class that we don't
     //     want to expose to users of the nsIDocument API outside of Gecko.
   }
@@ -1556,16 +1581,19 @@ protected:
   PRPackedBool mAllowDNSPrefetch;
   
   // True when this document is a static clone of a normal document
   PRPackedBool mIsStaticDocument;
 
   // True while this document is being cloned to a static document.
   PRPackedBool mCreatingStaticClone;
 
+  // True iff the document is being unlinked or deleted.
+  PRPackedBool mInUnlinkOrDeletion;
+
   // True if document has ever had script handling object.
   PRPackedBool mHasHadScriptHandlingObject;
 
   // True if we're waiting for a before-paint event.
   PRPackedBool mHavePendingPaint;
 
   // The document's script global object, the object from which the
   // document can get its script context and scope. This is the
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -261,16 +261,22 @@ JSRuntime *nsAutoGCRoot::sJSScriptRuntim
 
 PRBool nsContentUtils::sIsHandlingKeyBoardEvent = PR_FALSE;
 
 PRBool nsContentUtils::sInitialized = PR_FALSE;
 
 nsRefPtrHashtable<nsPrefObserverHashKey, nsPrefOldCallback>
   *nsContentUtils::sPrefCallbackTable = nsnull;
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+nsFrameLoader *nsContentUtils::sActiveFrameLoader = nsnull;
+#endif
+#endif
+
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
 public:
   EventListenerManagerMapEntry(const void *aKey)
     : mKey(aKey)
   {
@@ -6204,16 +6210,27 @@ mozAutoRemovableBlockerRemover::~mozAuto
 PRBool
 nsContentUtils::IsFocusedContent(nsIContent* aContent)
 {
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 
   return fm && fm->GetFocusedContent() == aContent;
 }
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+// static
+already_AddRefed<nsFrameLoader>
+nsContentUtils::GetActiveFrameLoader()
+{
+  return nsCOMPtr<nsFrameLoader>(sActiveFrameLoader).forget();
+}
+#endif
+#endif
+
 void nsContentUtils::RemoveNewlines(nsString &aString)
 {
   // strip CR/LF and null
   static const char badChars[] = {'\r', '\n', 0};
   aString.StripChars(badChars);
 }
 
 void
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1484,16 +1484,17 @@ nsDocument::~nsDocument()
            ("DOCUMENT %p destroyed", this));
 #endif
 
 #ifdef DEBUG
   nsCycleCollector_DEBUG_wasFreed(static_cast<nsIDocument*>(this));
 #endif
 
   mInDestructor = PR_TRUE;
+  mInUnlinkOrDeletion = PR_TRUE;
 
   // Clear mObservers to keep it in sync with the mutationobserver list
   mObservers.Clear();
 
   if (mStyleSheetSetList) {
     mStyleSheetSetList->Disconnect();
   }
 
@@ -1571,16 +1572,21 @@ nsDocument::~nsDocument()
     delete mBoxObjectTable;
   }
 
   mPendingTitleChangeEvent.Revoke();
 
   for (PRUint32 i = 0; i < mFileDataUris.Length(); ++i) {
     nsFileDataProtocolHandler::RemoveFileDataEntry(mFileDataUris[i]);
   }
+
+  // We don't want to leave residual locks on images. Make sure we're in an
+  // unlocked state, and then clear the table.
+  SetImageLockingState(PR_FALSE);
+  mImageTracker.Clear();
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
 
 NS_INTERFACE_TABLE_HEAD(nsDocument)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsDocument)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
@@ -1763,16 +1769,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
+  tmp->mInUnlinkOrDeletion = PR_TRUE;
+
   // Clear out our external resources
   tmp->mExternalResourceMap.Shutdown();
 
   nsAutoScriptBlocker scriptBlocker;
 
   // Unlink the mChildren nsAttrAndChildArray.
   for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()) - 1; 
        indx >= 0; --indx) {
@@ -1802,16 +1810,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
  }
 
   // nsDocument has a pretty complex destructor, so we're going to
   // assume that *most* cycles you actually want to break somewhere
   // else, and not unlink an awful lot here.
   //
   // In rare cases where you think an unlink will help here, add one
   // manually.
+
+  tmp->mInUnlinkOrDeletion = PR_FALSE;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 nsresult
 nsDocument::Init()
 {
   if (mCSSLoader || mNodeInfoManager || mScriptLoader) {
     return NS_ERROR_ALREADY_INITIALIZED;
@@ -1853,16 +1863,20 @@ nsDocument::Init()
   mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
   NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ASSERTION(GetOwnerDoc() == this, "Our nodeinfo is busted!");
 
   mScriptLoader = new nsScriptLoader(this);
   NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY);
 
+  if (!mImageTracker.Init()) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
   return NS_OK;
 }
 
 void 
 nsIDocument::DeleteAllProperties()
 {
   for (PRUint32 i = 0; i < GetPropertyTableCount(); ++i) {
     PropertyTable(i)->DeleteAllProperties();
@@ -1959,32 +1973,35 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
 
     mSubDocuments = nsnull;
   }
 
   // Destroy link map now so we don't waste time removing
   // links one by one
   DestroyElementMaps();
 
+  PRBool oldVal = mInUnlinkOrDeletion;
+  mInUnlinkOrDeletion = PR_TRUE;
   PRUint32 count = mChildren.ChildCount();
   { // Scope for update
     MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, PR_TRUE);    
     for (PRInt32 i = PRInt32(count) - 1; i >= 0; i--) {
       nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
 
       nsIContent* previousSibling = content->GetPreviousSibling();
 
       if (nsINode::GetFirstChild() == content) {
         mFirstChild = content->GetNextSibling();
       }
       mChildren.RemoveChildAt(i);
       nsNodeUtils::ContentRemoved(this, content, i, previousSibling);
       content->UnbindFromTree();
     }
   }
+  mInUnlinkOrDeletion = oldVal;
   mCachedRootElement = nsnull;
 
   // Reset our stylesheets
   ResetStylesheetsToURI(aURI);
   
   // Release the listener manager
   if (mListenerManager) {
     mListenerManager->Disconnect();
@@ -6943,20 +6960,23 @@ nsDocument::Destroy()
   // to drop any references to the document so that it can be destroyed.
   if (mIsGoingAway)
     return;
 
   mIsGoingAway = PR_TRUE;
 
   RemovedFromDocShell();
 
+  PRBool oldVal = mInUnlinkOrDeletion;
+  mInUnlinkOrDeletion = PR_TRUE;
   PRUint32 i, count = mChildren.ChildCount();
   for (i = 0; i < count; ++i) {
     mChildren.ChildAt(i)->DestroyContent();
   }
+  mInUnlinkOrDeletion = oldVal;
 
   mLayoutHistoryState = nsnull;
 
   // Shut down our external resource map.  We might not need this for
   // leak-fixing if we fix DocumentViewerImpl to do cycle-collection, but
   // tearing down all those frame trees right now is the right thing to do.
   mExternalResourceMap.Shutdown();
 
@@ -7945,8 +7965,99 @@ nsIDocument::ScheduleBeforePaintEvent()
     // paint even if we're frozen.  Either we'll get unfrozen and then the
     // event will fire, or we'll quietly go away at some point.
     mHavePendingPaint =
       !mPresShell ||
       mPresShell->GetPresContext()->RefreshDriver()->
         ScheduleBeforePaintEvent(this);
   }
 }
+
+nsresult
+nsDocument::AddImage(imgIRequest* aImage)
+{
+  NS_ENSURE_ARG_POINTER(aImage);
+
+  // See if the image is already in the hashtable. If it is, get the old count.
+  PRUint32 oldCount = 0;
+  mImageTracker.Get(aImage, &oldCount);
+
+  // Put the image in the hashtable, with the proper count.
+  PRBool success = mImageTracker.Put(aImage, oldCount + 1);
+  if (!success)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  // If this is the first insertion and we're locking images, lock this image
+  // too.
+  if ((oldCount == 0) && mLockingImages) {
+    nsresult rv = aImage->LockImage();
+    NS_ENSURE_SUCCESS(rv, rv);
+    return aImage->RequestDecode();
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsDocument::RemoveImage(imgIRequest* aImage)
+{
+  NS_ENSURE_ARG_POINTER(aImage);
+
+  // Get the old count. It should exist and be > 0.
+  PRUint32 count;
+  PRBool found = mImageTracker.Get(aImage, &count);
+  NS_ABORT_IF_FALSE(found, "Removing image that wasn't in the tracker!");
+  NS_ABORT_IF_FALSE(count > 0, "Entry in the cache tracker with count 0!");
+
+  // We're removing, so decrement the count.
+  count--;
+
+  // If the count is now zero, remove from the tracker.
+  // Otherwise, set the new value.
+  if (count == 0) {
+    mImageTracker.Remove(aImage);
+  } else {
+    mImageTracker.Put(aImage, count);
+  }
+
+  // If we removed the image from the tracker and we're locking images, unlock
+  // this image.
+  if ((count == 0) && mLockingImages)
+    return aImage->UnlockImage();
+
+  return NS_OK;
+}
+
+PLDHashOperator LockEnumerator(imgIRequest* aKey,
+                               PRUint32 aData,
+                               void*    userArg)
+{
+  aKey->LockImage();
+  aKey->RequestDecode();
+  return PL_DHASH_NEXT;
+}
+
+PLDHashOperator UnlockEnumerator(imgIRequest* aKey,
+                                 PRUint32 aData,
+                                 void*    userArg)
+{
+  aKey->UnlockImage();
+  return PL_DHASH_NEXT;
+}
+
+
+nsresult
+nsDocument::SetImageLockingState(PRBool aLocked)
+{
+  // If there's no change, there's nothing to do.
+  if (mLockingImages == aLocked)
+    return NS_OK;
+
+  // Otherwise, iterate over our images and perform the appropriate action.
+  mImageTracker.EnumerateRead(aLocked ? LockEnumerator
+                                      : UnlockEnumerator,
+                              nsnull);
+
+  // Update state.
+  mLockingImages = aLocked;
+
+  return NS_OK;
+}
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -971,16 +971,20 @@ public:
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
 
   virtual Element *GetElementById(const nsAString& aElementId);
 
   virtual Element *LookupImageElement(const nsAString& aElementId);
 
+  virtual NS_HIDDEN_(nsresult) AddImage(imgIRequest* aImage);
+  virtual NS_HIDDEN_(nsresult) RemoveImage(imgIRequest* aImage);
+  virtual NS_HIDDEN_(nsresult) SetImageLockingState(PRBool aLocked);
+
 protected:
   friend class nsNodeUtils;
 
   /**
    * Check that aId is not empty and log a message to the console
    * service if it is.
    * @returns PR_TRUE if aId looks correct, PR_FALSE otherwise.
    */
@@ -1131,16 +1135,19 @@ protected:
 
   PRPackedBool mInXBLUpdate:1;
 
   // This flag is only set in nsXMLDocument, for e.g. documents used in XBL. We
   // don't want animations to play in such documents, so we need to store the
   // flag here so that we can check it in nsDocument::GetAnimationController.
   PRPackedBool mLoadedAsInteractiveData:1;
 
+  // Whether we're currently holding a lock on all of our images.
+  PRPackedBool mLockingImages:1;
+
   PRUint8 mXMLDeclarationBits;
 
   PRUint8 mDefaultElementType;
 
   nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject> *mBoxObjectTable;
 
   // The channel that got passed to StartDocumentLoad(), if any
   nsCOMPtr<nsIChannel> mChannel;
@@ -1230,16 +1237,19 @@ private:
   nsCOMArray<imgIRequest> mPreloadingImages;
 
   nsCOMPtr<nsIDOMDOMImplementation> mDOMImplementation;
 
   nsCString mScrollToRef;
   PRUint8 mScrolledToRefAlready : 1;
   PRUint8 mChangeScrollPosWhenScrollingToRef : 1;
 
+  // Tracking for images in the document.
+  nsDataHashtable< nsPtrHashKey<imgIRequest>, PRUint32> mImageTracker;
+
 #ifdef DEBUG
 protected:
   PRBool mWillReparent;
 #endif
 };
 
 #define NS_DOCUMENT_INTERFACE_TABLE_BEGIN(_class)                             \
   NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class)                            \
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -85,16 +85,17 @@
 #include "nsIDOMEventTarget.h"
 #include "nsIFrame.h"
 #include "nsIFrameFrame.h"
 #include "nsDOMError.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsISHistory.h"
 #include "nsISHistoryInternal.h"
+#include "nsIDocShellHistory.h"
 #include "nsIDOMNSHTMLDocument.h"
 #include "nsIXULWindow.h"
 
 #include "nsLayoutUtils.h"
 #include "nsIView.h"
 #include "nsPLDOMEvent.h"
 
 #include "nsIURI.h"
@@ -185,26 +186,26 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameL
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 nsFrameLoader*
-nsFrameLoader::Create(nsIContent* aOwner)
+nsFrameLoader::Create(nsIContent* aOwner, PRBool aNetworkCreated)
 {
   NS_ENSURE_TRUE(aOwner, nsnull);
   nsIDocument* doc = aOwner->GetOwnerDoc();
   NS_ENSURE_TRUE(doc && !doc->GetDisplayDocument() &&
                  ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) ||
                    doc->IsStaticDocument()),
                  nsnull);
 
-  return new nsFrameLoader(aOwner);
+  return new nsFrameLoader(aOwner, aNetworkCreated);
 }
 
 NS_IMETHODIMP
 nsFrameLoader::LoadFrame()
 {
   NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED);
 
   nsAutoString src;
@@ -1165,16 +1166,19 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   return NS_OK;
 }
 
 void
 nsFrameLoader::DestroyChild()
 {
 #ifdef MOZ_IPC
   if (mRemoteBrowser) {
+#ifdef ANDROID
+    nsContentUtils::ClearActiveFrameLoader(this);
+#endif
     mRemoteBrowser->SetOwnerElement(nsnull);
     // If this fails, it's most likely due to a content-process crash,
     // and auto-cleanup will kick in.  Otherwise, the child side will
     // destroy itself and send back __delete__().
     unused << mRemoteBrowser->SendDestroy();
     mRemoteBrowser = nsnull;
   }
 #endif
@@ -1191,27 +1195,37 @@ nsFrameLoader::Destroy()
   if (mMessageManager) {
     mMessageManager->Disconnect();
   }
   if (mChildMessageManager) {
     static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
   }
 
   nsCOMPtr<nsIDocument> doc;
+  PRBool dynamicSubframeRemoval = PR_FALSE;
   if (mOwnerContent) {
     doc = mOwnerContent->GetOwnerDoc();
 
     if (doc) {
+      dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
       doc->SetSubDocumentFor(mOwnerContent, nsnull);
     }
 
     mOwnerContent = nsnull;
   }
   DestroyChild();
-  
+
+  // Seems like this is a dynamic frame removal.
+  if (dynamicSubframeRemoval) {
+    nsCOMPtr<nsIDocShellHistory> dhistory = do_QueryInterface(mDocShell);
+    if (dhistory) {
+      dhistory->RemoveFromSessionHistory();
+    }
+  }
+
   // Let the tree owner know we're gone.
   if (mIsTopLevelContent) {
     nsCOMPtr<nsIDocShellTreeItem> ourItem = do_QueryInterface(mDocShell);
     if (ourItem) {
       nsCOMPtr<nsIDocShellTreeItem> parentItem;
       ourItem->GetParent(getter_AddRefs(parentItem));
       nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
       if (owner) {
@@ -1324,16 +1338,23 @@ nsFrameLoader::MaybeCreateDocShell()
   nsCOMPtr<nsISupports> container =
     doc->GetContainer();
   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(container);
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
+  if (!mNetworkCreated) {
+    nsCOMPtr<nsIDocShellHistory> history = do_QueryInterface(mDocShell);
+    if (history) {
+      history->SetCreatedDynamically(PR_TRUE);
+    }
+  }
+
   // Get the frame name and tell the docshell about it.
   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
   nsAutoString frameName;
 
   PRInt32 namespaceID = mOwnerContent->GetNameSpaceID();
   if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
@@ -1700,16 +1721,19 @@ nsFrameLoader::GetRemoteBrowser()
 }
 #endif
 
 NS_IMETHODIMP
 nsFrameLoader::ActivateRemoteFrame() {
 #ifdef MOZ_IPC
   if (mRemoteBrowser) {
     mRemoteBrowser->Activate();
+#ifdef ANDROID
+    nsContentUtils::SetActiveFrameLoader(this);
+#endif
     return NS_OK;
   }
 #endif
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
 nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -79,25 +79,26 @@ class nsFrameLoader : public nsIFrameLoa
 {
   friend class AutoResetInShow;
 #ifdef MOZ_IPC
   typedef mozilla::dom::PBrowserParent PBrowserParent;
   typedef mozilla::dom::TabParent TabParent;
 #endif
 
 protected:
-  nsFrameLoader(nsIContent *aOwner) :
+  nsFrameLoader(nsIContent *aOwner, PRBool aNetworkCreated) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
     mDestroyCalled(PR_FALSE),
     mNeedsAsyncDestroy(PR_FALSE),
     mInSwap(PR_FALSE),
     mInShow(PR_FALSE),
-    mHideCalled(PR_FALSE)
+    mHideCalled(PR_FALSE),
+    mNetworkCreated(aNetworkCreated)
 #ifdef MOZ_IPC
     , mDelayRemoteDialogs(PR_FALSE)
     , mRemoteWidgetCreated(PR_FALSE)
     , mRemoteFrame(false)
     , mRemoteBrowser(nsnull)
 #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_WIDGET_QT)
     , mRemoteSocket(nsnull)
 #endif
@@ -108,17 +109,17 @@ public:
   ~nsFrameLoader() {
     mNeedsAsyncDestroy = PR_TRUE;
     if (mMessageManager) {
       mMessageManager->Disconnect();
     }
     nsFrameLoader::Destroy();
   }
 
-  static nsFrameLoader* Create(nsIContent* aOwner);
+  static nsFrameLoader* Create(nsIContent* aOwner, PRBool aNetworkCreated);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsFrameLoader)
   NS_DECL_NSIFRAMELOADER
   NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI);
   nsresult ReallyStartLoading();
   void Finalize();
   nsIDocShell* GetExistingDocShell() { return mDocShell; }
@@ -216,16 +217,20 @@ public:
 private:
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
   PRPackedBool mInShow : 1;
   PRPackedBool mHideCalled : 1;
+  // True when the object is created for an element which the parser has
+  // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
+  // it may lose the flag.
+  PRPackedBool mNetworkCreated : 1;
 
 #ifdef MOZ_IPC
   PRPackedBool mDelayRemoteDialogs : 1;
   PRPackedBool mRemoteWidgetCreated : 1;
   bool mRemoteFrame;
   // XXX leaking
   nsCOMPtr<nsIObserver> mChildHost;
   TabParent* mRemoteBrowser;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1315,16 +1315,17 @@ GK_ATOM(mozAnimateMotionDummyAttr, "_moz
 GK_ATOM(onbegin, "onbegin")
 GK_ATOM(onbeginEvent, "onbeginEvent")
 GK_ATOM(onend, "onend")
 GK_ATOM(onendEvent, "onendEvent")
 GK_ATOM(onrepeat, "onrepeat")
 GK_ATOM(onrepeatEvent, "onrepeatEvent")
 GK_ATOM(repeatCount, "repeatCount")
 GK_ATOM(repeatDur, "repeatDur")
+GK_ATOM(repeatEvent, "repeatEvent")
 GK_ATOM(restart, "restart")
 GK_ATOM(to, "to")
 GK_ATOM(XML, "XML")
 #endif
 
 #ifdef MOZ_MATHML
 // internal MathML attributes: different from columnalign_, columnlines_,
 // fontstyle_, rowalign_ and rowlines_
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -518,20 +518,23 @@ nsImageLoadingContent::LoadImageWithChan
   // XXX what should we do with content policies here, if anything?
   // Shouldn't that be done before the start of the load?
   // XXX what about shouldProcess?
 
   // Our state might change. Watch it.
   AutoStateChanger changer(this, PR_TRUE);
 
   // Do the load.
+  nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
   nsresult rv = nsContentUtils::GetImgLoader()->
     LoadImageWithChannel(aChannel, this, doc, aListener,
-                         getter_AddRefs(PrepareNextRequest()));
-  if (NS_FAILED(rv)) {
+                         getter_AddRefs(req));
+  if (NS_SUCCEEDED(rv)) {
+    TrackImage(req);
+  } else {
     // If we don't have a current URI, we might as well store this URI so people
     // know what we tried (and failed) to load.
     if (!mCurrentRequest)
       aChannel->GetURI(getter_AddRefs(mCurrentURI));
     FireEvent(NS_LITERAL_STRING("error"));
     return rv;
   }
   return NS_OK;;
@@ -653,23 +656,26 @@ nsImageLoadingContent::LoadImage(nsIURI*
                                aDocument->NodePrincipal(), &cpDecision);
   if (!NS_CP_ACCEPTED(cpDecision)) {
     FireEvent(NS_LITERAL_STRING("error"));
     SetBlockedRequest(aNewURI, cpDecision);
     return NS_OK;
   }
 
   // Not blocked. Do the load.
+  nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
   nsresult rv;
   rv = nsContentUtils::LoadImage(aNewURI, aDocument,
                                  aDocument->NodePrincipal(),
                                  aDocument->GetDocumentURI(),
                                  this, aLoadFlags,
-                                 getter_AddRefs(PrepareNextRequest()));
-  if (NS_FAILED(rv)) {
+                                 getter_AddRefs(req));
+  if (NS_SUCCEEDED(rv)) {
+    TrackImage(req);
+  } else {
     // If we don't have a current URI, we might as well store this URI so people
     // know what we tried (and failed) to load.
     if (!mCurrentRequest)
       mCurrentURI = aNewURI;
     FireEvent(NS_LITERAL_STRING("error"));
     return NS_OK;
   }
 
@@ -764,19 +770,22 @@ nsImageLoadingContent::UseAsPrimaryReque
   // Our state will change. Watch it.
   AutoStateChanger changer(this, aNotify);
 
   // Get rid if our existing images
   ClearPendingRequest(NS_BINDING_ABORTED);
   ClearCurrentRequest(NS_BINDING_ABORTED);
 
   // Clone the request we were given.
-  nsCOMPtr<imgIRequest> newRequest;
-  nsresult rv = aRequest->Clone(this, getter_AddRefs(PrepareNextRequest()));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<imgIRequest>& req = PrepareNextRequest();;
+  nsresult rv = aRequest->Clone(this, getter_AddRefs(req));
+  if (NS_SUCCEEDED(rv))
+    TrackImage(req);
+  else
+    return rv;
 
   return NS_OK;
 }
 
 nsIDocument*
 nsImageLoadingContent::GetOurDocument()
 {
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
@@ -896,29 +905,31 @@ nsImageLoadingContent::ClearCurrentReque
     // a URI as a placeholder for a failed load. Clear that now.
     mCurrentURI = nsnull;
     return;
   }
   NS_ABORT_IF_FALSE(!mCurrentURI,
                     "Shouldn't have both mCurrentRequest and mCurrentURI!");
 
   // Clean up the request.
+  UntrackImage(mCurrentRequest);
   mCurrentRequest->CancelAndForgetObserver(aReason);
   mCurrentRequest = nsnull;
 
   // We only block onload during the decoding of "current" images. This one is
   // going away, so we should unblock unconditionally here.
   SetBlockingOnload(PR_FALSE);
 }
 
 void
 nsImageLoadingContent::ClearPendingRequest(nsresult aReason)
 {
   if (!mPendingRequest)
     return;
+  UntrackImage(mPendingRequest);
   mPendingRequest->CancelAndForgetObserver(aReason);
   mPendingRequest = nsnull;
 }
 
 bool
 nsImageLoadingContent::HaveSize(imgIRequest *aImage)
 {
   // Handle the null case
@@ -948,16 +959,38 @@ nsImageLoadingContent::SetBlockingOnload
     else
       doc->UnblockOnload(PR_FALSE);
 
     // Update our state
     mBlockingOnload = aBlocking;
   }
 }
 
+nsresult
+nsImageLoadingContent::TrackImage(imgIRequest* aImage)
+{
+  nsIDocument* doc = GetOurDocument();
+  if (doc)
+    return doc->AddImage(aImage);
+  return NS_OK;
+}
+
+nsresult
+nsImageLoadingContent::UntrackImage(imgIRequest* aImage)
+{
+  // If GetOurDocument() returns null here, we've outlived our document.
+  // That's fine, because the document empties out the tracker and unlocks
+  // all locked images on destruction.
+  nsIDocument* doc = GetOurDocument();
+  if (doc)
+    return doc->RemoveImage(aImage);
+  return NS_OK;
+}
+
+
 void
 nsImageLoadingContent::CreateStaticImageClone(nsImageLoadingContent* aDest) const
 {
   aDest->mCurrentRequest = nsContentUtils::GetStaticRequest(mCurrentRequest);
   aDest->mForcedImageState = mForcedImageState;
   aDest->mImageBlockingStatus = mImageBlockingStatus;
   aDest->mLoadingEnabled = mLoadingEnabled;
   aDest->mStateChangerDepth = mStateChangerDepth;
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -277,16 +277,22 @@ protected:
   void ClearPendingRequest(nsresult aReason);
 
   /**
    * Static helper method to tell us if we have the size of a request. The
    * image may be null.
    */
   static bool HaveSize(imgIRequest *aImage);
 
+  /**
+   * Adds/Removes a given imgIRequest from our document's tracker.
+   */
+  nsresult TrackImage(imgIRequest* aImage);
+  nsresult UntrackImage(imgIRequest* aImage);
+
   /* MEMBERS */
   nsCOMPtr<imgIRequest> mCurrentRequest;
   nsCOMPtr<imgIRequest> mPendingRequest;
 
   // If the image was blocked or if there was an error loading, it's nice to
   // still keep track of what the URI was despite not having an imgIRequest.
   // We only maintain this in those situations (in the common case, this is
   // always null).
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -291,17 +291,16 @@ nsInProcessTabChildGlobal::InitTabChildG
                (jsuword) -1;
 #endif
 
   JS_SetThreadStackLimit(cx, stackLimit);
   JS_SetScriptStackQuota(cx, 100*1024*1024);
 
   JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX | JSOPTION_PRIVATE_IS_NSISUPPORTS);
   JS_SetVersion(cx, JSVERSION_LATEST);
-  JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 1 * 1024 * 1024);
 
   JSAutoRequest ar(cx);
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
                          /*nsIXPConnect::OMIT_COMPONENTS_OBJECT ?  |*/
                          nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
 
   nsISupports* scopeSupports =
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -473,16 +473,17 @@ IsPluginEnabledByExtension(nsIURI* uri, 
 
 nsObjectLoadingContent::nsObjectLoadingContent()
   : mPendingInstantiateEvent(nsnull)
   , mChannel(nsnull)
   , mType(eType_Loading)
   , mInstantiating(PR_FALSE)
   , mUserDisabled(PR_FALSE)
   , mSuppressed(PR_FALSE)
+  , mNetworkCreated(PR_TRUE)
   , mFallbackReason(ePluginOtherState)
 {
 }
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   DestroyImageLoadingContent();
   if (mFrameLoader) {
@@ -627,17 +628,17 @@ nsObjectLoadingContent::OnStartRequest(n
       // final listener.
       if (!mFinalListener) {
         mType = newType;
         return NS_BINDING_ABORTED;
       }
       break;
     case eType_Document: {
       if (!mFrameLoader) {
-        mFrameLoader = nsFrameLoader::Create(thisContent);
+        mFrameLoader = nsFrameLoader::Create(thisContent, mNetworkCreated);
         if (!mFrameLoader) {
           Fallback(PR_FALSE);
           return NS_ERROR_UNEXPECTED;
         }
       }
 
       rv = mFrameLoader->CheckForRecursiveLoad(uri);
       if (NS_FAILED(rv)) {
@@ -1281,17 +1282,17 @@ nsObjectLoadingContent::LoadObject(nsIUR
     if (newType != mType) {
       LOG(("OBJLC [%p]: (eOverrideServerType) Changing type from %u to %u\n", this, mType, newType));
 
       UnloadContent();
 
       // Must have a frameloader before creating a frame, or the frame will
       // create its own.
       if (!mFrameLoader && newType == eType_Document) {
-        mFrameLoader = nsFrameLoader::Create(thisContent);
+        mFrameLoader = nsFrameLoader::Create(thisContent, mNetworkCreated);
         if (!mFrameLoader) {
           mURI = nsnull;
           return NS_OK;
         }
       }
 
       // Must notify here for plugins
       // If aNotify is false, we'll just wait until we get a frame and use the
@@ -1984,17 +1985,17 @@ nsObjectLoadingContent::CreateStaticClon
       const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame(eDontFlush);
     nsIFrame* f = do_QueryFrame(frame);
     aDest->mPrintFrame = f;
   }
 
   if (mFrameLoader) {
     nsCOMPtr<nsIContent> content =
       do_QueryInterface(static_cast<nsIImageLoadingContent*>((aDest)));
-    nsFrameLoader* fl = nsFrameLoader::Create(content);
+    nsFrameLoader* fl = nsFrameLoader::Create(content, PR_FALSE);
     if (fl) {
       aDest->mFrameLoader = fl;
       mFrameLoader->CreateStaticClone(fl);
     }
   }
 }
 
 NS_IMETHODIMP
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -129,16 +129,20 @@ class nsObjectLoadingContent : public ns
 
     /**
      * Object state. This is a bitmask consisting of a subset of
      * NS_EVENT_STATE_BROKEN, NS_EVENT_STATE_USERDISABLED and
      * NS_EVENT_STATE_SUPPRESSED representing the current state of the object.
      */
     PRInt32 ObjectState() const;
 
+    void SetIsNetworkCreated(PRBool aNetworkCreated)
+    {
+      mNetworkCreated = aNetworkCreated;
+    }
   protected:
     /**
      * Load the object from the given URI.
      * @param aURI       The URI to load.
      * @param aNotify If true, nsIDocumentObserver state change notifications
      *                will be sent as needed.
      * @param aTypeHint  MIME Type hint. Overridden by the server unless this
      *                   class has the eOverrideServerType capability.
@@ -394,16 +398,22 @@ class nsObjectLoadingContent : public ns
     /**
      * Whether we are about to call instantiate on our frame. If we aren't,
      * SetFrame needs to asynchronously call Instantiate.
      */
     PRPackedBool                mInstantiating : 1;
     // Blocking status from content policy
     PRPackedBool                mUserDisabled  : 1;
     PRPackedBool                mSuppressed    : 1;
+
+    // True when the object is created for an element which the parser has
+    // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
+    // it may lose the flag.
+    PRPackedBool                mNetworkCreated : 1;
+
     // A specific state that caused us to fallback
     PluginSupportState          mFallbackReason;
 
     nsWeakFrame                 mPrintFrame;
 
     friend class nsAsyncInstantiateEvent;
 };
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -39,16 +39,22 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+#include "mozilla/dom/PBrowserParent.h"
+#endif
+#endif
+
 #include "nsCOMPtr.h"
 #include "nsEventStateManager.h"
 #include "nsEventListenerManager.h"
 #include "nsIMEStateManager.h"
 #include "nsContentEventHandler.h"
 #include "nsIContent.h"
 #include "nsINodeInfo.h"
 #include "nsIDocument.h"
@@ -154,16 +160,22 @@
 #include "nsIController.h"
 #include "nsICommandParams.h"
 #include "mozilla/Services.h"
 
 #ifdef XP_MACOSX
 #import <ApplicationServices/ApplicationServices.h>
 #endif
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+#include "nsFrameLoader.h"
+#endif
+#endif
+
 //#define DEBUG_DOCSHELL_FOCUS
 
 #define NS_USER_INTERACTION_INTERVAL 5000 // ms
 
 static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
@@ -1364,16 +1376,50 @@ nsEventStateManager::PreHandleEvent(nsPr
       DoContentCommandEvent(static_cast<nsContentCommandEvent*>(aEvent));
     }
     break;
   case NS_CONTENT_COMMAND_SCROLL:
     {
       DoContentCommandScrollEvent(static_cast<nsContentCommandEvent*>(aEvent));
     }
     break;
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  case NS_TEXT_TEXT:
+    {
+      nsTextEvent *textEvent = static_cast<nsTextEvent*>(aEvent);
+      if (IsTargetCrossProcess(textEvent)) {
+        // Will not be handled locally, remote the event
+        mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+        if (remoteBrowser &&
+            remoteBrowser->SendTextEvent(*textEvent)) {
+          // Cancel local dispatching
+          *aStatus = nsEventStatus_eConsumeNoDefault;
+        }
+      }
+    }
+    break;
+  case NS_COMPOSITION_START:
+  case NS_COMPOSITION_END:
+    {
+      nsCompositionEvent *compositionEvent =
+          static_cast<nsCompositionEvent*>(aEvent);
+      if (IsTargetCrossProcess(compositionEvent)) {
+        // Will not be handled locally, remote the event
+        mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+        if (remoteBrowser &&
+            remoteBrowser->SendCompositionEvent(*compositionEvent)) {
+          // Cancel local dispatching
+          *aStatus = nsEventStatus_eConsumeNoDefault;
+        }
+      }
+    }
+    break;
+#endif
+#endif
   }
   return NS_OK;
 }
 
 static PRInt32
 GetAccessModifierMask(nsISupports* aDocShell)
 {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
@@ -3194,24 +3240,88 @@ nsEventStateManager::PostHandleEvent(nsP
       mCurrentTarget->GetContentForEvent(presContext, aEvent,
                                          getter_AddRefs(targetContent));
       if (!NodeAllowsClickThrough(targetContent)) {
         *aStatus = nsEventStatus_eConsumeNoDefault;
       }
     }
     break;
 #endif
+
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  case NS_QUERY_SELECTED_TEXT:
+  case NS_QUERY_TEXT_CONTENT:
+  case NS_QUERY_CARET_RECT:
+  case NS_QUERY_TEXT_RECT:
+  case NS_QUERY_EDITOR_RECT:
+  case NS_QUERY_CONTENT_STATE:
+  // We don't remote nsITransferable yet
+  //case NS_QUERY_SELECTION_AS_TRANSFERABLE:
+  case NS_QUERY_CHARACTER_AT_POINT:
+    {
+      nsQueryContentEvent *queryEvent =
+          static_cast<nsQueryContentEvent*>(aEvent);
+      // If local query failed, try remote query
+      if (queryEvent->mSucceeded)
+        break;
+
+      mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+      if (remoteBrowser &&
+          remoteBrowser->SendQueryContentEvent(*queryEvent)) {
+        queryEvent->mWasAsync = PR_TRUE;
+        queryEvent->mSucceeded = PR_TRUE;
+      }
+    }
+    break;
+  case NS_SELECTION_SET:
+    {
+      nsSelectionEvent *selectionEvent =
+          static_cast<nsSelectionEvent*>(aEvent);
+      // If local handler failed, try remoting the event
+      if (selectionEvent->mSucceeded)
+        break;
+
+      mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+      if (remoteBrowser &&
+          remoteBrowser->SendSelectionEvent(*selectionEvent))
+        selectionEvent->mSucceeded = PR_TRUE;
+    }
+    break;
+#endif // ANDROID
+#endif // MOZ_IPC
   }
 
   //Reset target frame to null to avoid mistargeting after reentrant event
   mCurrentTarget = nsnull;
 
   return ret;
 }
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+mozilla::dom::PBrowserParent*
+nsEventStateManager::GetCrossProcessTarget()
+{
+  nsCOMPtr<nsFrameLoader> fl = nsContentUtils::GetActiveFrameLoader();
+  NS_ENSURE_TRUE(fl, nsnull);
+  return fl->GetRemoteBrowser();
+}
+
+PRBool
+nsEventStateManager::IsTargetCrossProcess(nsGUIEvent *aEvent)
+{
+  nsQueryContentEvent stateEvent(PR_TRUE, NS_QUERY_CONTENT_STATE, aEvent->widget);
+  nsContentEventHandler handler(mPresContext);
+  handler.OnQueryContentState(&stateEvent);
+  return !stateEvent.mSucceeded;
+}
+#endif
+#endif
+
 NS_IMETHODIMP
 nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
 {
   nsIMEStateManager::OnDestroyPresContext(aPresContext);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -326,16 +326,23 @@ protected:
    * BeginTrackingDragGesture). aEvent->widget must be
    * mCurrentTarget->GetNearestWidget().
    */
   void FillInEventFromGestureDown(nsMouseEvent* aEvent);
 
   nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent);
   nsresult DoContentCommandScrollEvent(nsContentCommandEvent* aEvent);
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  mozilla::dom::PBrowserParent *GetCrossProcessTarget();
+  PRBool IsTargetCrossProcess(nsGUIEvent *aEvent);
+#endif
+#endif
+
   PRInt32     mLockCursor;
 
   nsWeakFrame mCurrentTarget;
   nsCOMPtr<nsIContent> mCurrentTargetContent;
   nsWeakFrame mLastMouseOverFrame;
   nsCOMPtr<nsIContent> mLastMouseOverElement;
   nsWeakFrame mLastDragOverFrame;
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2868,17 +2868,17 @@ nsGenericHTMLFrameElement::GetContentWin
 nsresult
 nsGenericHTMLFrameElement::EnsureFrameLoader()
 {
   if (!GetParent() || !IsInDoc() || mFrameLoader) {
     // If frame loader is there, we just keep it around, cached
     return NS_OK;
   }
 
-  mFrameLoader = nsFrameLoader::Create(this);
+  mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
 {
   NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
   return NS_OK;
@@ -2931,17 +2931,20 @@ nsGenericHTMLFrameElement::BindToTree(ns
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDocument) {
     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                  "Missing a script blocker!");
     // We're in a document now.  Kick off the frame load.
     LoadSrc();
   }
-  
+
+  // We're now in document and scripts may move us, so clear
+  // the mNetworkCreated flag.
+  mNetworkCreated = PR_FALSE;
   return rv;
 }
 
 void
 nsGenericHTMLFrameElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   if (mFrameLoader) {
     // This iframe is being taken out of the document, destroy the
@@ -2992,17 +2995,17 @@ nsGenericHTMLFrameElement::CopyInnerTo(n
 {
   nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsIDocument* doc = aDest->GetOwnerDoc();
   if (doc->IsStaticDocument() && mFrameLoader) {
     nsGenericHTMLFrameElement* dest =
       static_cast<nsGenericHTMLFrameElement*>(aDest);
-    nsFrameLoader* fl = nsFrameLoader::Create(dest);
+    nsFrameLoader* fl = nsFrameLoader::Create(dest, PR_FALSE);
     NS_ENSURE_STATE(fl);
     dest->mFrameLoader = fl;
     static_cast<nsFrameLoader*>(mFrameLoader.get())->CreateStaticClone(fl);
   }
 
   return rv;
 }
 
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -40,16 +40,17 @@
 
 #include "nsMappedAttributeElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsINameSpaceManager.h"  // for kNameSpaceID_None
 #include "nsIFormControl.h"
 #include "nsIDOMNSHTMLFrameElement.h"
 #include "nsFrameLoader.h"
 #include "nsGkAtoms.h"
+#include "nsContentCreatorFunctions.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIDOMNodeList;
 class nsIFrame;
 class nsIStyleRule;
 class nsChildContentList;
 class nsDOMCSSDeclaration;
@@ -904,19 +905,21 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_B
  * A helper class for frame elements
  */
 
 class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
                                   public nsIDOMNSHTMLFrameElement,
                                   public nsIFrameLoaderOwner
 {
 public:
-  nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+  nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                            PRUint32 aFromParser)
     : nsGenericHTMLElement(aNodeInfo)
   {
+    mNetworkCreated = aFromParser == NS_FROM_PARSER_NETWORK;
   }
   virtual ~nsGenericHTMLFrameElement();
 
   // nsISupports
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
 
   // nsIDOMNSHTMLFrameElement
   NS_DECL_NSIDOMNSHTMLFRAMEELEMENT
@@ -953,16 +956,20 @@ public:
 protected:
   // This doesn't really ensure a frame loade in all cases, only when
   // it makes sense.
   nsresult EnsureFrameLoader();
   nsresult LoadSrc();
   nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
 
   nsRefPtr<nsFrameLoader> mFrameLoader;
+  // True when the element is created by the parser
+  // using NS_FROM_PARSER_NETWORK flag.
+  // If the element is modified, it may lose the flag.
+  PRPackedBool            mNetworkCreated;
 };
 
 //----------------------------------------------------------------------
 
 /**
  * A macro to implement the NS_NewHTMLXXXElement() functions.
  */
 #define NS_IMPL_NS_NEW_HTML_ELEMENT(_elementName)                            \
--- a/content/html/content/src/nsHTMLFrameElement.cpp
+++ b/content/html/content/src/nsHTMLFrameElement.cpp
@@ -41,17 +41,18 @@
 #include "nsIDOMDocument.h"
 #include "nsDOMError.h"
 
 
 class nsHTMLFrameElement : public nsGenericHTMLFrameElement,
                            public nsIDOMHTMLFrameElement
 {
 public:
-  nsHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo);
+  nsHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                     PRUint32 aFromParser = NS_NOT_FROM_PARSER);
   virtual ~nsHTMLFrameElement();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE(nsGenericHTMLFrameElement::)
 
@@ -71,21 +72,22 @@ public:
                                 nsAttrValue& aResult);
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
 };
 
 
-NS_IMPL_NS_NEW_HTML_ELEMENT(Frame)
+NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Frame)
 
 
-nsHTMLFrameElement::nsHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLFrameElement(aNodeInfo)
+nsHTMLFrameElement::nsHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                                       PRUint32 aFromParser)
+  : nsGenericHTMLFrameElement(aNodeInfo, aFromParser)
 {
 }
 
 nsHTMLFrameElement::~nsHTMLFrameElement()
 {
 }
 
 
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -50,17 +50,18 @@
 
 class nsHTMLIFrameElement : public nsGenericHTMLFrameElement,
                             public nsIDOMHTMLIFrameElement
 #ifdef MOZ_SVG
                             , public nsIDOMGetSVGDocument
 #endif
 {
 public:
-  nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo);
+  nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                      PRUint32 aFromParser = NS_NOT_FROM_PARSER);
   virtual ~nsHTMLIFrameElement();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE(nsGenericHTMLFrameElement::)
 
@@ -86,21 +87,22 @@ public:
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
 };
 
 
-NS_IMPL_NS_NEW_HTML_ELEMENT(IFrame)
+NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
 
 
-nsHTMLIFrameElement::nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLFrameElement(aNodeInfo)
+nsHTMLIFrameElement::nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                                         PRUint32 aFromParser)
+  : nsGenericHTMLFrameElement(aNodeInfo, aFromParser)
 {
 }
 
 nsHTMLIFrameElement::~nsHTMLIFrameElement()
 {
 }
 
 
--- a/content/html/content/src/nsHTMLObjectElement.cpp
+++ b/content/html/content/src/nsHTMLObjectElement.cpp
@@ -146,16 +146,17 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER
 
 
 nsHTMLObjectElement::nsHTMLObjectElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                                          PRUint32 aFromParser)
   : nsGenericHTMLFormElement(aNodeInfo),
     mIsDoneAddingChildren(!aFromParser)
 {
   RegisterFreezableElement();
+  SetIsNetworkCreated(aFromParser == NS_FROM_PARSER_NETWORK);
 }
 
 nsHTMLObjectElement::~nsHTMLObjectElement()
 {
   UnregisterFreezableElement();
   DestroyImageLoadingContent();
 }
 
@@ -459,16 +460,17 @@ nsHTMLObjectElement::StartObjectLoad(PRB
     LoadObject(uri, aNotify, ctype);
   }
   else {
     // Be sure to call the nsIURI version if we have no attribute
     // That handles the case where no URI is specified. An empty string would
     // get interpreted as the page itself, instead of absence of URI.
     LoadObject(nsnull, aNotify, ctype);
   }
+  SetIsNetworkCreated(PR_FALSE);
 }
 
 PRInt32
 nsHTMLObjectElement::IntrinsicState() const
 {
   return nsGenericHTMLFormElement::IntrinsicState() | ObjectState();
 }
 
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2319,16 +2319,62 @@ nsHTMLDocument::RemovedForm()
 }
 
 PRInt32
 nsHTMLDocument::GetNumFormsSynchronous()
 {
   return mNumForms;
 }
 
+nsresult
+nsHTMLDocument::GetBodySize(PRInt32* aWidth,
+                            PRInt32* aHeight)
+{
+  *aWidth = *aHeight = 0;
+
+  FlushPendingNotifications(Flush_Layout);
+
+  // Find the <body> element: this is what we'll want to use for the
+  // document's width and height values.
+  Element* body = GetBodyElement();
+  if (!body) {
+    return NS_OK;
+  }
+
+  // Now grab its frame
+  nsIFrame* frame = body->GetPrimaryFrame();
+  if (!frame)
+    return NS_OK;
+  
+  nsSize size = frame->GetSize();
+
+  *aWidth = nsPresContext::AppUnitsToIntCSSPixels(size.width);
+  *aHeight = nsPresContext::AppUnitsToIntCSSPixels(size.height);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLDocument::GetWidth(PRInt32* aWidth)
+{
+  NS_ENSURE_ARG_POINTER(aWidth);
+
+  PRInt32 height;
+  return GetBodySize(aWidth, &height);
+}
+
+NS_IMETHODIMP
+nsHTMLDocument::GetHeight(PRInt32* aHeight)
+{
+  NS_ENSURE_ARG_POINTER(aHeight);
+
+  PRInt32 width;
+  return GetBodySize(&width, aHeight);
+}
+
 NS_IMETHODIMP
 nsHTMLDocument::GetAlinkColor(nsAString& aAlinkColor)
 {
   aAlinkColor.Truncate();
 
   nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
   if (body) {
     body->GetALink(aAlinkColor);
--- a/content/media/VideoUtils.cpp
+++ b/content/media/VideoUtils.cpp
@@ -1,45 +1,45 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla code.
- *
- * The Initial Developer of the Original Code is
- * the Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Chris Pearce <chris@pearce.org.nz>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Chris Pearce <chris@pearce.org.nz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
 #include "VideoUtils.h"
 #include "prtypes.h"
 
 // Adds two 32bit unsigned numbers, retuns PR_TRUE if addition succeeded,
 // or PR_FALSE the if addition would result in an overflow.
 PRBool AddOverflow32(PRUint32 a, PRUint32 b, PRUint32& aResult) {
   PRUint64 rl = static_cast<PRUint64>(a) + static_cast<PRUint64>(b);
   if (rl > PR_UINT32_MAX) {
--- a/content/media/wave/nsWaveDecoder.cpp
+++ b/content/media/wave/nsWaveDecoder.cpp
@@ -1178,23 +1178,23 @@ nsWaveStateMachine::FirePositionChanged(
   mPositionChangeQueued = PR_TRUE;
   nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(mDecoder, &nsWaveDecoder::PlaybackPositionChanged);
   NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
 }
 
 nsresult
 nsWaveStateMachine::GetBuffered(nsHTMLTimeRanges* aBuffered)
 {
-  PRInt64 startOffset = mStream->GetNextCachedData(mWavePCMOffset);
-  while (startOffset >= 0) {
-    PRInt64 endOffset = mStream->GetCachedDataEnd(startOffset);
-    // Bytes [startOffset..endOffset] are cached.
-    aBuffered->Add(BytesToTime(startOffset - mWavePCMOffset),
-                   BytesToTime(endOffset - mWavePCMOffset));
-    startOffset = mStream->GetNextCachedData(endOffset);
+  PRInt64 startOffset = mStream->GetNextCachedData(mWavePCMOffset);
+  while (startOffset >= 0) {
+    PRInt64 endOffset = mStream->GetCachedDataEnd(startOffset);
+    // Bytes [startOffset..endOffset] are cached.
+    aBuffered->Add(BytesToTime(startOffset - mWavePCMOffset),
+                   BytesToTime(endOffset - mWavePCMOffset));
+    startOffset = mStream->GetNextCachedData(endOffset);
   }
   return NS_OK;
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsWaveDecoder, nsIObserver)
 
 nsWaveDecoder::nsWaveDecoder()
   : mInitialVolume(1.0f),
--- a/content/smil/nsISMILAnimationElement.h
+++ b/content/smil/nsISMILAnimationElement.h
@@ -48,17 +48,16 @@
 #define NS_ISMILANIMATIONELEMENT_IID \
 { 0x5c891601, 0x47aa, 0x4230,        \
   { 0xb8, 0xdc, 0xb9, 0x26, 0xd1, 0xe7, 0xd7, 0xf4 } }
 
 class nsISMILAttr;
 class nsSMILAnimationFunction;
 class nsSMILTimeContainer;
 class nsSMILTimedElement;
-class nsIContent;
 class nsIAtom;
 class nsAttrValue;
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
@@ -70,24 +69,24 @@ enum nsSMILTargetAttrType {
 };
 
 class nsISMILAnimationElement : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISMILANIMATIONELEMENT_IID)
 
   /*
-   * Returns this element as nsIContent.
+   * Returns this element as a mozilla::dom::Element.
    */
-  virtual const nsIContent& Content() const = 0;
+  virtual const mozilla::dom::Element& AsElement() const = 0;
 
   /*
-   * Non-const version of Content()
+   * Non-const version of Element()
    */
-  virtual nsIContent& Content() = 0;
+  virtual mozilla::dom::Element& AsElement() = 0;
 
   /*
    * Returns the source attribute as an nsAttrValue. The global namespace will
    * be used.
    *
    * (The 'Anim' here and below is largely to avoid conflicts for subclasses
    * that derive from nsGenericElement)
    *
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -319,18 +319,18 @@ nsSMILAnimationFunction::CompareTo(const
     aOther->mAnimationElement->TimedElement();
   if (thisTimedElement.IsTimeDependent(otherTimedElement))
     return 1;
   if (otherTimedElement.IsTimeDependent(thisTimedElement))
     return -1;
 
   // Animations that appear later in the document sort after those earlier in
   // the document
-  nsIContent& thisContent = mAnimationElement->Content();
-  nsIContent& otherContent = aOther->mAnimationElement->Content();
+  nsIContent& thisContent = mAnimationElement->AsElement();
+  nsIContent& otherContent = aOther->mAnimationElement->AsElement();
 
   NS_ABORT_IF_FALSE(&thisContent != &otherContent,
       "Two animations cannot have the same animation content element!");
 
   return (nsContentUtils::PositionIsBefore(&thisContent, &otherContent))
           ? -1 : 1;
 }
 
@@ -459,18 +459,19 @@ nsSMILAnimationFunction::InterpolateResu
     }
   }
 
   // Discrete-CalcMode case
   // Note: If interpolation failed (isn't supported for this type), the SVG
   // spec says to force discrete mode.
   if (GetCalcMode() == CALC_DISCRETE || NS_FAILED(rv)) {
     if (IsToAnimation()) {
-      // Two discrete values: our base value, and the val in our array
-      aResult = (simpleProgress < 0.5f) ? aBaseValue : aValues[0];
+      // SMIL 3, 12.6.4: Since a to animation has only 1 value, a discrete to
+      // animation will simply set the to value for the simple duration.
+      aResult = aValues[0];
     } else {
       PRUint32 index = (PRUint32) floor(simpleProgress * (aValues.Length()));
       aResult = aValues[index];
     }
     rv = NS_OK;
   }
   return rv;
 }
--- a/content/smil/nsSMILInstanceTime.cpp
+++ b/content/smil/nsSMILInstanceTime.cpp
@@ -99,17 +99,17 @@ nsSMILInstanceTime::nsSMILInstanceTime(c
       break;
   }
 
   SetBaseInterval(aBaseInterval);
 }
 
 nsSMILInstanceTime::~nsSMILInstanceTime()
 {
-  NS_ABORT_IF_FALSE(!mBaseInterval && !mCreator,
+  NS_ABORT_IF_FALSE(!mBaseInterval,
       "Destroying instance time without first calling Unlink()");
   NS_ABORT_IF_FALSE(mFixedEndpointRefCnt == 0,
       "Destroying instance time that is still used as the fixed endpoint of an "
       "interval");
 }
 
 void
 nsSMILInstanceTime::Unlink()
--- a/content/smil/nsSMILInstanceTime.h
+++ b/content/smil/nsSMILInstanceTime.h
@@ -135,18 +135,19 @@ protected:
   const nsSMILInstanceTime* GetBaseTime() const;
 
   nsSMILTimeValue mTime;
 
   // Internal flags used to represent the behaviour of different instance times
   enum {
     // Indicates that this instance time was generated by an event or a DOM
     // call. Such instance times require special handling when (i) the owning
-    // element is reset, and (ii) when a backwards seek is performed and the
-    // timing model is reconstructed.
+    // element is reset, (ii) when they are to be added as a new end instance
+    // times (as per SMIL's event sensitivity contraints), and (iii) when
+    // a backwards seek is performed and the timing model is reconstructed.
     kDynamic = 1,
 
     // Indicates that this instance time is referred to by an
     // nsSMILTimeValueSpec and as such may be updated. Such instance time should
     // not be filtered out by the nsSMILTimedElement even if they appear to be
     // in the past as they may be updated to a future time.
     kMayUpdate = 2,
 
--- a/content/smil/nsSMILParserUtils.cpp
+++ b/content/smil/nsSMILParserUtils.cpp
@@ -55,17 +55,19 @@
 
 namespace {
 
 const PRUint32 MSEC_PER_SEC  = 1000;
 const PRUint32 MSEC_PER_MIN  = 1000 * 60;
 const PRUint32 MSEC_PER_HOUR = 1000 * 60 * 60;
 const PRInt32  DECIMAL_BASE  = 10;
 
-#define ACCESSKEY_PREFIX NS_LITERAL_STRING("accesskey(")
+// XXX SVG/SMIL Animation use 'accessKey' whilst SMIL3 uses 'accesskey'
+//     We should allow both
+#define ACCESSKEY_PREFIX NS_LITERAL_STRING("accessKey(")
 #define REPEAT_PREFIX    NS_LITERAL_STRING("repeat(")
 #define WALLCLOCK_PREFIX NS_LITERAL_STRING("wallclock(")
 
 // NS_IS_SPACE relies on isspace which may return true for \xB and \xC but
 // SMILANIM does not consider these characters to be whitespace.
 inline PRBool
 IsSpace(const PRUnichar c)
 {
@@ -358,16 +360,19 @@ ParseElementBaseTimeValueSpec(const nsAS
   // The spec will probably look something like one of these
   //
   // element-name.begin
   // element-name.event-name
   // event-name
   // element-name.repeat(3)
   // event\.name
   //
+  // Technically `repeat(3)' is permitted but the behaviour in this case is not
+  // defined (for SMIL Animation) so we don't support it here.
+  //
 
   const PRUnichar* tokenStart = aSpec.BeginReading();
   const PRUnichar* tokenEnd = GetTokenEnd(aSpec, PR_TRUE);
   nsAutoString token(Substring(tokenStart, tokenEnd));
   Unescape(token);
 
   if (token.IsEmpty())
     return NS_ERROR_FAILURE;
--- a/content/smil/nsSMILTimeValueSpec.cpp
+++ b/content/smil/nsSMILTimeValueSpec.cpp
@@ -39,98 +39,139 @@
 #include "nsSMILInterval.h"
 #include "nsSMILTimeContainer.h"
 #include "nsSMILTimeValue.h"
 #include "nsSMILTimedElement.h"
 #include "nsSMILInstanceTime.h"
 #include "nsSMILParserUtils.h"
 #include "nsISMILAnimationElement.h"
 #include "nsContentUtils.h"
+#include "nsIEventListenerManager.h"
+#include "nsIDOMEventGroup.h"
+#include "nsGUIEvent.h"
+#include "nsIDOMTimeEvent.h"
 #include "nsString.h"
 
+using namespace mozilla::dom;
+
+//----------------------------------------------------------------------
+// Nested class: EventListener
+
+NS_IMPL_ISUPPORTS1(nsSMILTimeValueSpec::EventListener, nsIDOMEventListener)
+
+NS_IMETHODIMP
+nsSMILTimeValueSpec::EventListener::HandleEvent(nsIDOMEvent* aEvent)
+{
+  if (mSpec) {
+    mSpec->HandleEvent(aEvent);
+  }
+  return NS_OK;
+}
+
 //----------------------------------------------------------------------
 // Implementation
 
 #ifdef _MSC_VER
 // Disable "warning C4355: 'this' : used in base member initializer list".
-// We can ignore that warning because we know that mTimebase's constructor
-// doesn't dereference the pointer passed to it.
+// We can ignore that warning because we know that mReferencedElement's
+// constructor doesn't dereference the pointer passed to it.
 #pragma warning(push)
 #pragma warning(disable:4355)
 #endif
 nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsSMILTimedElement& aOwner,
                                          PRBool aIsBegin)
   : mOwner(&aOwner),
     mIsBegin(aIsBegin),
-    mTimebase(this)
+    mReferencedElement(this)
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 {
 }
 
 nsSMILTimeValueSpec::~nsSMILTimeValueSpec()
 {
-  UnregisterFromTimebase(GetTimebaseElement());
+  UnregisterFromReferencedElement(mReferencedElement.get());
+  if (mEventListener) {
+    mEventListener->Disconnect();
+    mEventListener = nsnull;
+  }
 }
 
 nsresult
 nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
-                             nsIContent* aContextNode)
+                             Element* aContextNode)
 {
   nsSMILTimeValueSpecParams params;
   nsresult rv =
     nsSMILParserUtils::ParseTimeValueSpecParams(aStringSpec, params);
 
   if (NS_FAILED(rv))
     return rv;
 
   mParams = params;
 
   // According to SMIL 3.0:
   //   The special value "indefinite" does not yield an instance time in the
   //   begin list. It will, however yield a single instance with the value
   //   "indefinite" in an end list. This value is not removed by a reset.
   if (mParams.mType == nsSMILTimeValueSpecParams::OFFSET ||
       (!mIsBegin && mParams.mType == nsSMILTimeValueSpecParams::INDEFINITE)) {
-    nsRefPtr<nsSMILInstanceTime> instance =
-      new nsSMILInstanceTime(mParams.mOffset);
-    if (!instance)
-      return NS_ERROR_OUT_OF_MEMORY;
-    mOwner->AddInstanceTime(instance, mIsBegin);
+    mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin);
+  }
+
+  // Fill in the event symbol to simplify handling later
+  if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
+    mParams.mEventSymbol = nsGkAtoms::repeatEvent;
   }
 
   ResolveReferences(aContextNode);
 
   return rv;
 }
 
 void
 nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode)
 {
-  if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE)
+  if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE &&
+      mParams.mType != nsSMILTimeValueSpecParams::EVENT &&
+      mParams.mType != nsSMILTimeValueSpecParams::REPEAT)
     return;
 
   NS_ABORT_IF_FALSE(aContextNode,
       "null context node for resolving timing references against");
 
   // If we're not bound to the document yet, don't worry, we'll get called again
   // when that happens
   if (!aContextNode->IsInDoc())
     return;
 
-  // Hold ref to the old content so that it isn't destroyed in between resetting
-  // the timebase and using the pointer to update the timebase.
-  nsRefPtr<nsIContent> oldTimebaseContent = mTimebase.get();
+  // Hold ref to the old element so that it isn't destroyed in between resetting
+  // the referenced element and using the pointer to update the referenced
+  // element.
+  nsRefPtr<Element> oldReferencedElement = mReferencedElement.get();
 
-  NS_ABORT_IF_FALSE(mParams.mDependentElemID, "NULL syncbase element id");
-  nsString idStr;
-  mParams.mDependentElemID->ToString(idStr);
-  mTimebase.ResetWithID(aContextNode, idStr);
-  UpdateTimebase(oldTimebaseContent, mTimebase.get());
+  if (mParams.mDependentElemID) {
+    mReferencedElement.ResetWithID(aContextNode,
+        nsDependentAtomString(mParams.mDependentElemID));
+  } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
+    Element* target = mOwner->GetTargetElement();
+    mReferencedElement.ResetWithElement(target);
+  } else {
+    NS_ABORT_IF_FALSE(PR_FALSE, "Syncbase or repeat spec without ID");
+  }
+  UpdateReferencedElement(oldReferencedElement, mReferencedElement.get());
+}
+
+PRBool
+nsSMILTimeValueSpec::IsEventBased() const
+{
+  return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
+         mParams.mType == nsSMILTimeValueSpecParams::REPEAT ||
+         mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY;
 }
 
 void
 nsSMILTimeValueSpec::HandleNewInterval(nsSMILInterval& aInterval,
                                        const nsSMILTimeContainer* aSrcContainer)
 {
   const nsSMILInstanceTime& baseInstance = mParams.mSyncBegin
     ? *aInterval.Begin() : *aInterval.End();
@@ -141,20 +182,26 @@ nsSMILTimeValueSpec::HandleNewInterval(n
   if (newTime.IsResolved()) {
     newTime.SetMillis(newTime.GetMillis() + mParams.mOffset.GetMillis());
   }
 
   // Create the instance time and register it with the interval
   nsRefPtr<nsSMILInstanceTime> newInstance =
     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this,
                            &aInterval);
-  if (!newInstance)
+  mOwner->AddInstanceTime(newInstance, mIsBegin);
+}
+
+void
+nsSMILTimeValueSpec::HandleTargetElementChange(Element* aNewTarget)
+{
+  if (!IsEventBased() || mParams.mDependentElemID)
     return;
 
-  mOwner->AddInstanceTime(newInstance, mIsBegin);
+  mReferencedElement.ResetWithElement(aNewTarget);
 }
 
 void
 nsSMILTimeValueSpec::HandleChangedInstanceTime(
     const nsSMILInstanceTime& aBaseTime,
     const nsSMILTimeContainer* aSrcContainer,
     nsSMILInstanceTime& aInstanceTimeToUpdate,
     PRBool aObjectChanged)
@@ -191,70 +238,198 @@ PRBool
 nsSMILTimeValueSpec::DependsOnBegin() const
 {
   return mParams.mSyncBegin;
 }
 
 void
 nsSMILTimeValueSpec::Traverse(nsCycleCollectionTraversalCallback* aCallback)
 {
-  mTimebase.Traverse(aCallback);
+  mReferencedElement.Traverse(aCallback);
 }
 
 void
 nsSMILTimeValueSpec::Unlink()
 {
-  UnregisterFromTimebase(GetTimebaseElement());
-  mTimebase.Unlink();
+  UnregisterFromReferencedElement(mReferencedElement.get());
+  mReferencedElement.Unlink();
 }
 
 //----------------------------------------------------------------------
 // Implementation helpers
 
 void
-nsSMILTimeValueSpec::UpdateTimebase(nsIContent* aFrom, nsIContent* aTo)
+nsSMILTimeValueSpec::UpdateReferencedElement(Element* aFrom, Element* aTo)
 {
   if (aFrom == aTo)
     return;
 
-  UnregisterFromTimebase(GetTimedElementFromContent(aFrom));
+  UnregisterFromReferencedElement(aFrom);
 
-  nsSMILTimedElement* to = GetTimedElementFromContent(aTo);
-  if (to) {
-    to->AddDependent(*this);
+  switch (mParams.mType)
+  {
+  case nsSMILTimeValueSpecParams::SYNCBASE:
+    {
+      nsSMILTimedElement* to = GetTimedElement(aTo);
+      if (to) {
+        to->AddDependent(*this);
+      }
+    }
+    break;
+
+  case nsSMILTimeValueSpecParams::EVENT:
+  case nsSMILTimeValueSpecParams::REPEAT:
+    RegisterEventListener(aTo);
+    break;
+
+  default:
+    // not a referencing-type or not yet supported
+    break;
   }
 }
 
 void
-nsSMILTimeValueSpec::UnregisterFromTimebase(nsSMILTimedElement* aTimedElement)
+nsSMILTimeValueSpec::UnregisterFromReferencedElement(Element* aElement)
 {
-  if (!aTimedElement)
+  if (!aElement)
     return;
 
-  aTimedElement->RemoveDependent(*this);
-  mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
+  if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) {
+    nsSMILTimedElement* timedElement = GetTimedElement(aElement);
+    if (timedElement) {
+      timedElement->RemoveDependent(*this);
+    }
+    mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
+  } else if (IsEventBased()) {
+    UnregisterEventListener(aElement);
+  }
 }
 
 nsSMILTimedElement*
-nsSMILTimeValueSpec::GetTimedElementFromContent(nsIContent* aContent)
+nsSMILTimeValueSpec::GetTimedElement(Element* aElement)
 {
-  if (!aContent)
+  if (!aElement)
     return nsnull;
 
-  nsCOMPtr<nsISMILAnimationElement> animElement = do_QueryInterface(aContent);
+  nsCOMPtr<nsISMILAnimationElement> animElement = do_QueryInterface(aElement);
   if (!animElement)
     return nsnull;
 
   return &animElement->TimedElement();
 }
 
-nsSMILTimedElement*
-nsSMILTimeValueSpec::GetTimebaseElement()
+void
+nsSMILTimeValueSpec::RegisterEventListener(Element* aTarget)
+{
+  NS_ABORT_IF_FALSE(mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
+                    mParams.mType == nsSMILTimeValueSpecParams::REPEAT,
+    "Attempting to register event-listener for unexpected nsSMILTimeValueSpec"
+    " type");
+  NS_ABORT_IF_FALSE(mParams.mEventSymbol,
+    "Attempting to register event-listener but there is no event name");
+
+  if (!aTarget)
+    return;
+
+  if (!mEventListener) {
+    mEventListener = new EventListener(this);
+  }
+
+  nsCOMPtr<nsIDOMEventGroup> sysGroup;
+  nsIEventListenerManager* elm =
+    GetEventListenerManager(aTarget, getter_AddRefs(sysGroup));
+  if (!elm)
+    return;
+  
+  elm->AddEventListenerByType(mEventListener,
+                              nsDependentAtomString(mParams.mEventSymbol),
+                              NS_EVENT_FLAG_BUBBLE |
+                              NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
+                              sysGroup);
+}
+
+void
+nsSMILTimeValueSpec::UnregisterEventListener(Element* aTarget)
+{
+  if (!aTarget || !mEventListener)
+    return;
+
+  nsCOMPtr<nsIDOMEventGroup> sysGroup;
+  nsIEventListenerManager* elm =
+    GetEventListenerManager(aTarget, getter_AddRefs(sysGroup));
+  if (!elm)
+    return;
+
+  elm->RemoveEventListenerByType(mEventListener,
+                                 nsDependentAtomString(mParams.mEventSymbol),
+                                 NS_EVENT_FLAG_BUBBLE |
+                                 NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
+                                 sysGroup);
+}
+
+nsIEventListenerManager*
+nsSMILTimeValueSpec::GetEventListenerManager(Element* aTarget,
+                                             nsIDOMEventGroup** aSystemGroup)
 {
-  return GetTimedElementFromContent(mTimebase.get());
+  NS_ABORT_IF_FALSE(aTarget, "null target; can't get EventListenerManager");
+  NS_ABORT_IF_FALSE(aSystemGroup && !*aSystemGroup,
+      "Bad out param for system group");
+
+  nsIEventListenerManager* elm = aTarget->GetListenerManager(PR_TRUE);
+  if (!elm)
+    return nsnull;
+
+  aTarget->GetSystemEventGroup(aSystemGroup);
+  if (!*aSystemGroup)
+    return nsnull;
+
+  return elm;
+}
+
+void
+nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent)
+{
+  NS_ABORT_IF_FALSE(mEventListener, "Got event without an event listener");
+  NS_ABORT_IF_FALSE(IsEventBased(),
+                    "Got event for non-event nsSMILTimeValueSpec");
+  NS_ABORT_IF_FALSE(aEvent, "No event supplied");
+
+  // XXX In the long run we should get the time from the event itself which will
+  // store the time in global document time which we'll need to convert to our
+  // time container
+  nsSMILTimeContainer* container = mOwner->GetTimeContainer();
+  if (!container)
+    return;
+
+  if (!CheckEventDetail(aEvent))
+    return;
+
+  nsSMILTime currentTime = container->GetCurrentTime();
+  nsSMILTimeValue newTime(currentTime + mParams.mOffset.GetMillis());
+
+  nsRefPtr<nsSMILInstanceTime> newInstance =
+    new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
+  mOwner->AddInstanceTime(newInstance, mIsBegin);
+}
+
+PRBool
+nsSMILTimeValueSpec::CheckEventDetail(nsIDOMEvent *aEvent)
+{
+  if (mParams.mType != nsSMILTimeValueSpecParams::REPEAT)
+    return PR_TRUE;
+
+  nsCOMPtr<nsIDOMTimeEvent> timeEvent = do_QueryInterface(aEvent);
+  if (!timeEvent) {
+    NS_WARNING("Received a repeat event that was not a DOMTimeEvent");
+    return PR_FALSE;
+  }
+
+  PRInt32 detail;
+  timeEvent->GetDetail(&detail);
+  return detail == mParams.mRepeatIterationOrAccessKey;
 }
 
 nsSMILTimeValue
 nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
     const nsSMILTimeValue& aSrcTime,
     const nsSMILTimeContainer* aSrcContainer)
 {
   // If the source time is either indefinite or unresolved the result is going
--- a/content/smil/nsSMILTimeValueSpec.h
+++ b/content/smil/nsSMILTimeValueSpec.h
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef NS_SMILTIMEVALUESPEC_H_
 #define NS_SMILTIMEVALUESPEC_H_
 
 #include "nsSMILTimeValueSpecParams.h"
 #include "nsReferencedElement.h"
 #include "nsAutoPtr.h"
+#include "nsIDOMEventListener.h"
 
 class nsAString;
 class nsSMILTimeValue;
 class nsSMILTimedElement;
 class nsSMILTimeContainer;
 class nsSMILInstanceTime;
 class nsSMILInterval;
 
@@ -58,63 +59,96 @@ class nsSMILInterval;
 // and synchronisation (for syncbase specifications).
 //
 // For an overview of how this class is related to other SMIL time classes see
 // the documentation in nsSMILTimeValue.h
 
 class nsSMILTimeValueSpec
 {
 public:
+  typedef mozilla::dom::Element Element;
+
   nsSMILTimeValueSpec(nsSMILTimedElement& aOwner, PRBool aIsBegin);
   ~nsSMILTimeValueSpec();
 
-  nsresult SetSpec(const nsAString& aStringSpec, nsIContent* aContextNode);
+  nsresult SetSpec(const nsAString& aStringSpec, Element* aContextNode);
   void     ResolveReferences(nsIContent* aContextNode);
+  PRBool   IsEventBased() const;
 
   void     HandleNewInterval(nsSMILInterval& aInterval,
                              const nsSMILTimeContainer* aSrcContainer);
+  void     HandleTargetElementChange(Element* aNewTarget);
 
   // For created nsSMILInstanceTime objects
   PRBool   DependsOnBegin() const;
   void     HandleChangedInstanceTime(const nsSMILInstanceTime& aBaseTime,
                                      const nsSMILTimeContainer* aSrcContainer,
                                      nsSMILInstanceTime& aInstanceTimeToUpdate,
                                      PRBool aObjectChanged);
   void     HandleDeletedInstanceTime(nsSMILInstanceTime& aInstanceTime);
 
   // Cycle-collection support
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
   void Unlink();
 
 protected:
-  void UpdateTimebase(nsIContent* aFrom, nsIContent* aTo);
-  void UnregisterFromTimebase(nsSMILTimedElement* aTimedElement);
-  nsSMILTimedElement* GetTimedElementFromContent(nsIContent* aContent);
-  nsSMILTimedElement* GetTimebaseElement();
+  void UpdateReferencedElement(Element* aFrom, Element* aTo);
+  void UnregisterFromReferencedElement(Element* aElement);
+  nsSMILTimedElement* GetTimedElement(Element* aElement);
+  void RegisterEventListener(Element* aElement);
+  void UnregisterEventListener(Element* aElement);
+  nsIEventListenerManager* GetEventListenerManager(Element* aElement,
+      nsIDOMEventGroup** aSystemGroup);
+  void HandleEvent(nsIDOMEvent* aEvent);
+  PRBool CheckEventDetail(nsIDOMEvent* aEvent);
   nsSMILTimeValue ConvertBetweenTimeContainers(const nsSMILTimeValue& aSrcTime,
                                       const nsSMILTimeContainer* aSrcContainer);
 
   nsSMILTimedElement*           mOwner;
   PRPackedBool                  mIsBegin; // Indicates if *we* are a begin spec,
                                           // not to be confused with
                                           // mParams.mSyncBegin which indicates
                                           // if we're synced with the begin of
                                           // the target.
   nsSMILTimeValueSpecParams     mParams;
 
-  class TimebaseElement : public nsReferencedElement {
+  class TimeReferenceElement : public nsReferencedElement
+  {
   public:
-    TimebaseElement(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
+    TimeReferenceElement(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
+    void ResetWithElement(Element* aTo) {
+      nsRefPtr<Element> from = get();
+      Unlink();
+      ElementChanged(from, aTo);
+    }
 
   protected:
-    virtual void ElementChanged(Element* aFrom, Element* aTo) {
+    virtual void ElementChanged(Element* aFrom, Element* aTo)
+    {
       nsReferencedElement::ElementChanged(aFrom, aTo);
-      mSpec->UpdateTimebase(aFrom, aTo);
+      mSpec->UpdateReferencedElement(aFrom, aTo);
     }
     virtual PRBool IsPersistent() { return PR_TRUE; }
   private:
     nsSMILTimeValueSpec* mSpec;
   };
 
-  TimebaseElement mTimebase;
+  TimeReferenceElement mReferencedElement;
+
+  class EventListener : public nsIDOMEventListener
+  {
+  public:
+    EventListener(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
+    void Disconnect()
+    {
+      mSpec = nsnull;
+    }
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIDOMEVENTLISTENER
+
+  private:
+    nsSMILTimeValueSpec* mSpec;
+  };
+  nsCOMPtr<EventListener> mEventListener;
 };
 
 #endif // NS_SMILTIMEVALUESPEC_H_
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -181,18 +181,16 @@ const PRUint8 nsSMILTimedElement::sMaxNu
 //----------------------------------------------------------------------
 // Ctor, dtor
 
 nsSMILTimedElement::nsSMILTimedElement()
 :
   mAnimationElement(nsnull),
   mFillMode(FILL_REMOVE),
   mRestartMode(RESTART_ALWAYS),
-  mBeginSpecSet(PR_FALSE),
-  mEndHasEventConditions(PR_FALSE),
   mInstanceSerialIndex(0),
   mClient(nsnull),
   mCurrentInterval(nsnull),
   mCurrentRepeatIteration(0),
   mPrevRegisteredMilestone(sMaxMilestone),
   mElementState(STATE_STARTUP),
   mSeekState(SEEK_NOT_SEEKING)
 {
@@ -338,16 +336,29 @@ nsSMILTimedElement::GetStartTime() const
 // nsSMILTimedElement
 
 void
 nsSMILTimedElement::AddInstanceTime(nsSMILInstanceTime* aInstanceTime,
                                     PRBool aIsBegin)
 {
   NS_ABORT_IF_FALSE(aInstanceTime, "Attempting to add null instance time");
 
+  // Event-sensitivity: If an element is not active (but the parent time
+  // container is), then events are only handled for begin specifications.
+  if (mElementState != STATE_ACTIVE && !aIsBegin &&
+      aInstanceTime->IsDynamic())
+  {
+    // No need to call Unlink here--dynamic instance times shouldn't be linked
+    // to anything that's going to miss them
+    NS_ABORT_IF_FALSE(!aInstanceTime->GetBaseInterval(),
+        "Dynamic instance time has a base interval--we probably need to unlink"
+        " it if we're not going to use it");
+    return;
+  }
+
   aInstanceTime->SetSerial(++mInstanceSerialIndex);
   InstanceTimeList& instanceList = aIsBegin ? mBeginInstances : mEndInstances;
   nsRefPtr<nsSMILInstanceTime>* inserted =
     instanceList.InsertElementSorted(aInstanceTime, InstanceTimeComparator());
   if (!inserted) {
     NS_WARNING("Insufficient memory to insert instance time");
     return;
   }
@@ -647,16 +658,31 @@ nsSMILTimedElement::HandleContainerTimeC
   // containers. For now we don't bother because when we re-resolve the time in
   // the nsSMILTimeValueSpec we'll check if anything has changed and if not, we
   // won't go any further.
   if (mElementState == STATE_WAITING || mElementState == STATE_ACTIVE) {
     NotifyChangedInterval();
   }
 }
 
+namespace
+{
+  PRBool
+  RemoveNonDynamic(nsSMILInstanceTime* aInstanceTime)
+  {
+    // Generally dynamically-generated instance times (DOM calls, event-based
+    // times) are not associated with their creator nsSMILTimeValueSpec since
+    // they may outlive them.
+    NS_ABORT_IF_FALSE(!aInstanceTime->IsDynamic() ||
+         !aInstanceTime->GetCreator(),
+        "Dynamic instance time should be unlinked from its creator");
+    return !aInstanceTime->IsDynamic();
+  }
+}
+
 void
 nsSMILTimedElement::Rewind()
 {
   NS_ABORT_IF_FALSE(mAnimationElement,
       "Got rewind request before being attached to an animation element");
   NS_ABORT_IF_FALSE(mSeekState == SEEK_NOT_SEEKING,
       "Got rewind request whilst already seeking");
 
@@ -668,53 +694,63 @@ nsSMILTimedElement::Rewind()
   // time recalculating the current interval
   mElementState = STATE_STARTUP;
   mCurrentRepeatIteration = 0;
 
   // Clear the intervals and instance times except those instance times we can't
   // regenerate (DOM calls etc.)
   RewindTiming();
 
-  UnsetBeginSpec();
-  UnsetEndSpec();
+  UnsetBeginSpec(RemoveNonDynamic);
+  UnsetEndSpec(RemoveNonDynamic);
 
   if (mClient) {
     mClient->Inactivate(PR_FALSE);
   }
 
   if (mAnimationElement->HasAnimAttr(nsGkAtoms::begin)) {
     nsAutoString attValue;
     mAnimationElement->GetAnimAttr(nsGkAtoms::begin, attValue);
-    SetBeginSpec(attValue, &mAnimationElement->Content());
+    SetBeginSpec(attValue, &mAnimationElement->AsElement(), RemoveNonDynamic);
   }
 
   if (mAnimationElement->HasAnimAttr(nsGkAtoms::end)) {
     nsAutoString attValue;
     mAnimationElement->GetAnimAttr(nsGkAtoms::end, attValue);
-    SetEndSpec(attValue, &mAnimationElement->Content());
+    SetEndSpec(attValue, &mAnimationElement->AsElement(), RemoveNonDynamic);
   }
 
   mPrevRegisteredMilestone = sMaxMilestone;
   RegisterMilestone();
 }
 
+namespace
+{
+  PRBool
+  RemoveNonDOM(nsSMILInstanceTime* aInstanceTime)
+  {
+    return !aInstanceTime->FromDOM();
+  }
+}
+
 PRBool
 nsSMILTimedElement::SetAttr(nsIAtom* aAttribute, const nsAString& aValue,
-                            nsAttrValue& aResult, nsIContent* aContextNode,
+                            nsAttrValue& aResult,
+                            Element* aContextNode,
                             nsresult* aParseResult)
 {
   PRBool foundMatch = PR_TRUE;
   nsresult parseResult = NS_OK;
 
   if (aAttribute == nsGkAtoms::begin) {
-    parseResult = SetBeginSpec(aValue, aContextNode);
+    parseResult = SetBeginSpec(aValue, aContextNode, RemoveNonDOM);
   } else if (aAttribute == nsGkAtoms::dur) {
     parseResult = SetSimpleDuration(aValue);
   } else if (aAttribute == nsGkAtoms::end) {
-    parseResult = SetEndSpec(aValue, aContextNode);
+    parseResult = SetEndSpec(aValue, aContextNode, RemoveNonDOM);
   } else if (aAttribute == nsGkAtoms::fill) {
     parseResult = SetFillMode(aValue);
   } else if (aAttribute == nsGkAtoms::max) {
     parseResult = SetMax(aValue);
   } else if (aAttribute == nsGkAtoms::min) {
     parseResult = SetMin(aValue);
   } else if (aAttribute == nsGkAtoms::repeatCount) {
     parseResult = SetRepeatCount(aValue);
@@ -737,21 +773,21 @@ nsSMILTimedElement::SetAttr(nsIAtom* aAt
 }
 
 PRBool
 nsSMILTimedElement::UnsetAttr(nsIAtom* aAttribute)
 {
   PRBool foundMatch = PR_TRUE;
 
   if (aAttribute == nsGkAtoms::begin) {
-    UnsetBeginSpec();
+    UnsetBeginSpec(RemoveNonDOM);
   } else if (aAttribute == nsGkAtoms::dur) {
     UnsetSimpleDuration();
   } else if (aAttribute == nsGkAtoms::end) {
-    UnsetEndSpec();
+    UnsetEndSpec(RemoveNonDOM);
   } else if (aAttribute == nsGkAtoms::fill) {
     UnsetFillMode();
   } else if (aAttribute == nsGkAtoms::max) {
     UnsetMax();
   } else if (aAttribute == nsGkAtoms::min) {
     UnsetMin();
   } else if (aAttribute == nsGkAtoms::repeatCount) {
     UnsetRepeatCount();
@@ -766,44 +802,43 @@ nsSMILTimedElement::UnsetAttr(nsIAtom* a
   return foundMatch;
 }
 
 //----------------------------------------------------------------------
 // Setters and unsetters
 
 nsresult
 nsSMILTimedElement::SetBeginSpec(const nsAString& aBeginSpec,
-                                 nsIContent* aContextNode)
+                                 Element* aContextNode,
+                                 RemovalTestFunction aRemove)
 {
-  mBeginSpecSet = PR_TRUE;
-  return SetBeginOrEndSpec(aBeginSpec, aContextNode, PR_TRUE);
+  return SetBeginOrEndSpec(aBeginSpec, aContextNode, PR_TRUE /*isBegin*/,
+                           aRemove);
 }
 
 void
-nsSMILTimedElement::UnsetBeginSpec()
+nsSMILTimedElement::UnsetBeginSpec(RemovalTestFunction aRemove)
 {
-  ClearBeginOrEndSpecs(PR_TRUE);
-  mBeginSpecSet = PR_FALSE;
+  ClearSpecs(mBeginSpecs, mBeginInstances, aRemove);
   UpdateCurrentInterval();
 }
 
 nsresult
 nsSMILTimedElement::SetEndSpec(const nsAString& aEndSpec,
-                               nsIContent* aContextNode)
+                               Element* aContextNode,
+                               RemovalTestFunction aRemove)
 {
-  // XXX When implementing events etc., don't forget to ensure
-  // mEndHasEventConditions is set if the specification contains conditions that
-  // describe event-values, repeat-values or accessKey-values.
-  return SetBeginOrEndSpec(aEndSpec, aContextNode, PR_FALSE);
+  return SetBeginOrEndSpec(aEndSpec, aContextNode, PR_FALSE /*!isBegin*/,
+                           aRemove);
 }
 
 void
-nsSMILTimedElement::UnsetEndSpec()
+nsSMILTimedElement::UnsetEndSpec(RemovalTestFunction aRemove)
 {
-  ClearBeginOrEndSpecs(PR_FALSE);
+  ClearSpecs(mEndSpecs, mEndInstances, aRemove);
   UpdateCurrentInterval();
 }
 
 nsresult
 nsSMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec)
 {
   nsSMILTimeValue duration;
   PRBool isMedia;
@@ -1066,37 +1101,46 @@ nsSMILTimedElement::IsTimeDependent(cons
 }
 
 void
 nsSMILTimedElement::BindToTree(nsIContent* aContextNode)
 {
   // Resolve references to other parts of the tree
   PRUint32 count = mBeginSpecs.Length();
   for (PRUint32 i = 0; i < count; ++i) {
-    nsSMILTimeValueSpec* beginSpec = mBeginSpecs[i];
-    NS_ABORT_IF_FALSE(beginSpec,
-        "null nsSMILTimeValueSpec in list of begin specs");
-    beginSpec->ResolveReferences(aContextNode);
+    mBeginSpecs[i]->ResolveReferences(aContextNode);
   }
 
   count = mEndSpecs.Length();
   for (PRUint32 j = 0; j < count; ++j) {
-    nsSMILTimeValueSpec* endSpec = mEndSpecs[j];
-    NS_ABORT_IF_FALSE(endSpec, "null nsSMILTimeValueSpec in list of end specs");
-    endSpec->ResolveReferences(aContextNode);
+    mEndSpecs[j]->ResolveReferences(aContextNode);
   }
 
   // Clear any previous milestone since it might be been processed whilst we
   // were not bound to the tree.
   mPrevRegisteredMilestone = sMaxMilestone;
 
   RegisterMilestone();
 }
 
 void
+nsSMILTimedElement::HandleTargetElementChange(Element* aNewTarget)
+{
+  PRUint32 count = mBeginSpecs.Length();
+  for (PRUint32 i = 0; i < count; ++i) {
+    mBeginSpecs[i]->HandleTargetElementChange(aNewTarget);
+  }
+
+  count = mEndSpecs.Length();
+  for (PRUint32 j = 0; j < count; ++j) {
+    mEndSpecs[j]->HandleTargetElementChange(aNewTarget);
+  }
+}
+
+void
 nsSMILTimedElement::Traverse(nsCycleCollectionTraversalCallback* aCallback)
 {
   PRUint32 count = mBeginSpecs.Length();
   for (PRUint32 i = 0; i < count; ++i) {
     nsSMILTimeValueSpec* beginSpec = mBeginSpecs[i];
     NS_ABORT_IF_FALSE(beginSpec,
         "null nsSMILTimeValueSpec in list of begin specs");
     beginSpec->Traverse(aCallback);
@@ -1129,117 +1173,95 @@ nsSMILTimedElement::Unlink()
   }
 }
 
 //----------------------------------------------------------------------
 // Implementation helpers
 
 nsresult
 nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
-                                      nsIContent* aContextNode,
-                                      PRBool aIsBegin)
+                                      Element* aContextNode,
+                                      PRBool aIsBegin,
+                                      RemovalTestFunction aRemove)
 {
-  ClearBeginOrEndSpecs(aIsBegin);
-
   PRInt32 start;
   PRInt32 end = -1;
   PRInt32 length;
   nsresult rv = NS_OK;
   TimeValueSpecList& timeSpecsList = aIsBegin ? mBeginSpecs : mEndSpecs;
+  InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
+
+  ClearSpecs(timeSpecsList, instances, aRemove);
 
   do {
     start = end + 1;
     end = aSpec.FindChar(';', start);
     length = (end == -1) ? -1 : end - start;
     nsAutoPtr<nsSMILTimeValueSpec>
       spec(new nsSMILTimeValueSpec(*this, aIsBegin));
     rv = spec->SetSpec(Substring(aSpec, start, length), aContextNode);
     if (NS_SUCCEEDED(rv)) {
       timeSpecsList.AppendElement(spec.forget());
     }
   } while (end != -1 && NS_SUCCEEDED(rv));
 
   if (NS_FAILED(rv)) {
-    ClearBeginOrEndSpecs(aIsBegin);
+    ClearSpecs(timeSpecsList, instances, aRemove);
   }
 
   UpdateCurrentInterval();
 
   return rv;
 }
 
 namespace
 {
-  class RemoveNonDOM
+  // Adaptor functor for RemoveInstanceTimes that allows us to use function
+  // pointers instead.
+  // Without this we'd have to either templatize ClearSpecs and all its callers
+  // or pass bool flags around to specify which removal function to use here.
+  class RemoveByFunction
   {
   public:
+    RemoveByFunction(nsSMILTimedElement::RemovalTestFunction aFunction)
+      : mFunction(aFunction) { }
     PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
     {
-      return !aInstanceTime->FromDOM();
+      return mFunction(aInstanceTime);
     }
+
+  private:
+    nsSMILTimedElement::RemovalTestFunction mFunction;
   };
 }
 
 void
-nsSMILTimedElement::ClearBeginOrEndSpecs(PRBool aIsBegin)
+nsSMILTimedElement::ClearSpecs(TimeValueSpecList& aSpecs,
+                               InstanceTimeList& aInstances,
+                               RemovalTestFunction aRemove)
 {
-  TimeValueSpecList& specs = aIsBegin ? mBeginSpecs : mEndSpecs;
-  specs.Clear();
-
-  // Remove only those instance times generated by the attribute, not those from
-  // DOM calls.
-  InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
-  RemoveNonDOM removeNonDOM;
-  RemoveInstanceTimes(instances, removeNonDOM);
+  aSpecs.Clear();
+  RemoveByFunction removeByFunction(aRemove);
+  RemoveInstanceTimes(aInstances, removeByFunction);
 }
 
 void
 nsSMILTimedElement::RewindTiming()
 {
-  RewindInstanceTimes(mBeginInstances);
-  RewindInstanceTimes(mEndInstances);
-
   if (mCurrentInterval) {
     mCurrentInterval->Unlink();
     mCurrentInterval = nsnull;
   }
 
   for (PRInt32 i = mOldIntervals.Length() - 1; i >= 0; --i) {
     mOldIntervals[i]->Unlink();
   }
   mOldIntervals.Clear();
 }
 
-namespace
-{
-  class RemoveNonDynamic
-  {
-  public:
-    PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
-    {
-      // Generally dynamically-generated instance times (DOM calls, event-based
-      // times) are not associated with their creator nsSMILTimeValueSpec.
-      // If that ever changes though we'll need to make sure to disassociate
-      // them here otherwise they'll get removed when we clear the set of
-      // nsSMILTimeValueSpecs later on.
-      NS_ABORT_IF_FALSE(!aInstanceTime->IsDynamic() ||
-           !aInstanceTime->GetCreator(),
-          "Instance time retained during rewind needs to be unlinked");
-      return !aInstanceTime->IsDynamic();
-    }
-  };
-}
-
-void
-nsSMILTimedElement::RewindInstanceTimes(InstanceTimeList& aList)
-{
-  RemoveNonDynamic removeNonDynamic;
-  RemoveInstanceTimes(aList, removeNonDynamic);
-}
-
 void
 nsSMILTimedElement::ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime)
 {
   // This should only be called within DoSampleAt as a helper function
   NS_ABORT_IF_FALSE(mElementState == STATE_ACTIVE,
       "Unexpected state to try to apply an early end");
 
   // Only apply an early end if we're not already ending.
@@ -1315,42 +1337,35 @@ nsSMILTimedElement::DoPostSeek()
     // SMIL seems to require this. SMIL 3.0, 'Hyperlinks and timing':
     //   Resolved end times associated with events, Repeat-values,
     //   Accesskey-values or added via DOM method calls are cleared when seeking
     //   to time earlier than the resolved end time.
     Reset();
     UpdateCurrentInterval();
   }
 
-  // XXX
-  // Note that SMIL gives the very cryptic description:
-  //   The associated time for the event is the document time before the seek.
-  //   This action does not resolve any times in the instance times list for end
-  //   times.
-  //
-  // The second sentence was added as a clarification in a SMIL 2.0 erratum.
-  // Presumably the intention is that we fire the event as implemented below but
-  // don't act on it. This makes sense at least for dependencies within the same
-  // time container. So we'll probably need to set a flag here to ensure we
-  // don't actually act on it when we implement event-based timing.
   switch (mSeekState)
   {
   case SEEK_FORWARD_FROM_ACTIVE:
   case SEEK_BACKWARD_FROM_ACTIVE:
     if (mElementState != STATE_ACTIVE) {
       FireTimeEventAsync(NS_SMIL_END, 0);
     }
     break;
 
   case SEEK_FORWARD_FROM_INACTIVE:
   case SEEK_BACKWARD_FROM_INACTIVE:
     if (mElementState == STATE_ACTIVE) {
       FireTimeEventAsync(NS_SMIL_BEGIN, 0);
     }
     break;
+
+  case SEEK_NOT_SEEKING:
+    /* Do nothing */
+    break;
   }
 
   mSeekState = SEEK_NOT_SEEKING;
 }
 
 void
 nsSMILTimedElement::UnpreserveInstanceTimes(InstanceTimeList& aList)
 {
@@ -1519,17 +1534,19 @@ nsSMILTimedElement::GetNextInterval(cons
 
   while (PR_TRUE) {
     // Calculate begin time
     if (aFixedBeginTime) {
       if (aFixedBeginTime->Time() < beginAfter)
         return NS_ERROR_FAILURE;
       // our ref-counting is not const-correct
       tempBegin = const_cast<nsSMILInstanceTime*>(aFixedBeginTime);
-    } else if (!mBeginSpecSet && beginAfter <= zeroTime) {
+    } else if ((!mAnimationElement ||
+                !mAnimationElement->HasAnimAttr(nsGkAtoms::begin)) &&
+               beginAfter <= zeroTime) {
       tempBegin = new nsSMILInstanceTime(nsSMILTimeValue(0));
     } else {
       PRInt32 beginPos = 0;
       tempBegin = GetNextGreaterOrEqual(mBeginInstances, beginAfter, beginPos);
       if (!tempBegin || !tempBegin->Time().IsResolved())
         return NS_ERROR_FAILURE;
     }
     NS_ABORT_IF_FALSE(tempBegin && tempBegin->Time().IsResolved() && 
@@ -1544,28 +1561,28 @@ nsSMILTimedElement::GetNextInterval(cons
       // If the last interval ended at the same point and was zero-duration and
       // this one is too, look for another end to use instead
       if (tempEnd && tempEnd->Time() == tempBegin->Time() &&
           prevIntervalWasZeroDur) {
         tempEnd = GetNextGreater(mEndInstances, tempBegin->Time(), endPos);
       }
 
       // If all the ends are before the beginning we have a bad interval UNLESS:
-      // a) We have end events which leave the interval open-ended, OR
-      // b) We never had any end attribute to begin with (and hence we should
+      // a) We never had any end attribute to begin with (and hence we should
       //    just use the active duration after allowing for the possibility of
-      //    an end instance provided by a DOM call)
-      // c) We have an end attribute but no end instances--this is a special
+      //    an end instance provided by a DOM call), OR
+      // b) We have an end attribute but no end instances--this is a special
       //    case that is needed for syncbase timing so that animations of the
       //    following sort: <animate id="a" end="a.begin+1s" ... /> can be
       //    resolved (see SVGT 1.2 Test Suite animate-elem-221-t.svg) by first
-      //    establishing an interval of unresolved duration.
-      PRBool openEndedIntervalOk = mEndHasEventConditions ||
-          mEndSpecs.IsEmpty() ||
-          mEndInstances.IsEmpty();
+      //    establishing an interval of unresolved duration, OR
+      // c) We have end events which leave the interval open-ended.
+      PRBool openEndedIntervalOk = mEndSpecs.IsEmpty() ||
+                                   mEndInstances.IsEmpty() ||
+                                   EndHasEventConditions();
       if (!tempEnd && !openEndedIntervalOk)
         return NS_ERROR_FAILURE; // Bad interval
 
       nsSMILTimeValue intervalEnd = tempEnd
                                   ? tempEnd->Time() : nsSMILTimeValue();
       nsSMILTimeValue activeEnd = CalcActiveEnd(tempBegin->Time(), intervalEnd);
 
       if (!tempEnd || intervalEnd != activeEnd) {
@@ -1901,18 +1918,16 @@ void
 nsSMILTimedElement::AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
     double aOffsetSeconds, PRBool aIsBegin)
 {
   double offset = aOffsetSeconds * PR_MSEC_PER_SEC;
   nsSMILTime timeWithOffset = aCurrentTime + PRInt64(NS_round(offset));
 
   nsSMILTimeValue timeVal(timeWithOffset);
 
-  // XXX If we re-use this method for event-based timing we'll need to change it
-  // so we don't end up setting SOURCE_DOM for event-based times.
   nsRefPtr<nsSMILInstanceTime> instanceTime =
     new nsSMILInstanceTime(timeVal, nsSMILInstanceTime::SOURCE_DOM);
 
   AddInstanceTime(instanceTime, aIsBegin);
 }
 
 void
 nsSMILTimedElement::RegisterMilestone()
@@ -2043,17 +2058,17 @@ nsSMILTimedElement::NotifyChangedInterva
 
 void
 nsSMILTimedElement::FireTimeEventAsync(PRUint32 aMsg, PRInt32 aDetail)
 {
   if (!mAnimationElement)
     return;
 
   nsCOMPtr<nsIRunnable> event =
-    new AsyncTimeEventRunner(&mAnimationElement->Content(), aMsg, aDetail);
+    new AsyncTimeEventRunner(&mAnimationElement->AsElement(), aMsg, aDetail);
   NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
 }
 
 const nsSMILInstanceTime*
 nsSMILTimedElement::GetEffectiveBeginInstance() const
 {
   switch (mElementState)
   {
@@ -2079,16 +2094,26 @@ nsSMILTimedElement::GetEffectiveBeginIns
 const nsSMILInterval*
 nsSMILTimedElement::GetPreviousInterval() const
 {
   return mOldIntervals.IsEmpty()
     ? nsnull
     : mOldIntervals[mOldIntervals.Length()-1].get();
 }
 
+PRBool
+nsSMILTimedElement::EndHasEventConditions() const
+{
+  for (PRUint32 i = 0; i < mEndSpecs.Length(); ++i) {
+    if (mEndSpecs[i]->IsEventBased())
+      return PR_TRUE;
+  }
+  return PR_FALSE;
+}
+
 //----------------------------------------------------------------------
 // Hashtable callback functions
 
 /* static */ PR_CALLBACK PLDHashOperator
 nsSMILTimedElement::NotifyNewIntervalCallback(TimeValueSpecPtrKey* aKey,
                                               void* aData)
 {
   NS_ABORT_IF_FALSE(aKey, "Null hash key for time container hash table");
--- a/content/smil/nsSMILTimedElement.h
+++ b/content/smil/nsSMILTimedElement.h
@@ -60,28 +60,41 @@ class nsIAtom;
 // nsSMILTimedElement
 
 class nsSMILTimedElement
 {
 public:
   nsSMILTimedElement();
   ~nsSMILTimedElement();
 
+  typedef mozilla::dom::Element Element;
+
   /*
    * Sets the owning animation element which this class uses to convert between
    * container times and to register timebase elements.
    */
   void SetAnimationElement(nsISMILAnimationElement* aElement);
 
   /*
    * Returns the time container with which this timed element is associated or
    * nsnull if it is not associated with a time container.
    */
   nsSMILTimeContainer* GetTimeContainer();
 
+  /*
+   * Returns the element targeted by the animation element. Needed for
+   * registering event listeners against the appropriate element.
+   */
+  mozilla::dom::Element* GetTargetElement()
+  {
+    return mAnimationElement ?
+        mAnimationElement->GetTargetElementContent() :
+        nsnull;
+  }
+
   /**
    * Methods for supporting the nsIDOMElementTimeControl interface.
    */
 
   /*
    * Adds a new begin instance time at the current container time plus or minus
    * the specified offset.
    *
@@ -244,26 +257,26 @@ public:
    * @param aAttribute  The name of the attribute to set. The namespace of this
    *                    attribute is not specified as it is checked by the host
    *                    element. Only attributes in the namespace defined for
    *                    SMIL attributes in the host language are passed to the
    *                    timed element.
    * @param aValue      The attribute value.
    * @param aResult     The nsAttrValue object that may be used for storing the
    *                    parsed result.
-   * @param aContextNode The node to use for context when resolving references
-   *                     to other elements.
+   * @param aContextNode The element to use for context when resolving
+   *                     references to other elements.
    * @param[out] aParseResult The result of parsing the attribute. Will be set
    *                          to NS_OK if parsing is successful.
    *
    * @return PR_TRUE if the given attribute is a timing attribute, PR_FALSE
    * otherwise.
    */
   PRBool SetAttr(nsIAtom* aAttribute, const nsAString& aValue,
-                 nsAttrValue& aResult, nsIContent* aContextNode,
+                 nsAttrValue& aResult, Element* aContextNode,
                  nsresult* aParseResult = nsnull);
 
   /**
    * Attempts to unset an attribute on this timed element.
    *
    * @param aAttribute  The name of the attribute to set. As with SetAttr the
    *                    namespace of the attribute is not specified (see
    *                    SetAttr).
@@ -313,25 +326,33 @@ public:
    * @param aContextNode  The node which provides the necessary context for
    *                      resolving references. This is typically the element in
    *                      the host language that owns this timed element. Should
    *                      not be null.
    */
   void BindToTree(nsIContent* aContextNode);
 
   /**
+   * Called when the target of the animation has changed so that event
+   * registrations can be updated.
+   */
+  void HandleTargetElementChange(mozilla::dom::Element* aNewTarget);
+
+  /**
    * Called when the timed element has been removed from a document so that
    * references to other elements can be broken.
    */
   void DissolveReferences() { Unlink(); }
 
   // Cycle collection
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
   void Unlink();
 
+  typedef PRBool (*RemovalTestFunction)(nsSMILInstanceTime* aInstance);
+
 protected:
   // Typedefs
   typedef nsTArray<nsAutoPtr<nsSMILTimeValueSpec> > TimeValueSpecList;
   typedef nsTArray<nsRefPtr<nsSMILInstanceTime> >   InstanceTimeList;
   typedef nsTArray<nsAutoPtr<nsSMILInterval> >      IntervalList;
   typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
   typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
 
@@ -353,43 +374,47 @@ protected:
   template <class TestFunctor>
   void RemoveInstanceTimes(InstanceTimeList& aArray, TestFunctor& aTest);
 
   //
   // Implementation helpers
   //
 
   nsresult          SetBeginSpec(const nsAString& aBeginSpec,
-                                 nsIContent* aContextNode);
+                                 Element* aContextNode,
+                                 RemovalTestFunction aRemove);
   nsresult          SetEndSpec(const nsAString& aEndSpec,
-                               nsIContent* aContextNode);
+                               Element* aContextNode,
+                               RemovalTestFunction aRemove);
   nsresult          SetSimpleDuration(const nsAString& aDurSpec);
   nsresult          SetMin(const nsAString& aMinSpec);
   nsresult          SetMax(const nsAString& aMaxSpec);
   nsresult          SetRestart(const nsAString& aRestartSpec);
   nsresult          SetRepeatCount(const nsAString& aRepeatCountSpec);
   nsresult          SetRepeatDur(const nsAString& aRepeatDurSpec);
   nsresult          SetFillMode(const nsAString& aFillModeSpec);
 
-  void              UnsetBeginSpec();
-  void              UnsetEndSpec();
+  void              UnsetBeginSpec(RemovalTestFunction aRemove);
+  void              UnsetEndSpec(RemovalTestFunction aRemove);
   void              UnsetSimpleDuration();
   void              UnsetMin();
   void              UnsetMax();
   void              UnsetRestart();
   void              UnsetRepeatCount();
   void              UnsetRepeatDur();
   void              UnsetFillMode();
 
   nsresult          SetBeginOrEndSpec(const nsAString& aSpec,
-                                      nsIContent* aContextNode,
-                                      PRBool aIsBegin);
-  void              ClearBeginOrEndSpecs(PRBool aIsBegin);
+                                      Element* aContextNode,
+                                      PRBool aIsBegin,
+                                      RemovalTestFunction aRemove);
+  void              ClearSpecs(TimeValueSpecList& aSpecs,
+                               InstanceTimeList& aInstances,
+                               RemovalTestFunction aRemove);
   void              RewindTiming();
-  void              RewindInstanceTimes(InstanceTimeList& aList);
   void              DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly);
 
   /**
    * Helper function to check for an early end and, if necessary, update the
    * current interval accordingly.
    *
    * See SMIL 3.0, section 5.4.5, Element life cycle, "Active Time - Playing an
    * interval" for a description of ending early.
@@ -481,16 +506,17 @@ protected:
   PRBool            GetNextMilestone(nsSMILMilestone& aNextMilestone) const;
 
   void              NotifyNewInterval();
   void              NotifyChangedInterval();
   void              FireTimeEventAsync(PRUint32 aMsg, PRInt32 aDetail);
   const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
   const nsSMILInterval* GetPreviousInterval() const;
   PRBool            HasPlayed() const { return !mOldIntervals.IsEmpty(); }
+  PRBool            EndHasEventConditions() const;
 
   // Hashtable callback methods
   PR_STATIC_CALLBACK(PLDHashOperator) NotifyNewIntervalCallback(
       TimeValueSpecPtrKey* aKey, void* aData);
 
   //
   // Members
   //
@@ -519,25 +545,16 @@ protected:
   {
     RESTART_ALWAYS,
     RESTART_WHENNOTACTIVE,
     RESTART_NEVER
   };
   nsSMILRestartMode               mRestartMode;
   static nsAttrValue::EnumTable   sRestartModeTable[];
 
-  //
-  // We need to distinguish between attempting to set the begin spec and failing
-  // (in which case the mBeginSpecs array will be empty) and not attempting to
-  // set the begin spec at all. In the first case, we should act as if the begin
-  // was indefinite, and in the second, we should act as if begin was 0s.
-  //
-  PRPackedBool                    mBeginSpecSet;
-  PRPackedBool                    mEndHasEventConditions;
-
   InstanceTimeList                mBeginInstances;
   InstanceTimeList                mEndInstances;
   PRUint32                        mInstanceSerialIndex;
 
   nsSMILAnimationFunction*        mClient;
   nsAutoPtr<nsSMILInterval>       mCurrentInterval;
   IntervalList                    mOldIntervals;
   PRUint32                        mCurrentRepeatIteration;
--- a/content/smil/test/Makefile.in
+++ b/content/smil/test/Makefile.in
@@ -72,16 +72,17 @@ include $(topsrcdir)/config/rules.mk
 	  test_smilMappedAttrPaced.xhtml \
 	  test_smilReset.xhtml \
 	  test_smilRestart.xhtml \
 	  test_smilFillMode.xhtml \
 	  test_smilGetStartTime.xhtml \
 	  test_smilGetSimpleDuration.xhtml \
 	  test_smilKeySplines.xhtml \
 	  test_smilKeyTimesPacedMode.xhtml \
+	  test_smilRepeatTiming.xhtml \
 	  test_smilSetCurrentTime.xhtml \
 	  test_smilSync.xhtml \
 	  test_smilSyncbaseTarget.xhtml \
 	  test_smilSyncTransform.xhtml \
 	  test_smilTextZoom.xhtml \
 	  test_smilTimeEvents.xhtml \
 	  test_smilTiming.xhtml \
 	  test_smilTimingZeroIntervals.xhtml \
new file mode 100644
--- /dev/null
+++ b/content/smil/test/test_smilRepeatTiming.xhtml
@@ -0,0 +1,96 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=485157
+-->
+<head>
+  <title>Test repeat timing</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank"
+  href="https://bugzilla.mozilla.org/show_bug.cgi?id=485157">Mozilla Bug
+  485157</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
+  <rect width="100" height="100" fill="green">
+    <set attributeName="width" to="100" dur="20s" repeatCount="5" begin="0s"
+      id="a" onrepeat="startWaiting(evt)"/>
+    <set attributeName="fill" attributeType="CSS" to="green"
+      begin="a.repeat(1)" onbegin="expectedBegin()" dur="20s"/>
+    <set attributeName="x" to="100"
+      begin="a.repeat(2)" onbegin="unexpectedBegin(this)" dur="20s"/>
+    <set attributeName="y" to="100"
+      begin="a.repeat(0)" onbegin="unexpectedBegin(this)" dur="20s"/>
+    <set attributeName="width" to="100"
+      begin="a.repeat(-1)" onbegin="unexpectedBegin(this)" dur="20s"/>
+    <set attributeName="height" to="100"
+      begin="a.repeat(a)" onbegin="unexpectedBegin(this)" dur="20s"/>
+  </rect>
+</svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+/** Test SMIL repeat timing **/
+
+/* Global Variables */
+const gTimeoutDur = 5000; // Time until we give up waiting for events in ms
+var gSvg  = document.getElementById('svg');
+var gRect = document.getElementById('circle');
+var gTimeoutID;
+var gGotBegin = false;
+
+SimpleTest.waitForExplicitFinish();
+
+function testBegin()
+{
+  gSvg.setCurrentTime(19.999);
+}
+
+function startWaiting(evt)
+{
+  is(evt.detail, 1, "Unexpected repeat event received: test broken");
+  if (gGotBegin)
+    return;
+
+  gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
+}
+
+function timeoutFail()
+{
+  ok(false, "Timed out waiting for begin event");
+  finish();
+}
+
+function expectedBegin()
+{
+  is(gGotBegin, false,
+     "Got begin event more than once for non-repeating animation");
+  gGotBegin = true;
+  clearTimeout(gTimeoutID);
+  // Wait a moment before finishing in case there are erroneous events waiting
+  // to be processed.
+  setTimeout(finish, 10);
+}
+
+function unexpectedBegin(elem)
+{
+  ok(false, "Got unexpected begin from animation with spec: " +
+            elem.getAttribute('begin'));
+}
+
+function finish()
+{
+  gSvg.pauseAnimations();
+  SimpleTest.finish();
+}
+
+window.addEventListener("load", testBegin, false);
+]]>
+</script>
+</pre>
+</body>
+</html>
--- a/content/svg/content/src/SVGLength.cpp
+++ b/content/svg/content/src/SVGLength.cpp
@@ -190,54 +190,38 @@ SVGLength::GetValueInSpecifiedUnit(PRUin
 float
 SVGLength::GetUserUnitsPerUnit(const nsSVGElement *aElement, PRUint8 aAxis) const
 {
   switch (mUnit) {
     case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
     case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
       return 1.0f;
     case nsIDOMSVGLength::SVG_LENGTHTYPE_MM:
-      return INCHES_PER_MM_FLOAT * GetUserUnitsPerInch(aElement);
+      return INCHES_PER_MM_FLOAT * GetUserUnitsPerInch();
     case nsIDOMSVGLength::SVG_LENGTHTYPE_CM:
-      return INCHES_PER_CM_FLOAT * GetUserUnitsPerInch(aElement);
+      return INCHES_PER_CM_FLOAT * GetUserUnitsPerInch();
     case nsIDOMSVGLength::SVG_LENGTHTYPE_IN:
-      return GetUserUnitsPerInch(aElement);
+      return GetUserUnitsPerInch();
     case nsIDOMSVGLength::SVG_LENGTHTYPE_PT:
-      return (1.0f/POINTS_PER_INCH_FLOAT) * GetUserUnitsPerInch(aElement);
+      return (1.0f/POINTS_PER_INCH_FLOAT) * GetUserUnitsPerInch();
     case nsIDOMSVGLength::SVG_LENGTHTYPE_PC:
-      return (12.0f/POINTS_PER_INCH_FLOAT) * GetUserUnitsPerInch(aElement);
+      return (12.0f/POINTS_PER_INCH_FLOAT) * GetUserUnitsPerInch();
     case nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE:
       return GetUserUnitsPerPercent(aElement, aAxis);
     case nsIDOMSVGLength::SVG_LENGTHTYPE_EMS:
       return nsSVGUtils::GetFontSize(const_cast<nsSVGElement*>(aElement));
     case nsIDOMSVGLength::SVG_LENGTHTYPE_EXS:
       return nsSVGUtils::GetFontXHeight(const_cast<nsSVGElement*>(aElement));
     default:
       NS_NOTREACHED("Unknown unit type");
       return std::numeric_limits<float>::quiet_NaN();
   }
 }
 
 /* static */ float
-SVGLength::GetUserUnitsPerInch(const nsIContent *aContent)
-{
-  if (aContent) {
-    nsPresContext *context = nsContentUtils::GetContextForContent(
-                                           const_cast<nsIContent*>(aContent));
-    if (context) {
-      float uuPerInch = float(context->AppUnitsPerInch()) /
-                        float(nsPresContext::AppUnitsPerCSSPixel());
-      NS_ASSERTION(uuPerInch > 0.0f, "Non-positive user units per inch");
-      return uuPerInch;
-    }
-  }
-  return std::numeric_limits<float>::quiet_NaN();
-}
-
-/* static */ float
 SVGLength::GetUserUnitsPerPercent(const nsSVGElement *aElement, PRUint8 aAxis)
 {
   if (aElement) {
     nsSVGSVGElement *viewportElement = const_cast<nsSVGElement*>(aElement)->GetCtx();
     if (viewportElement) {
       return NS_MAX(viewportElement->GetLength(aAxis) / 100.0f, 0.0f);
     }
   }
--- a/content/svg/content/src/SVGLength.h
+++ b/content/svg/content/src/SVGLength.h
@@ -210,35 +210,23 @@ private:
    *
    * This method returns numeric_limits<float>::quiet_NaN() if the conversion
    * factor between the length's current unit and user units is undefined (see
    * the comments for GetUserUnitsPerInch and GetUserUnitsPerPercent).
    */
   float GetUserUnitsPerUnit(const nsSVGElement *aElement, PRUint8 aAxis) const;
 
   /**
-   * The conversion factor between user units (CSS px) and a CSS absolute unit
-   * (in this case inches) is the same for all elements in a given document,
-   * except for elements for which the factor is undefined. The conversion
-   * factor is undefined for elements that are not in a document tree, and for
-   * elements in a document tree that don't have a pres context (elements under
-   * a display:none iframe, or elements belonging to a data document (an XHR
-   * response document or a document created via createDocument()).
-   *
-   * This helper acts as the basis for conversion between user units and all
-   * CSS absolute units (the conversion factors between CSS absolute units are
-   * fixed). Inches are chosen as the canonical unit because that's what
-   * pres/device contexts store, so it makes sense for this helper to also work
-   * in those terms to eliminate unnecessary multiplications/divisions that
-   * must then be reversed.
-   *
-   * This function returns a positive value if the conversion factor is
-   * defined, otherwise it returns numeric_limits<float>::quiet_NaN().
+   * The conversion factor between user units (CSS px) and CSS inches is
+   * constant: 96 px per inch.
    */
-  static float GetUserUnitsPerInch(const nsIContent *aContent);
+  static float GetUserUnitsPerInch()
+  {
+    return 96.0;
+  }
 
   /**
    * The conversion factor between user units and percentage units depends on
    * aElement being non-null, and on aElement having a viewport element
    * ancestor with only appropriate SVG elements between aElement and that
    * ancestor. If that's not the case, then the conversion factor is undefined.
    *
    * This function returns a non-negative value if the conversion factor is
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -341,17 +341,17 @@ SVGMotionSMILAnimationFunction::
   // Clear stale data
   mPath = nsnull;
   mPathVertices.Clear();
   mPathSourceType = ePathSourceType_None;
 
   // Do we have a mpath child? if so, it trumps everything. Otherwise, we look
   // through our list of path-defining attributes, in order of priority.
   nsSVGMpathElement* firstMpathChild =
-    GetFirstMpathChild(&mAnimationElement->Content());
+    GetFirstMpathChild(&mAnimationElement->AsElement());
 
   if (firstMpathChild) {
     RebuildPathAndVerticesFromMpathElem(firstMpathChild);
     mValueNeedsReparsingEverySample = PR_FALSE;
   } else if (HasAttr(nsGkAtoms::path)) {
     RebuildPathAndVerticesFromPathAttr();
     mValueNeedsReparsingEverySample = PR_FALSE;
   } else {
--- a/content/svg/content/src/nsSVGAnimationElement.cpp
+++ b/content/svg/content/src/nsSVGAnimationElement.cpp
@@ -101,24 +101,24 @@ nsSVGAnimationElement::Init()
   mTimedElement.SetTimeClient(&AnimationFunction());
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsISMILAnimationElement methods
 
-const nsIContent&
-nsSVGAnimationElement::Content() const
+const Element&
+nsSVGAnimationElement::AsElement() const
 {
   return *this;
 }
 
-nsIContent&
-nsSVGAnimationElement::Content()
+Element&
+nsSVGAnimationElement::AsElement()
 {
   return *this;
 }
 
 const nsAttrValue*
 nsSVGAnimationElement::GetAnimAttr(nsIAtom* aName) const
 {
   return mAttrsAndChildren.GetAttr(aName, kNameSpaceID_None);
@@ -367,46 +367,55 @@ nsSVGAnimationElement::ParseAttribute(PR
       if (NS_FAILED(rv)) {
         ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
         return PR_FALSE;
       }
       return PR_TRUE;
     }
   }
 
-  PRBool returnVal =
-    nsSVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
-                                              aValue, aResult);
-  if (aNamespaceID == kNameSpaceID_XLink &&
-      aAttribute == nsGkAtoms::href &&
-      IsInDoc()) {
-    // NOTE: If we fail the IsInDoc call, it's ok -- we'll update the target
-    // on next BindToTree call.
-    UpdateHrefTarget(this, aValue);
-  }
-  return returnVal;
+  return nsSVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
+                                                   aValue, aResult);
+}
+
+nsresult
+nsSVGAnimationElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
+                                    const nsAString* aValue, PRBool aNotify)
+{
+  nsresult rv =
+    nsSVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue,
+                                            aNotify);
+
+  if (aNamespaceID != kNameSpaceID_XLink || aName != nsGkAtoms::href)
+    return rv;
+
+  if (!aValue) {
+    mHrefTarget.Unlink();
+    AnimationTargetChanged();
+  } else if (IsInDoc()) {
+    UpdateHrefTarget(this, *aValue);
+  } // else: we're not yet in a document -- we'll update the target on
+    // next BindToTree call.
+
+  return rv;
 }
 
 nsresult
 nsSVGAnimationElement::UnsetAttr(PRInt32 aNamespaceID,
                                  nsIAtom* aAttribute, PRBool aNotify)
 {
   nsresult rv = nsSVGAnimationElementBase::UnsetAttr(aNamespaceID, aAttribute,
                                                      aNotify);
   NS_ENSURE_SUCCESS(rv,rv);
 
   if (aNamespaceID == kNameSpaceID_None) {
     if (AnimationFunction().UnsetAttr(aAttribute) ||
         mTimedElement.UnsetAttr(aAttribute)) {
       AnimationNeedsResample();
     }
-  } else if (aNamespaceID == kNameSpaceID_XLink) {
-    if (aAttribute == nsGkAtoms::href) {
-      mHrefTarget.Unlink();
-    }
   }
 
   return NS_OK;
 }
 
 PRBool
 nsSVGAnimationElement::IsNodeOfType(PRUint32 aFlags) const
 {
@@ -486,9 +495,17 @@ void
 nsSVGAnimationElement::UpdateHrefTarget(nsIContent* aNodeForContext,
                                         const nsAString& aHrefStr)
 {
   nsCOMPtr<nsIURI> targetURI;
   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
   nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI),
                                             aHrefStr, GetOwnerDoc(), baseURI);
   mHrefTarget.Reset(aNodeForContext, targetURI);
+  AnimationTargetChanged();
 }
+
+void
+nsSVGAnimationElement::AnimationTargetChanged()
+{
+  mTimedElement.HandleTargetElementChange(GetTargetElementContent());
+  AnimationNeedsResample();
+}
--- a/content/svg/content/src/nsSVGAnimationElement.h
+++ b/content/svg/content/src/nsSVGAnimationElement.h
@@ -79,47 +79,50 @@ public:
 
   virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
 
   // nsGenericElement specializations
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
+  virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
+                                const nsAString* aValue, PRBool aNotify);
 
   // nsISMILAnimationElement interface
-  virtual const nsIContent& Content() const;
-  virtual nsIContent& Content();
+  virtual const Element& AsElement() const;
+  virtual Element& AsElement();
   virtual const nsAttrValue* GetAnimAttr(nsIAtom* aName) const;
   virtual PRBool GetAnimAttr(nsIAtom* aAttName, nsAString& aResult) const;
   virtual PRBool HasAnimAttr(nsIAtom* aAttName) const;
-  virtual mozilla::dom::Element* GetTargetElementContent();
+  virtual Element* GetTargetElementContent();
   virtual nsIAtom* GetTargetAttributeName() const;
   virtual nsSMILTargetAttrType GetTargetAttributeType() const;
   virtual nsSMILTimedElement& TimedElement();
   virtual nsSMILTimeContainer* GetTimeContainer();
 
 protected:
   // nsSVGElement overrides
   PRBool IsEventName(nsIAtom* aName);
 
   void UpdateHrefTarget(nsIContent* aNodeForContext,
                         const nsAString& aHrefStr);
+  void AnimationTargetChanged();
 
   class TargetReference : public nsReferencedElement {
   public:
     TargetReference(nsSVGAnimationElement* aAnimationElement) :
       mAnimationElement(aAnimationElement) {}
   protected:
     // We need to be notified when target changes, in order to request a
     // sample (which will clear animation effects from old target and apply
-    // them to the new target).
+    // them to the new target) and update any event registrations.
     virtual void ElementChanged(Element* aFrom, Element* aTo) {
       nsReferencedElement::ElementChanged(aFrom, aTo);
-      mAnimationElement->AnimationNeedsResample();
+      mAnimationElement->AnimationTargetChanged();
     }
 
     // We need to override IsPersistent to get persistent tracking (beyond the
     // first time the target changes)
     virtual PRBool IsPersistent() { return PR_TRUE; }
   private:
     nsSVGAnimationElement* const mAnimationElement;
   };
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -180,41 +180,16 @@ GetValueFromString(const nsAString &aVal
     if (IsValidUnitType(*aUnitType)) {
       return NS_OK;
     }
   }
   
   return NS_ERROR_DOM_SYNTAX_ERR;
 }
 
-float
-nsSVGLength2::GetMMPerPixel(nsSVGSVGElement *aCtx) const
-{
-  if (!aCtx)
-    return 1;
-
-  float mmPerPx = aCtx->GetMMPerPx(mCtxType);
-
-  if (mmPerPx == 0.0f) {
-    NS_ASSERTION(mmPerPx != 0.0f, "invalid mm/pixels");
-    mmPerPx = 1e-4f; // some small value
-  }
-
-  return mmPerPx;
-}
-
-/*static*/ float
-nsSVGLength2::GetMMPerPixel(nsIFrame *aNonSVGFrame)
-{
-  nsPresContext* presContext = aNonSVGFrame->PresContext();
-  float pixelsPerInch =
-    presContext->AppUnitsToFloatCSSPixels(presContext->AppUnitsPerInch());
-  return 25.4f/pixelsPerInch;
-}
-
 static float
 FixAxisLength(float aLength)
 {
   if (aLength == 0.0f) {
     NS_WARNING("zero axis length");
     return 1e-20f;
   }
   return aLength;
@@ -268,25 +243,25 @@ nsSVGLength2::GetUnitScaleFactor(nsSVGEl
 float
 nsSVGLength2::GetUnitScaleFactor(nsSVGSVGElement *aCtx, PRUint8 aUnitType) const
 {
   switch (aUnitType) {
   case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
     return 1;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_MM:
-    return GetMMPerPixel(aCtx);
+    return GetMMPerPixel();
   case nsIDOMSVGLength::SVG_LENGTHTYPE_CM:
-    return GetMMPerPixel(aCtx) / 10.0f;
+    return GetMMPerPixel() / 10.0f;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_IN:
-    return GetMMPerPixel(aCtx) / 25.4f;
+    return GetMMPerPixel() / MM_PER_INCH_FLOAT;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PT:
-    return GetMMPerPixel(aCtx) * POINTS_PER_INCH_FLOAT / 25.4f;
+    return GetMMPerPixel() * POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PC:
-    return GetMMPerPixel(aCtx) * POINTS_PER_INCH_FLOAT / 24.4f / 12.0f;
+    return GetMMPerPixel() * POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT / 12.0f;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE:
     return 100.0f / GetAxisLength(aCtx);
   case nsIDOMSVGLength::SVG_LENGTHTYPE_EMS:
     return 1 / GetEmLength(aCtx);
   case nsIDOMSVGLength::SVG_LENGTHTYPE_EXS:
     return 1 / GetExLength(aCtx);
   default:
     NS_NOTREACHED("Unknown unit type");
@@ -301,25 +276,25 @@ nsSVGLength2::GetUnitScaleFactor(nsIFram
   if (content->IsSVG())
     return GetUnitScaleFactor(static_cast<nsSVGElement*>(content), aUnitType);
 
   switch (aUnitType) {
   case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
     return 1;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_MM:
-    return GetMMPerPixel(aFrame);
+    return GetMMPerPixel();
   case nsIDOMSVGLength::SVG_LENGTHTYPE_CM:
-    return GetMMPerPixel(aFrame) / 10.0f;
+    return GetMMPerPixel() / 10.0f;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_IN:
-    return GetMMPerPixel(aFrame) / 25.4f;
+    return GetMMPerPixel() / MM_PER_INCH_FLOAT;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PT:
-    return GetMMPerPixel(aFrame) * POINTS_PER_INCH_FLOAT / 25.4f;
+    return GetMMPerPixel() * POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PC:
-    return GetMMPerPixel(aFrame) * POINTS_PER_INCH_FLOAT / 24.4f / 12.0f;
+    return GetMMPerPixel() * POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT / 12.0f;
   case nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE:
     return 100.0f / GetAxisLength(aFrame);
   case nsIDOMSVGLength::SVG_LENGTHTYPE_EMS:
     return 1 / GetEmLength(aFrame);
   case nsIDOMSVGLength::SVG_LENGTHTYPE_EXS:
     return 1 / GetExLength(aFrame);
   default:
     NS_NOTREACHED("Unknown unit type");
--- a/content/svg/content/src/nsSVGLength2.h
+++ b/content/svg/content/src/nsSVGLength2.h
@@ -102,17 +102,17 @@ private:
   
   float mAnimVal;
   float mBaseVal;
   PRUint8 mSpecifiedUnitType;
   PRUint8 mAttrEnum; // element specified tracking for attribute
   PRUint8 mCtxType; // X, Y or Unspecified
   PRPackedBool mIsAnimated;
   
-  static float GetMMPerPixel(nsIFrame *aNonSVGFrame);
+  static float GetMMPerPixel() { return MM_PER_INCH_FLOAT / 96; }
   float GetAxisLength(nsIFrame *aNonSVGFrame) const;
   static float GetEmLength(nsIFrame *aFrame)
     { return nsSVGUtils::GetFontSize(aFrame); }
   static float GetExLength(nsIFrame *aFrame)
     { return nsSVGUtils::GetFontXHeight(aFrame); }
   float GetUnitScaleFactor(nsIFrame *aFrame, PRUint8 aUnitType) const;
 
   float GetMMPerPixel(nsSVGSVGElement *aCtx) const;
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -196,17 +196,16 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGSVG
 // Implementation
 
 nsSVGSVGElement::nsSVGSVGElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                                  PRUint32 aFromParser)
   : nsSVGSVGElementBase(aNodeInfo),
     mCoordCtx(nsnull),
     mViewportWidth(0),
     mViewportHeight(0),
-    mCoordCtxMmPerPx(0),
     mCurrentTranslate(0.0f, 0.0f),
     mCurrentScale(1.0f),
     mPreviousTranslate(0.0f, 0.0f),
     mPreviousScale(1.0f),
     mRedrawSuspendCount(0)
 #ifdef MOZ_SMIL
     ,mStartAnimationOnBindToTree(!aFromParser)
 #endif // MOZ_SMIL
@@ -304,49 +303,32 @@ nsSVGSVGElement::GetViewport(nsIDOMSVGRe
   // XXX
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* readonly attribute float pixelUnitToMillimeterX; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetPixelUnitToMillimeterX(float *aPixelUnitToMillimeterX)
 {
-  // to correctly determine this, the caller would need to pass in the
-  // right PresContext...
-  nsPresContext *context = nsContentUtils::GetContextForContent(this);
-  if (!context) {
-    *aPixelUnitToMillimeterX = 0.28f; // 90dpi
-    return NS_OK;
-  }
-
-  *aPixelUnitToMillimeterX = 25.4f / nsPresContext::AppUnitsToIntCSSPixels(context->AppUnitsPerInch());
+  *aPixelUnitToMillimeterX = MM_PER_INCH_FLOAT / 96;
   return NS_OK;
 }
 
 /* readonly attribute float pixelUnitToMillimeterY; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetPixelUnitToMillimeterY(float *aPixelUnitToMillimeterY)
 {
   return GetPixelUnitToMillimeterX(aPixelUnitToMillimeterY);
 }
 
 /* readonly attribute float screenPixelToMillimeterX; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetScreenPixelToMillimeterX(float *aScreenPixelToMillimeterX)
 {
-  // to correctly determine this, the caller would need to pass in the
-  // right PresContext...
-  nsPresContext *context = nsContentUtils::GetContextForContent(this);
-  if (!context) {
-    *aScreenPixelToMillimeterX = 0.28f; // 90dpi
-    return NS_OK;
-  }
-
-  *aScreenPixelToMillimeterX = 25.4f /
-      nsPresContext::AppUnitsToIntCSSPixels(context->AppUnitsPerInch());
+  *aScreenPixelToMillimeterX = MM_PER_INCH_FLOAT / 96;
   return NS_OK;
 }
 
 /* readonly attribute float screenPixelToMillimeterY; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetScreenPixelToMillimeterY(float *aScreenPixelToMillimeterY)
 {
   return GetScreenPixelToMillimeterX(aScreenPixelToMillimeterY);
@@ -1147,25 +1129,16 @@ nsSVGSVGElement::GetLength(PRUint8 aCtxT
   case nsSVGUtils::Y:
     return h;
   case nsSVGUtils::XY:
     return float(nsSVGUtils::ComputeNormalizedHypotenuse(w, h));
   }
   return 0;
 }
 
-float
-nsSVGSVGElement::GetMMPerPx(PRUint8 aCtxType)
-{
-  if (mCoordCtxMmPerPx == 0.0f) {
-    GetScreenPixelToMillimeterX(&mCoordCtxMmPerPx);
-  }
-  return mCoordCtxMmPerPx;
-}
-
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
 nsSVGSVGElement::PrependLocalTransformTo(const gfxMatrix &aMatrix)
 {
   if (nsSVGUtils::IsInnerSVG(this)) {
     float x, y;
--- a/content/svg/content/src/nsSVGSVGElement.h
+++ b/content/svg/content/src/nsSVGSVGElement.h
@@ -197,17 +197,16 @@ public:
   virtual void DidChangeViewBox(PRBool aDoSetAttr);
   virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
 
   virtual void DidAnimateViewBox();
   virtual void DidAnimatePreserveAspectRatio();
   
   // nsSVGSVGElement methods:
   float GetLength(PRUint8 mCtxType);
-  float GetMMPerPx(PRUint8 mCtxType = 0);
 
   // public helpers:
   gfxMatrix GetViewBoxTransform();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   svgFloatSize GetViewportSize() const {
     return svgFloatSize(mViewportWidth, mViewportHeight);
@@ -282,18 +281,16 @@ protected:
   //
   //   http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
   //
   // XXXjwatt Currently only used for outer <svg>, but maybe we could use -1 to
   // flag this as an inner <svg> to save the overhead of GetCtx calls?
   // XXXjwatt our frame should probably reset these when it's destroyed.
   float mViewportWidth, mViewportHeight;
 
-  float mCoordCtxMmPerPx;
-
 #ifdef MOZ_SMIL
   // The time container for animations within this SVG document fragment. Set
   // for all outermost <svg> elements (not nested <svg> elements).
   nsAutoPtr<nsSMILTimeContainer> mTimedDocumentRoot;
 #endif // MOZ_SMIL
 
   // zoom and pan
   // IMPORTANT: see the comment in RecordCurrentScaleTranslate before writing
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1973,17 +1973,21 @@ nsXULElement::LoadSrc()
         !GetOwnerDoc()->GetRootElement() ||
         GetOwnerDoc()->GetRootElement()->
             NodeInfo()->Equals(nsGkAtoms::overlay, kNameSpaceID_XUL)) {
         return NS_OK;
     }
     nsXULSlots* slots = static_cast<nsXULSlots*>(GetSlots());
     NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
     if (!slots->mFrameLoader) {
-        slots->mFrameLoader = nsFrameLoader::Create(this);
+        // PR_FALSE as the last parameter so that xul:iframe/browser/editor
+        // session history handling works like dynamic html:iframes.
+        // Usually xul elements are used in chrome, which doesn't have
+        // session history at all.
+        slots->mFrameLoader = nsFrameLoader::Create(this, PR_FALSE);
         NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
     }
 
     return slots->mFrameLoader->LoadFrame();
 }
 
 nsresult
 nsXULElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -671,16 +671,18 @@ DispatchPings(nsIContent *content, nsIUR
 }
 
 static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
 
 //*****************************************************************************
 //***    nsDocShell: Object Management
 //*****************************************************************************
 
+static PRUint64 gDocshellIDCounter = 0;
+
 // Note: operator new zeros our memory
 nsDocShell::nsDocShell():
     nsDocLoader(),
     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
     mTreeOwner(nsnull),
     mChromeEventHandler(nsnull),
     mCharsetReloadState(eCharsetReloadInit),
     mChildOffset(0),
@@ -710,16 +712,17 @@ nsDocShell::nsDocShell():
     mIsBeingDestroyed(PR_FALSE),
     mIsExecutingOnLoadHandler(PR_FALSE),
     mIsPrintingOrPP(PR_FALSE),
     mSavingOldViewer(PR_FALSE)
 #ifdef DEBUG
     , mInEnsureScriptEnv(PR_FALSE)
 #endif
 {
+    mHistoryID = ++gDocshellIDCounter;
     if (gDocShellCount++ == 0) {
         NS_ASSERTION(sURIFixup == nsnull,
                      "Huh, sURIFixup not null in first nsDocShell ctor!");
 
         CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
     }
 
 #ifdef PR_LOGGING
@@ -1220,17 +1223,29 @@ nsDocShell::LoadURI(nsIURI * aURI,
              */
             
             // Get the parent's load type
             parentDS->GetLoadType(&parentLoadType);            
 
             nsCOMPtr<nsIDocShellHistory> parent(do_QueryInterface(parentAsItem));
             if (parent) {
                 // Get the ShEntry for the child from the parent
-                parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
+                nsCOMPtr<nsISHEntry> currentSH;
+                PRBool oshe = PR_FALSE;
+                parent->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
+                PRBool dynamicallyAddedChild = mDynamicallyCreated;
+                if (!dynamicallyAddedChild && !oshe && currentSH) {
+                    currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
+                }
+                if (!dynamicallyAddedChild) {
+                    // Only use the old SHEntry, if we're sure enough that
+                    // it wasn't originally for some other frame.
+                    parent->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
+                }
+
                 // Make some decisions on the child frame's loadType based on the 
                 // parent's loadType. 
                 if (mCurrentURI == nsnull) {
                     // This is a newly created frame. Check for exception cases first. 
                     // By default the subframe will inherit the parent's loadType.
                     if (shEntry && (parentLoadType == LOAD_NORMAL ||
                                     parentLoadType == LOAD_LINK   ||
                                     parentLoadType == LOAD_NORMAL_EXTERNAL)) {
@@ -2952,16 +2967,23 @@ nsDocShell::SetTreeOwner(nsIDocShellTree
 NS_IMETHODIMP
 nsDocShell::SetChildOffset(PRUint32 aChildOffset)
 {
     mChildOffset = aChildOffset;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::GetHistoryID(PRUint64* aID)
+{
+  *aID = mHistoryID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::GetIsInUnload(PRBool* aIsInUnload)
 {
     *aIsInUnload = mFiredUnloadEvent;
     return NS_OK;
 }
 
 //*****************************************************************************
 // nsDocShell::nsIDocShellTreeNode
@@ -3004,40 +3026,29 @@ nsDocShell::AddChild(nsIDocShellTreeItem
     // from us.
     aChild->SetTreeOwner(nsnull);
     
     nsresult res = AddChildLoader(childAsDocLoader);
     NS_ENSURE_SUCCESS(res, res);
     NS_ASSERTION(mChildList.Count() > 0,
                  "child list must not be empty after a successful add");
 
-    // Set the child's index in the parent's children list 
-    // XXX What if the parent had different types of children?
-    // XXX in that case docshell hierarchy and SH hierarchy won't match.
-    {
-        nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
-        if (childDocShell) {
-            // If there are frameloaders in the finalization list, reduce
-            // the offset so that the SH hierarchy is more likely to match the
-            // docshell hierarchy
-            nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
-            PRUint32 offset = mChildList.Count() - 1;
-            if (doc) {
-               PRUint32 oldChildCount = offset; // Current child count - 1
-               for (PRUint32 i = 0; i < oldChildCount; ++i) {
-                 nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
-                 if (doc->FrameLoaderScheduledToBeFinalized(child)) {
-                   --offset;
-                 }
-               }
-            }
-
-            childDocShell->SetChildOffset(offset);
-        }
-    }
+    nsCOMPtr<nsIDocShellHistory> docshellhistory = do_QueryInterface(aChild);
+    PRBool dynamic = PR_FALSE;
+    docshellhistory->GetCreatedDynamically(&dynamic);
+    if (!dynamic) {
+        nsCOMPtr<nsISHEntry> currentSH;
+        PRBool oshe = PR_FALSE;
+        GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
+        if (currentSH) {
+            currentSH->HasDynamicallyAddedChild(&dynamic);
+        }
+    }
+    nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
+    childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Count() - 1);
 
     /* Set the child's global history if the parent has one */
     if (mGlobalHistory) {
         nsCOMPtr<nsIDocShellHistory>
             dsHistoryChild(do_QueryInterface(aChild));
         if (dsHistoryChild)
             dsHistoryChild->SetUseGlobalHistory(PR_TRUE);
     }
@@ -3392,16 +3403,99 @@ nsDocShell::SetUseGlobalHistory(PRBool a
 
 NS_IMETHODIMP
 nsDocShell::GetUseGlobalHistory(PRBool *aUseGlobalHistory)
 {
     *aUseGlobalHistory = (mGlobalHistory != nsnull);
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShell::RemoveFromSessionHistory()
+{
+    nsCOMPtr<nsISHistoryInternal> internalHistory;
+    nsCOMPtr<nsISHistory> sessionHistory;
+    nsCOMPtr<nsIDocShellTreeItem> root;
+    GetSameTypeRootTreeItem(getter_AddRefs(root));
+    if (root) {
+        nsCOMPtr<nsIWebNavigation> rootAsWebnav =
+            do_QueryInterface(root);
+        if (rootAsWebnav) {
+            rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
+            internalHistory = do_QueryInterface(sessionHistory);
+        }
+    }
+    if (!internalHistory) {
+        return NS_OK;
+    }
+
+    PRInt32 index = 0;
+    sessionHistory->GetIndex(&index);
+    nsAutoTArray<PRUint64, 16> ids;
+    ids.AppendElement(mHistoryID);
+    internalHistory->RemoveEntries(ids, index);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetCreatedDynamically(PRBool aDynamic)
+{
+    mDynamicallyCreated = aDynamic;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetCreatedDynamically(PRBool* aDynamic)
+{
+    *aDynamic = mDynamicallyCreated;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, PRBool* aOSHE)
+{
+    *aOSHE = PR_FALSE;
+    *aEntry = nsnull;
+    if (mLSHE) {
+        NS_ADDREF(*aEntry = mLSHE);
+    } else if (mOSHE) {
+        NS_ADDREF(*aEntry = mOSHE);
+        *aOSHE = PR_TRUE;
+    }
+    return NS_OK;
+}
+
+void
+nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
+{
+  nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
+  nsCOMPtr<nsISHistory> rootSH;
+  GetRootSessionHistory(getter_AddRefs(rootSH));
+  nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
+  if (!history || !shcontainer) {
+    return;
+  }
+
+  PRInt32 count = 0;
+  shcontainer->GetChildCount(&count);
+  nsAutoTArray<PRUint64, 16> ids;
+  for (PRInt32 i = 0; i < count; ++i) {
+    nsCOMPtr<nsISHEntry> child;
+    shcontainer->GetChildAt(i, getter_AddRefs(child));
+    if (child) {
+      PRUint64 id = 0;
+      child->GetDocshellID(&id);
+      ids.AppendElement(id);
+    }
+  }
+  PRInt32 index = 0;
+  rootSH->GetIndex(&index);
+  history->RemoveEntries(ids, index);
+}
+
 //-------------------------------------
 //-- Helper Method for Print discovery
 //-------------------------------------
 PRBool 
 nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog)
 {
   if (mIsPrintingOrPP && aDisplayErrorDialog) {
     DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nsnull, nsnull);
@@ -5628,16 +5722,41 @@ nsDocShell::OnStateChange(nsIWebProgress
         
             PRBool equalUri = PR_TRUE;
             // Store the wyciwyg url in session history, only if it is
             // being loaded fresh for the first time. We don't want 
             // multiple entries for successive loads
             if (mCurrentURI &&
                 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
                 !equalUri) {
+
+                nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
+                GetSameTypeParent(getter_AddRefs(parentAsItem));
+                nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
+                PRBool inOnLoadHandler = PR_FALSE;
+                if (parentDS) {
+                  parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
+                }
+                if (inOnLoadHandler) {
+                    // We're handling parent's load event listener, which causes
+                    // document.write in a subdocument.
+                    // Need to clear the session history for all child
+                    // docshells so that we can handle them like they would
+                    // all be added dynamically.
+                    nsCOMPtr<nsIDocShellHistory> parent =
+                        do_QueryInterface(parentAsItem);
+                    if (parent) {
+                        PRBool oshe = PR_FALSE;
+                        nsCOMPtr<nsISHEntry> entry;
+                        parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
+                        static_cast<nsDocShell*>(parent.get())->
+                            ClearFrameHistory(entry);
+                    }
+                }
+
                 // This is a document.write(). Get the made-up url
                 // from the channel and store it in session history.
                 rv = AddToSessionHistory(uri, wcwgChannel, nsnull,
                                          getter_AddRefs(mLSHE));
                 SetCurrentURI(uri, aRequest, PR_TRUE);
                 // Save history state of the previous page
                 rv = PersistLayoutHistoryState();
                 // We'll never get an Embed() for this load, so just go ahead
@@ -8197,16 +8316,20 @@ nsDocShell::InternalLoad(nsIURI * aURI,
     // mLSHE for the real page.
     if (mLoadType != LOAD_ERROR_PAGE)
         SetHistoryEntry(&mLSHE, aSHEntry);
 
     mSavingOldViewer = savePresentation;
 
     // If we have a saved content viewer in history, restore and show it now.
     if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
+        // Make sure our history ID points to the same ID as
+        // SHEntry's docshell ID.
+        aSHEntry->GetDocshellID(&mHistoryID);
+
         // It's possible that the previous viewer of mContentViewer is the
         // viewer that will end up in aSHEntry when it gets closed.  If that's
         // the case, we need to go ahead and force it into its shentry so we
         // can restore it.
         if (mContentViewer) {
             nsCOMPtr<nsIContentViewer> prevViewer;
             mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
             if (prevViewer) {
@@ -9105,16 +9228,38 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
             cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
         // If we already have a loading history entry, store the new cache key
         // in it.  Otherwise, since we're doing a reload and won't be updating
         // our history entry, store the cache key in our current history entry.
         if (mLSHE)
             mLSHE->SetCacheKey(cacheKey);
         else if (mOSHE)
             mOSHE->SetCacheKey(cacheKey);
+
+        // Since we're force-reloading, clear all the sub frame history.
+        ClearFrameHistory(mLSHE);
+        ClearFrameHistory(mOSHE);
+    }
+
+    if (aLoadType == LOAD_RELOAD_NORMAL) {
+        nsCOMPtr<nsISHEntry> currentSH;
+        PRBool oshe = PR_FALSE;
+        GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
+        PRBool dynamicallyAddedChild = PR_FALSE;
+        if (currentSH) {
+          currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
+        }
+        if (dynamicallyAddedChild) {
+          ClearFrameHistory(currentSH);
+        }
+    }
+
+    if (aLoadType == LOAD_REFRESH) {
+        ClearFrameHistory(mLSHE);
+        ClearFrameHistory(mOSHE);
     }
 
     if (updateHistory && shAvailable) { 
         // Update session history if necessary...
         if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
             /* This is  a fresh page getting loaded for the first time
              *.Create a Entry for it and add it to SH, if this is the
              * rootDocShell
@@ -9594,17 +9739,19 @@ nsDocShell::AddToSessionHistory(nsIURI *
 
     //Title is set in nsDocShell::SetTitle()
     entry->Create(aURI,              // uri
                   EmptyString(),     // Title
                   inputStream,       // Post data stream
                   nsnull,            // LayoutHistory state
                   cacheKey,          // CacheKey
                   mContentTypeHint,  // Content-type
-                  owner);            // Channel or provided owner
+                  owner,             // Channel or provided owner
+                  mHistoryID,
+                  mDynamicallyCreated);
     entry->SetReferrerURI(referrerURI);
     /* If cache got a 'no-store', ask SH not to store
      * HistoryLayoutState. By default, SH will set this
      * flag to PR_TRUE and save HistoryLayoutState.
      */    
     if (discardLayoutState) {
         entry->SetSaveLayoutStateFlag(PR_FALSE);
     }
@@ -9794,16 +9941,18 @@ nsDocShell::WalkHistoryEntries(nsISHEntr
     PRInt32 childCount;
     container->GetChildCount(&childCount);
     for (PRInt32 i = 0; i < childCount; i++) {
         nsCOMPtr<nsISHEntry> childEntry;
         container->GetChildAt(i, getter_AddRefs(childEntry));
         if (!childEntry) {
             // childEntry can be null for valid reasons, for example if the
             // docshell at index i never loaded anything useful.
+            // Remember to clone also nulls in the child array (bug 464064).
+            aCallback(nsnull, nsnull, i, aData);
             continue;
         }
 
         nsDocShell *childShell = nsnull;
         if (aRootShell) {
             // Walk the children of aRootShell and see if one of them
             // has srcChild as a SHEntry.
 
@@ -9846,16 +9995,25 @@ nsDocShell::CloneAndReplaceChild(nsISHEn
 {
     nsresult result = NS_OK;
     nsCOMPtr<nsISHEntry> dest;
 
     CloneAndReplaceData *data = static_cast<CloneAndReplaceData*>(aData);
     PRUint32 cloneID = data->cloneID;
     nsISHEntry *replaceEntry = data->replaceEntry;
 
+    nsCOMPtr<nsISHContainer> container =
+      do_QueryInterface(data->destTreeParent);
+    if (!aEntry) {
+      if (container) {
+        container->AddChild(nsnull, aEntryIndex);
+      }
+      return NS_OK;
+    }
+    
     PRUint32 srcID;
     aEntry->GetID(&srcID);
 
     if (srcID == cloneID) {
         // Just replace the entry, and don't walk the children.
         dest = replaceEntry;
         dest->SetIsSubFrame(PR_TRUE);
     } else {
@@ -9873,18 +10031,16 @@ nsDocShell::CloneAndReplaceChild(nsISHEn
                                     CloneAndReplaceChild, &childData);
         if (NS_FAILED(result))
             return result;
 
         if (aShell)
             aShell->SwapHistoryEntries(aEntry, dest);
     }
 
-    nsCOMPtr<nsISHContainer> container =
-        do_QueryInterface(data->destTreeParent);
     if (container)
         container->AddChild(dest, aEntryIndex);
 
     data->resultEntry = dest;
     return result;
 }
 
 /* static */ nsresult
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -658,16 +658,18 @@ protected:
     nsresult DoCommand(const char * inCommand);
     nsresult EnsureCommandHandler();
 
     nsIChannel* GetCurrentDocChannel();
 protected:
     // Override the parent setter from nsDocLoader
     virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader);
 
+    void ClearFrameHistory(nsISHEntry* aEntry);
+
     // Event type dispatched by RestorePresentation
     class RestorePresentationEvent : public nsRunnable {
     public:
         NS_DECL_NSIRUNNABLE
         RestorePresentationEvent(nsDocShell *ds) : mDocShell(ds) {}
         void Revoke() { mDocShell = nsnull; }
     private:
         nsRefPtr<nsDocShell> mDocShell;
@@ -744,25 +746,17 @@ protected:
     // For that reasons don't use nsCOMPtr.
 
     nsIDocShellTreeOwner *     mTreeOwner; // Weak Reference
     nsPIDOMEventTarget *       mChromeEventHandler; //Weak Reference
 
     eCharsetReloadState        mCharsetReloadState;
 
     // Offset in the parent's child list.
-    // XXXmats the line above is bogus, it's the offset in the parent's
-    // child list at the time this docshell was added to it,
-    // see nsDocShell::AddChild().  It isn't updated after that so if children
-    // with lower indices are removed this offset is no longer valid to be used
-    // as an index into the parent's child list (see bug 162283).  It MUST not
-    // be used for that purpose.  It's used as an index to get/add history
-    // entries into nsIDocShellHistory, although I very much doubt that it
-    // can be correct for that purpose as well...
-    // Try not to use it, we should get rid of it.
+    // -1 if the docshell is added dynamically to the parent shell.
     PRUint32                   mChildOffset;
     PRUint32                   mBusyFlags;
     PRUint32                   mAppType;
     PRUint32                   mLoadType;
 
     PRInt32                    mMarginWidth;
     PRInt32                    mMarginHeight;
 
@@ -807,19 +801,23 @@ protected:
 
     // Indicates that a DocShell in this "docshell tree" is printing
     PRPackedBool               mIsPrintingOrPP;
 
     // Indicates to CreateContentViewer() that it is safe to cache the old
     // presentation of the page, and to SetupNewViewer() that the old viewer
     // should be passed a SHEntry to save itself into.
     PRPackedBool               mSavingOldViewer;
+
+    // @see nsIDocShellHistory::createdDynamically
+    PRPackedBool               mDynamicallyCreated;
 #ifdef DEBUG
     PRPackedBool               mInEnsureScriptEnv;
 #endif
+    PRUint64                   mHistoryID;
 
     static nsIURIFixup *sURIFixup;
 
 #ifdef DEBUG
 private:
     // We're counting the number of |nsDocShells| to help find leaks
     static unsigned long gNumberOfDocShells;
 #endif /* DEBUG */
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -66,17 +66,17 @@ interface nsIRequest;
 interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 
-[scriptable, uuid(bf6db598-3833-400b-9e53-ec220cb2496c)]
+[scriptable, uuid(74470127-87eb-4f79-8293-1616fe9cb689)]
 interface nsIDocShell : nsISupports
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -523,9 +523,15 @@ interface nsIDocShell : nsISupports
   readonly attribute boolean canExecuteScripts;
 
   /**
    * Sets whether a docshell is active. An active docshell is one that is
    * visible, and thus is not a good candidate for certain optimizations
    * like image frame discarding. Docshells are active unless told otherwise.
    */
   attribute boolean isActive;
+
+
+  /**
+   * The ID of the docshell in the session history.
+   */
+  readonly attribute unsigned long long historyID;
 };
--- a/docshell/base/nsIDocShellHistory.idl
+++ b/docshell/base/nsIDocShellHistory.idl
@@ -34,30 +34,46 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 interface nsISHEntry;
 
-[scriptable, uuid(a89b80a8-3c44-4a25-9d2c-2fb42358b46e)]
+[scriptable, uuid(95e425aa-afc6-40a0-9db4-7f210a58310a)]
 interface nsIDocShellHistory : nsISupports
 {
   /**
    * Get the SHEntry associated with a child docshell
    */
   nsISHEntry getChildSHEntry(in long aChildOffset);
 
   /**
    * Add a Child SHEntry for a frameset page, given the child's loadtype.
    */
   void addChildSHEntry(in nsISHEntry aCloneReference,
                        in nsISHEntry aHistoryEntry,
                        in long aChildOffset,
                        in unsigned long aLoadType);
 
-  /*
+  /**
    * Whether this docshell should save entries in global history.
    */
   attribute boolean useGlobalHistory;
+
+  /**
+   * Removes nsISHEntry objects related to this docshell from session history.
+   * Use this only with subdocuments, like iframes.
+   */
+  void removeFromSessionHistory();
+
+  /**
+   * Set when an iframe/frame is added dynamically.
+   */
+  attribute boolean createdDynamically;
+
+  /**
+   * Returns false for mLSHE, true for mOSHE
+   */
+  boolean getCurrentSHEntry(out nsISHEntry aEntry);
 };
 
--- a/docshell/shistory/public/nsISHContainer.idl
+++ b/docshell/shistory/public/nsISHContainer.idl
@@ -53,17 +53,17 @@ interface nsISHContainer : nsISupports
 {
 	/**
      * The current number of nsISHEntries which are immediate children of the 
 	 * current SHEntry
      */
 	readonly attribute long childCount;
 
 	/**
-	 * Add a new child SHEntry.  Adds to the end of the list.
+	 * Add a new child SHEntry.  If offset is -1 adds to the end of the list.
 	 */
 	void AddChild(in nsISHEntry child, in long offset);
 
 	/**
 	 * Removes a child SHEntry
 	 */
 	void RemoveChild(in nsISHEntry child);
 
--- a/docshell/shistory/public/nsISHEntry.idl
+++ b/docshell/shistory/public/nsISHEntry.idl
@@ -53,17 +53,17 @@ interface nsISupportsArray;
 %{C++
 struct nsIntRect;
 class nsDocShellEditorData;
 %}
 [ref] native nsIntRect(nsIntRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
 
 
-[scriptable, uuid(62b0603f-57ca-439e-a0fb-6f6978500755)]
+[scriptable, uuid(39b73c3a-48eb-4189-8069-247279c3c42d)]
 interface nsISHEntry : nsIHistoryEntry
 {
     /** URI for the document */
     void setURI(in nsIURI aURI);
 
     /** Referrer URI */
     attribute nsIURI referrerURI;
 
@@ -183,17 +183,19 @@ interface nsISHEntry : nsIHistoryEntry
     void setScrollPosition(in long x, in long y);
     void getScrollPosition(out long x, out long y);
 
     /** Additional ways to create an entry */
     [noscript] void create(in nsIURI URI, in AString title,
                            in nsIInputStream inputStream,
                            in nsILayoutHistoryState layoutHistoryState,
                            in nsISupports cacheKey, in ACString contentType,
-                           in nsISupports owner);
+                           in nsISupports owner,
+                           in unsigned long long docshellID,
+                           in boolean dynamicCreation);
 
     nsISHEntry clone();
 
     /** Attribute that indicates if this entry is for a subframe navigation */
     void setIsSubFrame(in boolean aFlag);
 
     /** Return any content viewer present in or below this node in the
         nsSHEntry tree.  This will differ from contentViewer in the case
@@ -224,16 +226,33 @@ interface nsISHEntry : nsIHistoryEntry
      * Sets the owning pointer to the editor data assosicated with
      * this shistory entry. Unless forgetEditorData() is called, this
      * shentry will destroy the editor data when it's destroyed.
      */
     [noscript, notxpcom] void setEditorData(in nsDocShellEditorDataPtr aData);
 
     /** Returns true if this shistory entry is storing a detached editor. */
     [noscript, notxpcom] boolean hasDetachedEditor();
+
+    /**
+     * Returns true if the related docshell was added because of
+     * dynamic addition of an iframe/frame.
+     */
+    boolean isDynamicallyAdded();
+
+    /**
+     * Returns true if any of the child entries returns true
+     * when isDynamicallyAdded is called on it.
+     */
+    boolean hasDynamicallyAddedChild();
+
+    /**
+     * The history ID of the docshell.
+     */
+    attribute unsigned long long docshellID;
 };
 
 
 %{ C++
 // {BFD1A791-AD9F-11d3-BDC7-0050040A9B44}
 #define NS_SHENTRY_CID \
 {0xbfd1a791, 0xad9f, 0x11d3, {0xbd, 0xc7, 0x0, 0x50, 0x4, 0xa, 0x9b, 0x44}}
 
--- a/docshell/shistory/public/nsISHistoryInternal.idl
+++ b/docshell/shistory/public/nsISHistoryInternal.idl
@@ -45,19 +45,23 @@ interface nsISHistoryListener;
 interface nsIDocShell;
 
 %{C++
 #define NS_SHISTORY_INTERNAL_CID \
 { 0x9c47c121, 0x1c6e, 0x4d8f, \
   { 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
 
 #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
+
+template<class E> class nsTArray;
 %}
 
-[scriptable, uuid(7ca0fd71-437c-48ad-985d-11ce9e2429b4)]
+[ref] native nsDocshellIDArray(nsTArray<PRUint64>);
+
+[scriptable, uuid(2dede933-25e1-47a3-8f61-0127c785ea01)]
 interface nsISHistoryInternal: nsISupports
 {
   /**
    * Add a new Entry to the History List
    * @param aEntry - The entry to add
    * @param aPersist - If true this specifies that the entry should persist
    * in the list.  If false, this means that when new entries are added
    * this element will not appear in the session history list.
@@ -105,9 +109,16 @@ interface nsISHistoryInternal: nsISuppor
     * that has timed out.
     */
    void evictExpiredContentViewerForEntry(in nsISHEntry aEntry);
 
    /**
     * Evict all the content viewers in this session history
     */
    void evictAllContentViewers();
+
+   /**
+    * Removes entries from the history if their docshellID is in
+    * aIDs array.
+    */
+  [noscript, notxpcom] void RemoveEntries(in nsDocshellIDArray aIDs,
+                                          in long aStartIndex);
 };
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -107,18 +107,20 @@ nsSHEntry::nsSHEntry()
   , mPageIdentifier(mID)
   , mDocIdentifier(gEntryDocIdentifier++)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
   , mIsFrameNavigation(PR_FALSE)
   , mSaveLayoutState(PR_TRUE)
   , mExpired(PR_FALSE)
   , mSticky(PR_TRUE)
+  , mDynamicallyCreated(PR_FALSE)
   , mParent(nsnull)
   , mViewerBounds(0, 0, 0, 0)
+  , mDocShellID(0)
 {
 }
 
 nsSHEntry::nsSHEntry(const nsSHEntry &other)
   : mURI(other.mURI)
   , mReferrerURI(other.mReferrerURI)
   // XXX why not copy mDocument?
   , mTitle(other.mTitle)
@@ -129,21 +131,23 @@ nsSHEntry::nsSHEntry(const nsSHEntry &ot
   , mPageIdentifier(other.mPageIdentifier)
   , mDocIdentifier(other.mDocIdentifier)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
   , mIsFrameNavigation(other.mIsFrameNavigation)
   , mSaveLayoutState(other.mSaveLayoutState)
   , mExpired(other.mExpired)
   , mSticky(PR_TRUE)
+  , mDynamicallyCreated(other.mDynamicallyCreated)
   // XXX why not copy mContentType?
   , mCacheKey(other.mCacheKey)
   , mParent(other.mParent)
   , mViewerBounds(0, 0, 0, 0)
   , mOwner(other.mOwner)
+  , mDocShellID(other.mDocShellID)
 {
 }
 
 static PRBool
 ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
 {
   if (aEntry) {
     aEntry->SetParent(nsnull);
@@ -484,24 +488,27 @@ NS_IMETHODIMP nsSHEntry::SetContentType(
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle,
                   nsIInputStream * aInputStream,
                   nsILayoutHistoryState * aLayoutHistoryState,
                   nsISupports * aCacheKey, const nsACString& aContentType,
-                  nsISupports* aOwner)
+                  nsISupports* aOwner,
+                  PRUint64 aDocShellID, PRBool aDynamicCreation)
 {
   mURI = aURI;
   mTitle = aTitle;
   mPostData = aInputStream;
   mCacheKey = aCacheKey;
   mContentType = aContentType;
   mOwner = aOwner;
+  mDocShellID = aDocShellID;
+  mDynamicallyCreated = aDynamicCreation;
 
   // Set the LoadType by default to loadHistory during creation
   mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory;
 
   // By default all entries are set false for subframe flag. 
   // nsDocShell::CloneAndReplace() which creates entries for
   // all subframe navigations, sets the flag to true.
   mIsFrameNavigation = PR_FALSE;
@@ -598,51 +605,68 @@ nsSHEntry::GetChildCount(PRInt32 * aCoun
 {
   *aCount = mChildren.Count();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::AddChild(nsISHEntry * aChild, PRInt32 aOffset)
 {
-  NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
+  if (aChild) {
+    NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
+  }
 
-  NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
+  if (aOffset < 0) {
+    mChildren.AppendObject(aChild);
+    return NS_OK;
+  }
 
   //
   // Bug 52670: Ensure children are added in order.
   //
   //  Later frames in the child list may load faster and get appended
   //  before earlier frames, causing session history to be scrambled.
   //  By growing the list here, they are added to the right position.
   //
   //  Assert that aOffset will not be so high as to grow us a lot.
   //
   NS_ASSERTION(aOffset < (mChildren.Count()+1023), "Large frames array!\n");
 
+#ifdef DEBUG
   if (aOffset < mChildren.Count()) {
     nsISHEntry* oldChild = mChildren.ObjectAt(aOffset);
-    if (oldChild && oldChild != aChild) {
-      NS_WARNING("Adding child where we already have a child?  "
-                 "This will likely misbehave");
-      oldChild->SetParent(nsnull);
+    if (aChild && oldChild && oldChild != aChild) {
+      PRBool dyn = PR_FALSE;
+      oldChild->IsDynamicallyAdded(&dyn);
+      NS_WARN_IF_FALSE(dyn, "Adding child where we already have a child?  "
+                            "This may misbehave");
     }
   }
-  
-  // This implicitly extends the array to include aOffset
-  mChildren.ReplaceObjectAt(aChild, aOffset);
+#endif
+
+  mChildren.InsertObjectAt(aChild, aOffset);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::RemoveChild(nsISHEntry * aChild)
 {
   NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
-  PRBool childRemoved = mChildren.RemoveObject(aChild);
+  PRBool childRemoved = PR_FALSE;
+  PRBool dynamic = PR_FALSE;
+  aChild->IsDynamicallyAdded(&dynamic);
+  if (dynamic) {
+    childRemoved = mChildren.RemoveObject(aChild);
+  } else {
+    PRInt32 index = mChildren.IndexOfObject(aChild);
+    if (index >= 0) {
+      childRemoved = mChildren.ReplaceObjectAt(nsnull, index);
+    }
+  }
   if (childRemoved)
     aChild->SetParent(nsnull);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::GetChildAt(PRInt32 aIndex, nsISHEntry ** aResult)
 {
@@ -904,8 +928,45 @@ nsSHEntry::GetStateData(nsAString &aStat
 
 NS_IMETHODIMP
 nsSHEntry::SetStateData(const nsAString &aDataStr)
 {
   mStateData.Assign(aDataStr);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSHEntry::IsDynamicallyAdded(PRBool* aAdded)
+{
+  *aAdded = mDynamicallyCreated;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::HasDynamicallyAddedChild(PRBool* aAdded)
+{
+  *aAdded = PR_FALSE;
+  for (PRInt32 i = 0; i < mChildren.Count(); ++i) {
+    nsISHEntry* entry = mChildren[i];
+    if (entry) {
+      entry->IsDynamicallyAdded(aAdded);
+      if (*aAdded) {
+        break;
+      }
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::GetDocshellID(PRUint64* aID)
+{
+  *aID = mDocShellID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetDocshellID(PRUint64 aID)
+{
+  mDocShellID = aID;
+  return NS_OK;
+}
+
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -101,22 +101,24 @@ private:
   PRUint32                        mPageIdentifier;
   PRInt64                         mDocIdentifier;
   PRInt32                         mScrollPositionX;
   PRInt32                         mScrollPositionY;
   PRPackedBool                    mIsFrameNavigation;
   PRPackedBool                    mSaveLayoutState;
   PRPackedBool                    mExpired;
   PRPackedBool                    mSticky;
+  PRPackedBool                    mDynamicallyCreated;
   nsCString                       mContentType;
   nsCOMPtr<nsISupports>           mCacheKey;
   nsISHEntry *                    mParent;  // weak reference
   nsCOMPtr<nsISupports>           mWindowState;
   nsIntRect                       mViewerBounds;
   nsCOMArray<nsIDocShellTreeItem> mChildShells;
   nsCOMPtr<nsISupportsArray>      mRefreshURIList;
   nsCOMPtr<nsISupports>           mOwner;
   nsExpirationState               mExpirationState;
   nsAutoPtr<nsDocShellEditorData> mEditorData;
   nsString                        mStateData;
+  PRUint64                        mDocShellID;
 };
 
 #endif /* nsSHEntry_h */
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -55,16 +55,18 @@
 #include "nsIServiceManager.h"
 #include "nsIPrefService.h"
 #include "nsIURI.h"
 #include "nsIContentViewer.h"
 #include "nsICacheService.h"
 #include "nsIObserverService.h"
 #include "prclist.h"
 #include "mozilla/Services.h"
+#include "nsTArray.h"
+#include "nsCOMArray.h"
 
 // For calculating max history entries and max cachable contentviewers
 #include "nspr.h"
 #include <math.h>  // for log()
 
 #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
 #define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers"
 
@@ -340,16 +342,17 @@ nsSHistory::AddEntry(nsISHEntry * aSHEnt
   // If this is the very first transaction, initialize the list
   if(!mListRoot)
     mListRoot = txn;
 
   // Purge History list if it is too long
   if ((gHistoryMaxSize >= 0) && (mLength > gHistoryMaxSize))
     PurgeHistory(mLength-gHistoryMaxSize);
   
+  RemoveDynEntries(mIndex - 1, mIndex);
   return NS_OK;
 }
 
 /* Get size of the history list */
 NS_IMETHODIMP
 nsSHistory::GetCount(PRInt32 * aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
@@ -1058,21 +1061,134 @@ void
 nsSHistory::EvictAllContentViewersGlobally()
 {
   PRInt32 maxViewers = sHistoryMaxTotalViewers;
   sHistoryMaxTotalViewers = 0;
   EvictGlobalContentViewer();
   sHistoryMaxTotalViewers = maxViewers;
 }
 
+void GetDynamicChildren(nsISHContainer* aContainer,
+                        nsTArray<PRUint64>& aDocshellIDs,
+                        PRBool aOnlyTopLevelDynamic)
+{
+  PRInt32 count = 0;
+  aContainer->GetChildCount(&count);
+  for (PRInt32 i = 0; i < count; ++i) {
+    nsCOMPtr<nsISHEntry> child;
+    aContainer->GetChildAt(i, getter_AddRefs(child));
+    if (child) {
+      PRBool dynAdded = PR_FALSE;
+      child->IsDynamicallyAdded(&dynAdded);
+      if (dynAdded) {
+        PRUint64 docshellID = 0;
+        child->GetDocshellID(&docshellID);
+        aDocshellIDs.AppendElement(docshellID);
+      }
+      if (!dynAdded || !aOnlyTopLevelDynamic) {
+        nsCOMPtr<nsISHContainer> childAsContainer = do_QueryInterface(child);
+        if (childAsContainer) {
+          GetDynamicChildren(childAsContainer, aDocshellIDs,
+                             aOnlyTopLevelDynamic);
+        }
+      }
+    }
+  }
+}
+
+PRBool
+RemoveFromSessionHistoryContainer(nsISHContainer* aContainer,
+                                  nsTArray<PRUint64>& aDocshellIDs)
+{
+  nsCOMPtr<nsISHEntry> root = do_QueryInterface(aContainer);
+  NS_ENSURE_TRUE(root, PR_FALSE);
+
+  PRBool didRemove = PR_FALSE;
+  PRInt32 childCount = 0;
+  aContainer->GetChildCount(&childCount);
+  for (PRInt32 i = childCount - 1; i >= 0; --i) {
+    nsCOMPtr<nsISHEntry> child;
+    aContainer->GetChildAt(i, getter_AddRefs(child));
+    if (child) {
+      PRUint64 docshelldID = 0;
+      child->GetDocshellID(&docshelldID);
+      if (aDocshellIDs.Contains(docshelldID)) {
+        didRemove = PR_TRUE;
+        aContainer->RemoveChild(child);
+      } else {
+        nsCOMPtr<nsISHContainer> container = do_QueryInterface(child);
+        if (container) {
+          PRBool childRemoved =
+            RemoveFromSessionHistoryContainer(container, aDocshellIDs);
+          if (childRemoved) {
+            didRemove = PR_TRUE;
+          }
+        }
+      }
+    }
+  }
+  return didRemove;
+}
+
+PRBool RemoveChildEntries(nsISHistory* aHistory, PRInt32 aIndex,
+                          nsTArray<PRUint64>& aEntryIDs)
+{
+  nsCOMPtr<nsIHistoryEntry> rootHE;
+  aHistory->GetEntryAtIndex(aIndex, PR_FALSE, getter_AddRefs(rootHE));
+  nsCOMPtr<nsISHContainer> root = do_QueryInterface(rootHE);
+  return root ? RemoveFromSessionHistoryContainer(root, aEntryIDs) : PR_FALSE;
+}
+
+NS_IMETHODIMP_(void)
+nsSHistory::RemoveEntries(nsTArray<PRUint64>& aIDs, PRInt32 aStartIndex)
+{
+  PRInt32 index = aStartIndex;
+  while(index >= 0 && RemoveChildEntries(this, --index, aIDs));
+  index = aStartIndex;
+  while(index >= 0 && RemoveChildEntries(this, index++, aIDs));
+}
+
+void
+nsSHistory::RemoveDynEntries(PRInt32 aOldIndex, PRInt32 aNewIndex)
+{
+  // Search for the entries which are in the current index,
+  // but not in the new one.
+  nsCOMPtr<nsISHEntry> originalSH;
+  GetEntryAtIndex(aOldIndex, PR_FALSE, getter_AddRefs(originalSH));
+  nsCOMPtr<nsISHContainer> originalContainer = do_QueryInterface(originalSH);
+  nsAutoTArray<PRUint64, 16> toBeRemovedEntries;
+  if (originalContainer) {
+    nsTArray<PRUint64> originalDynDocShellIDs;
+    GetDynamicChildren(originalContainer, originalDynDocShellIDs, PR_TRUE);
+    if (originalDynDocShellIDs.Length()) {
+      nsCOMPtr<nsISHEntry> currentSH;
+      GetEntryAtIndex(aNewIndex, PR_FALSE, getter_AddRefs(currentSH));
+      nsCOMPtr<nsISHContainer> newContainer = do_QueryInterface(currentSH);
+      if (newContainer) {
+        nsTArray<PRUint64> newDynDocShellIDs;
+        GetDynamicChildren(newContainer, newDynDocShellIDs, PR_FALSE);
+        for (PRUint32 i = 0; i < originalDynDocShellIDs.Length(); ++i) {
+          if (!newDynDocShellIDs.Contains(originalDynDocShellIDs[i])) {
+            toBeRemovedEntries.AppendElement(originalDynDocShellIDs[i]);
+          }
+        }
+      }
+    }
+  }
+  if (toBeRemovedEntries.Length()) {
+    RemoveEntries(toBeRemovedEntries, aOldIndex);
+  }
+}
+
 NS_IMETHODIMP
 nsSHistory::UpdateIndex()
 {
   // Update the actual index with the right value. 
   if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
+    RemoveDynEntries(mIndex, mRequestedIndex);
     mIndex = mRequestedIndex;
   }
 
   mRequestedIndex = -1;
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1141,16 +1257,29 @@ nsSHistory::LoadURI(const PRUnichar* aUR
 }
 
 NS_IMETHODIMP
 nsSHistory::GotoIndex(PRInt32 aIndex)
 {
   return LoadEntry(aIndex, nsIDocShellLoadInfo::loadHistory, HIST_CMD_GOTOINDEX);
 }
 
+nsresult
+nsSHistory::LoadNextPossibleEntry(PRInt32 aNewIndex, long aLoadType, PRUint32 aHistCmd)
+{
+  mRequestedIndex = -1;
+  if (aNewIndex < mIndex) {
+    return LoadEntry(aNewIndex - 1, aLoadType, aHistCmd);
+  }
+  if (aNewIndex > mIndex) {
+    return LoadEntry(aNewIndex + 1, aLoadType, aHistCmd);
+  }
+  return NS_ERROR_FAILURE;
+}
+
 NS_IMETHODIMP
 nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
 {
   nsCOMPtr<nsIDocShell> docShell;
   nsCOMPtr<nsISHEntry> shEntry;
   // Keep note of requested history index in mRequestedIndex.
   mRequestedIndex = aIndex;
 
@@ -1213,43 +1342,61 @@ nsSHistory::LoadEntry(PRInt32 aIndex, lo
     // Going back or forward.
     if ((pCount > 0) && (nCount > 0)) {
       /* THis is a subframe navigation. Go find 
        * the docshell in which load should happen
        */
       PRBool frameFound = PR_FALSE;
       nsresult rv = CompareFrames(prevEntry, nextEntry, mRootDocShell, aLoadType, &frameFound);
       if (!frameFound) {
-        // we did not successfully find the subframe in which
-        // the new url was to be loaded. return error.
-        mRequestedIndex = -1;
-        return NS_ERROR_FAILURE; 
+        // We did not successfully find the subframe in which
+        // the new url was to be loaded. Go further in the history.
+        return LoadNextPossibleEntry(aIndex, aLoadType, aHistCmd);
       }
       return rv;
     }   // (pCount >0)
-    else
+    else {
+      // Loading top level page.
+      PRUint32 prevID = 0;
+      PRUint32 nextID = 0;
+      prevEntry->GetID(&prevID);
+      nextEntry->GetID(&nextID);
+      if (prevID == nextID) {
+        // Try harder to find something new to load.
+        // This may happen for example if some page removed iframes dynamically.
+        return LoadNextPossibleEntry(aIndex, aLoadType, aHistCmd);
+      }
       docShell = mRootDocShell;
     }
+  }
 
   if (!docShell) {
     // we did not successfully go to the proper index.
     // return error.
     mRequestedIndex = -1;
     return NS_ERROR_FAILURE;
   }
 
   // Start the load on the appropriate docshell
   return InitiateLoad(nextEntry, docShell, aLoadType);
 }
 
 nsresult
 nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
 {
   if (!aPrevEntry || !aNextEntry || !aParent)
-    return PR_FALSE;
+    return NS_ERROR_FAILURE;
+
+  // We should be comparing only entries which were created for the
+  // same docshell. This is here to just prevent anything strange happening.
+  // This check could be possibly an assertion.
+  PRUint64 prevdID, nextdID;
+  aPrevEntry->GetDocshellID(&prevdID);
+  aNextEntry->GetDocshellID(&nextdID);
+  NS_ENSURE_STATE(prevdID == nextdID);
 
   nsresult result = NS_OK;
   PRUint32 prevID, nextID;
 
   aPrevEntry->GetID(&prevID);
   aNextEntry->GetID(&nextID);
  
   // Check the IDs to verify if the pages are different.
@@ -1273,32 +1420,73 @@ nsSHistory::CompareFrames(nsISHEntry * a
     return NS_ERROR_FAILURE;
   if (!prevContainer || !nextContainer)
     return NS_ERROR_FAILURE;
 
   prevContainer->GetChildCount(&pcnt);
   nextContainer->GetChildCount(&ncnt);
   dsTreeNode->GetChildCount(&dsCount);
 
-  //XXX What to do if the children count don't match
-    
-  for (PRInt32 i=0; i<ncnt; i++){
-    nsCOMPtr<nsISHEntry> pChild, nChild;
-    nsCOMPtr<nsIDocShellTreeItem> dsTreeItemChild;
-	  
-    prevContainer->GetChildAt(i, getter_AddRefs(pChild));
+  // Create an array for child docshells.
+  nsCOMArray<nsIDocShell> docshells;
+  for (PRInt32 i = 0; i < dsCount; ++i) {
+    nsCOMPtr<nsIDocShellTreeItem> treeItem;
+    dsTreeNode->GetChildAt(i, getter_AddRefs(treeItem));
+    nsCOMPtr<nsIDocShell> shell = do_QueryInterface(treeItem);
+    if (shell) {
+      docshells.AppendObject(shell);
+    }
+  }
+
+  // Search for something to load next.
+  for (PRInt32 i = 0; i < ncnt; ++i) {
+    // First get an entry which may cause a new page to be loaded.
+    nsCOMPtr<nsISHEntry> nChild;
     nextContainer->GetChildAt(i, getter_AddRefs(nChild));
-    if (dsCount > 0)
-      dsTreeNode->GetChildAt(i, getter_AddRefs(dsTreeItemChild));
+    if (!nChild) {
+      continue;
+    }
+    PRUint64 docshellID = 0;
+    nChild->GetDocshellID(&docshellID);
 
-    if (!dsTreeItemChild)
-      return NS_ERROR_FAILURE;
+    // Then find the associated docshell.
+    nsIDocShell* dsChild = nsnull;
+    PRInt32 count = docshells.Count();
+    for (PRInt32 j = 0; j < count; ++j) {
+      PRUint64 shellID = 0;
+      nsIDocShell* shell = docshells[j];
+      shell->GetHistoryID(&shellID);
+      if (shellID == docshellID) {
+        dsChild = shell;
+        break;
+      }
+    }
+    if (!dsChild) {
+      continue;
+    }
 
-    nsCOMPtr<nsIDocShell> dsChild(do_QueryInterface(dsTreeItemChild));
+    // Then look at the previous entries to see if there was
+    // an entry for the docshell.
+    nsCOMPtr<nsISHEntry> pChild;
+    for (PRInt32 k = 0; k < pcnt; ++k) {
+      nsCOMPtr<nsISHEntry> child;
+      prevContainer->GetChildAt(k, getter_AddRefs(child));
+      if (child) {
+        PRUint64 dID = 0;
+        child->GetDocshellID(&dID);
+        if (dID == docshellID) {
+          pChild = child;
+          break;
+        }
+      }
+    }
 
+    // Finally recursively call this method.
+    // This will either load a new page to shell or some subshell or
+    // do nothing.
     CompareFrames(pChild, nChild, dsChild, aLoadType, aIsFrameFound);
   }     
   return result;
 }
 
 
 nsresult 
 nsSHistory::InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType)
--- a/docshell/shistory/src/nsSHistory.h
+++ b/docshell/shistory/src/nsSHistory.h
@@ -107,16 +107,19 @@ protected:
   void EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex);
   static void EvictGlobalContentViewer();
   static void EvictAllContentViewersGlobally();
 
   // Calculates a max number of total
   // content viewers to cache, based on amount of total memory
   static PRUint32 CalcMaxTotalViewers();
 
+  void RemoveDynEntries(PRInt32 aOldIndex, PRInt32 aNewIndex);
+
+  nsresult LoadNextPossibleEntry(PRInt32 aNewIndex, long aLoadType, PRUint32 aHistCmd);
 protected:
   nsCOMPtr<nsISHTransaction> mListRoot;
   PRInt32 mIndex;
   PRInt32 mLength;
   PRInt32 mRequestedIndex;
   // Session History listener
   nsWeakPtr mListener;
   // Weak reference. Do not refcount this.
--- a/docshell/test/navigation/Makefile.in
+++ b/docshell/test/navigation/Makefile.in
@@ -61,16 +61,28 @@ include $(topsrcdir)/config/rules.mk
 		test_popup-navigates-children.html \
 		test_reserved.html \
 		NavigationUtils.js \
 		navigate.html \
 		open.html \
 		iframe.html \
 		parent.html \
 		blank.html \
+		test_sessionhistory.html \
+		file_bug462076_1.html \
+		file_bug462076_2.html \
+		file_bug462076_3.html \
+		file_bug508537_1.html \
+		file_document_write_1.html \
+		file_static_and_dynamic_1.html \
+		frame0.html \
+		frame1.html \
+		frame2.html \
+		frame3.html \
+		goback.html \
 		$(NULL)
 
 ifneq (mobile,$(MOZ_BUILD_APP))
 _BROWSER_TEST_FILES = \
 		browser_bug343515.js \
 		bug343515_pg1.html \
 		bug343515_pg2.html \
 		bug343515_pg3.html \
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_bug462076_1.html
@@ -0,0 +1,55 @@
+<html>
+  <head>
+    <title>Bug 462076</title>
+    <script>
+      var srcs = [ "frame0.html",
+                   "frame1.html",
+                   "frame2.html",
+                   "frame3.html" ];
+
+      var checkCount = 0;
+
+      function makeFrame(index) {
+        var ifr = document.createElement("iframe");
+        ifr.src = srcs[index];
+        ifr.onload = checkFrame;
+        document.getElementById("container" + index).appendChild(ifr);
+      }
+
+      function runTest() {
+        var randomNumber = Math.floor(Math.random() * 4);
+        for (var i = randomNumber; i < 4; ++i) {
+          makeFrame(i);
+        }
+        for (var i = 0; i < randomNumber; ++i) {
+          makeFrame(i);
+        }
+      }
+
+      function checkFrame(evt) {
+        var ifr = evt.target;
+        opener.ok(new String(ifr.contentWindow.location).indexOf(ifr.src) >= 0,
+           "Wrong document loaded (" + ifr.src + ", " + 
+           ifr.contentWindow.location + ")!");
+
+        if (++checkCount == 4) {
+          if (++opener.testCount == 10) {
+            opener.nextTest();
+            window.close();
+          } else {
+            window.location.reload();
+          }
+        }
+      }
+    </script>
+  </head>
+  <body>
+    <div id="container0"></div>
+    <div id="container1"></div>
+    <div id="container2"></div>
+    <div id="container3"></div>
+    <script>
+      runTest();
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_bug462076_2.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <title>Bug 462076</title>
+    <script>
+      var srcs = [ "frame0.html",
+                   "frame1.html",
+                   "frame2.html",
+                   "frame3.html" ];
+
+      var checkCount = 0;
+
+      function makeFrame(index) {
+        var ifr = document.createElement("iframe");
+        ifr.src = srcs[index];
+        ifr.onload = checkFrame;
+        document.getElementById("container" + index).appendChild(ifr);
+      }
+
+      function runTest() {
+        var randomNumber = Math.floor(Math.random() * 4);
+        for (var i = randomNumber; i < 4; ++i) {
+          makeFrame(i);
+        }
+        for (var i = 0; i < randomNumber; ++i) {
+          makeFrame(i);
+        }
+      }
+
+      function checkFrame(evt) {
+        var ifr = evt.target;
+        opener.ok(new String(ifr.contentWindow.location).indexOf(ifr.src) >= 0,
+           "Wrong document loaded (" + ifr.src + ", " + 
+           ifr.contentWindow.location + ")!");
+
+        if (++checkCount == 4) {
+          if (++opener.testCount == 10) {
+            opener.nextTest();
+            window.close();
+          } else {
+            window.location.reload();
+          }
+        }
+      }
+    </script>
+  </head>
+  <body onload="runTest();">
+    <div id="container0"></div>
+    <div id="container1"></div>
+    <div id="container2"></div>
+    <div id="container3"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_bug462076_3.html
@@ -0,0 +1,52 @@
+<html>
+  <head>
+    <title>Bug 462076</title>
+    <script>
+      var srcs = [ "frame0.html",
+                   "frame1.html",
+                   "frame2.html",
+                   "frame3.html" ];
+
+      var checkCount = 0;
+
+      function makeFrame(index) {
+        var ifr = document.createElement("iframe");
+        ifr.src = srcs[index];
+        ifr.onload = checkFrame;
+        document.getElementById("container" + index).appendChild(ifr);
+      }
+
+      function runTest() {
+        var randomNumber = Math.floor(Math.random() * 4);
+        for (var i = randomNumber; i < 4; ++i) {
+          makeFrame(i);
+        }
+        for (var i = 0; i < randomNumber; ++i) {
+          makeFrame(i);
+        }
+      }
+
+      function checkFrame(evt) {
+        var ifr = evt.target;
+        opener.ok(new String(ifr.contentWindow.location).indexOf(ifr.src) >= 0,
+           "Wrong document loaded (" + ifr.src + ", " + 
+           ifr.contentWindow.location + ")!");
+
+        if (++checkCount == 4) {
+          if (++opener.testCount == 10) {
+            opener.nextTest();
+            window.close();
+          } else {
+            window.location.reload();
+          }
+        }
+      }
+    </script>
+  </head>
+  <body onload="setTimeout(runTest, 1000);">
+    <div id="container0"></div>
+    <div id="container1"></div>
+    <div id="container2"></div>
+    <div id="container3"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_bug508537_1.html
@@ -0,0 +1,34 @@
+<html>
+  <head>
+    <script>
+      function dynFrameLoad() {
+        var ifrs = document.getElementsByTagName("iframe");
+        opener.ok(new String(ifrs[0].contentWindow.location).indexOf(ifrs[0].src) >= 0,
+                  "Wrong document loaded (1)\n");
+        opener.ok(new String(ifrs[1].contentWindow.location).indexOf(ifrs[1].src) >= 0,
+                  "Wrong document loaded (2)\n");
+        if (opener && ++opener.testCount == 1) {
+          window.location = "goback.html";
+        } else {
+          opener.nextTest();
+          window.close();
+        }
+      }
+
+      window.addEventListener("load",
+        function () {
+          var container = document.getElementById("t1");
+          container.addEventListener("load", dynFrameLoad, true);
+          container.appendChild(container.appendChild(document.getElementById("i1")));
+        }, false);
+    </script>
+  </head>
+  <body>
+    <h5>Container:</h5>
+    <div id="t1"></div>
+    <h5>Original frames:</h5>
+    <iframe id="i1" src="frame0.html"></iframe>
+    <iframe src="frame1.html"></iframe>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_document_write_1.html
@@ -0,0 +1,22 @@
+<html>
+  <head>
+    <script>
+      function run() {
+        document.open();
+        document.write("<h5 id='dynamic'>document.written content</h5>");
+        document.close();
+        window.history.go(-1);
+        opener.setTimeout("isTestDynamic()", 2500);
+      }
+
+      function start() {
+        if (++opener.testCount == 1) {
+          setTimeout(run, 1000);
+        }
+      }
+    </script>
+  </head>
+  <body onload="start();">
+    <h5>static content</h5>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_static_and_dynamic_1.html
@@ -0,0 +1,32 @@
+<html>
+  <head>
+    <script>
+    function test() {
+      var ifr = document.createElement("iframe");
+      ifr.src = "frame0.html";
+      document.getElementById("dynamic").appendChild(ifr);
+      var staticFrame = document.getElementById("staticframe");
+      staticFrame.onload = window.location = "goback.html";
+      staticFrame.contentWindow.location = "frame1.html";
+    }
+
+    function start() {
+      if (++opener.testCount == 1) {
+        test();
+      } else {
+        var staticFrame = document.getElementById("staticframe");
+        opener.ok(new String(staticFrame.contentWindow.location).indexOf(staticFrame.src) >= 0,
+                  "Wrong document loaded!");
+        opener.nextTest();
+        window.close();
+      }
+    }
+    </script>
+  </head>
+  <body onload="setTimeout('start()', 1000)">
+    <h5>Dynamic</h5>
+    <div id="dynamic"></div>
+    <h5>Static</h5>
+    <div id="static"><iframe id="staticframe" src="frame0.html"></iframe></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/frame0.html
@@ -0,0 +1,3 @@
+<html>
+  <body>Frame 0</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/frame1.html
@@ -0,0 +1,3 @@
+<html>
+  <body>Frame 1</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/frame2.html
@@ -0,0 +1,3 @@
+<html>
+  <body>Frame 2</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/frame3.html
@@ -0,0 +1,3 @@
+<html>
+  <body>Frame 3</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/goback.html
@@ -0,0 +1,5 @@
+<html>
+  <body onload="setTimeout('window.history.go(-1)', 1000);">
+    window.history.go(-1);
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_sessionhistory.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=
+-->
+<head>
+  <title>Test for Bug </title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="nextTest()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug  **/
+
+var testFiles =
+  [ "file_bug462076_1.html",         // Dynamic frames before onload
+    "file_bug462076_2.html",         // Dynamic frames when handling onload
+    "file_bug462076_3.html",         // Dynamic frames after onload
+    "file_bug508537_1.html",         // Dynamic frames and forward-back
+    "file_document_write_1.html",    // Session history + document.write
+    "file_static_and_dynamic_1.html" // Static and dynamic frames and forward-back
+  ];
+var testCount = 0; // Used by the test files.
+
+SimpleTest.waitForExplicitFinish();
+
+var testWindow;
+function nextTest_() {
+  if (testFiles.length) {
+    testCount = 0;
+    testWindow = window.open(testFiles.shift(), "", "width=300,height=300");
+    testWindow.onunload = function () { } //XXX
+  } else {
+    SimpleTest.finish();
+  }
+}
+
+// Needed by file_document_write_1.html
+function isTestDynamic() {
+  var dyn = testWindow.document.getElementById("dynamic");
+  is(dyn, null, "Should have gone back to the static page!");
+  nextTest();
+  testWindow.close();
+}
+
+function nextTest() {
+  setTimeout(nextTest_, 1000);
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/interfaces/html/nsIDOMNSHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMNSHTMLDocument.idl
@@ -34,19 +34,21 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(386e9eee-1f06-40a6-a1a7-ed986646b793)]
+[scriptable, uuid(95cd5ad4-ae8a-4f0e-b168-35e03d5e0b9a)]
 interface nsIDOMNSHTMLDocument : nsISupports
 {
+  readonly attribute long                 width;
+  readonly attribute long                 height;
            attribute DOMString            alinkColor;
            attribute DOMString            linkColor;
            attribute DOMString            vlinkColor;
            attribute DOMString            bgColor;
            attribute DOMString            fgColor;
            attribute DOMString            domain;
 
   readonly attribute nsIDOMHTMLCollection embeds;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -38,39 +38,46 @@
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PDocumentRendererShmem;
 include protocol PDocumentRendererNativeID;
 include protocol PGeolocationRequest;
+include protocol PExternalHelperApp;
 
 include "mozilla/TabTypes.h";
 include "TabMessageUtils.h";
 include "gfxMatrix.h";
 include "mozilla/net/NeckoMessageUtils.h";
+include "IPC/nsGUIEventIPC.h";
 
 using IPC::URI;
 using MagicWindowHandle;
 using RemoteDOMEvent;
 using gfxMatrix;
+using nsCompositionEvent;
+using nsTextEvent;
+using nsQueryContentEvent;
+using nsSelectionEvent;
 
 namespace mozilla {
 namespace dom {
 
 rpc protocol PBrowser
 {
     manager PContent;
 
     manages PContentDialog;
     manages PDocumentRenderer;
     manages PDocumentRendererShmem;
     manages PDocumentRendererNativeID;
     manages PGeolocationRequest;
+    manages PExternalHelperApp;
 
 both:
     AsyncMessage(nsString aMessage, nsString aJSON);
 
 parent:
     /**
      * When child sends this message, parent should move focus to
      * the next or previous focusable element.
@@ -100,23 +107,27 @@ parent:
                           bool sameURI) returns (bool retval);
 
 
     rpc CreateWindow() returns (PBrowser window);
 
     sync SyncMessage(nsString aMessage, nsString aJSON)
       returns (nsString[] retval);
 
+    QueryContentResult(nsQueryContentEvent event);
+
     PGeolocationRequest(URI uri);
 
     PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
                    PRInt32[] aIntParams, nsString[] aStringParams);
 
     __delete__();
 
+    PExternalHelperApp(URI uri, nsCString aMimeContentType, bool aForceSave, PRInt64 aContentLength);
+
 child:
     CreateWidget(MagicWindowHandle parentWidget);
 
     LoadURL(nsCString uri);
 
     Move(PRUint32 x,
          PRUint32 y,
          PRUint32 width,
@@ -142,16 +153,24 @@ child:
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     KeyEvent(nsString aType,
              PRInt32 aKeyCode,
              PRInt32 aCharCode,
              PRInt32 aModifiers,
              bool aPreventDefault);
 
+    CompositionEvent(nsCompositionEvent event);
+
+    TextEvent(nsTextEvent event);
+
+    QueryContentEvent(nsQueryContentEvent event);
+
+    SelectionEvent(nsSelectionEvent event);
+
     /**
      * Activate event forwarding from client to parent.
      */
     ActivateFrameEvent(nsString aType, bool capture);
 
     LoadRemoteScript(nsString aURL);
 
     PDocumentRenderer(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h, nsString bgcolor, PRUint32 flags, bool flush);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -49,16 +49,17 @@
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsThreadUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/DocumentRendererShmemChild.h"
 #include "mozilla/ipc/DocumentRendererNativeIDChild.h"
+#include "mozilla/dom/ExternalHelperAppChild.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsISupportsImpl.h"
 #include "nsIURI.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
@@ -78,16 +79,18 @@
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsWeakReference.h"
 #include "nsISecureBrowserUI.h"
 #include "nsISSLStatusProvider.h"
 #include "nsSerializationHelper.h"
+#include "nsIFrame.h"
+#include "nsIView.h"
 
 #ifdef MOZ_WIDGET_QT
 #include <QX11EmbedWidget>
 #include <QGraphicsView>
 #include <QGraphicsWidget>
 #endif
 
 #ifdef MOZ_WIDGET_GTK2
@@ -113,18 +116,17 @@ class ContentDialogChild : public PConte
 {
 public:
   virtual bool Recv__delete__(const nsTArray<int>& aIntParams,
                               const nsTArray<nsString>& aStringParams);
 };
 
 
 TabChild::TabChild(PRUint32 aChromeFlags)
-  : mCx(nsnull)
-  , mTabChildGlobal(nsnull)
+  : mTabChildGlobal(nsnull)
   , mChromeFlags(aChromeFlags)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 nsresult
 TabChild::Init()
 {
@@ -500,22 +502,17 @@ TabChild::~TabChild()
     nsCOMPtr<nsIWeakReference> weak =
       do_GetWeakReference(static_cast<nsSupportsWeakReference*>(this));
     webBrowser->RemoveWebBrowserListener(weak, NS_GET_IID(nsIWebProgressListener));
 
     if (webBrowser) {
       webBrowser->SetContainerWindow(nsnull);
     }
     if (mCx) {
-      nsIXPConnect* xpc = nsContentUtils::XPConnect();
-      if (xpc) {
-         xpc->ReleaseJSContext(mCx, PR_FALSE);
-      } else {
-        JS_DestroyContext(mCx);
-      }
+      DestroyCx();
     }
     mTabChildGlobal->mTabChild = nsnull;
 }
 
 NS_IMETHODIMP
 TabChild::OnStateChange(nsIWebProgress *aWebProgress,
                         nsIRequest *aRequest,
                         PRUint32 aStateFlags,
@@ -715,25 +712,87 @@ TabChild::RecvKeyEvent(const nsString& a
   nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
   NS_ENSURE_TRUE(utils, true);
   PRBool ignored = PR_FALSE;
   utils->SendKeyEvent(aType, aKeyCode, aCharCode,
                       aModifiers, aPreventDefault, &ignored);
   return true;
 }
 
+bool
+TabChild::RecvCompositionEvent(const nsCompositionEvent& event)
+{
+  nsCompositionEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  return true;
+}
+
+bool
+TabChild::RecvTextEvent(const nsTextEvent& event)
+{
+  nsTextEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  IPC::ParamTraits<nsTextEvent>::Free(event);
+  return true;
+}
+
+bool
+TabChild::RecvQueryContentEvent(const nsQueryContentEvent& event)
+{
+  nsQueryContentEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  // Send result back even if query failed
+  SendQueryContentResult(localEvent);
+  return true;
+}
+
+bool
+TabChild::RecvSelectionEvent(const nsSelectionEvent& event)
+{
+  nsSelectionEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  return true;
+}
+
+bool
+TabChild::DispatchWidgetEvent(nsGUIEvent& event)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
+  NS_ENSURE_TRUE(window, false);
+
+  nsIDocShell *docShell = window->GetDocShell();
+  NS_ENSURE_TRUE(docShell, false);
+
+  nsCOMPtr<nsIPresShell> presShell;
+  docShell->GetPresShell(getter_AddRefs(presShell));
+  NS_ENSURE_TRUE(presShell, false);
+
+  nsIFrame *frame = presShell->GetRootFrame();
+  NS_ENSURE_TRUE(frame, false);
+
+  nsIView *view = frame->GetView();
+  NS_ENSURE_TRUE(view, false);
+
+  nsCOMPtr<nsIWidget> widget = view->GetNearestWidget(nsnull);
+  NS_ENSURE_TRUE(widget, false);
+
+  nsEventStatus status;
+  event.widget = widget;
+  NS_ENSURE_SUCCESS(widget->DispatchEvent(&event, status), false);
+  return true;
+}
+
 mozilla::ipc::PDocumentRendererChild*
-TabChild::AllocPDocumentRenderer(
-        const PRInt32& x,
-        const PRInt32& y,
-        const PRInt32& w,
-        const PRInt32& h,
-        const nsString& bgcolor,
-        const PRUint32& flags,
-        const bool& flush)
+TabChild::AllocPDocumentRenderer(const PRInt32& x,
+                                 const PRInt32& y,
+                                 const PRInt32& w,
+                                 const PRInt32& h,
+                                 const nsString& bgcolor,
+                                 const PRUint32& flags,
+                                 const bool& flush)
 {
     return new mozilla::ipc::DocumentRendererChild();
 }
 
 bool
 TabChild::DeallocPDocumentRenderer(PDocumentRendererChild* actor)
 {
     delete actor;
@@ -939,65 +998,17 @@ TabChild::RecvActivateFrameEvent(const n
   NS_ENSURE_TRUE(listener, true);
   chromeHandler->AddEventListener(aType, listener, capture);
   return true;
 }
 
 bool
 TabChild::RecvLoadRemoteScript(const nsString& aURL)
 {
-  nsCString url = NS_ConvertUTF16toUTF8(aURL);
-  nsCOMPtr<nsIURI> uri;
-  nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
-  NS_ENSURE_SUCCESS(rv, true);
-  NS_NewChannel(getter_AddRefs(mChannel), uri);
-  NS_ENSURE_TRUE(mChannel, true);
-
-  nsCOMPtr<nsIInputStream> input;
-  mChannel->Open(getter_AddRefs(input));
-  nsString dataString;
-  if (input) {
-    const PRUint32 bufferSize = 256;
-    char buffer[bufferSize];
-    nsCString data;
-    PRUint32 avail = 0;
-    input->Available(&avail);
-    PRUint32 read = 0;
-    if (avail) {
-      while (NS_SUCCEEDED(input->Read(buffer, bufferSize, &read)) && read) {
-        data.Append(buffer, read);
-        read = 0;
-      }
-    }
-    nsScriptLoader::ConvertToUTF16(mChannel, (PRUint8*)data.get(), data.Length(),
-                                   EmptyString(), nsnull, dataString);
-  }
-
-  if (!dataString.IsEmpty()) {
-    JSAutoRequest ar(mCx);
-    nsCOMPtr<nsPIDOMWindow> w = do_GetInterface(mWebNav);
-    jsval retval;
-    JSObject* global = nsnull;
-    rv = mRootGlobal->GetJSObject(&global);
-    NS_ENSURE_SUCCESS(rv, false);
-    JSPrincipals* jsprin = nsnull;
-    mPrincipal->GetJSPrincipals(mCx, &jsprin);
-
-    nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
-
-    nsContentUtils::ThreadJSContextStack()->Push(mCx);
-    JSBool ret = JS_EvaluateUCScriptForPrincipals(mCx, global, jsprin,
-                                                  (jschar*)dataString.get(),
-                                                  dataString.Length(),
-                                                  url.get(), 1, &retval);
-    JSPRINCIPALS_DROP(mCx, jsprin);
-    JSContext *unused;
-    nsContentUtils::ThreadJSContextStack()->Pop(&unused);
-    NS_ENSURE_TRUE(ret, true); // This gives us a useful warning!
-  }
+  LoadFrameScriptInternal(aURL);
   return true;
 }
 
 bool
 TabChild::RecvAsyncMessage(const nsString& aMessage,
                            const nsString& aJSON)
 {
   if (mTabChildGlobal) {
@@ -1090,18 +1101,16 @@ TabChild::InitTabChildGlobal()
                (jsuword) -1;
 #endif
 
   JS_SetThreadStackLimit(cx, stackLimit);
   JS_SetScriptStackQuota(cx, 100*1024*1024);
 
   JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX | JSOPTION_PRIVATE_IS_NSISUPPORTS);
   JS_SetVersion(cx, JSVERSION_LATEST);
-  JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 1 * 1024 * 1024);
-
   
   JSAutoRequest ar(cx);
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
                          /*nsIXPConnect::OMIT_COMPONENTS_OBJECT ?  |*/
                          nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
 
   nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
@@ -1112,29 +1121,29 @@ TabChild::InitTabChildGlobal()
   nsISupports* scopeSupports =
     NS_ISUPPORTS_CAST(nsPIDOMEventTarget*, scope);
   JS_SetContextPrivate(cx, scopeSupports);
 
   nsresult rv =
     xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports,
                                          NS_GET_IID(nsISupports),
                                          scope->GetPrincipal(), EmptyCString(),
-                                         flags, getter_AddRefs(mRootGlobal));
+                                         flags, getter_AddRefs(mGlobal));
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
   NS_ENSURE_TRUE(root, false);
   root->SetParentTarget(scope);
   
   JSObject* global = nsnull;
-  rv = mRootGlobal->GetJSObject(&global);
+  rv = mGlobal->GetJSObject(&global);
   NS_ENSURE_SUCCESS(rv, false);
 
   JS_SetGlobalObject(cx, global);
-
+  DidCreateCx();
   return true;
 }
 
 static bool
 SendSyncMessageToParent(void* aCallbackData,
                         const nsAString& aMessage,
                         const nsAString& aJSON,
                         nsTArray<nsString>* aJSONRetVal)
@@ -1220,8 +1229,29 @@ TabChildGlobal::GetJSContextForEventHand
 
 nsIPrincipal* 
 TabChildGlobal::GetPrincipal()
 {
   if (!mTabChild)
     return nsnull;
   return mTabChild->GetPrincipal();
 }
+
+PExternalHelperAppChild*
+TabChild::AllocPExternalHelperApp(const IPC::URI& uri,
+                                  const nsCString& aMimeContentType,
+                                  const bool& aForceSave,
+                                  const PRInt64& aContentLength)
+{
+  ExternalHelperAppChild *child = new ExternalHelperAppChild();
+  child->AddRef();
+  return child;
+}
+
+bool
+TabChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
+{
+  ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
+  child->Release();
+  return true;
+}
+
+
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -139,16 +139,17 @@ public:
   ContentListener(TabChild* aTabChild) : mTabChild(aTabChild) {}
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 protected:
   TabChild* mTabChild;
 };
 
 class TabChild : public PBrowserChild,
+                 public nsFrameScriptExecutor,
                  public nsIWebProgressListener2,
                  public nsIWebBrowserChrome2,
                  public nsIEmbeddingSiteWindow2,
                  public nsIWebBrowserChromeFocus,
                  public nsIInterfaceRequestor,
                  public nsIWindowProvider,
                  public nsSupportsWeakReference,
                  public nsIDialogCreator,
@@ -186,16 +187,20 @@ public:
                                 const PRInt32&  aClickCount,
                                 const PRInt32&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvKeyEvent(const nsString& aType,
                               const PRInt32&  aKeyCode,
                               const PRInt32&  aCharCode,
                               const PRInt32&  aModifiers,
                               const bool&     aPreventDefault);
+    virtual bool RecvCompositionEvent(const nsCompositionEvent& event);
+    virtual bool RecvTextEvent(const nsTextEvent& event);
+    virtual bool RecvQueryContentEvent(const nsQueryContentEvent& event);
+    virtual bool RecvSelectionEvent(const nsSelectionEvent& event);
     virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture);
     virtual bool RecvLoadRemoteScript(const nsString& aURL);
     virtual bool RecvAsyncMessage(const nsString& aMessage,
                                   const nsString& aJSON);
     virtual mozilla::ipc::PDocumentRendererChild* AllocPDocumentRenderer(
             const PRInt32& x,
             const PRInt32& y,
             const PRInt32& w,
@@ -214,16 +219,22 @@ public:
             const PRUint32& flags,
             const bool& flush);
     virtual PContentDialogChild* AllocPContentDialog(const PRUint32&,
                                                      const nsCString&,
                                                      const nsCString&,
                                                      const nsTArray<int>&,
                                                      const nsTArray<nsString>&);
     virtual bool DeallocPContentDialog(PContentDialogChild* aDialog);
+    virtual PExternalHelperAppChild *AllocPExternalHelperApp(
+            const IPC::URI& uri,
+            const nsCString& aMimeContentType,
+            const bool& aForceSave,
+            const PRInt64& aContentLength);
+    virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
     static void ParamsToArrays(nsIDialogParamBlock* aParams,
                                nsTArray<int>& aIntParams,
                                nsTArray<nsString>& aStringParams);
     static void ArraysToParams(const nsTArray<int>& aIntParams,
                                const nsTArray<nsString>& aStringParams,
                                nsIDialogParamBlock* aParams);
 
     virtual PDocumentRendererShmemChild* AllocPDocumentRendererShmem(
@@ -280,27 +291,25 @@ public:
     JSContext* GetJSContext() { return mCx; }
 
     nsIPrincipal* GetPrincipal() { return mPrincipal; }
 
 protected:
     NS_OVERRIDE
     virtual bool RecvDestroy();
 
+    bool DispatchWidgetEvent(nsGUIEvent& event);
+
 private:
     void ActorDestroy(ActorDestroyReason why);
 
     bool InitTabChildGlobal();
 
     nsCOMPtr<nsIWebNavigation> mWebNav;
-    nsCOMPtr<nsIXPConnectJSObjectHolder> mRootGlobal;
-    JSContext* mCx;
-    nsCOMPtr<nsIChannel> mChannel;
     TabChildGlobal* mTabChildGlobal;
-    nsCOMPtr<nsIPrincipal> mPrincipal;
     PRUint32 mChromeFlags;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -31,16 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/dom/ExternalHelperAppParent.h"
 #include "TabParent.h"
 
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/ipc/DocumentRendererShmemParent.h"
 #include "mozilla/ipc/DocumentRendererNativeIDParent.h"
 #include "mozilla/dom/ContentParent.h"
 
 #include "nsIURI.h"
@@ -66,16 +67,21 @@
 #include "nsIDOMNSHTMLFrameElement.h"
 #include "nsIDialogCreator.h"
 #include "nsThreadUtils.h"
 #include "nsSerializationHelper.h"
 #include "nsIPromptFactory.h"
 #include "nsIContent.h"
 #include "mozilla/unused.h"
 
+#ifdef ANDROID
+#include "AndroidBridge.h"
+using namespace mozilla;
+#endif
+
 using mozilla::ipc::DocumentRendererParent;
 using mozilla::ipc::DocumentRendererShmemParent;
 using mozilla::ipc::DocumentRendererNativeIDParent;
 using mozilla::dom::ContentParent;
 
 // The flags passed by the webProgress notifications are 16 bits shifted
 // from the ones registered by webProgressListeners.
 #define NOTIFY_FLAG_SHIFT 16
@@ -563,16 +569,42 @@ TabParent::RecvSyncMessage(const nsStrin
 bool
 TabParent::RecvAsyncMessage(const nsString& aMessage,
                             const nsString& aJSON)
 {
   return ReceiveMessage(aMessage, PR_FALSE, aJSON, nsnull);
 }
 
 bool
+TabParent::RecvQueryContentResult(const nsQueryContentEvent& event)
+{
+#ifdef ANDROID
+  if (!event.mSucceeded) {
+    AndroidBridge::Bridge()->ReturnIMEQueryResult(nsnull, 0, 0, 0);
+    return true;
+  }
+
+  switch (event.message) {
+  case NS_QUERY_TEXT_CONTENT:
+    AndroidBridge::Bridge()->ReturnIMEQueryResult(
+        event.mReply.mString.get(), event.mReply.mString.Length(), 0, 0);
+    break;
+  case NS_QUERY_SELECTED_TEXT:
+    AndroidBridge::Bridge()->ReturnIMEQueryResult(
+        event.mReply.mString.get(),
+        event.mReply.mString.Length(),
+        event.GetSelectionStart(),
+        event.GetSelectionEnd() - event.GetSelectionStart());
+    break;
+  }
+#endif
+  return true;
+}
+
+bool
 TabParent::ReceiveMessage(const nsString& aMessage,
                           PRBool aSync,
                           const nsString& aJSON,
                           nsTArray<nsString>* aJSONRetVal)
 {
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (frameLoader && frameLoader->GetFrameMessageManager()) {
     nsFrameMessageManager* manager = frameLoader->GetFrameMessageManager();
@@ -771,10 +803,30 @@ TabParent::ShouldDelayDialogs()
 
 already_AddRefed<nsFrameLoader>
 TabParent::GetFrameLoader() const
 {
   nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(mFrameElement);
   return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nsnull;
 }
 
+PExternalHelperAppParent*
+TabParent::AllocPExternalHelperApp(const IPC::URI& uri,
+                                   const nsCString& aMimeContentType,
+                                   const bool& aForceSave,
+                                   const PRInt64& aContentLength)
+{
+  ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
+  parent->AddRef();
+  parent->Init(this, aMimeContentType, aForceSave);
+  return parent;
+}
+
+bool
+TabParent::DeallocPExternalHelperApp(PExternalHelperAppParent* aService)
+{
+  ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
+  parent->Release();
+  return true;
+}
+
 } // namespace tabs
 } // namespace mozilla
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PContentDialogParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
+#include "mozilla/dom/PExternalHelperApp.h"
 
 #include "jsapi.h"
 #include "nsCOMPtr.h"
 #include "nsITabParent.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
@@ -95,21 +96,23 @@ class TabParent : public PBrowserParent
                 , public nsIWebProgress
                 , public nsIAuthPromptProvider
                 , public nsISecureBrowserUI
                 , public nsISSLStatusProvider
 {
 public:
     TabParent();
     virtual ~TabParent();
+    nsIDOMElement* GetOwnerElement() { return mFrameElement; }
     void SetOwnerElement(nsIDOMElement* aElement) { mFrameElement = aElement; }
+    nsIBrowserDOMWindow *GetBrowserDOMWindow() { return mBrowserDOMWindow; }
     void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
         mBrowserDOMWindow = aBrowserDOMWindow;
     }
-
+ 
     virtual bool RecvMoveFocus(const bool& aForward);
     virtual bool RecvEvent(const RemoteDOMEvent& aEvent);
     virtual bool RecvNotifyProgressChange(const PRInt64& aProgress,
                                           const PRInt64& aProgressMax,
                                           const PRInt64& aTotalProgress,
                                           const PRInt64& aMaxTotalProgress);
     virtual bool RecvNotifyStateChange(const PRUint32& aStateFlags,
                                        const nsresult& aStatus);
@@ -127,27 +130,35 @@ public:
                                       bool* aAllowRefresh);
 
     virtual bool AnswerCreateWindow(PBrowserParent** retval);
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const nsString& aJSON,
                                  nsTArray<nsString>* aJSONRetVal);
     virtual bool RecvAsyncMessage(const nsString& aMessage,
                                   const nsString& aJSON);
+    virtual bool RecvQueryContentResult(const nsQueryContentEvent& event);
     virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
                                                       const nsCString& aName,
                                                       const nsCString& aFeatures,
                                                       const nsTArray<int>& aIntParams,
                                                       const nsTArray<nsString>& aStringParams);
     virtual bool DeallocPContentDialog(PContentDialogParent* aDialog)
     {
       delete aDialog;
       return true;
     }
 
+    virtual PExternalHelperAppParent* AllocPExternalHelperApp(
+            const IPC::URI& uri,
+            const nsCString& aMimeContentType,
+            const bool& aForceSave,
+            const PRInt64& aContentLength);
+    virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
+
     void LoadURL(nsIURI* aURI);
     void Move(PRUint32 x, PRUint32 y, PRUint32 width, PRUint32 height);
     void Activate();
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         PRInt32 aButton, PRInt32 aClickCount,
                         PRInt32 aModifiers, PRBool aIgnoreRootScrollFrame);
     void SendKeyEvent(const nsAString& aType, PRInt32 aKeyCode,
                       PRInt32 aCharCode, PRInt32 aModifiers,
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -188,17 +188,17 @@ PluginModuleChild::Init(const std::strin
     pluginFile->Exists(&exists);
     NS_ASSERTION(exists, "plugin file ain't there");
 
     nsCOMPtr<nsIFile> pluginIfile;
     pluginIfile = do_QueryInterface(pluginFile);
 
     nsPluginFile lib(pluginIfile);
 
-    nsresult rv = lib.LoadPlugin(mLibrary);
+    nsresult rv = lib.LoadPlugin(&mLibrary);
     NS_ASSERTION(NS_OK == rv, "trouble with mPluginFile");
     NS_ASSERTION(mLibrary, "couldn't open shared object");
 
     if (!Open(aChannel, aParentProcessHandle, aIOLoop))
         return false;
 
     memset((void*) &mFunctions, 0, sizeof(mFunctions));
     mFunctions.size = sizeof(mFunctions);
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -1,15 +1,15 @@
 #filter substitution
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.mozilla.@MOZ_APP_NAME@"
       android:installLocation="auto"
       android:versionCode="1"
-      android:versionName="1.9.3"
+      android:versionName="@MOZ_APP_VERSION@"
       android:sharedUserId="org.mozilla.sharedID">
     <uses-sdk android:minSdkVersion="5"
               android:targetSdkVersion="5"/>
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
     <uses-permission android:name="android.permission.INTERNET"/> 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
 
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -49,16 +49,17 @@ JAVAFILES = \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   $(NULL)
 
 DEFINES += \
   -DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \
   -DMOZ_APP_NAME=$(MOZ_APP_NAME) \
+  -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
   -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
   $(MOZ_APP_NAME).apk  \
   App.java \
   Restarter.java \
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -133,16 +133,18 @@ empty-clip-rectangles.patch: f2fa15680ec
 empty-clip-extents.patch: b79ea8a6cab8bd28aebecf6e1e8229d5ac017264
 
 clip-rects-surface-extents.patch: 108b1c7825116ed3f93aa57384bbd3290cdc9181
 
 disable-previous-scaled-font-cache.patch: Disable the previous-scaled-font-cache until we figure out our ctm handling (#583035)
  
 copyarea-with-alpha.patch: support simple overlapping self copies in (some) color_alpha xlib surfaces. https://bugs.freedesktop.org/show_bug.cgi?id=29250
 
+fix-clip-test.patch: Use y 498c10032ea3f8631a928cd7df96766f2c8ddca4
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
--- a/gfx/cairo/cairo/src/cairo-clip.c
+++ b/gfx/cairo/cairo/src/cairo-clip.c
@@ -403,17 +403,17 @@ cairo_status_t
     if (rectangle->width == 0 || rectangle->height == 0) {
 	_cairo_clip_set_all_clipped (clip);
 	return CAIRO_STATUS_SUCCESS;
     }
 
     /* if a smaller clip has already been set, ignore the new path */
     if (clip->path != NULL) {
 	if (rectangle->x <= clip->path->extents.x &&
-	    rectangle->y <= clip->path->extents.x &&
+	    rectangle->y <= clip->path->extents.y &&
 	    rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
 	    rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
 	{
 	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
     return _cairo_clip_intersect_rectangle (clip, rectangle);
--- a/gfx/cairo/cairo/src/cairo-d2d-private.h
+++ b/gfx/cairo/cairo/src/cairo-d2d-private.h
@@ -63,16 +63,17 @@ struct _cairo_d2d_device
 
     HMODULE mD3D10_1;
     RefPtr<ID3D10Device1> mD3D10Device;
     RefPtr<ID3D10Effect> mSampleEffect;
     RefPtr<ID3D10InputLayout> mInputLayout;
     RefPtr<ID3D10Buffer> mQuadBuffer;
     RefPtr<ID3D10RasterizerState> mRasterizerState;
     RefPtr<ID3D10BlendState> mBlendStates[MAX_OPERATORS];
+    int mVRAMUsage;
 };
 typedef struct _cairo_d2d_device cairo_d2d_device_t;
 
 struct _cairo_d2d_surface {
     _cairo_d2d_surface() : d2d_clip(NULL), clipping(false), isDrawing(false),
 	textRenderingInit(true)
     {
 	_cairo_clip_init (&this->clip);
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -238,16 +238,17 @@ cairo_d2d_create_device_from_d3d10device
     memset(&rastDesc, 0, sizeof(rastDesc));
     rastDesc.CullMode = D3D10_CULL_NONE;
     rastDesc.FillMode = D3D10_FILL_SOLID;
     hr = device->mD3D10Device->CreateRasterizerState(&rastDesc, &device->mRasterizerState);
     if (FAILED(hr)) {
 	goto FAILED;
     }
     device->base.refcount = 1;
+    device->mVRAMUsage = 0;
 
     return &device->base;
 FAILED:
     delete &device->base;
     return NULL;
 }
 
 cairo_device_t *
@@ -691,16 +692,24 @@ static void
 _cairo_d2d_round_out_to_int_rect(cairo_rectangle_int_t *rect, double x1, double y1, double x2, double y2)
 {
     rect->x = (int)floor(x1);
     rect->y = (int)floor(y1);
     rect->width = (int)ceil(x2) - rect->x;
     rect->height = (int)ceil(y2) - rect->y;    
 }
 
+static int
+_cairo_d2d_compute_surface_mem_size(cairo_d2d_surface_t *surface)
+{
+    int size = surface->rt->GetPixelSize().width * surface->rt->GetPixelSize().height;
+    size *= surface->rt->GetPixelFormat().format == DXGI_FORMAT_A8_UNORM ? 1 : 4;
+    return size;
+}
+
 /**
  * Gets the surface buffer texture for window surfaces whose backbuffer
  * is not directly usable as a bitmap.
  *
  * \param surface D2D surface.
  * \return Buffer texture
  */
 static ID3D10Texture2D*
@@ -711,16 +720,17 @@ static ID3D10Texture2D*
 	DXGI_SURFACE_DESC surfDesc;
 	surface->surface->QueryInterface(&surf);
 	surf->GetDesc(&surfDesc);
 	CD3D10_TEXTURE2D_DESC softDesc(surfDesc.Format, surfDesc.Width, surfDesc.Height);
         softDesc.MipLevels = 1;
 	softDesc.Usage = D3D10_USAGE_DEFAULT;
 	softDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
 	surface->device->mD3D10Device->CreateTexture2D(&softDesc, NULL, &surface->bufferTexture);
+	surface->device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(surface);
     }
     return surface->bufferTexture;
 }
 
 /**
  * Ensure that the surface has an up-to-date surface bitmap. Used for
  * window surfaces which cannot have a surface bitmap directly related
  * to their backbuffer for some reason.
@@ -2349,31 +2359,37 @@ static cairo_surface_t*
     }
 
     newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
 
     _d2d_clear_surface(newSurf);
 
     newSurf->device = d2dsurf->device;
     cairo_addref_device(&newSurf->device->base);
+    newSurf->device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
 
     return reinterpret_cast<cairo_surface_t*>(newSurf);
 
 FAIL_CREATESIMILAR:
     /** Ensure we call our surfaces desctructor */
     newSurf->~cairo_d2d_surface_t();
     free(newSurf);
     return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
 }
 
 static cairo_status_t
 _cairo_d2d_finish(void	    *surface)
 {
     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
 
+    d2dsurf->device->mVRAMUsage -= _cairo_d2d_compute_surface_mem_size(d2dsurf);
+    if (d2dsurf->bufferTexture) {
+	d2dsurf->device->mVRAMUsage -= _cairo_d2d_compute_surface_mem_size(d2dsurf);
+    }
+
     reset_clip(d2dsurf);
 
     cairo_release_device(&d2dsurf->device->base);
     d2dsurf->~cairo_d2d_surface_t();
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
@@ -3393,16 +3409,17 @@ cairo_d2d_surface_create_for_hwnd(cairo_
 				      D2D1_ALPHA_MODE_PREMULTIPLIED));
     
     newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
 
     _d2d_clear_surface(newSurf);
 
     newSurf->device = d2d_device;
     cairo_addref_device(cairo_device);
+    d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
 
     return reinterpret_cast<cairo_surface_t*>(newSurf);
 
 FAIL_HWND:
     newSurf->~cairo_d2d_surface_t();
     free(newSurf);
     return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
 }
@@ -3502,16 +3519,17 @@ cairo_d2d_surface_create(cairo_device_t 
     }
 
     newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
 
     _d2d_clear_surface(newSurf);
 
     newSurf->device = d2d_device;
     cairo_addref_device(device);
+    d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
 
     return reinterpret_cast<cairo_surface_t*>(newSurf);
 
 FAIL_CREATE:
     newSurf->~cairo_d2d_surface_t();
     free(newSurf);
     return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
 }
@@ -3747,8 +3765,15 @@ cairo_d2d_release_dc(cairo_surface_t *su
     interopRT->ReleaseDC(&r);
 }
 
 int
 cairo_d2d_get_image_surface_cache_usage()
 {
   return _cairo_atomic_int_get(&cache_usage);
 }
+
+int
+cairo_d2d_get_surface_vram_usage(cairo_device_t *device)
+{
+    cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
+    return d2d_device->mVRAMUsage;
+}
--- a/gfx/cairo/cairo/src/cairo-win32.h
+++ b/gfx/cairo/cairo/src/cairo-win32.h
@@ -253,16 +253,23 @@ HDC cairo_d2d_get_dc(cairo_surface_t *su
  */
 void cairo_d2d_release_dc(cairo_surface_t *surcace, const cairo_rectangle_int_t *updated_rect);
 
 /**
  * Get an estimate of the amount of (video) RAM which is currently in use by the D2D
  * internal image surface cache.
  */
 int cairo_d2d_get_image_surface_cache_usage();
+
+/**
+ * Get an estimate of the amount of VRAM which is currently used by the d2d
+ * surfaces for a device. This does -not- include the internal image surface
+ * cache.
+ */
+int cairo_d2d_get_surface_vram_usage(cairo_device_t *device);
 #endif
 
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_WIN32_SURFACE */
 # error Cairo was not compiled with support for the win32 backend
 #endif /* CAIRO_HAS_WIN32_SURFACE */
 
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/fix-clip-test.patch
@@ -0,0 +1,15 @@
+Fix a clip test to test the right coordinate.
+
+Fixed upstream by 498c10032ea3f8631a928cd7df96766f2c8ddca4
+diff --git a/gfx/cairo/cairo/src/cairo-clip.c b/gfx/cairo/cairo/src/cairo-clip.c
+--- a/gfx/cairo/cairo/src/cairo-clip.c
++++ b/gfx/cairo/cairo/src/cairo-clip.c
+@@ -408,7 +408,7 @@ _cairo_clip_rectangle (cairo_clip_t     
+     /* if a smaller clip has already been set, ignore the new path */
+     if (clip->path != NULL) {
+ 	if (rectangle->x <= clip->path->extents.x &&
+-	    rectangle->y <= clip->path->extents.x &&
++	    rectangle->y <= clip->path->extents.y &&
+ 	    rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
+ 	    rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
+ 	{
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -61,18 +61,17 @@ extern HB_INTERNAL hb_font_funcs_t _hb_f
 
 struct _hb_face_t {
   hb_reference_count_t ref_count;
 
   hb_get_table_func_t  get_table;
   hb_destroy_func_t    destroy;
   void                *user_data;
 
-  hb_blob_t *head_blob;
-  const struct head *head_table;
+  unsigned int         units_per_em;
 
   struct hb_ot_layout_t *ot_layout;
 };
 
 
 /*
  * hb_font_t
  */
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -228,44 +228,53 @@ hb_font_get_kerning (hb_font_t *font, hb
 
 static hb_face_t _hb_face_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
 
   NULL, /* get_table */
   NULL, /* destroy */
   NULL, /* user_data */
 
-  NULL, /* head_blob */
-  NULL, /* head_table */
+  0,    /* units_per_em */
 
   NULL  /* ot_layout */
 };
 
 
 hb_face_t *
 hb_face_create_for_tables (hb_get_table_func_t  get_table,
 			   hb_destroy_func_t    destroy,
 			   void                *user_data)
 {
   hb_face_t *face;
+  hb_blob_t *head_blob;
+  const struct head *head_table;
 
   if (!HB_OBJECT_DO_CREATE (hb_face_t, face)) {
     if (destroy)
       destroy (user_data);
     return &_hb_face_nil;
   }
 
   face->get_table = get_table;
   face->destroy = destroy;
   face->user_data = user_data;
 
   face->ot_layout = _hb_ot_layout_new (face);
 
-  face->head_blob = Sanitizer<head>::sanitize (hb_face_get_table (face, HB_OT_TAG_head));
-  face->head_table = Sanitizer<head>::lock_instance (face->head_blob);
+  head_blob = Sanitizer<head>::sanitize (hb_face_get_table (face, HB_OT_TAG_head));
+  if (unlikely (hb_blob_get_length(head_blob) < head::min_size)) {
+    hb_face_destroy (face);
+    return &_hb_face_nil;
+  }
+
+  head_table = Sanitizer<head>::lock_instance (head_blob);
+  face->units_per_em = head_table->unitsPerEm;
+  hb_blob_unlock (head_blob);
+  hb_blob_destroy (head_blob);
 
   return face;
 }
 
 
 typedef struct _hb_face_for_data_closure_t {
   hb_blob_t *blob;
   unsigned int  index;
@@ -341,19 +350,16 @@ hb_face_get_reference_count (hb_face_t *
 
 void
 hb_face_destroy (hb_face_t *face)
 {
   HB_OBJECT_DO_DESTROY (face);
 
   _hb_ot_layout_free (face->ot_layout);
 
-  hb_blob_unlock (face->head_blob);
-  hb_blob_destroy (face->head_blob);
-
   if (face->destroy)
     face->destroy (face->user_data);
 
   free (face);
 }
 
 hb_blob_t *
 hb_face_get_table (hb_face_t *face,
--- a/gfx/harfbuzz/src/hb-ot-head-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-private.hh
@@ -37,17 +37,19 @@
 
 struct head
 {
   static const hb_tag_t Tag	= HB_OT_TAG_head;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     /* Shall we check for magicNumber here?  Who cares? */
-    return c->check_struct (this) && likely (version.major == 1);
+    return c->check_struct (this) &&
+      likely (version.major == 1) &&
+      likely (unitsPerEm >= 16 && unitsPerEm <= 16384);
   }
 
   FixedVersion	version;		/* Version of the head table--currently
 					 * 0x00010000 for version 1.0. */
   FixedVersion	fontRevision;		/* Set by font manufacturer. */
   ULONG		checkSumAdjustment;	/* To compute: set it to 0, sum the
 					 * entire font as ULONG, then store
 					 * 0xB1B0AFBA - sum. */
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
@@ -338,17 +338,17 @@ struct AnchorMatrix
   inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
     return this+matrix[row * cols + col];
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
     TRACE_SANITIZE ();
     if (!c->check_struct (this)) return false;
-    if (unlikely (cols >= ((unsigned int) -1) / rows)) return false;
+    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
     unsigned int count = rows * cols;
     if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
     for (unsigned int i = 0; i < count; i++)
       if (!matrix[i].sanitize (c, this)) return false;
     return true;
   }
 
   USHORT	rows;			/* Number of rows */
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -71,19 +71,19 @@ struct hb_ot_layout_context_t
     {
       unsigned int last;        /* the last valid glyph--used with cursive positioning */
       hb_position_t anchor_x;   /* the coordinates of the anchor point */
       hb_position_t anchor_y;   /* of the last valid glyph */
     } gpos;
   } info;
 
   /* Convert from font-space to user-space */
-  /* XXX div-by-zero / speed up */
-  inline hb_position_t scale_x (int16_t v) { return (int64_t) this->font->x_scale * v / this->face->head_table->unitsPerEm; }
-  inline hb_position_t scale_y (int16_t v) { return (int64_t) this->font->y_scale * v / this->face->head_table->unitsPerEm; }
+  /* XXX speed up */
+  inline hb_position_t scale_x (int16_t v) { return (int64_t) this->font->x_scale * v / this->face->units_per_em; }
+  inline hb_position_t scale_y (int16_t v) { return (int64_t) this->font->y_scale * v / this->face->units_per_em; }
 };
 
 
 HB_INTERNAL hb_ot_layout_t *
 _hb_ot_layout_new (hb_face_t *face);
 
 HB_INTERNAL void
 _hb_ot_layout_free (hb_ot_layout_t *layout);
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -69,29 +69,29 @@ void
   hb_blob_destroy (layout->gpos_blob);
 
   free (layout->new_gdef.klasses);
 }
 
 static const GDEF&
 _get_gdef (hb_face_t *face)
 {
-  return likely (face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
+  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
 }
 
 static const GSUB&
 _get_gsub (hb_face_t *face)
 {
-  return likely (face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
+  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
 }
 
 static const GPOS&
 _get_gpos (hb_face_t *face)
 {
-  return likely (face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
+  return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
 }
 
 
 /*
  * GDEF
  */
 
 /* TODO the public class_t is a mess */
--- a/gfx/src/nsCoord.h
+++ b/gfx/src/nsCoord.h
@@ -443,41 +443,45 @@ inline float NSCoordScale(nscoord aCoord
   return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
 }
 
 /// handy constants
 #define TWIPS_PER_POINT_INT           20
 #define TWIPS_PER_POINT_FLOAT         20.0f
 #define POINTS_PER_INCH_INT           72
 #define POINTS_PER_INCH_FLOAT         72.0f
+#define CM_PER_INCH_FLOAT             2.54f
+#define MM_PER_INCH_FLOAT             25.4f
 
 /* 
  * Twips/unit conversions
  */
-inline nscoord NSUnitsToTwips(float aValue, float aPointsPerUnit)
+inline float NSUnitsToTwips(float aValue, float aPointsPerUnit)
 {
-  return NSToCoordRoundWithClamp(aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT);
+  return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
 }
 
-inline float NSTwipsToUnits(nscoord aTwips, float aUnitsPerPoint)
+inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
 {
   return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
 }
 
-
 /// Unit conversion macros
 //@{
 #define NS_POINTS_TO_TWIPS(x)         NSUnitsToTwips((x), 1.0f)
 #define NS_INCHES_TO_TWIPS(x)         NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT)                      // 72 points per inch
 
 #define NS_MILLIMETERS_TO_TWIPS(x)    NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
 #define NS_CENTIMETERS_TO_TWIPS(x)    NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.3937f))
 
 #define NS_PICAS_TO_TWIPS(x)          NSUnitsToTwips((x), 12.0f)                      // 12 points per pica
 
+#define NS_POINTS_TO_INT_TWIPS(x)     NSToIntRound(NS_POINTS_TO_TWIPS(x))
+#define NS_INCHES_TO_INT_TWIPS(x)     NSToIntRound(NS_INCHES_TO_TWIPS(x))
+
 #define NS_TWIPS_TO_POINTS(x)         NSTwipsToUnits((x), 1.0f)
 #define NS_TWIPS_TO_INCHES(x)         NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
 
 #define NS_TWIPS_TO_MILLIMETERS(x)    NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
 #define NS_TWIPS_TO_CENTIMETERS(x)    NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.3937f))
 
 #define NS_TWIPS_TO_PICAS(x)          NSTwipsToUnits((x), 1.0f / 12.0f)
 //@}
--- a/gfx/src/nsIDeviceContext.h
+++ b/gfx/src/nsIDeviceContext.h
@@ -291,20 +291,26 @@ public:
 
   /**
    * Convert app units to device pixels which is used for gfx/thebes.
    */
   gfxFloat AppUnitsToGfxUnits(nscoord aAppUnits) const
   { return gfxFloat(aAppUnits) / AppUnitsPerDevPixel(); }
 
   /**
-   * Gets the number of app units in one inch; this is the device's DPI
-   * times AppUnitsPerDevPixel().
+   * Gets the number of app units in one physical inch; this is the
+   * device's DPI times AppUnitsPerDevPixel().
    */
-  PRInt32 AppUnitsPerInch() const { return mAppUnitsPerInch; }
+  PRInt32 AppUnitsPerPhysicalInch() const { return mAppUnitsPerPhysicalInch; }
+
+  /**
+   * Gets the number of app units in one CSS inch; this is the
+   * 96 times AppUnitsPerCSSPixel.
+   */
+  static PRInt32 AppUnitsPerCSSInch() { return 96 * AppUnitsPerCSSPixel(); }
 
   /**
    * Fill in an nsFont based on the ID of a system font.  This function
    * may or may not fill in the size, so the size should be set to a
    * reasonable default before calling.
    *
    * @param aID    The system font ID.
    * @param aInfo  The font structure to be filled in.
@@ -464,17 +470,17 @@ public:
    * without any initialization.  Only really used by
    * Gtk native theme stuff.
    */
   NS_IMETHOD ClearCachedSystemFonts() = 0;
 
   /**
    * Check to see if the DPI has changed
    * @return whether there was actually a change in the DPI
-   *         (whether AppUnitsPerDevPixel() or AppUnitsPerInch() changed)
+   *         (whether AppUnitsPerDevPixel() or AppUnitsPerPhysicalInch() changed)
   */
   virtual PRBool CheckDPIChange() = 0;
 
   /**
    * Set the pixel scaling factor: all lengths are multiplied by this factor
    * when we convert them to device pixels. Returns whether the ratio of 
    * app units to dev pixels changed because of the scale factor.
    */
@@ -489,16 +495,16 @@ public:
   /**
    * Get the unscaled ratio of app units to dev pixels; useful if something
    * needs to be converted from to unscaled pixels
    */
   PRInt32 UnscaledAppUnitsPerDevPixel() const { return mAppUnitsPerDevNotScaledPixel; }
 
 protected:
   PRInt32 mAppUnitsPerDevPixel;
-  PRInt32 mAppUnitsPerInch;
+  PRInt32 mAppUnitsPerPhysicalInch;
   PRInt32 mAppUnitsPerDevNotScaledPixel;
   float  mPixelScale;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDeviceContext, NS_IDEVICE_CONTEXT_IID)
 
 #endif /* nsIDeviceContext_h___ */
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -64,17 +64,18 @@ class nsIWidget;
 { 0x23db7c13, 0x873d, 0x4fb5, { 0xaf, 0x29, 0xc1, 0xe9, 0xed, 0x91, 0x23, 0xf9 } }
 // {D930E29B-6909-44e5-AB4B-AF10D6923705}
 #define NS_THEMERENDERER_CID \
 { 0xd930e29b, 0x6909, 0x44e5, { 0xab, 0x4b, 0xaf, 0x10, 0xd6, 0x92, 0x37, 0x5 } }
 
 enum nsTransparencyMode {
   eTransparencyOpaque = 0,  // Fully opaque
   eTransparencyTransparent, // Parts of the window may be transparent
-  eTransparencyGlass        // Transparent parts of the window have Vista AeroGlass effect applied
+  eTransparencyGlass,       // Transparent parts of the window have Vista AeroGlass effect applied
+  eTransparencyBorderlessGlass // As above, but without a border around the opaque areas when there would otherwise be one with eTransparencyGlass
 };
 
 /**
  * nsITheme is a service that provides platform-specific native
  * rendering for widgets.  In other words, it provides the necessary
  * operations to draw a rendering object (an nsIFrame) as a native
  * widget.
  *
--- a/gfx/src/nsThemeConstants.h
+++ b/gfx/src/nsThemeConstants.h
@@ -231,16 +231,17 @@
 #define NS_THEME_WIN_COMMUNICATIONS_TOOLBOX                221
 #define NS_THEME_WIN_MEDIA_TOOLBOX                         222
 #define NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX               223
 
 // Unified toolbar on the Mac
 #define NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR                   224
 
 // Vista glass
+#define NS_THEME_WIN_BORDERLESS_GLASS                      229
 #define NS_THEME_WIN_GLASS                                 230
 
 // Windows themed window frame elements
 #define NS_THEME_WINDOW_TITLEBAR                           231
 #define NS_THEME_WINDOW_TITLEBAR_MAXIMIZED                 232
 #define NS_THEME_WINDOW_FRAME_LEFT                         233
 #define NS_THEME_WINDOW_FRAME_RIGHT                        234
 #define NS_THEME_WINDOW_FRAME_BOTTOM                       235
--- a/gfx/src/thebes/nsSystemFontsAndroid.cpp
+++ b/gfx/src/thebes/nsSystemFontsAndroid.cpp
@@ -60,17 +60,17 @@ nsresult
 nsSystemFontsAndroid::GetSystemFontInfo(const char *aClassName, nsString *aFontName,
                                         gfxFontStyle *aFontStyle) const
 {
     aFontStyle->style = FONT_STYLE_NORMAL;
     aFontStyle->systemFont = PR_TRUE;
     *aFontName = NS_LITERAL_STRING("Droid Sans");
     aFontStyle->weight = 400;
     aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
-    aFontStyle->size = 9.0 * float(gfxPlatform::GetDPI()) / 72.0f;
+    aFontStyle->size = 9.0 * 96.0f / 72.0f;
     return NS_OK;
 }
 
 
 nsresult
 nsSystemFontsAndroid::GetSystemFont(nsSystemFontID anID, nsString *aFontName,
                                     gfxFontStyle *aFontStyle) const
 {
--- a/gfx/src/thebes/nsSystemFontsGTK2.cpp
+++ b/gfx/src/thebes/nsSystemFontsGTK2.cpp
@@ -216,17 +216,17 @@ nsSystemFontsGTK2::GetSystemFontInfo(Gtk
     aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
 
     float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE;
 
     // |size| is now either pixels or pango-points (not Mozilla-points!)
 
     if (!MOZ_pango_font_description_get_size_is_absolute(desc)) {
         // |size| is in pango-points, so convert to pixels.
-        size *= float(gfxPlatform::GetDPI()) / POINTS_PER_INCH_FLOAT;
+        size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
     }
 
     // |size| is now pixels
 
     aFontStyle->size = size;
   
     pango_font_description_free(desc);
 
--- a/gfx/src/thebes/nsSystemFontsQt.cpp
+++ b/gfx/src/thebes/nsSystemFontsQt.cpp
@@ -79,19 +79,17 @@ nsSystemFontsQt::GetSystemFontInfo(const
     *aFontName = quote + family + quote;
     aFontStyle->weight = qFont.weight();
     // FIXME: Set aFontStyle->stretch correctly!
     aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
     // use pixel size directly if it is set, otherwise compute from point size
     if (qFont.pixelSize() != -1) {
         aFontStyle->size = qFont.pixelSize();
     } else {
-        aFontStyle->size = qFont.pointSizeF()
-                           * float(gfxPlatform::GetDPI())
-                           / 72.0f;
+        aFontStyle->size = qFont.pointSizeF() * 96.0f / 72.0f;
     }
     return NS_OK;
 }
 
 
 nsresult
 nsSystemFontsQt::GetSystemFont(nsSystemFontID anID, nsString *aFontName,
                                  gfxFontStyle *aFontStyle) const
--- a/gfx/src/thebes/nsThebesDeviceContext.cpp
+++ b/gfx/src/thebes/nsThebesDeviceContext.cpp
@@ -275,17 +275,17 @@ nsThebesDeviceContext::nsThebesDeviceCon
 #ifdef PR_LOGGING
     if (!gThebesGFXLog)
         gThebesGFXLog = PR_NewLogModule("thebesGfx");
 #endif
 
     PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("#### Creating DeviceContext %p\n", this));
 
     mAppUnitsPerDevPixel = nscoord(-1);
-    mAppUnitsPerInch = nscoord(-1);
+    mAppUnitsPerPhysicalInch = nscoord(-1);
     mAppUnitsPerDevNotScaledPixel = nscoord(-1);
     mPixelScale = 1.0f;
 
     mFontCache = nsnull;
     mWidget = nsnull;
     mFontAliasTable = nsnull;
 
 #ifdef NS_DEBUG
@@ -592,113 +592,105 @@ PRBool
 nsThebesDeviceContext::IsPrinterSurface()
 {
   return(mPrintingSurface != NULL);
 }
 
 nsresult
 nsThebesDeviceContext::SetDPI()
 {
-    PRInt32 dpi = -1;
-    PRBool dotsArePixels = PR_TRUE;
-    // The number of device pixels per CSS pixel. A value <= 0 means choose
-    // automatically based on the DPI. A positive value is used as-is. This effectively
-    // controls the size of a CSS "px".
-    float prefDevPixelsPerCSSPixel = -1.0;
-
-    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
-    if (prefs) {
-        nsXPIDLCString prefString;
-        nsresult rv = prefs->GetCharPref("layout.css.devPixelsPerPx", getter_Copies(prefString));
-        if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
-            prefDevPixelsPerCSSPixel = static_cast<float>(atof(prefString));
-        }
-    }
+    float dpi = -1.0f;
 
     // PostScript, PDF and Mac (when printing) all use 72 dpi
     // Use a printing DC to determine the other dpi values
     if (mPrintingSurface) {
         switch (mPrintingSurface->GetType()) {
             case gfxASurface::SurfaceTypePDF:
             case gfxASurface::SurfaceTypePS:
             case gfxASurface::SurfaceTypeQuartz:
-                dpi = 72;
+                dpi = 72.0f;
                 break;
 #ifdef XP_WIN
             case gfxASurface::SurfaceTypeWin32:
             case gfxASurface::SurfaceTypeWin32Printing: {
                 PRInt32 OSVal = GetDeviceCaps(GetPrintHDC(), LOGPIXELSY);
-                dpi = 144;
+                dpi = 144.0f;
                 mPrintingScale = float(OSVal) / dpi;
                 break;
             }
 #endif
 #ifdef XP_OS2
             case gfxASurface::SurfaceTypeOS2:
                 LONG lDPI;
                 if (DevQueryCaps(GetPrintHDC(), CAPS_VERTICAL_FONT_RES, 1, &lDPI))
                     dpi = lDPI;
                 break;
 #endif
             default:
                 NS_NOTREACHED("Unexpected printing surface type");
                 break;
         }
-        dotsArePixels = PR_FALSE;
+
+        mAppUnitsPerDevNotScaledPixel =
+          NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
     } else {
-        nsresult rv;
-        // A value of -1 means use the minimum of 96 and the system DPI.
+        nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+
+        // A value of -1 means use the maximum of 96 and the system DPI.
         // A value of 0 means use the system DPI. A positive value is used as the DPI.
         // This sets the physical size of a device pixel and thus controls the
-        // interpretation of physical units such as "pt".
+        // interpretation of physical units.
         PRInt32 prefDPI = -1;
         if (prefs) {
-            rv = prefs->GetIntPref("layout.css.dpi", &prefDPI);
+            nsresult rv = prefs->GetIntPref("layout.css.dpi", &prefDPI);
             if (NS_FAILED(rv)) {
                 prefDPI = -1;
             }
         }
 
-        dpi = gfxPlatform::GetDPI();
+        if (prefDPI > 0) {
+            dpi = prefDPI;
+        } else if (mWidget) {
+            dpi = mWidget->GetDPI();
+
+            if (prefDPI < 0) {
+                dpi = PR_MAX(96.0f, dpi);
+            }
+        } else {
+            dpi = 96.0f;
+        }
+
+        // The number of device pixels per CSS pixel. A value <= 0 means choose
+        // automatically based on the DPI. A positive value is used as-is. This effectively
+        // controls the size of a CSS "px".
+        float devPixelsPerCSSPixel = -1.0;
 
-#ifdef MOZ_ENABLE_GTK2
-        if (prefDPI < 0) // Clamp the minimum dpi to 96dpi
-            dpi = PR_MAX(dpi, 96);
-#endif
- 
-        if (prefDPI > 0 && !mPrintingSurface)
-            dpi = prefDPI;
+        if (prefs) {
+            nsXPIDLCString prefString;
+            nsresult rv = prefs->GetCharPref("layout.css.devPixelsPerPx", getter_Copies(prefString));
+            if (NS_SUCCEEDED(rv) && !prefString.IsEmpty()) {
+                devPixelsPerCSSPixel = static_cast<float>(atof(prefString));
+            }
+        }
+
+        if (devPixelsPerCSSPixel <= 0) {
+            if (mWidget) {
+                devPixelsPerCSSPixel = mWidget->GetDefaultScale();
+            } else {
+                devPixelsPerCSSPixel = 1.0;
+            }
+        }
+
+        mAppUnitsPerDevNotScaledPixel =
+            PR_MAX(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
     }
 
-    NS_ASSERTION(dpi != -1, "no dpi set");
+    NS_ASSERTION(dpi != -1.0, "no dpi set");
 
-    if (dotsArePixels) {
-        if (prefDevPixelsPerCSSPixel <= 0) {
-            // Round down to multiple of 96, which is the number of dev pixels
-            // per CSS pixel.  Then, divide that into AppUnitsPerCSSPixel()
-            // to get the number of app units per dev pixel.  The PR_MAXes are
-            // to make sure we don't end up dividing by zero.
-            PRUint32 roundedDPIScaleFactor = dpi/96;
-            mAppUnitsPerDevNotScaledPixel =
-                PR_MAX(1, AppUnitsPerCSSPixel() / PR_MAX(1, roundedDPIScaleFactor));
-        } else {
-            mAppUnitsPerDevNotScaledPixel =
-                PR_MAX(1, static_cast<PRInt32>(AppUnitsPerCSSPixel() /
-                                               prefDevPixelsPerCSSPixel));
-        }
-    } else {
-        /* set mAppUnitsPerDevPixel so we're using exactly 72 dpi, even
-         * though that means we have a non-integer number of device "pixels"
-         * per CSS pixel
-         */
-        mAppUnitsPerDevNotScaledPixel = (AppUnitsPerCSSPixel() * 96) / dpi;
-    }
-
-    mAppUnitsPerInch = NSIntPixelsToAppUnits(dpi, mAppUnitsPerDevNotScaledPixel);
-
+    mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevNotScaledPixel);
     UpdateScaledAppUnits();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThebesDeviceContext::Init(nsIWidget *aWidget)
 {
@@ -1185,32 +1177,34 @@ nsThebesDeviceContext::CalcPrintingSize(
         break;
     }
 #endif
     default:
         NS_ERROR("trying to print to unknown surface type");
     }
 
     if (inPoints) {
-        mWidth = NSToCoordRound(float(size.width) * AppUnitsPerInch() / 72);
-        mHeight = NSToCoordRound(float(size.height) * AppUnitsPerInch() / 72);
+        // For printing, CSS inches and physical inches are identical
+        // so it doesn't matter which we use here
+        mWidth = NSToCoordRound(float(size.width) * AppUnitsPerPhysicalInch() / 72);
+        mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72);
     } else {
         mWidth = NSToIntRound(size.width);
         mHeight = NSToIntRound(size.height);
     }
 }
 
 PRBool nsThebesDeviceContext::CheckDPIChange() {
     PRInt32 oldDevPixels = mAppUnitsPerDevNotScaledPixel;
-    PRInt32 oldInches = mAppUnitsPerInch;
+    PRInt32 oldInches = mAppUnitsPerPhysicalInch;
 
     SetDPI();
 
     return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
-           oldInches != mAppUnitsPerInch;
+           oldInches != mAppUnitsPerPhysicalInch;
 }
 
 PRBool
 nsThebesDeviceContext::SetPixelScale(float aScale)
 {
     if (aScale <= 0) {
         NS_NOTREACHED("Invalid pixel scale value");
         return PR_FALSE;
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -194,16 +194,22 @@ CPPSRCS	= \
 	$(NULL)
 
 ifdef MOZ_IPC
 CPPSRCS += \
 	gfxSharedImageSurface.cpp \
 	$(NULL)
 endif
 
+ifneq (,$(filter x86 x86_64,$(CPU_ARCH)))
+ifdef __GNUC__
+gfxAlphaRecovery.$(OBJ_SUFFIX): MODULE_OPTIMIZE_FLAGS += -msse2
+endif
+endif
+
 SHARED_LIBRARY_LIBS += \
 	../layers/$(LIB_PREFIX)layers.$(LIB_SUFFIX) \
 	$(NULL)
 
 
 ifndef MOZ_ENABLE_LIBXUL
 EXTRA_DSO_LIBS	= gkgfx ycbcr
 ifeq (,$(filter-out WINNT WINCE OS2,$(OS_ARCH)))
--- a/gfx/thebes/gfxAlphaRecovery.cpp
+++ b/gfx/thebes/gfxAlphaRecovery.cpp
@@ -15,16 +15,17 @@
  * The Original Code is Thebes gfx.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vladimir Vukicevic <vladimir@pobox.com>
+ *   Bas Schouten <bschouten@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -34,16 +35,18 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxAlphaRecovery.h"
 
 #include "gfxImageSurface.h"
 
+#define MOZILLA_SSE_INCLUDE_HEADER_FOR_SSE2
+#include "mozilla/SSE.h"
 
 /** from cairo-xlib-utils.c, modified */
 /**
  * Given the RGB data for two image surfaces, one a source image composited
  * with OVER onto a black background, and one a source image composited with 
  * OVER onto a white background, reconstruct the original image data into
  * black_data.
  * 
@@ -92,16 +95,20 @@ gfxAlphaRecovery::RecoverAlpha(gfxImageS
 
     if (size != whiteSurf->GetSize() ||
         (blackSurf->Format() != gfxASurface::ImageFormatARGB32 &&
          blackSurf->Format() != gfxASurface::ImageFormatRGB24) ||
         (whiteSurf->Format() != gfxASurface::ImageFormatARGB32 &&
          whiteSurf->Format() != gfxASurface::ImageFormatRGB24))
         return PR_FALSE;
 
+    if (!analysis && RecoverAlphaSSE2(blackSurf, whiteSurf)) {
+        return PR_TRUE;
+    }
+
     blackSurf->Flush();
     whiteSurf->Flush();
 
     unsigned char* blackData = blackSurf->Data();
     unsigned char* whiteData = whiteSurf->Data();
 
     /* Get the alpha value of 'first' */
     PRUint32 first;
@@ -151,8 +158,137 @@ gfxAlphaRecovery::RecoverAlpha(gfxImageS
                     analysis->b = ((first >> 16) & 0xFF)/d_first_alpha;
                 }
             }
         }
     }
 
     return PR_TRUE;
 }
+
+// Align these for all platforms supporting MOZILLA_COMPILE_WITH_SSE2
+#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
+__declspec(align(16)) PRUint32 greenMaski[] =
+    { 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00 };
+__declspec(align(16)) PRUint32 alphaMaski[] =
+    { 0xff000000, 0xff000000, 0xff000000, 0xff000000 };
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+PRUint32 greenMaski[] __attribute__ ((aligned (16))) =
+    { 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00 };
+PRUint32 alphaMaski[] __attribute__ ((aligned (16))) =
+    { 0xff000000, 0xff000000, 0xff000000, 0xff000000 };
+#elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
+#pragma align 16 (greenMaski, alphaMaski)
+PRUint32 greenMaski[] = { 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00 };
+PRUint32 alphaMaski[] = { 0xff000000, 0xff000000, 0xff000000, 0xff000000 };
+#endif
+
+PRBool
+gfxAlphaRecovery::RecoverAlphaSSE2(gfxImageSurface* blackSurf,
+                                   const gfxImageSurface* whiteSurf)
+{
+#if defined(MOZILLA_COMPILE_WITH_SSE2)
+    if (!mozilla::supports_sse2()) {
+        return PR_FALSE;
+    }
+
+    gfxIntSize size = blackSurf->GetSize();
+
+    if (size != whiteSurf->GetSize() ||
+        (blackSurf->Format() != gfxASurface::ImageFormatARGB32 &&
+         blackSurf->Format() != gfxASurface::ImageFormatRGB24) ||
+        (whiteSurf->Format() != gfxASurface::ImageFormatARGB32 &&
+         whiteSurf->Format() != gfxASurface::ImageFormatRGB24))
+        return PR_FALSE;
+
+    blackSurf->Flush();
+    whiteSurf->Flush();
+
+    unsigned char* blackData = blackSurf->Data();
+    unsigned char* whiteData = whiteSurf->Data();
+
+    if (NS_PTR_TO_UINT32(blackData) & 0xf != NS_PTR_TO_UINT32(whiteData) & 0xf ||
+        (blackSurf->Stride() - whiteSurf->Stride()) & 0xf) {
+        // Cannot keep these in alignment.
+        return PR_FALSE;
+    }
+
+    __m128i greenMask = _mm_load_si128((__m128i*)greenMaski);
+    __m128i alphaMask = _mm_load_si128((__m128i*)alphaMaski);
+
+    for (PRInt32 i = 0; i < size.height; ++i) {
+        PRInt32 j = 0;
+        // Loop single pixels until at 4 byte alignment.
+        while (NS_PTR_TO_UINT32(blackData) & 0xf && j < size.width) {
+            *((PRUint32*)blackData) =
+                RecoverPixel(*reinterpret_cast<PRUint32*>(blackData),
+                             *reinterpret_cast<PRUint32*>(whiteData));
+            blackData += 4;
+            whiteData += 4;
+            j++;
+        }
+        // This extra loop allows the compiler to do some more clever registry
+        // management and makes it about 5% faster than with only the 4 pixel
+        // at a time loop.
+        for (; j < size.width - 8; j += 8) {
+            __m128i black1 = _mm_load_si128((__m128i*)blackData);
+	    __m128i white1 = _mm_load_si128((__m128i*)whiteData);
+            __m128i black2 = _mm_load_si128((__m128i*)(blackData + 16));
+	    __m128i white2 = _mm_load_si128((__m128i*)(whiteData + 16));
+
+            // Execute the same instructions as described in RecoverPixel, only
+            // using an SSE2 packed saturated subtract.
+            white1 = _mm_subs_epu8(white1, black1);
+            white2 = _mm_subs_epu8(white2, black2);
+            white1 = _mm_subs_epu8(greenMask, white1);
+            white2 = _mm_subs_epu8(greenMask, white2);
+            // Producing the final black pixel in an XMM register and storing
+            // that is actually faster than doing a masked store since that
+            // does an unaligned storage. We have the black pixel in a register
+            // anyway.
+            black1 = _mm_andnot_si128(alphaMask, black1);
+            black2 = _mm_andnot_si128(alphaMask, black2);
+            white1 = _mm_slli_si128(white1, 2);
+            white2 = _mm_slli_si128(white2, 2);
+            white1 = _mm_and_si128(alphaMask, white1);
+            white2 = _mm_and_si128(alphaMask, white2);
+            black1 = _mm_or_si128(white1, black1);
+            black2 = _mm_or_si128(white2, black2);
+
+            _mm_store_si128((__m128i*)blackData, black1);
+            _mm_store_si128((__m128i*)(blackData + 16), black2);
+            blackData += 32;
+            whiteData += 32;
+        }
+        for (; j < size.width - 4; j += 4) {
+            __m128i black = _mm_load_si128((__m128i*)blackData);
+	    __m128i white = _mm_load_si128((__m128i*)whiteData);
+
+            white = _mm_subs_epu8(white, black);
+            white = _mm_subs_epu8(greenMask, white);
+            black = _mm_andnot_si128(alphaMask, black);
+            white = _mm_slli_si128(white, 2);
+            white = _mm_and_si128(alphaMask, white);
+            black = _mm_or_si128(white, black);
+            _mm_store_si128((__m128i*)blackData, black);
+            blackData += 16;
+            whiteData += 16;
+        }
+        // Loop single pixels until we're done.
+        while (j < size.width) {
+            *((PRUint32*)blackData) =
+                RecoverPixel(*reinterpret_cast<PRUint32*>(blackData),
+                             *reinterpret_cast<PRUint32*>(whiteData));
+            blackData += 4;
+            whiteData += 4;
+            j++;
+        }
+        blackData += blackSurf->Stride() - j * 4;
+        whiteData += whiteSurf->Stride() - j * 4;
+    }
+
+    blackSurf->MarkDirty();
+    
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
--- a/gfx/thebes/gfxAlphaRecovery.h
+++ b/gfx/thebes/gfxAlphaRecovery.h
@@ -54,11 +54,17 @@ public:
      * black background and the other onto white, recovers alpha values from
      * the difference and sets the alpha values on the black surface.
      * The surfaces must have format RGB24 or ARGB32.
      * Returns PR_TRUE on success.
      */
     static PRBool RecoverAlpha (gfxImageSurface *blackSurface,
                                 const gfxImageSurface *whiteSurface,
                                 Analysis *analysis = nsnull);
+
+    /* This does the save as the previous function, only using SSE2
+     * optimizations, usually this should not be called directly.
+     */
+    static PRBool RecoverAlphaSSE2 (gfxImageSurface *blackSurface,
+                                    const gfxImageSurface *whiteSurface);
 };
 
 #endif /* _GFXALPHARECOVERY_H_ */
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -1197,16 +1197,21 @@ gfxFontUtils::ValidateSFNTHeaders(const 
         NS_WARNING("invalid font (missing OS/2 table)");
         return PR_FALSE;
     }
 #endif
 
     // -- head table data
     const HeadTable *headData = reinterpret_cast<const HeadTable*>(aFontData + headOffset);
 
+    if (headData->tableVersionNumber != HeadTable::HEAD_VERSION) {
+        NS_WARNING("invalid font (head table version)");
+        return PR_FALSE;
+    }
+
     if (headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER) {
         NS_WARNING("invalid font (head magic number)");
         return PR_FALSE;
     }
 
     if (headData->checkSumAdjustment != (HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum)) {
         NS_WARNING("invalid font (bad checksum)");
         // Bug 483459 - warn about a bad checksum but allow the font to be 
@@ -1965,18 +1970,20 @@ gfxFontUtils::MakeEOTHeader(const PRUint
 
     // at this point, all table offset/length values are within bounds
     
     // read in the data from those tables
 
     // -- head table data
     const HeadTable  *headData = reinterpret_cast<const HeadTable*>(aFontData + headOffset);
 
-    if (headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER)
+    if (headData->tableVersionNumber != HeadTable::HEAD_VERSION ||
+        headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER) {
         return NS_ERROR_FAILURE;
+    }
 
     eotHeader->checkSumAdjustment = headData->checkSumAdjustment;
 
     // -- name table data
 
     // -- first, read name table header
     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aFontData + nameOffset);
     PRUint32 nameStringsBase = PRUint32(nameHeader->stringOffset);
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -365,16 +365,17 @@ struct AutoSwap_PRUint24 {
     operator PRUint32() const { return value[0] << 16 | value[1] << 8 | value[2]; }
 private:
     AutoSwap_PRUint24() { }
     PRUint8  value[3];
 };
 
 struct HeadTable {
     enum {
+        HEAD_VERSION = 0x00010000,
         HEAD_MAGIC_NUMBER = 0x5F0F3CF5,
         HEAD_CHECKSUM_CALC_CONST = 0xB1B0AFBA
     };
 
     AutoSwap_PRUint32    tableVersionNumber;    // Fixed, 0x00010000 for version 1.0.
     AutoSwap_PRUint32    fontRevision;          // Set by font manufacturer.
     AutoSwap_PRUint32    checkSumAdjustment;    // To compute: set it to 0, sum the entire font as ULONG, then store 0xB1B0AFBA - sum.
     AutoSwap_PRUint32    magicNumber;           // Set to 0x5F0F3CF5.
--- a/gfx/thebes/gfxOS2Platform.cpp
+++ b/gfx/thebes/gfxOS2Platform.cpp
@@ -216,27 +216,8 @@ gfxOS2Platform::FindFontForChar(PRUint32
             }
         }
     }
 
     // no match found, so add to the set of non-matching codepoints
     mCodepointsWithNoFonts.set(aCh);
     return nsnull;
 }
-
-void
-gfxOS2Platform::InitDisplayCaps()
-{
-    // create DC compatible with the screen
-    HDC dc = DevOpenDC((HAB)1, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
-    if (dc > 0) {
-        // we do have a DC and we can query the DPI setting from it
-        LONG lDPI;
-        if (DevQueryCaps(dc, CAPS_VERTICAL_FONT_RES, 1, &lDPI))
-            gfxPlatform::sDPI = lDPI;
-        DevCloseDC(dc);
-    }
-
-    if (gfxPlatform::sDPI <= 0) {
-        // Fall back to something sane
-        gfxPlatform::sDPI = 96;
-    }
-}
--- a/gfx/thebes/gfxOS2Platform.h
+++ b/gfx/thebes/gfxOS2Platform.h
@@ -82,18 +82,16 @@ public:
     already_AddRefed<gfxOS2Font> FindFontForChar(PRUint32 aCh, gfxOS2Font *aFont);
 
     // return true if it's already known that we don't have a font for this char
     PRBool noFontWithChar(PRUint32 aCh) {
         return mCodepointsWithNoFonts.test(aCh);
     }
 
 protected:
-    void InitDisplayCaps();
-
     static gfxFontconfigUtils *sFontconfigUtils;
 
 private:
     // when font lookup fails for a character, cache it to skip future searches
     gfxSparseBitSet mCodepointsWithNoFonts;
 };
 
 #endif /* GFX_OS2_PLATFORM_H */
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -707,28 +707,40 @@ gfx_pango_fc_font_get_coverage(PangoFont
             self->mCoverage =
                 pango_coverage_ref(downloadedFontEntry->GetPangoCoverage());
         }
     }
 
     return pango_coverage_ref(self->mCoverage);
 }
 
+static PRInt32
+GetDPI()
+{
+#if defined(MOZ_WIDGET_GTK2)
+    return gfxPlatformGtk::GetDPI();
+#elif defined(MOZ_WIDGET_QT)
+    return gfxQtPlatform::GetDPI();
+#else
+    return 96;
+#endif
+}
+
 static PangoFontDescription *
 gfx_pango_fc_font_describe(PangoFont *font)
 {
     gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
     PangoFcFont *fcFont = &self->parent_instance;
     PangoFontDescription *result =
         pango_font_description_copy(fcFont->description);
 
     gfxFcFont *gfxFont = gfxPangoFcFont::GfxFont(self);
     if (gfxFont) {
         double pixelsize = gfxFont->GetStyle()->size;
-        double dpi = gfxPlatform::GetDPI();
+        double dpi = GetDPI();
         gint size = moz_pango_units_from_double(pixelsize * dpi / 72.0);
         pango_font_description_set_size(result, size);
     }
     return result;
 }
 
 static PangoFontDescription *
 gfx_pango_fc_font_describe_absolute(PangoFont *font)
@@ -1715,18 +1727,17 @@ gfx_pango_font_map_load_fontset(PangoFon
     return gfxPangoFontset::NewFontset(fontGroup, language);
 }
 
 static double
 gfx_pango_font_map_get_resolution(PangoFcFontMap *fcfontmap,
                                   PangoContext *context)
 {
     // This merely enables the FC_SIZE field of the pattern to be accurate.
-    // We use gfxPlatform::GetDPI() much of the time...
-    return gfxPlatform::GetDPI();
+    return GetDPI();
 }
 
 #ifdef MOZ_WIDGET_GTK2
 static void ApplyGdkScreenFontOptions(FcPattern *aPattern);
 #endif
 
 // Apply user settings and defaults to pattern in preparation for matching.
 static void
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -81,18 +81,16 @@
 #include "nsCRT.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
 #include "mozilla/FunctionTimer.h"
 
 gfxPlatform *gPlatform = nsnull;
 
-PRInt32 gfxPlatform::sDPI = -1;
-
 // These two may point to the same profile
 static qcms_profile *gCMSOutputProfile = nsnull;
 static qcms_profile *gCMSsRGBProfile = nsnull;
 
 static qcms_transform *gCMSRGBTransform = nsnull;
 static qcms_transform *gCMSInverseRGBTransform = nsnull;
 static qcms_transform *gCMSRGBATransform = nsnull;
 
@@ -1058,23 +1056,16 @@ static void MigratePrefs()
         rv = prefs->GetBoolPref(CMPrefNameOld, &CMWasEnabled);
         if (NS_SUCCEEDED(rv) && (CMWasEnabled == PR_TRUE))
             prefs->SetIntPref(CMPrefName, eCMSMode_All);
         prefs->ClearUserPref(CMPrefNameOld);
     }
 
 }
 
-void
-gfxPlatform::InitDisplayCaps()
-{
-    // Fall back to something sane
-    gfxPlatform::sDPI = 96;
-}
-
 // default SetupClusterBoundaries, based on Unicode properties;
 // platform subclasses may override if they wish
 static nsIUGenCategory* gGenCategory = nsnull;
 
 static nsIUGenCategory*
 GetGenCategory()
 {
     if (!gGenCategory) {
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -332,44 +332,27 @@ public:
      */
     static qcms_transform* GetCMSInverseRGBTransform();
 
     /**
      * Return sRGBA -> output device transform.
      */
     static qcms_transform* GetCMSRGBATransform();
 
-    /**
-     * Return display DPI
-     */
-    static PRInt32 GetDPI() {
-        if (sDPI < 0) {
-            gfxPlatform::GetPlatform()->InitDisplayCaps();
-        }
-        NS_ASSERTION(sDPI > 0, "Something is wrong");
-        return sDPI;
-    }
-
     virtual void FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aPref);
 
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     static PRBool GetBoolPref(const char *aPref, PRBool aDefault);
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, 
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
                                                
-    /**
-     * Initialize any needed display metrics (such as DPI)
-     */
-    virtual void InitDisplayCaps();
-    static PRInt32 sDPI;
-
     PRBool  mAllowDownloadableFonts;
 
     // whether to use the HarfBuzz layout engine
     PRInt8  mUseHarfBuzzLevel;
 
 private:
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -470,27 +470,32 @@ gfxPlatformGtk::CreateFontGroup(const ns
                                const gfxFontStyle *aStyle,
                                 gfxUserFontSet * /*aUserFontSet*/)
 {
     return new gfxFT2FontGroup(aFamilies, aStyle);
 }
 
 #endif
 
-void
-gfxPlatformGtk::InitDisplayCaps()
+static PRInt32 sDPI = 0;
+
+PRInt32
+gfxPlatformGtk::GetDPI()
 {
-    // Make sure init is run so we have a resolution
-    GdkScreen *screen = gdk_screen_get_default();
-    gtk_settings_get_for_screen(screen);
-    gfxPlatform::sDPI = PRInt32(round(gdk_screen_get_resolution(screen)));
-    if (gfxPlatform::sDPI <= 0) {
-        // Fall back to something sane
-        gfxPlatform::sDPI = 96;
+    if (!sDPI) {
+        // Make sure init is run so we have a resolution
+        GdkScreen *screen = gdk_screen_get_default();
+        gtk_settings_get_for_screen(screen);
+        sDPI = PRInt32(round(gdk_screen_get_resolution(screen)));
+        if (sDPI <= 0) {
+            // Fall back to something sane
+            sDPI = 96;
+        }
     }
+    return sDPI;
 }
 
 qcms_profile *
 gfxPlatformGtk::GetPlatformCMSOutputProfile()
 {
 #ifdef MOZ_X11
     const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
     const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -117,18 +117,18 @@ public:
 #ifndef MOZ_PANGO
     FT_Library GetFTLibrary();
 #endif
 
     static void SetGdkDrawable(gfxASurface *target,
                                GdkDrawable *drawable);
     static GdkDrawable *GetGdkDrawable(gfxASurface *target);
 
+    static PRInt32 GetDPI();
+
 protected:
-    void InitDisplayCaps();
-
     static gfxFontconfigUtils *sFontconfigUtils;
 
 private:
     virtual qcms_profile *GetPlatformCMSOutputProfile();
 };
 
 #endif /* GFX_PLATFORM_GTK_H */
--- a/gfx/thebes/gfxQtPlatform.cpp
+++ b/gfx/thebes/gfxQtPlatform.cpp
@@ -565,19 +565,18 @@ gfxQtPlatform::GetPrefFontEntries(const 
     return mPrefFonts.Get(aKey, array);
 }
 
 void
 gfxQtPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& array)
 {
     mPrefFonts.Put(aKey, array);
 }
+
 #endif
 
-void
-gfxQtPlatform::InitDisplayCaps()
+PRInt32
+gfxQtPlatform::GetDPI()
 {
     QDesktopWidget* rootWindow = qApp->desktop();
-    sDPI = rootWindow->logicalDpiY(); // y-axis DPI for fonts
-    if (sDPI <= 0)
-        sDPI = 96; // something more sensible
+    PRInt32 dpi = rootWindow->logicalDpiY(); // y-axis DPI for fonts
+    return dpi <= 0 ? 96 : dpi;
 }
-
--- a/gfx/thebes/gfxQtPlatform.h
+++ b/gfx/thebes/gfxQtPlatform.h
@@ -126,19 +126,20 @@ public:
 
 #ifndef MOZ_PANGO
     FT_Library GetFTLibrary();
 #endif
 
     RenderMode GetRenderMode() { return mRenderMode; }
     void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; }
 
+    static PRInt32 GetDPI();
+
 protected:
     static gfxFontconfigUtils *sFontconfigUtils;
-    void InitDisplayCaps();
 
 private:
     virtual qcms_profile *GetPlatformCMSOutputProfile();
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 
     RenderMode mRenderMode;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -102,16 +102,45 @@ public:
 
     NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed) {
         *memoryUsed = cairo_d2d_get_image_surface_cache_usage();
         return NS_OK;
     }
 }; 
 
 NS_IMPL_ISUPPORTS1(D2DCacheReporter, nsIMemoryReporter)
+
+class D2DVRAMReporter :
+    public nsIMemoryReporter
+{
+public:
+    D2DVRAMReporter()
+    { }
+
+    NS_DECL_ISUPPORTS
+
+    NS_IMETHOD GetPath(char **memoryPath) {
+        *memoryPath = strdup("gfx/d2d/surfacevram");
+        return NS_OK;
+    }
+
+    NS_IMETHOD GetDescription(char **desc) {
+        *desc = strdup("Video memory used by D2D surfaces");
+        return NS_OK;
+    }
+
+    NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed) {
+	*memoryUsed = cairo_d2d_get_surface_vram_usage(
+	    gfxWindowsPlatform::GetPlatform()->GetD2DDevice()
+	    );
+        return NS_OK;
+    }
+};
+
+NS_IMPL_ISUPPORTS1(D2DVRAMReporter, nsIMemoryReporter)
 #endif
 
 #ifdef WINCE
 #include <shlwapi.h>
 
 #ifdef CAIRO_HAS_DDRAW_SURFACE
 #include "gfxDDrawSurface.h"
 #endif
@@ -184,19 +213,20 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     
     OSVERSIONINFOA versionInfo;
     versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
     ::GetVersionExA(&versionInfo);
     bool isVistaOrHigher = versionInfo.dwMajorVersion >= 6;
 
 #ifdef CAIRO_HAS_D2D_SURFACE
     NS_RegisterMemoryReporter(new D2DCacheReporter());
+    NS_RegisterMemoryReporter(new D2DVRAMReporter());
     mD2DDevice = NULL;
 
-    if (isVistaOrHigher && 0) {
+    if (isVistaOrHigher) {
         // We need a DWriteFactory to work.
         HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
         D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
             GetProcAddress(d3d10module, "D3D10CreateDevice1");
         nsRefPtr<ID3D10Device1> device;
 
         if (createD3DDevice) {
             // We try 10.0 first even though we prefer 10.1, since we want to
@@ -593,26 +623,16 @@ gfxWindowsPlatform::WindowsOSVersion()
         } else {
             winVersion = PRInt32(vinfo.dwMajorVersion << 16) + vinfo.dwMinorVersion;
         }
     }
     return winVersion;
 }
 
 void
-gfxWindowsPlatform::InitDisplayCaps()
-{
-    HDC dc = GetDC((HWND)nsnull);
-
-    gfxPlatform::sDPI = GetDeviceCaps(dc, LOGPIXELSY);
-
-    ReleaseDC((HWND)nsnull, dc);
-}
-
-void
 gfxWindowsPlatform::FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aPref)
 {
     PRBool clearTextFontCaches = PR_TRUE;
 
     gfxPlatform::FontsPrefsChanged(aPrefBranch, aPref);
 
     if (!aPref) {
         mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -221,18 +221,16 @@ public:
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
 #endif
 
 #ifdef MOZ_FT2_FONTS
     FT_Library GetFTLibrary();
 #endif
 
 protected:
-    void InitDisplayCaps();
-
     RenderMode mRenderMode;
 
     PRBool mUseClearTypeForDownloadableFonts;
     PRBool mUseClearTypeAlways;
 
 private:
     void Init();
 
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -49,16 +49,17 @@ LIBRARY_NAME = mozipdlgen_s
 FORCE_STATIC_LIB = 1
 LIBXUL_LIBRARY = 1
 EXPORT_LIBRARY = 1
 
 ##-----------------------------------------------------------------------------
 ## When you add IPDL files to a source directory, list the directory here.
 ##
 IPDLDIRS =  \
+  uriloader/exthandler \
   dom/src/geolocation \
   dom/plugins  \
   dom/ipc  \
   gfx/layers/ipc \
   ipc/ipdl/test/cxx  \
   ipc/testshell  \
   js/ipc  \
   js/jetpack \
--- a/js/src/config/milestone.txt
+++ b/js/src/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.pl.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-2.0b4pre
+2.0b5pre
--- a/js/src/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/src/xpconnect/src/dom_quickstubs.qsconf
@@ -325,16 +325,18 @@ members = [
     'nsIDOMHTMLTextAreaElement.value',
     'nsIDOMHTMLTextAreaElement.type',
     'nsIDOMHTMLTextAreaElement.select',
     'nsIDOMHTMLTitleElement.text',
     'nsIDOMHTMLCanvasElement.width',
     'nsIDOMHTMLCanvasElement.height',
     'nsIDOMHTMLCanvasElement.getContext',
     'nsIDOMHTMLCanvasElement.toDataURL',
+    'nsIDOMNSHTMLDocument.width',
+    'nsIDOMNSHTMLDocument.height',
     'nsIDOMNSHTMLDocument.domain',
     'nsIDOMNSHTMLDocument.getSelection',
     'nsIDOMNSHTMLDocument.designMode',
     'nsIDOMNSHTMLElement.contentEditable',
     'nsIDOMNSHTMLElement.isContentEditable',
     'nsIDOMNSHTMLElement.offsetParent',
     'nsIDOMNSHTMLElement.innerHTML',
     'nsIDOMNSHTMLElement.offsetLeft',
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -96,17 +96,17 @@
  * @note Always call the member functions in the order of PrepareImage(),
  * ComputeSize(), and Draw().
  */
 class ImageRenderer {
 public:
   enum {
     FLAG_SYNC_DECODE_IMAGES = 0x01
   };
-  ImageRenderer(nsIFrame* aForFrame, const nsStyleImage& aImage, PRUint32 aFlags);
+  ImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage, PRUint32 aFlags);
   ~ImageRenderer();
   /**
    * Populates member variables to get ready for rendering.
    * @return PR_TRUE iff the image is ready, and there is at least a pixel to
    * draw.
    */
   PRBool PrepareImage();
   /**
@@ -122,17 +122,17 @@ public:
             nsIRenderingContext& aRenderingContext,
             const nsRect&        aDest,
             const nsRect&        aFill,
             const nsPoint&       aAnchor,
             const nsRect&        aDirty);
 
 private:
   nsIFrame*                 mForFrame;
-  nsStyleImage              mImage;
+  const nsStyleImage*       mImage;
   nsStyleImageType          mType;
   nsCOMPtr<imgIContainer>   mImageContainer;
   nsRefPtr<nsStyleGradient> mGradientData;
 #ifdef MOZ_SVG
   nsIFrame*                 mPaintServerFrame;
   nsLayoutUtils::SurfaceFromElementResult mImageElementSurface;
 #endif
   PRBool                    mIsReady;
@@ -2391,17 +2391,17 @@ PaintBackgroundLayer(nsPresContext* aPre
    *   background-size
    *   background-position
    *   background-repeat
    */
 
   PRUint32 irFlags = 0;
   if (aFlags & nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES)
     irFlags |= ImageRenderer::FLAG_SYNC_DECODE_IMAGES;
-  ImageRenderer imageRenderer(aForFrame, aLayer.mImage, irFlags);
+  ImageRenderer imageRenderer(aForFrame, &aLayer.mImage, irFlags);
   if (!imageRenderer.PrepareImage()) {
     // There's no image or it's not ready to be painted.
     return;
   }
 
   // Compute background origin area relative to aBorderArea now as we may need
   // it to compute the effective image size for a CSS gradient.
   nsRect bgPositioningArea(0, 0, 0, 0);
@@ -3587,21 +3587,21 @@ nsCSSRendering::GetTextDecorationRectInt
   r.pos.y = baseline - NS_floor(offset + 0.5);
   return r;
 }
 
 // ------------------
 // ImageRenderer
 // ------------------
 ImageRenderer::ImageRenderer(nsIFrame* aForFrame,
-                             const nsStyleImage& aImage,
+                             const nsStyleImage* aImage,
                              PRUint32 aFlags)
   : mForFrame(aForFrame)
   , mImage(aImage)
-  , mType(aImage.GetType())
+  , mType(aImage->GetType())
   , mImageContainer(nsnull)
   , mGradientData(nsnull)
 #ifdef MOZ_SVG
   , mPaintServerFrame(nsnull)
 #endif
   , mIsReady(PR_FALSE)
   , mSize(0, 0)
   , mFlags(aFlags)
@@ -3610,46 +3610,46 @@ ImageRenderer::ImageRenderer(nsIFrame* a
 
 ImageRenderer::~ImageRenderer()
 {
 }
 
 PRBool
 ImageRenderer::PrepareImage()
 {
-  if (mImage.IsEmpty() || !mImage.IsComplete()) {
+  if (mImage->IsEmpty() || !mImage->IsComplete()) {
     // Make sure the image is actually decoding
-    mImage.RequestDecode();
+    mImage->RequestDecode();
 
     // We can not prepare the image for rendering if it is not fully loaded.
     //
     // Special case: If we requested a sync decode and we have an image, push
     // on through
     nsCOMPtr<imgIContainer> img;
     if (!((mFlags & FLAG_SYNC_DECODE_IMAGES) &&
           (mType == eStyleImageType_Image) &&
-          (NS_SUCCEEDED(mImage.GetImageData()->GetImage(getter_AddRefs(img))) && img)))
+          (NS_SUCCEEDED(mImage->GetImageData()->GetImage(getter_AddRefs(img))) && img)))
     return PR_FALSE;
   }
 
   switch (mType) {
     case eStyleImageType_Image:
     {
       nsCOMPtr<imgIContainer> srcImage;
-      mImage.GetImageData()->GetImage(getter_AddRefs(srcImage));
-      NS_ABORT_IF_FALSE(srcImage, "If srcImage is null, mImage.IsComplete() "
+      mImage->GetImageData()->GetImage(getter_AddRefs(srcImage));
+      NS_ABORT_IF_FALSE(srcImage, "If srcImage is null, mImage->IsComplete() "
                                   "should have returned false");
 
-      if (!mImage.GetCropRect()) {
+      if (!mImage->GetCropRect()) {
         mImageContainer.swap(srcImage);
       } else {
         nsIntRect actualCropRect;
         PRBool isEntireImage;
         PRBool success =
-          mImage.ComputeActualCropRect(actualCropRect, &isEntireImage);
+          mImage->ComputeActualCropRect(actualCropRect, &isEntireImage);
         NS_ASSERTION(success, "ComputeActualCropRect() should not fail here");
         if (!success || actualCropRect.IsEmpty()) {
           // The cropped image has zero size
           return PR_FALSE;
         }
         if (isEntireImage) {
           // The cropped image is identical to the source image
           mImageContainer.swap(srcImage);
@@ -3668,24 +3668,24 @@ ImageRenderer::PrepareImage()
           }
           mImageContainer.swap(subImage);
         }
       }
       mIsReady = PR_TRUE;
       break;
     }
     case eStyleImageType_Gradient:
-      mGradientData = mImage.GetGradientData();
+      mGradientData = mImage->GetGradientData();
       mIsReady = PR_TRUE;
       break;
 #ifdef MOZ_SVG
     case eStyleImageType_Element:
     {
       nsAutoString elementId =
-        NS_LITERAL_STRING("#") + nsDependentString(mImage.GetElementId());
+        NS_LITERAL_STRING("#") + nsDependentString(mImage->GetElementId());
       nsCOMPtr<nsIURI> targetURI;
       nsCOMPtr<nsIURI> base = mForFrame->GetContent()->GetBaseURI();
       nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), elementId,
                                                 mForFrame->GetContent()->GetCurrentDoc(), base);
       nsSVGPaintingProperty* property = nsSVGEffects::GetPaintingPropertyForURI(
           targetURI, mForFrame->GetFirstContinuation(),
           nsSVGEffects::BackgroundImageProperty());
       if (!property)
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -921,18 +921,18 @@ DocumentViewerImpl::InitInternal(nsIWidg
         // the document viewer at the moment to get the right device context
         // (this won't break anyone, since page layout mode was never really
         // usable)
 #endif
         double pageWidth = 0, pageHeight = 0;
         mPresContext->GetPrintSettings()->GetEffectivePageSize(&pageWidth,
                                                                &pageHeight);
         mPresContext->SetPageSize(
-          nsSize(mPresContext->TwipsToAppUnits(NSToIntFloor(pageWidth)),
-                 mPresContext->TwipsToAppUnits(NSToIntFloor(pageHeight))));
+          nsSize(mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageWidth)),
+                 mPresContext->CSSTwipsToAppUnits(NSToIntFloor(pageHeight))));
         mPresContext->SetIsRootPaginatedDocument(PR_TRUE);
         mPresContext->SetPageScale(1.0f);
       }
 #endif
     }
   }
 
   nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryReferent(mContainer));
@@ -3670,17 +3670,17 @@ DocumentViewerImpl::Print(nsIPrintSettin
   if (pDoc)
     return pDoc->Print();
 
   if (!mPrintEngine) {
     mPrintEngine = new nsPrintEngine();
     NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY);
 
     rv = mPrintEngine->Initialize(this, docShell, mDocument, 
-                                  float(mDeviceContext->AppUnitsPerInch()) /
+                                  float(mDeviceContext->AppUnitsPerCSSInch()) /
                                   float(mDeviceContext->AppUnitsPerDevPixel()) /
                                   mPageZoom,
                                   mParentWidget,
 #ifdef NS_DEBUG
                                   mDebugFile
 #else
                                   nsnull
 #endif
@@ -3738,17 +3738,17 @@ DocumentViewerImpl::PrintPreview(nsIPrin
     aChildDOMWin->GetDocument(getter_AddRefs(domDoc));
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
     NS_ENSURE_STATE(doc);
 
     mPrintEngine = new nsPrintEngine();
     NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY);
 
     rv = mPrintEngine->Initialize(this, docShell, doc,
-                                  float(mDeviceContext->AppUnitsPerInch()) /
+                                  float(mDeviceContext->AppUnitsPerCSSInch()) /
                                   float(mDeviceContext->AppUnitsPerDevPixel()) /
                                   mPageZoom,
                                   mParentWidget,
 #ifdef NS_DEBUG
                                   mDebugFile
 #else
                                   nsnull
 #endif
@@ -3858,23 +3858,18 @@ DocumentViewerImpl::PrintPreviewNavigate
 
   if (fndPageFrame) {
     nscoord deadSpaceGapTwips = 0;
     nsIPageSequenceFrame * sqf = do_QueryFrame(seqFrame);
     if (sqf) {
       sqf->GetDeadSpaceValue(&deadSpaceGapTwips);
     }
 
-    // To compute deadSpaceGap, use the same presContext as was used
-    // to layout the seqFrame. (That presContext may have different
-    // TwipsToAppUnits conversion from this->mPresContext)
-    nscoord deadSpaceGap = 
-      seqFrame->PresContext()->TwipsToAppUnits(deadSpaceGapTwips);
-
-    nscoord newYPosn = 
+    nscoord deadSpaceGap = nsPresContext::CSSTwipsToAppUnits(deadSpaceGapTwips);
+    nscoord newYPosn =
       nscoord(mPrintEngine->GetPrintPreviewScale() * 
               float(fndPageFrame->GetPosition().y - deadSpaceGap));
     sf->ScrollTo(nsPoint(pt.x, newYPosn), nsIScrollableFrame::INSTANT);
   }
   return NS_OK;
 
 }
 
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -975,20 +975,17 @@ public:
   {
     mObservesMutationsForPrint = aObserve;
   }
   PRBool ObservesNativeAnonMutationsForPrint()
   {
     return mObservesMutationsForPrint;
   }
 
-  void SetIsActive(PRBool aIsActive)
-  {
-    mIsActive = aIsActive;
-  }
+  virtual nsresult SetIsActive(PRBool aIsActive) = 0;
 
   PRBool IsActive()
   {
     return mIsActive;
   }
 
   // mouse capturing
 
@@ -1123,16 +1120,17 @@ protected:
 
   PRPackedBool              mStylesHaveChanged;
   PRPackedBool              mDidInitialReflow;
   PRPackedBool              mIsDestroying;
   PRPackedBool              mIsReflowing;
   PRPackedBool              mPaintingSuppressed;  // For all documents we initially lock down painting.
   PRPackedBool              mIsThemeSupportDisabled;  // Whether or not form controls should use nsITheme in this shell.
   PRPackedBool              mIsActive;
+  PRPackedBool              mFrozen;
 
 #ifdef ACCESSIBILITY
   /**
    * Call this when there have been significant changes in the rendering for
    * a content subtree, so the matching accessibility subtree can be invalidated
    */
   void InvalidateAccessibleSubtree(nsIContent *aContent);
 #endif
@@ -1154,16 +1152,18 @@ protected:
   nsWeakFrame*              mWeakFrames;
 
   // Most recent canvas background color.
   nscolor                   mCanvasBackgroundColor;
 
   // Live pres shells, for memory and other tracking
   typedef nsPtrHashKey<nsIPresShell> PresShellPtrKey;
   static nsTHashtable<PresShellPtrKey> *sLiveShells;
+
+  static nsIContent* gKeyDownTarget;
 };
 
 /**
  * Create a new empty presentation shell. Upon success, call Init
  * before attempting to use the shell.
  */
 nsresult
 NS_NewPresShell(nsIPresShell** aInstancePtrResult);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3282,16 +3282,19 @@ nsLayoutUtils::GetFrameTransparency(nsIF
   if (aCSSRootFrame->IsThemed(&transparency))
     return transparency == nsITheme::eTransparent
          ? eTransparencyTransparent
          : eTransparencyOpaque;
 
   if (aCSSRootFrame->GetStyleDisplay()->mAppearance == NS_THEME_WIN_GLASS)
     return eTransparencyGlass;
 
+  if (aCSSRootFrame->GetStyleDisplay()->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS)
+    return eTransparencyBorderlessGlass;
+
   // We need an uninitialized window to be treated as opaque because
   // doing otherwise breaks window display effects on some platforms,
   // specifically Vista. (bug 450322)
   if (aBackgroundFrame->GetType() == nsGkAtoms::viewportFrame &&
       !aBackgroundFrame->GetFirstChild(nsnull)) {
     return eTransparencyOpaque;
   }
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -480,17 +480,17 @@ nsPresContext::GetFontPreferences()
   pref.Assign("font.minimum-size.");
   pref.Append(langGroup);
 
   PRInt32 size = nsContentUtils::GetIntPref(pref.get());
   if (unit == eUnit_px) {
     mMinimumFontSize = CSSPixelsToAppUnits(size);
   }
   else if (unit == eUnit_pt) {
-    mMinimumFontSize = this->PointsToAppUnits(size);
+    mMinimumFontSize = CSSPointsToAppUnits(size);
   }
 
   // get attributes specific to each generic font
   nsCAutoString generic_dot_langGroup;
   for (PRInt32 eType = eDefaultFont_Variable; eType < eDefaultFont_COUNT; ++eType) {
     generic_dot_langGroup.Assign(kGenericFont[eType]);
     generic_dot_langGroup.Append(langGroup);
 
@@ -544,20 +544,20 @@ nsPresContext::GetFontPreferences()
     // parity, we enable the ability to set a different font-size on all platforms.
 
     // get font.size.[generic].[langGroup]
     // size=0 means 'Auto', i.e., generic fonts retain the size of the variable font
     MAKE_FONT_PREF_KEY(pref, "font.size", generic_dot_langGroup);
     size = nsContentUtils::GetIntPref(pref.get());
     if (size > 0) {
       if (unit == eUnit_px) {
-        font->size = nsPresContext::CSSPixelsToAppUnits(size);
+        font->size = CSSPixelsToAppUnits(size);
       }
       else if (unit == eUnit_pt) {
-        font->size = this->PointsToAppUnits(size);
+        font->size = CSSPointsToAppUnits(size);
       }
     }
 
     // get font.size-adjust.[generic].[langGroup]
     // XXX only applicable on GFX ports that handle |font-size-adjust|
     MAKE_FONT_PREF_KEY(pref, "font.size-adjust", generic_dot_langGroup);
     cvalue = nsContentUtils::GetCharPref(pref.get());
     if (!cvalue.IsEmpty()) {
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -560,17 +560,17 @@ public:
   void SetFullZoom(float aZoom);
 
   nscoord GetAutoQualityMinFontSize() {
     return DevPixelsToAppUnits(mAutoQualityMinFontSizePixelsPref);
   }
   
   static PRInt32 AppUnitsPerCSSPixel() { return nsIDeviceContext::AppUnitsPerCSSPixel(); }
   PRInt32 AppUnitsPerDevPixel() const  { return mDeviceContext->AppUnitsPerDevPixel(); }
-  PRInt32 AppUnitsPerInch() const      { return mDeviceContext->AppUnitsPerInch(); }
+  static PRInt32 AppUnitsPerCSSInch() { return nsIDeviceContext::AppUnitsPerCSSInch(); }
 
   static nscoord CSSPixelsToAppUnits(PRInt32 aPixels)
   { return NSIntPixelsToAppUnits(aPixels,
                                  nsIDeviceContext::AppUnitsPerCSSPixel()); }
 
   static nscoord CSSPixelsToAppUnits(float aPixels)
   { return NSFloatPixelsToAppUnits(aPixels,
              float(nsIDeviceContext::AppUnitsPerCSSPixel())); }
@@ -614,29 +614,29 @@ public:
   { return mDeviceContext->AppUnitsToGfxUnits(aAppUnits); }
 
   gfxRect AppUnitsToGfxUnits(const nsRect& aAppRect) const
   { return gfxRect(AppUnitsToGfxUnits(aAppRect.x),
                    AppUnitsToGfxUnits(aAppRect.y),
                    AppUnitsToGfxUnits(aAppRect.width),
                    AppUnitsToGfxUnits(aAppRect.height)); }
 
-  nscoord TwipsToAppUnits(PRInt32 aTwips) const
-  { return NSCoordSaturatingMultiply(mDeviceContext->AppUnitsPerInch(),
-                                     NS_TWIPS_TO_INCHES(aTwips)); }
+  static nscoord CSSTwipsToAppUnits(float aTwips)
+  { return NSToCoordRoundWithClamp(
+      nsIDeviceContext::AppUnitsPerCSSInch() * NS_TWIPS_TO_INCHES(aTwips)); }
 
   // Margin-specific version, since they often need TwipsToAppUnits
-  nsMargin TwipsToAppUnits(const nsIntMargin &marginInTwips) const
-  { return nsMargin(TwipsToAppUnits(marginInTwips.left), 
-                    TwipsToAppUnits(marginInTwips.top),
-                    TwipsToAppUnits(marginInTwips.right),
-                    TwipsToAppUnits(marginInTwips.bottom)); }
+  static nsMargin CSSTwipsToAppUnits(const nsIntMargin &marginInTwips)
+  { return nsMargin(CSSTwipsToAppUnits(marginInTwips.left), 
+                    CSSTwipsToAppUnits(marginInTwips.top),
+                    CSSTwipsToAppUnits(marginInTwips.right),
+                    CSSTwipsToAppUnits(marginInTwips.bottom)); }
 
-  nscoord PointsToAppUnits(float aPoints) const
-  { return NSToCoordRound(aPoints * mDeviceContext->AppUnitsPerInch() /
+  static nscoord CSSPointsToAppUnits(float aPoints)
+  { return NSToCoordRound(aPoints * nsIDeviceContext::AppUnitsPerCSSInch() /
                           POINTS_PER_INCH_FLOAT); }
 
   nscoord RoundAppUnitsToNearestDevPixels(nscoord aAppUnits) const
   { return DevPixelsToAppUnits(AppUnitsToDevPixels(aAppUnits)); }
 
   struct ScrollbarStyles {
     // Always one of NS_STYLE_OVERFLOW_SCROLL, NS_STYLE_OVERFLOW_HIDDEN,
     // or NS_STYLE_OVERFLOW_AUTO.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -232,16 +232,17 @@ static NS_DEFINE_IID(kRangeCID,     NS_R
 #include "nsIMemoryReporter.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 
 PRBool nsIPresShell::gIsAccessibilityActive = PR_FALSE;
 CapturingContentInfo nsIPresShell::gCaptureInfo;
+nsIContent* nsIPresShell::gKeyDownTarget;
 
 // convert a color value to a string, in the CSS format #RRGGBB
 // *  - initially created for bugs 31816, 20760, 22963
 static void ColorToString(nscolor aColor, nsAutoString &aString);
 
 // Class ID's
 static NS_DEFINE_CID(kFrameSelectionCID, NS_FRAMESELECTION_CID);
 
@@ -951,16 +952,18 @@ public:
 
   virtual nsresult AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder,
                                                  nsDisplayList& aList,
                                                  nsIFrame* aFrame,
                                                  const nsRect& aBounds);
 
   virtual nscolor ComputeBackstopColor(nsIView* aDisplayRoot);
 
+  virtual NS_HIDDEN_(nsresult) SetIsActive(PRBool aIsActive);
+
 protected:
   virtual ~PresShell();
 
   void HandlePostedReflowCallbacks(PRBool aInterruptible);
   void CancelPostedReflowCallbacks();
 
   void UnsuppressAndInvalidate();
 
@@ -1357,16 +1360,17 @@ public:
   }
 
   static PRInt64 SizeOfBidiMemoryReporter(void *) {
     return EstimateShellsMemory(LiveShellBidiSizeEnumerator);
   }
 
 protected:
   void QueryIsActive();
+  nsresult UpdateImageLockingState();
 };
 
 class nsAutoCauseReflowNotifier
 {
 public:
   nsAutoCauseReflowNotifier(PresShell* aShell)
     : mShell(aShell)
   {
@@ -1591,16 +1595,17 @@ PresShell::PresShell()
 #endif
 #ifdef PR_LOGGING
   if (! gLog)
     gLog = PR_NewLogModule("PresShell");
 #endif
   mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
   mIsThemeSupportDisabled = PR_FALSE;
   mIsActive = PR_TRUE;
+  mFrozen = PR_FALSE;
 #ifdef DEBUG
   mPresArenaAllocCount = 0;
 #endif
 
   static bool registeredReporter = false;
   if (!registeredReporter) {
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutPresShell));
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutBidi));
@@ -1833,16 +1838,20 @@ PresShell::Destroy()
     if (accService) {
       accService->PresShellDestroyed(this);
     }
   }
 #endif // ACCESSIBILITY
 
   MaybeReleaseCapturingContent();
 
+  if (gKeyDownTarget && gKeyDownTarget->GetOwnerDoc() == mDocument) {
+    NS_RELEASE(gKeyDownTarget);
+  }
+
   mContentToScrollTo = nsnull;
 
   if (mPresContext) {
     // We need to notify the destroying the nsPresContext to ESM for
     // suppressing to use from ESM.
     mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);
   }
 
@@ -6455,16 +6464,40 @@ PresShell::HandleEvent(nsIView         *
                                              getter_AddRefs(focusedWindow));
 
       // otherwise, if there is no focused content or the focused content has
       // no frame, just use the root content. This ensures that key events
       // still get sent to the window properly if nothing is focused or if a
       // frame goes away while it is focused.
       if (!mCurrentEventContent || !GetCurrentEventFrame())
         mCurrentEventContent = mDocument->GetRootElement();
+
+      if (aEvent->message == NS_KEY_DOWN) {
+        NS_IF_RELEASE(gKeyDownTarget);
+        NS_IF_ADDREF(gKeyDownTarget = mCurrentEventContent);
+      }
+      else if ((aEvent->message == NS_KEY_PRESS || aEvent->message == NS_KEY_UP) &&
+               gKeyDownTarget) {
+        // If a different element is now focused for the keypress/keyup event
+        // than what was focused during the keydown event, check if the new
+        // focused element is not in a chrome document any more, and if so,
+        // retarget the event back at the keydown target. This prevents a
+        // content area from grabbing the focus from chrome in-between key
+        // events.
+        if (mCurrentEventContent &&
+            nsContentUtils::IsChromeDoc(gKeyDownTarget->GetCurrentDoc()) &&
+            !nsContentUtils::IsChromeDoc(mCurrentEventContent->GetCurrentDoc())) {
+          mCurrentEventContent = gKeyDownTarget;
+        }
+
+        if (aEvent->message == NS_KEY_UP) {
+          NS_RELEASE(gKeyDownTarget);
+        }
+      }
+
       mCurrentEventFrame = nsnull;
         
       if (!mCurrentEventContent || !GetCurrentEventFrame() ||
           InZombieDocument(mCurrentEventContent)) {
         rv = RetargetEventToParent(aEvent, aEventStatus);
         PopCurrentEventInfo();
         return rv;
       }
@@ -7268,16 +7301,19 @@ PresShell::Freeze()
   if (mDocument)
     mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull);
 
   nsPresContext* presContext = GetPresContext();
   if (presContext &&
       presContext->RefreshDriver()->PresContext() == presContext) {
     presContext->RefreshDriver()->Freeze();
   }
+
+  mFrozen = PR_TRUE;
+  UpdateImageLockingState();
 }
 
 void
 PresShell::FireOrClearDelayedEvents(PRBool aFireEvents)
 {
   mNoDelayedMouseEvents = PR_FALSE;
   mNoDelayedKeyEvents = PR_FALSE;
   if (!aFireEvents) {
@@ -7333,16 +7369,20 @@ PresShell::Thaw()
   if (mDocument)
     mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
 
   UnsuppressPainting();
 
   // Get the activeness of our presshell, as this might have changed
   // while we were in the bfcache
   QueryIsActive();
+
+  // We're now unfrozen
+  mFrozen = PR_FALSE;
+  UpdateImageLockingState();
 }
 
 //--------------------------------------------------------
 // Start of protected and private methods on the PresShell
 //--------------------------------------------------------
 
 void
 PresShell::MaybeScheduleReflow()
@@ -8969,8 +9009,26 @@ void PresShell::QueryIsActive()
   nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container));
   if (docshell) {
     PRBool isActive;
     nsresult rv = docshell->GetIsActive(&isActive);
     if (NS_SUCCEEDED(rv))
       SetIsActive(isActive);
   }
 }
+
+nsresult
+PresShell::SetIsActive(PRBool aIsActive)
+{
+  mIsActive = aIsActive;
+  return UpdateImageLockingState();
+}
+
+/*
+ * Determines the current image locking state. Called when one of the
+ * dependent factors changes.
+ */
+nsresult
+PresShell::UpdateImageLockingState()
+{
+  // We're locked if we're both thawed and active.
+  return mDocument->SetImageLockingState(!mFrozen && mIsActive);
+}
--- a/layout/base/tests/chrome/Makefile.in
+++ b/layout/base/tests/chrome/Makefile.in
@@ -44,16 +44,18 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _CHROME_FILES = \
 	test_bug396367-1.html \
 	test_bug396367-2.html \
 	test_bug504311.xul \
 	test_bug514660.xul \
 	test_bug533845.xul \
+	test_bug551434.html \
+	bug551434_childframe.html \
 	test_chrome_content_integration.xul \
 	     chrome_content_integration_window.xul \
 	test_printpreview.xul \
 	     printpreview_helper.xul \
 	test_printpreview_bug396024.xul \
 	     printpreview_bug396024_helper.xul \
 	test_printpreview_bug482976.xul \
 	     printpreview_bug482976_helper.xul \
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/chrome/bug551434_childframe.html
@@ -0,0 +1,1 @@
+<input id='i4'>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/chrome/test_bug551434.html
@@ -0,0 +1,79 @@
+<html>
+<head>
+  <title>Test for Bug 551434</title>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+</div>
+<pre id="test">
+<input id="i1" onkeydown="gKeyDown1++; $('i2').focus();" onkeypress="gKeyPress1++;" onkeyup="gKeyUp1++;"/>
+<input id="i2" onkeydown="gKeyDown2++;" onkeypress="gKeyPress2++;" onkeyup="gKeyUp2++;"/>
+
+<input id="i3" onkeydown="gKeyDown3++; frames[0].document.getElementById('i4').focus();"
+       onkeypress="gKeyPress3++;" onkeyup="gKeyUp3++;"/>
+<iframe id="iframe" src="http://example.org/chrome/layout/base/test/chrome/bug551434_childframe.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var gKeyDown1 = 0, gKeyPress1 = 0, gKeyUp1 = 0;
+var gKeyDown2 = 0, gKeyPress2 = 0, gKeyUp2 = 0;
+var gKeyDown3 = 0, gKeyPress3 = 0, gKeyUp3 = 0;
+
+function runTest()
+{
+  $("i1").focus();
+
+  // key events should not be retargeted when the focus changes to an
+  // element in the same document.
+  synthesizeKey("a", { type: "keydown" });
+  is(document.activeElement, $("i2"), "input 2 in focused");
+
+  synthesizeKey("a", { type: "keypress" });
+  synthesizeKey("a", { type: "keyup" });
+
+  is(gKeyDown1, 1, "keydown on input 1");
+  is(gKeyPress1, 0, "keypress on input 1");
+  is(gKeyUp1, 0, "keyup on input 1");
+  is(gKeyDown2, 0, "keydown on input 2");
+  is(gKeyPress2, 1, "keypress on input 2");
+  is(gKeyUp2, 1, "keyup on input 2");
+
+  is($("i1").value, "", "input 1 value");
+  is($("i2").value, "a", "input 2 value");
+
+  // key events should however be retargeted when the focus changes to an
+  // element in the a content document from a chrome document.
+  $("i3").focus();
+
+  synthesizeKey("b", { type: "keydown" });
+  synthesizeKey("b", { type: "keypress" });
+  synthesizeKey("b", { type: "keyup" });
+  is(gKeyDown3, 1, "keydown on input 3");
+  is(gKeyPress3, 1, "keypress on input 3");
+  is(gKeyUp3, 1, "keyup on input 3");
+
+  var i4 = frames[0].document.getElementById("i4");
+  is($("i3").value, "b", "input 3 value");
+  is(i4.value, "", "input 4 value");
+
+  is(document.activeElement, $("iframe"), "parent focus");
+  is(frames[0].document.activeElement, i4, "child focus");
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -6235,20 +6235,20 @@ void nsFrame::FillCursorInformationFromS
   aCursor.mCursor = ui->mCursor;
   aCursor.mHaveHotspot = PR_FALSE;
   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
 
   for (nsCursorImage *item = ui->mCursorArray,
                  *item_end = ui->mCursorArray + ui->mCursorArrayLength;
        item < item_end; ++item) {
     PRUint32 status;
-    nsresult rv = item->mImage->GetImageStatus(&status);
+    nsresult rv = item->GetImage()->GetImageStatus(&status);
     if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) {
       // This is the one we want
-      item->mImage->GetImage(getter_AddRefs(aCursor.mContainer));
+      item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
       aCursor.mHaveHotspot = item->mHaveHotspot;
       aCursor.mHotspotX = item->mHotspotX;
       aCursor.mHotspotY = item->mHotspotY;
       break;
     }
   }
 }
 
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -41,38 +41,38 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* rendering objects for replaced elements implemented by a plugin */
 
+#ifdef MOZ_WIDGET_QT
+#include <QWidget>
+#include <QKeyEvent>
+#ifdef MOZ_X11
+#include <QX11Info>
+#endif
+#endif
+
 #ifdef MOZ_IPC
 #include "mozilla/plugins/PluginMessageUtils.h"
 #endif
 
 #ifdef MOZ_X11
 #include <cairo-xlib.h>
 #include "gfxXlibSurface.h"
 /* X headers suck */
 enum { XKeyPress = KeyPress };
 #ifdef KeyPress
 #undef KeyPress
 #endif
 #endif
 
-#ifdef MOZ_WIDGET_QT
-#include <QWidget>
-#include <QKeyEvent>
-#ifdef MOZ_X11
-#include <QX11Info>
-#endif
-#endif
-
 #include "nscore.h"
 #include "nsCOMPtr.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsWidgetsCID.h"
 #include "nsIView.h"
 #include "nsIViewManager.h"
 #include "nsIDOMKeyListener.h"
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -113,23 +113,23 @@ NS_NewSimplePageSequenceFrame(nsIPresShe
 NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame)
 
 nsSimplePageSequenceFrame::nsSimplePageSequenceFrame(nsStyleContext* aContext) :
   nsContainerFrame(aContext),
   mTotalPages(-1),
   mSelectionHeight(-1),
   mYSelOffset(0)
 {
-  nscoord halfInch = PresContext()->TwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
+  nscoord halfInch = PresContext()->CSSTwipsToAppUnits(NS_INCHES_TO_TWIPS(0.5));
   mMargin.SizeTo(halfInch, halfInch, halfInch, halfInch);
 
   // XXX Unsafe to assume successful allocation
   mPageData = new nsSharedPageData();
   mPageData->mHeadFootFont = new nsFont(*PresContext()->GetDefaultFont(kGenericFont_serif));
-  mPageData->mHeadFootFont->size = PresContext()->PointsToAppUnits(10);
+  mPageData->mHeadFootFont->size = nsPresContext::CSSPointsToAppUnits(10);
 
   nsresult rv;
   mPageData->mPrintOptions = do_GetService(sPrintOptionsContractID, &rv);
 
   // Doing this here so we only have to go get these formats once
   SetPageNumberFormat("pagenumber",  "%1$d", PR_TRUE);
   SetPageNumberFormat("pageofpages", "%1$d of %2$d", PR_FALSE);
 }
@@ -185,34 +185,34 @@ nsSimplePageSequenceFrame::Reflow(nsPres
     nsIntMargin unwriteableTwips;
     mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips);
     NS_ASSERTION(unwriteableTwips.left  >= 0 && unwriteableTwips.top >= 0 &&
                  unwriteableTwips.right >= 0 && unwriteableTwips.bottom >= 0,
                  "Unwriteable twips should be non-negative");
 
     nsIntMargin marginTwips;
     mPageData->mPrintSettings->GetMarginInTwips(marginTwips);
-    mMargin = aPresContext->TwipsToAppUnits(marginTwips + unwriteableTwips);
+    mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips);
 
     PRInt16 printType;
     mPageData->mPrintSettings->GetPrintRange(&printType);
     mPrintRangeType = printType;
 
     nsIntMargin edgeTwips;
     mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips);
 
     // sanity check the values. three inches are sometimes needed
-    PRInt32 inchInTwips = NS_INCHES_TO_TWIPS(3.0);
+    PRInt32 inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0);
     edgeTwips.top = NS_MIN(NS_MAX(edgeTwips.top, 0), inchInTwips);
     edgeTwips.bottom = NS_MIN(NS_MAX(edgeTwips.bottom, 0), inchInTwips);
     edgeTwips.left = NS_MIN(NS_MAX(edgeTwips.left, 0), inchInTwips);
     edgeTwips.right = NS_MIN(NS_MAX(edgeTwips.right, 0), inchInTwips);
 
     mPageData->mEdgePaperMargin =
-      aPresContext->TwipsToAppUnits(edgeTwips + unwriteableTwips);
+      aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips);
   }
 
   // *** Special Override ***
   // If this is a sub-sdoc (meaning it doesn't take the whole page)
   // and if this Document is in the upper left hand corner
   // we need to suppress the top margin or it will reflow too small
 
   nsSize pageSize = aPresContext->GetPageSize();
@@ -227,23 +227,23 @@ nsSimplePageSequenceFrame::Reflow(nsPres
   mPageData->mReflowMargin = mMargin;
 
   // Compute the size of each page and the x coordinate that each page will
   // be placed at
   nscoord extraThreshold = NS_MAX(pageSize.width, pageSize.height)/10;
   PRInt32 gapInTwips = nsContentUtils::GetIntPref("print.print_extra_margin");
   gapInTwips = NS_MAX(0, gapInTwips);
 
-  nscoord extraGap = aPresContext->TwipsToAppUnits(gapInTwips);
+  nscoord extraGap = aPresContext->CSSTwipsToAppUnits(gapInTwips);
   extraGap = NS_MIN(extraGap, extraThreshold); // clamp to 1/10 of the largest dim of the page
 
   nscoord  deadSpaceGap = 0;
   if (isPrintPreview) {
     GetDeadSpaceValue(&gapInTwips);
-    deadSpaceGap = aPresContext->TwipsToAppUnits(gapInTwips);
+    deadSpaceGap = aPresContext->CSSTwipsToAppUnits(gapInTwips);
   }
 
   nsMargin extraMargin(0,0,0,0);
   nsSize   shadowSize(0,0);
   if (aPresContext->IsScreen()) {
     extraMargin.SizeTo(extraGap, extraGap, extraGap, extraGap);
     nscoord fourPixels = nsPresContext::CSSPixelsToAppUnits(4);
     shadowSize.SizeTo(fourPixels, fourPixels);
@@ -613,17 +613,17 @@ nsSimplePageSequenceFrame::PrintNextPage
 
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
       // On linux, need to rotate landscape-mode output on printed surfaces
       PRInt32 orientation;
       mPageData->mPrintSettings->GetOrientation(&orientation);
       if (nsIPrintSettings::kLandscapeOrientation == orientation) {
         // Shift up by one landscape-page-height (in points) before we rotate.
         float offset = POINTS_PER_INCH_FLOAT *
-           (mCurrentPageFrame->GetSize().height / float(dc->AppUnitsPerInch()));
+           (mCurrentPageFrame->GetSize().height / float(dc->AppUnitsPerCSSInch()));
         renderingContext->ThebesContext()->Translate(gfxPoint(offset, 0));
         renderingContext->ThebesContext()->Rotate(M_PI/2);
       }
 #endif // XP_UNIX && !XP_MACOSX
 
       nsRect drawingRect(nsPoint(0, 0),
                          mCurrentPageFrame->GetSize());
       nsRegion drawingRegion(drawingRect);
--- a/layout/generic/nsSimplePageSequence.h
+++ b/layout/generic/nsSimplePageSequence.h
@@ -98,17 +98,17 @@ public:
                                const nsDisplayListSet& aLists);
 
   // nsIPageSequenceFrame
   NS_IMETHOD SetPageNo(PRInt32 aPageNo) { return NS_OK;}
   NS_IMETHOD SetSelectionHeight(nscoord aYOffset, nscoord aHeight) { mYSelOffset = aYOffset; mSelectionHeight = aHeight; return NS_OK; }
   NS_IMETHOD SetTotalNumPages(PRInt32 aTotal) { mTotalPages = aTotal; return NS_OK; }
 
   // Gets the dead space (the gray area) around the Print Preview Page
-  NS_IMETHOD GetDeadSpaceValue(nscoord* aValue) { *aValue = NS_INCHES_TO_TWIPS(0.25); return NS_OK; }
+  NS_IMETHOD GetDeadSpaceValue(nscoord* aValue) { *aValue = NS_INCHES_TO_INT_TWIPS(0.25); return NS_OK; }
   
   // For Shrink To Fit
   NS_IMETHOD GetSTFPercent(float& aSTFPercent);
 
   // Async Printing
   NS_IMETHOD StartPrint(nsPresContext*  aPresContext,
                         nsIPrintSettings* aPrintSettings,
                         PRUnichar*        aDocTitle,
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -992,17 +992,17 @@ IsSizeOK(nsPresContext* aPresContext, ns
     && PRBool(float(PR_ABS(a - b))
               < (1.0f - NS_MATHML_DELIMITER_FACTOR) * float(b));
   // Nearer: True if 'a' is around max{ +/-10% of 'b' , 'b' - 5pt },
   // as documented in The TeXbook, Ch.17, p.152.
   // i.e. within 10% and within 5pt
   PRBool isNearer = PR_FALSE;
   if (aHint & (NS_STRETCH_NEARER | NS_STRETCH_LARGEOP)) {
     float c = NS_MAX(float(b) * NS_MATHML_DELIMITER_FACTOR,
-                     float(b) - aPresContext->PointsToAppUnits(NS_MATHML_DELIMITER_SHORTFALL_POINTS));
+                     float(b) - nsPresContext::CSSPointsToAppUnits(NS_MATHML_DELIMITER_SHORTFALL_POINTS));
     isNearer = PRBool(float(PR_ABS(b - a)) <= (float(b) - c));
   }
   // Smaller: Mainly for transitory use, to compare two candidate
   // choices
   PRBool isSmaller =
     (aHint & NS_STRETCH_SMALLER)
     && PRBool((float(a) >= (NS_MATHML_DELIMITER_FACTOR * float(b)))
               && (a <= b));
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -343,36 +343,38 @@ nsMathMLFrame::GetAxisHeight(nsIRenderin
 /* static */ nscoord
 nsMathMLFrame::CalcLength(nsPresContext*   aPresContext,
                           nsStyleContext*   aStyleContext,
                           const nsCSSValue& aCSSValue)
 {
   NS_ASSERTION(aCSSValue.IsLengthUnit(), "not a length unit");
 
   if (aCSSValue.IsFixedLengthUnit()) {
-    return aPresContext->TwipsToAppUnits(aCSSValue.GetLengthTwips());
+    return aCSSValue.GetFixedLength(aPresContext);
+  }
+  if (aCSSValue.IsPixelLengthUnit()) {
+    return aCSSValue.GetPixelLength();
   }
 
   nsCSSUnit unit = aCSSValue.GetUnit();
 
-  if (eCSSUnit_Pixel == unit) {
-    return nsPresContext::CSSPixelsToAppUnits(aCSSValue.GetFloatValue());
-  }
-  else if (eCSSUnit_EM == unit) {
+  if (eCSSUnit_EM == unit) {
     const nsStyleFont* font = aStyleContext->GetStyleFont();
     return NSToCoordRound(aCSSValue.GetFloatValue() * (float)font->mFont.size);
   }
   else if (eCSSUnit_XHeight == unit) {
     nscoord xHeight;
     const nsStyleFont* font = aStyleContext->GetStyleFont();
     nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font->mFont);
     fm->GetXHeight(xHeight);
     return NSToCoordRound(aCSSValue.GetFloatValue() * (float)xHeight);
   }
 
+  // MathML doesn't specify other CSS units such as rem or ch
+  NS_ERROR("Unsupported unit");
   return 0;
 }
 
 /* static */ PRBool
 nsMathMLFrame::ParseNamedSpaceValue(nsIFrame*   aMathMLmstyleFrame,
                                     nsString&   aString,
                                     nsCSSValue& aCSSValue)
 {
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -170,17 +170,17 @@ nsMathMLmmultiscriptsFrame::Place(nsIRen
   fm->GetXHeight (xHeight);
 
   nscoord ruleSize;
   GetRuleThickness (aRenderingContext, fm, ruleSize);
 
   // scriptspace from TeX for extra spacing after sup/subscript (0.5pt in plain TeX)
   // forced to be at least 1 pixel here
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
-  nscoord scriptSpace = NS_MAX(PresContext()->PointsToAppUnits(0.5f), onePixel);
+  nscoord scriptSpace = NS_MAX(nsPresContext::CSSPointsToAppUnits(0.5f), onePixel);
 
   /////////////////////////////////////
   // first the shift for the subscript
 
   // subScriptShift{1,2}
   // = minimum amount to shift the subscript down
   // = sub{1,2} in TeXbook
   // subScriptShift1 = subscriptshift attribute * x-height
--- a/layout/mathml/nsMathMLmoverFrame.cpp
+++ b/layout/mathml/nsMathMLmoverFrame.cpp
@@ -252,17 +252,17 @@ nsMathMLmoverFrame::Place(nsIRenderingCo
 { 
   if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
       !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
     // place like superscript
     return nsMathMLmsupFrame::PlaceSuperScript(PresContext(),
                                                aRenderingContext,
                                                aPlaceOrigin,
                                                aDesiredSize,
-                                               this, 0, PresContext()->PointsToAppUnits(0.5f));
+                                               this, 0, nsPresContext::CSSPointsToAppUnits(0.5f));
   }
 
   ////////////////////////////////////
   // Get the children's desired sizes
 
   nsBoundingMetrics bmBase, bmOver;
   nsHTMLReflowMetrics baseSize;
   nsHTMLReflowMetrics overSize;
--- a/layout/mathml/nsMathMLmsubFrame.cpp
+++ b/layout/mathml/nsMathMLmsubFrame.cpp
@@ -84,17 +84,17 @@ nsMathMLmsubFrame::TransmitAutomaticData
 }
 
 /* virtual */ nsresult
 nsMathMLmsubFrame::Place (nsIRenderingContext& aRenderingContext,
                           PRBool               aPlaceOrigin,
                           nsHTMLReflowMetrics& aDesiredSize)
 {
   // extra spacing after sup/subscript
-  nscoord scriptSpace = PresContext()->PointsToAppUnits(0.5f); // 0.5pt as in plain TeX
+  nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); // 0.5pt as in plain TeX
 
   // check if the subscriptshift attribute is there
   nscoord subScriptShift = 0;
   nsAutoString value;
   GetAttribute(mContent, mPresentationData.mstyle,
                nsGkAtoms::subscriptshift_, value);
   if (!value.IsEmpty()) {
     nsCSSValue cssValue;
--- a/layout/mathml/nsMathMLmsupFrame.cpp
+++ b/layout/mathml/nsMathMLmsupFrame.cpp
@@ -84,17 +84,17 @@ nsMathMLmsupFrame::TransmitAutomaticData
 }
 
 /* virtual */ nsresult
 nsMathMLmsupFrame::Place(nsIRenderingContext& aRenderingContext,
                          PRBool               aPlaceOrigin,
                          nsHTMLReflowMetrics& aDesiredSize)
 {
   // extra spacing after sup/subscript
-  nscoord scriptSpace = PresContext()->PointsToAppUnits(0.5f); // 0.5pt as in plain TeX
+  nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); // 0.5pt as in plain TeX
 
   // check if the superscriptshift attribute is there
   nsAutoString value;
   nscoord supScriptShift = 0;
   GetAttribute(mContent, mPresentationData.mstyle,
                nsGkAtoms::superscriptshift_, value);
   if (!value.IsEmpty()) {
     nsCSSValue cssValue;
--- a/layout/mathml/nsMathMLmunderFrame.cpp
+++ b/layout/mathml/nsMathMLmunderFrame.cpp
@@ -249,17 +249,17 @@ nsMathMLmunderFrame::Place(nsIRenderingC
 {
   if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
       !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
     // place like subscript
     return nsMathMLmsubFrame::PlaceSubScript(PresContext(),
                                              aRenderingContext,
                                              aPlaceOrigin,
                                              aDesiredSize,
-                                             this, 0, PresContext()->PointsToAppUnits(0.5f));
+                                             this, 0, nsPresContext::CSSPointsToAppUnits(0.5f));
   }
 
   ////////////////////////////////////
   // Get the children's desired sizes
 
   nsBoundingMetrics bmBase, bmUnder;
   nsHTMLReflowMetrics baseSize;
   nsHTMLReflowMetrics underSize;
--- a/layout/mathml/nsMathMLmunderoverFrame.cpp
+++ b/layout/mathml/nsMathMLmunderoverFrame.cpp
@@ -285,17 +285,18 @@ nsMathMLmunderoverFrame::Place(nsIRender
 {
   if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
       !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
     // place like sub-superscript pair
     return nsMathMLmsubsupFrame::PlaceSubSupScript(PresContext(),
                                                    aRenderingContext,
                                                    aPlaceOrigin,
                                                    aDesiredSize,
-                                                   this, 0, 0, PresContext()->PointsToAppUnits(0.5f));
+                                                   this, 0, 0,
+                                                   nsPresContext::CSSPointsToAppUnits(0.5f));
   }
 
   ////////////////////////////////////
   // Get the children's desired sizes
 
   nsBoundingMetrics bmBase, bmUnder, bmOver;
   nsHTMLReflowMetrics baseSize;
   nsHTMLReflowMetrics underSize;
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2016,17 +2016,17 @@ nsPrintEngine::ReflowPrintObject(nsPrint
   aPO->mPresContext->SetContainer(supps);
 
   aPO->mPresShell->BeginObservingDocument();
 
   aPO->mPresContext->SetPageSize(adjSize);
   aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
   aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
   // Calculate scale factor from printer to screen
-  float printDPI = float(mPrt->mPrintDC->AppUnitsPerInch()) /
+  float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
                    float(mPrt->mPrintDC->AppUnitsPerDevPixel());
   aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
 
   if (mIsCreatingPrintPreview && documentIsTopLevel) {
     mDocViewerPrint->SetPrintPreviewPresentation(aPO->mWindow,
                                                  aPO->mViewManager,
                                                  aPO->mPresContext,
                                                  aPO->mPresShell);
@@ -2353,18 +2353,18 @@ nsPrintEngine::DoPrint(nsPrintObject * a
                                         &endFrame, endPageNum, endRect);
           if (NS_SUCCEEDED(rv)) {
             mPrt->mPrintSettings->SetStartPageRange(startPageNum);
             mPrt->mPrintSettings->SetEndPageRange(endPageNum);
             nsIntMargin marginTwips(0,0,0,0);
             nsIntMargin unwrtMarginTwips(0,0,0,0);
             mPrt->mPrintSettings->GetMarginInTwips(marginTwips);
             mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips);
-            nsMargin totalMargin = poPresContext->TwipsToAppUnits(marginTwips + 
-                                                              unwrtMarginTwips);
+            nsMargin totalMargin = poPresContext->CSSTwipsToAppUnits(marginTwips + 
+                                                                     unwrtMarginTwips);
             if (startPageNum == endPageNum) {
               {
                 startRect.y -= totalMargin.top;
                 endRect.y   -= totalMargin.top;
 
                 // Clip out selection regions above the top of the first page
                 if (startRect.y < 0) {
                   // Reduce height to be the height of the positive-territory
--- a/layout/reftests/svg/smil/anim-discrete-to-1.svg
+++ b/layout/reftests/svg/smil/anim-discrete-to-1.svg
@@ -1,10 +1,10 @@
 <svg xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      class="reftest-wait"
      onload="setTimeAndSnapshot(0.0, true)">
   <script xlink:href="smil-util.js" type="text/javascript"/>
-  <rect x="15" y="15" width="200" height="200" fill="blue">
+  <rect x="15" y="15" width="200" height="100" fill="blue">
     <animate attributeName="height" calcMode="discrete"
-             to="100" dur="2s"/>
+             to="200" dur="2s"/>
   </rect>
 </svg>
--- a/layout/reftests/svg/smil/anim-discrete-to-2.svg
+++ b/layout/reftests/svg/smil/anim-discrete-to-2.svg
@@ -1,10 +1,10 @@
 <svg xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      class="reftest-wait"
      onload="setTimeAndSnapshot(0.99, true)">
   <script xlink:href="smil-util.js" type="text/javascript"/>
-  <rect x="15" y="15" width="200" height="200" fill="blue">
+  <rect x="15" y="15" width="200" height="100" fill="blue">
     <animate attributeName="height" calcMode="discrete"
-             to="100" dur="2s"/>
+             to="200" dur="2s"/>
   </rect>
 </svg>
--- a/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg
+++ b/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg
@@ -160,54 +160,58 @@
   <!-- Some calcMode="discrete" tests animating *up* to higer values. -->
 
   <!-- At 5s the animated value should be 1. -->
   <filter id="filter_9" x="0%" y="0%" width="100%" height="100%">
     <feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
       <animate attributeName="numOctaves"
                calcMode="discrete"
                begin="0s" dur="10.1s"
+               from="1"
                to="4"
                fill="freeze"/>
     </feTurbulence>
   </filter>
   <rect x="0" y="80" width="20" height="20" filter="url(#filter_9)"/>
 
   <!-- At exactly 5s the animated value should change to 4. -->
   <filter id="filter_10" x="0%" y="0%" width="100%" height="100%">
     <feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
       <animate attributeName="numOctaves"
                calcMode="discrete"
                begin="0s" dur="10s"
+               from="1"
                to="4"
                fill="freeze"/>
     </feTurbulence>
   </filter>
   <rect x="20" y="80" width="20" height="20" filter="url(#filter_10)"/>
 
 
   <!-- Some calcMode="discrete" tests animating *down* to lower values. -->
 
   <!-- At 5s the animated value should be 4. -->
   <filter id="filter_11" x="0%" y="0%" width="100%" height="100%">
     <feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
       <animate attributeName="numOctaves"
                calcMode="discrete"
                begin="0s" dur="10.1s"
+               from="4"
                to="1"
                fill="freeze"/>
     </feTurbulence>
   </filter>
   <rect x="0" y="100" width="20" height="20" filter="url(#filter_11)"/>
 
   <!-- At exactly 5s the animated value should change to 1. -->
   <filter id="filter_12" x="0%" y="0%" width="100%" height="100%">
     <feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
       <animate attributeName="numOctaves"
                calcMode="discrete"
                begin="0s" dur="10s"
+               from="4"
                to="1"
                fill="freeze"/>
     </feTurbulence>
   </filter>
   <rect x="20" y="100" width="20" height="20" filter="url(#filter_12)"/>
 
 </svg>
--- a/layout/reftests/svg/smil/anim-svg-preserveAspectRatio-01.svg
+++ b/layout/reftests/svg/smil/anim-svg-preserveAspectRatio-01.svg
@@ -10,29 +10,31 @@
        tests that the animation doesn't affect the element too early -->
   <svg width="100" height="50" viewBox="0 0 100 100"
        preserveAspectRatio="xMidYMid meet">
     <!-- this should change the referencing element at 1.25s,
          causing the red rect to stretch to fill its whole viewport -->
     <animate attributeName="preserveAspectRatio"
              calcMode="discrete"
              begin="0s" dur="2.5s"
+             from="xMidYMid meet"
              to="xMidYMid slice"
              fill="freeze"/>
     <rect width="100%" height="100%" fill="red"/>
   </svg>
   <rect x="25" width="50" height="50" fill="lime"/>
 
   <!-- 50% through animation simple duration -
        tests that the animation affects the element now -->
   <rect y="50" width="100" height="50" fill="red"/>
   <svg y="50" width="100" height="50" viewBox="0 0 100 100"
        preserveAspectRatio="xMidYMid meet">
     <!-- this should change the referencing element at 1s,
          causing the lime rect to stretch to fill its whole viewport -->
     <animate attributeName="preserveAspectRatio"
              calcMode="discrete"
              begin="0s" dur="2s"
+             from="xMidYMid meet"
              to="xMidYMid slice"
              fill="freeze"/>
     <rect width="100%" height="100%" fill="lime"/>
   </svg>
 </svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/event/event-begin-1.svg
@@ -0,0 +1,16 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="
+        document.documentElement.pauseAnimations();
+        document.documentElement.setCurrentTime(0);
+        click('circle');
+        delayedSnapshot(2)">
+  <script xlink:href="event-util.js" type="text/javascript"/>
+  <circle id="circle" r="10"/>
+  <rect width="100" height="100" fill="red">
+    <set attributeName="fill" attributeType="CSS"
+      to="green"
+      begin="circle.click" dur="4s"/>
+  </rect>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/event/event-begin-load-1.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait" id="svg"
+     onload="
+        document.documentElement.pauseAnimations();
+        document.documentElement.setCurrentTime(0);
+        delayedSnapshot(2)">
+  <script xlink:href="event-util.js" type="text/javascript"/>
+  <rect width="100" height="100" fill="red">
+    <set attributeName="fill" attributeType="CSS"
+      to="green"
+      begin="svg.SVGLoad" dur="4s"/>
+  </rect>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/event/event-begin-offset-1.svg
@@ -0,0 +1,16 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="
+        document.documentElement.pauseAnimations();
+        document.documentElement.setCurrentTime(0);
+        click('circle');
+        delayedSnapshot(6)">
+  <script xlink:href="event-util.js" type="text/javascript"/>
+  <circle id="circle" r="10"/>
+  <rect width="100" height="100" fill="red">
+    <set attributeName="fill" attributeType="CSS"
+      to="green"
+      begin="circle.click+4s" dur="4s"/>
+  </rect>