Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <emorley@mozilla.com>
Thu, 19 Jul 2012 13:25:37 +0100
changeset 102873 e1dcf7c892d1cc076baaa647b485d3f0e7b95255
parent 102767 6d5150ee06ce3b9c88e65c546c93e922d10f5ccb (current diff)
parent 102872 614017b8bd95732c891db13501044908fe07e19a (diff)
child 102879 01929e390ba54dfd34fec8514abaa6e20c37ee2a
child 102898 f08c782d011269ce64779e8fb9e03ea269a97da4
push idunknown
push userunknown
push dateunknown
milestone17.0a1
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
build/mobile/robocop/robotium-solo-3.2.1.jar
content/base/public/nsIDocument.h
dom/base/nsDOMClassInfo.cpp
js/src/jshash.cpp
js/src/jshash.h
--- a/accessible/src/base/nsAccessiblePivot.h
+++ b/accessible/src/base/nsAccessiblePivot.h
@@ -7,28 +7,29 @@
 #ifndef _nsAccessiblePivot_H_
 #define _nsAccessiblePivot_H_
 
 #include "nsIAccessiblePivot.h"
 
 #include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsCycleCollectionParticipant.h"
+#include "mozilla/Attributes.h"
 
 class Accessible;
 class nsIAccessibleTraversalRule;
 
 // raised when current pivot's position is needed but it is not in the tree.
 #define NS_ERROR_NOT_IN_TREE \
 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 0x26)
 
 /**
  * Class represents an accessible pivot.
  */
-class nsAccessiblePivot: public nsIAccessiblePivot
+class nsAccessiblePivot MOZ_FINAL : public nsIAccessiblePivot
 {
 public:
   nsAccessiblePivot(Accessible* aRoot);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsAccessiblePivot, nsIAccessiblePivot)
 
   NS_DECL_NSIACCESSIBLEPIVOT
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -913,16 +913,17 @@ class KeyBinding
 public:
   /**
    * Modifier mask values.
    */
   static const PRUint32 kShift = 1;
   static const PRUint32 kControl = 2;
   static const PRUint32 kAlt = 4;
   static const PRUint32 kMeta = 8;
+  static const PRUint32 kOS = 16;
 
   KeyBinding() : mKey(0), mModifierMask(0) {}
   KeyBinding(PRUint32 aKey, PRUint32 aModifierMask) :
     mKey(aKey), mModifierMask(aModifierMask) {};
 
   inline bool IsEmpty() const { return !mKey; }
   inline PRUint32 Key() const { return mKey; }
   inline PRUint32 ModifierMask() const { return mModifierMask; }
--- a/accessible/src/html/HTMLTableAccessible.cpp
+++ b/accessible/src/html/HTMLTableAccessible.cpp
@@ -761,17 +761,17 @@ HTMLTableAccessible::ColExtentAt(PRUint3
   if (!tableLayout)
     return 0;
 
   nsCOMPtr<nsIDOMElement> domElement;
   PRInt32 startRowIndex, startColIndex, rowSpan, colSpan, actualRowSpan;
   bool isSelected;
   PRInt32 columnExtent = 0;
 
-  nsresult rv = tableLayout->
+  tableLayout->
     GetCellDataAt(aRowIdx, aColIdx, *getter_AddRefs(domElement),
                   startRowIndex, startColIndex, rowSpan, colSpan,
                   actualRowSpan, columnExtent, isSelected);
 
   return columnExtent;
 }
 
 PRUint32
@@ -781,17 +781,17 @@ HTMLTableAccessible::RowExtentAt(PRUint3
   if (!tableLayout)
     return 0;
 
   nsCOMPtr<nsIDOMElement> domElement;
   PRInt32 startRowIndex, startColIndex, rowSpan, colSpan, actualColSpan;
   bool isSelected;
   PRInt32 rowExtent = 0;
 
-  nsresult rv = tableLayout->
+  tableLayout->
     GetCellDataAt(aRowIdx, aColIdx, *getter_AddRefs(domElement),
                   startRowIndex, startColIndex, rowSpan, colSpan,
                   rowExtent, actualColSpan, isSelected);
 
   return rowExtent;
 }
 
 bool
--- a/accessible/src/xul/XULMenuAccessible.cpp
+++ b/accessible/src/xul/XULMenuAccessible.cpp
@@ -179,16 +179,19 @@ XULMenuitemAccessible::AccessKey() const
           modifierKey = KeyBinding::kControl;
           break;
         case nsIDOMKeyEvent::DOM_VK_ALT:
           modifierKey = KeyBinding::kAlt;
           break;
         case nsIDOMKeyEvent::DOM_VK_META:
           modifierKey = KeyBinding::kMeta;
           break;
+        case nsIDOMKeyEvent::DOM_VK_WIN:
+          modifierKey = KeyBinding::kOS;
+          break;
       }
     }
   }
 
   return KeyBinding(accesskey[0], modifierKey);
 }
 
 KeyBinding
@@ -221,25 +224,31 @@ XULMenuitemAccessible::KeyboardShortcut(
 
   PRUint32 modifierMask = 0;
   if (modifiersStr.Find("shift") != -1)
     modifierMask |= KeyBinding::kShift;
   if (modifiersStr.Find("alt") != -1)
     modifierMask |= KeyBinding::kAlt;
   if (modifiersStr.Find("meta") != -1)
     modifierMask |= KeyBinding::kMeta;
+  if (modifiersStr.Find("os") != -1)
+    modifierMask |= KeyBinding::kOS;
   if (modifiersStr.Find("control") != -1)
     modifierMask |= KeyBinding::kControl;
   if (modifiersStr.Find("accel") != -1) {
     // Get the accelerator key value from prefs, overriding the default.
     switch (Preferences::GetInt("ui.key.accelKey", 0)) {
       case nsIDOMKeyEvent::DOM_VK_META:
         modifierMask |= KeyBinding::kMeta;
         break;
 
+      case nsIDOMKeyEvent::DOM_VK_WIN:
+        modifierMask |= KeyBinding::kOS;
+        break;
+
       case nsIDOMKeyEvent::DOM_VK_ALT:
         modifierMask |= KeyBinding::kAlt;
         break;
 
       case nsIDOMKeyEvent::DOM_VK_CONTROL:
         modifierMask |= KeyBinding::kControl;
         break;
 
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -53,24 +53,27 @@ function getContentWindow() {
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
     'websettings-read', 'websettings-readwrite',
     'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification',
     'geolocation', 'device-storage', 'alarms'
   ];
+
   urls.forEach(function(url) {
     url = url.trim();
-    let uri = Services.io.newURI(url, null, null);
-    let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
+    if (url) {
+      let uri = Services.io.newURI(url, null, null);
+      let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
 
-    permissions.forEach(function(permission) {
-      Services.perms.add(uri, permission, allow);
-    });
+      permissions.forEach(function(permission) {
+        Services.perms.add(uri, permission, allow);
+      });
+    }
   });
 }
 
 var shell = {
   get contentBrowser() {
     delete this.contentBrowser;
     return this.contentBrowser = document.getElementById('homescreen');
   },
--- a/browser/app/macbuild/Contents/Info.plist.in
+++ b/browser/app/macbuild/Contents/Info.plist.in
@@ -199,21 +199,21 @@
 			</array>
 		</dict>
 	</array>
 	<key>CFBundleVersion</key>
 	<string>%MAC_BUNDLE_VERSION%</string>
 	<key>NSAppleScriptEnabled</key>
 	<true/>
 	<key>LSMinimumSystemVersion</key>
-	<string>10.5</string>
+	<string>10.6</string>
 	<key>LSMinimumSystemVersionByArchitecture</key>
 	<dict>
 		<key>i386</key>
-		<string>10.5.0</string>
+		<string>10.6.0</string>
 		<key>x86_64</key>
 		<string>10.6.0</string>
 	</dict>
   <key>NSSupportsAutomaticGraphicsSwitching</key>
   <true/>
   <key>NSPrincipalClass</key>
   <string>GeckoNSApplication</string>
 </dict>
--- a/browser/base/content/test/browser_bug553455.js
+++ b/browser/base/content/test/browser_bug553455.js
@@ -706,19 +706,19 @@ function test_renotify_installed() {
 function test_cancel_restart() {
   // Wait for the progress notification
   wait_for_notification(function(aPanel) {
     let notification = aPanel.childNodes[0];
     is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
 
     // Close the notification
     let anchor = document.getElementById("addons-notification-icon");
-    EventUtils.synthesizeMouseAtCenter(anchor, {});
+    anchor.click();
     // Reopen the notification
-    EventUtils.synthesizeMouseAtCenter(anchor, {});
+    anchor.click();
 
     ok(PopupNotifications.isPanelOpen, "Notification should still be open");
     is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
     isnot(notification, aPanel.childNodes[0], "Should have reconstructed the notification UI");
     notification = aPanel.childNodes[0];
     is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
     let button = document.getAnonymousElementByAttribute(notification, "anonid", "cancel");
 
--- a/browser/base/content/test/browser_popupNotification.js
+++ b/browser/base/content/test/browser_popupNotification.js
@@ -733,16 +733,20 @@ function triggerMainCommand(popup) {
 }
 
 function triggerSecondaryCommand(popup, index) {
   info("[Test #" + gTestIndex + "] triggering secondary command");
   let notifications = popup.childNodes;
   ok(notifications.length > 0, "at least one notification displayed");
   let notification = notifications[0];
 
+  // Cancel the arrow panel slide-in transition (bug 767133) such that
+  // it won't interfere with us interacting with the dropdown.
+  document.getAnonymousNodes(popup)[0].style.transition = "none";
+
   notification.button.focus();
 
   popup.addEventListener("popupshown", function () {
     popup.removeEventListener("popupshown", arguments.callee, false);
 
     // Press down until the desired command is selected
     for (let i = 0; i <= index; i++)
       EventUtils.synthesizeKey("VK_DOWN", {});
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -468,17 +468,17 @@ function openAboutDialog() {
 #else
   var features = "chrome,centerscreen,dependent,dialog=no";
 #endif
   window.openDialog("chrome://browser/content/aboutDialog.xul", "", features);
 }
 
 function openPreferences(paneID, extraArgs)
 {
-  if (Services.prefs.getBoolPref("browser.preferences.inContent")) {  
+  if (Services.prefs.getBoolPref("browser.preferences.inContent")) {
     openUILinkIn("about:preferences", "tab");
   } else {
     var instantApply = getBoolPref("browser.preferences.instantApply", false);
     var features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
 
     var win = Services.wm.getMostRecentWindow("Browser:Preferences");
     if (win) {
       win.focus();
@@ -487,27 +487,27 @@ function openPreferences(paneID, extraAr
         win.document.documentElement.showPane(pane);
       }
 
       if (extraArgs && extraArgs["advancedTab"]) {
         var advancedPaneTabs = win.document.getElementById("advancedPrefs");
         advancedPaneTabs.selectedTab = win.document.getElementById(extraArgs["advancedTab"]);
       }
 
-     return win;
+     return;
     }
 
-    return openDialog("chrome://browser/content/preferences/preferences.xul",
-                      "Preferences", features, paneID, extraArgs);
+    openDialog("chrome://browser/content/preferences/preferences.xul",
+               "Preferences", features, paneID, extraArgs);
   }
 }
 
 function openAdvancedPreferences(tabID)
 {
-  return openPreferences("paneAdvanced", { "advancedTab" : tabID });
+  openPreferences("paneAdvanced", { "advancedTab" : tabID });
 }
 
 /**
  * Opens the troubleshooting information (about:support) page for this version
  * of the application.
  */
 function openTroubleshootingPage()
 {
--- a/browser/components/sessionstore/test/browser_461743_sample.html
+++ b/browser/components/sessionstore/test/browser_461743_sample.html
@@ -20,17 +20,17 @@
     frames[0].removeEventListener("DOMContentLoaded", handleLoad, false);
     frames[1].removeEventListener("DOMContentLoaded", handleLoad, false);
 
     var flip = 0;
     MutationEvent.prototype.toString = function() {
       return flip++ == 0 ? chromeUrl : exploitUrl;
     };
 
-    var href = Components.lookupMethod(frames[1].location, "href");
+    var href = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(frames[1].location), "href").get;
     var loadChrome = { handleEvent: href };
     var loadExploit = { handleEvent: href };
 
     function delay() {
       var xhr = new XMLHttpRequest();
       xhr.open("GET", location.href, false);
       xhr.send(null);
     }
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1900,41 +1900,16 @@ toolbar[mode="text"] toolbarbutton.chevr
 #appmenu-editmenu-paste {
   list-style-image: url("moz-icon://stock/gtk-paste?size=menu");
 }
 #wrapper-appmenu-toolbar-button,
 .appmenu-edit-button[disabled="true"] {
   opacity: .3;
 }
 
-/* Inspector / Highlighter */
-
-#highlighter-panel {
-  -moz-appearance: none;
-  -moz-window-shadow: none;
-  background: -moz-linear-gradient(top -1deg, #ffdd88, #ffeeaa);
-  border: none;
-  opacity: 0.35;
-}
-
-listitem.style-selector {
-  background-color: DarkGray;
-  color: white;
-}
-
-listitem.style-section {
-  background-color: LightGray;
-  color: black;
-  font-weight: bold;
-}
-
-panel[dimmed="true"] {
-  opacity: 0.5;
-}
-
 /* Add-on bar */
 
 #addon-bar {
   box-shadow: 0 1px 0 rgba(0,0,0,.15) inset;
   padding: 0;
   min-height: 20px;
 }
 
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -247,21 +247,21 @@
   -moz-appearance: treetwistyopen;
 }
 
 /**
  * Animations
  */
 
 .details[open][animated] {
-  -moz-animation-duration: 0.25s;
-  -moz-animation-name: showblock;
+  animation-duration: 0.25s;
+  animation-name: showblock;
 }
 
-@-moz-keyframes showblock {
+@keyframes showblock {
   from {
     opacity: 0;
     transform-origin: top;
     transform: scaleY(0);
   }
 
   to {
     opacity: 1;
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/downloads.css
@@ -199,35 +199,35 @@ richlistitem[type="download"][state="1"]
 
 #downloads-indicator-notification {
   opacity: 0;
   background: url("chrome://browser/skin/downloads/download-notification.png")
               center no-repeat;
   background-size: 16px;
 }
 
-@-moz-keyframes downloadsIndicatorNotificationRight {
+@keyframes downloadsIndicatorNotificationRight {
   from { opacity: 0; transform: translate(-128px, 128px) scale(8); }
-  20%  { opacity: .85; -moz-animation-timing-function: ease-out; }
+  20%  { opacity: .85; animation-timing-function: ease-out; }
   to   { opacity: 0; transform: translate(0) scale(1); }
 }
 
-@-moz-keyframes downloadsIndicatorNotificationLeft {
+@keyframes downloadsIndicatorNotificationLeft {
   from { opacity: 0; transform: translate(128px, 128px) scale(8); }
-  20%  { opacity: .85; -moz-animation-timing-function: ease-out; }
+  20%  { opacity: .85; animation-timing-function: ease-out; }
   to   { opacity: 0; transform: translate(0) scale(1); }
 }
 
 #downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-  -moz-animation-name: downloadsIndicatorNotificationRight;
-  -moz-animation-duration: 1s;
+  animation-name: downloadsIndicatorNotificationRight;
+  animation-duration: 1s;
 }
 
 #downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-  -moz-animation-name: downloadsIndicatorNotificationLeft;
+  animation-name: downloadsIndicatorNotificationLeft;
 }
 
 /*** Progress bar and text ***/
 
 #downloads-indicator-counter {
   height: 12px;
   margin: 0;
   color: hsl(0,0%,30%);
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -2619,41 +2619,16 @@ toolbarbutton.chevron > .toolbarbutton-m
 .allTabs-preview:not(:hover):not([closebuttonhover]) > html|canvas {
   opacity: .8;
 }
 
 .allTabs-preview:focus > * > .allTabs-preview-inner {
   box-shadow: @focusRingShadow@;
 }
 
-/* Inspector / Highlighter */
-
-#highlighter-panel {
-  -moz-appearance: none;
-  -moz-window-shadow: none;
-  background: -moz-linear-gradient(top -1deg, #ffdd88, #ffeeaa);
-  border: none;
-  opacity: 0.35;
-}
-
-listitem.style-selector {
-  background-color: DarkGray;
-  color: white;
-}
-
-listitem.style-section {
-  background-color: LightGray;
-  color: black;
-  font-weight: bold;
-}
-
-panel[dimmed="true"] {
-  opacity: 0.5;
-}
-
 /* Add-on bar */
 
 #addon-bar {
   min-height: 18px;
   padding-right: 16px; /* replace with -moz-padding-end when/if bug 631729 gets fixed */
 }
 
 #addon-bar:not(:-moz-lwtheme) {
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -247,21 +247,21 @@
   -moz-appearance: treetwistyopen;
 }
 
 /**
  * Animations
  */
 
 .details[open][animated] {
-  -moz-animation-duration: 0.25s;
-  -moz-animation-name: showblock;
+  animation-duration: 0.25s;
+  animation-name: showblock;
 }
 
-@-moz-keyframes showblock {
+@keyframes showblock {
   from {
     opacity: 0;
     transform-origin: top;
     transform: scaleY(0);
   }
 
   to {
     opacity: 1;
--- a/browser/themes/pinstripe/downloads/downloads.css
+++ b/browser/themes/pinstripe/downloads/downloads.css
@@ -220,35 +220,35 @@ richlistitem[type="download"][state="1"]
 
 #downloads-indicator-notification {
   opacity: 0;
   background: url("chrome://browser/skin/downloads/download-notification.png")
               center no-repeat;
   background-size: 16px;
 }
 
-@-moz-keyframes downloadsIndicatorNotificationRight {
+@keyframes downloadsIndicatorNotificationRight {
   from { opacity: 0; transform: translate(-128px, 128px) scale(8); }
-  20%  { opacity: .85; -moz-animation-timing-function: ease-out; }
+  20%  { opacity: .85; animation-timing-function: ease-out; }
   to   { opacity: 0; transform: translate(0) scale(1); }
 }
 
-@-moz-keyframes downloadsIndicatorNotificationLeft {
+@keyframes downloadsIndicatorNotificationLeft {
   from { opacity: 0; transform: translate(128px, 128px) scale(8); }
-  20%  { opacity: .85; -moz-animation-timing-function: ease-out; }
+  20%  { opacity: .85; animation-timing-function: ease-out; }
   to   { opacity: 0; transform: translate(0) scale(1); }
 }
 
 #downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-  -moz-animation-name: downloadsIndicatorNotificationRight;
-  -moz-animation-duration: 1s;
+  animation-name: downloadsIndicatorNotificationRight;
+  animation-duration: 1s;
 }
 
 #downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-  -moz-animation-name: downloadsIndicatorNotificationLeft;
+  animation-name: downloadsIndicatorNotificationLeft;
 }
 
 /*** Progress bar and text ***/
 
 #downloads-indicator-counter {
   height: 12px;
   margin: 0;
   color: hsl(0,0%,30%);
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2563,41 +2563,16 @@ toolbarbutton.bookmark-item[dragover="tr
 .allTabs-preview:not(:hover):not([closebuttonhover]) > html|canvas {
   opacity: .8;
 }
 
 .allTabs-preview:focus > * > .allTabs-preview-inner {
   outline: 1px dotted -moz-dialogText;
 }
 
-/* Inspector / Highlighter */
-
-#highlighter-panel {
-  -moz-appearance: none;
-  -moz-window-shadow: none;
-  background: -moz-linear-gradient(top -1deg, #ffdd88, #ffeeaa);
-  border: none;
-  opacity: 0.35;
-}
-
-listitem.style-selector {
-  background-color: DarkGray;
-  color: white;
-}
-
-listitem.style-section {
-  background-color: LightGray;
-  color: black;
-  font-weight: bold;
-}
-
-panel[dimmed="true"] {
-  opacity: 0.5;
-}
-
 /* Add-on bar */
 
 #addon-bar {
   -moz-appearance: none;
   min-height: 20px;
   border-top-style: none;
   border-bottom-style: none;
   padding-top: 1px;
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -258,21 +258,21 @@
   background-image: url("chrome://global/skin/tree/twisty-open.png");
 }
 
 /**
  * Animations
  */
 
 .details[open][animated] {
-  -moz-animation-duration: 0.25s;
-  -moz-animation-name: showblock;
+  animation-duration: 0.25s;
+  animation-name: showblock;
 }
 
-@-moz-keyframes showblock {
+@keyframes showblock {
   from {
     opacity: 0;
     transform-origin: top;
     transform: scaleY(0);
   }
 
   to {
     opacity: 1;
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -219,35 +219,35 @@ richlistitem[type="download"][state="1"]
 
 #downloads-indicator-notification {
   opacity: 0;
   background: url("chrome://browser/skin/downloads/download-notification.png")
               center no-repeat;
   background-size: 16px;
 }
 
-@-moz-keyframes downloadsIndicatorNotificationRight {
+@keyframes downloadsIndicatorNotificationRight {
   from { opacity: 0; transform: translate(-128px, 128px) scale(8); }
-  20%  { opacity: .85; -moz-animation-timing-function: ease-out; }
+  20%  { opacity: .85; animation-timing-function: ease-out; }
   to   { opacity: 0; transform: translate(0) scale(1); }
 }
 
-@-moz-keyframes downloadsIndicatorNotificationLeft {
+@keyframes downloadsIndicatorNotificationLeft {
   from { opacity: 0; transform: translate(128px, 128px) scale(8); }
-  20%  { opacity: .85; -moz-animation-timing-function: ease-out; }
+  20%  { opacity: .85; animation-timing-function: ease-out; }
   to   { opacity: 0; transform: translate(0) scale(1); }
 }
 
 #downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-  -moz-animation-name: downloadsIndicatorNotificationRight;
-  -moz-animation-duration: 1s;
+  animation-name: downloadsIndicatorNotificationRight;
+  animation-duration: 1s;
 }
 
 #downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-  -moz-animation-name: downloadsIndicatorNotificationLeft;
+  animation-name: downloadsIndicatorNotificationLeft;
 }
 
 /*** Progress bar and text ***/
 
 #downloads-indicator-counter {
   height: 12px;
   margin: 0;
   color: hsl(0,0%,30%);
--- a/build/mobile/devicemanagerSUT.py
+++ b/build/mobile/devicemanagerSUT.py
@@ -217,17 +217,17 @@ class DeviceManagerSUT(DeviceManager):
             if select.select([self._sock], [], [], 1)[0]:
                 temp = self._sock.recv(1024)
             if (self.debug >= 4): print "response: " + str(temp)
           except socket.error, err:
             self._sock.close()
             self._sock = None
             # This error shows up with we have our tegra rebooted.
             if err[0] == errno.ECONNRESET:
-              raise AgentError("Automation error: Error receiving data from socket (possible reboot). cmd=%s; err=%s" % (cmd, err), True)
+              raise AgentError("Automation error: Error receiving data from socket (possible reboot). cmd=%s; err=%s" % (cmd, err))
             raise AgentError("Error receiving data from socket. cmd=%s; err=%s" % (cmd, err))
 
           data += temp
 
           # If something goes wrong in the agent it will send back a string that
           # starts with '##AGENT-WARNING##'
           errorMatch = self.agentErrorRE.match(data)
           if errorMatch:
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -7,17 +7,17 @@ topsrcdir   = @top_srcdir@
 srcdir      = @srcdir@
 VPATH       = @srcdir@
 TESTPATH    = $(topsrcdir)/mobile/android/base/tests
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = robocop
 
-ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.2.1.jar
+ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.3.jar
 
 JAVAFILES = \
   R.java \
 
 _JAVA_HARNESS = \
   Actions.java \
   Assert.java \
   Driver.java \
--- a/build/mobile/robocop/README
+++ b/build/mobile/robocop/README
@@ -1,9 +1,9 @@
 Robocop is a Mozilla project which uses Robotium to test Firefox on Android devices.
 
 Robotium is an open source tool licensed under the Apache 2.0 license and the original 
 source can be found here:
 http://code.google.com/p/robotium/
 
-We are including robotium-solo-3.2.1.jar as a binary and are not modifying it in anyway 
+We are including robotium-solo-3.3.jar as a binary and are not modifying it in anyway 
 from the original download found at: 
 http://code.google.com/p/robotium/
deleted file mode 100644
index f4107c7496ec18d7a5fc2fe56742036ef3861bb7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index 0000000000000000000000000000000000000000..0fd9421101ed0dc10a00a2b85c4b0811abd2bd2a
GIT binary patch
literal 55662
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%0A%1ye!~0l$d$K~~1G`#%`9tYJMee9Q2ehaT
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
V0B=?{kfEAD7zu31|33xd0RVv90Gj{+
--- a/configure.in
+++ b/configure.in
@@ -7067,17 +7067,17 @@ AC_SUBST(DLLFLAGS)
 dnl We need to wrap dlopen and related functions on Android because we use
 dnl our own linker.
 if test "$OS_TARGET" = Android; then
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
     if test -n "$MOZ_OLD_LINKER"; then
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=dlopen,--wrap=dlclose,--wrap=dlerror,--wrap=dlsym,--wrap=dladdr"
     fi
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
-    WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise"
+    WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
 fi
 
 dnl ========================================================
 dnl = Use malloc wrapper lib
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(wrap-malloc,
 [  --enable-wrap-malloc    Wrap malloc calls (gnu linker only)],
     _WRAP_MALLOC=1,
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1865,16 +1865,17 @@ public:
    * nsEventStateManager::IsHandlingUserInput() stops returning true.
    * This enables us to detect long running user-generated event handlers.
    */
   static TimeDuration HandlingUserInputTimeout();
 
   static void GetShiftText(nsAString& text);
   static void GetControlText(nsAString& text);
   static void GetMetaText(nsAString& text);
+  static void GetOSText(nsAString& text);
   static void GetAltText(nsAString& text);
   static void GetModifierSeparatorText(nsAString& text);
 
   /**
    * Returns if aContent has a tabbable subdocument.
    * A sub document isn't tabbable when it's a zombie document.
    *
    * @param aElement element to test.
@@ -2169,16 +2170,17 @@ private:
   /**
    * True if there's a fragment parser activation on the stack.
    */
   static bool sFragmentParsingActive;
 
   static nsString* sShiftText;
   static nsString* sControlText;
   static nsString* sMetaText;
+  static nsString* sOSText;
   static nsString* sAltText;
   static nsString* sModifierSeparator;
 };
 
 typedef nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
                                                     HTMLSplitOnSpacesTokenizer;
 
 #define NS_HOLD_JS_OBJECTS(obj, clazz)                                         \
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -14,17 +14,16 @@
 #include "nsILoadGroup.h"
 #include "nsCRT.h"
 #include "mozFlushType.h"
 #include "nsIAtom.h"
 #include "nsCompatibility.h"
 #include "nsTObserverArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
-#include "nsNodeInfoManager.h"
 #include "nsIVariant.h"
 #include "nsIObserver.h"
 #include "nsGkAtoms.h"
 #include "nsAutoPtr.h"
 #include "nsPIDOMWindow.h"
 #include "nsSMILAnimationController.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocumentEncoder.h"
@@ -121,38 +120,19 @@ class nsIDocument : public nsINode
 {
 public:
   typedef mozilla::dom::Element Element;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
 #ifdef MOZILLA_INTERNAL_API
-  nsIDocument()
-    : nsINode(nsnull),
-      mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
-      mNodeInfoManager(nsnull),
-      mCompatMode(eCompatibility_FullStandards),
-      mIsInitialDocumentInWindow(false),
-      mMayStartLayout(true),
-      mVisible(true),
-      mRemovedFromDocShell(false),
-      // mAllowDNSPrefetch starts true, so that we can always reliably && it
-      // with various values that might disable it.  Since we never prefetch
-      // unless we get a window, and in that case the docshell value will get
-      // &&-ed in, this is safe.
-      mAllowDNSPrefetch(true),
-      mIsBeingUsedAsImage(false),
-      mHasLinksToUpdate(false),
-      mPartID(0)
-  {
-    SetInDocument();
-  }
+  nsIDocument();
 #endif
-  
+
   /**
    * Let the document know that we're starting to load data into it.
    * @param aCommand The parser command. Must not be null.
    *                 XXXbz It's odd to have that here.
    * @param aChannel The channel the data will come from. The channel must be
    *                 able to report its Content-Type.
    * @param aLoadGroup The loadgroup this document should use from now on.
    *                   Note that the document might not be the only thing using
@@ -1683,24 +1663,17 @@ public:
       --mInSyncOperationCount;
     }
   }
 
 private:
   PRUint64 mWarnedAbout;
 
 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.
-  }
-
+  ~nsIDocument();
   nsPropertyTable* GetExtraPropertyTable(PRUint16 aCategory);
 
   // Never ever call this. Only call GetWindow!
   virtual nsPIDOMWindow *GetWindowInternal() const = 0;
 
   // Never ever call this. Only call GetInnerWindow!
   virtual nsPIDOMWindow *GetInnerWindowInternal() = 0;
 
@@ -1747,29 +1720,27 @@ protected:
   PRInt32 mCharacterSetSource;
 
   // This is just a weak pointer; the parent document owns its children.
   nsIDocument* mParentDocument;
 
   // A reference to the element last returned from GetRootElement().
   mozilla::dom::Element* mCachedRootElement;
 
-  // We'd like these to be nsRefPtrs, but that'd require us to include
-  // additional headers that we don't want to expose.
-  // The cleanup is handled by the nsDocument destructor.
+  // We hold a strong reference to mNodeInfoManager through mNodeInfo
   nsNodeInfoManager* mNodeInfoManager; // [STRONG]
-  mozilla::css::Loader* mCSSLoader; // [STRONG]
+  nsRefPtr<mozilla::css::Loader> mCSSLoader;
   nsHTMLStyleSheet* mAttrStyleSheet;
 
   // The set of all object, embed, applet, video and audio elements for
   // which this is the owner document. (They might not be in the document.)
   // These are non-owning pointers, the elements are responsible for removing
   // themselves when they go away.
   nsAutoPtr<nsTHashtable<nsPtrHashKey<nsIContent> > > mFreezableElements;
-  
+
   // The set of all links that need their status resolved.  Links must add themselves
   // to this set by calling RegisterPendingLinkUpdate when added to a document and must
   // remove themselves by calling UnregisterPendingLinkUpdate when removed from a document.
   nsTHashtable<nsPtrHashKey<mozilla::dom::Link> > mLinksToUpdate;
 
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
   nsRefPtr<nsSMILAnimationController> mAnimationController;
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -211,16 +211,17 @@ PRUint32 nsContentUtils::sRunnersCountAt
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
 
 bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
 bool nsContentUtils::sAllowXULXBL_for_file = false;
 
 nsString* nsContentUtils::sShiftText = nsnull;
 nsString* nsContentUtils::sControlText = nsnull;
 nsString* nsContentUtils::sMetaText = nsnull;
+nsString* nsContentUtils::sOSText = nsnull;
 nsString* nsContentUtils::sAltText = nsnull;
 nsString* nsContentUtils::sModifierSeparator = nsnull;
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sIsIdleObserverAPIEnabled = false;
 
@@ -431,16 +432,25 @@ void
 nsContentUtils::GetMetaText(nsAString& text)
 {
   if (!sMetaText)
     InitializeModifierStrings();
   text.Assign(*sMetaText);
 }
 
 void
+nsContentUtils::GetOSText(nsAString& text)
+{
+  if (!sOSText) {
+    InitializeModifierStrings();
+  }
+  text.Assign(*sOSText);
+}
+
+void
 nsContentUtils::GetAltText(nsAString& text)
 {
   if (!sAltText)
     InitializeModifierStrings();
   text.Assign(*sAltText);
 }
 
 void
@@ -462,30 +472,33 @@ nsContentUtils::InitializeModifierString
   if (bundleService) {
     rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
                                       getter_AddRefs(bundle));
   }
   
   NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded");
   nsXPIDLString shiftModifier;
   nsXPIDLString metaModifier;
+  nsXPIDLString osModifier;
   nsXPIDLString altModifier;
   nsXPIDLString controlModifier;
   nsXPIDLString modifierSeparator;
   if (bundle) {
     //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_SHIFT").get(), getter_Copies(shiftModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_META").get(), getter_Copies(metaModifier));
+    bundle->GetStringFromName(NS_LITERAL_STRING("VK_WIN").get(), getter_Copies(osModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_ALT").get(), getter_Copies(altModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_CONTROL").get(), getter_Copies(controlModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("MODIFIER_SEPARATOR").get(), getter_Copies(modifierSeparator));
   }
   //if any of these don't exist, we get  an empty string
   sShiftText = new nsString(shiftModifier);
   sMetaText = new nsString(metaModifier);
+  sOSText = new nsString(osModifier);
   sAltText = new nsString(altModifier);
   sControlText = new nsString(controlModifier);
   sModifierSeparator = new nsString(modifierSeparator);  
 }
 
 bool nsContentUtils::sImgLoaderInitialized;
 
 void
@@ -1448,16 +1461,18 @@ nsContentUtils::Shutdown()
   sBlockedScriptRunners = nsnull;
 
   delete sShiftText;
   sShiftText = nsnull;
   delete sControlText;  
   sControlText = nsnull;
   delete sMetaText;  
   sMetaText = nsnull;
+  delete sOSText;
+  sOSText = nsnull;
   delete sAltText;  
   sAltText = nsnull;
   delete sModifierSeparator;
   sModifierSeparator = nsnull;
 
   NS_IF_RELEASE(sSameOriginChecker);
   
   nsTextEditorState::ShutDown();
@@ -2769,38 +2784,30 @@ bool
 nsContentUtils::IsDraggableLink(const nsIContent* aContent) {
   nsCOMPtr<nsIURI> absURI;
   return aContent->IsLink(getter_AddRefs(absURI));
 }
 
 static bool
 TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, PRUint32 aPerm)
 {
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    // System principal is always allowed and never denied permission.
-    return aPerm == nsIPermissionManager::ALLOW_ACTION;
-  }
-
-  nsCOMPtr<nsIURI> uri;
-  if (NS_FAILED(!aPrincipal ||
-      aPrincipal->GetURI(getter_AddRefs(uri))) ||
-      !uri) {
-    // We always deny (i.e. don't allow) the permission if we don't
-    // have a principal or we don't know the URI.
+  if (!aPrincipal) {
+    // We always deny (i.e. don't allow) the permission if we don't have a
+    // principal.
     return aPerm != nsIPermissionManager::ALLOW_ACTION;
   }
 
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService("@mozilla.org/permissionmanager;1");
   NS_ENSURE_TRUE(permMgr, false);
 
   PRUint32 perm;
-  nsresult rv = permMgr->TestPermission(uri, aType, &perm);
+  nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
   NS_ENSURE_SUCCESS(rv, false);
-  
+
   return perm == aPerm;
 }
 
 bool
 nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType)
 {
   return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION);
 }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1489,54 +1489,82 @@ nsDOMImplementation::CreateHTMLDocument(
   document.forget(aReturn);
 
   return NS_OK;
 }
 
 // ==================================================================
 // =
 // ==================================================================
-
-  // NOTE! nsDocument::operator new() zeroes out all members, so don't
-  // bother initializing members to 0.
+nsIDocument::nsIDocument()
+  : nsINode(nsnull),
+    mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
+    mNodeInfoManager(nsnull),
+    mCompatMode(eCompatibility_FullStandards),
+    mIsInitialDocumentInWindow(false),
+    mMayStartLayout(true),
+    mVisible(true),
+    mRemovedFromDocShell(false),
+    // mAllowDNSPrefetch starts true, so that we can always reliably && it
+    // with various values that might disable it.  Since we never prefetch
+    // unless we get a window, and in that case the docshell value will get
+    // &&-ed in, this is safe.
+    mAllowDNSPrefetch(true),
+    mIsBeingUsedAsImage(false),
+    mHasLinksToUpdate(false),
+    mPartID(0)
+{
+  SetInDocument();
+}
+
+// NOTE! nsDocument::operator new() zeroes out all members, so don't
+// bother initializing members to 0.
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
   , mAnimatingImages(true)
   , mVisibilityState(eHidden)
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
-  
+
 #ifdef PR_LOGGING
   if (!gDocumentLeakPRLog)
     gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
 
   if (gDocumentLeakPRLog)
     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
            ("DOCUMENT %p created", this));
 
   if (!gCspPRLog)
     gCspPRLog = PR_NewLogModule("CSP");
 #endif
 
   // Start out mLastStyleSheetSet as null, per spec
   SetDOMStringToNull(mLastStyleSheetSet);
-  
+
   mLinksToUpdate.Init();
 }
 
 static PLDHashOperator
 ClearAllBoxObjects(nsIContent* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
 {
   if (aBoxObject) {
     aBoxObject->Clear();
   }
   return PL_DHASH_NEXT;
 }
 
+nsIDocument::~nsIDocument()
+{
+  if (mNodeInfoManager) {
+    mNodeInfoManager->DropDocumentReference();
+  }
+}
+
+
 nsDocument::~nsDocument()
 {
 #ifdef PR_LOGGING
   if (gDocumentLeakPRLog)
     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
            ("DOCUMENT %p destroyed", this));
 #endif
 
@@ -1608,22 +1636,16 @@ nsDocument::~nsDocument()
 
   if (mScriptLoader) {
     mScriptLoader->DropDocumentReference();
   }
 
   if (mCSSLoader) {
     // Could be null here if Init() failed
     mCSSLoader->DropDocumentReference();
-    NS_RELEASE(mCSSLoader);
-  }
-
-  // XXX Ideally we'd do this cleanup in the nsIDocument destructor.
-  if (mNodeInfoManager) {
-    mNodeInfoManager->DropDocumentReference();
   }
 
   delete mHeaderData;
 
   if (mBoxObjectTable) {
     mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
     delete mBoxObjectTable;
   }
@@ -1905,17 +1927,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedEncoder)
 
   tmp->mParentDocument = nsnull;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPreloadingImages)
 
-  
+
   if (tmp->mBoxObjectTable) {
    tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
    delete tmp->mBoxObjectTable;
    tmp->mBoxObjectTable = nsnull;
  }
 
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
@@ -1926,29 +1948,29 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   if (tmp->mSubDocuments) {
     PL_DHashTableDestroy(tmp->mSubDocuments);
     tmp->mSubDocuments = nsnull;
   }
 
   tmp->mFrameRequestCallbacks.Clear();
 
   tmp->mRadioGroups.Clear();
-  
+
   // 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.
 
   tmp->mIdentifierMap.Clear();
 
   if (tmp->mAnimationController) {
     tmp->mAnimationController->Unlink();
   }
 
   tmp->mPendingTitleChangeEvent.Revoke();
-  
+
   tmp->mInUnlinkOrDeletion = false;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 nsresult
 nsDocument::Init()
 {
   if (mCSSLoader || mNodeInfoManager || mScriptLoader) {
@@ -1956,59 +1978,51 @@ nsDocument::Init()
   }
 
   mIdentifierMap.Init();
   mStyledLinks.Init();
   mRadioGroups.Init();
 
   // Force initialization.
   nsINode::nsSlots* slots = GetSlots();
-  NS_ENSURE_TRUE(slots,NS_ERROR_OUT_OF_MEMORY);
 
   // Prepend self as mutation-observer whether we need it or not (some
   // subclasses currently do, other don't). This is because the code in
   // nsNodeUtils always notifies the first observer first, expecting the
   // first observer to be the document.
   NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)),
                  NS_ERROR_OUT_OF_MEMORY);
 
 
   mOnloadBlocker = new nsOnloadBlocker();
-  NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
-
   mCSSLoader = new mozilla::css::Loader(this);
-  NS_ENSURE_TRUE(mCSSLoader, NS_ERROR_OUT_OF_MEMORY);
-  NS_ADDREF(mCSSLoader);
   // Assume we're not quirky, until we know otherwise
   mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
 
   mNodeInfoManager = new nsNodeInfoManager();
-  NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
-
   nsresult  rv = mNodeInfoManager->Init(this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mNodeInfo keeps NodeInfoManager alive!
   mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
   NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_NODE,
                     "Bad NodeType in aNodeInfo");
 
   NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
 
   mScriptLoader = new nsScriptLoader(this);
-  NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY);
 
   mImageTracker.Init();
   mPlugins.Init();
 
   return NS_OK;
 }
 
-void 
+void
 nsIDocument::DeleteAllProperties()
 {
   for (PRUint32 i = 0; i < GetPropertyTableCount(); ++i) {
     PropertyTable(i)->DeleteAllProperties();
   }
 }
 
 void
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -14,19 +14,19 @@
 #include "nsIDocShell.h"
 #include "nsStringFwd.h"
 #include "nsIFrameLoader.h"
 #include "nsPoint.h"
 #include "nsSize.h"
 #include "nsIURI.h"
 #include "nsAutoPtr.h"
 #include "nsFrameMessageManager.h"
-#include "Layers.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Attributes.h"
+#include "Layers.h"
 
 class nsIURI;
 class nsSubDocumentFrame;
 class nsIView;
 class nsIInProcessContentFrameMessageManager;
 class AutoResetInShow;
 class nsITabParent;
 
new file mode 100644
--- /dev/null
+++ b/content/canvas/crashtests/767337-1.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="c" width="500" height="1000">
+</canvas>
+<script>
+var ctxt = document.getElementById('c').getContext('2d');
+for (var k = 0; k < 100; ++j) {
+  for (var j = 0; j < 10; ++j) {
+    for (var i = 0; i < 1000; ++i) {
+      gradient = ctxt.createLinearGradient(0,0,200,i);
+      gradient.addColorStop(0,'black');
+      gradient.addColorStop(1,'rgba(0, 255*k/100, 0, 0.1)');
+      ctxt.fillStyle = gradient;
+      ctxt.fillRect(j*50, 2*i, 50, 2);
+    }
+  }
+}
+</script>
+</body>
+</html>
\ No newline at end of file
--- a/content/canvas/crashtests/crashtests.list
+++ b/content/canvas/crashtests/crashtests.list
@@ -5,8 +5,9 @@ load 647480.html
 load 0px-size-font-667225.html
 load texImage2D.html
 load 729116.html
 load 745699-1.html
 load 746813-1.html
 # this test crashes in a bunch places still
 #load 745818-large-source.html
 load 743499-negative-size.html
+load 767337-1.html
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -20,17 +20,16 @@
 #include "nsHTMLCanvasElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIMemoryReporter.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsWrapperCache.h"
 #include "nsIObserver.h"
 
 #include "GLContextProvider.h"
-#include "Layers.h"
 
 #include "mozilla/LinkedList.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/ImageData.h"
 
 #ifdef XP_MACOSX
 #include "ForceDiscreteGPUHelperCGL.h"
 #endif
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -261,16 +261,17 @@ enum {
  MOUSE_SCROLL_PIXELS
 };
 
 // mask values for ui.key.chromeAccess and ui.key.contentAccess
 #define NS_MODIFIER_SHIFT    1
 #define NS_MODIFIER_CONTROL  2
 #define NS_MODIFIER_ALT      4
 #define NS_MODIFIER_META     8
+#define NS_MODIFIER_OS       16
 
 static nsIDocument *
 GetDocumentFromWindow(nsIDOMWindow *aWindow)
 {
   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow);
   nsCOMPtr<nsIDocument> doc;
 
   if (win) {
@@ -285,16 +286,17 @@ GetAccessModifierMaskFromPref(PRInt32 aI
 {
   PRInt32 accessKey = Preferences::GetInt("ui.key.generalAccessKey", -1);
   switch (accessKey) {
     case -1:                             break; // use the individual prefs
     case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
     case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
     case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
     case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
+    case nsIDOMKeyEvent::DOM_VK_WIN:     return NS_MODIFIER_OS;
     default:                             return 0;
   }
 
   switch (aItemType) {
   case nsIDocShellTreeItem::typeChrome:
     return Preferences::GetInt("ui.key.chromeAccess", 0);
   case nsIDocShellTreeItem::typeContent:
     return Preferences::GetInt("ui.key.contentAccess", 0);
@@ -1162,16 +1164,18 @@ nsEventStateManager::PreHandleEvent(nsPr
       if (keyEvent->IsShift())
         modifierMask |= NS_MODIFIER_SHIFT;
       if (keyEvent->IsControl())
         modifierMask |= NS_MODIFIER_CONTROL;
       if (keyEvent->IsAlt())
         modifierMask |= NS_MODIFIER_ALT;
       if (keyEvent->IsMeta())
         modifierMask |= NS_MODIFIER_META;
+      if (keyEvent->IsOS())
+        modifierMask |= NS_MODIFIER_OS;
 
       // Prevent keyboard scrolling while an accesskey modifier is in use.
       if (modifierMask && (modifierMask == sChromeAccessModifier ||
                            modifierMask == sContentAccessModifier))
         HandleAccessKey(aPresContext, keyEvent, aStatus, nsnull,
                         eAccessKeyProcessingNormal, modifierMask);
     }
     // then fall through...
@@ -1519,16 +1523,20 @@ nsEventStateManager::GetAccessKeyLabelPr
   if (modifier & NS_MODIFIER_CONTROL) {
     nsContentUtils::GetControlText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
   if (modifier & NS_MODIFIER_META) {
     nsContentUtils::GetMetaText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
+  if (modifier & NS_MODIFIER_OS) {
+    nsContentUtils::GetOSText(modifierText);
+    aPrefix.Append(modifierText + separator);
+  }
   if (modifier & NS_MODIFIER_ALT) {
     nsContentUtils::GetAltText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
   if (modifier & NS_MODIFIER_SHIFT) {
     nsContentUtils::GetShiftText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
@@ -1632,20 +1640,19 @@ nsEventStateManager::HandleAccessKey(nsP
         esm->HandleAccessKey(parentPC, aEvent, aStatus, docShell,
                              eAccessKeyProcessingUp, aModifierMask);
     }
   }// if end. bubble up process
 }// end of HandleAccessKey
 
 bool
 nsEventStateManager::DispatchCrossProcessEvent(nsEvent* aEvent,
-                                               nsIFrameLoader* aFrameLoader,
+                                               nsFrameLoader* aFrameLoader,
                                                nsEventStatus *aStatus) {
-  nsFrameLoader* fml = static_cast<nsFrameLoader*>(aFrameLoader);
-  PBrowserParent* remoteBrowser = fml->GetRemoteBrowser();
+  PBrowserParent* remoteBrowser = aFrameLoader->GetRemoteBrowser();
   TabParent* remote = static_cast<TabParent*>(remoteBrowser);
   if (!remote) {
     return false;
   }
 
   switch (aEvent->eventStructType) {
   case NS_MOUSE_EVENT: {
     nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
@@ -1783,39 +1790,67 @@ nsEventStateManager::HandleCrossProcessE
       }
       nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
       if (IsRemoteTarget(target) && !targets.Contains(target)) {
         targets.AppendElement(target);
       }
     }
   }
 
+  if (targets.Length() == 0) {
+    return false;
+  }
+
   // Look up the frame loader for all the remote targets we found, and
   // then dispatch the event to the remote content they represent.
   bool dispatched = false;
   for (PRUint32 i = 0; i < targets.Length(); ++i) {
     nsIContent* target = targets[i];
     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target);
     if (!loaderOwner) {
-      return false;
+      continue;
     }
 
     nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
     if (!frameLoader) {
-      return false;
+      continue;
     }
 
     PRUint32 eventMode;
     frameLoader->GetEventMode(&eventMode);
     if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) {
-      return false;
+      continue;
     }
 
-    nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aTargetFrame);
-    aEvent->refPoint = pt.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
+    // The "toplevel widget" in content processes is always at position
+    // 0,0.  Map the event coordinates to match that.
+    if (aEvent->eventStructType != NS_TOUCH_EVENT) {
+      nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
+                                                                aTargetFrame);
+      aEvent->refPoint =
+        pt.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
+    } else {
+      nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent();
+      aEvent->refPoint = nsIntPoint();
+      // Find out how far we're offset from the nearest widget.
+      nsPoint offset =
+        nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, targetFrame);
+      nsIntPoint intOffset =
+        offset.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
+      nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
+      // Then offset all the touch points by that distance, to put them
+      // in the space where top-left is 0,0.
+      const nsTArray<nsCOMPtr<nsIDOMTouch> >& touches = touchEvent->touches;
+      for (PRUint32 i = 0; i < touches.Length(); ++i) {
+        nsIDOMTouch* touch = touches[i];
+        if (touch) {
+          touch->mRefPoint += intOffset;
+        }
+      }
+    }
 
     dispatched |= DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
   }
   return dispatched;
 }
 
 //
 // CreateClickHoldTimer
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -442,17 +442,17 @@ protected:
   void DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
                                nsIFrame* aTargetFrame);
   void DoQuerySelectedText(nsQueryContentEvent* aEvent);
 
   bool RemoteQueryContentEvent(nsEvent *aEvent);
   mozilla::dom::TabParent *GetCrossProcessTarget();
   bool IsTargetCrossProcess(nsGUIEvent *aEvent);
 
-  bool DispatchCrossProcessEvent(nsEvent* aEvent, nsIFrameLoader* remote,
+  bool DispatchCrossProcessEvent(nsEvent* aEvent, nsFrameLoader* remote,
                                  nsEventStatus *aStatus);
   bool HandleCrossProcessEvent(nsEvent *aEvent,
                                  nsIFrame* aTargetFrame,
                                  nsEventStatus *aStatus);
 
 private:
   static inline void DoStateChange(mozilla::dom::Element* aElement,
                                    nsEventStates aState, bool aAddState);
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -191,18 +191,21 @@ destroying the nsBuiltinDecoder object.
 #include "nsSize.h"
 #include "prlog.h"
 #include "gfxContext.h"
 #include "gfxRect.h"
 #include "MediaResource.h"
 #include "nsMediaDecoder.h"
 #include "nsHTMLMediaElement.h"
 #include "mozilla/ReentrantMonitor.h"
+#include "ImageLayers.h"
+class nsAudioStream;
 
-class nsAudioStream;
+typedef mozilla::layers::Image Image;
+typedef mozilla::layers::ImageContainer ImageContainer;
 
 static inline bool IsCurrentThread(nsIThread* aThread) {
   return NS_GetCurrentThread() == aThread;
 }
 
 // Decoder backends must implement this class to perform the codec
 // specific parts of decoding the video/audio format.
 class nsDecoderStateMachine : public nsRunnable
--- a/content/media/nsBuiltinDecoderReader.h
+++ b/content/media/nsBuiltinDecoderReader.h
@@ -2,17 +2,16 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(nsBuiltinDecoderReader_h_)
 #define nsBuiltinDecoderReader_h_
 
 #include <nsDeque.h>
-#include "ImageLayers.h"
 #include "nsSize.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "MediaStreamGraph.h"
 #include "SharedBuffer.h"
 
 // Stores info relevant to presenting media frames.
 class nsVideoInfo {
 public:
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -545,21 +545,21 @@ void nsBuiltinDecoderStateMachine::SendO
   nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
   aOutput->AppendFrames(buffer.forget(), aAudio->mFrames, PRInt32(offset), aAudio->mFrames,
                         MOZ_AUDIO_DATA_FORMAT);
   LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of data to MediaStream for AudioData at %lld",
                      mDecoder.get(), aAudio->mFrames - PRInt32(offset), aAudio->mTime));
   aStream->mAudioFramesWritten += aAudio->mFrames - PRInt32(offset);
 }
 
-static void WriteVideoToMediaStream(Image* aImage,
+static void WriteVideoToMediaStream(mozilla::layers::Image* aImage,
                                     PRInt64 aDuration, const gfxIntSize& aIntrinsicSize,
                                     VideoSegment* aOutput)
 {
-  nsRefPtr<Image> image = aImage;
+  nsRefPtr<mozilla::layers::Image> image = aImage;
   aOutput->AppendFrame(image.forget(), aDuration, aIntrinsicSize);
 }
 
 static const TrackID TRACK_AUDIO = 1;
 static const TrackID TRACK_VIDEO = 2;
 static const TrackRate RATE_VIDEO = USECS_PER_S;
 
 void nsBuiltinDecoderStateMachine::SendOutputStreamData()
--- a/content/media/nsMediaDecoder.h
+++ b/content/media/nsMediaDecoder.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(nsMediaDecoder_h_)
 #define nsMediaDecoder_h_
 
-#include "ImageLayers.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "VideoFrameContainer.h"
 #include "MediaStreamGraph.h"
 
 class nsHTMLMediaElement;
 class nsIStreamListener;
 class nsTimeRanges;
 class nsIMemoryReporter;
@@ -33,18 +32,16 @@ static const PRUint32 FRAMEBUFFER_LENGTH
 static const PRUint32 FRAMEBUFFER_LENGTH_MAX = 16384;
 
 // All methods of nsMediaDecoder must be called from the main thread only
 // with the exception of GetVideoFrameContainer and GetStatistics,
 // which can be called from any thread.
 class nsMediaDecoder : public nsIObserver
 {
 public:
-  typedef mozilla::layers::Image Image;
-  typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   typedef mozilla::SourceMediaStream SourceMediaStream;
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
 
   nsMediaDecoder();
@@ -336,17 +333,17 @@ public:
   virtual void Resume(bool aForceBuffering) = 0;
 
   // Returns a weak reference to the media element we're decoding for,
   // if it's available.
   nsHTMLMediaElement* GetMediaElement();
 
   // Returns the current size of the framebuffer used in
   // MozAudioAvailable events.
-  PRUint32 GetFrameBufferLength() { return mFrameBufferLength; };
+  PRUint32 GetFrameBufferLength() { return mFrameBufferLength; }
 
   // Sets the length of the framebuffer used in MozAudioAvailable events.
   // The new size must be between 512 and 16384.
   virtual nsresult RequestFrameBufferLength(PRUint32 aLength);
 
   // Moves any existing channel loads into the background, so that they don't
   // block the load event. This is called when we stop delaying the load
   // event. Any new loads initiated (for example to seek) will also be in the
@@ -363,17 +360,17 @@ public:
   bool CanPlayThrough();
 
   // Returns the size, in bytes, of the heap memory used by the currently
   // queued decoded video and audio data.
   virtual PRInt64 VideoQueueMemoryInUse() = 0;
   virtual PRInt64 AudioQueueMemoryInUse() = 0;
 
   VideoFrameContainer* GetVideoFrameContainer() { return mVideoFrameContainer; }
-  ImageContainer* GetImageContainer()
+  mozilla::layers::ImageContainer* GetImageContainer()
   {
     return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nsnull;
   }
 
 protected:
 
   // Start timer to update download progress information.
   nsresult StartProgress();
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -36,19 +36,24 @@ void UpdateListIndicesFromIndex(nsTArray
 namespace mozilla {
 
 // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
 // clear our DOMSVGAnimatedLengthList's weak ref to us to be safe. (The other
 // option would be to not unlink and rely on the breaking of the other edges in
 // the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLengthList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLengthList)
-  // No need to null check tmp - script/SMIL can't detach us from mAList
-  ( tmp->IsAnimValList() ? tmp->mAList->mAnimVal : tmp->mAList->mBaseVal ) = nsnull;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+  if (tmp->mAList) {
+    if (tmp->IsAnimValList()) {
+      tmp->mAList->mAnimVal = nsnull;
+    } else {
+      tmp->mAList->mBaseVal = nsnull;
+    }
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+  }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLengthList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLengthList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
--- a/content/svg/content/src/DOMSVGNumberList.cpp
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -36,19 +36,24 @@ void UpdateListIndicesFromIndex(nsTArray
 } // namespace
 
 // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
 // clear our DOMSVGAnimatedNumberList's weak ref to us to be safe. (The other
 // option would be to not unlink and rely on the breaking of the other edges in
 // the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGNumberList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGNumberList)
-  // No need to null check tmp - script/SMIL can't detach us from mAList
-  ( tmp->IsAnimValList() ? tmp->mAList->mAnimVal : tmp->mAList->mBaseVal ) = nsnull;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+  if (tmp->mAList) {
+    if (tmp->IsAnimValList()) {
+      tmp->mAList->mAnimVal = nsnull;
+    } else {
+      tmp->mAList->mBaseVal = nsnull;
+    }
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+  }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGNumberList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGNumberList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
--- a/content/svg/content/src/DOMSVGTransformList.cpp
+++ b/content/svg/content/src/DOMSVGTransformList.cpp
@@ -32,20 +32,24 @@ void UpdateListIndicesFromIndex(
 namespace mozilla {
 
 // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
 // clear our DOMSVGAnimatedTransformList's weak ref to us to be safe. (The other
 // option would be to not unlink and rely on the breaking of the other edges in
 // the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGTransformList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGTransformList)
-  // No need to null check tmp - script/SMIL can't detach us from mAList
-  ( tmp->IsAnimValList() ? tmp->mAList->mAnimVal : tmp->mAList->mBaseVal ) =
-    nsnull;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+  if (tmp->mAList) {
+    if (tmp->IsAnimValList()) {
+      tmp->mAList->mAnimVal = nsnull;
+    } else {
+      tmp->mAList->mBaseVal = nsnull;
+    }
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+  }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGTransformList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGTransformList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
--- a/content/svg/content/src/nsSVGGraphicElement.cpp
+++ b/content/svg/content/src/nsSVGGraphicElement.cpp
@@ -232,17 +232,17 @@ nsSVGGraphicElement::GetAnimateMotionTra
 {
   return mAnimateMotionTransform.get();
 }
 
 void
 nsSVGGraphicElement::SetAnimateMotionTransform(const gfxMatrix* aMatrix)
 {
   if ((!aMatrix && !mAnimateMotionTransform) ||
-      aMatrix && mAnimateMotionTransform && *aMatrix == *mAnimateMotionTransform) {
+      (aMatrix && mAnimateMotionTransform && *aMatrix == *mAnimateMotionTransform)) {
     return;
   }
   mAnimateMotionTransform = aMatrix ? new gfxMatrix(*aMatrix) : nsnull;
   DidAnimateTransformList();
 }
 
 SVGAnimatedTransformList*
 nsSVGGraphicElement::GetAnimatedTransformList()
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -56,23 +56,26 @@ PRUint32 nsXBLPrototypeHandler::gRefCnt 
 
 PRInt32 nsXBLPrototypeHandler::kMenuAccessKey = -1;
 PRInt32 nsXBLPrototypeHandler::kAccelKey = -1;
 
 const PRInt32 nsXBLPrototypeHandler::cShift = (1<<0);
 const PRInt32 nsXBLPrototypeHandler::cAlt = (1<<1);
 const PRInt32 nsXBLPrototypeHandler::cControl = (1<<2);
 const PRInt32 nsXBLPrototypeHandler::cMeta = (1<<3);
+const PRInt32 nsXBLPrototypeHandler::cOS = (1<<4);
 
-const PRInt32 nsXBLPrototypeHandler::cShiftMask = (1<<4);
-const PRInt32 nsXBLPrototypeHandler::cAltMask = (1<<5);
-const PRInt32 nsXBLPrototypeHandler::cControlMask = (1<<6);
-const PRInt32 nsXBLPrototypeHandler::cMetaMask = (1<<7);
+const PRInt32 nsXBLPrototypeHandler::cShiftMask = (1<<5);
+const PRInt32 nsXBLPrototypeHandler::cAltMask = (1<<6);
+const PRInt32 nsXBLPrototypeHandler::cControlMask = (1<<7);
+const PRInt32 nsXBLPrototypeHandler::cMetaMask = (1<<8);
+const PRInt32 nsXBLPrototypeHandler::cOSMask = (1<<9);
 
-const PRInt32 nsXBLPrototypeHandler::cAllModifiers = cShiftMask | cAltMask | cControlMask | cMetaMask;
+const PRInt32 nsXBLPrototypeHandler::cAllModifiers =
+  cShiftMask | cAltMask | cControlMask | cMetaMask | cOSMask;
 
 nsXBLPrototypeHandler::nsXBLPrototypeHandler(const PRUnichar* aEvent,
                                              const PRUnichar* aPhase,
                                              const PRUnichar* aAction,
                                              const PRUnichar* aCommand,
                                              const PRUnichar* aKeyCode,
                                              const PRUnichar* aCharCode,
                                              const PRUnichar* aModifiers,
@@ -491,16 +494,18 @@ nsXBLPrototypeHandler::DispatchXULKeyCom
 
   // Copy the modifiers from the key event.
   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
   if (!keyEvent) {
     NS_ERROR("Trying to execute a key handler for a non-key event!");
     return NS_ERROR_FAILURE;
   }
 
+  // XXX We should use widget::Modifiers for supporting all modifiers.
+
   bool isAlt = false;
   bool isControl = false;
   bool isShift = false;
   bool isMeta = false;
   keyEvent->GetAltKey(&isAlt);
   keyEvent->GetCtrlKey(&isControl);
   keyEvent->GetShiftKey(&isShift);
   keyEvent->GetMetaKey(&isMeta);
@@ -641,21 +646,22 @@ PRInt32 nsXBLPrototypeHandler::GetMatchi
 }
 
 PRInt32 nsXBLPrototypeHandler::KeyToMask(PRInt32 key)
 {
   switch (key)
   {
     case nsIDOMKeyEvent::DOM_VK_META:
       return cMeta | cMetaMask;
-      break;
+
+    case nsIDOMKeyEvent::DOM_VK_WIN:
+      return cOS | cOSMask;
 
     case nsIDOMKeyEvent::DOM_VK_ALT:
       return cAlt | cAltMask;
-      break;
 
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     default:
       return cControl | cControlMask;
   }
   return cControl | cControlMask;  // for warning avoidance
 }
 
@@ -752,24 +758,26 @@ nsXBLPrototypeHandler::ConstructPrototyp
     char* token = nsCRT::strtok( str, ", \t", &newStr );
     while( token != NULL ) {
       if (PL_strcmp(token, "shift") == 0)
         mKeyMask |= cShift | cShiftMask;
       else if (PL_strcmp(token, "alt") == 0)
         mKeyMask |= cAlt | cAltMask;
       else if (PL_strcmp(token, "meta") == 0)
         mKeyMask |= cMeta | cMetaMask;
+      else if (PL_strcmp(token, "os") == 0)
+        mKeyMask |= cOS | cOSMask;
       else if (PL_strcmp(token, "control") == 0)
         mKeyMask |= cControl | cControlMask;
       else if (PL_strcmp(token, "accel") == 0)
         mKeyMask |= KeyToMask(kAccelKey);
       else if (PL_strcmp(token, "access") == 0)
         mKeyMask |= KeyToMask(kMenuAccessKey);
       else if (PL_strcmp(token, "any") == 0)
-        mKeyMask &= ~(mKeyMask << 4);
+        mKeyMask &= ~(mKeyMask << 5);
     
       token = nsCRT::strtok( newStr, ", \t", &newStr );
     }
 
     nsMemory::Free(str);
   }
 
   nsAutoString key(aCharCode);
@@ -848,59 +856,65 @@ nsXBLPrototypeHandler::ReportKeyConflict
                                   params, ArrayLength(params),
                                   nsnull, EmptyString(), mLineNumber);
 }
 
 bool
 nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
                                           bool aIgnoreShiftKey)
 {
-  nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
-  nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent));
+  nsEvent* event = aEvent->GetInternalNSEvent();
+  NS_ENSURE_TRUE(event && NS_IS_INPUT_EVENT(event), false);
+  nsInputEvent* inputEvent = static_cast<nsInputEvent*>(event);
 
-  bool keyPresent;
   if (mKeyMask & cMetaMask) {
-    key ? key->GetMetaKey(&keyPresent) : mouse->GetMetaKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cMeta) != 0))
+    if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
       return false;
+    }
+  }
+
+  if (mKeyMask & cOSMask) {
+    if (inputEvent->IsOS() != ((mKeyMask & cOS) != 0)) {
+      return false;
+    }
   }
 
   if (mKeyMask & cShiftMask && !aIgnoreShiftKey) {
-    key ? key->GetShiftKey(&keyPresent) : mouse->GetShiftKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cShift) != 0))
+    if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) {
       return false;
+    }
   }
 
   if (mKeyMask & cAltMask) {
-    key ? key->GetAltKey(&keyPresent) : mouse->GetAltKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cAlt) != 0))
+    if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) {
       return false;
+    }
   }
 
   if (mKeyMask & cControlMask) {
-    key ? key->GetCtrlKey(&keyPresent) : mouse->GetCtrlKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cControl) != 0))
+    if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) {
       return false;
+    }
   }
 
   return true;
 }
 
 nsresult
 nsXBLPrototypeHandler::Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream)
 {
   nsresult rv = aStream->Read8(&mPhase);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = aStream->Read8(&mKeyMask);
-  NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Read8(&mType);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Read8(&mMisc);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  rv = aStream->Read32(reinterpret_cast<PRUint32*>(&mKeyMask));
+  NS_ENSURE_SUCCESS(rv, rv);
   PRUint32 detail; 
   rv = aStream->Read32(&detail);
   NS_ENSURE_SUCCESS(rv, rv);
   mDetail = detail;
 
   nsAutoString name;
   rv = aStream->ReadString(name);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -926,22 +940,22 @@ nsXBLPrototypeHandler::Write(nsIScriptCo
   if ((mType & NS_HANDLER_TYPE_XUL) || !mEventName)
     return NS_OK;
 
   XBLBindingSerializeDetails type = XBLBinding_Serialize_Handler;
 
   nsresult rv = aStream->Write8(type);
   rv = aStream->Write8(mPhase);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = aStream->Write8(mKeyMask);
-  NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Write8(mType);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Write8(mMisc);
   NS_ENSURE_SUCCESS(rv, rv);
+  rv = aStream->Write32(static_cast<PRUint32>(mKeyMask));
+  NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Write32(mDetail);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aStream->Write32(mLineNumber);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/xbl/src/nsXBLPrototypeHandler.h
+++ b/content/xbl/src/nsXBLPrototypeHandler.h
@@ -167,47 +167,50 @@ protected:
   static PRInt32 kAccelKey;
   static PRInt32 kMenuAccessKey;
   static void InitAccessKeys();
 
   static const PRInt32 cShift;
   static const PRInt32 cAlt;
   static const PRInt32 cControl;
   static const PRInt32 cMeta;
+  static const PRInt32 cOS;
 
   static const PRInt32 cShiftMask;
   static const PRInt32 cAltMask;
   static const PRInt32 cControlMask;
   static const PRInt32 cMetaMask;
+  static const PRInt32 cOSMask;
 
   static const PRInt32 cAllModifiers;
 
 protected:
   union {
     nsIWeakReference* mHandlerElement;  // For XUL <key> element handlers. [STRONG]
     PRUnichar*        mHandlerText;     // For XBL handlers (we don't build an
                                         // element for the <handler>, and instead
                                         // we cache the JS text or command name
                                         // that we should use.
   };
 
   PRUint32 mLineNumber;  // The line number we started at in the XBL file
   
   // The following four values make up 32 bits.
   PRUint8 mPhase;            // The phase (capturing, bubbling)
-  PRUint8 mKeyMask;          // Which modifier keys this event handler expects to have down
-                             // in order to be matched.
   PRUint8 mType;             // The type of the handler.  The handler is either a XUL key
                              // handler, an XBL "command" event, or a normal XBL event with
                              // accompanying JavaScript.  The high bit is used to indicate
                              // whether this handler should prevent the default action.
   PRUint8 mMisc;             // Miscellaneous extra information.  For key events,
                              // stores whether or not we're a key code or char code.
                              // For mouse events, stores the clickCount.
 
+  PRInt32 mKeyMask;          // Which modifier keys this event handler expects to have down
+                             // in order to be matched.
+ 
   // The primary filter information for mouse/key events.
   PRInt32 mDetail;           // For key events, contains a charcode or keycode. For
                              // mouse events, stores the button info.
 
   // Prototype handlers are chained. We own the next handler in the chain.
   nsXBLPrototypeHandler* mNextHandler;
   nsCOMPtr<nsIAtom> mEventName; // The type of the event, e.g., "keypress"
   nsRefPtr<nsXBLEventHandler> mHandler;
--- a/dom/apps/src/AppsService.js
+++ b/dom/apps/src/AppsService.js
@@ -9,17 +9,16 @@ function debug(s) {
 }
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Webapps.jsm");
 
-const APPS_SERVICE_CONTRACTID = "@mozilla.org/AppsService;1";
 const APPS_SERVICE_CID        = Components.ID("{05072afa-92fe-45bf-ae22-39b69c117058}");
 
 function AppsService()
 {
   debug("AppsService Constructor");
 }
 
 AppsService.prototype = {
@@ -30,17 +29,11 @@ AppsService.prototype = {
 
   getAppLocalIdByManifestURL: function getAppLocalIdByManifestURL(aManifestURL) {
     debug("getAppLocalIdByManifestURL( " + aManifestURL + " )");
     return DOMApplicationRegistry.getAppLocalIdByManifestURL(aManifestURL);
   },
 
   classID : APPS_SERVICE_CID,
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService]),
-
-  classInfo : XPCOMUtils.generateCI({classID: APPS_SERVICE_CID,
-                                     contractID: APPS_SERVICE_CONTRACTID,
-                                     classDescription: "AppsService",
-                                     interfaces: [Ci.nsIAppsService],
-                                     flags: Ci.nsIClassInfo.DOM_OBJECT})
 }
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([AppsService])
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -153,16 +153,20 @@ Navigator::Invalidate()
     mSmsManager->Shutdown();
     mSmsManager = nsnull;
   }
 
 #ifdef MOZ_B2G_RIL
   if (mTelephony) {
     mTelephony = nsnull;
   }
+
+  if (mVoicemail) {
+    mVoicemail = nsnull;
+  }
 #endif
 
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nsnull;
   }
 
   if (mMobileConnection) {
@@ -1175,16 +1179,47 @@ Navigator::GetMozTelephony(nsIDOMTelepho
     // mTelephony may be null here!
     telephony = mTelephony;
   }
 
   telephony.forget(aTelephony);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+Navigator::GetMozVoicemail(nsIDOMMozVoicemail** aVoicemail)
+{
+  *aVoicemail = nsnull;
+
+  if (!mVoicemail) {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
+
+    // Chrome is always allowed access, so do the permission check only
+    // for non-chrome pages.
+    if (!nsContentUtils::IsCallerChrome()) {
+      nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
+      NS_ENSURE_TRUE(doc, NS_OK);
+
+      nsCOMPtr<nsIURI> uri;
+      doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
+
+      if (!nsContentUtils::URIIsChromeOrInPref(uri, "dom.voicemail.whitelist")) {
+        return NS_OK;
+      }
+    }
+
+    nsresult rv = NS_NewVoicemail(window, getter_AddRefs(mVoicemail));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  NS_ADDREF(*aVoicemail = mVoicemail);
+  return NS_OK;
+}
+
 #endif // MOZ_B2G_RIL
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorNetwork
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetMozConnection(nsIDOMMozConnection** aConnection)
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -27,16 +27,17 @@ class nsIDOMMozConnection;
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "nsIDOMNavigatorUserMedia.h"
 #endif
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMNavigatorTelephony.h"
 class nsIDOMTelephony;
+class nsIDOMMozVoicemail;
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "nsIDOMNavigatorBluetooth.h"
 #endif
 
 #include "nsIDOMNavigatorSystemMessages.h"
 
@@ -142,16 +143,17 @@ private:
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<nsGeolocation> mGeolocation;
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<power::PowerManager> mPowerManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
 #ifdef MOZ_B2G_RIL
   nsCOMPtr<nsIDOMTelephony> mTelephony;
+  nsCOMPtr<nsIDOMMozVoicemail> mVoicemail;
 #endif
   nsRefPtr<network::Connection> mConnection;
   nsRefPtr<network::MobileConnection> mMobileConnection;
 #ifdef MOZ_B2G_BT
   nsCOMPtr<nsIDOMBluetoothManager> mBluetooth;
 #endif
   nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
   nsWeakPtr mWindow;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -506,16 +506,18 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsIDOMMobileConnection.h"
 #include "USSDReceivedEvent.h"
 #include "mozilla/dom/network/Utils.h"
 
 #ifdef MOZ_B2G_RIL
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "CallEvent.h"
+#include "nsIDOMVoicemail.h"
+#include "nsIDOMVoicemailEvent.h"
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothManager.h"
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothDeviceEvent.h"
 #endif
@@ -1661,16 +1663,20 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(MozWifiConnectionInfoEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(MozVoicemail, nsEventTargetSH,
+                           EVENTTARGET_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(MozVoicemailEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
 #ifdef MOZ_B2G_BT
   NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)  
   NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
@@ -4474,16 +4480,26 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTelephonyCall)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CallEvent, nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(MozVoicemail, nsIDOMMozVoicemail)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozVoicemail)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(MozVoicemailEvent, nsIDOMMozVoicemailEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozVoicemailEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
+  DOM_CLASSINFO_MAP_END
 #endif
 
 #ifdef MOZ_B2G_BT
   DOM_CLASSINFO_MAP_BEGIN(BluetoothManager, nsIDOMBluetoothManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothManager)
   DOM_CLASSINFO_MAP_END  
 
   DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -518,16 +518,18 @@ DOMCI_CLASS(MozContactChangeEvent)
 DOMCI_CLASS(MozApplicationEvent)
 
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(MozWifiStatusChangeEvent)
 DOMCI_CLASS(MozWifiConnectionInfoEvent)
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
+DOMCI_CLASS(MozVoicemail)
+DOMCI_CLASS(MozVoicemailEvent)
 #endif
 
 #ifdef MOZ_B2G_BT
 DOMCI_CLASS(BluetoothManager)
 DOMCI_CLASS(BluetoothAdapter)
 DOMCI_CLASS(BluetoothDevice)
 DOMCI_CLASS(BluetoothDeviceEvent)
 #endif
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -420,10 +420,152 @@ ThrowingConstructor(JSContext* cx, unsig
 }
 
 JSBool
 ThrowingConstructorWorkers(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   return Throw<false>(cx, NS_ERROR_FAILURE);
 }
 
+bool
+XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
+                    JSPropertyDescriptor* desc,
+                    // And the things we need to determine the descriptor
+                    Prefable<JSFunctionSpec>* methods,
+                    jsid* methodIds,
+                    JSFunctionSpec* methodSpecs,
+                    size_t methodCount,
+                    Prefable<JSPropertySpec>* attributes,
+                    jsid* attributeIds,
+                    JSPropertySpec* attributeSpecs,
+                    size_t attributeCount,
+                    Prefable<ConstantSpec>* constants,
+                    jsid* constantIds,
+                    ConstantSpec* constantSpecs,
+                    size_t constantCount)
+{
+  for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) {
+    MOZ_ASSERT(methods[prefIdx].specs);
+    if (methods[prefIdx].enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = methods[prefIdx].specs - methodSpecs;
+      for ( ; methodIds[i] != JSID_VOID; ++i) {
+        if (id == methodIds[i]) {
+          JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call,
+                                               methodSpecs[i].nargs, 0,
+                                               wrapper, id);
+          if (!fun)
+              return false;
+          JSObject *funobj = JS_GetFunctionObject(fun);
+          desc->value.setObject(*funobj);
+          desc->attrs = methodSpecs[i].flags;
+          desc->obj = wrapper;
+          desc->setter = nsnull;
+          desc->getter = nsnull;
+          return true;
+        }
+      }
+    }
+  }
+
+  for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) {
+    MOZ_ASSERT(attributes[prefIdx].specs);
+    if (attributes[prefIdx].enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = attributes[prefIdx].specs - attributeSpecs;
+      for ( ; attributeIds[i] != JSID_VOID; ++i) {
+        if (id == attributeIds[i]) {
+          desc->attrs = attributeSpecs[i].flags;
+          desc->obj = wrapper;
+          desc->setter = attributeSpecs[i].setter;
+          desc->getter = attributeSpecs[i].getter;
+          return true;
+        }
+      }
+    }
+  }
+
+  for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) {
+    MOZ_ASSERT(constants[prefIdx].specs);
+    if (constants[prefIdx].enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = constants[prefIdx].specs - constantSpecs;
+      for ( ; constantIds[i] != JSID_VOID; ++i) {
+        if (id == constantIds[i]) {
+          desc->attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
+          desc->obj = wrapper;
+          desc->value = constantSpecs[i].value;
+          return true;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+bool
+XrayEnumerateProperties(JS::AutoIdVector& props,
+                        Prefable<JSFunctionSpec>* methods,
+                        jsid* methodIds,
+                        JSFunctionSpec* methodSpecs,
+                        size_t methodCount,
+                        Prefable<JSPropertySpec>* attributes,
+                        jsid* attributeIds,
+                        JSPropertySpec* attributeSpecs,
+                        size_t attributeCount,
+                        Prefable<ConstantSpec>* constants,
+                        jsid* constantIds,
+                        ConstantSpec* constantSpecs,
+                        size_t constantCount)
+{
+  for (size_t prefIdx = 0; prefIdx < methodCount; ++prefIdx) {
+    MOZ_ASSERT(methods[prefIdx].specs);
+    if (methods[prefIdx].enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = methods[prefIdx].specs - methodSpecs;
+      for ( ; methodIds[i] != JSID_VOID; ++i) {
+        if ((methodSpecs[i].flags & JSPROP_ENUMERATE) &&
+            !props.append(methodIds[i])) {
+          return false;
+        }
+      }
+    }
+  }
+
+  for (size_t prefIdx = 0; prefIdx < attributeCount; ++prefIdx) {
+    MOZ_ASSERT(attributes[prefIdx].specs);
+    if (attributes[prefIdx].enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = attributes[prefIdx].specs - attributeSpecs;
+      for ( ; attributeIds[i] != JSID_VOID; ++i) {
+        if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
+            !props.append(attributeIds[i])) {
+          return false;
+        }
+      }
+    }
+  }
+
+  for (size_t prefIdx = 0; prefIdx < constantCount; ++prefIdx) {
+    MOZ_ASSERT(constants[prefIdx].specs);
+    if (constants[prefIdx].enabled) {
+      // Set i to be the index into our full list of ids/specs that we're
+      // looking at now.
+      size_t i = constants[prefIdx].specs - constantSpecs;
+      for ( ; constantIds[i] != JSID_VOID; ++i) {
+        if (!props.append(constantIds[i])) {
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1003,12 +1003,45 @@ public:
     const T& Value() const {
       return *storage.addr();
     }
     void Destroy() {
       storage.addr()->~T();
     }
 };
 
+// Implementation of the bits that XrayWrapper needs
+bool
+XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
+                    JSPropertyDescriptor* desc,
+                    // And the things we need to determine the descriptor
+                    Prefable<JSFunctionSpec>* methods,
+                    jsid* methodIds,
+                    JSFunctionSpec* methodSpecs,
+                    size_t methodCount,
+                    Prefable<JSPropertySpec>* attributes,
+                    jsid* attributeIds,
+                    JSPropertySpec* attributeSpecs,
+                    size_t attributeCount,
+                    Prefable<ConstantSpec>* constants,
+                    jsid* constantIds,
+                    ConstantSpec* constantSpecs,
+                    size_t constantCount);
+
+bool
+XrayEnumerateProperties(JS::AutoIdVector& props,
+                        Prefable<JSFunctionSpec>* methods,
+                        jsid* methodIds,
+                        JSFunctionSpec* methodSpecs,
+                        size_t methodCount,
+                        Prefable<JSPropertySpec>* attributes,
+                        jsid* attributeIds,
+                        JSPropertySpec* attributeSpecs,
+                        size_t attributeCount,
+                        Prefable<ConstantSpec>* constants,
+                        jsid* constantIds,
+                        ConstantSpec* constantSpecs,
+                        size_t constantCount);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -764,21 +764,22 @@ class PropertyDefiner:
         return len(self.regular) > 0
     def variableName(self, chrome):
         if chrome and self.hasChromeOnly():
             return "sChrome" + self.name
         if self.hasNonChromeOnly():
             return "s" + self.name
         return "NULL"
     def usedForXrays(self, chrome):
-        # We only need Xrays for methods and attributes.  And we only need them
-        # for the non-chrome ones if we have no chromeonly things.  Otherwise
-        # (we have chromeonly attributes) we need Xrays for the chrome
-        # methods/attributes.  Finally, in workers there are no Xrays.
-        return ((self.name is "Methods" or self.name is "Attributes") and
+        # We only need Xrays for methods, attributes and constants.  And we only
+        # need them for the non-chrome ones if we have no chromeonly things.
+        # Otherwise (we have chromeonly attributes) we need Xrays for the chrome
+        # methods/attributes/constants.  Finally, in workers there are no Xrays.
+        return ((self.name is "Methods" or self.name is "Attributes" or
+                 self.name is "Constants") and
                 chrome == self.hasChromeOnly() and
                 not self.descriptor.workers)
 
     def __str__(self):
         # We only need to generate id arrays for things that will end
         # up used via ResolveProperty or EnumerateProperties.
         str = self.generateArray(self.regular, self.variableName(False),
                                  self.usedForXrays(False))
@@ -1007,17 +1008,17 @@ class PropertyArrays():
         self.consts = ConstDefiner(descriptor, "Constants")
 
     @staticmethod
     def arrayNames():
         return [ "staticMethods", "methods", "attrs", "consts" ]
 
     @staticmethod
     def xrayRelevantArrayNames():
-        return [ "methods", "attrs" ]
+        return [ "methods", "attrs", "consts" ]
 
     def hasChromeOnly(self):
         return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
                       self.arrayNames(), False)
     def variableNames(self, chrome):
         names = {}
         for array in self.arrayNames():
             names[array] = getattr(self, array).variableName(chrome)
@@ -3788,132 +3789,76 @@ class CGClass(CGThing):
         result = ''
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
         return result
 
-class CGResolveProperty(CGAbstractMethod):
-    def __init__(self, descriptor, properties):
-        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
-                Argument('jsid', 'id'), Argument('bool', 'set'),
-                Argument('JSPropertyDescriptor*', 'desc')]
-        CGAbstractMethod.__init__(self, descriptor, "ResolveProperty", "bool", args)
+class CGXrayHelper(CGAbstractMethod):
+    def __init__(self, descriptor, name, args, properties):
+        CGAbstractMethod.__init__(self, descriptor, name, "bool", args)
         self.properties = properties
+
     def definition_body(self):
-        str = ""
-
         varNames = self.properties.variableNames(True)
 
         methods = self.properties.methods
         if methods.hasNonChromeOnly() or methods.hasChromeOnly():
-            str += """  // %(methods)s has an end-of-list marker at the end that we ignore
-  for (size_t prefIdx = 0; prefIdx < ArrayLength(%(methods)s)-1; ++prefIdx) {
-    MOZ_ASSERT(%(methods)s[prefIdx].specs);
-    if (%(methods)s[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = %(methods)s[prefIdx].specs - %(methods)s_specs;
-      for ( ; %(methods)s_ids[i] != JSID_VOID; ++i) {
-        if (id == %(methods)s_ids[i]) {
-          JSFunction *fun = JS_NewFunctionById(cx, %(methods)s_specs[i].call, %(methods)s_specs[i].nargs, 0, wrapper, id);
-          if (!fun)
-              return false;
-          JSObject *funobj = JS_GetFunctionObject(fun);
-          desc->value.setObject(*funobj);
-          desc->attrs = %(methods)s_specs[i].flags;
-          desc->obj = wrapper;
-          desc->setter = nsnull;
-          desc->getter = nsnull;
-          return true;
-        }
-      }
-    }
-  }
-
-""" % varNames
+            methodArgs = """// %(methods)s has an end-of-list marker at the end that we ignore
+%(methods)s, %(methods)s_ids, %(methods)s_specs, ArrayLength(%(methods)s) - 1""" % varNames
+        else:
+            methodArgs = "NULL, NULL, NULL, 0"
+        methodArgs = CGGeneric(methodArgs)
 
         attrs = self.properties.attrs
         if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
-            str += """  // %(attrs)s has an end-of-list marker at the end that we ignore
-  for (size_t prefIdx = 0; prefIdx < ArrayLength(%(attrs)s)-1; ++prefIdx) {
-    MOZ_ASSERT(%(attrs)s[prefIdx].specs);
-    if (%(attrs)s[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = %(attrs)s[prefIdx].specs - %(attrs)s_specs;;
-      for ( ; %(attrs)s_ids[i] != JSID_VOID; ++i) {
-        if (id == %(attrs)s_ids[i]) {
-          desc->attrs = %(attrs)s_specs[i].flags;
-          desc->obj = wrapper;
-          desc->setter = %(attrs)s_specs[i].setter;
-          desc->getter = %(attrs)s_specs[i].getter;
-          return true;
-        }
-      }
-    }
-  }
-
-""" % varNames
-
-        return str + "  return true;"
-
-class CGEnumerateProperties(CGAbstractMethod):
+            attrArgs = """// %(attrs)s has an end-of-list marker at the end that we ignore
+%(attrs)s, %(attrs)s_ids, %(attrs)s_specs, ArrayLength(%(attrs)s) - 1""" % varNames
+        else:
+            attrArgs = "NULL, NULL, NULL, 0"
+        attrArgs = CGGeneric(attrArgs)
+
+        consts = self.properties.consts
+        if consts.hasNonChromeOnly() or consts.hasChromeOnly():
+            constArgs = """// %(consts)s has an end-of-list marker at the end that we ignore
+%(consts)s, %(consts)s_ids, %(consts)s_specs, ArrayLength(%(consts)s) - 1""" % varNames
+        else:
+            constArgs = "NULL, NULL, NULL, 0"
+        constArgs = CGGeneric(constArgs)
+
+        prefixArgs = CGGeneric(self.getPrefixArgs())
+
+        return CGIndenter(
+            CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ",\n"),
+                      pre=("return Xray%s(" % self.name),
+                      post=");",
+                      reindent=True)).define()
+
+class CGResolveProperty(CGXrayHelper):
+    def __init__(self, descriptor, properties):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
+                Argument('jsid', 'id'), Argument('bool', 'set'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
+                              properties)
+
+    def getPrefixArgs(self):
+        return "cx, wrapper, id, desc"
+
+
+class CGEnumerateProperties(CGXrayHelper):
     def __init__(self, descriptor, properties):
         args = [Argument('JS::AutoIdVector&', 'props')]
-        CGAbstractMethod.__init__(self, descriptor, "EnumerateProperties", "bool", args)
-        self.properties = properties
-    def definition_body(self):
-        str = ""
-
-        varNames = self.properties.variableNames(True)
-
-        methods = self.properties.methods
-        if methods.hasNonChromeOnly() or methods.hasChromeOnly():
-            str += """  // %(methods)s has an end-of-list marker at the end that we ignore
-  for (size_t prefIdx = 0; prefIdx < ArrayLength(%(methods)s)-1; ++prefIdx) {
-    MOZ_ASSERT(%(methods)s[prefIdx].specs);
-    if (%(methods)s[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = %(methods)s[prefIdx].specs - %(methods)s_specs;
-      for ( ; %(methods)s_ids[i] != JSID_VOID; ++i) {
-        if ((%(methods)s_specs[i].flags & JSPROP_ENUMERATE) &&
-            !props.append(%(methods)s_ids[i])) {
-          return false;
-        }
-      }
-    }
-  }
-
-""" % varNames
-
-        attrs = self.properties.attrs
-        if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
-            str += """  // %(attrs)s has an end-of-list marker at the end that we ignore
-  for (size_t prefIdx = 0; prefIdx < ArrayLength(%(attrs)s)-1; ++prefIdx) {
-    MOZ_ASSERT(%(attrs)s[prefIdx].specs);
-    if (%(attrs)s[prefIdx].enabled) {
-      // Set i to be the index into our full list of ids/specs that we're
-      // looking at now.
-      size_t i = %(attrs)s[prefIdx].specs - %(attrs)s_specs;;
-      for ( ; %(attrs)s_ids[i] != JSID_VOID; ++i) {
-        if ((%(attrs)s_specs[i].flags & JSPROP_ENUMERATE) &&
-            !props.append(%(attrs)s_ids[i])) {
-          return false;
-        }
-      }
-    }
-  }
-
-""" % varNames
-
-        return str + "  return true;"
+        CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
+                              properties)
+
+    def getPrefixArgs(self):
+        return "props"
 
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_bluetooth_bluetoothmanager_h__
 #define mozilla_dom_bluetooth_bluetoothmanager_h__
 
 #include "BluetoothCommon.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothManager.h"
 #include "mozilla/Observer.h"
+#include "nsIEventTarget.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothManager : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothManager
                        , public BluetoothSignalObserver
 {
 public:
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -117,16 +117,17 @@ BrowserElementChild.prototype = {
 
     addMsgListener("get-screenshot", this._recvGetScreenshot);
     addMsgListener("set-visible", this._recvSetVisible);
     addMsgListener("get-can-go-back", this._recvCanGoBack);
     addMsgListener("get-can-go-forward", this._recvCanGoForward);
     addMsgListener("go-back", this._recvGoBack);
     addMsgListener("go-forward", this._recvGoForward);
     addMsgListener("reload", this._recvReload);
+    addMsgListener("stop", this._recvStop);
     addMsgListener("unblock-modal-prompt", this._recvStopWaiting);
     addMsgListener("fire-ctx-callback", this._recvFireCtxCallback);
 
     let els = Cc["@mozilla.org/eventlistenerservice;1"]
                 .getService(Ci.nsIEventListenerService);
 
     // We are using the system group for those events so if something in the
     // content called .stopPropagation() this will still be called.
@@ -476,16 +477,21 @@ BrowserElementChild.prototype = {
       webNav.LOAD_FLAGS_NONE;
     try {
       webNav.reload(reloadFlags);
     } catch(e) {
       // Silently swallow errors; these can happen if a used cancels reload
     }
   },
 
+  _recvStop: function(data) {
+    let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+    webNav.stop(webNav.STOP_NETWORK);
+  },
+
   _keyEventHandler: function(e) {
     if (whitelistedEvents.indexOf(e.keyCode) != -1 && !e.defaultPrevented) {
       sendAsyncMsg('keyevent', {
         type: e.type,
         keyCode: e.keyCode,
         charCode: e.charCode,
       });
     }
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -164,16 +164,17 @@ function BrowserElementParent(frameLoade
     XPCNativeWrapper.unwrap(self._frameElement)[domName] = self._sendDOMRequest.bind(self, msgName);
   }
 
   // Define methods on the frame element.
   defineMethod('setVisible', this._setVisible);
   defineMethod('goBack', this._goBack);
   defineMethod('goForward', this._goForward);
   defineMethod('reload', this._reload);
+  defineMethod('stop', this._stop);
   defineDOMRequestMethod('getScreenshot', 'get-screenshot');
   defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
   defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
 }
 
 BrowserElementParent.prototype = {
   get _window() {
     return this._frameElement.ownerDocument.defaultView;
@@ -336,16 +337,20 @@ BrowserElementParent.prototype = {
   _goForward: function() {
     this._sendAsyncMsg('go-forward');
   },
 
   _reload: function(hardReload) {
     this._sendAsyncMsg('reload', {hardReload: hardReload});
   },
 
+  _stop: function() {
+    this._sendAsyncMsg('stop');
+  },
+
   _fireKeyEvent: function(data) {
     let evt = this._window.document.createEvent("KeyboardEvent");
     evt.initKeyEvent(data.json.type, true, true, this._window,
                      false, false, false, false, // modifiers
                      data.json.keyCode,
                      data.json.charCode);
 
     this._frameElement.dispatchEvent(evt);
--- a/dom/browser-element/mochitest/Makefile.in
+++ b/dom/browser-element/mochitest/Makefile.in
@@ -76,16 +76,19 @@ MOCHITEST_FILES = \
 		test_browserElement_inproc_OpenWindowRejected.html \
 		file_browserElement_OpenWindowRejected.html \
 		browserElement_SecurityChange.js \
 		test_browserElement_inproc_SecurityChange.html \
 		file_browserElement_SecurityChange.html \
 		browserElement_BackForward.js \
 	        file_bug741717.sjs \
 		browserElement_Reload.js \
+	        file_bug709759.sjs \
+		browserElement_Stop.js \
+                test_browserElement_inproc_Stop.html \
                 browserElement_ContextmenuEvents.js \
                 test_browserElement_inproc_ContextmenuEvents.html \
 		$(NULL)
 
 # Disabled due to https://bugzilla.mozilla.org/show_bug.cgi?id=774100
 #		test_browserElement_inproc_Reload.html \
 
 # OOP tests don't work on Windows (bug 763081) or native-fennec (bug
@@ -114,15 +117,16 @@ MOCHITEST_FILES += \
 		test_browserElement_oop_Close.html \
 		test_browserElement_oop_CloseFromOpener.html \
 		test_browserElement_oop_OpenWindow.html \
 		test_browserElement_oop_OpenWindowInFrame.html \
 		test_browserElement_oop_OpenWindowRejected.html \
 		test_browserElement_oop_SecurityChange.html \
 		test_browserElement_oop_BackForward.html \
 		test_browserElement_oop_Reload.html \
+		test_browserElement_oop_Stop.html \
                 test_browserElement_oop_ContextmenuEvents.html \
 		$(NULL)
 endif #}
 endif #}
 
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Stop.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 709759 - Test the stop ability of <iframe mozbrowser>.
+
+// The img that is loaded will never be returned and will block
+// the page from loading, the timeout ensures that the page is
+// actually blocked from loading, once stop is called the
+// image load will be cancaelled and mozbrowserloadend should be called.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+
+var iframe;
+var stopped = false;
+var imgSrc = 'http://test/tests/dom/browser-element/mochitest/file_bug709759.sjs';
+
+function runTest() {
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addToWhitelist();
+
+  iframe = document.createElement('iframe');
+  iframe.mozbrowser = true;
+
+  iframe.addEventListener('mozbrowserloadend', loadend);
+  iframe.src = 'data:text/html,<html>' +
+    '<body><img src="' + imgSrc + '" /></body></html>';
+
+  document.body.appendChild(iframe);
+
+  setTimeout(function() {
+    stopped = true;
+    iframe.stop();
+  }, 200);
+}
+
+function loadend() {
+  ok(stopped, 'Iframes network connections were stopped');
+  SimpleTest.finish();
+}
+
+runTest();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/file_bug709759.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+  response.processAsync();
+  response.setHeader("Content-Type", "image/jpeg", false);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Stop.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test of browser element.</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Stop.js">
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Stop.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test of browser element.</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_Stop.js">
+</script>
+</body>
+</html>
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -20,16 +20,20 @@
 #include "nsContentUtils.h"
 #include "nsXULAppAPI.h"
 #include "TabChild.h"
 #include "DeviceStorageRequestChild.h"
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
+#ifdef MOZ_WIDGET_GONK
+#include "nsIVolumeService.h"
+#endif
+
 using namespace mozilla::dom;
 using namespace mozilla::dom::devicestorage;
 
 #include "nsDirectoryServiceDefs.h"
 
 DeviceStorageFile::DeviceStorageFile(nsIFile* aFile, const nsAString& aPath)
   : mPath(aPath)
   , mEditable(false)
@@ -265,25 +269,36 @@ nsDOMDeviceStorage::SetRootFileForType(c
 {
   PRInt32 typeResult = DEVICE_STORAGE_TYPE_DEFAULT;
 
   nsCOMPtr<nsIFile> f;
   nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   NS_ASSERTION(dirService, "Must have directory service");
 
 #ifdef MOZ_WIDGET_GONK
-  // check that /sdcard exists, if it doesn't go no further.
-  NS_NewLocalFile(NS_LITERAL_STRING("/sdcard"), false, getter_AddRefs(f));
-  bool check = false;
-  f->Exists(&check);
-  if (!check) {
-    mFile = nsnull;
+  mFile = nsnull;
+
+  nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
+  if (!vs) {
     return typeResult;
   }
-  f = nsnull;
+
+  nsCOMPtr<nsIVolume> v;
+  vs->GetVolumeByPath(NS_LITERAL_STRING("/sdcard"), getter_AddRefs(v));
+  
+  if (!v) {
+    return typeResult;
+  }
+
+  PRInt32 state;
+  v->GetState(&state);
+
+  if (state != nsIVolume::STATE_MOUNTED) {
+    return typeResult;
+  }
 #endif
 
   // Picture directory
   if (aType.Equals(NS_LITERAL_STRING("pictures"))) {
 #ifdef MOZ_WIDGET_GONK
     if (aIndex == 0) {
       NS_NewLocalFile(NS_LITERAL_STRING("/sdcard/DCIM"), false, getter_AddRefs(f));
     }
--- a/dom/file/FileHelper.h
+++ b/dom/file/FileHelper.h
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_file_filehelper_h__
 #define mozilla_dom_file_filehelper_h__
 
 #include "FileCommon.h"
 
 #include "nsIRequestObserver.h"
+#include "nsThreadUtils.h"
 
 class nsIFileStorage;
 
 BEGIN_FILE_NAMESPACE
 
 class FileHelper;
 class FileRequest;
 class FileOutputStreamWrapper;
--- a/dom/indexedDB/ipc/Makefile.in
+++ b/dom/indexedDB/ipc/Makefile.in
@@ -26,18 +26,17 @@ EXPORTS_mozilla/dom/indexedDB = Serializ
 
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/indexedDB \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
-# Bug 770046 - Cannot fail.
-# MOCHITEST_FILES = test_ipc.html
+MOCHITEST_FILES = test_ipc.html
 
 # Need to enable these tests sometime soon.
 #XPCSHELL_TESTS = unit
 
 # We're copying tests from another directory so this check is wrong for us.
 #NO_XPCSHELL_MANIFEST_CHECK = 1
 
 include $(topsrcdir)/config/config.mk
--- a/dom/indexedDB/test/head.js
+++ b/dom/indexedDB/test/head.js
@@ -53,16 +53,20 @@ function triggerMainCommand(popup)
 
 function triggerSecondaryCommand(popup, index)
 {
   info("triggering secondary command, " + index);
   let notifications = popup.childNodes;
   ok(notifications.length > 0, "at least one notification displayed");
   let notification = notifications[0];
 
+  // Cancel the arrow panel slide-in transition (bug 767133) such that
+  // it won't interfere with us interacting with the dropdown.
+  document.getAnonymousNodes(popup)[0].style.transition = "none";
+
   notification.button.focus();
 
   popup.addEventListener("popupshown", function () {
     popup.removeEventListener("popupshown", arguments.callee, false);
 
     // Press down until the desired command is selected
     for (let i = 0; i <= index; i++)
       EventUtils.synthesizeKey("VK_DOWN", {});
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -15,17 +15,17 @@ include protocol PIndexedDB;
 
 include "mozilla/dom/TabMessageUtils.h";
 include "gfxMatrix.h";
 include "mozilla/net/NeckoMessageUtils.h";
 include "IPC/nsGUIEventIPC.h";
 
 using IPC::URI;
 using gfxMatrix;
-using mozilla::LayersBackend;
+using mozilla::layers::LayersBackend;
 using mozilla::WindowsHandle;
 using nscolor;
 using nsCompositionEvent;
 using nsIMEUpdatePreference;
 using nsIntSize;
 using nsKeyEvent;
 using nsMouseEvent;
 using nsMouseScrollEvent;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1025,17 +1025,17 @@ TabChild::InitWidget(const nsIntSize& si
     }
     mWidget->Create(
         nsnull, 0,              // no parents
         nsIntRect(nsIntPoint(0, 0), size),
         nsnull,                 // HandleWidgetEvent
         nsnull                  // nsDeviceContext
         );
 
-    LayerManager::LayersBackend be;
+    LayersBackend be;
     uint64_t id;
     int32_t maxTextureSize;
     RenderFrameChild* remoteFrame =
         static_cast<RenderFrameChild*>(SendPRenderFrameConstructor(
                                            &be, &maxTextureSize, &id));
     if (!remoteFrame) {
       NS_WARNING("failed to construct RenderFrame");
       return false;
--- a/dom/settings/SettingsService.js
+++ b/dom/settings/SettingsService.js
@@ -128,19 +128,17 @@ SettingsServiceLock.prototype = {
 
   classInfo : XPCOMUtils.generateCI({classID: SETTINGSSERVICELOCK_CID,
                                      contractID: SETTINGSSERVICELOCK_CONTRACTID,
                                      classDescription: "SettingsServiceLock",
                                      interfaces: [nsISettingsServiceLock],
                                      flags: nsIClassInfo.DOM_OBJECT})
 };
 
-const SETTINGSSERVICE_CONTRACTID = "@mozilla.org/settingsService;1";
 const SETTINGSSERVICE_CID        = Components.ID("{3458e760-8513-11e1-b0c4-0800200c9a66}");
-const nsISettingsService         = Ci.nsISettingsService;
 
 let myGlobal = this;
 
 function SettingsService()
 {
   debug("settingsService Constructor");
   this._locks = new Queue();
   var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
@@ -166,18 +164,12 @@ SettingsService.prototype = {
       function() { lock.createTransactionAndProcess(); },
       function() { dump("ensureDB error cb!\n"); },
       myGlobal );
     this.nextTick(function() { this._open = false; }, lock);
     return lock;
   },
 
   classID : SETTINGSSERVICE_CID,
-  QueryInterface : XPCOMUtils.generateQI([nsISettingsService]),
-
-  classInfo : XPCOMUtils.generateCI({classID: SETTINGSSERVICE_CID,
-                                     contractID: SETTINGSSERVICE_CONTRACTID,
-                                     classDescription: "SettingsService",
-                                     interfaces: [nsISettingsService],
-                                     flags: nsIClassInfo.DOM_OBJECT})
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService]),
 }
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock])
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -17,27 +17,30 @@ Cu.import("resource://gre/modules/ril_co
 const DEBUG = RIL.DEBUG_CONTENT_HELPER;
 
 const RILCONTENTHELPER_CID =
   Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
 const MOBILECONNECTIONINFO_CID =
   Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
 const MOBILENETWORKINFO_CID =
   Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}");
+const VOICEMAILSTATUS_CID=
+  Components.ID("{5467f2eb-e214-43ea-9b89-67711241ec8e}");
 
 const RIL_IPC_MSG_NAMES = [
   "RIL:CardStateChanged",
   "RIL:VoiceInfoChanged",
   "RIL:DataInfoChanged",
   "RIL:EnumerateCalls",
   "RIL:GetAvailableNetworks",
   "RIL:NetworkSelectionModeChanged",
   "RIL:SelectNetwork",
   "RIL:SelectNetworkAuto",
   "RIL:CallStateChanged",
+  "RIL:VoicemailNotification",
   "RIL:CallError",
   "RIL:GetCardLock:Return:OK",
   "RIL:GetCardLock:Return:KO",
   "RIL:SetCardLock:Return:OK",
   "RIL:SetCardLock:Return:KO",
   "RIL:UnlockCardLock:Return:OK",
   "RIL:UnlockCardLock:Return:KO",
   "RIL:UssdReceived",
@@ -93,16 +96,35 @@ MobileNetworkInfo.prototype = {
 
   shortName: null,
   longName: null,
   mcc: 0,
   mnc: 0,
   state: null
 };
 
+function VoicemailStatus() {}
+VoicemailStatus.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]),
+  classID:        VOICEMAILSTATUS_CID,
+  classInfo:      XPCOMUtils.generateCI({
+    classID:          VOICEMAILSTATUS_CID,
+    classDescription: "VoicemailStatus",
+    flags:            Ci.nsIClassInfo.DOM_OBJECT,
+    interfaces:       [Ci.nsIDOMMozVoicemailStatus]
+  }),
+
+  // nsIDOMMozVoicemailStatus
+
+  hasMessages: false,
+  messageCount: Ci.nsIDOMMozVoicemailStatus.MESSAGE_COUNT_UNKNOWN,
+  returnNumber: null,
+  returnMessage: null
+};
+
 function RILContentHelper() {
   this.voiceConnectionInfo = new MobileConnectionInfo();
   this.dataConnectionInfo = new MobileConnectionInfo();
 
   this.initRequests();
   this.initMessageListener(RIL_IPC_MSG_NAMES);
   Services.obs.addObserver(this, "xpcom-shutdown", false);
 
@@ -307,39 +329,62 @@ RILContentHelper.prototype = {
     }
     let request = Services.DOMRequest.createRequest(window);
     let requestId = this.getRequestId(request);
     cpmm.sendAsyncMessage("RIL:CancelUSSD", {requestId: requestId});
     return request;
   },
 
   _telephonyCallbacks: null,
-  _enumerationTelephonyCallbacks: null,
+  _voicemailCallbacks: null,
+  _enumerateTelephonyCallbacks: null,
+
+  voicemailStatus: null,
+
+  registerCallback: function registerCallback(callbackType, callback) {
+    let callbacks = this[callbackType];
+    if (!callbacks) {
+      callbacks = this[callbackType] = [];
+    }
+
+    if (callbacks.indexOf(callback) != -1) {
+      throw new Error("Already registered this callback!");
+    }
+
+    callbacks.push(callback);
+    if (DEBUG) debug("Registered " + callbackType + " callback: " + callback);
+  },
+
+  unregisterCallback: function unregisterCallback(callbackType, callback) {
+    let callbacks = this[callbackType];
+    if (!callbacks) {
+      return;
+    }
+
+    let index = callbacks.indexOf(callback);
+    if (index != -1) {
+      callbacks.splice(index, 1);
+      if (DEBUG) debug("Unregistered telephony callback: " + callback);
+    }
+  },
 
   registerTelephonyCallback: function registerTelephonyCallback(callback) {
-    if (this._telephonyCallbacks) {
-      if (this._telephonyCallbacks.indexOf(callback) != -1) {
-        throw new Error("Already registered this callback!");
-      }
-    } else {
-      this._telephonyCallbacks = [];
-    }
-    this._telephonyCallbacks.push(callback);
-    debug("Registered telephony callback: " + callback);
+    this.registerCallback("_telephonyCallbacks", callback);
+  },
+
+  unregisterTelephonyCallback: function unregisteTelephonyCallback(callback) {
+    this.unregisterCallback("_telephonyCallbacks", callback);
   },
 
-  unregisterTelephonyCallback: function unregisterTelephonyCallback(callback) {
-    if (!this._telephonyCallbacks) {
-      return;
-    }
-    let index = this._telephonyCallbacks.indexOf(callback);
-    if (index != -1) {
-      this._telephonyCallbacks.splice(index, 1);
-      debug("Unregistered telephony callback: " + callback);
-    }
+  registerVoicemailCallback: function registerVoicemailCallback(callback) {
+    this.registerCallback("_voicemailCallbacks", callback);
+  },
+
+  unregisterVoicemailCallback: function unregisteVoicemailCallback(callback) {
+    this.unregisterCallback("_voicemailCallbacks", callback);
   },
 
   enumerateCalls: function enumerateCalls(callback) {
     debug("Requesting enumeration of calls for callback: " + callback);
     cpmm.sendAsyncMessage("RIL:EnumerateCalls");
     if (!this._enumerationTelephonyCallbacks) {
       this._enumerationTelephonyCallbacks = [];
     }
@@ -482,24 +527,29 @@ RILContentHelper.prototype = {
         this.handleSelectNetwork(msg.json,
                                  RIL.GECKO_NETWORK_SELECTION_MANUAL);
         break;
       case "RIL:SelectNetworkAuto":
         this.handleSelectNetwork(msg.json,
                                  RIL.GECKO_NETWORK_SELECTION_AUTOMATIC);
         break;
       case "RIL:CallStateChanged":
-        this._deliverTelephonyCallback("callStateChanged",
-                                       [msg.json.callIndex, msg.json.state,
-                                        msg.json.number, msg.json.isActive]);
+        this._deliverCallback("_telephonyCallbacks",
+                              "callStateChanged",
+                              [msg.json.callIndex, msg.json.state,
+                               msg.json.number, msg.json.isActive]);
         break;
       case "RIL:CallError":
-        this._deliverTelephonyCallback("notifyError",
-                                        [msg.json.callIndex,
-                                         msg.json.error]);
+        this._deliverCallback("_telephonyCallbacks",
+                              "notifyError",
+                              [msg.json.callIndex,
+                               msg.json.error]);
+        break;
+      case "RIL:VoicemailNotification":
+        this.handleVoicemailNotification(msg.json);
         break;
       case "RIL:GetCardLock:Return:OK":
       case "RIL:SetCardLock:Return:OK":
       case "RIL:UnlockCardLock:Return:OK":
         this.fireRequestSuccess(msg.json.requestId, msg.json);
         break;
       case "RIL:GetCardLock:Return:KO":
       case "RIL:SetCardLock:Return:KO":
@@ -585,37 +635,71 @@ RILContentHelper.prototype = {
 
     if (message.error) {
       this.fireRequestError(message.requestId, message.error);
     } else {
       this.fireRequestSuccess(message.requestId, null);
     }
   },
 
-  _deliverTelephonyCallback: function _deliverTelephonyCallback(name, args) {
-    if (!this._telephonyCallbacks) {
+  handleVoicemailNotification: function handleVoicemailNotification(message) {
+    let changed = false;
+    if (!this.voicemailStatus) {
+      this.voicemailStatus = new VoicemailStatus();
+    }
+
+    if (this.voicemailStatus.hasMessages != message.active) {
+      changed = true;
+      this.voicemailStatus.hasMessages = message.active;
+    }
+
+    if (this.voicemailStatus.messageCount != message.msgCount) {
+      changed = true;
+      this.voicemailStatus.messageCount = message.msgCount;
+    }
+
+    if (this.voicemailStatus.returnNumber != message.returnNumber) {
+      changed = true;
+      this.voicemailStatus.returnNumber = message.returnNumber;
+    }
+
+    if (this.voicemailStatus.returnMessage != message.returnMessage) {
+      changed = true;
+      this.voicemailStatus.returnMessage = message.returnMessage;
+    }
+
+    if (changed) {
+      this._deliverCallback("_voicemailCallbacks",
+                            "voicemailNotification",
+                            [this.voicemailStatus]);
+    }
+  },
+
+  _deliverCallback: function _deliverCallback(callbackType, name, args) {
+    let thisCallbacks = this[callbackType];
+    if (!thisCallbacks) {
       return;
     }
 
-    let callbacks = this._telephonyCallbacks.slice();
+    let callbacks = thisCallbacks.slice();
     for each (let callback in callbacks) {
-      if (this._telephonyCallbacks.indexOf(callback) == -1) {
+      if (thisCallbacks.indexOf(callback) == -1) {
         continue;
       }
       let handler = callback[name];
       if (typeof handler != "function") {
         throw new Error("No handler for " + name);
       }
       try {
         handler.apply(callback, args);
       } catch (e) {
         debug("callback handler for " + name + " threw an exception: " + e);
       }
     }
-  },
+  }
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- RILContentHelper: " + s + "\n");
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -775,26 +775,40 @@ RadioInterfaceLayer.prototype = {
       return;
     }
 
     if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
       // Don't know how to handle binary data yet.
       return;
     }
 
+    // TODO: Bug #768441
+    // For now we don't store indicators persistently. When the mwi.discard
+    // flag is false, we'll need to persist the indicator to EFmwis.
+    // See TS 23.040 9.2.3.24.2
+
+    let mwi = message.mwi;
+    if (mwi) {
+      mwi.returnNumber = message.sender || null;
+      mwi.returnMessage = message.fullBody || null;
+      ppmm.sendAsyncMessage("RIL:VoicemailNotification", mwi);
+      return;
+    }
+
     let id = gSmsDatabaseService.saveReceivedMessage(message.sender || null,
                                                      message.fullBody || null,
                                                      message.timestamp);
     let sms = gSmsService.createSmsMessage(id,
                                            DOM_SMS_DELIVERY_RECEIVED,
                                            message.sender || null,
                                            message.receiver || null,
                                            message.fullBody || null,
                                            message.timestamp,
                                            false);
+
     Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
   },
 
   /**
    * Local storage for sent SMS messages.
    */
   _sentSmsEnvelopes: null,
   createSmsEnvelope: function createSmsEnvelope(options) {
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIMobileConnectionProvider.idl"
 
 interface nsIDOMMozMobileConnectionInfo;
 interface nsIDOMDOMRequest;
 interface nsIDOMWindow;
+interface nsIDOMMozVoicemailStatus;
 
 [scriptable, uuid(c14c71b8-afba-403b-8320-94593de9380f)]
 interface nsIRILTelephonyCallback : nsISupports
 {
   /**
    * Notified when a telephony call changes state.
    *
    * @param callIndex
@@ -57,16 +58,28 @@ interface nsIRILTelephonyCallback : nsIS
    *        Call identifier assigned by the RIL. -1 if no connection
    * @param error
    *        Error from RIL.
    */
   void notifyError(in long callIndex,
                    in AString error);
 };
 
+[scriptable, uuid(3ac98987-a63c-4ebe-adbd-ff7a0348d804)]
+interface nsIRILVoicemailCallback : nsISupports
+{
+  /**
+   * Called when a voicemail notification has been received by the network.
+   *
+   * @param status
+   *        The new voicemail status
+   */
+  void voicemailNotification(in nsIDOMMozVoicemailStatus status);
+};
+
 [scriptable, uuid(8a711703-1ee5-4675-9d9a-0b188e944cfe)]
 interface nsIRILDataCallInfo : nsISupports
 {
   /**
    * Current data call state, one of the
    * nsINetworkInterface::NETWORK_STATE_* constants.
    */
   readonly attribute unsigned long state;
@@ -112,22 +125,25 @@ interface nsIRILContactCallback : nsISup
    */
   void receiveContactsList(in DOMString type, in jsval contacts);
 };
 
 /**
  * Helper that runs in the content process and exposes information
  * to the DOM.
  */
-[scriptable, uuid(2f8b0929-2ecf-498c-bfa7-42690509696e)]
+[scriptable, uuid(d2ec602f-9746-4ada-b0c6-f1c1a3cf3578)]
 interface nsIRILContentHelper : nsIMobileConnectionProvider
 {
   void registerTelephonyCallback(in nsIRILTelephonyCallback callback);
   void unregisterTelephonyCallback(in nsIRILTelephonyCallback callback);
 
+  void registerVoicemailCallback(in nsIRILVoicemailCallback callback);
+  void unregisterVoicemailCallback(in nsIRILVoicemailCallback callback);
+
   /**
    * Will continue calling callback.enumerateCallState until the callback
    * returns false.
    */
   void enumerateCalls(in nsIRILTelephonyCallback callback);
 
   /**
    * Functionality for making and managing phone calls.
@@ -140,16 +156,18 @@ interface nsIRILContentHelper : nsIMobil
 
   void answerCall(in unsigned long callIndex);
   void rejectCall(in unsigned long callIndex);
   void holdCall(in unsigned long callIndex);
   void resumeCall(in unsigned long callIndex);
 
   attribute bool microphoneMuted;
   attribute bool speakerEnabled;
+
+  readonly attribute nsIDOMMozVoicemailStatus voicemailStatus;
 };
 
 [scriptable, uuid(fd9e8b38-b839-4d56-8482-3bf1f5c8f2ee)]
 interface nsIICCRecords : nsISupports
 {
   /**
    * Mobile Subscriber ISDN Number
    */
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -510,17 +510,17 @@ const PDU_TOA_NATIONAL_NUM  = 0x88; // N
 const PDU_TOA_PRIVATE_NUM   = 0x89; // Private numbering plan
 const PDU_TOA_ERMES_NUM     = 0x8A; // Ermes numbering plan
 const PDU_TOA_INTERNATIONAL = 0x90; // International number
 const PDU_TOA_NATIONAL      = 0xA0; // National number. Prefix or escape digits
                                     // shall not be included
 const PDU_TOA_NETWORK_SPEC  = 0xB0; // Network specific number This is used to
                                     // indicate administration/service number
                                     // specific to the serving network
-const PDU_TOA_SUSCRIBER     = 0xC0; // Suscriber number. This is used when a
+const PDU_TOA_SUBSCRIBER    = 0xC0; // Subscriber number. This is used when a
                                     // specific short number representation is
                                     // stored in one or more SCs as part of a
                                     // higher layer application
 const PDU_TOA_ALPHANUMERIC  = 0xD0; // Alphanumeric, (coded according to GSM TS
                                     // 03.38 7-bit default alphabet)
 const PDU_TOA_ABBREVIATED   = 0xE0; // Abbreviated number
 
 /**
@@ -652,31 +652,42 @@ const PDU_PID_REPLACE_SHORT_MESSAGE_TYPE
 const PDU_PID_ENHANDED_MESSAGE_SERVICE     = 0x5E;
 const PDU_PID_RETURN_CALL_MESSAGE          = 0x5F
 const PDU_PID_ANSI_136_R_DATA              = 0x7C;
 const PDU_PID_ME_DATA_DOWNLOAD             = 0x7D;
 const PDU_PID_ME_DEPERSONALIZATION         = 0x7E;
 const PDU_PID_USIM_DATA_DOWNLOAD           = 0x7F;
 
 // DCS - Data Coding Scheme
-const PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00;
-const PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04;
-const PDU_DCS_MSG_CODING_16BITS_ALPHABET= 0x08;
-const PDU_DCS_MSG_CLASS_ME_SPECIFIC     = 0xF1;
-const PDU_DCS_MSG_CLASS_SIM_SPECIFIC    = 0xF2;
-const PDU_DCS_MSG_CLASS_TE_SPECIFIC     = 0xF3;
+const PDU_DCS_MSG_CODING_7BITS_ALPHABET  = 0x00;
+const PDU_DCS_MSG_CODING_8BITS_ALPHABET  = 0x04;
+const PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08;
+const PDU_DCS_MSG_CLASS_ME_SPECIFIC      = 0xF1;
+const PDU_DCS_MSG_CLASS_SIM_SPECIFIC     = 0xF2;
+const PDU_DCS_MSG_CLASS_TE_SPECIFIC      = 0xF3;
+const PDU_DCS_CODING_GROUP_BITS          = 0xF0;
+const PDU_DCS_CODING_GROUP_7BITS_DISCARD = 0xC0;
+const PDU_DCS_CODING_GROUP_7BITS_STORE   = 0xD0;
+const PDU_DCS_CODING_GROUP_16BITS_STORE  = 0xE0;
+const PDU_DCS_MWI_ACTIVE_BITS            = 0x08;
+const PDU_DCS_MWI_ACTIVE_VALUE           = 0x08;
+const PDU_DCS_MWI_TYPE_BITS              = 0x03;
+const PDU_DCS_MWI_TYPE_VOICEMAIL         = 0x00;
+const PDU_DCS_MWI_TYPE_FAX               = 0x01;
+const PDU_DCS_MWI_TYPE_EMAIL             = 0x02;
+const PDU_DCS_MWI_TYPE_OTHER             = 0x03;
 
 // Because service center timestamp omit the century. Yay.
 const PDU_TIMESTAMP_YEAR_OFFSET = 2000;
 
 // See 9.2.3.24 TP‑User Data (TP‑UD)
 const PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT         = 0x00;
 const PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION           = 0x01;
-const PDU_IEI_APPLICATION_PORT_ADDREESING_SCHEME_8BIT  = 0x04;
-const PDU_IEI_APPLICATION_PORT_ADDREESING_SCHEME_16BIT = 0x05;
+const PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT  = 0x04;
+const PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT = 0x05;
 const PDU_IEI_SMSC_CONTROL_PARAMS                      = 0x06;
 const PDU_IEI_UDH_SOURCE_INDICATOR                     = 0x07;
 const PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT        = 0x08;
 const PDU_IEI_WIRELESS_CONTROL_MESSAGE_PROTOCOL        = 0x09;
 const PDU_IEI_TEXT_FORMATING                           = 0x0A;
 const PDU_IEI_PREDEFINED_SOUND                         = 0x0B;
 const PDU_IEI_USER_DATA_SOUND                          = 0x0C;
 const PDU_IEI_PREDEFINED_ANIMATION                     = 0x0D;
@@ -1329,16 +1340,21 @@ const PDU_NL_SINGLE_SHIFT_TABLES = [
   // 0123456789ABCDEF
   + "PQRSTUVWXYZ     "
   // 012345.....6789ABCDEF
   + "     \u20ac          "
   // 0123456789ABCDEF
   + "                "
 ];
 
+// Special SMS Message Indication constants
+const PDU_MWI_STORE_TYPE_BIT     = 0x80;
+const PDU_MWI_STORE_TYPE_DISCARD = 0x00;
+const PDU_MWI_STORE_TYPE_STORE   = 0x80;
+
 const RADIOTECH_FAMILY_3GPP = 1;  // GSM, WCDMA, LTE
 const RADIOTECH_FAMILY_3GPP2 = 2; // CDMA, EVDO
 
 const DATACALL_RADIOTECHNOLOGY_CDMA = 0;
 const DATACALL_RADIOTECHNOLOGY_GSM = 1;
 
 const DATACALL_AUTH_NONE = 0;
 const DATACALL_AUTH_PAP = 1;
@@ -1457,10 +1473,12 @@ const GECKO_RADIO_TECH = [
   "hsupa",
   "hspa",
   "evdob",
   "ehrpd",
   "lte",
   "hspa+",
 ];
 
+const GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN = -1;
+
 // Allow this file to be imported via Components.utils.import().
 const EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -3957,71 +3957,81 @@ let GsmPDUHelper = {
     for (let i = 0; i < message.length; ++i) {
       let code = message.charCodeAt(i);
       this.writeHexOctet((code >> 8) & 0xFF);
       this.writeHexOctet(code & 0xFF);
     }
   },
 
   /**
-   * Read 1 + UDHL octets and construct user data header at return.
+   * Read 1 + UDHL octets and construct user data header.
+   *
+   * @param msg
+   *        message object for output.
    *
-   * @return A header object with properties contained in received message.
-   * The properties set include:
-   * <ul>
-   * <li>length: totoal length of the header, default 0.
-   * <li>langIndex: used locking shift table index, default
-   *     PDU_NL_IDENTIFIER_DEFAULT.
-   * <li>langShiftIndex: used locking shift table index, default
-   *     PDU_NL_IDENTIFIER_DEFAULT.
-   * </ul>
+   * @see 3GPP TS 23.040 9.2.3.24
    */
-  readUserDataHeader: function readUserDataHeader() {
+  readUserDataHeader: function readUserDataHeader(msg) {
+    /**
+     * A header object with properties contained in received message.
+     * The properties set include:
+     *
+     * length: totoal length of the header, default 0.
+     * langIndex: used locking shift table index, default
+     * PDU_NL_IDENTIFIER_DEFAULT.
+     * langShiftIndex: used locking shift table index, default
+     * PDU_NL_IDENTIFIER_DEFAULT.
+     *
+     */
     let header = {
       length: 0,
       langIndex: PDU_NL_IDENTIFIER_DEFAULT,
       langShiftIndex: PDU_NL_IDENTIFIER_DEFAULT
     };
 
     header.length = this.readHexOctet();
+    if (DEBUG) debug("Read UDH length: " + header.length);
+
     let dataAvailable = header.length;
     while (dataAvailable >= 2) {
       let id = this.readHexOctet();
       let length = this.readHexOctet();
+      if (DEBUG) debug("Read UDH id: " + id + ", length: " + length);
+
       dataAvailable -= 2;
 
       switch (id) {
         case PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT: {
           let ref = this.readHexOctet();
           let max = this.readHexOctet();
           let seq = this.readHexOctet();
           dataAvailable -= 3;
           if (max && seq && (seq <= max)) {
             header.segmentRef = ref;
             header.segmentMaxSeq = max;
             header.segmentSeq = seq;
           }
           break;
         }
-        case PDU_IEI_APPLICATION_PORT_ADDREESING_SCHEME_8BIT: {
+        case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT: {
           let dstp = this.readHexOctet();
           let orip = this.readHexOctet();
           dataAvailable -= 2;
           if ((dstp < PDU_APA_RESERVED_8BIT_PORTS)
               || (orip < PDU_APA_RESERVED_8BIT_PORTS)) {
             // 3GPP TS 23.040 clause 9.2.3.24.3: "A receiving entity shall
             // ignore any information element where the value of the
             // Information-Element-Data is Reserved or not supported"
             break;
           }
           header.destinationPort = dstp;
           header.originatorPort = orip;
           break;
         }
-        case PDU_IEI_APPLICATION_PORT_ADDREESING_SCHEME_16BIT: {
+        case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT: {
           let dstp = (this.readHexOctet() << 8) | this.readHexOctet();
           let orip = (this.readHexOctet() << 8) | this.readHexOctet();
           dataAvailable -= 4;
           // 3GPP TS 23.040 clause 9.2.3.24.4: "A receiving entity shall
           // ignore any information element where the value of the
           // Information-Element-Data is Reserved or not supported"
           if ((dstp < PDU_APA_VALID_16BIT_PORTS)
               && (orip < PDU_APA_VALID_16BIT_PORTS)) {
@@ -4051,16 +4061,51 @@ let GsmPDUHelper = {
           break;
         case PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT:
           let langIndex = this.readHexOctet();
           --dataAvailable;
           if (langIndex < PDU_NL_LOCKING_SHIFT_TABLES.length) {
             header.langIndex = langIndex;
           }
           break;
+        case PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION:
+          let msgInd = this.readHexOctet() & 0xFF;
+          let msgCount = this.readHexOctet();
+          dataAvailable -= 2;
+
+
+          /*
+           * TS 23.040 V6.8.1 Sec 9.2.3.24.2
+           * bits 1 0   : basic message indication type
+           * bits 4 3 2 : extended message indication type
+           * bits 6 5   : Profile id
+           * bit  7     : storage type
+           */
+          let storeType = msgInd & PDU_MWI_STORE_TYPE_BIT;
+          let mwi = msg.mwi;
+          if (!mwi) {
+            mwi = msg.mwi = {};
+          }
+
+          if (storeType == PDU_MWI_STORE_TYPE_STORE) {
+            // Store message because TP_UDH indicates so, note this may override
+            // the setting in DCS, but that is expected
+            mwi.discard = false;
+          } else if (mwi.discard === undefined) {
+            // storeType == PDU_MWI_STORE_TYPE_DISCARD
+            // only override mwi.discard here if it hasn't already been set
+            mwi.discard = true;
+          }
+
+          mwi.msgCount = msgCount & 0xFF;
+          mwi.active = mwi.msgCount > 0;
+
+          if (DEBUG) debug("MWI in TP_UDH received: " + JSON.stringify(mwi));
+
+          break;
         default:
           if (DEBUG) {
             debug("readUserDataHeader: unsupported IEI(" + id
                   + "), " + length + " bytes.");
           }
 
           // Read out unsupported data
           if (length) {
@@ -4078,17 +4123,17 @@ let GsmPDUHelper = {
           break;
       }
     }
 
     if (dataAvailable != 0) {
       throw new Error("Illegal user data header found!");
     }
 
-    return header;
+    msg.header = header;
   },
 
   /**
    * Write out user data header.
    *
    * @param options
    *        Options containing information for user data header write-out. The
    *        `userDataHeaderLength` property must be correctly pre-calculated.
@@ -4253,32 +4298,48 @@ let GsmPDUHelper = {
 
     msg.epid = msg.pid;
     switch (msg.epid & 0xC0) {
       case 0x40:
         // Bit 7..0 = 01xxxxxx
         switch (msg.epid) {
           case PDU_PID_SHORT_MESSAGE_TYPE_0:
             return;
+          case PDU_PID_RETURN_CALL_MESSAGE:
+            // Level 1 of message waiting indication:
+            // Only a return call message is provided
+            let mwi = msg.mwi = {};
+
+            // TODO: When should we de-activate the level 1 indicator?
+            mwi.active = true;
+            mwi.discard = false;
+            mwi.msgCount = GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN;
+            if (DEBUG) debug("TP-PID got return call message: " + msg.sender);
+            return;
         }
         break;
     }
+
     msg.epid = PDU_PID_DEFAULT;
   },
 
   /**
    * Read TP-Data-Coding-Scheme(TP-DCS)
    *
    * @param msg
    *        message object for output.
    *
    * @see 3GPP TS 23.040 9.2.3.10, 3GPP TS 23.038 4.
    */
   readDataCodingScheme: function readDataCodingScheme(msg) {
     let dcs = this.readHexOctet();
+    if (DEBUG) debug("PDU: read dcs: " + dcs);
+
+    // Level 2 of message waiting indication
+    this.readMessageWaitingFromDCS(msg, dcs);
 
     // 7 bit is the default fallback encoding.
     let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
     switch (dcs & 0xC0) {
       case 0x0:
         // bits 7..4 = 00xx
         switch (dcs & 0x0C) {
           case 0x4:
@@ -4308,16 +4369,58 @@ let GsmPDUHelper = {
     }
 
     msg.dcs = dcs;
     msg.encoding = encoding;
 
     if (DEBUG) debug("PDU: message encoding is " + encoding + " bit.");
   },
 
+  readMessageWaitingFromDCS: function readMessageWaitingFromDCS(msg, dcs) {
+    // 0xC0 == 7 bit, don't store
+    // 0xD0 == 7 bit, store
+    // 0xE0 == UCS-2, store
+    let codingGroup = dcs & PDU_DCS_CODING_GROUP_BITS;
+
+    if (codingGroup == PDU_DCS_CODING_GROUP_7BITS_DISCARD ||
+        codingGroup == PDU_DCS_CODING_GROUP_7BITS_STORE ||
+        codingGroup == PDU_DCS_CODING_GROUP_16BITS_STORE) {
+
+      // Indiciates voicemail indicator set or clear
+      let active = (dcs & PDU_DCS_MWI_ACTIVE_BITS) == PDU_DCS_MWI_ACTIVE_VALUE;
+
+      // If TP-UDH is present, these values will be overwritten
+      switch (dcs & PDU_DCS_MWI_TYPE_BITS) {
+        case PDU_DCS_MWI_TYPE_VOICEMAIL:
+          let mwi = msg.mwi;
+          if (!mwi) {
+            mwi = msg.mwi = {};
+          }
+
+          mwi.active = active;
+          mwi.discard = codingGroup == PDU_DCS_CODING_GROUP_7BITS_DISCARD;
+          mwi.msgCount = active ? GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN : 0;
+
+          if (DEBUG) {
+            debug("MWI in DCS received for voicemail: " + JSON.stringify(mwi));
+          }
+          break;
+        case PDU_DCS_MWI_TYPE_FAX:
+          if (DEBUG) debug("MWI in DCS received for fax");
+          break;
+        case PDU_DCS_MWI_TYPE_EMAIL:
+          if (DEBUG) debug("MWI in DCS received for email");
+          break;
+        default:
+          if (DEBUG) debug("MWI in DCS received for \"other\"");
+          break;
+      }
+    }
+  },
+
   /**
    * Read GSM TP-Service-Centre-Time-Stamp(TP-SCTS).
    *
    * @see 3GPP TS 23.040 9.2.3.11
    */
   readTimestamp: function readTimestamp() {
     let year   = this.readSwappedNibbleBcdNum(1) + PDU_TIMESTAMP_YEAR_OFFSET;
     let month  = this.readSwappedNibbleBcdNum(1) - 1;
@@ -4351,29 +4454,31 @@ let GsmPDUHelper = {
    */
   readUserData: function readUserData(msg, length) {
     if (DEBUG) {
       debug("Reading " + length + " bytes of user data.");
     }
 
     let paddingBits = 0;
     if (msg.udhi) {
-      msg.header = this.readUserDataHeader();
+      this.readUserDataHeader(msg);
 
       if (msg.encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
         let headerBits = (msg.header.length + 1) * 8;
         let headerSeptets = Math.ceil(headerBits / 7);
 
         length -= headerSeptets;
         paddingBits = headerSeptets * 7 - headerBits;
       } else {
         length -= (msg.header.length + 1);
       }
     }
 
+    if (DEBUG) debug("After header, " + length + " septets left of user data");
+
     msg.body = null;
     msg.data = null;
     switch (msg.encoding) {
       case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
         // 7 bit encoding allows 140 octets, which means 160 characters
         // ((140x8) / 7 = 160 chars)
         if (length > PDU_MAX_USER_DATA_7BIT) {
           if (DEBUG) debug("PDU error: user data is too long: " + length);
@@ -4449,23 +4554,25 @@ let GsmPDUHelper = {
     // An empty message object. This gets filled below and then returned.
     let msg = {
       // D:DELIVER, DR:DELIVER-REPORT, S:SUBMIT, SR:SUBMIT-REPORT,
       // ST:STATUS-REPORT, C:COMMAND
       // M:Mandatory, O:Optional, X:Unavailable
       //                  D  DR S  SR ST C
       SMSC:      null, // M  M  M  M  M  M
       mti:       null, // M  M  M  M  M  M
-      udhi:      null, // M  M  X  M  M  M
+      udhi:      null, // M  M  O  M  M  M
       sender:    null, // M  X  X  X  X  X
       recipient: null, // X  X  M  X  M  M
       pid:       null, // M  O  M  O  O  M
       epid:      null, // M  O  M  O  O  M
       dcs:       null, // M  O  M  O  O  X
-      encoding:  null, // M  O  M  O  O  X
+      mwi:       null, // O  O  O  O  O  O
+      replace:  false, // O  O  O  O  O  O
+      header:    null, // M  M  O  M  M  M
       body:      null, // M  O  M  O  O  O
       data:      null, // M  O  M  O  O  O
       timestamp: null, // M  X  X  X  X  X
       status:    null, // X  X  X  X  M  X
       scts:      null, // X  X  X  M  M  X
       dt:        null, // X  X  X  X  M  X
     };
 
--- a/dom/telephony/Makefile.in
+++ b/dom/telephony/Makefile.in
@@ -16,18 +16,23 @@ LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 CPPSRCS = \
   Telephony.cpp \
   TelephonyCall.cpp \
   CallEvent.cpp \
+  Voicemail.cpp \
+  VoicemailEvent.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorTelephony.idl \
   nsIDOMTelephony.idl \
   nsIDOMTelephonyCall.idl \
   nsIDOMCallEvent.idl \
+  nsIDOMVoicemail.idl \
+  nsIDOMVoicemailEvent.idl \
+  nsIDOMVoicemailStatus.idl \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/telephony/TelephonyFactory.h
+++ b/dom/telephony/TelephonyFactory.h
@@ -3,16 +3,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_telephony_telephonyfactory_h__
 #define mozilla_dom_telephony_telephonyfactory_h__
 
 #include "nsIDOMTelephony.h"
+#include "nsIDOMVoicemail.h"
 #include "nsPIDOMWindow.h"
 
-// Implemented in Telephony.cpp.
+// Implemented in Telephony.cpp / Voicemail.cpp.
 
 nsresult
 NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony);
 
+nsresult
+NS_NewVoicemail(nsPIDOMWindow* aWindow, nsIDOMMozVoicemail** aVoicemail);
+
 #endif // mozilla_dom_telephony_telephonyfactory_h__
new file mode 100644
--- /dev/null
+++ b/dom/telephony/Voicemail.cpp
@@ -0,0 +1,111 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Voicemail.h"
+#include "nsIDOMVoicemailStatus.h"
+
+#include "mozilla/Services.h"
+#include "nsContentUtils.h"
+#include "nsDOMClassInfo.h"
+#include "nsRadioInterfaceLayer.h"
+#include "nsServiceManagerUtils.h"
+
+#include "VoicemailEvent.h"
+
+DOMCI_DATA(MozVoicemail, mozilla::dom::telephony::Voicemail)
+
+USING_TELEPHONY_NAMESPACE
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Voicemail)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Voicemail,
+                                                  nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(statuschanged)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Voicemail,
+                                                nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(statuschanged)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Voicemail)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozVoicemail)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozVoicemail)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(Voicemail, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(Voicemail, nsDOMEventTargetHelper)
+
+NS_IMPL_ISUPPORTS1(Voicemail::RILVoicemailCallback, nsIRILVoicemailCallback)
+
+Voicemail::Voicemail(nsPIDOMWindow* aWindow, nsIRILContentHelper* aRIL)
+  : mRIL(aRIL)
+{
+  BindToOwner(aWindow);
+
+  mRILVoicemailCallback = new RILVoicemailCallback(this);
+
+  nsresult rv = aRIL->RegisterVoicemailCallback(mRILVoicemailCallback);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed registering voicemail callback with RIL");
+  }
+}
+
+Voicemail::~Voicemail()
+{
+  if (mRIL && mRILVoicemailCallback) {
+    mRIL->UnregisterVoicemailCallback(mRILVoicemailCallback);
+  }
+}
+
+// nsIDOMMozVoicemail
+
+NS_IMETHODIMP
+Voicemail::GetStatus(nsIDOMMozVoicemailStatus** aStatus)
+{
+  *aStatus = nsnull;
+
+  NS_ENSURE_STATE(mRIL);
+  return mRIL->GetVoicemailStatus(aStatus);
+}
+
+NS_IMPL_EVENT_HANDLER(Voicemail, statuschanged)
+
+// nsIRILVoicemailCallback
+
+NS_IMETHODIMP
+Voicemail::VoicemailNotification(nsIDOMMozVoicemailStatus* aStatus)
+{
+  nsRefPtr<VoicemailEvent> event = new VoicemailEvent(nsnull, nsnull);
+  nsresult rv = event->InitVoicemailEvent(NS_LITERAL_STRING("statuschanged"),
+                                          false, false, aStatus);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = event->SetTrusted(true);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool dummy;
+  rv = DispatchEvent(static_cast<nsIDOMMozVoicemailEvent*>(event), &dummy);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+NS_NewVoicemail(nsPIDOMWindow* aWindow, nsIDOMMozVoicemail** aVoicemail)
+{
+  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
+    aWindow :
+    aWindow->GetCurrentInnerWindow();
+
+  nsCOMPtr<nsIRILContentHelper> ril =
+    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  NS_ENSURE_STATE(ril);
+
+  nsRefPtr<Voicemail> voicemail = new Voicemail(innerWindow, ril);
+  voicemail.forget(aVoicemail);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/telephony/Voicemail.h
@@ -0,0 +1,61 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_telephony_voicemail_h__
+#define mozilla_dom_telephony_voicemail_h__
+
+#include "TelephonyCommon.h"
+
+#include "nsDOMEvent.h"
+#include "nsDOMEventTargetHelper.h"
+#include "nsIDOMVoicemail.h"
+#include "nsIRadioInterfaceLayer.h"
+
+class nsIRILContentHelper;
+class nsIDOMMozVoicemailStatus;
+
+BEGIN_TELEPHONY_NAMESPACE
+
+class Voicemail : public nsDOMEventTargetHelper,
+                  public nsIDOMMozVoicemail
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMMOZVOICEMAIL
+  NS_DECL_NSIRILVOICEMAILCALLBACK
+
+  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Voicemail, nsDOMEventTargetHelper)
+
+  Voicemail(nsPIDOMWindow* aWindow, nsIRILContentHelper* aRIL);
+  virtual ~Voicemail();
+
+private:
+  nsCOMPtr<nsIRILContentHelper> mRIL;
+  nsCOMPtr<nsIRILVoicemailCallback> mRILVoicemailCallback;
+
+  NS_DECL_EVENT_HANDLER(statuschanged)
+
+  class RILVoicemailCallback : public nsIRILVoicemailCallback
+  {
+    Voicemail* mVoicemail;
+
+  public:
+    NS_DECL_ISUPPORTS
+    NS_FORWARD_NSIRILVOICEMAILCALLBACK(mVoicemail->)
+
+    RILVoicemailCallback(Voicemail* aVoicemail)
+    : mVoicemail(aVoicemail)
+    {
+      NS_ASSERTION(mVoicemail, "Null pointer!");
+    }
+  };
+};
+
+END_TELEPHONY_NAMESPACE
+
+#endif // mozilla_dom_telephony_voicemail_h__
new file mode 100644
--- /dev/null
+++ b/dom/telephony/VoicemailEvent.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VoicemailEvent.h"
+#include "nsDOMClassInfo.h"
+#include "nsIDOMVoicemailStatus.h"
+
+DOMCI_DATA(MozVoicemailEvent, mozilla::dom::telephony::VoicemailEvent)
+
+USING_TELEPHONY_NAMESPACE
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(VoicemailEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VoicemailEvent, nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mStatus)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VoicemailEvent, nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStatus)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(VoicemailEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozVoicemailEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozVoicemailEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(VoicemailEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(VoicemailEvent, nsDOMEvent)
+
+nsresult
+VoicemailEvent::InitVoicemailEvent(const nsAString& aEventTypeArg,
+                                   bool aCanBubbleArg, bool aCancelableArg,
+                                   nsIDOMMozVoicemailStatus* aStatus)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg,
+                                      aCancelableArg);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mStatus = aStatus;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+VoicemailEvent::GetStatus(nsIDOMMozVoicemailStatus** aStatus)
+{
+  NS_IF_ADDREF(*aStatus = mStatus);
+  return NS_OK;
+}
+
+namespace {
+
+nsresult
+NS_NewDOMVoicemailEvent(nsIDOMEvent** aInstancePtrResult,
+                  nsPresContext* aPresContext,
+                  nsEvent* aEvent)
+{
+  return CallQueryInterface(
+    new mozilla::dom::telephony::VoicemailEvent(aPresContext, aEvent),
+    aInstancePtrResult);
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/dom/telephony/VoicemailEvent.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_telephony_VoicemailEvent_h__
+#define mozilla_dom_telephony_VoicemailEvent_h__
+
+#include "TelephonyCommon.h"
+
+#include "nsIDOMVoicemailEvent.h"
+#include "nsDOMEvent.h"
+
+class nsIDOMMozVoicemailStatus;
+
+BEGIN_TELEPHONY_NAMESPACE
+
+class VoicemailEvent : public nsIDOMMozVoicemailEvent,
+                       public nsDOMEvent
+{
+public:
+  VoicemailEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+    : nsDOMEvent(aPresContext, aEvent) { }
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMMOZVOICEMAILEVENT
+
+  NS_FORWARD_TO_NSDOMEVENT
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VoicemailEvent, nsDOMEvent)
+
+  nsresult InitVoicemailEvent(const nsAString& aEventTypeArg,
+                              bool aCanBubbleArg, bool aCancelableArg,
+                              nsIDOMMozVoicemailStatus* aStatus);
+
+private:
+  nsCOMPtr<nsIDOMMozVoicemailStatus> mStatus;
+};
+
+END_TELEPHONY_NAMESPACE
+
+#endif // mozilla_dom_telephony_VoicemailEvent_h__
--- a/dom/telephony/nsIDOMNavigatorTelephony.idl
+++ b/dom/telephony/nsIDOMNavigatorTelephony.idl
@@ -2,14 +2,16 @@
 /* vim: set ts=2 et sw=2 tw=40: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMTelephony;
+interface nsIDOMMozVoicemail;
 
-[scriptable, builtinclass, uuid(fb2f5927-41ea-442a-8292-81074f69dc41)]
+[scriptable, builtinclass, uuid(4a297d39-2730-47b8-b406-666b3737aacb)]
 interface nsIDOMNavigatorTelephony : nsISupports
 {
   readonly attribute nsIDOMTelephony mozTelephony;
+  readonly attribute nsIDOMMozVoicemail mozVoicemail;
 };
new file mode 100644
--- /dev/null
+++ b/dom/telephony/nsIDOMVoicemail.idl
@@ -0,0 +1,23 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEventTarget.idl"
+
+interface nsIDOMMozVoicemailStatus;
+
+[scriptable, builtinclass, uuid(db5b727a-daf2-40b9-83e4-cc110eab44ca)]
+interface nsIDOMMozVoicemail : nsIDOMEventTarget
+{
+  /**
+   * The current voicemail status, or null when the status is unknown
+   */
+  readonly attribute nsIDOMMozVoicemailStatus status;
+
+  /**
+   * The current voicemail status has changed
+   */
+  attribute nsIDOMEventListener onstatuschanged;
+};
new file mode 100644
--- /dev/null
+++ b/dom/telephony/nsIDOMVoicemailEvent.idl
@@ -0,0 +1,18 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEvent.idl"
+
+interface nsIDOMMozVoicemailStatus;
+
+[scriptable, builtinclass, uuid(4642f196-1a30-4a9b-986f-7f1574d5cee1)]
+interface nsIDOMMozVoicemailEvent : nsIDOMEvent
+{
+  /**
+   * The voicemail status that caused this event to fire
+   */
+  readonly attribute nsIDOMMozVoicemailStatus status;
+};
new file mode 100644
--- /dev/null
+++ b/dom/telephony/nsIDOMVoicemailStatus.idl
@@ -0,0 +1,50 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(8c58859a-e006-466a-ad76-b188ba0918ab)]
+interface nsIDOMMozVoicemailStatus : nsISupports
+{
+  /**
+   * There are voicemail messages waiting, but the count is unknown.
+   */
+  const long MESSAGE_COUNT_UNKNOWN = -1;
+
+  /**
+   * Whether or not there are messages waiting in the voicemail box
+   */
+  readonly attribute boolean hasMessages;
+
+  /**
+   * The total message count. Some voicemail indicators will only specify that
+   * messages are waiting, but not the actual number. In that case, the value
+   * of messageCount will be MESSAGE_COUNT_UNKNOWN (-1).
+   *
+   * Logic for a voicemail notification might look something like:
+   * if (status.hasMessages) {
+   *   // show new voicemail notification
+   *   if (status.messageCount > 0) {
+   *     // add a label for the message count
+   *   }
+   * } else {
+   *   // hide the voicemail notification
+   * }
+   */
+  readonly attribute long messageCount;
+
+  /**
+   * Return call number received for this voicemail status, or null if one
+   * wasn't provided.
+   */
+  readonly attribute DOMString returnNumber;
+
+  /**
+   * Displayable return call message received for this voicemail status, or null
+   * if one wasn't provided.
+   */
+  readonly attribute DOMString returnMessage;
+};
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -11,8 +11,9 @@ qemu = true
 [test_outgoing_hangup_alerting.js]
 [test_outgoing_hangup_held.js]
 # Bug 761533
 #[test_outgoing_badNumber.js]
 #expectedfailure = true
 #[test_outgoing_busy.js]
 #expectedfailure = true
 [test_outgoing_reject.js]
+[test_voicemail_statuschanged.py]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/pdu_builder.js
@@ -0,0 +1,149 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Only bring in what we need from ril_worker/RadioInterfaceLayer here. Reusing
+// that code turns out to be a nightmare, so there is some code duplication.
+let PDUBuilder = {
+  toHexString: function toHexString(n, length) {
+    let str = n.toString(16);
+    if (str.length < length) {
+      for (let i = 0; i < length - str.length; i++) {
+        str = "0" + str;
+      }
+    }
+    return str.toUpperCase();
+  },
+
+  writeUint16: function writeUint16(value) {
+    this.buf += (value & 0xff).toString(16).toUpperCase();
+    this.buf += ((value >> 8) & 0xff).toString(16).toUpperCase();
+  },
+
+  writeHexOctet: function writeHexOctet(octet) {
+    this.buf += this.toHexString(octet, 2);
+  },
+
+  writeSwappedNibbleBCD: function writeSwappedNibbleBCD(data) {
+    data = data.toString();
+    let zeroCharCode = '0'.charCodeAt(0);
+
+    for (let i = 0; i < data.length; i += 2) {
+      let low = data.charCodeAt(i) - zeroCharCode;
+      let high;
+      if (i + 1 < data.length) {
+        high = data.charCodeAt(i + 1) - zeroCharCode;
+      } else {
+        high = 0xF;
+      }
+
+      this.writeHexOctet((high << 4) | low);
+    }
+  },
+
+  writeStringAsSeptets: function writeStringAsSeptets(message,
+                                                      paddingBits,
+                                                      langIndex,
+                                                      langShiftIndex)
+  {
+    const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
+    const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
+
+    let dataBits = paddingBits;
+    let data = 0;
+    for (let i = 0; i < message.length; i++) {
+      let septet = langTable.indexOf(message[i]);
+      if (septet == PDU_NL_EXTENDED_ESCAPE) {
+        continue;
+      }
+
+      if (septet >= 0) {
+        data |= septet << dataBits;
+        dataBits += 7;
+      } else {
+        septet = langShiftTable.indexOf(message[i]);
+        if (septet == -1) {
+          throw new Error(message[i] + " not in 7 bit alphabet "
+                          + langIndex + ":" + langShiftIndex + "!");
+        }
+
+        if (septet == PDU_NL_RESERVED_CONTROL) {
+          continue;
+        }
+
+        data |= PDU_NL_EXTENDED_ESCAPE << dataBits;
+        dataBits += 7;
+        data |= septet << dataBits;
+        dataBits += 7;
+      }
+
+      for (; dataBits >= 8; dataBits -= 8) {
+        this.writeHexOctet(data & 0xFF);
+        data >>>= 8;
+      }
+    }
+
+    if (dataBits != 0) {
+      this.writeHexOctet(data & 0xFF);
+    }
+  },
+
+  buildAddress: function buildAddress(address) {
+    let addressFormat = PDU_TOA_ISDN; // 81
+    if (address[0] == '+') {
+      addressFormat = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91
+      address = address.substring(1);
+    }
+
+    this.buf = "";
+    this.writeHexOctet(address.length);
+    this.writeHexOctet(addressFormat);
+    this.writeSwappedNibbleBCD(address);
+
+    return this.buf;
+  },
+
+  // assumes 7 bit encoding
+  buildUserData: function buildUserData(options) {
+    let headerLength = 0;
+    this.buf = "";
+    if (options.headers) {
+      for each (let header in options.headers) {
+        headerLength += 2; // id + length octets
+        if (header.octets) {
+          headerLength += header.octets.length;
+        }
+      };
+    }
+
+    let encodedBodyLength = options.body.length;
+    let headerOctets = (headerLength ? headerLength + 1 : 0);
+
+    let paddingBits;
+    let userDataLengthInSeptets;
+    let headerSeptets = Math.ceil(headerOctets * 8 / 7);
+    userDataLengthInSeptets = headerSeptets + encodedBodyLength;
+    paddingBits = headerSeptets * 7 - headerOctets * 8;
+
+    this.writeHexOctet(userDataLengthInSeptets);
+    if (options.headers) {
+      this.writeHexOctet(headerLength);
+
+      for each (let header in options.headers) {
+        this.writeHexOctet(header.id);
+        this.writeHexOctet(header.length);
+
+        if (header.octets) {
+          for each (let octet in header.octets) {
+            this.writeHexOctet(octet);
+          }
+        }
+      }
+    }
+
+    this.writeStringAsSeptets(options.body, paddingBits,
+                              PDU_NL_IDENTIFIER_DEFAULT,
+                              PDU_NL_IDENTIFIER_DEFAULT);
+    return this.buf;
+  }
+};
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_voicemail_statuschanged.js
@@ -0,0 +1,229 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const WHITELIST_PREF = "dom.voicemail.whitelist";
+let uriPrePath = window.location.protocol + "//" + window.location.host;
+SpecialPowers.setCharPref(WHITELIST_PREF, uriPrePath);
+
+let voicemail = window.navigator.mozVoicemail;
+ok(voicemail instanceof MozVoicemail);
+is(voicemail.status, null);
+
+function sendIndicatorPDU(pdu, listener, nextTest) {
+  let smsCommand = "sms pdu " + pdu;
+  let commandCompleted = false;
+  let sawEvent = false;
+
+ voicemail.addEventListener("statuschanged", function statusChanged(event) {
+    voicemail.removeEventListener("statuschanged", statusChanged);
+
+    try {
+      listener(event);
+    } catch (e) {
+      ok(false, String(e));
+    }
+
+    sawEvent = true;
+    if (commandCompleted) {
+      nextTest();
+    }
+  });
+
+  log("-> " + smsCommand);
+  runEmulatorCmd(smsCommand, function(result) {
+    log("<- " + result);
+    is(result[0], "OK");
+    commandCompleted = true;
+    if (sawEvent) {
+      nextTest();
+    }
+  });
+}
+
+// TODO: Add tests for store/discard once they are implemented
+// See RadioInterfaceLayer.js / Bug #768441
+
+function isVoicemailStatus(status) {
+  is(voicemail.status.hasMessages, status.hasMessages);
+  is(voicemail.status.messageCount, status.messageCount);
+  is(voicemail.status.returnNumber, status.returnNumber);
+  is(voicemail.status.returnMessage, status.returnMessage);
+}
+
+const MWI_PDU_PREFIX = "0000";
+const MWI_PDU_UDH_PREFIX = "0040";
+const MWI_PID_DEFAULT = "00";
+const MWI_PID_RETURN_CALL_MSG = "5F";
+const MWI_DCS_DATA_MSG = "F0";
+const MWI_DCS_DISCARD_INACTIVE = "C0";
+const MWI_DCS_DISCARD_ACTIVE = "C8";
+const MWI_TIMESTAMP = "00000000000000";
+
+const MWI_LEVEL1_SENDER = "+15125551234";
+const MWI_LEVEL1_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL1_SENDER);
+const MWI_DEFAULT_BODY = "1 new voicemail";
+const MWI_UD_DEFAULT = PDUBuilder.buildUserData({
+  body: MWI_DEFAULT_BODY
+});
+
+// Level 1 Message Waiting is just a return call message
+const MWI_LEVEL1_PDU =
+  MWI_PDU_PREFIX +
+  MWI_LEVEL1_PDU_ADDRESS +
+  MWI_PID_RETURN_CALL_MSG +
+  MWI_DCS_DATA_MSG +
+  MWI_TIMESTAMP +
+  MWI_UD_DEFAULT;
+
+function testLevel1Indicator() {
+
+  function onLevel1Indicator(event) {
+    let status = event.status;
+    ok(status instanceof MozVoicemailStatus);
+    is(status.hasMessages, true);
+    is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN);
+    is(status.returnNumber, MWI_LEVEL1_SENDER);
+    is(status.returnMessage, MWI_DEFAULT_BODY);
+    isVoicemailStatus(status);
+  }
+
+  sendIndicatorPDU(MWI_LEVEL1_PDU, onLevel1Indicator, testLevel2DiscardActive);
+}
+
+const MWI_LEVEL2_SENDER = "+15125551235";
+const MWI_LEVEL2_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL2_SENDER);
+const MWI_LEVEL2_DISCARD_ACTIVE_PDU =
+  MWI_PDU_PREFIX +
+  MWI_LEVEL2_PDU_ADDRESS +
+  MWI_PID_DEFAULT +
+  MWI_DCS_DISCARD_ACTIVE +
+  MWI_TIMESTAMP +
+  MWI_UD_DEFAULT;
+
+function testLevel2DiscardActive() {
+
+  function onLevel2Active(event) {
+    let status = event.status;
+    ok(status instanceof MozVoicemailStatus);
+    is(status.hasMessages, true);
+    is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN);
+    is(status.returnNumber, MWI_LEVEL2_SENDER);
+    is(status.returnMessage, MWI_DEFAULT_BODY);
+    isVoicemailStatus(status);
+  }
+
+  sendIndicatorPDU(MWI_LEVEL2_DISCARD_ACTIVE_PDU,
+                   onLevel2Active,
+                   testLevel2DiscardInactive);
+
+}
+
+const MWI_LEVEL2_DISCARD_INACTIVE_PDU =
+  MWI_PDU_PREFIX +
+  MWI_LEVEL2_PDU_ADDRESS +
+  MWI_PID_DEFAULT +
+  MWI_DCS_DISCARD_INACTIVE +
+  MWI_TIMESTAMP +
+  MWI_UD_DEFAULT;
+
+function testLevel2DiscardInactive() {
+  function onLevel2Inactive(event) {
+    let status = event.status;
+    ok(status instanceof MozVoicemailStatus);
+    is(status.hasMessages, false);
+    is(status.messageCount, 0);
+    is(status.returnNumber, MWI_LEVEL2_SENDER);
+    is(status.returnMessage, MWI_DEFAULT_BODY);
+    isVoicemailStatus(status);
+  }
+
+  sendIndicatorPDU(MWI_LEVEL2_DISCARD_INACTIVE_PDU,
+                   onLevel2Inactive,
+                   testLevel3DiscardActive);
+}
+
+
+// Tests for Level 3 MWI with a message count in the User Data Header
+const MWI_LEVEL3_SENDER = "+15125551236";
+const MWI_LEVEL3_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL3_SENDER);
+
+const MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT = 3;
+const MWI_LEVEL3_ACTIVE_BODY = "3 new voicemails";
+const MWI_LEVEL3_ACTIVE_UD = PDUBuilder.buildUserData({
+  headers: [{
+    id: PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
+    length: 2,
+    octets: [
+      PDU_MWI_STORE_TYPE_DISCARD,
+      MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT
+    ]
+  }],
+  body: MWI_LEVEL3_ACTIVE_BODY
+});
+
+const MWI_LEVEL3_DISCARD_ACTIVE_PDU =
+  MWI_PDU_UDH_PREFIX +
+  MWI_LEVEL3_PDU_ADDRESS +
+  MWI_PID_DEFAULT +
+  MWI_DCS_DISCARD_ACTIVE +
+  MWI_TIMESTAMP +
+  MWI_LEVEL3_ACTIVE_UD;
+
+function testLevel3DiscardActive() {
+
+  function onLevel3Active(event) {
+    let status = event.status;
+    ok(status instanceof MozVoicemailStatus);
+    is(status.hasMessages, true);
+    is(status.messageCount, MWI_LEVEL3_ACTIVE_UDH_MSG_COUNT);
+    is(status.returnNumber, MWI_LEVEL3_SENDER);
+    is(status.returnMessage, MWI_LEVEL3_ACTIVE_BODY);
+    isVoicemailStatus(status);
+  }
+
+  sendIndicatorPDU(MWI_LEVEL3_DISCARD_ACTIVE_PDU,
+                   onLevel3Active,
+                   testLevel3DiscardInactive);
+}
+
+const MWI_LEVEL3_INACTIVE_BODY = "No unread voicemails";
+const MWI_LEVEL3_INACTIVE_UD = PDUBuilder.buildUserData({
+  headers: [{
+    id: PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION,
+    length: 2,
+    octets: [
+      PDU_MWI_STORE_TYPE_DISCARD,
+      0 // messageCount
+    ]
+  }],
+  body: MWI_LEVEL3_INACTIVE_BODY
+});
+
+const MWI_LEVEL3_DISCARD_INACTIVE_PDU =
+  MWI_PDU_UDH_PREFIX +
+  MWI_LEVEL3_PDU_ADDRESS +
+  MWI_PID_DEFAULT +
+  MWI_DCS_DISCARD_ACTIVE +
+  MWI_TIMESTAMP +
+  MWI_LEVEL3_INACTIVE_UD;
+
+function testLevel3DiscardInactive() {
+  function onLevel3Inactive(event) {
+    let status = event.status;
+    ok(status instanceof MozVoicemailStatus);
+    is(status.hasMessages, false);
+    is(status.messageCount, 0);
+    is(status.returnNumber, MWI_LEVEL3_SENDER);
+    is(status.returnMessage, MWI_LEVEL3_INACTIVE_BODY);
+    isVoicemailStatus(status);
+  }
+
+  sendIndicatorPDU(MWI_LEVEL3_DISCARD_INACTIVE_PDU, onLevel3Inactive, cleanUp);
+}
+
+function cleanUp() {
+  SpecialPowers.clearUserPref(WHITELIST_PREF);
+  finish();
+}
+
+testLevel1Indicator();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_voicemail_statuschanged.py
@@ -0,0 +1,20 @@
+from marionette_test import MarionetteTestCase
+import os
+
+class TestVoicemailStatusChanged(MarionetteTestCase):
+
+    def testStatusChanged(self):
+        this_dir = os.path.abspath(os.path.dirname(__file__))
+        system_gonk_dir = os.path.abspath(os.path.join(this_dir,
+            os.path.pardir, os.path.pardir, os.path.pardir, "system", "gonk"))
+
+        ril_consts_path = os.path.join(system_gonk_dir, "ril_consts.js")
+        self.marionette.import_script(ril_consts_path)
+
+        pdu_builder_path = os.path.join(this_dir, "pdu_builder.js")
+        self.marionette.import_script(pdu_builder_path)
+
+        test_path = os.path.join(this_dir, "test_voicemail_statuschanged.js")
+        test = open(test_path, "r").read()
+        self.marionette.set_script_timeout(30000)
+        self.marionette.execute_async_script(test)
--- a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
+++ b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
@@ -37,16 +37,22 @@ https://bugzilla.mozilla.org/show_bug.cg
         ok(false, "'EventTarget' shouldn't throw in a sandbox");
       }
       try {
         var xhr = Components.utils.evalInSandbox("XMLHttpRequest()", sandbox);
         is(xhr, "[object XMLHttpRequest]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object");
       } catch (e) {
         ok(false, "'XMLHttpRequest()' shouldn't throw in a sandbox");
       }
+      try {
+        var canvas = Components.utils.evalInSandbox("document.createElement('canvas').getContext('2d')", sandbox);
+        is(canvas.DRAWWINDOW_DRAW_CARET, CanvasRenderingContext2D.DRAWWINDOW_DRAW_CARET, "Constants should be defined on DOM objects in a sandbox");
+      } catch (e) {
+        ok(false, "'document.createElement('canvas').getContext('2D')' shouldn't throw in a sandbox");
+      }
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   ]]>
   </script>
 </window>
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -5000,35 +5000,37 @@ nsEditor::HandleKeyPressEvent(nsIDOMKeyE
     if (nativeKeyEvent->keyCode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE) {
       aKeyEvent->PreventDefault();
     }
     return NS_OK;
   }
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
+    case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
       aKeyEvent->PreventDefault(); // consumed
       return NS_OK;
     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
-          nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       DeleteSelection(nsIEditor::ePrevious, nsIEditor::eStrip);
       aKeyEvent->PreventDefault(); // consumed
       return NS_OK;
     case nsIDOMKeyEvent::DOM_VK_DELETE:
       // on certain platforms (such as windows) the shift key
       // modifies what delete does (cmd_cut in this case).
       // bailing here to allow the keybindings to do the cut.
       if (nativeKeyEvent->IsShift() || nativeKeyEvent->IsControl() ||
-          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+          nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
       aKeyEvent->PreventDefault(); // consumed
       return NS_OK; 
   }
   return NS_OK;
 }
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -594,16 +594,17 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOM
 
   nsKeyEvent* nativeKeyEvent = GetNativeKeyEvent(aKeyEvent);
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
   NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS,
                "HandleKeyPressEvent gets non-keypress event");
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
+    case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
     case nsIDOMKeyEvent::DOM_VK_DELETE:
       // These keys are handled on nsEditor, so, we can bypass
       // nsPlaintextEditor.
       return nsEditor::HandleKeyPressEvent(aKeyEvent);
@@ -614,17 +615,17 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOM
         return nsPlaintextEditor::HandleKeyPressEvent(aKeyEvent);
       }
 
       if (IsTabbable()) {
         return NS_OK; // let it be used for focus switching
       }
 
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
-          nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
 
       nsCOMPtr<nsISelection> selection;
       nsresult rv = GetSelection(getter_AddRefs(selection));
       NS_ENSURE_SUCCESS(rv, rv);
       PRInt32 offset;
       nsCOMPtr<nsIDOMNode> node, blockParent;
@@ -664,32 +665,33 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOM
         return NS_OK; // don't type text for shift tabs
       }
       aKeyEvent->PreventDefault();
       return TypedText(NS_LITERAL_STRING("\t"), eTypedText);
     }
     case nsIDOMKeyEvent::DOM_VK_RETURN:
     case nsIDOMKeyEvent::DOM_VK_ENTER:
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
-          nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       aKeyEvent->PreventDefault(); // consumed
       if (nativeKeyEvent->IsShift() && !IsPlaintextEditor()) {
         // only inserts a br node
         return TypedText(EmptyString(), eTypedBR);
       }
       // uses rules to figure out what to insert
       return TypedText(EmptyString(), eTypedBreak);
   }
 
   // NOTE: On some keyboard layout, some characters are inputted with Control
   // key or Alt key, but at that time, widget sets FALSE to these keys.
   if (nativeKeyEvent->charCode == 0 || nativeKeyEvent->IsControl() ||
-      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+      nativeKeyEvent->IsOS()) {
     // we don't PreventDefault() here or keybindings like control-x won't work
     return NS_OK;
   }
   aKeyEvent->PreventDefault();
   nsAutoString str(nativeKeyEvent->charCode);
   return TypedText(str, eTypedText);
 }
 
--- a/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
+++ b/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
@@ -132,16 +132,20 @@ function runTests()
     //   Basically, modifier keys shouldn't cause keypress event.  However,
     //   even if it were dispatched by widget's bug, editor should consume
     //   it when editor is editable.
     reset("");
     synthesizeKey("VK_META", { type: "keypress" });
     check(aDescription + "Meta", true, true, !aIsReadonly);
 
     reset("");
+    synthesizeKey("VK_WIN", { type: "keypress" });
+    check(aDescription + "OS", true, true, !aIsReadonly);
+
+    reset("");
     synthesizeKey("VK_SHIFT", { type: "keypress" });
     check(aDescription + "Shift", true, true, !aIsReadonly);
 
     reset("");
     synthesizeKey("VK_CONTROL", { type: "keypress" });
     check(aDescription + "Control", true, true, !aIsReadonly);
 
     // Alt key press event installs menubar key event listener, so,
@@ -171,16 +175,20 @@ function runTests()
     reset("");
     synthesizeKey("VK_BACK_SPACE", { altKey: true });
     check(aDescription + "Alt+Backspace", true, true, aIsReadonly);
 
     reset("");
     synthesizeKey("VK_BACK_SPACE", { metaKey: true });
     check(aDescription + "Meta+Backspace", true, true, aIsReadonly);
 
+    reset("");
+    synthesizeKey("VK_BACK_SPACE", { osKey: true });
+    check(aDescription + "OS+Backspace", true, true, aIsReadonly);
+
     // Delete key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable, delete is consumed.
     //   Otherwise, editor doesn't consume the event.
     reset("");
     synthesizeKey("VK_DELETE", { });
     check(aDescription + "Delete", true, true, !aIsReadonly);
 
@@ -195,16 +203,20 @@ function runTests()
     reset("");
     synthesizeKey("VK_DELETE", { altKey: true });
     check(aDescription + "Alt+Delete", true, true, false);
 
     reset("");
     synthesizeKey("VK_DELETE", { metaKey: true });
     check(aDescription + "Meta+Delete", true, true, false);
 
+    reset("");
+    synthesizeKey("VK_DELETE", { osKey: true });
+    check(aDescription + "OS+Delete", true, true, false);
+
     // Return key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
     //   and Shift+Return.
     //   Otherwise, editor doesn't consume the event.
     reset("a");
     synthesizeKey("VK_RETURN", { });
     check(aDescription + "Return",
@@ -229,16 +241,21 @@ function runTests()
     check(aDescription + "Alt+Return", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Alt+Return");
 
     reset("a");
     synthesizeKey("VK_RETURN", { metaKey: true });
     check(aDescription + "Meta+Return", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Meta+Return");
 
+    reset("a");
+    synthesizeKey("VK_RETURN", { osKey: true });
+    check(aDescription + "OS+Return", true, true, false);
+    is(aElement.innerHTML, "a", aDescription + "OS+Return");
+
     // Enter key (same as Return key):
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
     //   and Shift+Return.
     //   Otherwise, editor doesn't consume the event.
     reset("a");
     synthesizeKey("VK_ENTER", { });
     check(aDescription + "Enter",
@@ -263,16 +280,21 @@ function runTests()
     check(aDescription + "Alt+Enter", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Alt+Enter");
 
     reset("a");
     synthesizeKey("VK_ENTER", { metaKey: true });
     check(aDescription + "Meta+Enter", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Meta+Enter");
 
+    reset("a");
+    synthesizeKey("VK_ENTER", { osKey: true });
+    check(aDescription + "OS+Enter", true, true, false);
+    is(aElement.innerHTML, "a", aDescription + "OS+Enter");
+
     // Tab key:
     //   If editor is tabbable, editor doesn't consume all tab key events.
     //   Otherwise, editor consumes tab key event without any modifier keys.
     reset("a");
     synthesizeKey("VK_TAB", { });
     check(aDescription + "Tab",
           true, true, !aIsTabbable && !aIsReadonly);
     is(aElement.innerHTML,
@@ -306,16 +328,23 @@ function runTests()
 
     reset("a");
     synthesizeKey("VK_TAB", { metaKey: true });
     check(aDescription + "Meta+Tab", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Meta+Tab");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab)");
 
+    reset("a");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab", true, true, false);
+    is(aElement.innerHTML, "a", aDescription + "OS+Tab");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab)");
+
     // Indent/Outdent tests:
     // UL
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
     synthesizeKey("VK_TAB", { });
     check(aDescription + "Tab on UL",
           true, true, !aIsTabbable && !aIsReadonly);
     is(aElement.innerHTML,
        aIsReadonly || aIsTabbable ?
@@ -367,16 +396,24 @@ function runTests()
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
     synthesizeKey("VK_TAB", { metaKey: true });
     check(aDescription + "Meta+Tab on UL", true, true, false);
     is(aElement.innerHTML, "<ul><li id=\"target\">ul list item</li></ul>",
        aDescription + "Meta+Tab on UL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on UL)");
 
+    resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on UL", true, true, false);
+    is(aElement.innerHTML, "<ul><li id=\"target\">ul list item</li></ul>",
+       aDescription + "OS+Tab on UL");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on UL)");
+
     // OL
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { });
     check(aDescription + "Tab on OL",
           true, true, !aIsTabbable && !aIsReadonly);
     is(aElement.innerHTML,
        aIsReadonly || aIsTabbable ?
          "<ol><li id=\"target\">ol list item</li></ol>" :
@@ -427,16 +464,24 @@ function runTests()
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { metaKey: true });
     check(aDescription + "Meta+Tab on OL", true, true, false);
     is(aElement.innerHTML, "<ol><li id=\"target\">ol list item</li></ol>",
        aDescription + "Meta+Tab on OL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on OL)");
 
+    resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on OL", true, true, false);
+    is(aElement.innerHTML, "<ol><li id=\"target\">ol list item</li></ol>",
+       aDescription + "OS+Tab on OL");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on OL)");
+
     // TD
     resetForIndent("<table><tr><td id=\"target\">td</td></tr></table>");
     synthesizeKey("VK_TAB", { });
     check(aDescription + "Tab on TD",
           true, true, !aIsTabbable && !aIsReadonly);
     is(aElement.innerHTML,
        aIsTabbable || aIsReadonly ?
          "<table><tbody><tr><td id=\"target\">td</td></tr></tbody></table>" :
@@ -489,16 +534,25 @@ function runTests()
     synthesizeKey("VK_TAB", { metaKey: true });
     check(aDescription + "Meta+Tab on TD", true, true, false);
     is(aElement.innerHTML,
        "<table><tbody><tr><td id=\"target\">td</td></tr></tbody></table>",
        aDescription + "Meta+Tab on TD");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on TD)");
 
+    resetForIndent("<table><tr><td id=\"target\">td</td></tr></table>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on TD", true, true, false);
+    is(aElement.innerHTML,
+       "<table><tbody><tr><td id=\"target\">td</td></tr></tbody></table>",
+       aDescription + "OS+Tab on TD");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on TD)");
+
     // TH
     resetForIndent("<table><tr><th id=\"target\">th</th></tr></table>");
     synthesizeKey("VK_TAB", { });
     check(aDescription + "Tab on TH",
           true, true, !aIsTabbable && !aIsReadonly);
     is(aElement.innerHTML,
        aIsTabbable || aIsReadonly ?
          "<table><tbody><tr><th id=\"target\">th</th></tr></tbody></table>" :
@@ -551,16 +605,25 @@ function runTests()
     synthesizeKey("VK_TAB", { metaKey: true });
     check(aDescription + "Meta+Tab on TH", true, true, false);
     is(aElement.innerHTML,
        "<table><tbody><tr><th id=\"target\">th</th></tr></tbody></table>",
        aDescription + "Meta+Tab on TH");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on TH)");
 
+    resetForIndent("<table><tr><th id=\"target\">th</th></tr></table>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on TH", true, true, false);
+    is(aElement.innerHTML,
+       "<table><tbody><tr><th id=\"target\">th</th></tr></tbody></table>",
+       aDescription + "OS+Tab on TH");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on TH)");
+
     // Esc key:
     //   In all cases, esc key events are not consumed
     reset("abc");
     synthesizeKey("VK_ESCAPE", { });
     check(aDescription + "Esc", true, true, false);
 
     reset("abc");
     synthesizeKey("VK_ESCAPE", { shiftKey: true });
@@ -573,16 +636,20 @@ function runTests()
     reset("abc");
     synthesizeKey("VK_ESCAPE", { altKey: true });
     check(aDescription + "Alt+Esc", true, true, false);
 
     reset("abc");
     synthesizeKey("VK_ESCAPE", { metaKey: true });
     check(aDescription + "Meta+Esc", true, true, false);
 
+    reset("abc");
+    synthesizeKey("VK_ESCAPE", { osKey: true });
+    check(aDescription + "OS+Esc", true, true, false);
+
     // typical typing tests:
     reset("");
     synthesizeKey("M", { shiftKey: true });
     check(aDescription + "M", true, true, !aIsReadonly);
     synthesizeKey("o", { });
     check(aDescription + "o", true, true, !aIsReadonly);
     synthesizeKey("z", { });
     check(aDescription + "z", true, true, !aIsReadonly);
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -353,51 +353,55 @@ nsPlaintextEditor::HandleKeyPressEvent(n
 
   nsKeyEvent* nativeKeyEvent = GetNativeKeyEvent(aKeyEvent);
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
   NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS,
                "HandleKeyPressEvent gets non-keypress event");
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
+    case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
     case nsIDOMKeyEvent::DOM_VK_DELETE:
       // These keys are handled on nsEditor
       return nsEditor::HandleKeyPressEvent(aKeyEvent);
     case nsIDOMKeyEvent::DOM_VK_TAB: {
       if (IsTabbable()) {
         return NS_OK; // let it be used for focus switching
       }
 
       if (nativeKeyEvent->IsShift() || nativeKeyEvent->IsControl() ||
-          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+          nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
 
       // else we insert the tab straight through
       aKeyEvent->PreventDefault();
       return TypedText(NS_LITERAL_STRING("\t"), eTypedText);
     }
     case nsIDOMKeyEvent::DOM_VK_RETURN:
     case nsIDOMKeyEvent::DOM_VK_ENTER:
       if (IsSingleLineEditor() || nativeKeyEvent->IsControl() ||
-          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+          nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       aKeyEvent->PreventDefault();
       return TypedText(EmptyString(), eTypedBreak);
   }
 
   // NOTE: On some keyboard layout, some characters are inputted with Control
   // key or Alt key, but at that time, widget sets FALSE to these keys.
   if (nativeKeyEvent->charCode == 0 || nativeKeyEvent->IsControl() ||
-      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+      nativeKeyEvent->IsOS()) {
     // we don't PreventDefault() here or keybindings like control-x won't work
     return NS_OK;
   }
   aKeyEvent->PreventDefault();
   nsAutoString str(nativeKeyEvent->charCode);
   return TypedText(str, eTypedText);
 }
 
--- a/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
+++ b/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
@@ -119,16 +119,20 @@ function runTests()
     //   Basically, modifier keys shouldn't cause keypress event.  However,
     //   even if it were dispatched by widget's bug, editor should consume
     //   it when editor is editable.
     reset("");
     synthesizeKey("VK_META", { type: "keypress" });
     check(aDescription + "Meta", true, true, !aIsReadonly);
 
     reset("");
+    synthesizeKey("VK_WIN", { type: "keypress" });
+    check(aDescription + "OS", true, true, !aIsReadonly);
+
+    reset("");
     synthesizeKey("VK_SHIFT", { type: "keypress" });
     check(aDescription + "Shift", true, true, !aIsReadonly);
 
     reset("");
     synthesizeKey("VK_CONTROL", { type: "keypress" });
     check(aDescription + "Control", true, true, !aIsReadonly);
 
     // Alt key press event installs menubar key event listener, so,
@@ -164,16 +168,20 @@ function runTests()
     // Mac: cmd_deleteWordBackward
     check(aDescription + "Alt+Backspace",
           true, true, aIsReadonly || kIsWin || kIsMac);
 
     reset("");
     synthesizeKey("VK_BACK_SPACE", { metaKey: true });
     check(aDescription + "Meta+Backspace", true, true, aIsReadonly);
 
+    reset("");
+    synthesizeKey("VK_BACK_SPACE", { osKey: true });
+    check(aDescription + "OS+Backspace", true, true, aIsReadonly);
+
     // Delete key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable, delete is consumed.
     //   Otherwise, editor doesn't consume the event but the native key
     //   bindings on nsTextControlFrame may consume it.
     reset("");
     synthesizeKey("VK_DELETE", { });
     // Linux: native handler
@@ -201,16 +209,21 @@ function runTests()
           true, true, kIsMac);
 
     reset("");
     synthesizeKey("VK_DELETE", { metaKey: true });
     // Linux: native handler consumed.
     check(aDescription + "Meta+Delete",
           true, true, kIsLinux);
 
+    reset("");
+    synthesizeKey("VK_DELETE", { osKey: true });
+    check(aDescription + "OS+Delete",
+          true, true, false);
+
     // XXX input.value returns "\n" when it's empty, so, we should use dummy
     // value ("a") for the following tests.
 
     // Return key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
     //   and Shift+Return.
     //   Otherwise, editor doesn't consume the event.
@@ -238,16 +251,21 @@ function runTests()
     check(aDescription + "Alt+Return", true, true, false);
     is(aElement.value, "a", aDescription + "Alt+Return");
 
     reset("a");
     synthesizeKey("VK_RETURN", { metaKey: true });
     check(aDescription + "Meta+Return", true, true, false);
     is(aElement.value, "a", aDescription + "Meta+Return");
 
+    reset("a");
+    synthesizeKey("VK_RETURN", { osKey: true });
+    check(aDescription + "OS+Return", true, true, false);
+    is(aElement.value, "a", aDescription + "OS+Return");
+
     // Enter key (same as Return key):
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
     //   and Shift+Return.
     //   Otherwise, editor doesn't consume the event.
     reset("a");
     synthesizeKey("VK_ENTER", { });
     check(aDescription + "Enter",
@@ -272,16 +290,21 @@ function runTests()
     check(aDescription + "Alt+Enter", true, true, false);
     is(aElement.value, "a", aDescription + "Alt+Enter");
 
     reset("a");
     synthesizeKey("VK_ENTER", { metaKey: true });
     check(aDescription + "Meta+Enter", true, true, false);
     is(aElement.value, "a", aDescription + "Meta+Enter");
 
+    reset("a");
+    synthesizeKey("VK_ENTER", { osKey: true });
+    check(aDescription + "OS+Enter", true, true, false);
+    is(aElement.value, "a", aDescription + "OS+Enter");
+
     // Tab key:
     //   If editor is tabbable, editor doesn't consume all tab key events.
     //   Otherwise, editor consumes tab key event without any modifier keys.
     reset("a");
     synthesizeKey("VK_TAB", { });
     check(aDescription + "Tab",
           true, true, !aIsTabbable && !aIsReadonly);
     is(aElement.value, !aIsTabbable && !aIsReadonly ? "a\t" : "a",
@@ -325,16 +348,23 @@ function runTests()
 
     reset("a");
     synthesizeKey("VK_TAB", { metaKey: true });
     check(aDescription + "Meta+Tab", true, true, false);
     is(aElement.value, "a", aDescription + "Meta+Tab");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab)");
 
+    reset("a");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab", true, true, false);
+    is(aElement.value, "a", aDescription + "OS+Tab");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab)");
+
     // Esc key:
     //   In all cases, esc key events are not consumed
     reset("abc");
     synthesizeKey("VK_ESCAPE", { });
     check(aDescription + "Esc", true, true, false);
 
     reset("abc");
     synthesizeKey("VK_ESCAPE", { shiftKey: true });
@@ -347,16 +377,20 @@ function runTests()
     reset("abc");
     synthesizeKey("VK_ESCAPE", { altKey: true });
     check(aDescription + "Alt+Esc", true, true, false);
 
     reset("abc");
     synthesizeKey("VK_ESCAPE", { metaKey: true });
     check(aDescription + "Meta+Esc", true, true, false);
 
+    reset("abc");
+    synthesizeKey("VK_ESCAPE", { osKey: true });
+    check(aDescription + "OS+Esc", true, true, false);
+
     // typical typing tests:
     reset("");
     synthesizeKey("M", { shiftKey: true });
     check(aDescription + "M", true, true, !aIsReadonly);
     synthesizeKey("o", { });
     check(aDescription + "o", true, true, !aIsReadonly);
     synthesizeKey("z", { });
     check(aDescription + "z", true, true, !aIsReadonly);
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -17,16 +17,17 @@
 #include "nsILineInputStream.h"
 #include "nsIIDNService.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "prprf.h"
 #include "mozilla/storage.h"
 #include "mozilla/Attributes.h"
 #include "nsXULAppAPI.h"
 #include "nsIPrincipal.h"
+#include "nsContentUtils.h"
 
 static nsPermissionManager *gPermissionManager = nsnull;
 
 using mozilla::dom::ContentParent;
 using mozilla::dom::ContentChild;
 using mozilla::unused; // ha!
 
 static bool
@@ -506,16 +507,22 @@ nsPermissionManager::Add(nsIURI     *aUR
 
 NS_IMETHODIMP
 nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal,
                                       const char* aType, PRUint32 aPermission,
                                       PRUint32 aExpireType, PRInt64 aExpireTime)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
+  // We don't add the system principal because it actually has no URI and we
+  // always allow action for them.
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIURI> uri;
   aPrincipal->GetURI(getter_AddRefs(uri));
 
   return Add(uri, aType, aPermission, aExpireType, aExpireTime);
 }
 
 nsresult
 nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
@@ -696,16 +703,21 @@ nsPermissionManager::Remove(const nsACSt
 }
 
 NS_IMETHODIMP
 nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal,
                                          const char* aType)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
+  // System principals are never added to the database, no need to remove them.
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIURI> uri;
   aPrincipal->GetURI(getter_AddRefs(uri));
   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
   nsCAutoString host;
   uri->GetHost(host);
 
   return Remove(host, aType);
@@ -785,29 +797,43 @@ nsPermissionManager::TestPermission(nsIU
 
 NS_IMETHODIMP
 nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal,
                                                  const char* aType,
                                                  PRUint32* aPermission)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
+  // System principals do not have URI so we can't try to get
+  // retro-compatibility here.
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    *aPermission = nsIPermissionManager::ALLOW_ACTION;
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIURI> uri;
   aPrincipal->GetURI(getter_AddRefs(uri));
 
   return TestPermission(uri, aType, aPermission);
 }
 
 NS_IMETHODIMP
 nsPermissionManager::TestExactPermissionFromPrincipal(nsIPrincipal* aPrincipal,
                                                       const char* aType,
                                                       PRUint32* aPermission)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
+  // System principals do not have URI so we can't try to get
+  // retro-compatibility here.
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    *aPermission = nsIPermissionManager::ALLOW_ACTION;
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIURI> uri;
   aPrincipal->GetURI(getter_AddRefs(uri));
 
   return TestExactPermission(uri, aType, aPermission);
 }
 
 nsresult
 nsPermissionManager::CommonTestPermission(nsIURI     *aURI,
--- a/extensions/spellcheck/hunspell/src/affentry.cpp
+++ b/extensions/spellcheck/hunspell/src/affentry.cpp
@@ -592,17 +592,18 @@ inline int SfxEntry::test_condition(cons
                             while (p && *p != ']' && (p = nextchar(p)));
 			    st--;
                         }
                         if (p && *p != ']') p = nextchar(p);
                     } else if (pos) {
                         if (neg) return 0;
                         else if (i == numconds) return 1;
                         ingroup = true;
-			while (p && *p != ']' && (p = nextchar(p)));
+			while (p && *p != ']' && (p = nextchar(p)))
+                          ;
 //			if (p && *p != ']') p = nextchar(p);
                         st--;
                     }
                     if (!pos) {
                         i++;
                         st--;
                     }
                     if (st < beg && p && *p != ']') return 0; // word <= condition
--- a/extensions/spellcheck/hunspell/src/mozHunspellDirProvider.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspellDirProvider.h
@@ -33,29 +33,30 @@
  *
  ******* END LICENSE BLOCK *******/
 
 #ifndef mozHunspellDirProvider_h__
 #define mozHunspellDirProvider_h__
 
 #include "nsIDirectoryService.h"
 #include "nsISimpleEnumerator.h"
+#include "mozilla/Attributes.h"
 
-class mozHunspellDirProvider :
+class mozHunspellDirProvider MOZ_FINAL :
   public nsIDirectoryServiceProvider2
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDIRECTORYSERVICEPROVIDER
   NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
 
   static char const *const kContractID;
 
 private:
-  class AppendingEnumerator : public nsISimpleEnumerator
+  class AppendingEnumerator MOZ_FINAL : public nsISimpleEnumerator
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISIMPLEENUMERATOR
 
     AppendingEnumerator(nsISimpleEnumerator* aBase);
 
   private:
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -1566,17 +1566,19 @@ public:
         nsRefPtr<gfxXlibSurface> xsurface =
             gfxXlibSurface::Create(DefaultScreenOfDisplay(dpy),
                                    renderFMT,
                                    gfxIntSize(aSize.width, aSize.height));
 
         XSync(dpy, False);
         mConfig = nsnull;
 
-        if (sEGLLibrary.HasKHRImagePixmap() && sEGLLibrary.HasKHRImageTexture2D()) {
+        if (sEGLLibrary.HasKHRImagePixmap() &&
+            mGLContext->IsExtensionSupported(GLContext::OES_EGL_image))
+        {
             mEGLImage =
                 sEGLLibrary.fCreateImage(EGL_DISPLAY(),
                                          EGL_NO_CONTEXT,
                                          LOCAL_EGL_NATIVE_PIXMAP_KHR,
                                          (EGLClientBuffer)xsurface->XDrawable(),
                                          nsnull);
 
             if (!mEGLImage) {
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -11,16 +11,17 @@
 #include "nsISupportsImpl.h"
 #include "gfxPattern.h"
 #include "nsThreadUtils.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/Mutex.h"
 #include "gfxPlatform.h"
+#include "LayersBackend.h"
 
 #ifdef XP_MACOSX
 #include "nsIOSurface.h"
 #endif
 #ifdef XP_WIN
 struct ID3D10Texture2D;
 struct ID3D10Device;
 struct ID3D10ShaderResourceView;
@@ -128,28 +129,28 @@ public:
   };
 
   Format GetFormat() { return mFormat; }
   void* GetImplData() { return mImplData; }
 
   virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
   virtual gfxIntSize GetSize() = 0;
 
-  ImageBackendData* GetBackendData(LayerManager::LayersBackend aBackend)
+  ImageBackendData* GetBackendData(LayersBackend aBackend)
   { return mBackendData[aBackend]; }
-  void SetBackendData(LayerManager::LayersBackend aBackend, ImageBackendData* aData)
+  void SetBackendData(LayersBackend aBackend, ImageBackendData* aData)
   { mBackendData[aBackend] = aData; }
 
 protected:
   Image(void* aImplData, Format aFormat) :
     mImplData(aImplData),
     mFormat(aFormat)
   {}
 
-  nsAutoPtr<ImageBackendData> mBackendData[LayerManager::LAYERS_LAST];
+  nsAutoPtr<ImageBackendData> mBackendData[mozilla::layers::LAYERS_LAST];
 
   void* mImplData;
   Format mFormat;
 };
 
 /**
  * A RecycleBin is owned by an ImageContainer. We store buffers in it that we
  * want to recycle from one image to the next.It's a separate object from 
--- a/gfx/layers/LayerSorter.cpp
+++ b/gfx/layers/LayerSorter.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerSorter.h"
 #include "DirectedGraph.h"
 #include "limits.h"
 #include "gfxLineSegment.h"
+#include "Layers.h"
 
 namespace mozilla {
 namespace layers {
 
 enum LayerSortOrder {
   Undefined,
   ABeforeB,
   BBeforeA,
--- a/gfx/layers/LayerSorter.h
+++ b/gfx/layers/LayerSorter.h
@@ -1,18 +1,20 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_LAYERSORTER_H
 #define GFX_LAYERSORTER_H
 
-#include "Layers.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 namespace layers {
 
+class Layer;
+
 void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers);
 
 }
 }
 #endif /* GFX_LAYERSORTER_H */
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -13,17 +13,17 @@
 #include "nsRect.h"
 #include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
 #include "gfx3DMatrix.h"
 #include "gfxColor.h"
 #include "gfxPattern.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
-
+#include "LayersBackend.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/TimeStamp.h"
 
 #if defined(DEBUG) || defined(PR_LOGGING)
 #  include <stdio.h>            // FILE
 #  include "prlog.h"
 #  ifndef MOZ_LAYERS_HAVE_LOG
 #    define MOZ_LAYERS_HAVE_LOG
@@ -195,25 +195,16 @@ static void LayerManagerUserDataDestroy(
  * 
  * Layers are refcounted. The layer manager holds a reference to the
  * root layer, and each container layer holds a reference to its children.
  */
 class THEBES_API LayerManager {
   NS_INLINE_DECL_REFCOUNTING(LayerManager)
 
 public:
-  enum LayersBackend {
-    LAYERS_NONE = 0,
-    LAYERS_BASIC,
-    LAYERS_OPENGL,
-    LAYERS_D3D9,
-    LAYERS_D3D10,
-    LAYERS_LAST
-  };
-
   LayerManager() : mDestroyed(false), mSnapEffectiveTransforms(true), mId(0)
   {
     InitLog();
   }
   virtual ~LayerManager() {}
 
   /**
    * Release layers and resources held by this layer manager, and mark
@@ -503,17 +494,17 @@ public:
   void StartFrameTimeRecording();
   nsTArray<float> StopFrameTimeRecording();
 
   void PostPresent();
 
   static bool IsLogEnabled();
   static PRLogModuleInfo* GetLog() { return sLog; }
 
-  bool IsCompositingCheap(LayerManager::LayersBackend aBackend)
+  bool IsCompositingCheap(LayersBackend aBackend)
   { return LAYERS_BASIC != aBackend; }
 
   virtual bool IsCompositingCheap() { return true; }
 
 protected:
   nsRefPtr<Layer> mRoot;
   gfx::UserData mUserData;
   bool mDestroyed;
new file mode 100644
--- /dev/null
+++ b/gfx/layers/LayersBackend.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_LAYERSBACKEND_H
+#define GFX_LAYERSBACKEND_H
+
+namespace mozilla {
+namespace layers {
+enum LayersBackend {
+  LAYERS_NONE = 0,
+  LAYERS_BASIC,
+  LAYERS_OPENGL,
+  LAYERS_D3D9,
+  LAYERS_D3D10,
+  LAYERS_LAST
+};
+}
+}
+
+#endif /* GFX_LAYERSBACKEND_H */
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -28,16 +28,17 @@ DEFINES += -DD3D_DEBUG_INFO
 endif
 
 EXPORTS = \
         BasicLayers.h \
         BasicTiledThebesLayer.h \
         BasicImplData.h \
         ImageLayers.h \
         Layers.h \
+        LayersBackend.h \
         LayerManagerOGLShaders.h \
         LayerManagerOGL.h \
         LayerManagerOGLProgram.h \
         ReadbackLayer.h \
         LayerSorter.h \
         $(NULL)
 
 CPPSRCS = \
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -5,16 +5,17 @@
 
 #include "mozilla/layers/PLayersParent.h"
 #include "gfxImageSurface.h"
 #include "GLContext.h"
 #include "gfxUtils.h"
 
 #include "BasicLayersImpl.h"
 #include "nsXULAppAPI.h"
+#include "LayersBackend.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class BasicCanvasLayer : public CanvasLayer,
                          public BasicImplData
@@ -369,17 +370,17 @@ void
 BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
 {
   if (!HasShadow()) {
     BasicCanvasLayer::Paint(aContext, aMaskLayer);
     return;
   }
 
   if (mGLContext &&
-      BasicManager()->GetParentBackendType() == LayerManager::LAYERS_OPENGL) {
+      BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) {
     TextureImage::TextureShareType flags;
     // if process type is default, then it is single-process (non-e10s)
     if (XRE_GetProcessType() == GeckoProcessType_Default)
       flags = TextureImage::ThreadShared;
     else
       flags = TextureImage::ProcessShared;
 
     SharedTextureHandle handle = GetSharedBackBufferHandle();
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -1128,17 +1128,17 @@ BasicShadowLayerManager::SetIsFirstPaint
   ShadowLayerForwarder::SetIsFirstPaint();
 }
 
 already_AddRefed<ThebesLayer>
 BasicShadowLayerManager::CreateThebesLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
 #ifdef FORCE_BASICTILEDTHEBESLAYER
-  if (HasShadowManager() && GetParentBackendType() == LayerManager::LAYERS_OPENGL) {
+  if (HasShadowManager() && GetParentBackendType() == LAYERS_OPENGL) {
     // BasicTiledThebesLayer doesn't support main
     // thread compositing so only return this layer
     // type if we have a shadow manager.
     nsRefPtr<BasicTiledThebesLayer> layer =
       new BasicTiledThebesLayer(this);
     MAYBE_CREATE_SHADOW(Thebes);
     return layer.forget();
   } else
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -9,31 +9,31 @@
 #include "gfxWindowsSurface.h"
 #include "yuv_convert.h"
 #include "../d3d9/Nv3DVUtils.h"
 
 #include "gfxWindowsPlatform.h"
 
 namespace mozilla {
 namespace layers {
-  
+
 static already_AddRefed<ID3D10Texture2D>
 DataToTexture(ID3D10Device *aDevice,
               unsigned char *data,
               int stride,
               const gfxIntSize &aSize)
 {
   D3D10_SUBRESOURCE_DATA srdata;
-  
+
   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
                              aSize.width,
                              aSize.height,
                              1, 1);
   desc.Usage = D3D10_USAGE_IMMUTABLE;
-  
+
   srdata.pSysMem = data;
   srdata.SysMemPitch = stride;
 
   nsRefPtr<ID3D10Texture2D> texture;
   HRESULT hr = aDevice->CreateTexture2D(&desc, &srdata, getter_AddRefs(texture));
 
   if (FAILED(hr)) {
     LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for data"),
@@ -94,24 +94,24 @@ ImageLayerD3D10::GetLayer()
 ID3D10ShaderResourceView*
 ImageLayerD3D10::GetImageSRView(Image* aImage, bool& aHasAlpha, IDXGIKeyedMutex **aMutex)
 {
   NS_ASSERTION(aImage, "Null image.");
 
   if (aImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
     RemoteBitmapImage *remoteImage =
       static_cast<RemoteBitmapImage*>(aImage);
-      
-    if (!aImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
+
+    if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) {
       nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData());
       dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize);
 
       if (dat->mTexture) {
         device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
-        aImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
+        aImage->SetBackendData(mozilla::layers::LAYERS_D3D10, dat.forget());
       }
     }
 
     aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
   } else if (aImage->GetFormat() == Image::REMOTE_IMAGE_DXGI_TEXTURE) {
     RemoteDXGITextureImage *remoteImage =
       static_cast<RemoteDXGITextureImage*>(aImage);
 
@@ -121,34 +121,34 @@ ImageLayerD3D10::GetImageSRView(Image* a
   } else if (aImage->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImage *cairoImage =
       static_cast<CairoImage*>(aImage);
 
     if (!cairoImage->mSurface) {
       return nsnull;
     }
 
-    if (!aImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
+    if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) {
       nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData());
       dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
 
       if (dat->mTexture) {
         device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
-        aImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
+        aImage->SetBackendData(mozilla::layers::LAYERS_D3D10, dat.forget());
       }
     }
 
     aHasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
   } else {
     NS_WARNING("Incorrect image type.");
     return nsnull;
   }
 
   TextureD3D10BackendData *data =
-    static_cast<TextureD3D10BackendData*>(aImage->GetBackendData(LayerManager::LAYERS_D3D10));
+    static_cast<TextureD3D10BackendData*>(aImage->GetBackendData(mozilla::layers::LAYERS_D3D10));
 
   if (!data) {
     return nsnull;
   }
 
   if (aMutex &&
       SUCCEEDED(data->mTexture->QueryInterface(IID_IDXGIKeyedMutex, (void**)aMutex))) {
     if (FAILED((*aMutex)->AcquireSync(0, 0))) {
@@ -196,17 +196,17 @@ ImageLayerD3D10::RenderLayer()
                  static_cast<CairoImage*>(image)->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA,
                  "Image layer has alpha image");
     bool hasAlpha = false;
 
     nsRefPtr<ID3D10ShaderResourceView> srView = GetImageSRView(image, hasAlpha, getter_AddRefs(keyedMutex));
     if (!srView) {
       return;
     }
-    
+
     PRUint8 shaderFlags = SHADER_PREMUL;
     shaderFlags |= LoadMaskTexture();
     shaderFlags |= hasAlpha
                   ? SHADER_RGBA : SHADER_RGB;
     shaderFlags |= mFilter == gfxPattern::FILTER_NEAREST
                   ? SHADER_POINT : SHADER_LINEAR;
     technique = SelectShader(shaderFlags);
 
@@ -223,22 +223,22 @@ ImageLayerD3D10::RenderLayer()
   } else if (image->GetFormat() == Image::PLANAR_YCBCR) {
     PlanarYCbCrImage *yuvImage =
       static_cast<PlanarYCbCrImage*>(image);
 
     if (!yuvImage->mBufferSize) {
       return;
     }
 
-    if (!yuvImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
+    if (!yuvImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) {
       AllocateTexturesYCbCr(yuvImage);
     }
 
     PlanarYCbCrD3D10BackendData *data =
-      static_cast<PlanarYCbCrD3D10BackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_D3D10));
+      static_cast<PlanarYCbCrD3D10BackendData*>(yuvImage->GetBackendData(mozilla::layers::LAYERS_D3D10));
 
     if (!data) {
       return;
     }
 
     nsRefPtr<ID3D10Device> dev;
     data->mYTexture->GetDevice(getter_AddRefs(dev));
     if (dev != device()) {
@@ -362,17 +362,17 @@ void ImageLayerD3D10::AllocateTexturesYC
     LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D10::AllocateTextures(): Failed to create texture"),
                                      hr);
     return;
   }
   device()->CreateShaderResourceView(backendData->mYTexture, NULL, getter_AddRefs(backendData->mYView));
   device()->CreateShaderResourceView(backendData->mCbTexture, NULL, getter_AddRefs(backendData->mCbView));
   device()->CreateShaderResourceView(backendData->mCrTexture, NULL, getter_AddRefs(backendData->mCrView));
 
-  aImage->SetBackendData(LayerManager::LAYERS_D3D10, backendData.forget());
+  aImage->SetBackendData(mozilla::layers::LAYERS_D3D10, backendData.forget());
 }
 
 already_AddRefed<ID3D10ShaderResourceView>
 ImageLayerD3D10::GetAsTexture(gfxIntSize* aSize)
 {
   if (!GetContainer()) {
     return nsnull;
   }
@@ -464,19 +464,19 @@ RemoteDXGITextureImage::GetAsSurface()
   softTexture->Unmap(0);
 
   return surface.forget();
 }
 
 TextureD3D10BackendData*
 RemoteDXGITextureImage::GetD3D10TextureBackendData(ID3D10Device *aDevice)
 {
-  if (GetBackendData(LayerManager::LAYERS_D3D10)) {
+  if (GetBackendData(mozilla::layers::LAYERS_D3D10)) {
     TextureD3D10BackendData *data =
-      static_cast<TextureD3D10BackendData*>(GetBackendData(LayerManager::LAYERS_D3D10));
+      static_cast<TextureD3D10BackendData*>(GetBackendData(mozilla::layers::LAYERS_D3D10));
     
     nsRefPtr<ID3D10Device> device;
     data->mTexture->GetDevice(getter_AddRefs(device));
 
     if (device == aDevice) {
       return data;
     }
   }
@@ -489,15 +489,15 @@ RemoteDXGITextureImage::GetD3D10TextureB
   }
 
   nsAutoPtr<TextureD3D10BackendData> data(new TextureD3D10BackendData());
 
   data->mTexture = texture;
 
   aDevice->CreateShaderResourceView(texture, NULL, getter_AddRefs(data->mSRView));
 
-  SetBackendData(LayerManager::LAYERS_D3D10, data);
+  SetBackendData(mozilla::layers::LAYERS_D3D10, data);
 
   return data.forget();
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -447,17 +447,16 @@ LayerManagerD3D10::CreateDrawTarget(cons
        aFormat != FORMAT_B8G8R8X8)) {
     return LayerManager::CreateDrawTarget(aSize, aFormat);
   }
 
   nsRefPtr<ID3D10Texture2D> texture;
   
   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
   desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
-  desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
   
   HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(texture));
 
   if (FAILED(hr)) {
     NS_WARNING("Failed to create new texture for CreateOptimalSurface!");
     return LayerManager::CreateDrawTarget(aSize, aFormat);
   }
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -50,18 +50,16 @@ extern cairo_user_data_key_t gKeyD3D10Te
  *
  * For the time being, LayerManagerD3D10 both forwards layers
  * transactions and receives forwarded transactions.  In the Azure
  * future, it will only be a ShadowLayerManager.
  */
 class THEBES_API LayerManagerD3D10 : public ShadowLayerManager,
                                      public ShadowLayerForwarder {
 public:
-  typedef LayerManager::LayersBackend LayersBackend;
-
   LayerManagerD3D10(nsIWidget *aWidget);
   virtual ~LayerManagerD3D10();
 
   /*
    * Initializes the layer manager, this is when the layer manager will
    * actually access the device and attempt to create the swap chain used
    * to draw to the window. If this method fails the device cannot be used.
    * This function is not threadsafe.
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -274,17 +274,17 @@ static void AllocateTexturesYCbCr(Planar
     backendData->mCrTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
     aDevice->UpdateSurface(tmpSurfaceCr, NULL, dstSurface, NULL);
   } else {
     backendData->mYTexture->UnlockRect(0);
     backendData->mCbTexture->UnlockRect(0);
     backendData->mCrTexture->UnlockRect(0);
   }
 
-  aImage->SetBackendData(LayerManager::LAYERS_D3D9, backendData.forget());
+  aImage->SetBackendData(mozilla::layers::LAYERS_D3D9, backendData.forget());
 }
 
 Layer*
 ImageLayerD3D9::GetLayer()
 {
   return this;
 }
 
@@ -299,49 +299,49 @@ IDirect3DTexture9*
 ImageLayerD3D9::GetTexture(Image *aImage, bool& aHasAlpha)
 {
   NS_ASSERTION(aImage, "Null image.");
 
   if (aImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
     RemoteBitmapImage *remoteImage =
       static_cast<RemoteBitmapImage*>(aImage);
       
-    if (!aImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
+    if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D9)) {
       nsAutoPtr<TextureD3D9BackendData> dat(new TextureD3D9BackendData());
       dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize, D3DFMT_A8R8G8B8);
       if (dat->mTexture) {
-        aImage->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
+        aImage->SetBackendData(mozilla::layers::LAYERS_D3D9, dat.forget());
       }
     }
 
     aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
   } else if (aImage->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImage *cairoImage =
       static_cast<CairoImage*>(aImage);
 
     if (!cairoImage->mSurface) {
       return nsnull;
     }
 
-    if (!aImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
+    if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D9)) {
       nsAutoPtr<TextureD3D9BackendData> dat(new TextureD3D9BackendData());
       dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
       if (dat->mTexture) {
-        aImage->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
+        aImage->SetBackendData(mozilla::layers::LAYERS_D3D9, dat.forget());
       }
     }
 
     aHasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
   } else {
     NS_WARNING("Inappropriate image type.");
     return nsnull;
   }
 
   TextureD3D9BackendData *data =
-    static_cast<TextureD3D9BackendData*>(aImage->GetBackendData(LayerManager::LAYERS_D3D9));
+    static_cast<TextureD3D9BackendData*>(aImage->GetBackendData(mozilla::layers::LAYERS_D3D9));
 
   if (!data) {
     return nsnull;
   }
 
   nsRefPtr<IDirect3DDevice9> dev;
   data->mTexture->GetDevice(getter_AddRefs(dev));
   if (dev != device()) {
@@ -411,22 +411,22 @@ ImageLayerD3D9::RenderLayer()
   } else {
     PlanarYCbCrImage *yuvImage =
       static_cast<PlanarYCbCrImage*>(image);
 
     if (!yuvImage->mBufferSize) {
       return;
     }
 
-    if (!yuvImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
+    if (!yuvImage->GetBackendData(mozilla::layers::LAYERS_D3D9)) {
       AllocateTexturesYCbCr(yuvImage, device(), mD3DManager);
     }
 
     PlanarYCbCrD3D9BackendData *data =
-      static_cast<PlanarYCbCrD3D9BackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_D3D9));
+      static_cast<PlanarYCbCrD3D9BackendData*>(yuvImage->GetBackendData(mozilla::layers::LAYERS_D3D9));
 
     if (!data) {
       return;
     }
 
     nsRefPtr<IDirect3DDevice9> dev;
     data->mYTexture->GetDevice(getter_AddRefs(dev));
     if (dev != device()) {
@@ -611,31 +611,31 @@ ShadowImageLayerD3D9::RenderLayer()
 {
   if (mBuffer) {
     mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
   } else if (mYCbCrImage) {
     if (!mYCbCrImage->mBufferSize) {
       return;
     }
 
-    if (!mYCbCrImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
+    if (!mYCbCrImage->GetBackendData(mozilla::layers::LAYERS_D3D9)) {
       AllocateTexturesYCbCr(mYCbCrImage, device(), mD3DManager);
     }
 
     PlanarYCbCrD3D9BackendData *data =
-      static_cast<PlanarYCbCrD3D9BackendData*>(mYCbCrImage->GetBackendData(LayerManager::LAYERS_D3D9));
+      static_cast<PlanarYCbCrD3D9BackendData*>(mYCbCrImage->GetBackendData(mozilla::layers::LAYERS_D3D9));
 
     if (!data) {
       return;
     }
 
     if (!mYCbCrImage->mBufferSize) {
       return;
     }
-    
+
     SetShaderTransformAndOpacity();
 
     device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(0,
                                                           0,
                                                           mYCbCrImage->mSize.width,
                                                           mYCbCrImage->mSize.height),
                                        1);
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -635,17 +635,17 @@ CompositorParent::AllocPLayers(const Lay
   // NULL before returning from this method, to avoid accessing it elsewhere.
   nsIntRect rect;
   mWidget->GetBounds(rect);
   mWidgetSize.width = rect.width;
   mWidgetSize.height = rect.height;
 
   *aBackend = aBackendHint;
 
-  if (aBackendHint == LayerManager::LAYERS_OPENGL) {
+  if (aBackendHint == mozilla::layers::LAYERS_OPENGL) {
     nsRefPtr<LayerManagerOGL> layerManager;
     layerManager =
       new LayerManagerOGL(mWidget, mEGLSurfaceSize.width, mEGLSurfaceSize.height, mRenderToEGLSurface);
     mWidget = NULL;
     mLayerManager = layerManager;
     ShadowLayerManager* shadowManager = layerManager->AsShadowManager();
     if (shadowManager) {
       shadowManager->SetCompositorID(mCompositorID);  
@@ -657,17 +657,17 @@ CompositorParent::AllocPLayers(const Lay
     }
 
     ShadowLayerManager* slm = layerManager->AsShadowManager();
     if (!slm) {
       return NULL;
     }
     *aMaxTextureSize = layerManager->GetMaxTextureSize();
     return new ShadowLayersParent(slm, this, 0);
-  } else if (aBackendHint == LayerManager::LAYERS_BASIC) {
+  } else if (aBackendHint == mozilla::layers::LAYERS_BASIC) {
     nsRefPtr<LayerManager> layerManager = new BasicShadowLayerManager(mWidget);
     mWidget = NULL;
     mLayerManager = layerManager;
     ShadowLayerManager* slm = layerManager->AsShadowManager();
     if (!slm) {
       return NULL;
     }
     *aMaxTextureSize = layerManager->GetMaxTextureSize();
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -2,17 +2,17 @@
  * vim: sw=2 ts=8 et :
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PLayers;
 
-using mozilla::LayersBackend;
+using mozilla::layers::LayersBackend;
 using mozilla::null_t;
 
 namespace mozilla {
 namespace layers {
 
 /**
  * The PCompositor protocol is used to manage communication between
  * the main thread and the compositor thread context. It's primary
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layers/PLayersParent.h"
 #include "ShadowLayers.h"
 #include "ShadowLayerChild.h"
 #include "gfxipc/ShadowLayerUtils.h"
 #include "RenderTrace.h"
 #include "sampler.h"
 #include "nsXULAppAPI.h"
+#include "LayersBackend.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace layers {
 
 typedef nsTArray<SurfaceDescriptor> BufferArray; 
 typedef std::vector<Edit> EditVector;
@@ -104,17 +105,17 @@ struct AutoTxnEnd {
   AutoTxnEnd(Transaction* aTxn) : mTxn(aTxn) {}
   ~AutoTxnEnd() { mTxn->End(); }
   Transaction* mTxn;
 };
 
 ShadowLayerForwarder::ShadowLayerForwarder()
  : mShadowManager(NULL)
  , mMaxTextureSize(0)
- , mParentBackend(LayerManager::LAYERS_NONE)
+ , mParentBackend(mozilla::layers::LAYERS_NONE)
  , mIsFirstPaint(false)
 {
   mTxn = new Transaction();
 }
 
 ShadowLayerForwarder::~ShadowLayerForwarder()
 {
   NS_ABORT_IF_FALSE(mTxn->Finished(), "unfinished transaction?");
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -6,17 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_ShadowLayers_h
 #define mozilla_layers_ShadowLayers_h 1
 
 #include "gfxASurface.h"
 
 #include "ImageLayers.h"
-#include "Layers.h"
+#include "LayersBackend.h"
 #include "mozilla/ipc/SharedMemory.h"
 
 class gfxSharedImageSurface;
 
 namespace mozilla {
 namespace layers {
 
 class Edit;
@@ -96,17 +96,16 @@ enum OpenMode {
  */
 
 class ShadowLayerForwarder
 {
   friend class AutoOpenSurface;
 
 public:
   typedef gfxASurface::gfxContentType gfxContentType;
-  typedef LayerManager::LayersBackend LayersBackend;
 
   virtual ~ShadowLayerForwarder();
 
   /**
    * Begin recording a transaction to be forwarded atomically to a
    * ShadowLayerManager.
    */
   void BeginTransaction();
@@ -459,17 +458,17 @@ protected:
  * SurfaceDeallocator interface
  */
 class ISurfaceDeAllocator
 {
 public:
   virtual void DestroySharedSurface(gfxSharedImageSurface* aSurface) = 0;
   virtual void DestroySharedSurface(SurfaceDescriptor* aSurface) = 0;
 protected:
-  ~ISurfaceDeAllocator() {};
+  ~ISurfaceDeAllocator() {}
 };
 
 /**
  * A ShadowLayer is the representation of a child-context's Layer in a
  * parent context.  They can be transformed, clipped,
  * etc. independently of their origin Layers.
  *
  * Note that ShadowLayers can themselves have a shadow in a parent
@@ -486,17 +485,17 @@ public:
    * that is why allowed multiple call with the same Allocator
    */
   virtual void SetAllocator(ISurfaceDeAllocator* aAllocator)
   {
     NS_ASSERTION(!mAllocator || mAllocator == aAllocator, "Stomping allocator?");
     mAllocator = aAllocator;
   }
 
-  virtual void DestroyFrontBuffer() { };
+  virtual void DestroyFrontBuffer() { }
 
   /**
    * The following methods are
    *
    * CONSTRUCTION PHASE ONLY
    *
    * They are analogous to the Layer interface.
    */
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/layers/ImageContainerParent.h"
 
 #include "ipc/AutoOpenSurface.h"
 #include "ImageLayerOGL.h"
 #include "gfxImageSurface.h"
 #include "gfxUtils.h"
 #include "yuv_convert.h"
 #include "GLContextProvider.h"
+#include "LayersBackend.h"
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
 # include "GLXLibrary.h"
 # include "mozilla/X11Util.h"
 #endif
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
@@ -167,34 +168,34 @@ AllocateTextureIOSurface(MacIOSurfaceIma
   void *nativeCtx = aGL->GetNativeData(GLContext::NativeGLContext);
 
   aIOImage->GetIOSurface()->CGLTexImageIOSurface2D(nativeCtx,
                                      LOCAL_GL_RGBA, LOCAL_GL_BGRA,
                                      LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, 0);
 
   aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 
-  aIOImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
+  aIOImage->SetBackendData(LAYERS_OPENGL, backendData.forget());
 }
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 struct THEBES_API GonkIOSurfaceImageOGLBackendData : public ImageBackendData
 {
   GLTexture mTexture;
 };
 
 void
 AllocateTextureIOSurface(GonkIOSurfaceImage *aIOImage, mozilla::gl::GLContext* aGL)
 {
   nsAutoPtr<GonkIOSurfaceImageOGLBackendData> backendData(
     new GonkIOSurfaceImageOGLBackendData);
 
   backendData->mTexture.Allocate(aGL);
-  aIOImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
+  aIOImage->SetBackendData(LAYERS_OPENGL, backendData.forget());
 }
 #endif
 
 Layer*
 ImageLayerOGL::GetLayer()
 {
   return this;
 }
@@ -226,28 +227,28 @@ ImageLayerOGL::RenderLayer(int,
     PlanarYCbCrImage *yuvImage =
       static_cast<PlanarYCbCrImage*>(image);
 
     if (!yuvImage->mBufferSize) {
       return;
     }
 
     PlanarYCbCrOGLBackendData *data =
-      static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+      static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LAYERS_OPENGL));
 
     if (data && data->mTextures->GetGLContext() != gl()) {
       // If these textures were allocated by another layer manager,
       // clear them out and re-allocate below.
       data = nsnull;
-      yuvImage->SetBackendData(LayerManager::LAYERS_OPENGL, nsnull);
+      yuvImage->SetBackendData(LAYERS_OPENGL, nsnull);
     }
 
     if (!data) {
       AllocateTexturesYCbCr(yuvImage);
-      data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+      data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LAYERS_OPENGL));
     }
 
     if (!data || data->mTextures->GetGLContext() != gl()) {
       // XXX - Can this ever happen? If so I need to fix this!
       return;
     }
 
     gl()->MakeCurrent();
@@ -289,28 +290,28 @@ ImageLayerOGL::RenderLayer(int,
     if (!cairoImage->mSurface) {
       return;
     }
 
     NS_ASSERTION(cairoImage->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA,
                  "Image layer has alpha image");
 
     CairoOGLBackendData *data =
-      static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+      static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LAYERS_OPENGL));
 
     if (data && data->mTexture.GetGLContext() != gl()) {
       // If this texture was allocated by another layer manager, clear
       // it out and re-allocate below.
       data = nsnull;
-      cairoImage->SetBackendData(LayerManager::LAYERS_OPENGL, nsnull);
+      cairoImage->SetBackendData(LAYERS_OPENGL, nsnull);
     }
 
     if (!data) {
       AllocateTexturesCairo(cairoImage);
-      data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+      data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LAYERS_OPENGL));
     }
 
     if (!data || data->mTexture.GetGLContext() != gl()) {
       // XXX - Can this ever happen? If so I need to fix this!
       return;
     }
 
     gl()->MakeCurrent();
@@ -375,65 +376,65 @@ ImageLayerOGL::RenderLayer(int,
      }
 
      if (!ioImage) {
        return;
      }
 
      gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
-     if (!ioImage->GetBackendData(LayerManager::LAYERS_OPENGL)) {
+     if (!ioImage->GetBackendData(LAYERS_OPENGL)) {
        AllocateTextureIOSurface(ioImage, gl());
      }
 
      MacIOSurfaceImageOGLBackendData *data =
-      static_cast<MacIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+      static_cast<MacIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LAYERS_OPENGL));
 
      gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
      gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, data->mTexture.GetTextureID());
 
      ShaderProgramOGL *program =
        mOGLManager->GetProgram(gl::RGBARectLayerProgramType, GetMaskLayer());
-     
+
      program->Activate();
      if (program->GetTexCoordMultiplierUniformLocation() != -1) {
        // 2DRect case, get the multiplier right for a sampler2DRect
        program->SetTexCoordMultiplier(ioImage->GetSize().width, ioImage->GetSize().height);
      } else {
        NS_ASSERTION(0, "no rects?");
      }
-     
-     program->SetLayerQuadRect(nsIntRect(0, 0, 
-                                         ioImage->GetSize().width, 
+
+     program->SetLayerQuadRect(nsIntRect(0, 0,
+                                         ioImage->GetSize().width,
                                          ioImage->GetSize().height));
      program->SetLayerTransform(GetEffectiveTransform());
      program->SetLayerOpacity(GetEffectiveOpacity());
      program->SetRenderOffset(aOffset);
      program->SetTextureUnit(0);
      program->LoadMask(GetMaskLayer());
-    
+
      mOGLManager->BindAndDrawQuad(program);
      gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 #endif
 #ifdef MOZ_WIDGET_GONK
   } else if (image->GetFormat() == Image::GONK_IO_SURFACE) {
 
     GonkIOSurfaceImage *ioImage = static_cast<GonkIOSurfaceImage*>(image);
     if (!ioImage) {
       return;
     }
 
     gl()->MakeCurrent();
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
-    if (!ioImage->GetBackendData(LayerManager::LAYERS_OPENGL)) {
+    if (!ioImage->GetBackendData(LAYERS_OPENGL)) {
       AllocateTextureIOSurface(ioImage, gl());
     }
     GonkIOSurfaceImageOGLBackendData *data =
-      static_cast<GonkIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+      static_cast<GonkIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LAYERS_OPENGL));
 
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl()->BindExternalBuffer(data->mTexture.GetTextureID(), ioImage->GetNativeBuffer());
 
     ShaderProgramOGL *program = mOGLManager->GetProgram(RGBAExternalLayerProgramType, GetMaskLayer());
 
     gl()->ApplyFilterToBoundTexture(mFilter);
 
@@ -509,17 +510,17 @@ ImageLayerOGL::AllocateTexturesYCbCr(Pla
     return;
 
   nsAutoPtr<PlanarYCbCrOGLBackendData> backendData(
     new PlanarYCbCrOGLBackendData);
 
   PlanarYCbCrImage::Data &data = aImage->mData;
 
   gl()->MakeCurrent();
- 
+
   mTextureRecycleBin->GetTexture(TextureRecycleBin::TEXTURE_Y, data.mYSize, gl(), &backendData->mTextures[0]);
   SetClamping(gl(), backendData->mTextures[0].GetTextureID());
 
   mTextureRecycleBin->GetTexture(TextureRecycleBin::TEXTURE_C, data.mCbCrSize, gl(), &backendData->mTextures[1]);
   SetClamping(gl(), backendData->mTextures[1].GetTextureID());
 
   mTextureRecycleBin->GetTexture(TextureRecycleBin::TEXTURE_C, data.mCbCrSize, gl(), &backendData->mTextures[2]);
   SetClamping(gl(), backendData->mTextures[2].GetTextureID());
@@ -528,17 +529,17 @@ ImageLayerOGL::AllocateTexturesYCbCr(Pla
                      &backendData->mTextures[0],
                      &backendData->mTextures[1],
                      &backendData->mTextures[2]);
 
   backendData->mYSize = aImage->mData.mYSize;
   backendData->mCbCrSize = aImage->mData.mCbCrSize;
   backendData->mTextureRecycleBin = mTextureRecycleBin;
 
-  aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
+  aImage->SetBackendData(LAYERS_OPENGL, backendData.forget());
 }
 
 void
 ImageLayerOGL::AllocateTexturesCairo(CairoImage *aImage)
 {
   nsAutoPtr<CairoOGLBackendData> backendData(
     new CairoOGLBackendData);
 
@@ -561,26 +562,26 @@ ImageLayerOGL::AllocateTexturesCairo(Cai
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
   if (sGLXLibrary.SupportsTextureFromPixmap(aImage->mSurface)) {
     if (aImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
       backendData->mLayerProgram = gl::RGBALayerProgramType;
     } else {
       backendData->mLayerProgram = gl::RGBXLayerProgramType;
     }
 
-    aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
+    aImage->SetBackendData(LAYERS_OPENGL, backendData.forget());
     return;
   }
 #endif
   backendData->mLayerProgram =
     gl->UploadSurfaceToTexture(aImage->mSurface,
                                nsIntRect(0,0, aImage->mSize.width, aImage->mSize.height),
                                tex, true);
 
-  aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
+  aImage->SetBackendData(LAYERS_OPENGL, backendData.forget());
 }
 
 /*
  * Returns a size that is larger than and closest to aSize where both
  * width and height are powers of two.
  * If the OpenGL setup is capable of using non-POT textures, then it
  * will just return aSize.
  */
@@ -615,17 +616,17 @@ ImageLayerOGL::LoadAsTexture(GLuint aTex
 
   CairoImage* cairoImage = static_cast<CairoImage*>(image);
 
   if (!cairoImage->mSurface) {
     return false;
   }
 
   CairoOGLBackendData *data = static_cast<CairoOGLBackendData*>(
-    cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL));
+    cairoImage->GetBackendData(LAYERS_OPENGL));
 
   if (!data) {
     NS_ASSERTION(cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_ALPHA,
                  "OpenGL mask layers must be backed by alpha surfaces");
 
     // allocate a new texture and save the details in the backend data
     data = new CairoOGLBackendData;
     data->mTextureSize = CalculatePOTSize(cairoImage->mSize, gl());
@@ -645,17 +646,17 @@ ImageLayerOGL::LoadAsTexture(GLuint aTex
     data->mLayerProgram =
       texGL->UploadSurfaceToTexture(cairoImage->mSurface,
                                     nsIntRect(0,0,
                                               data->mTextureSize.width,
                                               data->mTextureSize.height),
                                     texID, true, nsIntPoint(0,0), false,
                                     aTextureUnit);
 
-    cairoImage->SetBackendData(LayerManager::LAYERS_OPENGL, data);
+    cairoImage->SetBackendData(LAYERS_OPENGL, data);
 
     gl()->MakeCurrent();
     gl()->fActiveTexture(aTextureUnit);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, texID);
     gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
                          LOCAL_GL_LINEAR);
     gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
                          LOCAL_GL_LINEAR);
--- a/gfx/layers/opengl/LayerManagerOGLProgram.h
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.h
@@ -7,22 +7,23 @@
 #define GFX_LAYERMANAGEROGLPROGRAM_H
 
 #include <string.h>
 
 #include "prenv.h"
 
 #include "nsString.h"
 #include "GLContext.h"
-#include "Layers.h"
-
+#include "gfx3DMatrix.h"
 
 namespace mozilla {
 namespace layers {
 
+class Layer;
+
 // The kinds of mask layer a shader can support
 // We rely on the items in this enum being sequential
 enum MaskType {
   MaskNone = 0,   // no mask layer
   Mask2d,         // mask layer for layers with 2D transforms
   Mask3d,         // mask layer for layers with 3D transforms
   NumMaskTypes
 };
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -495,26 +495,20 @@ gfxPlatformGtk::GetPlatformCMSOutputProf
     int retFormat;
     unsigned long retLength, retAfter;
     unsigned char *retProperty ;
 
     iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
     if (iccAtom) {
         // read once to get size, once for the data
         if (Success == XGetWindowProperty(dpy, root, iccAtom,
-                                          0, 0 /* length */,
+                                          0, INT_MAX /* length */,
                                           False, AnyPropertyType,
                                           &retAtom, &retFormat, &retLength,
                                           &retAfter, &retProperty)) {
-            XGetWindowProperty(dpy, root, iccAtom,
-                               0, retLength,
-                               False, AnyPropertyType,
-                               &retAtom, &retFormat, &retLength,
-                               &retAfter, &retProperty);
-
             qcms_profile* profile = NULL;
 
             if (retLength > 0)
                 profile = qcms_profile_from_memory(retProperty, retLength);
 
             XFree(retProperty);
 
             if (profile) {
--- a/ipc/chromium/src/base/process_util_linux.cc
+++ b/ipc/chromium/src/base/process_util_linux.cc
@@ -2,41 +2,161 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/process_util.h"
 
 #include <ctype.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <memory>
 #include <unistd.h>
 #include <string>
 #include <sys/types.h>
 #include <sys/wait.h>
 
 #include "base/debug_util.h"
 #include "base/eintr_wrapper.h"
 #include "base/file_util.h"
 #include "base/logging.h"
 #include "base/string_tokenizer.h"
 #include "base/string_util.h"
 
+#ifdef ANDROID
+#include <pthread.h>
+/*
+ * Currently, PR_DuplicateEnvironment is implemented in mozglue/build/BionicGlue.cpp
+ */
+#define HAVE_PR_DUPLICATE_ENVIRONMENT
+
+#include "plstr.h"
+#include "prenv.h"
+#include "prmem.h"
+/* Temporary until we have PR_DuplicateEnvironment in prenv.h */
+extern "C" { NSPR_API(pthread_mutex_t *)PR_GetEnvLock(void); }
+#endif
+
 namespace {
 
 enum ParsingState {
   KEY_NAME,
   KEY_VALUE
 };
 
 static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
 
 }  // namespace
 
 namespace base {
 
+#ifdef HAVE_PR_DUPLICATE_ENVIRONMENT
+/* 
+ * I tried to put PR_DuplicateEnvironment down in mozglue, but on android 
+ * this winds up failing because the strdup/free calls wind up mismatching. 
+ */
+
+static char **
+PR_DuplicateEnvironment(void)
+{
+    char **result = NULL;
+    char **s;
+    char **d;
+    pthread_mutex_lock(PR_GetEnvLock());
+    for (s = environ; *s != NULL; s++)
+      ;
+    if ((result = (char **)PR_Malloc(sizeof(char *) * (s - environ + 1))) != NULL) {
+      for (s = environ, d = result; *s != NULL; s++, d++) {
+        *d = PL_strdup(*s);
+      }
+      *d = NULL;
+    }
+    pthread_mutex_unlock(PR_GetEnvLock());
+    return result;
+}
+
+class EnvironmentEnvp
+{
+public:
+  EnvironmentEnvp()
+    : mEnvp(PR_DuplicateEnvironment()) {}
+
+  EnvironmentEnvp(const environment_map &em)
+  {
+    mEnvp = (char **)PR_Malloc(sizeof(char *) * (em.size() + 1));
+    if (!mEnvp) {
+      return;
+    }
+    char **e = mEnvp;
+    for (environment_map::const_iterator it = em.begin();
+         it != em.end(); ++it, ++e) {
+      std::string str = it->first;
+      str += "=";
+      str += it->second;
+      *e = PL_strdup(str.c_str());
+    }
+    *e = NULL;
+  }
+
+  ~EnvironmentEnvp()
+  {
+    if (!mEnvp) {
+      return;
+    }
+    for (char **e = mEnvp; *e; ++e) {
+      PL_strfree(*e);
+    }
+    PR_Free(mEnvp);
+  }
+
+  char * const *AsEnvp() { return mEnvp; }
+
+  void ToMap(environment_map &em)
+  {
+    if (!mEnvp) {
+      return;
+    }
+    em.clear();
+    for (char **e = mEnvp; *e; ++e) {
+      const char *eq;
+      if ((eq = strchr(*e, '=')) != NULL) {
+        std::string varname(*e, eq - *e);
+        em[varname.c_str()] = &eq[1];
+      }
+    }
+  }
+
+private:
+  char **mEnvp;
+};
+
+class Environment : public environment_map
+{
+public:
+  Environment()
+  {
+    EnvironmentEnvp envp;
+    envp.ToMap(*this);
+  }
+
+  char * const *AsEnvp() {
+    mEnvp.reset(new EnvironmentEnvp(*this));
+    return mEnvp->AsEnvp();
+  }
+
+  void Merge(const environment_map &em)
+  {
+    for (const_iterator it = em.begin(); it != em.end(); ++it) {
+      (*this)[it->first] = it->second;
+    }
+  }
+private:
+  std::auto_ptr<EnvironmentEnvp> mEnvp;
+};
+#endif // HAVE_PR_DUPLICATE_ENVIRONMENT
+
 bool LaunchApp(const std::vector<std::string>& argv,
                const file_handle_mapping_vector& fds_to_remap,
                bool wait, ProcessHandle* process_handle) {
   return LaunchApp(argv, fds_to_remap, environment_map(),
                    wait, process_handle);
 }
 
 bool LaunchApp(const std::vector<std::string>& argv,
@@ -45,45 +165,59 @@ bool LaunchApp(const std::vector<std::st
                bool wait, ProcessHandle* process_handle,
                ProcessArchitecture arch) {
   scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
   // Illegal to allocate memory after fork and before execvp
   InjectiveMultimap fd_shuffle1, fd_shuffle2;
   fd_shuffle1.reserve(fds_to_remap.size());
   fd_shuffle2.reserve(fds_to_remap.size());
 
+#ifdef HAVE_PR_DUPLICATE_ENVIRONMENT
+  Environment env;
+  env.Merge(env_vars_to_set);
+  char * const *envp = env.AsEnvp();
+  if (!envp) {
+    DLOG(ERROR) << "FAILED to duplicate environment for: " << argv_cstr[0];
+    return false;
+  }
+#endif
+
   pid_t pid = fork();
   if (pid < 0)
     return false;
 
   if (pid == 0) {
     for (file_handle_mapping_vector::const_iterator
         it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
       fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
       fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
     }
 
     if (!ShuffleFileDescriptors(&fd_shuffle1))
       _exit(127);
 
     CloseSuperfluousFds(fd_shuffle2);
 
+    for (size_t i = 0; i < argv.size(); i++)
+      argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+    argv_cstr[argv.size()] = NULL;
+
+#ifdef HAVE_PR_DUPLICATE_ENVIRONMENT
+    execve(argv_cstr[0], argv_cstr.get(), envp);
+#else
     for (environment_map::const_iterator it = env_vars_to_set.begin();
          it != env_vars_to_set.end(); ++it) {
       if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/))
         _exit(127);
     }
-
-    for (size_t i = 0; i < argv.size(); i++)
-      argv_cstr[i] = const_cast<char*>(argv[i].c_str());
-    argv_cstr[argv.size()] = NULL;
-    execvp(argv_cstr[0], argv_cstr.get());
+    execv(argv_cstr[0], argv_cstr.get());
+#endif
     // if we get here, we're in serious trouble and should complain loudly
     DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
-    exit(127);
+    _exit(127);
   } else {
     gProcessLog.print("==> process %d launched child process %d\n",
                       GetCurrentProcId(), pid);
     if (wait)
       HANDLE_EINTR(waitpid(pid, 0, 0));
 
     if (process_handle)
       *process_handle = pid;
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -20,40 +20,38 @@
 #include "gfx3DMatrix.h"
 #include "gfxColor.h"
 #include "gfxMatrix.h"
 #include "gfxPattern.h"
 #include "gfxPoint.h"
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "gfxASurface.h"
-#include "Layers.h"
+#include "LayersBackend.h"
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4800 )
 #endif
 
 #if !defined(OS_POSIX)
 // This condition must be kept in sync with the one in
 // ipc_message_utils.h, but this dummy definition of
 // base::FileDescriptor acts as a static assert that we only get one
 // def or the other (or neither, in which case code using
 // FileDescriptor fails to build)
 namespace base { struct FileDescriptor { }; }
 #endif
 
-using mozilla::layers::LayerManager;
-
 namespace mozilla {
 
 typedef gfxASurface::gfxContentType gfxContentType;
 typedef gfxASurface::gfxImageFormat PixelFormat;
 typedef gfxASurface::gfxSurfaceType gfxSurfaceType;
 typedef gfxPattern::GraphicsFilter GraphicsFilterType;
-typedef LayerManager::LayersBackend LayersBackend;
+typedef layers::LayersBackend LayersBackend;
 
 // This is a cross-platform approximation to HANDLE, which we expect
 // to be typedef'd to void* or thereabouts.
 typedef uintptr_t WindowsHandle;
 
 // XXX there are out of place and might be generally useful.  Could
 // move to nscore.h or something.
 struct void_t {
@@ -513,20 +511,20 @@ struct ParamTraits<mozilla::gfxSurfaceTy
 template <>
 struct ParamTraits<mozilla::GraphicsFilterType>
   : public EnumSerializer<mozilla::GraphicsFilterType,
                           gfxPattern::FILTER_FAST,
                           gfxPattern::FILTER_SENTINEL>
 {};
 
 template <>
-struct ParamTraits<mozilla::LayersBackend>
-  : public EnumSerializer<mozilla::LayersBackend,
-                          LayerManager::LAYERS_NONE,
-                          LayerManager::LAYERS_LAST>
+struct ParamTraits<mozilla::layers::LayersBackend>
+  : public EnumSerializer<mozilla::layers::LayersBackend,
+                          mozilla::layers::LAYERS_NONE,
+                          mozilla::layers::LAYERS_LAST>
 {};
 
 template <>
 struct ParamTraits<mozilla::PixelFormat>
   : public EnumSerializer<mozilla::PixelFormat,
                           gfxASurface::ImageFormatARGB32,
                           gfxASurface::ImageFormatUnknown>
 {};
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4847,19 +4847,16 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
          * for the already-emitted function definition prolog opcode. See
          * comments in EmitStatementList.
          */
         JS_ASSERT(pn->isOp(JSOP_NOP));
         JS_ASSERT(bce->sc->inFunction());
         return EmitFunctionDefNop(cx, bce, pn->pn_index);
     }
 
-    JS_ASSERT_IF(pn->pn_funbox->funIsHeavyweight(),
-                 fun->kind() == JSFUN_INTERPRETED);
-
     {
         FunctionBox *funbox = pn->pn_funbox;
         SharedContext sc(cx, /* scopeChain = */ NULL, fun, funbox, funbox->strictModeState);
         sc.cxFlags = funbox->cxFlags;
         if (bce->sc->funMightAliasLocals())
             sc.setFunMightAliasLocals();  // inherit funMightAliasLocals from parent
         sc.bindings.transfer(&funbox->bindings);
         JS_ASSERT_IF(bce->sc->inStrictMode(), sc.inStrictMode());
--- a/js/src/frontend/SemanticAnalysis.cpp
+++ b/js/src/frontend/SemanticAnalysis.cpp
@@ -51,56 +51,18 @@ SetFunctionKinds(FunctionBox *funbox, bo
         ParseNode *pn = fn->pn_body;
         if (!pn)
             continue;
 
         if (funbox->kids)
             SetFunctionKinds(funbox->kids, isHeavyweight, topInFunction, isDirectEval);
 
         JSFunction *fun = funbox->function();
-
-        JS_ASSERT(fun->kind() == JSFUN_INTERPRETED);
-
-        if (funbox->funIsHeavyweight()) {
-            /* nothing to do */
-        } else if (isDirectEval || funbox->inAnyDynamicScope()) {
-            /*
-             * Either we are in a with-block or a function scope that is
-             * subject to direct eval; or we are compiling strict direct eval
-             * code.
-             *
-             * In either case, fun may reference names that are not bound but
-             * are not necessarily global either. (In the strict direct eval
-             * case, we could bind them, but currently do not bother; see
-             * the comment about strict mode code in BindTopLevelVar.)
-             */
-            JS_ASSERT(!fun->isNullClosure());
-        } else {
-            bool hasUpvars = false;
-
-            if (pn->isKind(PNK_UPVARS)) {
-                AtomDefnMapPtr upvars = pn->pn_names;
-                JS_ASSERT(!upvars->empty());
-
-                /* Determine whether the this function contains upvars. */
-                for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) {
-                    if (!r.front().value()->resolve()->isFreeVar()) {
-                        hasUpvars = true;
-                        break;
-                    }
-                }
-            }
-
-            if (!hasUpvars) {
-                /* No lexical dependencies => null closure, for best performance. */
-                fun->setKind(JSFUN_NULL_CLOSURE);
-            }
-        }
-
-        if (fun->kind() == JSFUN_INTERPRETED && pn->isKind(PNK_UPVARS)) {
+        JS_ASSERT(fun->isInterpreted());
+        if (pn->isKind(PNK_UPVARS)) {
             /*
              * We loop again over all upvars, and for each non-free upvar,
              * ensure that its containing function has been flagged as
              * heavyweight.
              *
              * The emitter must see funIsHeavyweight() accurately before
              * generating any code for a tree of nested functions.
              */
--- a/js/src/jsast.tbl
+++ b/js/src/jsast.tbl
@@ -43,16 +43,17 @@ ASTDEF(AST_BLOCK_STMT,            "Block
 ASTDEF(AST_EXPR_STMT,             "ExpressionStatement",            "expressionStatement")
 ASTDEF(AST_LAB_STMT,              "LabeledStatement",               "labeledStatement")
 ASTDEF(AST_IF_STMT,               "IfStatement",                    "ifStatement")
 ASTDEF(AST_SWITCH_STMT,           "SwitchStatement",                "switchStatement")
 ASTDEF(AST_WHILE_STMT,            "WhileStatement",                 "whileStatement")
 ASTDEF(AST_DO_STMT,               "DoWhileStatement",               "doWhileStatement")
 ASTDEF(AST_FOR_STMT,              "ForStatement",                   "forStatement")
 ASTDEF(AST_FOR_IN_STMT,           "ForInStatement",                 "forInStatement")
+ASTDEF(AST_FOR_OF_STMT,           "ForOfStatement",                 "forOfStatement")
 ASTDEF(AST_BREAK_STMT,            "BreakStatement",                 "breakStatement")
 ASTDEF(AST_CONTINUE_STMT,         "ContinueStatement",              "continueStatement")
 ASTDEF(AST_WITH_STMT,             "WithStatement",                  "withStatement")
 ASTDEF(AST_RETURN_STMT,           "ReturnStatement",                "returnStatement")
 ASTDEF(AST_TRY_STMT,              "TryStatement",                   "tryStatement")
 ASTDEF(AST_THROW_STMT,            "ThrowStatement",                 "throwStatement")
 ASTDEF(AST_DEBUGGER_STMT,         "DebuggerStatement",              "debuggerStatement")
 ASTDEF(AST_LET_STMT,              "LetStatement",                   "letStatement")
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -218,17 +218,19 @@ JS_ClearAllTrapsForCompartment(JSContext
     cx->compartment->clearTraps(cx->runtime->defaultFreeOp());
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
 {
     rt->debugHooks.interruptHook = hook;
     rt->debugHooks.interruptHookData = closure;
-    return JS_TRUE;
+    for (InterpreterFrames *f = rt->interpreterFrames; f; f = f->older)
+        f->enableInterruptsUnconditionally();
+    return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep)
 {
     if (hoop)
         *hoop = rt->debugHooks.interruptHook;
     if (closurep)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -823,43 +823,43 @@ typedef enum NukeReferencesToWindow {
 
 // These filters are designed to be ephemeral stack classes, and thus don't
 // do any rooting or holding of their members.
 struct CompartmentFilter {
     virtual bool match(JSCompartment *c) const = 0;
 };
 
 struct AllCompartments : public CompartmentFilter {
-    virtual bool match(JSCompartment *c) const { return true; };
+    virtual bool match(JSCompartment *c) const { return true; }
 };
 
 struct ContentCompartmentsOnly : public CompartmentFilter {
     virtual bool match(JSCompartment *c) const {
         return !IsSystemCompartment(c);
-    };
+    }
 };
 
 struct ChromeCompartmentsOnly : public CompartmentFilter {
     virtual bool match(JSCompartment *c) const {
         return IsSystemCompartment(c);
-    };
+    }
 };
 
 struct SingleCompartment : public CompartmentFilter {
     JSCompartment *ours;
-    SingleCompartment(JSCompartment *c) : ours(c) {};
-    virtual bool match(JSCompartment *c) const { return c == ours; };
+    SingleCompartment(JSCompartment *c) : ours(c) {}
+    virtual bool match(JSCompartment *c) const { return c == ours; }
 };
 
 struct CompartmentsWithPrincipals : public CompartmentFilter {
     JSPrincipals *principals;
-    CompartmentsWithPrincipals(JSPrincipals *p) : principals(p) {};
+    CompartmentsWithPrincipals(JSPrincipals *p) : principals(p) {}
     virtual bool match(JSCompartment *c) const {
         return JS_GetCompartmentPrincipals(c) == principals;
-    };
+    }
 };
 
 extern JS_FRIEND_API(JSBool)
 NukeCrossCompartmentWrappers(JSContext* cx,
                              const CompartmentFilter& sourceFilter,
                              const CompartmentFilter& targetFilter,
                              NukeReferencesToWindow nukeReferencesToWindow);
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -382,17 +382,16 @@ js::XDRInterpretedFunction(XDRState<mode
     if (!xdr->codeUint32(&flagsword))
         return false;
 
     if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script))
         return false;
 
     if (mode == XDR_DECODE) {
         fun->nargs = flagsword >> 16;
-        JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16_t(flagsword);
         fun->atom.init(atom);
         fun->initScript(script);
         script->setFunction(fun);
         if (!fun->setTypeForScriptedFunction(cx))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
@@ -1214,18 +1213,18 @@ js_NewFunction(JSContext *cx, JSObject *
         funobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
         if (!funobj)
             return NULL;
     }
     RootedFunction fun(cx, static_cast<JSFunction *>(funobj));
 
     /* Initialize all function members. */
     fun->nargs = uint16_t(nargs);
-    fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK);
-    if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
+    fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED);
+    if (flags & JSFUN_INTERPRETED) {
         JS_ASSERT(!native);
         fun->mutableScript().init(NULL);
         fun->initEnvironment(parent);
     } else {
         fun->u.native = native;
         JS_ASSERT(fun->u.native);
     }
     if (kind == JSFunction::ExtendedFinalizeKind) {
@@ -1263,53 +1262,58 @@ js_CloneFunctionObject(JSContext *cx, Ha
     }
     clone->atom.init(fun->atom);
 
     if (kind == JSFunction::ExtendedFinalizeKind) {
         clone->flags |= JSFUN_EXTENDED;
         clone->initializeExtended();
     }
 
-    if (cx->compartment == fun->compartment()) {
+    if (cx->compartment == fun->compartment() && !types::UseNewTypeForClone(fun)) {
         /*
          * We can use the same type as the original function provided that (a)
          * its prototype is correct, and (b) its type is not a singleton. The
          * first case will hold in all compileAndGo code, and the second case
          * will have been caught by CloneFunctionObject coming from function
          * definitions or read barriers, so will not get here.
          */
         if (fun->getProto() == proto && !fun->hasSingletonType())
             clone->setType(fun->type());
     } else {
+        if (!clone->setSingletonType(cx))
+            return NULL;
+
         /*
          * Across compartments we have to clone the script for interpreted
          * functions. Cross-compartment cloning only happens via JSAPI
          * (JS_CloneFunctionObject) which dynamically ensures that 'script' has
          * no enclosing lexical scope (only the global scope).
          */
         if (clone->isInterpreted()) {
             RootedScript script(cx, clone->script());
             JS_ASSERT(script);
             JS_ASSERT(script->compartment() == fun->compartment());
-            JS_ASSERT(script->compartment() != cx->compartment);
-            JS_ASSERT(!script->enclosingStaticScope());
+            JS_ASSERT_IF(script->compartment() != cx->compartment,
+                         !script->enclosingStaticScope() && !script->compileAndGo);
+
+            RootedObject scope(cx, script->enclosingStaticScope());
 
             clone->mutableScript().init(NULL);
 
-            JSScript *cscript = CloneScript(cx, NullPtr(), clone, script);
+            JSScript *cscript = CloneScript(cx, scope, clone, script);
             if (!cscript)
                 return NULL;
 
             clone->setScript(cscript);
             cscript->setFunction(clone);
-            if (!clone->setTypeForScriptedFunction(cx))
-                return NULL;
+
+            GlobalObject *global = script->compileAndGo ? &script->global() : NULL;
 
             js_CallNewScriptHook(cx, clone->script(), clone);
-            Debugger::onNewScript(cx, clone->script(), NULL);
+            Debugger::onNewScript(cx, clone->script(), global);
         }
     }
     return clone;
 }
 
 JSFunction *
 js_DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
                   unsigned nargs, unsigned attrs, AllocKind kind)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -35,19 +35,16 @@
  * pointer-chasing.
  */
 #define JSFUN_PROTOTYPE     0x0800  /* function is Function.prototype for some
                                        global object */
 
 #define JSFUN_EXPR_CLOSURE  0x1000  /* expression closure: function(x) x*x */
 #define JSFUN_EXTENDED      0x2000  /* structure is FunctionExtended */
 #define JSFUN_INTERPRETED   0x4000  /* use u.i if kind >= this value else u.native */
-#define JSFUN_NULL_CLOSURE  0x8000  /* null closure entrains no scope chain */
-#define JSFUN_KINDMASK      0xc000  /* encode interp vs. native and closure
-                                       optimization level -- see above */
 
 namespace js { class FunctionExtended; }
 
 struct JSFunction : public JSObject
 {
     uint16_t        nargs;        /* maximum number of specified arguments,
                                      reflected as f.length/f.arity */
     uint16_t        flags;        /* flags, see JSFUN_* below and in jsapi.h */
@@ -60,31 +57,24 @@ struct JSFunction : public JSObject
                                      use the accessor! */
         } i;
         void            *nativeOrScript;
     } u;
     js::HeapPtrAtom  atom;        /* name for diagnostics and decompiling */
 
     bool hasDefaults()       const { return flags & JSFUN_HAS_DEFAULTS; }
     bool hasRest()           const { return flags & JSFUN_HAS_REST; }
-    bool isInterpreted()     const { return kind() >= JSFUN_INTERPRETED; }
+    bool isInterpreted()     const { return flags & JSFUN_INTERPRETED; }
     bool isNative()          const { return !isInterpreted(); }
     bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
     bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
-    bool isNullClosure()     const { return kind() == JSFUN_NULL_CLOSURE; }
     bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
     bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
     bool isNamedLambda()     const { return (flags & JSFUN_LAMBDA) && atom; }
 
-    uint16_t kind()          const { return flags & JSFUN_KINDMASK; }
-    void setKind(uint16_t k) {
-        JS_ASSERT(!(k & ~JSFUN_KINDMASK));
-        flags = (flags & ~JSFUN_KINDMASK) | k;
-    }
-
     /* Returns the strictness of this function, which must be interpreted. */
     inline bool inStrictMode() const;
 
     void setArgCount(uint16_t nargs) {
         JS_ASSERT(this->nargs == 0);
         this->nargs = nargs;
     }
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3624,17 +3624,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_DEFFUN: {
         JSObject *obj = script->getObject(GET_UINT32_INDEX(pc));
 
         TypeSet *res = NULL;
         if (op == JSOP_LAMBDA)
             res = &pushed[0];
 
         if (res) {
-            if (script->hasGlobal())
+            if (script->hasGlobal() && !UseNewTypeForClone(obj->toFunction()))
                 res->addType(cx, Type::ObjectType(obj));
             else
                 res->addType(cx, Type::UnknownType());
         } else {
             cx->compartment->types.monitorBytecode(cx, script, offset);
         }
         break;
       }
@@ -3921,22 +3921,24 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_ANYNAME:
       case JSOP_GETFUNNS:
       case JSOP_FILTER:
         /* Note: the second value pushed by filter is a hole, and not modelled. */
       case JSOP_ENDFILTER:
         pushed[0].addType(cx, Type::UnknownType());
         break;
 
-      case JSOP_CALLEE:
-        if (script->hasGlobal())
-            pushed[0].addType(cx, Type::ObjectType(script->function()));
+      case JSOP_CALLEE: {
+        JSFunction *fun = script->function();
+        if (script->hasGlobal() && !UseNewTypeForClone(fun))
+            pushed[0].addType(cx, Type::ObjectType(fun));
         else
             pushed[0].addType(cx, Type::UnknownType());
         break;
+      }
 
       default:
         /* Display fine-grained debug information first */
         fprintf(stderr, "Unknown bytecode %02x at #%u:%05u\n", op, script->id(), offset);
         TypeFailure(cx, "Unknown bytecode %02x", op);
     }
 
     return true;
@@ -5035,16 +5037,21 @@ JSFunction::setTypeForScriptedFunction(J
     JS_ASSERT(script()->function() == this);
 
     if (!cx->typeInferenceEnabled())
         return true;
 
     if (singleton) {
         if (!setSingletonType(cx))
             return false;
+    } else if (UseNewTypeForClone(this)) {
+        /*
+         * Leave the default unknown-properties type for the function, it
+         * should not be used by scripts or appear in type sets.
+         */
     } else {
         RootedFunction self(cx, this);
 
         TypeObject *type = cx->compartment->types.newTypeObject(cx, script(),
                                                                 JSProto_Function, getProto());
         if (!type)
             return false;
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -484,16 +484,76 @@ extern void TypeDynamicResult(JSContext 
 inline bool
 UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
 {
     return fp->isConstructing() && cx->typeInferenceEnabled() &&
            fp->prev() && fp->prev()->isScriptFrame() &&
            UseNewType(cx, fp->prev()->script(), fp->prevpc());
 }
 
+inline bool
+UseNewTypeForClone(JSFunction *fun)
+{
+    if (fun->hasSingletonType() || !fun->isInterpreted())
+        return false;
+
+    /*
+     * When a function is being used as a wrapper for another function, it
+     * improves precision greatly to distinguish between different instances of
+     * the wrapper; otherwise we will conflate much of the information about
+     * the wrapped functions.
+     *
+     * An important example is the Class.create function at the core of the
+     * Prototype.js library, which looks like:
+     *
+     * var Class = {
+     *   create: function() {
+     *     return function() {
+     *       this.initialize.apply(this, arguments);
+     *     }
+     *   }
+     * };
+     *
+     * Each instance of the innermost function will have a different wrapped
+     * initialize method. We capture this, along with similar cases, by looking
+     * for short scripts which use both .apply and arguments. For such scripts,
+     * whenever creating a new instance of the function we both give that
+     * instance a singleton type and clone the underlying script.
+     */
+
+    JSScript *script = fun->script();
+
+    if (script->length >= 50)
+        return false;
+
+    if (script->hasConsts() ||
+        script->hasObjects() ||
+        script->hasRegexps() ||
+        script->hasClosedArgs() ||
+        script->hasClosedVars())
+    {
+        return false;
+    }
+
+    bool hasArguments = false;
+    bool hasApply = false;
+
+    for (jsbytecode *pc = script->code;
+         pc != script->code + script->length;
+         pc += GetBytecodeLength(pc))
+    {
+        if (*pc == JSOP_ARGUMENTS)
+            hasArguments = true;
+        if (*pc == JSOP_FUNAPPLY)
+            hasApply = true;
+    }
+
+    return hasArguments && hasApply;
+}
+
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
 /* static */ inline unsigned
 TypeScript::NumTypeSets(JSScript *script)
 {
     return script->nTypeSets + analyze::TotalSlots(script);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -918,17 +918,17 @@ DoIncDec(JSContext *cx, HandleScript scr
 #  define JS_THREADED_INTERP 0
 # endif
 #endif
 
 template<typename T>
 class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
   public:
     GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
-    void enableInterrupts() const { *variable = value; }
+    void enable() const { *variable = value; }
 
   private:
     T *variable;
     T value;
 };
 
 inline InterpreterFrames::InterpreterFrames(JSContext *cx, FrameRegs *regs,
                                             const InterruptEnablerBase &enabler)
@@ -1083,17 +1083,17 @@ js::Interpret(JSContext *cx, StackFrame 
         JS_EXTENSION &&interrupt,
 # include "jsopcode.tbl"
 # undef OPDEF
     };
 
     register void * const *jumpTable = normalJumpTable;
 
     typedef GenericInterruptEnabler<void * const *> InterruptEnabler;
-    InterruptEnabler interruptEnabler(&jumpTable, interruptJumpTable);
+    InterruptEnabler interrupts(&jumpTable, interruptJumpTable);
 
 # define DO_OP()            JS_BEGIN_MACRO                                    \
                                 CHECK_PCCOUNT_INTERRUPTS();                   \
                                 JS_EXTENSION_(goto *jumpTable[op]);           \
                             JS_END_MACRO
 # define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
                                 TypeCheckNextBytecode(cx, script, n, regs);   \
                                 js::gc::MaybeVerifyBarriers(cx);              \
@@ -1111,17 +1111,17 @@ js::Interpret(JSContext *cx, StackFrame 
 
 # define END_EMPTY_CASES
 
 #else /* !JS_THREADED_INTERP */
 
     register int switchMask = 0;
     int switchOp;
     typedef GenericInterruptEnabler<int> InterruptEnabler;
-    InterruptEnabler interruptEnabler(&switchMask, -1);
+    InterruptEnabler interrupts(&switchMask, -1);
 
 # define DO_OP()            goto do_op
 # define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
                                 JS_ASSERT((n) == len);                        \
                                 goto advance_pc;                              \
                             JS_END_MACRO
 
 # define BEGIN_CASE(OP)     case OP:
@@ -1146,18 +1146,16 @@ js::Interpret(JSContext *cx, StackFrame 
 # define END_CASE_LEN11     len = 11; goto advance_pc;
 # define END_CASE_LEN12     len = 12; goto advance_pc;
 # define END_VARLEN_CASE    goto advance_pc;
 # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
 # define END_EMPTY_CASES    goto advance_pc_by_one;
 
 #endif /* !JS_THREADED_INTERP */
 
-#define ENABLE_INTERRUPTS() (interruptEnabler.enableInterrupts())
-
 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
     (dbl = script->getConst(GET_UINT32_INDEX(regs.pc + (PCOFF))).toDouble())
 
 #if defined(JS_METHODJIT)
     bool useMethodJIT = false;
 #endif
 
 #ifdef JS_METHODJIT
@@ -1209,45 +1207,36 @@ js::Interpret(JSContext *cx, StackFrame 
         if ((n) <= 0)                                                         \
             goto check_backedge;                                              \
         DO_OP();                                                              \
     JS_END_MACRO
 
 #define SET_SCRIPT(s)                                                         \
     JS_BEGIN_MACRO                                                            \
         script = (s);                                                         \
-        if (script->hasAnyBreakpointsOrStepMode())                            \
-            ENABLE_INTERRUPTS();                                              \
-        if (script->hasScriptCounts)                                          \
-            ENABLE_INTERRUPTS();                                              \
+        if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \
+            interrupts.enable();                                              \
         JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP,                        \
                      script->hasAnyBreakpointsOrStepMode());                  \
     JS_END_MACRO
 
-#define CHECK_INTERRUPT_HANDLER()                                             \
-    JS_BEGIN_MACRO                                                            \
-        if (cx->runtime->debugHooks.interruptHook)                            \
-            ENABLE_INTERRUPTS();                                              \
-    JS_END_MACRO
-
     /* Repoint cx->regs to a local variable for faster access. */
     FrameRegs regs = cx->regs();
     PreserveRegsGuard interpGuard(cx, regs);
 
     /*
      * Help Debugger find frames running scripts that it has put in
      * single-step mode.
      */
-    InterpreterFrames interpreterFrame(cx, &regs, interruptEnabler);
+    InterpreterFrames interpreterFrame(cx, &regs, interrupts);
 
     /* Copy in hot values that change infrequently. */
     JSRuntime *const rt = cx->runtime;
     Rooted<JSScript*> script(cx);
     SET_SCRIPT(regs.fp()->script());
-    CHECK_INTERRUPT_HANDLER();
 
     /*
      * Pool of rooters for use in this interpreter frame. References to these
      * are used for local variables within interpreter cases. This avoids
      * creating new rooters each time an interpreter case is entered, and also
      * correctness pitfalls due to incorrect compilation of destructor calls
      * around computed gotos.
      */
@@ -1255,19 +1244,16 @@ js::Interpret(JSContext *cx, StackFrame 
     RootedString rootString0(cx), rootString1(cx);
     RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
     RootedFunction rootFunction0(cx);
     RootedTypeObject rootType0(cx);
     RootedPropertyName rootName0(cx);
     RootedId rootId0(cx);
     RootedShape rootShape0(cx);
 
-    if (rt->profilingScripts)
-        ENABLE_INTERRUPTS();
-
     if (!entryFrame)
         entryFrame = regs.fp();
 
 #if JS_HAS_GENERATORS
     if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
         JS_ASSERT(size_t(regs.pc - script->code) <= script->length);
         JS_ASSERT(regs.stackDepth() <= script->nslots);
 
@@ -1310,30 +1296,31 @@ js::Interpret(JSContext *cx, StackFrame 
             }
         }
     }
 
     /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */
     if (interpMode == JSINTERP_REJOIN)
         interpMode = JSINTERP_NORMAL;
 
-    CHECK_INTERRUPT_HANDLER();
-
     RESET_USE_METHODJIT();
 
     /*
      * It is important that "op" be initialized before calling DO_OP because
      * it is possible for "op" to be specially assigned during the normal
      * processing of an opcode while looping. We rely on DO_NEXT_OP to manage
      * "op" correctly in all other cases.
      */
     JSOp op;
     int32_t len;
     len = 0;
 
+    if (rt->profilingScripts || cx->runtime->debugHooks.interruptHook)
+        interrupts.enable();
+
     DO_NEXT_OP(len);
 
 #if JS_THREADED_INTERP
     /*
      * This is a loop, but it does not look like a loop. The loop-closing
      * jump is distributed throughout goto *jumpTable[op] inside of DO_OP.
      * When interrupts are enabled, jumpTable is set to interruptJumpTable
      * where all jumps point to the interrupt label. The latter, after
@@ -1419,17 +1406,16 @@ js::Interpret(JSContext *cx, StackFrame 
                 goto forced_return;
               case JSTRAP_THROW:
                 cx->setPendingException(rval);
                 goto error;
               default:
                 break;
             }
             JS_ASSERT(status == JSTRAP_CONTINUE);
-            CHECK_INTERRUPT_HANDLER();
             JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
         }
 
         interpMode = JSINTERP_NORMAL;
 
 #if JS_THREADED_INTERP
         jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
         JS_EXTENSION_(goto *normalJumpTable[op]);
@@ -1733,30 +1719,28 @@ BEGIN_CASE(JSOP_IN)
 END_CASE(JSOP_IN)
 
 BEGIN_CASE(JSOP_ITER)
 {
     JS_ASSERT(regs.stackDepth() >= 1);
     uint8_t flags = GET_UINT8(regs.pc);
     if (!ValueToIterator(cx, flags, &regs.sp[-1]))
         goto error;
-    CHECK_INTERRUPT_HANDLER();
     JS_ASSERT(!regs.sp[-1].isPrimitive());
 }
 END_CASE(JSOP_ITER)
 
 BEGIN_CASE(JSOP_MOREITER)
 {
     JS_ASSERT(regs.stackDepth() >= 1);
     JS_ASSERT(regs.sp[-1].isObject());
     PUSH_NULL();
     bool cond;
     if (!IteratorMore(cx, &regs.sp[-2].toObject(), &cond, &regs.sp[-1]))
         goto error;
-    CHECK_INTERRUPT_HANDLER();
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_MOREITER)
 
 BEGIN_CASE(JSOP_ITERNEXT)
 {
     JS_ASSERT(regs.stackDepth() >= unsigned(GET_INT8(regs.pc)));
     Value *itervp = regs.sp - GET_INT8(regs.pc);
@@ -2407,17 +2391,16 @@ BEGIN_CASE(JSOP_EVAL)
     CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
     if (IsBuiltinEvalForScope(regs.fp()->scopeChain(), args.calleev())) {
         if (!DirectEval(cx, args))
             goto error;
     } else {
         if (!InvokeKernel(cx, args))
             goto error;
     }
-    CHECK_INTERRUPT_HANDLER();
     regs.sp = args.spAfterCall();
     TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 BEGIN_CASE(JSOP_FUNAPPLY)
     if (!GuardFunApplyArgumentsOptimization(cx))
         goto error;
@@ -2440,17 +2423,16 @@ BEGIN_CASE(JSOP_FUNCALL)
                 goto error;
         } else {
             if (!InvokeKernel(cx, args))
                 goto error;
         }
         Value *newsp = args.spAfterCall();
         TypeScript::Monitor(cx, script, regs.pc, newsp[-1]);
         regs.sp = newsp;
-        CHECK_INTERRUPT_HANDLER();
         len = JSOP_CALL_LENGTH;
         DO_NEXT_OP(len);
     }
 
     if (!TypeMonitorCall(cx, args, construct))
         goto error;
 
     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
@@ -2478,17 +2460,16 @@ BEGIN_CASE(JSOP_FUNCALL)
                                                         mjit::CompileRequest_Interpreter,
                                                         regs.fp());
         if (status == mjit::Compile_Error)
             goto error;
         if (status == mjit::Compile_Okay) {
             mjit::JaegerStatus status = mjit::JaegerShot(cx, true);
             CHECK_PARTIAL_METHODJIT(status);
             interpReturnOK = mjit::JaegerStatusToSuccess(status);
-            CHECK_INTERRUPT_HANDLER();
             goto jit_return;
         }
     }
 #endif
 
     if (!regs.fp()->prologue(cx, newType))
         goto error;
     if (cx->compartment->debugMode()) {
@@ -2501,18 +2482,16 @@ BEGIN_CASE(JSOP_FUNCALL)
           case JSTRAP_THROW:
           case JSTRAP_ERROR:
             goto error;
           default:
             JS_NOT_REACHED("bad ScriptDebugPrologue status");
         }
     }
 
-    CHECK_INTERRUPT_HANDLER();
-
     /* Load first op and dispatch it (safe since JSOP_STOP). */
     op = (JSOp) *regs.pc;
     DO_OP();
 }
 
 BEGIN_CASE(JSOP_SETCALL)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
@@ -3074,50 +3053,44 @@ BEGIN_CASE(JSOP_NEWINIT)
         gc::AllocKind kind = GuessObjectGCKind(0);
         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
     }
     if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
         goto error;
 
     PUSH_OBJECT(*obj);
     TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
-
-    CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWINIT)
 
 BEGIN_CASE(JSOP_NEWARRAY)
 {
     unsigned count = GET_UINT24(regs.pc);
     RootedObject &obj = rootObject0;
     obj = NewDenseAllocatedArray(cx, count);
     if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
         goto error;
 
     PUSH_OBJECT(*obj);
     TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
-
-    CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWARRAY)
 
 BEGIN_CASE(JSOP_NEWOBJECT)
 {
     RootedObject &baseobj = rootObject0;
     baseobj = script->getObject(regs.pc);
 
     RootedObject &obj = rootObject1;
     obj = CopyInitializerObject(cx, baseobj);
     if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
         goto error;
 
     PUSH_OBJECT(*obj);
     TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
-
-    CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWOBJECT)
 
 BEGIN_CASE(JSOP_ENDINIT)
 {
     /* FIXME remove JSOP_ENDINIT bug 588522 */
     JS_ASSERT(regs.stackDepth() >= 1);
     JS_ASSERT(regs.sp[-1].isObject());
@@ -3321,17 +3294,16 @@ BEGIN_CASE(JSOP_DEBUGGER)
         regs.fp()->setReturnValue(rval);
         interpReturnOK = true;
         goto forced_return;
       case JSTRAP_THROW:
         cx->setPendingException(rval);
         goto error;
       default:;
     }
-    CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_DEBUGGER)
 
 #if JS_HAS_XML_SUPPORT
 BEGIN_CASE(JSOP_DEFXMLNS)
 {
     JS_ASSERT(!script->strictModeCode);
 
@@ -3838,17 +3810,16 @@ END_CASE(JSOP_ARRAYPUSH)
                 regs.fp()->setReturnValue(rval);
                 interpReturnOK = true;
                 goto forced_return;
               case JSTRAP_THROW:
                 cx->setPendingException(rval);
               case JSTRAP_CONTINUE:
               default:;
             }
-            CHECK_INTERRUPT_HANDLER();
         }
 
         for (TryNoteIter tni(regs); !tni.done(); ++tni) {
             JSTryNote *tn = *tni;
 
             UnwindScope(cx, tn->stackDepth);
 
             /*
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -229,24 +229,25 @@ HasInstance(JSContext *cx, HandleObject 
  *
  * Elements of this list are allocated within the js::Interpret stack
  * frames themselves; the list is headed by this thread's js::ThreadData.
  */
 class InterpreterFrames {
   public:
     class InterruptEnablerBase {
       public:
-        virtual void enableInterrupts() const = 0;
+        virtual void enable() const = 0;
     };
 
     InterpreterFrames(JSContext *cx, FrameRegs *regs, const InterruptEnablerBase &enabler);
     ~InterpreterFrames();
 
     /* If this js::Interpret frame is running |script|, enable interrupts. */
     inline void enableInterruptsIfRunning(JSScript *script);
+    inline void enableInterruptsUnconditionally() { enabler.enable(); }
 
     InterpreterFrames *older;
 
   private:
     JSContext *context;
     FrameRegs *regs;
     const InterruptEnablerBase &enabler;
 };
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -459,17 +459,17 @@ DefVarOrConstOperation(JSContext *cx, Ha
 
     return true;
 }
 
 inline void
 InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
 {
     if (script == regs->fp()->script())
-        enabler.enableInterrupts();
+        enabler.enable();
 }
 
 static JS_ALWAYS_INLINE bool
 AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
 {
     if (lhs.isInt32() && rhs.isInt32()) {
         int32_t l = lhs.toInt32(), r = rhs.toInt32();
         int32_t sum = l + r;
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -491,16 +491,19 @@ class NodeBuilder
     bool returnStatement(Value arg, TokenPos *pos, Value *dst);
 
     bool forStatement(Value init, Value test, Value update, Value stmt,
                       TokenPos *pos, Value *dst);
 
     bool forInStatement(Value var, Value expr, Value stmt,
                         bool isForEach, TokenPos *pos, Value *dst);
 
+    bool forOfStatement(Value var, Value expr, Value stmt, TokenPos *pos, Value *dst);
+
+
     bool withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst);
 
     bool whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst);
 
     bool doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst);
 
     bool switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst);
 
@@ -835,16 +838,30 @@ NodeBuilder::forInStatement(Value var, V
                    "left", var,
                    "right", expr,
                    "body", stmt,
                    "each", BooleanValue(isForEach),
                    dst);
 }
 
 bool
+NodeBuilder::forOfStatement(Value var, Value expr, Value stmt, TokenPos *pos, Value *dst)
+{
+    Value cb = callbacks[AST_FOR_OF_STMT];
+    if (!cb.isNull())
+        return callback(cb, var, expr, stmt, pos, dst);
+
+    return newNode(AST_FOR_OF_STMT, pos,
+                   "left", var,
+                   "right", expr,
+                   "body", stmt,
+                   dst);
+}
+
+bool
 NodeBuilder::withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst)
 {
     Value cb = callbacks[AST_WITH_STMT];
     if (!cb.isNull())
         return callback(cb, expr, stmt, pos, dst);
 
     return newNode(AST_WITH_STMT, pos,
                    "object", expr,
@@ -1607,16 +1624,17 @@ class ASTSerializer
         if (!pn) {
             dst->setMagic(JS_SERIALIZE_NO_NODE);
             return true;
         }
         return statement(pn, dst);
     }
 
     bool forInit(ParseNode *pn, Value *dst);
+    bool forOfOrIn(ParseNode *loop, ParseNode *head, Value var, Value stmt, Value *dst);
     bool statement(ParseNode *pn, Value *dst);
     bool blockStatement(ParseNode *pn, Value *dst);
     bool switchStatement(ParseNode *pn, Value *dst);
     bool switchCase(ParseNode *pn, Value *dst);
     bool tryStatement(ParseNode *pn, Value *dst);
     bool catchClause(ParseNode *pn, Value *dst);
 
     bool optExpression(ParseNode *pn, Value *dst) {
@@ -2068,16 +2086,29 @@ ASTSerializer::forInit(ParseNode *pn, Va
     }
 
     return (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
            ? variableDeclaration(pn, false, dst)
            : expression(pn, dst);
 }
 
 bool
+ASTSerializer::forOfOrIn(ParseNode *loop, ParseNode *head, Value var, Value stmt, Value *dst)
+{
+    Value expr;
+    bool isForEach = loop->pn_iflags & JSITER_FOREACH;
+    bool isForOf = loop->pn_iflags & JSITER_FOR_OF;
+    JS_ASSERT(!isForOf || !isForEach);
+
+    return expression(head->pn_kid3, &expr) &&
+        (isForOf ? builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst) :
+         builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst));
+}
+
+bool
 ASTSerializer::statement(ParseNode *pn, Value *dst)
 {
     JS_CHECK_RECURSION(cx, return false);
     switch (pn->getKind()) {
       case PNK_FUNCTION:
       case PNK_VAR:
       case PNK_CONST:
         return declaration(pn, dst);
@@ -2148,28 +2179,24 @@ ASTSerializer::statement(ParseNode *pn, 
       case PNK_FOR:
       {
         ParseNode *head = pn->pn_left;
 
         Value stmt;
         if (!statement(pn->pn_right, &stmt))
             return false;
 
-        bool isForEach = pn->pn_iflags & JSITER_FOREACH;
-
         if (head->isKind(PNK_FORIN)) {
-            Value var, expr;
-
+            Value var;
             return (!head->pn_kid1
                     ? pattern(head->pn_kid2, NULL, &var)
                     : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
-                      ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
-                      : variableDeclaration(head->pn_kid1, false, &var)) &&
-                   expression(head->pn_kid3, &expr) &&
-                   builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
+                    ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
+                    : variableDeclaration(head->pn_kid1, false, &var)) &&
+                forOfOrIn(pn, head, var, stmt, dst);
         }
 
         Value init, test, update;
 
         return forInit(head->pn_kid1, &init) &&
                optExpression(head->pn_kid2, &test) &&
                optExpression(head->pn_kid3, &update) &&
                builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
@@ -2187,23 +2214,19 @@ ASTSerializer::statement(ParseNode *pn, 
 
         Value var;
         if (!variableDeclaration(prelude, false, &var))
             return false;
 
         ParseNode *head = loop->pn_left;
         JS_ASSERT(head->isKind(PNK_FORIN));
 
-        bool isForEach = loop->pn_iflags & JSITER_FOREACH;
-
-        Value expr, stmt;
-
-        return expression(head->pn_kid3, &expr) &&
-               statement(loop->pn_right, &stmt) &&
-               builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
+        Value stmt;
+
+        return statement(loop->pn_right, &stmt) && forOfOrIn(loop, head, var, stmt, dst);
       }
 
       case PNK_BREAK:
       case PNK_CONTINUE:
       {
         Value label;
 
         return optIdentifier(pn->pn_atom, NULL, &label) &&
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -92,27 +92,44 @@ js::UnwrapObject(JSObject *wrapped, bool
     if (flagsp)
         *flagsp = flags;
     return wrapped;
 }
 
 JS_FRIEND_API(JSObject *)
 js::UnwrapObjectChecked(JSContext *cx, JSObject *obj)
 {
-    while (obj->isWrapper() &&
-           !JS_UNLIKELY(!!obj->getClass()->ext.innerObject)) {
+    while (true) {
         JSObject *wrapper = obj;
-        Wrapper *handler = Wrapper::wrapperHandler(obj);
-        bool rvOnFailure;
-        if (!handler->enter(cx, wrapper, JSID_VOID,
-                            Wrapper::PUNCTURE, &rvOnFailure))
-            return rvOnFailure ? obj : NULL;
-        obj = Wrapper::wrappedObject(obj);
-        JS_ASSERT(obj);
+        obj = UnwrapOneChecked(cx, obj);
+        if (!obj || obj == wrapper)
+            return obj;
     }
+}
+
+JS_FRIEND_API(JSObject *)
+js::UnwrapOneChecked(JSContext *cx, JSObject *obj)
+{
+    // Checked unwraps should never unwrap outer windows.
+    if (!obj->isWrapper() ||
+        JS_UNLIKELY(!!obj->getClass()->ext.innerObject))
+    {
+        return obj;
+    }
+
+    Wrapper *handler = Wrapper::wrapperHandler(obj);
+    bool rvOnFailure;
+    if (!handler->enter(cx, obj, JSID_VOID,
+                        Wrapper::PUNCTURE, &rvOnFailure))
+    {
+        return rvOnFailure ? obj : NULL;
+    }
+    obj = Wrapper::wrappedObject(obj);
+    JS_ASSERT(obj);
+
     return obj;
 }
 
 bool
 js::IsCrossCompartmentWrapper(const JSObject *wrapper)
 {
     return wrapper->isWrapper() &&
            !!(Wrapper::wrapperHandler(wrapper)->flags() & Wrapper::CROSS_COMPARTMENT);
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -320,16 +320,21 @@ UnwrapObject(JSObject *obj, bool stopAtO
 
 // Given a JSObject, returns that object stripped of wrappers. At each stage,
 // the security wrapper has the opportunity to veto the unwrap. Since checked
 // code should never be unwrapping outer window wrappers, we always stop at
 // outer windows.
 JS_FRIEND_API(JSObject *)
 UnwrapObjectChecked(JSContext *cx, JSObject *obj);
 
+// Unwrap only the outermost security wrapper, with the same semantics as
+// above. This is the checked version of Wrapper::wrappedObject.
+JS_FRIEND_API(JSObject *)
+UnwrapOneChecked(JSContext *cx, JSObject *obj);
+
 JS_FRIEND_API(bool)
 IsCrossCompartmentWrapper(const JSObject *obj);
 
 void
 NukeCrossCompartmentWrapper(JSObject *wrapper);
 
 bool
 RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget);
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -5189,17 +5189,17 @@ js_GetXMLMethod(JSContext *cx, HandleObj
     return ok;
 }
 
 JSBool
 js_TestXMLEquality(JSContext *cx, const Value &v1, const Value &v2, JSBool *bp)
 {
     JSXML *xml, *vxml;
     JSObject *vobj;
-    JSBool ok;
+    JSBool ok = JS_TRUE;
     JSString *str, *vstr;
     double d, d2;
 
     JSObject *obj;
     jsval v;
     if (v1.isObject() && v1.toObject().isXML()) {
         obj = &v1.toObject();
         v = v2;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4238,18 +4238,18 @@ mjit::Compiler::inlineCallHelper(uint32_
         /*
          * Test if the callee is even a function. If this doesn't match, we
          * take a _really_ slow path later.
          */
         Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData, tmp);
 
         /* Test if the function is scripted. */
         stubcc.masm.load16(Address(icCalleeData, offsetof(JSFunction, flags)), tmp);
-        stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp);
-        Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED));
+        Jump isNative = stubcc.masm.branchTest32(Assembler::Zero, tmp,
+                                                 Imm32(JSFUN_INTERPRETED));
         tempRegs.putReg(tmp);
 
         /*
          * N.B. After this call, the frame will have a dynamic frame size.
          * Check after the function is known not to be a native so that the
          * catch-all/native path has a static depth.
          */
         if (callIC.frameSize.isDynamic()) {
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -23,24 +23,32 @@
 
 #include "jsautooplen.h"
 
 using namespace js;
 using namespace js::mjit;
 
 typedef JSC::MacroAssembler::RegisterID RegisterID;
 
+static inline bool
+SuitableForBitop(FrameEntry *fe)
+{
+    return !(fe->isNotType(JSVAL_TYPE_INT32) &&
+             fe->isNotType(JSVAL_TYPE_DOUBLE) &&
+             fe->isNotType(JSVAL_TYPE_BOOLEAN));
+}
+
 void
 mjit::Compiler::ensureInteger(FrameEntry *fe, Uses uses)
 {
+    JS_ASSERT(SuitableForBitop(fe));
+
     if (fe->isConstant()) {
-        if (!fe->isType(JSVAL_TYPE_INT32)) {
-            JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
-            fe->convertConstantDoubleToInt32(cx);
-        }
+        if (!fe->isType(JSVAL_TYPE_INT32))
+            fe->convertConstantDoubleOrBooleanToInt32(cx);
     } else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
         FPRegisterID fpreg = frame.tempFPRegForData(fe);
         FPRegisterID fptemp = frame.allocFPReg();
         RegisterID data = frame.allocReg();
         Jump truncateGuard = masm.branchTruncateDoubleToInt32(fpreg, data);
 
         Label syncPath = stubcc.syncExitAndJump(uses);
         stubcc.linkExitDirect(truncateGuard, stubcc.masm.label());
@@ -63,17 +71,17 @@ mjit::Compiler::ensureInteger(FrameEntry
         JumpList isDouble;
         stubcc.masm.addDouble(fpreg, fptemp);
         stubcc.masm.branchConvertDoubleToInt32(fptemp, data, isDouble, Registers::FPConversionTemp);
         stubcc.crossJump(stubcc.masm.jump(), masm.label());
         isDouble.linkTo(syncPath, &stubcc.masm);
 
         frame.freeReg(fptemp);
         frame.learnType(fe, JSVAL_TYPE_INT32, data);
-    } else if (!fe->isType(JSVAL_TYPE_INT32)) {
+    } else if (!fe->isType(JSVAL_TYPE_INT32) && !fe->isType(JSVAL_TYPE_BOOLEAN)) {
         if (masm.supportsFloatingPoint()) {
             FPRegisterID fptemp = frame.allocFPReg();
             RegisterID typeReg = frame.tempRegForType(fe);
             frame.pinReg(typeReg);
             RegisterID dataReg = frame.copyDataIntoReg(fe);
             frame.unpinReg(typeReg);
 
             Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
@@ -109,17 +117,17 @@ mjit::Compiler::ensureInteger(FrameEntry
 }
 
 void
 mjit::Compiler::jsop_bitnot()
 {
     FrameEntry *top = frame.peek(-1);
 
     /* We only want to handle integers here. */
-    if (top->isNotType(JSVAL_TYPE_INT32) && top->isNotType(JSVAL_TYPE_DOUBLE)) {
+    if (!SuitableForBitop(top)) {
         prepareStubCall(Uses(1));
         INLINE_STUBCALL(stubs::BitNot, REJOIN_FALLTHROUGH);
         frame.pop();
         frame.pushSynced(JSVAL_TYPE_INT32);
         return;
     }
 
     ensureInteger(top, Uses(1));
@@ -165,22 +173,21 @@ mjit::Compiler::jsop_bitop(JSOp op)
         stub = stubs::Ursh;
         break;
       default:
         JS_NOT_REACHED("wat");
         return;
     }
 
     /* Convert a double RHS to integer if it's constant for the test below. */
-    if (rhs->isConstant() && rhs->getValue().isDouble())
-        rhs->convertConstantDoubleToInt32(cx);
+    if (rhs->isConstant() && (rhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_BOOLEAN)))
+        rhs->convertConstantDoubleOrBooleanToInt32(cx);
 
     /* We only want to handle integers here. */
-    if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
-        (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
+    if (!SuitableForBitop(lhs) || !SuitableForBitop(rhs) ||
         (op == JSOP_URSH && rhs->isConstant() && rhs->getValue().toInt32() % 32 == 0)) {
         prepareStubCall(Uses(2));
         INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
         frame.popn(2);
         frame.pushSynced(op != JSOP_URSH ? JSVAL_TYPE_INT32 : knownPushedType(0));
         return;
     }
 
--- a/js/src/methodjit/FrameEntry.h
+++ b/js/src/methodjit/FrameEntry.h
@@ -51,18 +51,20 @@ class FrameEntry
 #elif defined JS_PUNBOX64
     uint64_t getPayload() const {
         JS_ASSERT(isConstant());
         return v_.asBits & JSVAL_PAYLOAD_MASK;
     }
 #endif
 
     /* For a constant double FrameEntry, truncate to an int32. */
-    void convertConstantDoubleToInt32(JSContext *cx) {
-        JS_ASSERT(isType(JSVAL_TYPE_DOUBLE) && isConstant());
+    void convertConstantDoubleOrBooleanToInt32(JSContext *cx) {
+        JS_ASSERT(isConstant());
+        JS_ASSERT(isType(JSVAL_TYPE_DOUBLE) || isType(JSVAL_TYPE_BOOLEAN));
+
         int32_t value;
         ToInt32(cx, getValue(), &value);
 
         Value newValue = Int32Value(value);
         setConstant(newValue);
     }
 
     /*
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1722,19 +1722,16 @@ DisassembleScript(JSContext *cx, JSScrip
 #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) Sprint(sp, " " #flag);
 
         SHOW_FLAG(LAMBDA);
         SHOW_FLAG(HEAVYWEIGHT);
         SHOW_FLAG(EXPR_CLOSURE);
 
 #undef SHOW_FLAG
 
-        if (fun->isNullClosure())
-            Sprint(sp, " NULL_CLOSURE");
-
         Sprint(sp, "\n");
     }
 
     if (!js_Disassemble(cx, script, lines, sp))
         return false;
     SrcNotes(cx, script, sp);
     TryNotes(cx, script, sp);
 
--- a/js/src/tests/js1_8_5/extensions/reflect-parse.js
+++ b/js/src/tests/js1_8_5/extensions/reflect-parse.js
@@ -42,16 +42,17 @@ function genFunDecl(id, params, body) Pa
                                                 generator: true })
 function varDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" })
 function letDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" })
 function constDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" })
 function ident(name) Pattern({ type: "Identifier", name: name })
 function dotExpr(obj, id) Pattern({ type: "MemberExpression", computed: false, object: obj, property: id })
 function memExpr(obj, id) Pattern({ type: "MemberExpression", computed: true, object: obj, property: id })
 function forStmt(init, test, update, body) Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body })
+function forOfStmt(lhs, rhs, body) Pattern({ type: "ForOfStatement", left: lhs, right: rhs, body: body })
 function forInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: false })
 function forEachInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: true })
 function breakStmt(lab) Pattern({ type: "BreakStatement", label: lab })
 function continueStmt(lab) Pattern({ type: "ContinueStatement", label: lab })
 function blockStmt(body) Pattern({ type: "BlockStatement", body: body })
 var emptyStmt = Pattern({ type: "EmptyStatement" })
 function ifStmt(test, cons, alt) Pattern({ type: "IfStatement", test: test, alternate: alt, consequent: cons })
 function labStmt(lab, stmt) Pattern({ type: "LabeledStatement", label: lab, body: stmt })
@@ -643,33 +644,44 @@ var axbycz = objPatt([{ key: ident("a"),
 var xyz = arrPatt([ident("x"), ident("y"), ident("z")]);
 
 assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt));
 assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt));
+assertStmt("for (var {a:x,b:y,c:z} of foo);", forOfStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
+assertStmt("for (let {a:x,b:y,c:z} of foo);", forOfStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
+assertStmt("for ({a:x,b:y,c:z} of foo);", forOfStmt(axbycz, ident("foo"), emptyStmt));
+assertStmt("for (var [x,y,z] of foo);", forOfStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
+assertStmt("for (let [x,y,z] of foo);", forOfStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
+assertStmt("for ([x,y,z] of foo);", forOfStmt(xyz, ident("foo"), emptyStmt));
 assertStmt("for each (var {a:x,b:y,c:z} in foo);", forEachInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for each (let {a:x,b:y,c:z} in foo);", forEachInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for each ({a:x,b:y,c:z} in foo);", forEachInStmt(axbycz, ident("foo"), emptyStmt));
 assertStmt("for each (var [x,y,z] in foo);", forEachInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for each (let [x,y,z] in foo);", forEachInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for each ([x,y,z] in foo);", forEachInStmt(xyz, ident("foo"), emptyStmt));
 assertError("for (const x in foo);", SyntaxError);
 assertError("for (const {a:x,b:y,c:z} in foo);", SyntaxError);
 assertError("for (const [x,y,z] in foo);", SyntaxError);
+assertError("for (const x of foo);", SyntaxError);
+assertError("for (const {a:x,b:y,c:z} of foo);", SyntaxError);
+assertError("for (const [x,y,z] of foo);", SyntaxError);
 assertError("for each (const x in foo);", SyntaxError);
 assertError("for each (const {a:x,b:y,c:z} in foo);", SyntaxError);
 assertError("for each (const [x,y,z] in foo);", SyntaxError);
 
 // destructuring in for-in and for-each-in loop heads with initializers
 
 assertStmt("for (var {a:x,b:y,c:z} = 22 in foo);", forInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertStmt("for (var [x,y,z] = 22 in foo);", forInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
+assertStmt("for (var {a:x,b:y,c:z} = 22 of foo);", forOfStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
+assertStmt("for (var [x,y,z] = 22 of foo);", forOfStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertStmt("for each (var {a:x,b:y,c:z} = 22 in foo);", forEachInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertStmt("for each (var [x,y,z] = 22 in foo);", forEachInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertError("for (x = 22 in foo);", SyntaxError);
 assertError("for ({a:x,b:y,c:z} = 22 in foo);", SyntaxError);
 assertError("for ([x,y,z] = 22 in foo);", SyntaxError);
 assertError("for (const x = 22 in foo);", SyntaxError);
 assertError("for (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError);
 assertError("for (const [x,y,z] = 22 in foo);", SyntaxError);
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -20,17 +20,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 120);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 121);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/crashtests/761831.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+  function removeRoot() {
+    window.removeEventListener("DOMNodeRemoved", removeRoot, true);
+    document.open();
+  }
+
+  window.addEventListener("DOMNodeRemoved", removeRoot, true);
+
+  var r = document.documentElement;
+  document.removeChild(r);
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+</html>
--- a/js/xpconnect/crashtests/crashtests.list
+++ b/js/xpconnect/crashtests/crashtests.list
@@ -34,11 +34,12 @@ load 608963.html
 load 616930-1.html
 load 639737-1.html
 load 648206-1.html
 load 705875.html
 load 720305-1.html
 load 723465.html
 load 732870.html
 load 751995.html
+load 761831.html
 asserts(0-1) load 752038.html # We may hit bug 645229 here.
 asserts(1) load 753162.html # We hit bug 675518 or bug 680086 here.
 load 754311.html
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2692,81 +2692,72 @@ NS_IMETHODIMP
 nsXPCComponents_Utils::LookupMethod(const JS::Value& object,
                                     const JS::Value& name,
                                     JSContext *cx,
                                     JS::Value *retval)
 {
     JSAutoRequest ar(cx);
 
     // first param must be a JSObject
-    if (JSVAL_IS_PRIMITIVE(object))
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    JSObject* obj = JSVAL_TO_OBJECT(object);
-    while (obj && !js::IsWrapper(obj) && !IS_WRAPPER_CLASS(js::GetObjectClass(obj)))
-        obj = JS_GetPrototype(obj);
-
-    if (!obj)
+    if (!object.isObject())
         return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    JSObject* unwrappedObject;
-    nsresult rv = nsXPConnect::GetXPConnect()->GetJSObjectOfWrapper(cx, obj, &unwrappedObject);
-    if (NS_FAILED(rv))
-        return rv;
-
-    unwrappedObject = JS_ObjectToInnerObject(cx, unwrappedObject);
-    if (!unwrappedObject)
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    // second param must be a string
+    JSObject *obj = &object.toObject();
+
+    // second param must be a string.
     if (!JSVAL_IS_STRING(name))
         return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    // Make sure the name that we use for looking up the method/property is
-    // atomized.
-    jsid name_id;
-    JS::Value dummy;
-    if (!JS_ValueToId(cx, name, &name_id) ||
-        !JS_IdToValue(cx, name_id, &dummy))
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    // this will do verification and the method lookup for us
-    // Note that if |obj| is an XPCNativeWrapper this will all still work.
-    // We'll hand back the same method that we'd hand back for the underlying
-    // XPCWrappedNative.  This means no deep wrapping, unfortunately, but we
-    // can't keep track of both the underlying function and the
-    // XPCNativeWrapper at once in a single parent slot...
-    XPCCallContext inner_cc(JS_CALLER, cx, unwrappedObject, nsnull, name_id);
-
-    // was our jsobject really a wrapped native at all?
-    XPCWrappedNative* wrapper = inner_cc.GetWrapper();
-    if (!wrapper || !wrapper->IsValid())
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    // did we find a method/attribute by that name?
-    XPCNativeMember* member = inner_cc.GetMember();
-    if (!member || member->IsConstant())
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    // it would a be a big surprise if there is a member without an interface :)
-    XPCNativeInterface* iface = inner_cc.GetInterface();
-    if (!iface)
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    jsval funval;
-
-    // get (and perhaps lazily create) the member's cloned function
-    if (!member->NewFunctionObject(inner_cc, iface, obj, &funval))
-        return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    NS_ASSERTION(JS_ValueToFunction(inner_cc, funval),
-                 "Function is not a function");
-
-    // Stick the function in the return value. This roots it.
-    *retval = funval;
+    JSString *methodName = name.toString();
+    jsid methodId = INTERNED_STRING_TO_JSID(cx, JS_InternJSString(cx, methodName));
+
+    // If |obj| is a cross-compartment wrapper, try to puncture it. If this fails,
+    // we don't have full access to the other compartment, in which case we throw.
+    // Otherwise, enter the compartment.
+    if (js::IsCrossCompartmentWrapper(obj)) {
+        obj = js::UnwrapOneChecked(cx, obj);
+        if (!obj)
+            return NS_ERROR_XPC_BAD_CONVERT_JS;
+    }
+
+    {
+        // Enter the target compartment.
+        JSAutoEnterCompartment ac;
+        if (!ac.enter(cx, obj))
+            return NS_ERROR_FAILURE;
+
+        // Now, try to create an Xray wrapper around the object. This won't work
+        // if the object isn't Xray-able. In that case, we throw.
+        JSObject *xray = WrapperFactory::WrapForSameCompartmentXray(cx, obj);
+        if (!xray)
+            return NS_ERROR_XPC_BAD_CONVERT_JS;
+
+        // Alright, now do the lookup.
+        *retval = JSVAL_VOID;
+        JSPropertyDescriptor desc;
+        if (!JS_GetPropertyDescriptorById(cx, xray, methodId, 0, &desc))
+            return NS_ERROR_FAILURE;
+
+        // First look for a method value. If that's not there, try a getter,
+        // since historically lookupMethod also works for getters.
+        JSObject *methodObj = desc.value.isObject() ? &desc.value.toObject() : NULL;
+        if (!methodObj && (desc.attrs & JSPROP_GETTER))
+            methodObj = JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter);
+
+        // Callers of this function seem to expect bound methods. Make it happen.
+        // Note that this is unnecessary until bug 658909 is fixed.
+        if (methodObj && JS_ObjectIsCallable(cx, methodObj))
+            methodObj = JS_BindCallable(cx, methodObj, obj);
+
+        // Set the return value if appropriate.
+        *retval = methodObj ? ObjectValue(*methodObj) : JSVAL_VOID;
+    }
+
+    // Now that we've left the target compartment, wrap for the caller.
+    if (!JS_WrapValue(cx, retval))
+        return NS_ERROR_FAILURE;;
+
     return NS_OK;
 }
 
 /* void reportError (); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ReportError(const JS::Value &error, JSContext *cx)
 {
     // This function shall never fail! Silently eat any failure conditions.
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -358,41 +358,41 @@ xpc_qsThrow(JSContext *cx, nsresult rv)
  * functions, as that name is statically known.  But that would be redundant;
  * the information is handy at runtime anyway.  Also, this code often produces
  * a more specific error message, e.g. "[nsIDOMHTMLDocument.appendChild]"
  * rather than "[nsIDOMNode.appendChild]".
  */
 static void
 GetMemberInfo(JSObject *obj, jsid memberId, const char **ifaceName)
 {
-    // Get the interface name.  From DefinePropertyIfFound (in
-    // xpcwrappednativejsops.cpp) and XPCThrower::Verbosify.
-    //
-    // We could instead make the quick stub could pass in its interface name,
-    // but this code often produces a more specific error message, e.g.
     *ifaceName = "Unknown";
 
-    NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)) ||
-                 js::GetObjectClass(obj) == &XPC_WN_Tearoff_JSClass,
-                 "obj must be a wrapper");
-    XPCWrappedNativeProto *proto;
-    if (IS_SLIM_WRAPPER(obj)) {
-        proto = GetSlimWrapperProto(obj);
-    } else {
-        XPCWrappedNative *wrapper = (XPCWrappedNative *) js::GetObjectPrivate(obj);
-        proto = wrapper->GetProto();
-    }
-    if (proto) {
-        XPCNativeSet *set = proto->GetSet();
-        if (set) {
-            XPCNativeMember *member;
-            XPCNativeInterface *iface;
+    // Don't try to generate a useful name if there are security wrappers,
+    // because it isn't worth the risk of something going wrong just to generate
+    // an error message. Instead, only handle the simple case where we have the
+    // reflector in hand.
+    if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) {
+        XPCWrappedNativeProto *proto;
+        if (IS_SLIM_WRAPPER_OBJECT(obj)) {
+            proto = GetSlimWrapperProto(obj);
+        } else {
+            MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(obj));
+            XPCWrappedNative *wrapper =
+                static_cast<XPCWrappedNative *>(js::GetObjectPrivate(obj));
+            proto = wrapper->GetProto();
+        }
+        if (proto) {
+            XPCNativeSet *set = proto->GetSet();
+            if (set) {
+                XPCNativeMember *member;
+                XPCNativeInterface *iface;
 
-            if (set->FindMember(memberId, &member, &iface))
-                *ifaceName = iface->GetNameString();
+                if (set->FindMember(memberId, &member, &iface))
+                    *ifaceName = iface->GetNameString();
+            }
         }
     }
 }
 
 static void
 GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp)
 {
     JSObject *funobj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
--- a/js/xpconnect/tests/mochitest/Makefile.in
+++ b/js/xpconnect/tests/mochitest/Makefile.in
@@ -66,16 +66,17 @@ MOCHITEST_FILES =	bug500931_helper.html 
 		test_bug764389.html \
 		file_nodelists.html \
 		file_bug706301.html \
 		file_exnstack.html \
 		file_expandosharing.html \
 		file_bug760131.html \
 		file_empty.html \
 		file_documentdomain.html \
+		test_lookupMethod.html \
 		$(NULL)
 
 MOCHITEST_CHROME_FILES	= \
 		test_bug361111.xul \
 		test_bug760131.html \
 		$(NULL)
 
 ifneq ($(OS_TARGET),Android)
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/mochitest/test_lookupMethod.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=774245
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 774245</title>
+  <script type="application/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=774245">Mozilla Bug 774245</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Components.lookupMethod in content scope. **/
+SimpleTest.waitForExplicitFinish();
+
+var gLoaded = 0;
+function loaded() {
+  if (++gLoaded == 2)
+    go();
+}
+
+var sameOriginWin;
+var crossOriginWin;
+function go() {
+  // Grab references to the content windows.
+  sameOriginWin = document.getElementById('ifr-same').contentWindow;
+  crossOriginWin = document.getElementById('ifr-cross').contentWindow;
+
+  // Test same-compartment.
+  document.getElementsByTagName = function() { ok(false, "dont call me"); };
+  var result = Components.lookupMethod(document, 'getElementsByTagName')('iframe');
+  is(result.length, 2, "same-origin lookupMethod works");
+
+  // Test that the method is bound.
+  var gebtn = Components.lookupMethod(document, 'getElementsByTagName');
+  is(Function.call.apply(gebtn, [window, 'iframe']).length, 2, "method is bound");
+
+  // Test that we throw for location objects. Location objects already use same-
+  // compartment Xrays, so callers shouldn't need to use lookupMethod there. And
+  // making it work would involve complicating the security surounding the
+  // implementation.
+  try {
+    Components.lookupMethod(location, 'href');
+    ok(false, "Didn't throw when we should have!");
+  } catch(e) {
+    ok(true, "Correctly threw when trying to lookupMethod on location object");
+  }
+
+  // Test cross-compartment same-origin.
+  sameOriginWin.setTimeout = function() { ok(false, "dont call me either"); };
+  Components.lookupMethod(sameOriginWin, 'setTimeout')(continueTest, 0);
+}
+
+function continueTest() {
+  // Test that cross-origin fails.
+  try {
+    Components.lookupMethod(crossOriginWin, 'top');
+    ok(false, "Should have thrown");
+  } catch (e) {
+    ok(true, "Threw appropriately");
+  }
+
+  SimpleTest.finish();
+}
+
+
+</script>
+</pre>
+<iframe id="ifr-same" onload="loaded();" src="file_empty.html"></iframe>
+<iframe id="ifr-cross" onload="loaded();" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html"></iframe>
+</body>
+</html>
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -535,9 +535,45 @@ WrapperFactory::WrapComponentsObject(JSC
 {
     JSObject *wrapperObj =
         Wrapper::New(cx, obj, JS_GetPrototype(obj), JS_GetGlobalForObject(cx, obj),
                      &FilteringWrapper<SameCompartmentSecurityWrapper, ComponentsObjectPolicy>::singleton);
 
     return wrapperObj;
 }
 
+JSObject *
+WrapperFactory::WrapForSameCompartmentXray(JSContext *cx, JSObject *obj)
+{
+    // We should be same-compartment here.
+    MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
+
+    // Sort out what kind of Xray we can do. If we can't Xray, bail.
+    XrayType type = GetXrayType(obj);
+    if (type == NotXray)
+        return NULL;
+
+    // Select the appropriate proxy handler.
+    Wrapper *wrapper = NULL;
+    if (type == XrayForWrappedNative)
+        wrapper = &XrayWrapper<DirectWrapper>::singleton;
+    else if (type == XrayForDOMProxyObject)
+        wrapper = &XrayWrapper<DirectWrapper, ProxyXrayTraits>::singleton;
+    else if (type == XrayForDOMObject)
+        wrapper = &XrayWrapper<DirectWrapper, DOMXrayTraits>::singleton;
+    else
+        MOZ_NOT_REACHED("Bad Xray type");
+
+    // Make the Xray.
+    JSObject *parent = JS_GetGlobalForObject(cx, obj);
+    JSObject *wrapperObj = Wrapper::New(cx, obj, NULL, parent, wrapper);
+    if (!wrapperObj)
+        return NULL;
+
+    // Make the holder.
+    JSObject *xrayHolder = XrayUtils::createHolder(cx, obj, parent);
+    if (!xrayHolder)
+        return nsnull;
+    js::SetProxyExtra(wrapperObj, 0, js::ObjectValue(*xrayHolder));
+    return wrapperObj;
 }
+
+}
--- a/js/xpconnect/wrappers/WrapperFactory.h
+++ b/js/xpconnect/wrappers/WrapperFactory.h
@@ -83,15 +83,18 @@ class WrapperFactory {
     // Wrap a (same compartment) object in a SOW.
     static JSObject *WrapSOWObject(JSContext *cx, JSObject *obj);
 
     // Return true if this is a Components object.
     static bool IsComponentsObject(JSObject *obj);
 
     // Wrap a (same compartment) Components object.
     static JSObject *WrapComponentsObject(JSContext *cx, JSObject *obj);
+
+    // Wrap a same-compartment object for Xray inspection.
+    static JSObject *WrapForSameCompartmentXray(JSContext *cx, JSObject *obj);
 };
 
 extern js::DirectWrapper XrayWaiver;
 
 }
 
 #endif /* _xpc_WRAPPERFACTORY_H */
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1613,9 +1613,26 @@ template <> XRAY XRAY::singleton(0);
 template class XRAY;
 #undef XRAY
 
 #define XRAY XrayWrapper<CrossCompartmentWrapper, DOMXrayTraits >
 template <> XRAY XRAY::singleton(0);
 template class XRAY;
 #undef XRAY
 
+/* Same-compartment non-filtering versions. */
+
+#define XRAY XrayWrapper<DirectWrapper, XPCWrappedNativeXrayTraits >
+template <> XRAY XRAY::singleton(0);
+template class XRAY;
+#undef XRAY
+
+#define XRAY XrayWrapper<DirectWrapper, ProxyXrayTraits >
+template <> XRAY XRAY::singleton(0);
+template class XRAY;
+#undef XRAY
+
+#define XRAY XrayWrapper<DirectWrapper, DOMXrayTraits >
+template <> XRAY XRAY::singleton(0);
+template class XRAY;
+#undef XRAY
+
 }
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2300,17 +2300,17 @@ InternalInvalidateThebesLayersInSubtree(
 {
   if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT))
     return false;
 
   bool foundContainerLayer = false;
   if (aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
     // Delete the invalid region to indicate that all Thebes contents
     // need to be invalidated
-    aFrame->Properties().Delete(ThebesLayerInvalidRegionProperty());
+    FrameLayerBuilder::InvalidateThebesLayerContents(aFrame, aFrame->GetVisualOverflowRectRelativeToSelf());
     foundContainerLayer = true;
   }
 
   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
   if (!aFrame->GetFirstPrincipalChild()) {
     nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(aFrame);
     if (subdocumentFrame) {
       // Descend into the subdocument
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -15,16 +15,20 @@
 
 class nsDisplayListBuilder;
 class nsDisplayList;
 class nsDisplayItem;
 class gfxContext;
 class nsRootPresContext;
 
 namespace mozilla {
+namespace layers {
+class ContainerLayer;
+class ThebesLayer;
+}
 
 class FrameLayerBuilder;
 
 enum LayerState {
   LAYER_NONE,
   LAYER_INACTIVE,
   LAYER_ACTIVE,
   // Force an active layer even if it causes incorrect rendering, e.g.
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2778,24 +2778,34 @@ nsDisplayTransform::GetResultingTransfor
     aFrame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
   /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
   if (disp->mSpecifiedTransform) {
     result = nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
                                                     aFrame->GetStyleContext(),
                                                     aFrame->PresContext(),
                                                     dummy, bounds, aAppUnitsPerPixel);
   } else if (hasSVGTransforms) {
+    // Correct the translation components for zoom:
+    float pixelsPerCSSPx = aFrame->PresContext()->AppUnitsPerCSSPixel() /
+                             aAppUnitsPerPixel;
+    svgTransform.x0 *= pixelsPerCSSPx;
+    svgTransform.y0 *= pixelsPerCSSPx;
     result = gfx3DMatrix::From2D(svgTransform);
   } else {
      NS_ASSERTION(aFrame->GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
                   aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN,
                   "If we don't have a transform, then we must have another reason to have an nsDisplayTransform created");
   }
 
   if (hasSVGTransforms && !transformFromSVGParent.IsIdentity()) {
+    // Correct the translation components for zoom:
+    float pixelsPerCSSPx = aFrame->PresContext()->AppUnitsPerCSSPixel() /
+                             aAppUnitsPerPixel;
+    transformFromSVGParent.x0 *= pixelsPerCSSPx;
+    transformFromSVGParent.y0 *= pixelsPerCSSPx;
     result = result * gfx3DMatrix::From2D(transformFromSVGParent);
   }
 
   const nsStyleDisplay* parentDisp = nsnull;
   nsStyleContext* parentStyleContext = aFrame->GetStyleContext()->GetParent();
   if (parentStyleContext) {
     parentDisp = parentStyleContext->GetStyleDisplay();
   }
@@ -3290,19 +3300,19 @@ nsDisplaySVGEffects::BuildLayer(nsDispla
     return nsnull;
 
   nsIFrame* firstFrame =
     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(mFrame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
 
   bool isOK = true;
-  nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
-  nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
-  nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
+  effectProperties.GetClipPathFrame(&isOK);
+  effectProperties.GetMaskFrame(&isOK);
+  effectProperties.GetFilterFrame(&isOK);
 
   if (!isOK) {
     return nsnull;
   }
 
   nsRefPtr<ContainerLayer> container = GetLayerBuilderForManager(aManager)->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nsnull);
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -15,17 +15,16 @@
 
 #include "nsCOMPtr.h"
 #include "nsIFrame.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsISelection.h"
 #include "nsCaret.h"
 #include "plarena.h"
-#include "Layers.h"
 #include "nsRegion.h"
 #include "FrameLayerBuilder.h"
 #include "nsThemeConstants.h"
 #include "ImageLayers.h"
 
 #include "mozilla/StandardInteger.h"
 
 #include <stdlib.h>
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -422,17 +422,17 @@ nsListControlFrame::Reflow(nsPresContext
   PRInt32 length = GetNumberOfOptions();  
 
   nscoord oldHeightOfARow = HeightOfARow();
 
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW) && autoHeight) {
     // When not doing an initial reflow, and when the height is auto, start off
     // with our computed height set to what we'd expect our height to be.
     nscoord computedHeight = CalcIntrinsicHeight(oldHeightOfARow, length);
-    state.ApplyMinMaxConstraints(nsnull, &computedHeight);
+    computedHeight = state.ApplyMinMaxHeight(computedHeight);
     state.SetComputedHeight(computedHeight);
   }
 
   nsresult rv = nsHTMLScrollFrame::Reflow(aPresContext, aDesiredSize,
                                           state, aStatus);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mMightNeedSecondPass) {
@@ -480,17 +480,17 @@ nsListControlFrame::Reflow(nsPresContext
   // XXXbz We're just changing the height here; do we need to dirty ourselves
   // or anything like that?  We might need to, per the letter of the reflow
   // protocol, but things seem to work fine without it...  Is that just an
   // implementation detail of nsHTMLScrollFrame that we're depending on?
   nsHTMLScrollFrame::DidReflow(aPresContext, &state, aStatus);
 
   // Now compute the height we want to have
   nscoord computedHeight = CalcIntrinsicHeight(HeightOfARow(), length); 
-  state.ApplyMinMaxConstraints(nsnull, &computedHeight);
+  computedHeight = state.ApplyMinMaxHeight(computedHeight);
   state.SetComputedHeight(computedHeight);
 
   nsHTMLScrollFrame::WillReflow(aPresContext);
 
   // XXXbz to make the ascent really correct, we should add our
   // mComputedPadding.top to it (and subtract it from descent).  Need that
   // because nsGfxScrollFrame just adds in the border....
   return nsHTMLScrollFrame::Reflow(aPresContext, aDesiredSize, state, aStatus);
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1424,21 +1424,19 @@ nsBlockFrame::ComputeFinalSize(const nsH
       // here. We need GetSkipSides to check whether we ran out of content
       // height in the current frame, not whether it's last-in-flow.
     }
 
     // Don't carry out a bottom margin when our height is fixed.
     aMetrics.mCarriedOutBottomMargin.Zero();
   }
   else if (NS_FRAME_IS_COMPLETE(aState.mReflowStatus)) {
-    nscoord autoHeight = bottomEdgeOfChildren;
-    autoHeight -= borderPadding.top;
-    nscoord oldAutoHeight = autoHeight;
-    aReflowState.ApplyMinMaxConstraints(nsnull, &autoHeight);
-    if (autoHeight != oldAutoHeight) {
+    nscoord contentHeight = bottomEdgeOfChildren - borderPadding.top;
+    nscoord autoHeight = aReflowState.ApplyMinMaxHeight(contentHeight);
+    if (autoHeight != contentHeight) {
       // Our min-height or max-height made our height change.  Don't carry out
       // our kids' bottom margins.
       aMetrics.mCarriedOutBottomMargin.Zero();
     }
     autoHeight += borderPadding.top + borderPadding.bottom;
     aMetrics.height = autoHeight;
   }
   else {
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -293,17 +293,18 @@ static nsSize ComputeInsideBorderSize(Sc
       aState->mReflowState.mComputedPadding.LeftRight();
   }
   nscoord contentHeight = aState->mReflowState.ComputedHeight();
   if (contentHeight == NS_UNCONSTRAINEDSIZE) {
     contentHeight = aDesiredInsideBorderSize.height -
       aState->mReflowState.mComputedPadding.TopBottom();
   }
 
-  aState->mReflowState.ApplyMinMaxConstraints(&contentWidth, &contentHeight);
+  contentWidth  = aState->mReflowState.ApplyMinMaxWidth(contentWidth);
+  contentHeight = aState->mReflowState.ApplyMinMaxHeight(contentHeight);
   return nsSize(contentWidth + aState->mReflowState.mComputedPadding.LeftRight(),
                 contentHeight + aState->mReflowState.mComputedPadding.TopBottom());
 }
 
 static void
 GetScrollbarMetrics(nsBoxLayoutState& aState, nsIBox* aBox, nsSize* aMin,
                     nsSize* aPref, bool aVertical)
 {
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -2422,35 +2422,16 @@ nsCSSOffsetState::ComputePadding(nscoord
     mComputedPadding.bottom = NS_MAX(0, nsLayoutUtils::
       ComputeWidthDependentValue(aContainingBlockWidth,
                                  stylePadding->mPadding.GetBottom()));
   }
   return isWidthDependent;
 }
 
 void
-nsHTMLReflowState::ApplyMinMaxConstraints(nscoord* aFrameWidth,
-                                          nscoord* aFrameHeight) const
-{
-  if (aFrameWidth) {
-    if (NS_UNCONSTRAINEDSIZE != mComputedMaxWidth) {
-      *aFrameWidth = NS_MIN(*aFrameWidth, mComputedMaxWidth);
-    }
-    *aFrameWidth = NS_MAX(*aFrameWidth, mComputedMinWidth);
-  }
-
-  if (aFrameHeight) {
-    if (NS_UNCONSTRAINEDSIZE != mComputedMaxHeight) {
-      *aFrameHeight = NS_MIN(*aFrameHeight, mComputedMaxHeight);
-    }
-    *aFrameHeight = NS_MAX(*aFrameHeight, mComputedMinHeight);
-  }
-}
-
-void
 nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth,
                                        nscoord aContainingBlockHeight,
                                        const nsHTMLReflowState* aContainingBlockRS)
 {
   mComputedMinWidth = ComputeWidthValue(aContainingBlockWidth,
                                         mStylePosition->mBoxSizing,
                                         mStylePosition->mMinWidth);
 
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -408,21 +408,35 @@ public:
 
 
   void ComputeContainingBlockRectangle(nsPresContext*          aPresContext,
                                        const nsHTMLReflowState* aContainingBlockRS,
                                        nscoord&                 aContainingBlockWidth,
                                        nscoord&                 aContainingBlockHeight);
 
   /**
-   * Apply the mComputed(Min/Max)(Width/Height) values to the content
-   * size computed so far. If a passed-in pointer is null, we skip
-   * adjusting that dimension.
+   * Apply the mComputed(Min/Max)Width constraints to the content
+   * size computed so far.
    */
-  void ApplyMinMaxConstraints(nscoord* aContentWidth, nscoord* aContentHeight) const;
+  nscoord ApplyMinMaxWidth(nscoord aWidth) const {
+    if (NS_UNCONSTRAINEDSIZE != mComputedMaxWidth) {
+      aWidth = NS_MIN(aWidth, mComputedMaxWidth);
+    }
+    return NS_MAX(aWidth, mComputedMinWidth);
+  }
+  /**
+   * Apply the mComputed(Min/Max)Height constraints to the content
+   * size computed so far.
+   */
+  nscoord ApplyMinMaxHeight(nscoord aHeight) const {
+    if (NS_UNCONSTRAINEDSIZE != mComputedMaxHeight) {
+      aHeight = NS_MIN(aHeight, mComputedMaxHeight);
+    }
+    return NS_MAX(aHeight, mComputedMinHeight);
+  }
 
   bool ShouldReflowAllKids() const {
     // Note that we could make a stronger optimization for mVResize if
     // we use it in a ShouldReflowChild test that replaces the current
     // checks of NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN, if it
     // were tested there along with NS_FRAME_CONTAINS_RELATIVE_HEIGHT.
     // This would need to be combined with a slight change in which
     // frames NS_FRAME_CONTAINS_RELATIVE_HEIGHT is marked on.
--- a/layout/ipc/PRenderFrame.ipdl
+++ b/layout/ipc/PRenderFrame.ipdl
@@ -3,17 +3,17 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBrowser;
 include protocol PLayers;
 
-using mozilla::LayersBackend;
+using mozilla::layers::LayersBackend;
 
 namespace mozilla {
 namespace layout {
 
 /**
  * PRenderFrame (in the layout sense of "frame") represents one web
  * "page".  It's used to graft content processes' layer trees into
  * chrome's rendering path.  The lifetime of a PRenderFrame is tied to
--- a/layout/ipc/RenderFrameChild.cpp
+++ b/layout/ipc/RenderFrameChild.cpp
@@ -2,16 +2,17 @@
  * vim: sw=2 ts=8 et :
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RenderFrameChild.h"
 #include "mozilla/layers/ShadowLayersChild.h"
+#include "LayersBackend.h"
 
 using mozilla::layers::PLayersChild;
 using mozilla::layers::ShadowLayersChild;
 
 namespace mozilla {
 namespace layout {
 
 void
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ShadowLayersParent.h"
 #include "nsContentUtils.h"
 #include "nsFrameLoader.h"
 #include "nsIObserver.h"
 #include "nsSubDocumentFrame.h"
 #include "nsViewportFrame.h"
 #include "RenderFrameParent.h"
+#include "LayersBackend.h"
 
 typedef nsContentView::ViewConfig ViewConfig;
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace layout {
 
 typedef FrameMetrics::ViewID ViewID;
@@ -90,17 +91,17 @@ static void ApplyTransform(nsRect& aRect
   aRect.height = aRect.height * aTransform._22;
 }
  
 static void
 AssertInTopLevelChromeDoc(ContainerLayer* aContainer,
                           nsIFrame* aContainedFrame)
 {
   NS_ASSERTION(
-    (aContainer->Manager()->GetBackendType() != LayerManager::LAYERS_BASIC) ||
+    (aContainer->Manager()->GetBackendType() != mozilla::layers::LAYERS_BASIC) ||
     (aContainedFrame->GetNearestWidget() ==
      static_cast<BasicLayerManager*>(aContainer->Manager())->GetRetainerWidget()),
     "Expected frame to be in top-level chrome document");
 }
 
 // Return view for given ID in aArray, NULL if not found.
 static nsContentView*
 FindViewForId(const ViewMap& aMap, ViewID aId)
@@ -311,17 +312,17 @@ ClearContainer(ContainerLayer* aContaine
 
 // Return true iff |aManager| is a "temporary layer manager".  They're
 // used for small software rendering tasks, like drawWindow.  That's
 // currently implemented by a BasicLayerManager without a backing
 // widget, and hence in non-retained mode.
 static bool
 IsTempLayerManager(LayerManager* aManager)
 {
-  return (LayerManager::LAYERS_BASIC == aManager->GetBackendType() &&
+  return (mozilla::layers::LAYERS_BASIC == aManager->GetBackendType() &&
           !static_cast<BasicLayerManager*>(aManager)->IsRetained());
 }
 
 // Recursively create a new array of scrollables, preserving any scrollables
 // that are still in the layer tree.
 //
 // aXScale and aYScale are used to calculate any values that need to be in
 // chrome-document CSS pixels and aren't part of the rendering loop, such as
@@ -448,28 +449,28 @@ BuildBackgroundPatternFor(ContainerLayer
 already_AddRefed<LayerManager>
 GetFrom(nsFrameLoader* aFrameLoader)
 {
   nsIDocument* doc = aFrameLoader->GetOwnerDoc();
   return nsContentUtils::LayerManagerForDocument(doc);
 }
 
 RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader,
-                                     LayerManager::LayersBackend* aBackendType,
+                                     mozilla::layers::LayersBackend* aBackendType,
                                      int* aMaxTextureSize,
                                      uint64_t* aId)
   : mLayersId(0)
   , mFrameLoader(aFrameLoader)
   , mFrameLoaderDestroyed(false)
   , mBackgroundColor(gfxRGBA(1, 1, 1))
 {
   mContentViews[FrameMetrics::ROOT_SCROLL_ID] =
     new nsContentView(aFrameLoader, FrameMetrics::ROOT_SCROLL_ID);
 
-  *aBackendType = LayerManager::LAYERS_NONE;
+  *aBackendType = mozilla::layers::LAYERS_NONE;
   *aMaxTextureSize = 0;
   *aId = 0;
 
   nsRefPtr<LayerManager> lm = GetFrom(mFrameLoader);
   *aBackendType = lm->GetBackendType();
   *aMaxTextureSize = lm->GetMaxTextureSize();
 
   if (CompositorParent::CompositorLoop()) {
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -8,17 +8,17 @@
 #ifndef mozilla_layout_RenderFrameParent_h
 #define mozilla_layout_RenderFrameParent_h
 
 #include "mozilla/layout/PRenderFrameParent.h"
 #include "mozilla/layers/ShadowLayersManager.h"
 
 #include <map>
 #include "nsDisplayList.h"
-#include "Layers.h"
+#include "LayersBackend.h"
 
 class nsContentView;
 class nsFrameLoader;
 class nsSubDocumentFrame;
 
 namespace mozilla {
 
 namespace layers {
@@ -36,17 +36,17 @@ class RenderFrameParent : public PRender
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ShadowLayersParent ShadowLayersParent;
   typedef FrameMetrics::ViewID ViewID;
 
 public:
   typedef std::map<ViewID, nsRefPtr<nsContentView> > ViewMap;
 
   RenderFrameParent(nsFrameLoader* aFrameLoader,
-                    LayerManager::LayersBackend* aBackendType,
+                    mozilla::layers::LayersBackend* aBackendType,
                     int* aMaxTextureSize,
                     uint64_t* aId);
   virtual ~RenderFrameParent();
 
   void Destroy();
 
   /**
    * Helper function for getting a non-owning reference to a scrollable.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filter-scaled-02-ref.html
@@ -0,0 +1,15 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+  <body style="-moz-transform: scale(1.4)">
+   <div style="position: absolute; top: 20px; left: 200px">
+    <svg width="200" viewBox="0 0 222 222">
+     <rect fill="green" x="120" y="100" width="100" height="120"/>
+     <rect fill="none" stroke="black" stroke-width="4"
+           x="120" y="100" width="100" height="120"/>
+    </svg>
+   </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filter-scaled-02.html
@@ -0,0 +1,25 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+  <head>
+    <title>Test case for scaled SVG with filter region</title>
+    <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=765107 -->
+  </head>
+  <body style="-moz-transform: scale(1.4)">
+   <div style="position: absolute; top: 20px; left: 200px">
+    <svg width="200" viewBox="0 0 222 222">
+     <filter id="filter" x="-20%" width="140%">
+      <feMerge>
+        <feMergeNode/>
+      </feMerge>
+     </filter>
+     <rect fill="green" x="120" y="100" width="100" height="120"
+           filter="url(#filter)"/>
+     <rect fill="none" stroke="black" stroke-width="4"
+           x="120" y="100" width="100" height="120"/>
+    </svg>
+   </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/dynamic-filtered-foreignObject-01.svg
@@ -0,0 +1,31 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=769942 -->
+  <script>
+
+function run_test() {
+  var fO = document.getElementById("fO");
+  fO.parentNode.removeChild(fO);
+  document.documentElement.removeAttribute("class");
+}
+
+document.addEventListener("MozReftestInvalidate", run_test);
+setTimeout(run_test, 3000);
+
+  </script>
+  <filter id="filter" x="0" y="0" width="150" height="150"
+          filterUnits="userSpaceOnUse"
+          primitiveUnits="userSpaceOnUse">
+    <feOffset dx="-50" dy="-50"/>
+  </filter>
+  <rect width="100%" height="100%" fill="lime"/>
+  <g filter="url(#filter)">
+    <foreignObject id="fO" x="50" y="50" width="100" height="100">
+      <div xmlns="http://www.w3.org/1999/xhtml"
+           style="display:block; width:100%; height:100%; background:red;"/>
+    </foreignObject>
+  </g>
+</svg>
--- a/layout/reftests/svg/filters/reftest.list
+++ b/layout/reftests/svg/filters/reftest.list
@@ -1,12 +1,14 @@
 # In general, the fe*-1 tests test basic functionality clipped to a filter primitive
 # subregion. The fe*-2 tests test with no clipping (which stresses
 # the automatic optimal surface-size computation a bit more).
 
+== dynamic-filtered-foreignObject-01.svg pass.svg
+
 == feBlend-1.svg feBlend-1-ref.svg
 == feBlend-2.svg feBlend-2-ref.svg
 
 == feColorMatrix-1.svg feColorMatrix-1-ref.svg
 == feColorMatrix-2.svg feColorMatrix-2-ref.svg
 
 == feComponentTransfer-1.svg feComponentTransfer-1-ref.svg
 == feComponentTransfer-2.svg feComponentTransfer-2-ref.svg
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -132,16 +132,17 @@ random == dynamic-use-nested-01b.svg dyn
 == filter-basic-03.svg pass.svg
 == filter-bounds-01.svg pass.svg
 == filter-bounds-02.svg pass.svg
 fails-if(Android) == filter-extref-differentOrigin-01.svg pass.svg # Bug 695385
 == filter-foreignObject-01.svg pass.svg
 == filter-in-mask-01.svg pass.svg
 == filter-invalidation-01.svg pass.svg
 == filter-scaled-01.svg pass.svg
+== filter-scaled-02.html filter-scaled-02-ref.html
 == filter-translated-01.svg filter-translated-01-ref.svg
 == filters-and-group-opacity-01.svg filters-and-group-opacity-01-ref.svg
 == foreignObject-01.svg pass.svg
 == foreignObject-02.svg foreignObject-02-ref.svg
 == foreignObject-ancestor-style-change-01.svg foreignObject-ancestor-style-change-01-ref.svg
 == foreignObject-change-transform-01.svg pass.svg
 == foreignObject-display-01.svg pass.svg
 == foreignObject-form-theme.svg foreignObject-form-theme-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/perspective-origin-4-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <title>Testcase for bug 770629</title>
+  <style>
+
+div {
+  position: absolute;
+  left: 125px;
+  width: 50px;
+  height: 100px;
+  background: blue;
+}
+
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/perspective-origin-4a.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <title>Testcase for bug 770629</title>
+  <style>
+
+.outer {
+  position: absolute;
+  left: 100px;
+  -moz-transform: scale(0.5,1);
+  -moz-perspective: 200px; 
+  -moz-perspective-origin: 50% 0px;
+}
+
+.inner {
+  width: 100px;
+  height: 100px;
+  background: blue;
+  -moz-transform: rotateY(0deg);
+}
+
+  </style>
+</head>
+<body>
+  <div class="outer"> 
+    <div class="inner"></div> 
+  </div>
+</body>
+</html>
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -34,16 +34,17 @@ fuzzy-if(d2d&&layersGPUAccelerated,52,68
 != backface-visibility-1a.html about:blank
 == backface-visibility-1b.html about:blank
 == backface-visibility-1c.html about:blank
 == backface-visibility-2.html backface-visibility-2-ref.html
 != perspective-origin-1a.html rotatex-perspective-1a.html
 == perspective-origin-1b.html perspective-origin-1a.html
 random-if(Android&&!browserIsRemote) == perspective-origin-2a.html perspective-origin-2-ref.html # bug 732568
 == perspective-origin-3a.html perspective-origin-3-ref.html
+== perspective-origin-4a.html perspective-origin-4-ref.html
 != sorting-1a.html sorting-1-ref.html
 # Parallel planes, different z depth
 == sorting-2a.html sorting-2-ref.html
 # Parallel planes, same z depth (shouldn't be sorted!)
 == sorting-2b.html sorting-2-ref.html
 == sorting-3a.html green-rect.html
 # Different, but equivalent (for the given transform) transform origins
 == rotatex-transformorigin-1a.html rotatex-transformorigin-1-ref.html
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -1494,17 +1494,17 @@ nsSVGUtils::CompositeSurfaceMatrix(gfxCo
     aContext->SetSource(aSurface);
     aContext->Paint(aOpacity);
     aContext->Restore();
   } else {
     DrawTarget *dt = aContext->GetDrawTarget();
     Matrix oldMat = dt->GetTransform();
     RefPtr<SourceSurface> surf =
       gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
-    dt->SetTransform(oldMat * ToMatrix(aCTM));
+    dt->SetTransform(ToMatrix(aCTM) * oldMat);
 
     gfxSize size = aSurface->GetSize();
     NS_ASSERTION(size.width >= 0 && size.height >= 0, "Failure to get size for aSurface.");
 
     gfxPoint pt = aSurface->GetDeviceOffset();
 
     dt->FillRect(Rect(-pt.x, -pt.y, size.width, size.height),
                  SurfacePattern(surf, EXTEND_CLAMP,
--- a/layout/xul/base/src/nsBoxFrame.cpp
+++ b/layout/xul/base/src/nsBoxFrame.cpp
@@ -683,17 +683,17 @@ nsBoxFrame::Reflow(nsPresContext*       
         // fall through
       case NS_STYLE_BOX_SIZING_PADDING:
         outsideBoxSizing -= aReflowState.mComputedPadding.TopBottom();
         break;
     }
     computedSize.height -= outsideBoxSizing;
     // Note: might be negative now, but that's OK because min-width is
     // never negative.
-    aReflowState.ApplyMinMaxConstraints(nsnull, &computedSize.height);
+    computedSize.height = aReflowState.ApplyMinMaxHeight(computedSize.height);
     computedSize.height += outsideBoxSizing;
   } else {
     computedSize.height += m.top + m.bottom;
   }
 
   nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
 
   SetBounds(state, r);
--- a/layout/xul/base/src/nsMenuBarListener.cpp
+++ b/layout/xul/base/src/nsMenuBarListener.cpp
@@ -28,16 +28,17 @@ using namespace mozilla;
  */
 
 NS_IMPL_ISUPPORTS1(nsMenuBarListener, nsIDOMEventListener)
 
 #define MODIFIER_SHIFT    1
 #define MODIFIER_CONTROL  2
 #define MODIFIER_ALT      4
 #define MODIFIER_META     8
+#define MODIFIER_OS       16
 
 ////////////////////////////////////////////////////////////////////////
 
 PRInt32 nsMenuBarListener::mAccessKey = -1;
 PRUint32 nsMenuBarListener::mAccessKeyMask = 0;
 bool nsMenuBarListener::mAccessKeyFocuses = false;
 
 nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBar) 
@@ -81,16 +82,18 @@ void nsMenuBarListener::InitAccessKey()
   if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT)
     mAccessKeyMask = MODIFIER_SHIFT;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL)
     mAccessKeyMask = MODIFIER_CONTROL;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT)
     mAccessKeyMask = MODIFIER_ALT;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META)
     mAccessKeyMask = MODIFIER_META;
+  else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_WIN)
+    mAccessKeyMask = MODIFIER_OS;
 
   mAccessKeyFocuses = Preferences::GetBool("ui.key.menuAccessKeyFocuses");
 }
 
 void
 nsMenuBarListener::ToggleMenuActiveState()
 {
   nsMenuFrame* closemenu = mMenuBarFrame->ToggleMenuActiveState();
@@ -265,33 +268,39 @@ nsMenuBarListener::IsAccessKeyPressed(ns
           (modifiers & mAccessKeyMask) &&
           (modifiers & ~(mAccessKeyMask | MODIFIER_SHIFT)) == 0);
 }
 
 PRUint32
 nsMenuBarListener::GetModifiers(nsIDOMKeyEvent* aKeyEvent)
 {
   PRUint32 modifiers = 0;
-  bool modifier;
+  nsInputEvent* inputEvent =
+    static_cast<nsInputEvent*>(aKeyEvent->GetInternalNSEvent());
+  MOZ_ASSERT(inputEvent);
 
-  aKeyEvent->GetShiftKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsShift()) {
     modifiers |= MODIFIER_SHIFT;
+  }
 
-  aKeyEvent->GetCtrlKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsControl()) {
     modifiers |= MODIFIER_CONTROL;
+  }
 
-  aKeyEvent->GetAltKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsAlt()) {
     modifiers |= MODIFIER_ALT;
+  }
 
-  aKeyEvent->GetMetaKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsMeta()) {
     modifiers |= MODIFIER_META;
+  }
+
+  if (inputEvent->IsOS()) {
+    modifiers |= MODIFIER_OS;
+  }
 
   return modifiers;
 }
 
 ////////////////////////////////////////////////////////////////////////
 nsresult
 nsMenuBarListener::KeyDown(nsIDOMEvent* aKeyEvent)
 {
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -1089,41 +1089,49 @@ nsMenuFrame::BuildAcceleratorText(bool a
   char* str = ToNewCString(modifiers);
   char* newStr;
   char* token = nsCRT::strtok(str, ", \t", &newStr);
 
   nsAutoString shiftText;
   nsAutoString altText;
   nsAutoString metaText;
   nsAutoString controlText;
+  nsAutoString osText;
   nsAutoString modifierSeparator;
 
   nsContentUtils::GetShiftText(shiftText);
   nsContentUtils::GetAltText(altText);
   nsContentUtils::GetMetaText(metaText);
   nsContentUtils::GetControlText(controlText);
+  nsContentUtils::GetOSText(osText);
   nsContentUtils::GetModifierSeparatorText(modifierSeparator);
 
   while (token) {
       
     if (PL_strcmp(token, "shift") == 0)
       accelText += shiftText;
     else if (PL_strcmp(token, "alt") == 0) 
       accelText += altText; 
     else if (PL_strcmp(token, "meta") == 0) 
       accelText += metaText; 
+    else if (PL_strcmp(token, "os") == 0)
+      accelText += osText; 
     else if (PL_strcmp(token, "control") == 0) 
       accelText += controlText; 
     else if (PL_strcmp(token, "accel") == 0) {
       switch (accelKey)
       {
         case nsIDOMKeyEvent::DOM_VK_META:
           accelText += metaText;
           break;
 
+        case nsIDOMKeyEvent::DOM_VK_WIN:
+          accelText += osText;
+          break;
+
         case nsIDOMKeyEvent::DOM_VK_ALT:
           accelText += altText;
           break;
 
         case nsIDOMKeyEvent::DOM_VK_CONTROL:
         default:
           accelText += controlText;
           break;
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -465,17 +465,17 @@ public class AboutHomeContent extends Sc
                         final String homepageUrl = jsonobj.getString("homepageURL");
                         row.setOnClickListener(new View.OnClickListener() {
                             public void onClick(View v) {
                                 if (mUriLoadCallback != null)
                                     mUriLoadCallback.callback(homepageUrl);
                             }
                         });
 
-                        Favicons favicons = GeckoApp.mAppContext.mFavicons;
+                        Favicons favicons = GeckoApp.mAppContext.getFavicons();
                         favicons.loadFavicon(pageUrl, iconUrl,
                                     new Favicons.OnFaviconLoadedListener() {
                             public void onFaviconLoaded(String url, Drawable favicon) {
                                 if (favicon != null) {
                                     ImageView icon = (ImageView) row.findViewById(R.id.addon_icon);
                                     icon.setImageDrawable(favicon);
                                 }
                             }
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -414,17 +414,17 @@ abstract public class BrowserApp extends
     void addDoorHanger(String message, String value, JSONArray buttons, Tab tab, JSONObject options) {
         mDoorHangerPopup.addDoorHanger(message, value, buttons, tab, options, mBrowserToolbar.mFavicon);
     }
 
     /* Favicon methods */
     private void loadFavicon(final Tab tab) {
         maybeCancelFaviconLoad(tab);
 
-        long id = mFavicons.loadFavicon(tab.getURL(), tab.getFaviconURL(),
+        long id = getFavicons().loadFavicon(tab.getURL(), tab.getFaviconURL(),
                         new Favicons.OnFaviconLoadedListener() {
 
             public void onFaviconLoaded(String pageUrl, Drawable favicon) {
                 // Leave favicon UI untouched if we failed to load the image
                 // for some reason.
                 if (favicon == null)
                     return;
 
@@ -452,17 +452,17 @@ abstract public class BrowserApp extends
 
     private void maybeCancelFaviconLoad(Tab tab) {
         long faviconLoadId = tab.getFaviconLoadId();
 
         if (faviconLoadId == Favicons.NOT_LOADING)
             return;
 
         // Cancel pending favicon load task
-        mFavicons.cancelFaviconLoad(faviconLoadId);
+        getFavicons().cancelFaviconLoad(faviconLoadId);
 
         // Reset favicon load state
         tab.setFaviconLoadId(Favicons.NOT_LOADING);
     }
 
 
     /* About:home UI */
     void updateAboutHomeTopSites() {
@@ -547,20 +547,24 @@ abstract public class BrowserApp extends
     public void closeOptionsMenu() {
         if (!mBrowserToolbar.closeOptionsMenu())
             super.closeOptionsMenu();
     }
 
     @Override
     public void setFullScreen(final boolean fullscreen) {
       super.setFullScreen(fullscreen);
-      if (fullscreen)
-          mBrowserToolbar.hide();
-      else
-          mBrowserToolbar.show();
+      mMainHandler.post(new Runnable() {
+          public void run() {
+              if (fullscreen)
+                  mBrowserToolbar.hide();
+              else
+                  mBrowserToolbar.show();
+          }
+      });
     }
 
     @Override
     public boolean onPrepareOptionsMenu(Menu aMenu)
     {
         if (aMenu == null)
             return false;
 
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -91,21 +91,21 @@ abstract public class GeckoApp
     private GeckoProfile mProfile;
     public static boolean sIsGeckoReady = false;
     public static int mOrientation;
     private boolean mIsRestoringActivity;
 
     private GeckoConnectivityReceiver mConnectivityReceiver;
     private GeckoBatteryManager mBatteryReceiver;
     private PromptService mPromptService;
+    private Favicons mFavicons;
 
     public DoorHangerPopup mDoorHangerPopup;
     public FormAssistPopup mFormAssistPopup;
     public TabsPanel mTabsPanel;
-    public Favicons mFavicons;
 
     private LayerController mLayerController;
     private GeckoLayerClient mLayerClient;
     private AbsoluteLayout mPluginContainer;
     private FindInPageBar mFindInPageBar;
 
     private FullScreenHolder mFullScreenPluginContainer;
     private View mFullScreenPluginView;
@@ -386,16 +386,23 @@ abstract public class GeckoApp
                     return pkgInfo.packageName;
                 }
             }
         }
 
         return null;
     }
 
+    synchronized Favicons getFavicons() {
+        if (mFavicons == null)
+            mFavicons = new Favicons(this);
+
+        return mFavicons;
+    }
+
     Class<?> getPluginClass(String packageName, String className)
             throws NameNotFoundException, ClassNotFoundException {
         Context pluginContext = mAppContext.createPackageContext(packageName,
                 Context.CONTEXT_INCLUDE_CODE |
                 Context.CONTEXT_IGNORE_SECURITY);
         ClassLoader pluginCL = pluginContext.getClassLoader();
         return pluginCL.loadClass(className);
     }
@@ -762,17 +769,17 @@ abstract public class GeckoApp
                 byte[] thumbnail = BrowserDB.getThumbnailForUrl(getContentResolver(), tab.getURL());
                 if (thumbnail != null)
                     processThumbnail(tab, null, thumbnail);
                 return;
             }
 
             int dw = tab.getThumbnailWidth();
             int dh = tab.getThumbnailHeight();
-            GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), 0, 0, 0, 0, 0, 0, dw, dh, dw, dh, GeckoAppShell.SCREENSHOT_THUMBNAIL, tab.getThumbnailBuffer()));
+            GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), 0, 0, 0, 0, 0, 0, dw, dh, dw, dh, ScreenshotHandler.SCREENSHOT_THUMBNAIL, tab.getThumbnailBuffer()));
         }
     }
 
     void handleThumbnailData(Tab tab, ByteBuffer data) {
         if (shouldUpdateThumbnail(tab)) {
             Bitmap b = tab.getThumbnailBitmap();
             b.copyPixelsFromBuffer(data);
             processThumbnail(tab, b, null);
@@ -874,17 +881,17 @@