Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Fri, 13 Jul 2012 19:50:02 -0700
changeset 112845 c4c50dc6317c4ba6f8ca4e89458536d61a83f41c
parent 112844 a29f6c63551663cc3aa24b1bb56d9d058fa0ea4e (current diff)
parent 103966 be26e809e6b1cd1cee82a687bf57f9f45d286f07 (diff)
child 112846 54a63d0ec0f3228f355f79b00fa2d502c8cafd35
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/src/generic/ARIAGridAccessible.h
accessible/src/html/HTMLTableAccessible.h
accessible/src/xul/XULTreeGridAccessible.h
browser/base/content/browser.js
build/mobile/devicemanagerADB.py
build/mobile/devicemanagerSUT.py
configure.in
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/events/src/nsEventListenerManager.cpp
content/xbl/src/nsXBLPrototypeBinding.cpp
dom/base/ConsoleAPI.js
dom/ipc/CrashReporterParent.cpp
dom/ipc/CrashReporterParent.h
dom/plugins/base/PluginPRLibrary.h
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
dom/plugins/base/nsPluginNativeWindowGtk2.cpp
dom/plugins/base/nsPluginTags.cpp
dom/plugins/base/nsPluginTags.h
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginInstanceChild.h
dom/plugins/ipc/PluginLibrary.h
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
dom/tests/mochitest/general/test_consoleAPI.html
dom/wifi/WifiWorker.js
editor/libeditor/base/nsSelectionState.cpp
editor/libeditor/base/nsSelectionState.h
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/nsHTMLEditRules.h
editor/libeditor/text/nsTextEditRules.cpp
extensions/cookie/nsPermissionManager.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicBuffers.cpp
gfx/layers/basic/BasicBuffers.h
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicColorLayer.cpp
gfx/layers/basic/BasicContainerLayer.cpp
gfx/layers/basic/BasicImageLayer.cpp
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/basic/BasicLayersImpl.cpp
gfx/layers/basic/BasicLayersImpl.h
gfx/layers/basic/BasicThebesLayer.cpp
gfx/layers/basic/BasicThebesLayer.h
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
gfx/layers/ipc/ShadowLayerUtilsX11.cpp
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/ipc/ShadowLayersParent.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
gfx/thebes/gfxASurface.h
gfx/thebes/gfxPattern.h
ipc/glue/GeckoChildProcessHost.cpp
js/src/Makefile.in
js/src/builtin/Eval.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/gc/Barrier.h
js/src/gc/Root.h
js/src/ion/CodeGenerator.cpp
js/src/ion/CompilerRoot.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonCaches.cpp
js/src/ion/MIR.h
js/src/ion/TypeOracle.cpp
js/src/ion/TypeOracle.h
js/src/ion/arm/CodeGenerator-arm.cpp
js/src/ion/x64/CodeGenerator-x64.cpp
js/src/ion/x86/CodeGenerator-x86.cpp
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdbgapi.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsproxy.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/tests/js1_8_1/regress/regress-452498-108.js
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
layout/base/nsPresShell.cpp
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsSelection.cpp
layout/reftests/svg/reftest.list
layout/tables/BasicTableLayoutStrategy.cpp
layout/xul/base/src/nsSliderFrame.cpp
layout/xul/base/src/nsSliderFrame.h
mobile/android/base/GeckoApp.java
mobile/android/base/Makefile.in
mobile/android/base/resources/drawable-hdpi/abouthome_separator.9.png
mobile/android/base/resources/drawable-hdpi/tabs_normal.png
mobile/android/base/resources/drawable-hdpi/tabs_pressed.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable-large-hdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-large-hdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-large-hdpi/tabs_normal.png
mobile/android/base/resources/drawable-large-hdpi/tabs_pressed.png
mobile/android/base/resources/drawable-large-mdpi/tabs_button.xml
mobile/android/base/resources/drawable-large-mdpi/tabs_button_expanded.xml
mobile/android/base/resources/drawable-large-mdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-large-mdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-large-mdpi/tabs_normal.png
mobile/android/base/resources/drawable-large-mdpi/tabs_pressed.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_normal.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_pressed.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_icon.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_logo.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_separator.9.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_sync_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_sync_logo.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_sync_pressed_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_thumbnail.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_bg_curve.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_texture_port.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xhdpi-v11/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xhdpi-v11/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xhdpi-v11/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_arrow.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_popup_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_shadow_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/favicon.png
mobile/android/base/resources/drawable-xhdpi-v11/find_close.png
mobile/android/base/resources/drawable-xhdpi-v11/find_next.png
mobile/android/base/resources/drawable-xhdpi-v11/find_prev.png
mobile/android/base/resources/drawable-xhdpi-v11/folder.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_addons_empty.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_star.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_foward.png
mobile/android/base/resources/drawable-xhdpi-v11/larry_blue.png
mobile/android/base/resources/drawable-xhdpi-v11/larry_green.png
mobile/android/base/resources/drawable-xhdpi-v11/reader.png
mobile/android/base/resources/drawable-xhdpi-v11/reading_list.png
mobile/android/base/resources/drawable-xhdpi-v11/remote_tabs_off.png
mobile/android/base/resources/drawable-xhdpi-v11/remote_tabs_on.png
mobile/android/base/resources/drawable-xhdpi-v11/site_security_identified.png
mobile/android/base/resources/drawable-xhdpi-v11/site_security_verified.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_close.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_new.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_thumbnail_default.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_thumbnail_shadow.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_carat.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_normal.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_pressed.png
mobile/android/base/resources/drawable-xhdpi-v11/urlbar_stop.png
mobile/android/base/resources/drawable-xhdpi-v11/validation_arrow.png
mobile/android/base/resources/drawable-xhdpi-v11/validation_arrow_inverted.png
mobile/android/base/resources/drawable-xhdpi-v11/validation_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v14/menu.png
mobile/android/base/resources/drawable-xhdpi-v14/menu_normal.png
mobile/android/base/resources/drawable-xhdpi-v14/menu_pressed.png
mobile/android/base/resources/drawable-xhdpi-v14/tab_new_normal.png
mobile/android/base/resources/drawable-xhdpi-v14/tab_new_pressed.png
mobile/android/base/resources/drawable-xhdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-xhdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable/abouthome_separator.9.png
mobile/android/base/resources/drawable/tabs_button.xml
mobile/android/base/resources/drawable/tabs_button_contracted.xml
mobile/android/base/resources/drawable/tabs_button_tail.xml
mobile/android/base/resources/drawable/tabs_expanded_pressed.png
mobile/android/base/resources/drawable/tabs_normal.png
mobile/android/base/resources/drawable/tabs_pressed.png
mobile/android/base/resources/layout-v14/browser_toolbar.xml
mobile/android/base/resources/layout-v14/tabs_panel_toolbar.xml
netwerk/protocol/websocket/WebSocketChannel.cpp
rdf/base/src/nsCompositeDataSource.cpp
rdf/base/src/nsInMemoryDataSource.cpp
security/manager/ssl/src/NSSErrorsService.cpp
security/manager/ssl/src/SSLServerCertVerification.cpp
security/manager/ssl/src/TransportSecurityInfo.cpp
security/manager/ssl/src/nsCertTree.cpp
security/manager/ssl/src/nsNSSCertificate.cpp
security/manager/ssl/src/nsUsageArrayHelper.cpp
testing/marionette/client/marionette/www/test.xul
testing/marionette/client/marionette/www/test2.xul
testing/marionette/client/marionette/www/test_nested_iframe.xul
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
toolkit/content/widgets/videocontrols.xml
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/xre/nsEmbedFunctions.cpp
widget/LookAndFeel.h
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/nsAppShell.cpp
widget/android/nsLookAndFeel.cpp
widget/android/nsLookAndFeel.h
widget/android/nsWindow.cpp
widget/gtk2/nsWindow.cpp
widget/xpwidgets/nsXPLookAndFeel.cpp
widget/xpwidgets/nsXPLookAndFeel.h
xpcom/build/nsXULAppAPI.h
xpcom/glue/nsTArray.h
--- a/accessible/src/generic/ARIAGridAccessible.h
+++ b/accessible/src/generic/ARIAGridAccessible.h
@@ -25,17 +25,17 @@ class ARIAGridAccessible : public Access
 {
 public:
   ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // Accessible
   virtual TableAccessible* AsTable() { return this; }
 
   // nsAccessNode
   virtual void Shutdown();
 
   // TableAccessible
--- a/accessible/src/html/HTMLTableAccessible.h
+++ b/accessible/src/html/HTMLTableAccessible.h
@@ -90,17 +90,17 @@ class HTMLTableAccessible : public Acces
                             public TableAccessible
 {
 public:
   HTMLTableAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessible Table
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // TableAccessible
   virtual Accessible* Caption();
   virtual void Summary(nsString& aSummary);
   virtual PRUint32 ColCount();
   virtual PRUint32 RowCount();
   virtual Accessible* CellAt(PRUint32 aRowIndex, PRUint32 aColumnIndex);
   virtual PRInt32 CellIndexAt(PRUint32 aRowIdx, PRUint32 aColIdx);
--- a/accessible/src/xpcom/xpcAccessibleTable.h
+++ b/accessible/src/xpcom/xpcAccessibleTable.h
@@ -60,70 +60,9 @@ public:
   nsresult UnselectColumn(PRInt32 aColIdx);
   nsresult UnselectRow(PRInt32 aRowIdx);
   nsresult IsProbablyForLayout(bool* aIsForLayout);
 
 protected:
   mozilla::a11y::TableAccessible* mTable;
 };
 
-#define NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE \
-  NS_IMETHOD GetCaption(nsIAccessible** aCaption) \
-    { return xpcAccessibleTable::GetCaption(aCaption); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSummary(nsAString & aSummary) \
-    { return xpcAccessibleTable::GetSummary(aSummary); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnCount(PRInt32* aColumnCount) \
-    { return xpcAccessibleTable::GetColumnCount(aColumnCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowCount(PRInt32* aRowCount) \
-    { return xpcAccessibleTable::GetRowCount(aRowCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetCellAt(PRInt32 rowIndex, PRInt32 columnIndex, nsIAccessible** _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetCellAt(rowIndex, columnIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetCellIndexAt(PRInt32 rowIndex, PRInt32 columnIndex, PRInt32 *_retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetCellIndexAt(rowIndex, columnIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnIndexAt(PRInt32 cellIndex, PRInt32 *_retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetColumnIndexAt(cellIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowIndexAt(PRInt32 cellIndex, PRInt32 *_retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowIndexAt(cellIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowAndColumnIndicesAt(PRInt32 cellIndex, PRInt32 *rowIndex NS_OUTPARAM, PRInt32 *columnIndex NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowAndColumnIndicesAt(cellIndex, rowIndex, columnIndex); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnExtentAt(PRInt32 row, PRInt32 column, PRInt32* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetColumnExtentAt(row, column, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowExtentAt(PRInt32 row, PRInt32 column, PRInt32* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowExtentAt(row, column, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnDescription(PRInt32 columnIndex, nsAString& _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetColumnDescription(columnIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowDescription(PRInt32 rowIndex, nsAString& _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowDescription(rowIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD IsColumnSelected(PRInt32 colIdx, bool* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::IsColumnSelected(colIdx, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD IsRowSelected(PRInt32 rowIdx, bool* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::IsRowSelected(rowIdx, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD IsCellSelected(PRInt32 rowIdx, PRInt32 colIdx, bool* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::IsCellSelected(rowIdx, colIdx, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedCellCount(PRUint32* aSelectedCellCount) \
-    { return xpcAccessibleTable::GetSelectedCellCount(aSelectedCellCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedColumnCount(PRUint32* aSelectedColumnCount) \
-    { return xpcAccessibleTable::GetSelectedColumnCount(aSelectedColumnCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedRowCount(PRUint32* aSelectedRowCount) \
-    { return xpcAccessibleTable::GetSelectedRowCount(aSelectedRowCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedCells(nsIArray** aSelectedCells) \
-    { return xpcAccessibleTable::GetSelectedCells(aSelectedCells); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedCellIndices(PRUint32* cellsArraySize NS_OUTPARAM, \
-                                                  PRInt32** cellsArray NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetSelectedCellIndices(cellsArraySize, cellsArray); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedColumnIndices(PRUint32* colsArraySize NS_OUTPARAM, \
-                                                    PRInt32** colsArray NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetSelectedColumnIndices(colsArraySize, colsArray); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedRowIndices(PRUint32* rowsArraySize NS_OUTPARAM, \
-                                                 PRInt32** rowsArray NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetSelectedRowIndices(rowsArraySize, rowsArray); } \
-  NS_SCRIPTABLE NS_IMETHOD SelectRow(PRInt32 aRowIdx) \
-    { return xpcAccessibleTable::SelectRow(aRowIdx); } \
-  NS_SCRIPTABLE NS_IMETHOD SelectColumn(PRInt32 aColIdx) \
-    { return xpcAccessibleTable::SelectColumn(aColIdx); } \
-  NS_SCRIPTABLE NS_IMETHOD UnselectColumn(PRInt32 aColIdx) \
-    { return xpcAccessibleTable::UnselectColumn(aColIdx); } \
-  NS_IMETHOD UnselectRow(PRInt32 aRowIdx) \
-    { return xpcAccessibleTable::UnselectRow(aRowIdx); } \
-  NS_IMETHOD IsProbablyForLayout(bool* aResult) \
-  { return xpcAccessibleTable::IsProbablyForLayout(aResult); } \
-
 #endif // MOZILLA_A11Y_XPCOM_XPACCESSIBLETABLE_H_
--- a/accessible/src/xul/XULListboxAccessible.h
+++ b/accessible/src/xul/XULListboxAccessible.h
@@ -65,17 +65,17 @@ class XULListboxAccessible : public XULS
 {
 public:
   XULListboxAccessible(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~XULListboxAccessible() {}
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // TableAccessible
   virtual PRUint32 ColCount();
   virtual PRUint32 RowCount();
   virtual Accessible* CellAt(PRUint32 aRowIndex, PRUint32 aColumnIndex);
   virtual bool IsColSelected(PRUint32 aColIdx);
   virtual bool IsRowSelected(PRUint32 aRowIdx);
   virtual bool IsCellSelected(PRUint32 aRowIdx, PRUint32 aColIdx);
--- a/accessible/src/xul/XULTreeGridAccessible.h
+++ b/accessible/src/xul/XULTreeGridAccessible.h
@@ -23,17 +23,17 @@ class XULTreeGridAccessible : public XUL
 {
 public:
   XULTreeGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // TableAccessible
   virtual PRUint32 ColCount();
   virtual PRUint32 RowCount();
   virtual Accessible* CellAt(PRUint32 aRowIndex, PRUint32 aColumnIndex);
   virtual void ColDescription(PRUint32 aColIdx, nsString& aDescription);
   virtual bool IsColSelected(PRUint32 aColIdx);
   virtual bool IsRowSelected(PRUint32 aRowIdx);
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -48,17 +48,18 @@ let FormAssistant = {
           return;
 
         let ignore = {
           button: true,
           file: true,
           checkbox: true,
           radio: true,
           reset: true,
-          submit: true
+          submit: true,
+          image: true
         };
     
         if (evt.target instanceof HTMLSelectElement) { 
           content.setTimeout(function showIMEForSelect() {
             sendAsyncMessage("Forms:Input", getJSON(evt.target));
           });
         } else if (evt.target instanceof HTMLOptionElement &&
                    evt.target.parentNode instanceof HTMLSelectElement) {
@@ -151,16 +152,20 @@ let FormAssistant = {
         Services.obs.removeObserver(this, "ime-enabled-state-changed", false);
         Services.obs.removeObserver(this, "xpcom-shutdown");
         removeMessageListener("Forms:Select:Choice", this);
         break;
     }
   },
 
   tryShowIme: function(element) {
+    if (!element) {
+      return;
+    }
+
     // FIXME/bug 729623: work around apparent bug in the IME manager
     // in gecko.
     let readonly = element.getAttribute("readonly");
     if (readonly) {
       return false;
     }
 
     sendAsyncMessage("Forms:Input", getJSON(element));
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -38,16 +38,20 @@ XPCOMUtils.defineLazyServiceGetter(Servi
                                    '@mozilla.org/focus-manager;1',
                                    'nsIFocusManager');
 
 XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
   Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
   return DebuggerServer;
 });
 
+function getContentWindow() {
+  return shell.contentBrowser.contentWindow;
+}
+
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // 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',
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -29,38 +29,43 @@ ContentPermissionPrompt.prototype = {
 
   _id: 0,
   prompt: function(request) {
     // returns true if the request was handled
     if (this.handleExistingPermission(request))
        return;
 
     let browser = Services.wm.getMostRecentWindow("navigator:browser");
-    let content = browser.content;
+    let content = browser.getContentWindow();
     if (!content)
       return;
 
     let requestId = this._id++;
     content.addEventListener("mozContentEvent", function contentEvent(evt) {
       if (evt.detail.id != requestId)
         return;
+      evt.target.removeEventListener(evt.type, contentEvent);
 
-      content.removeEventListener(evt.type, contentEvent);
       if (evt.detail.type == "permission-allow") {
         request.allow();
         return;
       }
 
       request.cancel();
     });
 
-    browser.shell.sendEvent(browser.content, "mozChromeEvent", {
-      "type": "permission-prompt", "permission": request.type,
-      "id": requestId, "url": request.uri.spec
-    });
+    let details = {
+      "type": "permission-prompt",
+      "permission": request.type,
+      "id": requestId,
+      "url": request.uri.spec
+    };
+    let event = content.document.createEvent("CustomEvent");
+    event.initCustomEvent("mozChromeEvent", true, true, details);
+    content.dispatchEvent(event);
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
 };
 
 
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -135,30 +135,37 @@ var gPluginHandler = {
       case "PluginBlocklisted":
       case "PluginOutdated":
 #ifdef XP_MACOSX
       case "npapi-carbon-event-model-failure":
 #endif
         self.pluginUnavailable(plugin, event.type);
         break;
 
+      case "PluginVulnerableUpdatable":
+        let updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
+        self.addLinkClickCallback(updateLink, "openPluginUpdatePage");
+        /* FALLTHRU */
+
+      case "PluginVulnerableNoUpdate":
       case "PluginClickToPlay":
         self._handleClickToPlayEvent(plugin);
         break;
 
       case "PluginDisabled":
         let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
         self.addLinkClickCallback(manageLink, "managePlugins");
         break;
     }
 
     // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
-    if (event.type != "PluginCrashed" && event.type != "PluginClickToPlay") {
+    if (event.type != "PluginCrashed") {
       let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
-      if (self.isTooSmall(plugin, overlay))
+      /* overlay might be null, so only operate on it if it exists */
+      if (overlay != null && self.isTooSmall(plugin, overlay))
           overlay.style.visibility = "hidden";
     }
   },
 
   activatePlugins: function PH_activatePlugins(aContentWindow) {
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     browser._clickToPlayPluginsActivated = true;
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -219,16 +226,22 @@ var gPluginHandler = {
                "PFSWindow", "chrome,centerscreen,resizable=yes",
                {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
   },
 
   // Callback for user clicking on a disabled plugin
   managePlugins: function (aEvent) {
     BrowserOpenAddonsMgr("addons://list/plugin");
   },
+ 
+  // Callback for user clicking on the link in a click-to-play plugin
+  // (where the plugin has an update)
+  openPluginUpdatePage: function (aEvent) {
+    openURL(Services.urlFormatter.formatURLPref("plugins.update.url"));
+  },
 
 #ifdef MOZ_CRASHREPORTER
   // Callback for user clicking "submit a report" link
   submitReport : function(pluginDumpID, browserDumpID) {
     // The crash reporter wants a DOM element it can append an IFRAME to,
     // which it uses to submit a form. Let's just give it gBrowser.
     this.CrashSubmit.submit(pluginDumpID);
     if (browserDumpID)
@@ -253,25 +266,28 @@ var gPluginHandler = {
     let pluginsPermission = Services.perms.testPermission(browser.currentURI, "plugins");
     let overlay = doc.getAnonymousElementByAttribute(aPlugin, "class", "mainBox");
 
     if (browser._clickToPlayPluginsActivated) {
       let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
       objLoadingContent.playPlugin();
       return;
     } else if (pluginsPermission == Ci.nsIPermissionManager.DENY_ACTION) {
-      overlay.style.visibility = "hidden";
+      if (overlay)
+        overlay.style.visibility = "hidden";
       return;
     }
 
-    let overlay = doc.getAnonymousElementByAttribute(aPlugin, "class", "mainBox");
     // The overlay is null if the XBL binding is not attached (element is display:none).
     if (overlay) {
       overlay.addEventListener("click", function(aEvent) {
-        if (aEvent.button == 0 && aEvent.isTrusted)
+        // Have to check that the target is a XULElement and not the link
+        // to update the plugin
+        if (aEvent.target instanceof XULElement && 
+            aEvent.button == 0 && aEvent.isTrusted)
           gPluginHandler.activateSinglePlugin(aEvent.target.ownerDocument.defaultView.top, aPlugin);
       }, true);
     }
 
     if (!browser._clickToPlayDoorhangerShown)
       gPluginHandler._showClickToPlayNotification(browser);
   },
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -996,16 +996,18 @@ var gBrowserInit = {
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
 
     gBrowser.addEventListener("PluginNotFound",     gPluginHandler, true);
     gBrowser.addEventListener("PluginCrashed",      gPluginHandler, true);
     gBrowser.addEventListener("PluginBlocklisted",  gPluginHandler, true);
     gBrowser.addEventListener("PluginOutdated",     gPluginHandler, true);
     gBrowser.addEventListener("PluginDisabled",     gPluginHandler, true);
     gBrowser.addEventListener("PluginClickToPlay",  gPluginHandler, true);
+    gBrowser.addEventListener("PluginVulnerableUpdatable", gPluginHandler, true);
+    gBrowser.addEventListener("PluginVulnerableNoUpdate", gPluginHandler, true);
     gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
 #ifdef XP_MACOSX
     gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true);
 #endif
 
     Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false);
 
     window.addEventListener("AppCommand", HandleAppCommandEvent, true);
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -512,10 +512,108 @@ function test16d() {
 // Tests that mContentType is used for click-to-play plugins, and not the
 // inspected type.
 function test17() {
   var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(clickToPlayNotification, "Test 17, Should have a click-to-play notification");
   var missingNotification = PopupNotifications.getNotification("missing-plugins", gTestBrowser);
   ok(!missingNotification, "Test 17, Should not have a missing plugin notification");
 
+  registerFakeBlocklistService(Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE);
+  prepareTest(test18a, gTestRoot + "plugin_test.html");
+}
+
+const Cr = Components.results;
+const Cm = Components.manager;
+const Cc = Components.classes;
+const gReg = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+const gRealBlocklistServiceCID = Cc["@mozilla.org/extensions/blocklist;1"];
+const gFakeBlocklistServiceCID = Components.ID("{614b68a0-3c53-4ec0-8146-28cc1e25f8a1}");
+var gFactory = null;
+
+function registerFakeBlocklistService(blockState) {
+
+  var BlocklistService = {
+    getPluginBlocklistState: function(plugin, appVersion, toolkitVersion) {
+      return blockState;
+    },
+
+    classID: gFakeBlocklistServiceCID,
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIBlocklistService])
+  };
+
+  gFactory = {
+    createInstance: function(outer, iid) {
+      if (outer != null)
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      return BlocklistService.QueryInterface(iid);
+    }
+  };
+
+  gReg.registerFactory(gFakeBlocklistServiceCID,
+                       "Fake Blocklist Service",
+                       "@mozilla.org/extensions/blocklist;1",
+                       gFactory);
+}
+
+function unregisterFakeBlocklistService() {
+  if (gFactory != null ) {
+    gReg.unregisterFactory(gFakeBlocklistServiceCID, gFactory);
+    gFactory = null;
+    // This should restore the original blocklist service:
+    gReg.registerFactory(gRealBlocklistServiceCID,
+                         "Blocklist Service",
+                         "@mozilla.org/extensions/blocklist;1",
+                         null);
+  }
+}
+
+// Tests a vulnerable, updatable plugin
+function test18a() {
+  var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(clickToPlayNotification, "Test 18a, Should have a click-to-play notification");
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 18a, Plugin should not be activated");
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+  ok(overlay.style.visibility != "hidden", "Test 18a, Plugin overlay should exist, not be hidden");
+  var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
+  ok(updateLink.style.visibility != "hidden", "Test 18a, Plugin should have an update link");
+
+  var tabOpenListener = new TabOpenListener(Services.urlFormatter.formatURLPref("plugins.update.url"), false, false);
+  tabOpenListener.handleEvent = function(event) {
+    if (event.type == "TabOpen") {
+      gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
+      this.tab = event.originalTarget;
+      ok(event.target.label == this.url, "Test 18a, Update link should open up the plugin check page");
+      gBrowser.removeTab(this.tab);
+      test18b();
+    }
+  };
+  EventUtils.synthesizeMouse(updateLink, 5, 5, {}, gTestBrowser.contentWindow);
+}
+
+function test18b() {
+  unregisterFakeBlocklistService();
+  registerFakeBlocklistService(Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE);
+  prepareTest(test18c, gTestRoot + "plugin_test.html");
+}
+
+// Tests a vulnerable plugin with no update
+function test18c() {
+  var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(clickToPlayNotification, "Test 18c, Should have a click-to-play notification");
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 18c, Plugin should not be activated");
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+  ok(overlay.style.visibility != "hidden", "Test 18c, Plugin overlay should exist, not be hidden");
+  var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
+  ok(updateLink.style.display != "block", "Test 18c, Plugin should not have an update link");
+
+  unregisterFakeBlocklistService();
+  var plugin = get_test_plugin();
+  plugin.clicktoplay = false;
+
   finishTest();
 }
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -52,16 +52,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_clean-exit.js \
 	browser_dbg_bug723069_editor-breakpoints.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_displayName.js \
 	browser_dbg_iframes.js \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_multiple-windows.js \
 	browser_dbg_menustatus.js \
+	browser_dbg_bfcache.js \
 	head.js \
 	$(NULL)
 
 MOCHITEST_BROWSER_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_bfcache.js
@@ -0,0 +1,118 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the debugger is updated with the correct scripts when moving
+ * back and forward in the tab.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+var gScripts = null;
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+
+    testInitialLoad();
+  });
+}
+
+function testInitialLoad() {
+  gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+    executeSoon(function() {
+      validateFirstPage();
+      testLocationChange();
+    });
+  });
+
+  gDebuggee.firstCall();
+}
+
+function testLocationChange()
+{
+  gDebugger.DebuggerController.activeThread.resume(function() {
+    gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+      ok(true, "Successfully reattached to the tab again.");
+      gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
+        executeSoon(function() {
+          validateSecondPage();
+          testBack();
+        });
+      });
+    });
+    content.location = STACK_URL;
+  });
+}
+
+function testBack()
+{
+  gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+    ok(true, "Successfully reattached to the tab after going back.");
+    gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
+      executeSoon(function() {
+        validateFirstPage();
+        testForward();
+      });
+    });
+  });
+
+  info("Going back.");
+  content.history.back();
+}
+
+function testForward()
+{
+  gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+    ok(true, "Successfully reattached to the tab after going forward.");
+    gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
+      executeSoon(function() {
+        validateSecondPage();
+        closeDebuggerAndFinish();
+      });
+    });
+  });
+
+  info("Going forward.");
+  content.history.forward();
+}
+
+function validateFirstPage() {
+  gScripts = gDebugger.DebuggerView.Scripts._scripts;
+
+  is(gScripts.itemCount, 2, "Found the expected number of scripts.");
+
+  let label1 = "test-script-switching-01.js";
+  let label2 = "test-script-switching-02.js";
+
+  ok(gDebugger.DebuggerView.Scripts.containsLabel(label1),
+     "Found the first script label.");
+  ok(gDebugger.DebuggerView.Scripts.containsLabel(label2),
+     "Found the second script label.");
+}
+
+function validateSecondPage() {
+  gScripts = gDebugger.DebuggerView.Scripts._scripts;
+
+  is(gScripts.itemCount, 1, "Found the expected number of scripts.");
+
+  ok(gDebugger.DebuggerView.Scripts.containsLabel("browser_dbg_stack.html"),
+     "Found the single script label.");
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+  gScripts = null;
+});
--- a/build/mobile/devicemanager.py
+++ b/build/mobile/devicemanager.py
@@ -504,17 +504,38 @@ class DeviceManager:
   @abstractmethod
   def chmodDir(self, remoteDir):
     """
     external function
     returns:
     success: True
     failure: False
     """
-    
+
+  @staticmethod
+  def _escapedCommandLine(cmd):
+    """ Utility function to return escaped and quoted version of command line """
+    quotedCmd = []
+
+    for arg in cmd:
+      arg.replace('&', '\&')
+
+      needsQuoting = False
+      for char in [ ' ', '(', ')', '"', '&' ]:
+        if arg.find(char) >= 0:
+          needsQuoting = True
+          break
+      if needsQuoting:
+        arg = '\'%s\'' % arg
+
+      quotedCmd.append(arg)
+
+    return " ".join(quotedCmd)
+
+
 class NetworkTools:
   def __init__(self):
     pass
 
   # Utilities to get the local ip address
   def getInterfaceIp(self, ifname):
     if os.name != "nt":
       import fcntl
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -90,34 +90,23 @@ class DeviceManagerADB(DeviceManager):
     if self.host:
       self.disconnectRemoteADB()
 
   # external function: executes shell command on device
   # returns:
   # success: <return code>
   # failure: None
   def shell(self, cmd, outputfile, env=None, cwd=None):
-    # need to quote and escape special characters here
-    for (index, arg) in enumerate(cmd):
-      arg.replace('&', '\&')
-
-      needsQuoting = False
-      for char in [ ' ', '(', ')', '"', '&' ]:
-        if arg.find(char):
-          needsQuoting = True
-          break
-      if needsQuoting:
-        cmd[index] = '\'%s\'' % arg
-
-    # This is more complex than you'd think because adb doesn't actually
-    # return the return code from a process, so we have to capture the output
-    # to get it
     # FIXME: this function buffers all output of the command into memory,
     # always. :(
-    cmdline = " ".join(cmd) + "; echo $?"
+
+    # Getting the return code is more complex than you'd think because adb
+    # doesn't actually return the return code from a process, so we have to
+    # capture the output to get it
+    cmdline = "%s; echo $?" % self._escapedCommandLine(cmd)
 
     # prepend cwd and env to command if necessary
     if cwd:
       cmdline = "cd %s; %s" % (cwd, cmdline)
     if env:
       envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
       cmdline = envstr + "; " + cmdline
 
--- a/build/mobile/devicemanagerSUT.py
+++ b/build/mobile/devicemanagerSUT.py
@@ -255,17 +255,17 @@ class DeviceManagerSUT(DeviceManager):
         self._sock = None
         raise AgentError("Error closing socket")
 
   # external function: executes shell command on device
   # returns:
   # success: <return code>
   # failure: None
   def shell(self, cmd, outputfile, env=None, cwd=None):
-    cmdline = subprocess.list2cmdline(cmd)
+    cmdline = self._escapedCommandLine(cmd)
     if env:
       cmdline = '%s %s' % (self.formatEnvString(env), cmdline)
 
     try:
       if cwd:
         self.sendCmds([{ 'cmd': 'execcwd %s %s' % (cwd, cmdline) }], outputfile)
       else:
         self.sendCmds([{ 'cmd': 'exec su -c "%s"' % cmdline }], outputfile)
--- a/client.mk
+++ b/client.mk
@@ -186,17 +186,17 @@ everything: clean build
 ifdef MOZ_OBJDIR
   PGO_OBJDIR = $(MOZ_OBJDIR)
 else
   PGO_OBJDIR := $(TOPSRCDIR)
 endif
 
 profiledbuild::
 	$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_GENERATE=1 MOZ_PGO_INSTRUMENTED=1
-	$(MAKE) -C $(PGO_OBJDIR) stage-package MOZ_PGO_INSTRUMENTED=1
+	$(MAKE) -C $(PGO_OBJDIR) package MOZ_PGO_INSTRUMENTED=1 MOZ_INTERNAL_SIGNING_FORMAT= MOZ_EXTERNAL_SIGNING_FORMAT=
 	MOZ_PGO_INSTRUMENTED=1 OBJDIR=${PGO_OBJDIR} JARLOG_DIR=${PGO_OBJDIR}/jarlog/en-US $(PROFILE_GEN_SCRIPT)
 	$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild
 	$(MAKE) -f $(TOPSRCDIR)/client.mk realbuild MOZ_PROFILE_USE=1
 
 #####################################################
 # Build date unification
 
 ifdef MOZ_UNIFY_BDATE
--- a/configure.in
+++ b/configure.in
@@ -4034,17 +4034,17 @@ fi
 fi # SKIP_LIBRARY_CHECKS
 
 dnl system ZLIB support
 dnl ========================================================
 MOZ_ZLIB_CHECK([1.2.3])
 
 if test "$MOZ_NATIVE_ZLIB" != 1; then
     MOZ_ZLIB_CFLAGS=
-    MOZ_ZLIB_LIBS='$(call EXPAND_LIBNAME_PATH,mozz,'"$_objdir"'/modules/zlib/src)'
+    MOZ_ZLIB_LIBS='$(call EXPAND_LIBNAME_PATH,mozz,'"$MOZ_BUILD_ROOT"'/modules/zlib/src)'
 fi
 
 if test "$MOZ_LINKER" = 1 -a "$MOZ_NATIVE_ZLIB" != 1; then
     AC_MSG_ERROR([Custom dynamic linker requires --with-system-zlib])
 fi
 
 if test -z "$SKIP_LIBRARY_CHECKS"; then
 dnl system BZIP2 Support
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -75,30 +75,16 @@ static NS_DEFINE_CID(kAppShellCID, NS_AP
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
 #endif
 
 #define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG)
 
-#include "mozilla/Preferences.h"
-
-static bool gClickToPlayPlugins = false;
-
-static void
-InitPrefCache()
-{
-  static bool initializedPrefCache = false;
-  if (!initializedPrefCache) {
-    mozilla::Preferences::AddBoolVarCache(&gClickToPlayPlugins, "plugins.click_to_play");
-  }
-  initializedPrefCache = true;
-}
-
 class nsAsyncInstantiateEvent : public nsRunnable {
 public:
   nsObjectLoadingContent *mContent;
   nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
   : mContent(aContent)
   {
     static_cast<nsIObjectLoadingContent *>(mContent)->AddRef();
   }
@@ -176,16 +162,22 @@ nsPluginErrorEvent::Run()
 {
   LOG(("OBJLC []: Firing plugin not found event for content %p\n",
        mContent.get()));
   nsString type;
   switch (mState) {
     case ePluginClickToPlay:
       type = NS_LITERAL_STRING("PluginClickToPlay");
       break;
+    case ePluginVulnerableUpdatable:
+      type = NS_LITERAL_STRING("PluginVulnerableUpdatable");
+      break;
+    case ePluginVulnerableNoUpdate:
+      type = NS_LITERAL_STRING("PluginVulnerableNoUpdate");
+      break;
     case ePluginUnsupported:
       type = NS_LITERAL_STRING("PluginNotFound");
       break;
     case ePluginDisabled:
       type = NS_LITERAL_STRING("PluginDisabled");
       break;
     case ePluginBlocklisted:
       type = NS_LITERAL_STRING("PluginBlocklisted");
@@ -479,17 +471,21 @@ nsresult nsObjectLoadingContent::IsPlugi
 
   // Check to see if the plugin is disabled before deciding if it
   // should be in the "click to play" state, since we only want to
   // display "click to play" UI for enabled plugins.
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  if (!mShouldPlay) {
+  if (!pluginHost->IsPluginClickToPlayForType(aMIMEType.get())) {
+    mCTPPlayable = true;
+  }
+
+  if (!mCTPPlayable) {
     nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
     MOZ_ASSERT(thisContent);
     nsIDocument* ownerDoc = thisContent->OwnerDoc();
 
     nsCOMPtr<nsIDOMWindow> window = ownerDoc->GetWindow();
     if (!window) {
       return NS_ERROR_FAILURE;
     }
@@ -500,22 +496,27 @@ nsresult nsObjectLoadingContent::IsPlugi
     rv = topWindow->GetDocument(getter_AddRefs(topDocument));
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIDocument> topDoc = do_QueryInterface(topDocument);
     nsIURI* topUri = topDoc->GetDocumentURI();
 
     nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     PRUint32 permission;
-    rv = permissionManager->TestPermission(topUri,
-                                           "plugins",
-                                           &permission);
+    rv = permissionManager->TestPermission(topUri, "plugins", &permission);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    PRUint32 state;
+    rv = pluginHost->GetBlocklistStateForType(aMIMEType.get(), &state);
     NS_ENSURE_SUCCESS(rv, rv);
-    if (permission == nsIPermissionManager::ALLOW_ACTION) {
-      mShouldPlay = true;
+
+    if (permission == nsIPermissionManager::ALLOW_ACTION &&
+        state != nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE &&
+        state != nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
+      mCTPPlayable = true;
     } else {
       return NS_ERROR_PLUGIN_CLICKTOPLAY;
     }
   }
 
   return NS_OK;
 }
 
@@ -537,39 +538,45 @@ GetExtensionFromURI(nsIURI* uri, nsCStri
 }
 
 /**
  * Checks whether a plugin exists and is enabled for the extension
  * in the given URI. The MIME type is returned in the mimeType out parameter.
  */
 bool nsObjectLoadingContent::IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType)
 {
-  if (!mShouldPlay) {
-    return false;
-  }
-
   nsCAutoString ext;
   GetExtensionFromURI(uri, ext);
+  bool enabled = false;
 
   if (ext.IsEmpty()) {
     return false;
   }
 
   nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
   nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
   if (!pluginHost) {
     return false;
   }
 
   const char* typeFromExt;
   if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt))) {
     mimeType = typeFromExt;
-    return true;
+    enabled = true;
+
+    if (!pluginHost->IsPluginClickToPlayForType(mimeType.get())) {
+      mCTPPlayable = true;
+    }
   }
-  return false;
+
+  if (!mCTPPlayable) {
+    return false;
+  } else {
+    return enabled;
+  }
 }
 
 nsresult
 nsObjectLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* /*aParent*/,
                                    nsIContent* /*aBindingParent*/,
                                    bool /*aCompileEventHandlers*/)
 {
   if (aDocument) {
@@ -593,39 +600,30 @@ nsObjectLoadingContent::nsObjectLoadingC
   , mType(eType_Loading)
   , mInstantiating(false)
   , mUserDisabled(false)
   , mSuppressed(false)
   , mNetworkCreated(true)
   , mIsStopping(false)
   , mSrcStreamLoading(false)
   , mFallbackReason(ePluginOtherState)
-{
-  InitPrefCache();
-  // If plugins.click_to_play is false, plugins should always play
-  mShouldPlay = !gClickToPlayPlugins;
-  // If plugins.click_to_play is true, track the activated state of plugins.
-  mActivated = !gClickToPlayPlugins;
-}
+  , mCTPPlayable(false)
+  , mActivated(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   DestroyImageLoadingContent();
   if (mFrameLoader) {
     mFrameLoader->Destroy();
   }
 }
 
 nsresult
 nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI)
 {
-  if (!mShouldPlay) {
-    return NS_ERROR_PLUGIN_CLICKTOPLAY;
-  }
-
   // Don't do anything if we already have an active instance.
   if (mInstanceOwner) {
     return NS_OK;
   }
 
   // Don't allow re-entry into initialization code.
   if (mInstantiating) {
     return NS_OK;
@@ -660,16 +658,24 @@ nsObjectLoadingContent::InstantiatePlugi
 
   nsresult rv = NS_ERROR_FAILURE;
   nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
   nsPluginHost* pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  if (!pluginHost->IsPluginClickToPlayForType(aMimeType)) {
+    mCTPPlayable = true;
+  }
+
+  if (!mCTPPlayable) {
+    return NS_ERROR_PLUGIN_CLICKTOPLAY;
+  }
+
   // If you add early return(s), be sure to balance this call to
   // appShell->SuspendNative() with additional call(s) to
   // appShell->ReturnNative().
   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
   if (appShell) {
     appShell->SuspendNative();
   }
 
@@ -1186,16 +1192,20 @@ nsObjectLoadingContent::ObjectState() co
       if (mUserDisabled)
         return NS_EVENT_STATE_USERDISABLED;
 
       // Otherwise, broken
       nsEventStates state = NS_EVENT_STATE_BROKEN;
       switch (mFallbackReason) {
         case ePluginClickToPlay:
           return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
+        case ePluginVulnerableUpdatable:
+          return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
+        case ePluginVulnerableNoUpdate:
+          return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
         case ePluginDisabled:
           state |= NS_EVENT_STATE_HANDLER_DISABLED;
           break;
         case ePluginBlocklisted:
           state |= NS_EVENT_STATE_HANDLER_BLOCKED;
           break;
         case ePluginCrashed:
           state |= NS_EVENT_STATE_HANDLER_CRASHED;
@@ -1928,35 +1938,53 @@ nsObjectLoadingContent::GetPluginSupport
       }
     } else if (!hasAlternateContent) {
       hasAlternateContent =
         nsStyleUtil::IsSignificantChild(child, true, false);
     }
   }
 
   PluginSupportState pluginDisabledState = GetPluginDisabledState(aContentType);
-  if (pluginDisabledState == ePluginClickToPlay) {
-    return ePluginClickToPlay;
+  if (pluginDisabledState == ePluginClickToPlay ||
+      pluginDisabledState == ePluginVulnerableUpdatable ||
+      pluginDisabledState == ePluginVulnerableNoUpdate) {
+    return pluginDisabledState;
   } else if (hasAlternateContent) {
     return ePluginOtherState;
   } else {
     return pluginDisabledState;
   }
 }
 
 PluginSupportState
 nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
 {
   nsresult rv = IsPluginEnabledForType(aContentType);
-  if (rv == NS_ERROR_PLUGIN_DISABLED)
+  if (rv == NS_ERROR_PLUGIN_DISABLED) {
     return ePluginDisabled;
-  if (rv == NS_ERROR_PLUGIN_CLICKTOPLAY)
+  }
+  if (rv == NS_ERROR_PLUGIN_CLICKTOPLAY) {
+    PRUint32 state;
+    nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
+    nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
+    if (pluginHost) {
+      rv = pluginHost->GetBlocklistStateForType(aContentType.get(), &state);
+      if (NS_SUCCEEDED(rv)) {
+        if (state == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
+          return ePluginVulnerableUpdatable;
+        } else if (state == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
+          return ePluginVulnerableNoUpdate;
+        }
+      }
+    }
     return ePluginClickToPlay;
-  if (rv == NS_ERROR_PLUGIN_BLOCKLISTED)
+  }
+  if (rv == NS_ERROR_PLUGIN_BLOCKLISTED) {
     return ePluginBlocklisted;
+  }
   return ePluginUnsupported;
 }
 
 void
 nsObjectLoadingContent::CreateStaticClone(nsObjectLoadingContent* aDest) const
 {
   nsImageLoadingContent::CreateStaticImageClone(aDest);
 
@@ -2208,17 +2236,17 @@ nsObjectLoadingContent::NotifyContentObj
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::PlayPlugin()
 {
   if (!nsContentUtils::IsCallerChrome())
     return NS_OK;
 
-  mShouldPlay = true;
+  mCTPPlayable = true;
   return LoadObject(mURI, true, mContentType, true);
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetActivated(bool* aActivated)
 {
   *aActivated = mActivated;
   return NS_OK;
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -33,17 +33,19 @@ class nsObjectFrame;
 
 enum PluginSupportState {
   ePluginUnsupported,  // The plugin is not supported (e.g. not installed)
   ePluginDisabled,     // The plugin has been explicitly disabled by the user
   ePluginBlocklisted,  // The plugin is blocklisted and disabled
   ePluginOutdated,     // The plugin is considered outdated, but not disabled
   ePluginOtherState,   // Something else (e.g. uninitialized or not a plugin)
   ePluginCrashed,
-  ePluginClickToPlay   // The plugin is disabled until the user clicks on it
+  ePluginClickToPlay,  // The plugin is disabled until the user clicks on it
+  ePluginVulnerableUpdatable, // The plugin is vulnerable (update available)
+  ePluginVulnerableNoUpdate   // The plugin is vulnerable (no update available)
 };
 
 /**
  * INVARIANTS OF THIS CLASS
  * - mChannel is non-null between asyncOpen and onStopRequest (NOTE: Only needs
  *   to be valid until onStopRequest is called on mFinalListener, not
  *   necessarily until the channel calls onStopRequest on us)
  * - mChannel corresponds to the channel that gets passed to the
@@ -367,19 +369,21 @@ class nsObjectLoadingContent : public ns
     bool                        mUserDisabled  : 1;
     bool                        mSuppressed    : 1;
 
     // True when the object is created for an element which the parser has
     // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
-    // Used to keep track of whether or not a plugin should be played.
-    // This is used for click-to-play plugins.
-    bool                        mShouldPlay : 1;
+    // Used to keep track of if a plugin is blocked by click-to-play.
+    // True indicates the plugin is not click-to-play or it has been clicked by
+    // the user.
+    // False indicates the plugin is click-to-play and has not yet been clicked.
+    bool                        mCTPPlayable    : 1;
 
     // Used to keep track of whether or not a plugin has been played.
     // This is used for click-to-play plugins.
     bool                        mActivated : 1;
 
     // Protects DoStopPlugin from reentry (bug 724781).
     bool                        mIsStopping : 1;
 
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -237,16 +237,20 @@ private:
 // Handler for click to play plugin
 #define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(36)
 // Content is in the optimum region.
 #define NS_EVENT_STATE_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(37)
 // Content is in the suboptimal region.
 #define NS_EVENT_STATE_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(38)
 // Content is in the sub-suboptimal region.
 #define NS_EVENT_STATE_SUB_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(39)
+// Handler for click to play plugin (vulnerable w/update)
+#define NS_EVENT_STATE_VULNERABLE_UPDATABLE NS_DEFINE_EVENT_STATE_MACRO(40)
+// Handler for click to play plugin (vulnerable w/no update)
+#define NS_EVENT_STATE_VULNERABLE_NO_UPDATE NS_DEFINE_EVENT_STATE_MACRO(41)
 
 /**
  * NOTE: do not go over 63 without updating nsEventStates::InternalType!
  */
 
 #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |     \
                             NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER |   \
                             NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -277,17 +277,19 @@ nsEventListenerManager::AddEventListener
              (aTypeAtom == nsGkAtoms::ontouchstart ||
               aTypeAtom == nsGkAtoms::ontouchend ||
               aTypeAtom == nsGkAtoms::ontouchmove ||
               aTypeAtom == nsGkAtoms::ontouchenter ||
               aTypeAtom == nsGkAtoms::ontouchleave ||
               aTypeAtom == nsGkAtoms::ontouchcancel)) {
     mMayHaveTouchEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
-    if (window)
+    // we don't want touchevent listeners added by scrollbars to flip this flag
+    // so we ignore listeners created with system event flag
+    if (window && !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT))
       window->SetHasTouchEventListeners();
   } else if (aTypeAtom == nsGkAtoms::onmouseenter ||
              aTypeAtom == nsGkAtoms::onmouseleave) {
     mMayHaveMouseEnterLeaveEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     if (window) {
 #ifdef DEBUG
       nsCOMPtr<nsIDocument> d = do_QueryInterface(window->GetExtantDocument());
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -1843,22 +1843,16 @@ nsXBLPrototypeBinding::ReadContentNode(n
   if (namespaceID == kNameSpaceID_XUL) {
     nsIURI* documentURI = aDocument->GetDocumentURI();
 
     nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
     NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY);
 
     prototype->mNodeInfo = nodeInfo;
 
-    nsCOMPtr<Element> result;
-    nsresult rv =
-      nsXULElement::Create(prototype, aDocument, false, getter_AddRefs(result));
-    NS_ENSURE_SUCCESS(rv, rv);
-    content = result;
-
     nsXULPrototypeAttribute* attrs = nsnull;
     if (attrCount > 0) {
       attrs = new nsXULPrototypeAttribute[attrCount];
     }
 
     prototype->mAttributes = attrs;
     prototype->mNumAttributes = attrCount;
 
@@ -1887,16 +1881,22 @@ nsXBLPrototypeBinding::ReadContentNode(n
           aNim->GetNodeInfo(nameAtom, prefixAtom,
                             namespaceID, nsIDOMNode::ATTRIBUTE_NODE);
         attrs[i].mName.SetTo(ni);
       }
       
       rv = prototype->SetAttrAt(i, val, documentURI);
       NS_ENSURE_SUCCESS(rv, rv);
     }
+
+    nsCOMPtr<Element> result;
+    nsresult rv =
+      nsXULElement::Create(prototype, aDocument, false, getter_AddRefs(result));
+    NS_ENSURE_SUCCESS(rv, rv);
+    content = result;
   }
   else {
 #endif
     NS_NewElement(getter_AddRefs(content), nodeInfo.forget(), NOT_FROM_PARSER);
 
     for (PRUint32 i = 0; i < attrCount; i++) {
       rv = ReadNamespace(aStream, namespaceID);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/ConsoleAPI.js
+++ b/dom/base/ConsoleAPI.js
@@ -102,29 +102,53 @@ ConsoleAPI.prototype = {
         self.queueCall("groupEnd", arguments);
       },
       time: function CA_time() {
         self.queueCall("time", arguments);
       },
       timeEnd: function CA_timeEnd() {
         self.queueCall("timeEnd", arguments);
       },
+      profile: function CA_profile() {
+        // Send a notification picked up by the profiler if installed.
+        // This must happen right away otherwise we will miss samples
+        let consoleEvent = {
+          action: "profile",
+          arguments: arguments
+        };
+        consoleEvent.wrappedJSObject = consoleEvent;
+        Services.obs.notifyObservers(consoleEvent, "console-api-profiler",
+                                     null);  
+      },
+      profileEnd: function CA_profileEnd() {
+        // Send a notification picked up by the profiler if installed.
+        // This must happen right away otherwise we will miss samples
+        let consoleEvent = {
+          action: "profileEnd",
+          arguments: arguments
+        };
+        consoleEvent.wrappedJSObject = consoleEvent;
+        Services.obs.notifyObservers(consoleEvent, "console-api-profiler",
+                                     null);  
+      },
       __exposedProps__: {
         log: "r",
         info: "r",
         warn: "r",
         error: "r",
         debug: "r",
         trace: "r",
         dir: "r",
         group: "r",
         groupCollapsed: "r",
         groupEnd: "r",
         time: "r",
-        timeEnd: "r"
+        timeEnd: "r",
+        profile: "r",
+        profileEnd: "r"
       }
     };
 
     // We need to return an actual content object here, instead of a wrapped
     // chrome object. This allows things like console.log.bind() to work.
     let contentObj = Cu.createObjectIn(aWindow);
     function genPropDesc(fun) {
       return { enumerable: true, configurable: true, writable: true,
@@ -138,16 +162,18 @@ ConsoleAPI.prototype = {
       debug: genPropDesc('debug'),
       trace: genPropDesc('trace'),
       dir: genPropDesc('dir'),
       group: genPropDesc('group'),
       groupCollapsed: genPropDesc('groupCollapsed'),
       groupEnd: genPropDesc('groupEnd'),
       time: genPropDesc('time'),
       timeEnd: genPropDesc('timeEnd'),
+      profile: genPropDesc('profile'),
+      profileEnd: genPropDesc('profileEnd'),
       __noSuchMethod__: { enumerable: true, configurable: true, writable: true,
                           value: function() {} },
       __mozillaConsole__: { value: true }
     };
 
     Object.defineProperties(contentObj, properties);
     Cu.makeObjectPropsNormal(contentObj);
 
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -16,18 +16,17 @@
 #define DOM_OBJECT_SLOT 0
 
 // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to
 // start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses
 // that one.
 #define DOM_PROTOTYPE_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 1)
 
 // We use these flag bits for the new bindings.
-#define JSCLASS_IS_DOMJSCLASS JSCLASS_USERBIT1
-#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT2
+#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
 
 namespace mozilla {
 namespace dom {
 
 typedef bool
 (* ResolveProperty)(JSContext* cx, JSObject* wrapper, jsid id, bool set,
                     JSPropertyDescriptor* desc);
 typedef bool
--- a/dom/indexedDB/test/browser_permissionsPrompt.html
+++ b/dom/indexedDB/test/browser_permissionsPrompt.html
@@ -5,19 +5,18 @@
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
       function testSteps()
       {
         const name = window.location.pathname;
-        const description = "My Test Database";
 
-        let request = indexedDB.open(name, 1, description);
+        let request = indexedDB.open(name, 1);
         request.onerror = grabEventAndContinueHandler;
         request.onsuccess = grabEventAndContinueHandler;
         let event = yield;
 
         if (event.type == "success") {
           testResult = event.target.result;
         }
         else {
--- a/dom/indexedDB/test/browser_quotaPrompt.html
+++ b/dom/indexedDB/test/browser_quotaPrompt.html
@@ -46,22 +46,21 @@
             finishTest();
           }
         }
       }
 
       function testSteps()
       {
         const name = window.location.pathname;
-        const description = "My Test Database";
 
         window.addEventListener("indexedDB-addMore", onAddMore, true);
         window.addEventListener("indexedDB-done", onDone, true);
 
-        let request = indexedDB.open(name, version++, description);
+        let request = indexedDB.open(name, version++);
         request.onerror = errorHandler;
         request.onupgradeneeded = grabEventAndContinueHandler;
         let event = yield;
 
         db = event.target.result;
 
         db.onversionchange = function () { db.close(); };
 
--- a/dom/indexedDB/test/test_create_objectStore.html
+++ b/dom/indexedDB/test/test_create_objectStore.html
@@ -8,17 +8,16 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
-      const description = "My Test Database";
       const objectStoreInfo = [
         { name: "1", options: { keyPath: null } },
         { name: "2", options: { keyPath: null, autoIncrement: true } },
         { name: "3", options: { keyPath: null, autoIncrement: false } },
         { name: "4", options: { keyPath: null } },
         { name: "5", options: { keyPath: "foo" } },
         { name: "6" },
         { name: "7", options: null },
@@ -26,17 +25,17 @@
         { name: "9", options: { autoIncrement: false } },
         { name: "10", options: { keyPath: "foo", autoIncrement: false } },
         { name: "11", options: { keyPath: "foo", autoIncrement: true } },
         { name: "" },
         { name: null },
         { name: undefined }
       ];
 
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let count = db.objectStoreNames.length;
       is(count, 0, "correct objectStoreNames length");
--- a/dom/indexedDB/test/test_file_array.html
+++ b/dom/indexedDB/test/test_file_array.html
@@ -8,17 +8,16 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const b1 = getRandomBlob(10000);
 
     const b2 = [ getRandomBlob(5000), getRandomBlob(3000), getRandomBlob(12000),
       getRandomBlob(17000), getRandomBlob(16000), getRandomBlob(16000),
       getRandomBlob(8000)
@@ -30,17 +29,17 @@
       { key: 1, blobs: [ b1, b1, b1, b1, b1, b1, b1, b1, b1, b1 ],
         expectedFileIds: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] },
       { key: 2, blobs: [ b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6] ],
         expectedFileIds: [2, 3, 4, 5, 6, 7, 8] },
       { key: 3, blobs: [ b3[0], b3[0], b3[1], b3[2], b3[2], b3[0], b3[0] ],
         expectedFileIds: [9, 9, 10, 11, 11, 9, 9] }
     ];
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_file_cross_database_copying.html
+++ b/dom/indexedDB/test/test_file_cross_database_copying.html
@@ -10,27 +10,27 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const databaseInfo = [
-      { name: window.location.pathname + "1", description: "Test Database 1" },
-      { name: window.location.pathname + "2", description: "Test Database 2" }
+      { name: window.location.pathname + "1" },
+      { name: window.location.pathname + "2" }
     ];
 
     const objectStoreName = "Blobs";
 
     const fileData = { key: 1, file: getRandomFile("random.bin", 100000) };
 
     let databases = [];
     for each (let info in databaseInfo) {
-      let request = indexedDB.open(info.name, 1, info.description);
+      let request = indexedDB.open(info.name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
--- a/dom/indexedDB/test/test_file_delete.html
+++ b/dom/indexedDB/test/test_file_delete.html
@@ -10,26 +10,25 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const fileData1 = { key: 1, file: getRandomFile("random1.bin", 110000) };
     const fileData2 = { key: 2, file: getRandomFile("random2.bin", 120000) };
     const fileData3 = { key: 3, file: getRandomFile("random3.bin", 130000) };
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
@@ -62,17 +61,17 @@
     scheduleGC();
     yield;
 
     ok(!hasFileInfo(name, 1), "Correct ref count");
     ok(hasFileInfo(name, 2), "Correct ref count");
     ok(hasFileInfo(name, 3), "Correct ref count");
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "success", "Got correct event type");
 
       let db = event.target.result;
       db.onerror = errorHandler;
--- a/dom/indexedDB/test/test_file_os_delete.html
+++ b/dom/indexedDB/test/test_file_os_delete.html
@@ -10,27 +10,26 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     getUsage(grabFileUsageAndContinueHandler);
     let startUsage = yield;
 
     const fileData = { key: 1, file: getRandomFile("random.bin", 100000) };
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
--- a/dom/indexedDB/test/test_file_put_get_object.html
+++ b/dom/indexedDB/test/test_file_put_get_object.html
@@ -10,27 +10,26 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const blob = getRandomBlob(1000);
     const file = getRandomFile("random.bin", 100000);
 
     const objectData1 = { key: 1, object: { foo: blob, bar: blob } };
     const objectData2 = { key: 2, object: { foo: file, bar: file } };
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_file_put_get_values.html
+++ b/dom/indexedDB/test/test_file_put_get_values.html
@@ -10,24 +10,23 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const blobData = { key: 1, blob: getRandomBlob(10000) };
     const fileData = { key: 2, file: getRandomFile("random.bin", 100000) };
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_file_quota.html
+++ b/dom/indexedDB/test/test_file_quota.html
@@ -11,24 +11,23 @@
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
     const DEFAULT_QUOTA_MB = 50;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const testData = { key: 0, value: {} };
     const fileData = { key: 1, file: null };
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_file_replace.html
+++ b/dom/indexedDB/test/test_file_replace.html
@@ -8,27 +8,26 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const blobData = { key: 42, blobs: [] };
 
     for (let i = 0; i < 100; i++) {
       blobData.blobs[i] = getRandomBlob(i);
     }
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_file_resurrection_delete.html
+++ b/dom/indexedDB/test/test_file_resurrection_delete.html
@@ -10,24 +10,23 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const fileData = { key: 1, file: getRandomFile("random.bin", 100000) };
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
@@ -67,17 +66,17 @@
     }
 
     scheduleGC();
     yield;
 
     is(getFileRefCount(name, 1), 0, "Correct ref count");
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "success", "Got correct event type");
 
       let db = event.target.result;
       db.onerror = errorHandler;
--- a/dom/indexedDB/test/test_file_resurrection_transaction_abort.html
+++ b/dom/indexedDB/test/test_file_resurrection_transaction_abort.html
@@ -10,24 +10,23 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const fileData = { key: 1, file: getRandomFile("random.bin", 100000) };
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
--- a/dom/indexedDB/test/test_file_sharing.html
+++ b/dom/indexedDB/test/test_file_sharing.html
@@ -10,26 +10,25 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreInfo = [
       { name: "Blobs", options: { } },
       { name: "Other Blobs", options: { } }
     ];
 
     const fileData = { key: 1, file: getRandomFile("random.bin", 100000) };
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_file_transaction_abort.html
+++ b/dom/indexedDB/test/test_file_transaction_abort.html
@@ -10,24 +10,23 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const fileData = { key: 1, file: getRandomFile("random.bin", 100000) };
 
     {
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
--- a/dom/indexedDB/test/test_filehandle_quota.html
+++ b/dom/indexedDB/test/test_filehandle_quota.html
@@ -11,19 +11,18 @@
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
     const DEFAULT_QUOTA_MB = 50;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_filehandle_serialization.html
+++ b/dom/indexedDB/test/test_filehandle_serialization.html
@@ -10,27 +10,27 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const databaseInfo = [
-      { name: window.location.pathname + "1", description: "Test Database 1" },
-      { name: window.location.pathname + "2", description: "Test Database 2" }
+      { name: window.location.pathname + "1" },
+      { name: window.location.pathname + "2" }
     ];
 
     const objectStoreName = "Blobs";
 
     const testFile = getRandomFile("random.bin", 100000);
 
     let databases = [];
     for each (let info in databaseInfo) {
-      let request = indexedDB.open(info.name, 1, info.description);
+      let request = indexedDB.open(info.name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
--- a/dom/indexedDB/test/test_filehandle_store_snapshot.html
+++ b/dom/indexedDB/test/test_filehandle_store_snapshot.html
@@ -10,23 +10,22 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
 
     const name = window.location.pathname;
-    const description = "My Test Database";
 
     const objectStoreName = "Blobs";
 
     const testFile = getRandomFile("random.bin", 100000);
 
-    let request = indexedDB.open(name, 1, description);
+    let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     let db = event.target.result;
--- a/dom/indexedDB/test/test_readonly_transactions.html
+++ b/dom/indexedDB/test/test_readonly_transactions.html
@@ -8,20 +8,19 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
-      const description = "My Test Database";
       const osName = "foo";
 
-      let request = indexedDB.open(name, 1, description);
+      let request = indexedDB.open(name, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
--- a/dom/indexedDB/test/unit/test_add_twice_failure.js
+++ b/dom/indexedDB/test/unit/test_add_twice_failure.js
@@ -3,19 +3,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = request.result;
 
   ok(event.target === request, "Good event target");
 
--- a/dom/indexedDB/test/unit/test_clear.js
+++ b/dom/indexedDB/test/unit/test_clear.js
@@ -3,20 +3,19 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const entryCount = 1000;
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = request.result;
 
   event.target.onsuccess = continueToNextStep;
 
--- a/dom/indexedDB/test/unit/test_cursor_update_updates_indexes.js
+++ b/dom/indexedDB/test/unit/test_cursor_update_updates_indexes.js
@@ -3,17 +3,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const START_DATA = "hi";
   const END_DATA = "bye";
   const objectStoreInfo = [
     { name: "1", options: { keyPath: null }, key: 1,
       entry: { data: START_DATA } },
     { name: "2", options: { keyPath: "foo" },
       entry: { foo: 1, data: START_DATA } },
     { name: "3", options: { keyPath: null, autoIncrement: true },
@@ -22,17 +21,17 @@ function testSteps()
       entry: { data: START_DATA } },
   ];
 
   for (let i = 0; i < objectStoreInfo.length; i++) {
     // Create our object stores.
     let info = objectStoreInfo[i];
 
     ok(true, "1");
-    request = indexedDB.open(name, i + 1, description);
+    request = indexedDB.open(name, i + 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     event = yield;
 
     let db = event.target.result;
 
     ok(true, "2");
     let objectStore = info.hasOwnProperty("options") ?
--- a/dom/indexedDB/test/unit/test_cursors.js
+++ b/dom/indexedDB/test/unit/test_cursors.js
@@ -3,23 +3,22 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const keys = [1, -1, 0, 10, 2000, "q", "z", "two", "b", "a"];
   const sortedKeys = [-1, 0, 1, 10, 2000, "a", "b", "q", "two", "z"];
 
   is(keys.length, sortedKeys.length, "Good key setup");
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore("autoIncrement",
                                          { autoIncrement: true });
--- a/dom/indexedDB/test/unit/test_event_source.js
+++ b/dom/indexedDB/test/unit/test_event_source.js
@@ -3,20 +3,19 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "Objects";
 
-  var request = indexedDB.open(name, 1, description);
+  var request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   var event = yield;
 
   is(event.target.source, null, "correct event.target.source");
 
   var db = event.target.result;
   var objectStore = db.createObjectStore(objectStoreName,
--- a/dom/indexedDB/test/unit/test_getAll.js
+++ b/dom/indexedDB/test/unit/test_getAll.js
@@ -3,21 +3,20 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
   const values = [ "a", "1", 1, "foo", 300, true, false, 4.5, null ];
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
--- a/dom/indexedDB/test/unit/test_global_data.js
+++ b/dom/indexedDB/test/unit/test_global_data.js
@@ -3,35 +3,34 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStore =  { name: "Objects",
                          options: { keyPath: "id", autoIncrement: true } };
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db1 = event.target.result;
 
   is(db1.objectStoreNames.length, 0, "No objectStores in db1");
 
   db1.createObjectStore(objectStore.name, objectStore.options);
 
   continueToNextStep();
   yield;
 
-  request = indexedDB.open(name, 1, description);
+  request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   let db2 = event.target.result;
 
   ok(db1 !== db2, "Databases are not the same object");
 
--- a/dom/indexedDB/test/unit/test_index_getAll.js
+++ b/dom/indexedDB/test/unit/test_index_getAll.js
@@ -3,17 +3,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "People";
 
   const objectStoreData = [
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
     { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
@@ -47,17 +46,17 @@ function testSteps()
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
     { key: "237-23-7737", value: { name: "Pat", height: 65 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
   ];
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore(objectStoreName);
--- a/dom/indexedDB/test/unit/test_index_getAllObjects.js
+++ b/dom/indexedDB/test/unit/test_index_getAllObjects.js
@@ -3,17 +3,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "People";
 
   const objectStoreData = [
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
     { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
@@ -47,17 +46,17 @@ function testSteps()
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
     { key: "237-23-7737", value: { name: "Pat", height: 65 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
   ];
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore(objectStoreName, {});
--- a/dom/indexedDB/test/unit/test_indexes.js
+++ b/dom/indexedDB/test/unit/test_indexes.js
@@ -3,17 +3,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? this.window ? window.location.pathname : "Splendid Test" : "Splendid Test";
-  const description = "My Test Database";
 
   const objectStoreName = "People";
 
   const objectStoreData = [
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
@@ -48,17 +47,17 @@ function testSteps()
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
     { key: "237-23-7737", value: { name: "Pat", height: 65 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
   ];
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
   let db = event.target.result;
 
   let objectStore = db.createObjectStore(objectStoreName, { keyPath: null });
 
--- a/dom/indexedDB/test/unit/test_indexes_bad_values.js
+++ b/dom/indexedDB/test/unit/test_indexes_bad_values.js
@@ -3,17 +3,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
   const objectStoreName = "People";
 
   const objectStoreData = [
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
@@ -34,17 +33,17 @@ function testSteps()
   const objectStoreDataWeightSort = [
     { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
     { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
     { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
     { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
   ];
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore(objectStoreName, { } );
--- a/dom/indexedDB/test/unit/test_key_requirements.js
+++ b/dom/indexedDB/test/unit/test_key_requirements.js
@@ -3,19 +3,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps(); 
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
   db.addEventListener("error", function(event) {
     event.preventDefault();
   }, false);
--- a/dom/indexedDB/test/unit/test_objectCursors.js
+++ b/dom/indexedDB/test/unit/test_objectCursors.js
@@ -3,31 +3,30 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
   const objectStores = [
     { name: "a", autoIncrement: false },
     { name: "b", autoIncrement: true }
   ];
 
   const indexes = [
     { name: "a", options: { } },
     { name: "b", options: { unique: true } }
   ];
 
   var j = 0;
   for (let i in objectStores) {
-    let request = indexedDB.open(name, ++j, description);
+    let request = indexedDB.open(name, ++j);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     let event = yield;
 
     let db = event.target.result;
 
     let objectStore =
       db.createObjectStore(objectStores[i].name,
@@ -50,17 +49,17 @@ function testSteps()
 
     ok(event.target.result == 1 || event.target.result == 2, "Good id");
     db.close();
   }
 
   executeSoon(function() { testGenerator.next(); });
   yield;
 
-  let request = indexedDB.open(name, j, description);
+  let request = indexedDB.open(name, j);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   for (let i in objectStores) {
     for (let j in indexes) {
--- a/dom/indexedDB/test/unit/test_objectStore_inline_autoincrement_key_added_on_put.js
+++ b/dom/indexedDB/test/unit/test_objectStore_inline_autoincrement_key_added_on_put.js
@@ -4,19 +4,18 @@
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const IDBObjectStore = Components.interfaces.nsIIDBObjectStore;
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
-  var request = indexedDB.open(name, 1, description);
+  var request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   var event = yield;
 
   var db = event.target.result;
 
   var test = {
     name: "inline key; key generator",
--- a/dom/indexedDB/test/unit/test_objectStore_remove_values.js
+++ b/dom/indexedDB/test/unit/test_objectStore_remove_values.js
@@ -4,17 +4,16 @@
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const IDBObjectStore = Components.interfaces.nsIIDBObjectStore;
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
   var data = [
     { name: "inline key; key generator",
       autoIncrement: true,
       storedObject: {name: "Lincoln"},
       keyName: "id",
       keyValue: undefined,
     },
@@ -36,17 +35,17 @@ function testSteps()
       keyName: null,
       keyValue: 1,
     }
   ];
 
   for (let i = 0; i < data.length; i++) {
     let test = data[i];
 
-    let request = indexedDB.open(name, i+1, description);
+    let request = indexedDB.open(name, i+1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     let event = yield;
 
     let db = event.target.result;
 
     let objectStore = db.createObjectStore(test.name,
                                            { keyPath: test.keyName,
--- a/dom/indexedDB/test/unit/test_open_objectStore.js
+++ b/dom/indexedDB/test/unit/test_open_objectStore.js
@@ -4,20 +4,19 @@
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "Objects";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
   is(db.objectStoreNames.length, 0, "Bad objectStores list");
 
--- a/dom/indexedDB/test/unit/test_overlapping_transactions.js
+++ b/dom/indexedDB/test/unit/test_overlapping_transactions.js
@@ -3,20 +3,19 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStores = [ "foo", "bar" ];
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
   is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
   event.target.onsuccess = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/unit/test_put_get_values.js
+++ b/dom/indexedDB/test/unit/test_put_get_values.js
@@ -3,23 +3,22 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "Objects";
 
   let testString = { key: 0, value: "testString" };
   let testInt = { key: 1, value: 1002 };
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore(objectStoreName,
                                          { autoIncrement: 0 });
--- a/dom/indexedDB/test/unit/test_put_get_values_autoIncrement.js
+++ b/dom/indexedDB/test/unit/test_put_get_values_autoIncrement.js
@@ -3,23 +3,22 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "Objects";
 
   let testString = { value: "testString" };
   let testInt = { value: 1002 };
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore(objectStoreName,
                                          { autoIncrement: 1 });
--- a/dom/indexedDB/test/unit/test_remove_index.js
+++ b/dom/indexedDB/test/unit/test_remove_index.js
@@ -5,20 +5,19 @@
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
 
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const indexName = "My Test Index";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
   is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
   let objectStore = db.createObjectStore("test store", { keyPath: "foo" });
--- a/dom/indexedDB/test/unit/test_remove_objectStore.js
+++ b/dom/indexedDB/test/unit/test_remove_objectStore.js
@@ -5,20 +5,19 @@
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
 
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
   const objectStoreName = "Objects";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
   is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
   let objectStore = db.createObjectStore(objectStoreName,
@@ -37,17 +36,17 @@ function testSteps()
   }
   yield;
 
   is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
   is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
 
   db.close();
 
-  let request = indexedDB.open(name, 2, description);
+  let request = indexedDB.open(name, 2);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
   let trans = event.target.transaction;
 
   let oldObjectStore = trans.objectStore(objectStoreName);
@@ -81,17 +80,17 @@ function testSteps()
   db.deleteObjectStore(objectStore.name);
   is(db.objectStoreNames.length, 0, "Correct objectStores list");
 
   continueToNextStep();
   yield;
 
   db.close();
 
-  let request = indexedDB.open(name, 3, description);
+  let request = indexedDB.open(name, 3);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
 
--- a/dom/indexedDB/test/unit/test_request_readyState.js
+++ b/dom/indexedDB/test/unit/test_request_readyState.js
@@ -3,19 +3,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   is(request.readyState, "pending", "Correct readyState");
 
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   is(request.readyState, "done", "Correct readyState");
 
--- a/dom/indexedDB/test/unit/test_setVersion.js
+++ b/dom/indexedDB/test/unit/test_setVersion.js
@@ -3,19 +3,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   // Check default state.
   is(db.version, 1, "Correct default version for a new database.");
@@ -25,17 +24,17 @@ function testSteps()
     42,
   ];
 
   db.close();
 
   for (let i = 0; i < versions.length; i++) {
     let version = versions[i];
 
-    let request = indexedDB.open(name, version, description);
+    let request = indexedDB.open(name, version);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     let event = yield;
 
     let db = event.target.result;
 
     is(db.version, version, "Database version number updated correctly");
     is(event.target.transaction.mode, "versionchange", "Correct mode");
--- a/dom/indexedDB/test/unit/test_setVersion_events.js
+++ b/dom/indexedDB/test/unit/test_setVersion_events.js
@@ -3,20 +3,19 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
-  const description = "My Test Database";
 
   // Open a datbase for the first time.
-  let request = indexedDB.open(name, 1, description);
+  let request = indexedDB.open(name, 1);
 
   // Sanity checks
   ok(request instanceof IDBRequest, "Request should be an IDBRequest");
   ok(request instanceof IDBOpenDBRequest, "Request should be an IDBOpenDBRequest");
   //ok(request instanceof EventTarget, "Request should be an EventTarget");
   is(request.source, null, "Request should have no source");
   try {
     request.result;
@@ -41,17 +40,17 @@ function testSteps()
     is(event.target.version, 1, "Correct db version");
     is(event.oldVersion, 1, "Correct event oldVersion");
     is(event.newVersion, 2, "Correct event newVersion");
     is(versionChangeEventCount++, 0, "Correct count");
     db1.close();
   }, false);
 
   // Open the database again and trigger an upgrade that should succeed
-  request = indexedDB.open(name, 2, description);
+  request = indexedDB.open(name, 2);
   request.onerror = errorHandler;
   request.onsuccess = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   if (SpecialPowers.isMainProcess()) {
     request.onblocked = errorHandler;
   }
   else {
     todo(false, "Need to fix blocked events in child processes!");
@@ -79,31 +78,31 @@ function testSteps()
     is(event.target, db2, "Correct target");
     is(event.target.version, 2, "Correct db version");
     is(event.oldVersion, 2, "Correct event oldVersion");
     is(event.newVersion, 3, "Correct event newVersion");
     is(versionChangeEventCount++, 1, "Correct count");
   }, false);
 
   // Test opening the existing version again
-  request = indexedDB.open(name, 2, description);
+  request = indexedDB.open(name, 2);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   if (SpecialPowers.isMainProcess()) {
     request.onblocked = errorHandler;
   }
   else {
     todo(false, "Need to fix blocked events in child processes!");
   }
   event = yield;
 
   db3 = event.target.result;
 
   // Test an upgrade that should fail
-  request = indexedDB.open(name, 3, description);
+  request = indexedDB.open(name, 3);
   request.onerror = errorHandler;
   request.onsuccess = errorHandler;
   request.onupgradeneeded = errorHandler;
   request.onblocked = grabEventAndContinueHandler;
 
   event = yield;
   ok(true, "Got version change blocked event");
   ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -94,16 +94,25 @@ CrashReporterParent::GenerateHangCrashRe
     notes.Init(4);
     notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
     if (!CrashReporter::AppendExtraData(mParentDumpID, notes))
         NS_WARNING("problem appending parent data to .extra");
     return true;
 }
 
 bool
+CrashReporterParent::GenerateCrashReportForMinidump(nsIFile* minidump,
+    const AnnotationTable* processNotes)
+{
+    if (!CrashReporter::GetIDFromMinidump(minidump, mChildDumpID))
+        return false;
+    return GenerateChildData(processNotes);
+}
+
+bool
 CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
 {
     MOZ_ASSERT(mInitialized);
 
     nsCAutoString type;
     switch (mProcessType) {
         case GeckoProcessType_Content:
             type = NS_LITERAL_CSTRING("content");
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -44,16 +44,20 @@ public:
   /* Attempt to create a bare-bones crash report, along with extra process-
      specific annotations present in the given AnnotationTable. Returns true if
      successful, false otherwise.
   */
   template<class Toplevel>
   bool
   GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
 
+  bool
+  GenerateCrashReportForMinidump(nsIFile* minidump,
+                                 const AnnotationTable* processNotes);
+
   /* Instantiate a new crash reporter actor from a given parent that manages
      the protocol.
   */
   template<class Toplevel>
   static bool CreateCrashReporter(Toplevel* actor);
 #endif
   /* Initialize this reporter with data from the child process */
   void
@@ -130,17 +134,17 @@ CrashReporterParent::GeneratePairedMinid
 }
 
 template<class Toplevel>
 inline bool
 CrashReporterParent::GenerateCrashReport(Toplevel* t,
                                          const AnnotationTable* processNotes)
 {
   nsCOMPtr<nsIFile> crashDump;
-  if (t->TakeMinidump(getter_AddRefs(crashDump)) &&
+  if (t->TakeMinidump(getter_AddRefs(crashDump), NULL) &&
       CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
     return GenerateChildData(processNotes);
   }
   return false;
 }
 
 template<class Toplevel>
 /* static */ bool
--- a/dom/plugins/base/nsIPluginTag.idl
+++ b/dom/plugins/base/nsIPluginTag.idl
@@ -1,18 +1,19 @@
 /* -*- Mode: IDL; 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 "nsISupports.idl"
 
-[scriptable, uuid(88e03453-a773-47ba-9d84-14f672ac99e2)]
+[scriptable, uuid(a361a7e7-7f8d-4b68-91e9-30ae096460d4)]
 interface nsIPluginTag : nsISupports
 {
   readonly attribute AUTF8String description;
   readonly attribute AUTF8String filename;
   readonly attribute AUTF8String fullpath;
   readonly attribute AUTF8String version;
   readonly attribute AUTF8String name;
            attribute boolean  disabled;
            attribute boolean  blocklisted;
+           attribute boolean  clicktoplay;
 };
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -337,18 +337,20 @@ nsPluginHost::nsPluginHost()
   // has a zeroing operator new.
 {
   // check to see if pref is set at startup to let plugins take over in
   // full page mode for certain image mime types that we handle internally
   mOverrideInternalTypes =
     Preferences::GetBool("plugin.override_internal_types", false);
 
   mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
+  mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
 
   Preferences::AddStrongObserver(this, "plugin.disable");
+  Preferences::AddStrongObserver(this, "plugins.click_to_play");
 
   nsCOMPtr<nsIObserverService> obsService =
     mozilla::services::GetObserverService();
   if (obsService) {
     obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 #ifdef MOZ_WIDGET_ANDROID
     obsService->AddObserver(this, "application-foreground", false);
     obsService->AddObserver(this, "application-background", false);
@@ -1289,16 +1291,46 @@ nsPluginHost::IsPluginEnabledForType(con
     if (plugin->HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED))
       return NS_ERROR_PLUGIN_BLOCKLISTED;
     else
       return NS_ERROR_PLUGIN_DISABLED;
   }
 
   return NS_OK;
 }
+ 
+bool
+nsPluginHost::IsPluginClickToPlayForType(const char* aMimeType)
+{
+  nsPluginTag *plugin = FindPluginForType(aMimeType, true);
+  if (plugin && 
+      (plugin->HasFlag(NS_PLUGIN_FLAG_CLICKTOPLAY) || mPluginsClickToPlay)) {
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+nsresult
+nsPluginHost::GetBlocklistStateForType(const char *aMimeType, PRUint32 *aState) 
+{
+  nsPluginTag *plugin = FindPluginForType(aMimeType, true);
+  if (plugin) {
+    nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
+    if (blocklist) {
+      // The EmptyString()s are so we use the currently running application
+      // and toolkit versions
+      return blocklist->GetPluginBlocklistState(plugin, EmptyString(),
+                                                EmptyString(), aState);
+    }
+  }
+
+  return NS_ERROR_FAILURE;
+}
 
 // check comma delimitered extensions
 static int CompareExtensions(const char *aExtensionList, const char *aExtension)
 {
   if (!aExtensionList || !aExtension)
     return -1;
 
   const char *pExt = aExtensionList;
@@ -2069,29 +2101,42 @@ nsresult nsPluginHost::ScanPluginsDirect
 
       nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
       if (blocklist) {
         PRUint32 state;
         rv = blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
                                                 EmptyString(), &state);
 
         if (NS_SUCCEEDED(rv)) {
-          // If the blocklist says so then block the plugin. If the blocklist says
-          // it is risky and we have never seen this plugin before then disable it
-          if (state == nsIBlocklistService::STATE_BLOCKED)
-            pluginTag->Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
-          else if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore)
-            enabled = false;
-          else if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore)
-            warnOutdated = true;
+          // If the blocklist says so, block the plugin.
+          // If the blocklist says it is risky and we have never seen this
+          // plugin before, then disable it.
+          // If the blocklist says this is an outdated plugin, warn about
+          // outdated plugins.
+          // If the blocklist says the plugin is one of the click-to-play
+          // states, set the click-to-play flag.
+          if (state == nsIBlocklistService::STATE_BLOCKED) {
+             pluginTag->Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
+          }
+          if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) {
+             enabled = false;
+          }
+          if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore) {
+             warnOutdated = true;
+          }
+          if (state == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
+              state == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
+            pluginTag->Mark(NS_PLUGIN_FLAG_CLICKTOPLAY);
+          }
         }
       }
 
-      if (!enabled)
+      if (!enabled) {
         pluginTag->UnMark(NS_PLUGIN_FLAG_ENABLED);
+      }
 
       // Plugin unloading is tag-based. If we created a new tag and loaded
       // the library in the process then we want to attempt to unload it here.
       // Only do this if the pref is set for aggressive unloading.
       if (UnloadPluginsASAP()) {
         pluginTag->TryUnloadPlugin(false);
       }
     }
@@ -3297,16 +3342,17 @@ NS_IMETHODIMP nsPluginHost::Observe(nsIS
 {
   if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
     OnShutdown();
     UnloadPlugins();
     sInst->Release();
   }
   if (!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
     mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
+    mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
     // Unload or load plugins as needed
     if (mPluginsDisabled) {
       UnloadPlugins();
     } else {
       LoadPlugins();
     }
   }
 #ifdef MOZ_WIDGET_ANDROID
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -80,16 +80,18 @@ public:
   nsresult LoadPlugins();
   nsresult UnloadPlugins();
 
   nsresult SetUpPluginInstance(const char *aMimeType,
                                nsIURI *aURL,
                                nsIPluginInstanceOwner *aOwner);
   nsresult IsPluginEnabledForType(const char* aMimeType);
   nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
+  bool     IsPluginClickToPlayForType(const char *aMimeType);
+  nsresult GetBlocklistStateForType(const char *aMimeType, PRUint32 *state);
 
   nsresult GetPluginCount(PRUint32* aPluginCount);
   nsresult GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray);
 
   nsresult GetURL(nsISupports* pluginInst,
                   const char* url,
                   const char* target,
                   nsNPAPIPluginStreamListener* streamListener,
@@ -276,16 +278,18 @@ private:
   bool mPluginsLoaded;
   bool mDontShowBadPluginMessage;
 
   // set by pref plugin.override_internal_types
   bool mOverrideInternalTypes;
 
   // set by pref plugin.disable
   bool mPluginsDisabled;
+  // set by pref plugins.click_to_play
+  bool mPluginsClickToPlay;
 
   // Any instances in this array will have valid plugin objects via GetPlugin().
   // When removing an instance it might not die - be sure to null out it's plugin.
   nsTArray< nsRefPtr<nsNPAPIPluginInstance> > mInstances;
 
   nsCOMPtr<nsIFile> mPluginRegFile;
 #ifdef XP_WIN
   nsRefPtr<nsPluginDirServiceProvider> mPrivateDirServiceProvider;
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -315,16 +315,40 @@ nsPluginTag::SetBlocklisted(bool aBlockl
   if (aBlocklisted)
     Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
   else
     UnMark(NS_PLUGIN_FLAG_BLOCKLISTED);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsPluginTag::GetClicktoplay(bool *aClicktoplay)
+{
+  *aClicktoplay = HasFlag(NS_PLUGIN_FLAG_CLICKTOPLAY);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::SetClicktoplay(bool aClicktoplay)
+{
+  if (HasFlag(NS_PLUGIN_FLAG_CLICKTOPLAY) == aClicktoplay) {
+    return NS_OK;
+  }
+  
+  if (aClicktoplay) {
+    Mark(NS_PLUGIN_FLAG_CLICKTOPLAY);
+  } else {
+    UnMark(NS_PLUGIN_FLAG_CLICKTOPLAY);
+  }
+  
+  mPluginHost->UpdatePluginInfo(nsnull);
+  return NS_OK;
+}
+
 void nsPluginTag::Mark(PRUint32 mask)
 {
   bool wasEnabled = IsEnabled();
   mFlags |= mask;
 
   if (mPluginHost && wasEnabled != IsEnabled()) {
     mPluginHost->UpdatePluginInfo(this);
   }
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -22,16 +22,17 @@ struct nsPluginInfo;
 
 // Remember that flags are written out to pluginreg.dat, be careful
 // changing their meaning.
 #define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
 // no longer used                   0x0002    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_FROMCACHE    0x0004    // this plugintag info was loaded from cache
 // no longer used                   0x0008    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_BLOCKLISTED  0x0010    // this is a blocklisted plugin
+#define NS_PLUGIN_FLAG_CLICKTOPLAY  0x0020    // this is a click-to-play plugin
 
 // A linked-list of plugin information that is used for instantiating plugins
 // and reflecting plugin information into JavaScript.
 class nsPluginTag : public nsIPluginTag
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPLUGINTAG
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -22,19 +22,16 @@
 #include "mozilla/ipc/SyncChannel.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/plugins/BrowserStreamParent.h"
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "PluginIdentifierParent.h"
 
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
-#ifdef MOZ_CRASHREPORTER
-#include "mozilla/dom/CrashReporterParent.h"
-#endif
 #include "nsNPAPIPlugin.h"
 #include "nsIFile.h"
 
 #ifdef XP_WIN
 #include "mozilla/widget/AudioSession.h"
 #endif
 #include "sampler.h"
 
@@ -44,16 +41,22 @@ using mozilla::PluginLibrary;
 using mozilla::ipc::SyncChannel;
 using mozilla::dom::PCrashReporterParent;
 using mozilla::dom::CrashReporterParent;
 
 using namespace mozilla;
 using namespace mozilla::plugins;
 using namespace mozilla::plugins::parent;
 
+#ifdef MOZ_CRASHREPORTER
+#include "mozilla/dom/CrashReporterParent.h"
+
+using namespace CrashReporter;
+#endif
+
 static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
 static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
 
 template<>
 struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
 {
     typedef mozilla::plugins::PluginModuleParent Class;
@@ -128,28 +131,28 @@ PluginModuleParent::~PluginModuleParent(
 
     if (mSubprocess) {
         mSubprocess->Delete();
         mSubprocess = nsnull;
     }
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     if (mFlashProcess1)
-        CrashReporter::UnregisterInjectorCallback(mFlashProcess1);
+        UnregisterInjectorCallback(mFlashProcess1);
     if (mFlashProcess2)
-        CrashReporter::UnregisterInjectorCallback(mFlashProcess2);
+        UnregisterInjectorCallback(mFlashProcess2);
 #endif
 
     Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
     Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
 }
 
 #ifdef MOZ_CRASHREPORTER
 void
-PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
+PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes)
 {
     typedef nsDependentCString CS;
 
     // Get the plugin filename, try to get just the file leafname
     const std::string& pluginFile = mSubprocess->GetPluginFilePath();
     size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
     if (filePos == std::string::npos)
         filePos = 0;
@@ -195,29 +198,27 @@ PluginModuleParent::CleanupFromTimeout()
     if (!mShutdown && OkToCleanup())
         Close();
 }
 
 bool
 PluginModuleParent::ShouldContinueFromReplyTimeout()
 {
 #ifdef MOZ_CRASHREPORTER
-    if (mPluginDumpID.IsEmpty()) {
-        CrashReporterParent* crashReporter = CrashReporter();
-        if (crashReporter->GeneratePairedMinidump(this)) {
-            mBrowserDumpID = crashReporter->ParentDumpID();
-            mPluginDumpID = crashReporter->ChildDumpID();
-            PLUGIN_LOG_DEBUG(
-                    ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
-                     NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
-                     NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
-                     NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
-        } else {
-            NS_WARNING("failed to capture paired minidumps from hang");
-        }
+    CrashReporterParent* crashReporter = CrashReporter();
+    if (crashReporter->GeneratePairedMinidump(this)) {
+        mBrowserDumpID = crashReporter->ParentDumpID();
+        mPluginDumpID = crashReporter->ChildDumpID();
+        PLUGIN_LOG_DEBUG(
+                ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
+                 NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
+                 NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
+                 NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
+    } else {
+        NS_WARNING("failed to capture paired minidumps from hang");
     }
 #endif
 
     // this must run before the error notification from the channel,
     // or not at all
     MessageLoop::current()->PostTask(
         FROM_HERE,
         mTaskFactory.NewRunnableMethod(
@@ -232,43 +233,109 @@ PluginModuleParent::ShouldContinueFromRe
 #ifdef MOZ_CRASHREPORTER
 CrashReporterParent*
 PluginModuleParent::CrashReporter()
 {
     return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
 }
 #endif
 
+#ifdef MOZ_CRASHREPORTER
+static void
+RemoveMinidump(nsIFile* minidump)
+{
+    if (!minidump)
+        return;
+
+    minidump->Remove(false);
+    nsCOMPtr<nsIFile> extraFile;
+    if (GetExtraFileForMinidump(minidump,
+                                getter_AddRefs(extraFile))) {
+        extraFile->Remove(true);
+    }
+}
+
+void
+PluginModuleParent::ProcessFirstMinidump()
+{
+    CrashReporterParent* crashReporter = CrashReporter();
+    if (!crashReporter)
+        return;
+
+    AnnotationTable notes;
+    notes.Init(4);
+    WriteExtraDataForMinidump(notes);
+        
+    if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
+        crashReporter->GenerateHangCrashReport(&notes);
+        return;
+    }
+
+    PRUint32 sequence = PR_UINT32_MAX;
+    nsCOMPtr<nsIFile> dumpFile;
+    nsCAutoString flashProcessType;
+    TakeMinidump(getter_AddRefs(dumpFile), &sequence);
+
+#ifdef MOZ_CRASHREPORTER_INJECTOR
+    nsCOMPtr<nsIFile> childDumpFile;
+    PRUint32 childSequence;
+
+    if (mFlashProcess1 &&
+        TakeMinidumpForChild(mFlashProcess1,
+                             getter_AddRefs(childDumpFile),
+                             &childSequence)) {
+        if (childSequence < sequence) {
+            RemoveMinidump(dumpFile);
+            dumpFile = childDumpFile;
+            sequence = childSequence;
+            flashProcessType.AssignLiteral("Broker");
+        }
+        else {
+            RemoveMinidump(childDumpFile);
+        }
+    }
+    if (mFlashProcess2 &&
+        TakeMinidumpForChild(mFlashProcess2,
+                             getter_AddRefs(childDumpFile),
+                             &childSequence)) {
+        if (childSequence < sequence) {
+            RemoveMinidump(dumpFile);
+            dumpFile = childDumpFile;
+            sequence = childSequence;
+            flashProcessType.AssignLiteral("Sandbox");
+        }
+        else {
+            RemoveMinidump(childDumpFile);
+        }
+    }
+#endif
+
+    if (!dumpFile) {
+        NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
+        return;
+    }
+
+    PLUGIN_LOG_DEBUG(("got child minidump: %s",
+                      NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
+
+    GetIDFromMinidump(dumpFile, mPluginDumpID);
+    if (!flashProcessType.IsEmpty()) {
+        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
+    }
+    crashReporter->GenerateCrashReportForMinidump(dumpFile, &notes);
+}
+#endif
+
 void
 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
 {
     switch (why) {
     case AbnormalShutdown: {
 #ifdef MOZ_CRASHREPORTER
-        CrashReporterParent* crashReporter = CrashReporter();
-
-        CrashReporter::AnnotationTable notes;
-        notes.Init(4);
-        WriteExtraDataForMinidump(notes);
-        
-        if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
-            crashReporter->GenerateHangCrashReport(&notes);
-        }
-        else if (!mPluginDumpID.IsEmpty()) {
-            // Nothing to do, we've already written this minidump in
-            // PluginModuleParent::OnCrash
-        }
-        else if (crashReporter->GenerateCrashReport(this, &notes)) {
-            mPluginDumpID = crashReporter->ChildDumpID();
-            PLUGIN_LOG_DEBUG(("got child minidump: %s",
-                              NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
-        }
-        else {
-            NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
-        }
+        ProcessFirstMinidump();
 #endif
 
         mShutdown = true;
         // Defer the PluginCrashed method so that we don't re-enter
         // and potentially modify the actor child list while enumerating it.
         if (mPlugin)
             MessageLoop::current()->PostTask(
                 FROM_HERE,
@@ -1243,40 +1310,15 @@ PluginModuleParent::InitializeInjector()
         mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot);
         if (mFlashProcess2) {
             InjectCrashReporterIntoProcess(mFlashProcess2, this);
         }
     }
 }
 
 void
-PluginModuleParent::OnCrash(DWORD processID, const nsAString& aDumpID)
+PluginModuleParent::OnCrash(DWORD processID)
 {
-    if (!mPluginDumpID.IsEmpty()) {
-        // One process has already crashed: we assume that the first-to-crash
-        // is the interesting one
-        return;
-    }
-
-    mPluginDumpID = aDumpID;
-
-    CrashReporter::AnnotationTable notes;
-    notes.Init(4);
-    WriteExtraDataForMinidump(notes);
-    notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("plugin"));
-    if (processID == mFlashProcess1) {
-        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
-                  NS_LITERAL_CSTRING("Broker"));
-    }
-    else if (processID == mFlashProcess2) {
-        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
-                  NS_LITERAL_CSTRING("Sandbox"));
-    }
-    else {
-        NS_ERROR("Got minidump for Flash process neither broker nor sandbox.");
-    }
-    CrashReporter::AppendExtraData(aDumpID, notes);
-
     GetIPCChannel()->CloseWithError();
     KillProcess(OtherProcess(), 1, false);
 }
 
 #endif // MOZ_CRASHREPORTER_INJECTOR
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -283,16 +283,17 @@ private:
     virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,
                                     bool* handled);
 #endif
 
 private:
     CrashReporterParent* CrashReporter();
 
 #ifdef MOZ_CRASHREPORTER
+    void ProcessFirstMinidump();
     void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
 #endif
     void CleanupFromTimeout();
     static int TimeoutChanged(const char* aPref, void* aModule);
     void NotifyPluginCrashed();
 
     PluginProcessParent* mSubprocess;
     // the plugin thread in mSubprocess
@@ -314,17 +315,17 @@ private:
     ScopedClose mPluginXSocketFdDup;
 #endif
 
     friend class mozilla::dom::CrashReporterParent;
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     void InitializeInjector();
     
-    NS_OVERRIDE void OnCrash(DWORD processID, const nsAString& aDumpID);
+    NS_OVERRIDE void OnCrash(DWORD processID);
 
     DWORD mFlashProcess1;
     DWORD mFlashProcess2;
 #endif
 };
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/tests/mochitest/general/test_consoleAPI.html
+++ b/dom/tests/mochitest/general/test_consoleAPI.html
@@ -27,16 +27,18 @@ function doTest() {
     "debug": "function",
     "trace": "function",
     "dir": "function",
     "group": "function",
     "groupCollapsed": "function",
     "groupEnd": "function",
     "time": "function",
     "timeEnd": "function",
+    "profile": "function",
+    "profileEnd": "function",
     "__noSuchMethod__": "function"
   };
 
   var foundProps = 0;
   for (var prop in console) {
     foundProps++;
     is(typeof(console[prop]), expectedProps[prop], "expect console prop " + prop + " exists");
   }
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -231,19 +231,24 @@ var WifiManager = (function() {
   var scanModeActive = false;
 
   function doSetScanModeCommand(setActive, callback) {
     doBooleanCommand(setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE", "OK", callback);
   }
 
   function scanCommand(forceActive, callback) {
     if (forceActive && !scanModeActive) {
-      doSetScanModeCommand(true, function(ok) {
-        ok && doBooleanCommand("SCAN", "OK", function(ok) {
-          ok && doSetScanModeCommand(false, callback);
+      // Note: we ignore errors from doSetScanMode.
+      doSetScanModeCommand(true, function(ignore) {
+        doBooleanCommand("SCAN", "OK", function(ok) {
+          doSetScanModeCommand(false, function(ignore) {
+            // The result of scanCommand is the result of the actual SCAN
+            // request.
+            callback(ok);
+          });
         });
       });
       return;
     }
     doBooleanCommand("SCAN", "OK", callback);
   }
 
   function setScanModeCommand(setActive, callback) {
@@ -598,17 +603,17 @@ var WifiManager = (function() {
     resetConnections(manager.ifname, function() {
       stopDhcp(manager.ifname, function() {
         callback();
       });
     });
   }
 
   manager.start = function() {
-    debug("detected SDK version " + sdkVersion);
+    debug("detected SDK version " + sdkVersion + " and device " + device);
 
     // If we reconnected to an already-running supplicant, then manager.state
     // will have already been updated to the supplicant's state. Otherwise, we
     // started the supplicant ourselves and need to connect.
     if (manager.state === "UNINITIALIZED")
       connectToSupplicant(connectCallback);
   }
 
--- a/editor/libeditor/base/nsSelectionState.cpp
+++ b/editor/libeditor/base/nsSelectionState.cpp
@@ -24,23 +24,23 @@ nsSelectionState::~nsSelectionState()
   MakeEmpty();
 }
 
 void
 nsSelectionState::DoTraverse(nsCycleCollectionTraversalCallback &cb)
 {
   for (PRUint32 i = 0, iEnd = mArray.Length(); i < iEnd; ++i)
   {
-    nsRangeStore &item = mArray[i];
+    nsRangeStore* item = mArray[i];
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
                                        "selection state mArray[i].startNode");
-    cb.NoteXPCOMChild(item.startNode);
+    cb.NoteXPCOMChild(item->startNode);
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
                                        "selection state mArray[i].endNode");
-    cb.NoteXPCOMChild(item.endNode);
+    cb.NoteXPCOMChild(item->endNode);
   }
 }
 
 nsresult  
 nsSelectionState::SaveSelection(nsISelection *aSel)
 {
   NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
   PRInt32 i,rangeCount, arrayCount = mArray.Length();
@@ -48,16 +48,17 @@ nsSelectionState::SaveSelection(nsISelec
   
   // if we need more items in the array, new them
   if (arrayCount<rangeCount)
   {
     PRInt32 count = rangeCount-arrayCount;
     for (i=0; i<count; i++)
     {
       mArray.AppendElement();
+      mArray[i] = new nsRangeStore();
     }
   }
   
   // else if we have too many, delete them
   else if (arrayCount>rangeCount)
   {
     for (i = arrayCount-1; i >= rangeCount; i--)
     {
@@ -66,17 +67,17 @@ nsSelectionState::SaveSelection(nsISelec
   }
   
   // now store the selection ranges
   nsresult res = NS_OK;
   for (i=0; i<rangeCount; i++)
   {
     nsCOMPtr<nsIDOMRange> range;
     res = aSel->GetRangeAt(i, getter_AddRefs(range));
-    mArray[i].StoreRange(range);
+    mArray[i]->StoreRange(range);
   }
   
   return res;
 }
 
 nsresult  
 nsSelectionState::RestoreSelection(nsISelection *aSel)
 {
@@ -86,32 +87,32 @@ nsSelectionState::RestoreSelection(nsISe
 
   // clear out selection
   aSel->RemoveAllRanges();
   
   // set the selection ranges anew
   for (i=0; i<arrayCount; i++)
   {
     nsRefPtr<nsRange> range;
-    mArray[i].GetRange(getter_AddRefs(range));
+    mArray[i]->GetRange(getter_AddRefs(range));
     NS_ENSURE_TRUE(range, NS_ERROR_UNEXPECTED);
    
     res = aSel->AddRange(range);
     if(NS_FAILED(res)) return res;
 
   }
   return NS_OK;
 }
 
 bool
 nsSelectionState::IsCollapsed()
 {
   if (1 != mArray.Length()) return false;
   nsRefPtr<nsRange> range;
-  mArray[0].GetRange(getter_AddRefs(range));
+  mArray[0]->GetRange(getter_AddRefs(range));
   NS_ENSURE_TRUE(range, false);
   bool bIsCollapsed = false;
   range->GetCollapsed(&bIsCollapsed);
   return bIsCollapsed;
 }
 
 bool
 nsSelectionState::IsEqual(nsSelectionState *aSelState)
@@ -119,18 +120,18 @@ nsSelectionState::IsEqual(nsSelectionSta
   NS_ENSURE_TRUE(aSelState, false);
   PRUint32 i, myCount = mArray.Length(), itsCount = aSelState->mArray.Length();
   if (myCount != itsCount) return false;
   if (myCount < 1) return false;
 
   for (i=0; i<myCount; i++)
   {
     nsRefPtr<nsRange> myRange, itsRange;
-    mArray[i].GetRange(getter_AddRefs(myRange));
-    aSelState->mArray[i].GetRange(getter_AddRefs(itsRange));
+    mArray[i]->GetRange(getter_AddRefs(myRange));
+    aSelState->mArray[i]->GetRange(getter_AddRefs(itsRange));
     NS_ENSURE_TRUE(myRange && itsRange, false);
   
     PRInt16 compResult;
     nsresult rv;
     rv = myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
     if (NS_FAILED(rv) || compResult) return false;
     rv = myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
     if (NS_FAILED(rv) || compResult) return false;
@@ -185,31 +186,31 @@ nsRangeUpdater::DropRangeItem(nsRangeSto
 nsresult 
 nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
 {
   PRUint32 i, theCount = aSelState.mArray.Length();
   if (theCount < 1) return NS_ERROR_FAILURE;
 
   for (i=0; i<theCount; i++)
   {
-    RegisterRangeItem(&aSelState.mArray[i]);
+    RegisterRangeItem(aSelState.mArray[i]);
   }
 
   return NS_OK;
 }
 
 nsresult 
 nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
 {
   PRUint32 i, theCount = aSelState.mArray.Length();
   if (theCount < 1) return NS_ERROR_FAILURE;
 
   for (i=0; i<theCount; i++)
   {
-    DropRangeItem(&aSelState.mArray[i]);
+    DropRangeItem(aSelState.mArray[i]);
   }
 
   return NS_OK;
 }
 
 // gravity methods:
 
 nsresult
--- a/editor/libeditor/base/nsSelectionState.h
+++ b/editor/libeditor/base/nsSelectionState.h
@@ -25,16 +25,18 @@ class nsRange;
 
 // first a helper struct for saving/setting ranges
 struct nsRangeStore 
 {
   nsRangeStore();
   ~nsRangeStore();
   nsresult StoreRange(nsIDOMRange *aRange);
   nsresult GetRange(nsRange** outRange);
+
+  NS_INLINE_DECL_REFCOUNTING(nsRangeStore)
         
   nsCOMPtr<nsIDOMNode> startNode;
   PRInt32              startOffset;
   nsCOMPtr<nsIDOMNode> endNode;
   PRInt32              endOffset;
   // DEBUG:   static PRInt32 n;
 };
 
@@ -50,17 +52,17 @@ class nsSelectionState
   
     nsresult SaveSelection(nsISelection *aSel);
     nsresult RestoreSelection(nsISelection *aSel);
     bool     IsCollapsed();
     bool     IsEqual(nsSelectionState *aSelState);
     void     MakeEmpty();
     bool     IsEmpty();
   protected:    
-    nsTArray<nsRangeStore> mArray;
+    nsTArray<nsRefPtr<nsRangeStore> > mArray;
     
     friend class nsRangeUpdater;
 };
 
 class nsRangeUpdater
 {
   public:    
   
@@ -94,51 +96,52 @@ class nsRangeUpdater
     nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
     nsresult WillRemoveContainer();
     nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen);
     nsresult WillInsertContainer();
     nsresult DidInsertContainer();
     nsresult WillMoveNode();
     nsresult DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset);
   protected:    
-    nsTArray<nsRangeStore*> mArray;
+    nsTArray<nsRefPtr<nsRangeStore> > mArray;
     bool mLock;
 };
 
 
 /***************************************************************************
  * helper class for using nsSelectionState.  stack based class for doing
  * preservation of dom points across editor actions
  */
 
 class NS_STACK_CLASS nsAutoTrackDOMPoint
 {
   private:
     nsRangeUpdater &mRU;
     nsCOMPtr<nsIDOMNode> *mNode;
     PRInt32 *mOffset;
-    nsRangeStore mRangeItem;
+    nsRefPtr<nsRangeStore> mRangeItem;
   public:
     nsAutoTrackDOMPoint(nsRangeUpdater &aRangeUpdater, nsCOMPtr<nsIDOMNode> *aNode, PRInt32 *aOffset) :
     mRU(aRangeUpdater)
     ,mNode(aNode)
     ,mOffset(aOffset)
     {
-      mRangeItem.startNode = *mNode;
-      mRangeItem.endNode = *mNode;
-      mRangeItem.startOffset = *mOffset;
-      mRangeItem.endOffset = *mOffset;
-      mRU.RegisterRangeItem(&mRangeItem);
+      mRangeItem = new nsRangeStore();
+      mRangeItem->startNode = *mNode;
+      mRangeItem->endNode = *mNode;
+      mRangeItem->startOffset = *mOffset;
+      mRangeItem->endOffset = *mOffset;
+      mRU.RegisterRangeItem(mRangeItem);
     }
     
     ~nsAutoTrackDOMPoint()
     {
-      mRU.DropRangeItem(&mRangeItem);
-      *mNode  = mRangeItem.startNode;
-      *mOffset = mRangeItem.startOffset;
+      mRU.DropRangeItem(mRangeItem);
+      *mNode  = mRangeItem->startNode;
+      *mOffset = mRangeItem->startOffset;
     }
 };
 
 
 
 /***************************************************************************
  * another helper class for nsSelectionState.  stack based class for doing
  * Will/DidReplaceContainer()
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -179,16 +179,17 @@ mDocChangeRange(nsnull)
   mCachedStyles[11] = StyleCache(nsEditProperty::samp, EmptyString(), EmptyString());
   mCachedStyles[12] = StyleCache(nsEditProperty::var, EmptyString(), EmptyString());
   mCachedStyles[13] = StyleCache(nsEditProperty::cite, EmptyString(), EmptyString());
   mCachedStyles[14] = StyleCache(nsEditProperty::abbr, EmptyString(), EmptyString());
   mCachedStyles[15] = StyleCache(nsEditProperty::acronym, EmptyString(), EmptyString());
   mCachedStyles[16] = StyleCache(nsEditProperty::cssBackgroundColor, EmptyString(), EmptyString());
   mCachedStyles[17] = StyleCache(nsEditProperty::sub, EmptyString(), EmptyString());
   mCachedStyles[18] = StyleCache(nsEditProperty::sup, EmptyString(), EmptyString());
+  mRangeItem = new nsRangeStore();
 }
 
 nsHTMLEditRules::~nsHTMLEditRules()
 {
   // remove ourselves as a listener to edit actions
   // In some cases, we have already been removed by 
   // ~nsHTMLEditor, in which case we will get a null pointer here
   // which we ignore.  But this allows us to add the ability to
@@ -282,27 +283,27 @@ nsHTMLEditRules::BeforeEdit(nsEditor::Op
     nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     NS_ENSURE_SUCCESS(res, res);
   
     // get the selection start location
     nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
     PRInt32 selOffset;
     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
-    mRangeItem.startNode = selStartNode;
-    mRangeItem.startOffset = selOffset;
+    mRangeItem->startNode = selStartNode;
+    mRangeItem->startOffset = selOffset;
 
     // get the selection end location
     res = mHTMLEditor->GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
-    mRangeItem.endNode = selEndNode;
-    mRangeItem.endOffset = selOffset;
+    mRangeItem->endNode = selEndNode;
+    mRangeItem->endOffset = selOffset;
 
     // register this range with range updater to track this as we perturb the doc
-    (mHTMLEditor->mRangeUpdater).RegisterRangeItem(&mRangeItem);
+    (mHTMLEditor->mRangeUpdater).RegisterRangeItem(mRangeItem);
 
     // clear deletion state bool
     mDidDeleteSelection = false;
     
     // clear out mDocChangeRange and mUtilRange
     if(mDocChangeRange)
     {
       // clear out our accounting of what changed
@@ -356,17 +357,17 @@ nsHTMLEditRules::AfterEdit(nsEditor::Ope
   NS_PRECONDITION(mActionNesting>0, "bad action nesting!");
   nsresult res = NS_OK;
   if (!--mActionNesting)
   {
     // do all the tricky stuff
     res = AfterEditInner(action, aDirection);
 
     // free up selectionState range item
-    (mHTMLEditor->mRangeUpdater).DropRangeItem(&mRangeItem);
+    (mHTMLEditor->mRangeUpdater).DropRangeItem(mRangeItem);
 
     // Reset the contenteditable count to its previous value
     if (mRestoreContentEditableCount) {
       nsCOMPtr<nsIDOMDocument> doc = mHTMLEditor->GetDOMDocument();
       NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
       nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
       NS_ENSURE_TRUE(htmlDoc, NS_ERROR_FAILURE);
       if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
@@ -448,21 +449,23 @@ nsHTMLEditRules::AfterEditInner(nsEditor
         (action == nsEditor::kOpInsertBreak) || 
         (action == nsHTMLEditor::kOpHTMLPaste ||
         (action == nsHTMLEditor::kOpLoadHTML)))
     {
       res = AdjustWhitespace(selection);
       NS_ENSURE_SUCCESS(res, res);
       
       // also do this for original selection endpoints. 
-      nsWSRunObject(mHTMLEditor, mRangeItem.startNode, mRangeItem.startOffset).AdjustWhitespace();
+      nsWSRunObject(mHTMLEditor, mRangeItem->startNode,
+                    mRangeItem->startOffset).AdjustWhitespace();
       // we only need to handle old selection endpoint if it was different from start
-      if ((mRangeItem.startNode != mRangeItem.endNode) || (mRangeItem.startOffset != mRangeItem.endOffset))
-      {
-        nsWSRunObject(mHTMLEditor, mRangeItem.endNode, mRangeItem.endOffset).AdjustWhitespace();
+      if (mRangeItem->startNode != mRangeItem->endNode ||
+          mRangeItem->startOffset != mRangeItem->endOffset) {
+        nsWSRunObject(mHTMLEditor, mRangeItem->endNode,
+                      mRangeItem->endOffset).AdjustWhitespace();
       }
     }
     
     // if we created a new block, make sure selection lands in it
     if (mNewBlock)
     {
       res = PinSelectionToNewBlock(selection);
       mNewBlock = 0;
@@ -489,17 +492,18 @@ nsHTMLEditRules::AfterEditInner(nsEditor
       res = ReapplyCachedStyles();
       NS_ENSURE_SUCCESS(res, res);
       res = ClearCachedStyles();
       NS_ENSURE_SUCCESS(res, res);
     }    
   }
 
   res = mHTMLEditor->HandleInlineSpellCheck(action, selection, 
-                                            mRangeItem.startNode, mRangeItem.startOffset,
+                                            mRangeItem->startNode,
+                                            mRangeItem->startOffset,
                                             rangeStartParent, rangeStartOffset,
                                             rangeEndParent, rangeEndOffset);
   NS_ENSURE_SUCCESS(res, res);
 
   // detect empty doc
   res = CreateBogusNodeIfNeeded(selection);
   
   // adjust selection HINT if needed
@@ -5567,43 +5571,43 @@ nsHTMLEditRules::GetNodesForOperation(ns
 
   nsresult res = NS_OK;
   
   // bust up any inlines that cross our range endpoints,
   // but only if we are allowed to touch content.
   
   if (!aDontTouchContent)
   {
-    nsAutoTArray<nsRangeStore, 16> rangeItemArray;
+    nsTArray<nsRefPtr<nsRangeStore> > rangeItemArray;
     if (!rangeItemArray.AppendElements(rangeCount)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     NS_ASSERTION(static_cast<PRUint32>(rangeCount) == rangeItemArray.Length(),
                  "How did that happen?");
 
     // first register ranges for special editor gravity
     for (i = 0; i < rangeCount; i++)
     {
       opRange = inArrayOfRanges[0];
-      nsRangeStore *item = rangeItemArray.Elements() + i;
-      item->StoreRange(opRange);
-      mHTMLEditor->mRangeUpdater.RegisterRangeItem(item);
+      rangeItemArray[i] = new nsRangeStore();
+      rangeItemArray[i]->StoreRange(opRange);
+      mHTMLEditor->mRangeUpdater.RegisterRangeItem(rangeItemArray[i]);
       inArrayOfRanges.RemoveObjectAt(0);
     }    
     // now bust up inlines.  Safe to start at rangeCount-1, since we
     // asserted we have enough items above.
     for (i = rangeCount-1; i >= 0 && NS_SUCCEEDED(res); i--)
     {
-      res = BustUpInlinesAtRangeEndpoints(rangeItemArray[i]);
+      res = BustUpInlinesAtRangeEndpoints(*rangeItemArray[i]);
     } 
     // then unregister the ranges
     for (i = 0; i < rangeCount; i++)
     {
-      nsRangeStore *item = rangeItemArray.Elements() + i;
+      nsRangeStore* item = rangeItemArray[i];
       mHTMLEditor->mRangeUpdater.DropRangeItem(item);
       nsRefPtr<nsRange> range;
       nsresult res2 = item->GetRange(getter_AddRefs(range));
       opRange = range;
       if (NS_FAILED(res2) && NS_SUCCEEDED(res)) {
         // Remember the failure, but keep going so we make sure to unregister
         // all our range items.
         res = res2;
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -288,14 +288,14 @@ protected:
   bool                    mListenerEnabled;
   bool                    mReturnInEmptyLIKillsList;
   bool                    mDidDeleteSelection;
   bool                    mDidRangedDelete;
   bool                    mRestoreContentEditableCount;
   nsRefPtr<nsRange>       mUtilRange;
   PRUint32                mJoinOffset;  // need to remember an int across willJoin/didJoin...
   nsCOMPtr<nsIDOMNode>    mNewBlock;
-  nsRangeStore            mRangeItem;
+  nsRefPtr<nsRangeStore>  mRangeItem;
   StyleCache              mCachedStyles[SIZE_STYLE_TABLE];
 };
 
 #endif //nsHTMLEditRules_h__
 
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -643,17 +643,18 @@ nsTextEditRules::WillInsertText(nsEditor
       {
         mTimer->Cancel();
       }
       else
       {
         mTimer = do_CreateInstance("@mozilla.org/timer;1", &res);
         NS_ENSURE_SUCCESS(res, res);
       }
-      mTimer->InitWithCallback(this, 600, nsITimer::TYPE_ONE_SHOT);
+      mTimer->InitWithCallback(this, LookAndFeel::GetPasswordMaskDelay(),
+                               nsITimer::TYPE_ONE_SHOT);
     } 
     else 
     {
       FillBufWithPWChars(outString, outString->Length());
     }
   }
 
   // get the (collapsed) selection location
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -14,16 +14,17 @@
 #include "nsArrayEnumerator.h"
 #include "nsTArray.h"
 #include "nsReadableUtils.h"
 #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"
 
 static nsPermissionManager *gPermissionManager = nsnull;
 
 using mozilla::dom::ContentParent;
 using mozilla::dom::ContentChild;
 using mozilla::unused; // ha!
@@ -110,17 +111,17 @@ nsHostEntry::nsHostEntry(const nsHostEnt
  * the database is closed.
  *
  * Note: Beware that, if you hold onto a |CloseDatabaseListener| from a
  * |nsPermissionManager|, this will create a cycle.
  *
  * Note: Once the callback has been called this DeleteFromMozHostListener cannot
  * be reused.
  */
-class CloseDatabaseListener : public mozIStorageCompletionCallback
+class CloseDatabaseListener MOZ_FINAL : public mozIStorageCompletionCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
   /**
    * @param aManager The owning manager.
    * @param aRebuildOnSuccess If |true|, reinitialize the database once
    * it has been closed. Otherwise, do nothing such.
@@ -159,17 +160,17 @@ CloseDatabaseListener::Complete()
  * the database and reinitializing it.
  *
  * Note: Beware that, if you hold onto a |DeleteFromMozHostListener| from a
  * |nsPermissionManager|, this will create a cycle.
  *
  * Note: Once the callback has been called this DeleteFromMozHostListener cannot
  * be reused.
  */
-class DeleteFromMozHostListener : public mozIStorageStatementCallback
+class DeleteFromMozHostListener MOZ_FINAL : public mozIStorageStatementCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGESTATEMENTCALLBACK
 
   /**
    * @param aManager The owning manager.
    */
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -135,13 +135,21 @@ EXPORTS_mozilla/layers += ShadowLayerUti
 CPPSRCS += ShadowLayerUtilsX11.cpp
 endif #}
 
 ifdef MOZ_ENABLE_D3D10_LAYER
 EXPORTS_mozilla/layers += ShadowLayerUtilsD3D10.h
 DEFINES	+= -DMOZ_ENABLE_D3D10_LAYER
 endif
 
+# NB: Gralloc is available on other platforms that use the android GL
+# libraries, but only Gonk is able to use it reliably because Gecko
+# has full system permissions there.
+ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
+EXPORTS_mozilla/layers += ShadowLayerUtilsGralloc.h
+CPPSRCS += ShadowLayerUtilsGralloc.cpp
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS)
--- a/gfx/layers/ThebesLayerBuffer.h
+++ b/gfx/layers/ThebesLayerBuffer.h
@@ -167,16 +167,26 @@ protected:
     nsRefPtr<gfxASurface> tmp = mBuffer.forget();
     mBuffer = aBuffer;
     mBufferRect = aBufferRect;
     mBufferRotation = aBufferRotation;
     return tmp.forget();
   }
 
   /**
+   * Set the buffer only.  This is intended to be used with the
+   * shadow-layer Open/CloseDescriptor interface, to ensure we don't
+   * accidentally touch a buffer when it's not mapped.
+   */
+  void SetBuffer(gfxASurface* aBuffer)
+  {
+    mBuffer = aBuffer;
+  }
+
+  /**
    * Get a context at the specified resolution for updating |aBounds|,
    * which must be contained within a single quadrant.
    */
   already_AddRefed<gfxContext>
   GetContextForQuadrantUpdate(const nsIntRect& aBounds);
 
 private:
   bool BufferSizeOkFor(const nsIntSize& aSize)
--- a/gfx/layers/basic/BasicBuffers.cpp
+++ b/gfx/layers/basic/BasicBuffers.cpp
@@ -42,20 +42,20 @@ BasicThebesLayerBuffer::DrawTo(ThebesLay
     // Bug 599189 if there is a non-integer-translation transform in aTarget,
     // we might sample pixels outside GetEffectiveVisibleRegion(), which is wrong
     // and may cause gray lines.
     gfxUtils::ClipToRegionSnapped(aTarget, aLayer->GetEffectiveVisibleRegion());
   }
 
   // Pull out the mask surface and transform here, because the mask
   // is internal to basic layers
-  gfxMatrix maskTransform;
-  if (nsRefPtr<gfxASurface> maskSurface =
-        GetMaskSurfaceAndTransform(aMaskLayer, &maskTransform)) {
-    DrawBufferWithRotation(aTarget, aOpacity, maskSurface, &maskTransform);
+  AutoMaskData mask;
+  if (GetMaskData(aMaskLayer, &mask)) {
+    DrawBufferWithRotation(aTarget, aOpacity,
+                           mask.GetSurface(), &mask.GetTransform());
   } else {
     DrawBufferWithRotation(aTarget, aOpacity);
   }
   aTarget->Restore();
 }
 
 already_AddRefed<gfxASurface>
 BasicThebesLayerBuffer::CreateBuffer(ContentType aType, 
--- a/gfx/layers/basic/BasicBuffers.h
+++ b/gfx/layers/basic/BasicBuffers.h
@@ -53,16 +53,37 @@ public:
     oldBuffer = SetBuffer(aBuffer, aRect, aRotation);
   }
 
   void SetBackingBufferAndUpdateFrom(
     gfxASurface* aBuffer,
     gfxASurface* aSource, const nsIntRect& aRect, const nsIntPoint& aRotation,
     const nsIntRegion& aUpdateRegion);
 
+  /**
+   * When BasicThebesLayerBuffer is used with layers that hold
+   * SurfaceDescriptor, this buffer only has a valid gfxASurface in
+   * the scope of an AutoOpenSurface for that SurfaceDescriptor.  That
+   * is, it's sort of a "virtual buffer" that's only mapped an
+   * unmapped within the scope of AutoOpenSurface.  None of the
+   * underlying buffer attributes (rect, rotation) are affected by
+   * mapping/unmapping.
+   *
+   * These helpers just exist to provide more descriptive names of the
+   * map/unmap process.
+   */
+  void MapBuffer(gfxASurface* aBuffer)
+  {
+    SetBuffer(aBuffer);
+  }
+  void UnmapBuffer()
+  {
+    SetBuffer(nsnull);
+  }
+
 private:
   BasicThebesLayerBuffer(gfxASurface* aBuffer,
                          const nsIntRect& aRect, const nsIntPoint& aRotation)
     // The size policy doesn't really matter here; this constructor is
     // intended to be used for creating temporaries
     : ThebesLayerBuffer(ContainsVisibleBounds)
   {
     SetBuffer(aBuffer, aRect, aRotation);
@@ -82,28 +103,35 @@ public:
     MOZ_COUNT_CTOR(ShadowThebesLayerBuffer);
   }
 
   ~ShadowThebesLayerBuffer()
   {
     MOZ_COUNT_DTOR(ShadowThebesLayerBuffer);
   }
 
-  void Swap(gfxASurface* aNewBuffer,
-            const nsIntRect& aNewRect, const nsIntPoint& aNewRotation,
-            gfxASurface** aOldBuffer,
+  /**
+   * Swap in the old "virtual buffer" (see above) attributes in aNew*
+   * and return the old ones in aOld*.
+   *
+   * Swap() must only be called when the buffer is in its "unmapped"
+   * state, that is the underlying gfxASurface is not available.  It
+   * is expected that the owner of this buffer holds an unmapped
+   * SurfaceDescriptor as the backing storage for this buffer.  That's
+   * why no gfxASurface or SurfaceDescriptor parameters appear here.
+   */
+  void Swap(const nsIntRect& aNewRect, const nsIntPoint& aNewRotation,
             nsIntRect* aOldRect, nsIntPoint* aOldRotation)
   {
     *aOldRect = BufferRect();
     *aOldRotation = BufferRotation();
 
     nsRefPtr<gfxASurface> oldBuffer;
-    oldBuffer = SetBuffer(aNewBuffer,
-                          aNewRect, aNewRotation);
-    oldBuffer.forget(aOldBuffer);
+    oldBuffer = SetBuffer(nsnull, aNewRect, aNewRotation);
+    MOZ_ASSERT(!oldBuffer);
   }
 
 protected:
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(ContentType, const nsIntSize&, PRUint32)
   {
     NS_RUNTIMEABORT("ShadowThebesLayer can't paint content");
     return nsnull;
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -334,19 +334,18 @@ BasicShadowableCanvasLayer::Initialize(c
   BasicCanvasLayer::Initialize(aData);
   if (!HasShadow())
       return;
 
   // XXX won't get here currently; need to figure out what to do on
   // canvas resizes
 
   if (IsSurfaceDescriptorValid(mBackBuffer)) {
-    nsRefPtr<gfxASurface> backSurface =
-      BasicManager()->OpenDescriptor(mBackBuffer);
-    if (gfxIntSize(mBounds.width, mBounds.height) != backSurface->GetSize()) {
+    AutoOpenSurface backSurface(OPEN_READ_ONLY, mBackBuffer);
+    if (gfxIntSize(mBounds.width, mBounds.height) != backSurface.Size()) {
       DestroyBackBuffer();
     }
   }
 }
 
 void
 BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
 {
@@ -363,25 +362,23 @@ BasicShadowableCanvasLayer::Paint(gfxCon
     if (!BasicManager()->AllocBuffer(
         gfxIntSize(mBounds.width, mBounds.height),
         isOpaque ?
           gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA,
         &mBackBuffer))
     NS_RUNTIMEABORT("creating CanvasLayer back buffer failed!");
   }
 
-  nsRefPtr<gfxASurface> backSurface =
-    BasicManager()->OpenDescriptor(mBackBuffer);
-
+  AutoOpenSurface autoBackSurface(OPEN_READ_WRITE, mBackBuffer);
 
   if (aMaskLayer) {
     static_cast<BasicImplData*>(aMaskLayer->ImplData())
       ->Paint(aContext, nsnull);
   }
-  UpdateSurface(backSurface, nsnull);
+  UpdateSurface(autoBackSurface.Get(), nsnull);
   FireDidTransactionCallback();
 
   BasicManager()->PaintedCanvas(BasicManager()->Hold(this),
                                 mNeedsYFlip ? true : false,
                                 mBackBuffer);
 }
 
 class BasicShadowCanvasLayer : public ShadowCanvasLayer,
@@ -432,54 +429,52 @@ BasicShadowCanvasLayer::Initialize(const
 {
   NS_RUNTIMEABORT("Incompatibe surface type");
 }
 
 void
 BasicShadowCanvasLayer::Swap(const CanvasSurface& aNewFront, bool needYFlip,
                              CanvasSurface* aNewBack)
 {
-  nsRefPtr<gfxASurface> surface =
-    BasicManager()->OpenDescriptor(aNewFront);
+  AutoOpenSurface autoSurface(OPEN_READ_ONLY, aNewFront);
   // Destroy mFrontBuffer if size different
-  gfxIntSize sz = surface->GetSize();
+  gfxIntSize sz = autoSurface.Size();
   bool surfaceConfigChanged = sz != gfxIntSize(mBounds.width, mBounds.height);
   if (IsSurfaceDescriptorValid(mFrontSurface)) {
-    nsRefPtr<gfxASurface> front = BasicManager()->OpenDescriptor(mFrontSurface);
+    AutoOpenSurface autoFront(OPEN_READ_ONLY, mFrontSurface);
     surfaceConfigChanged = surfaceConfigChanged ||
-                           surface->GetContentType() != front->GetContentType();
+                           autoSurface.ContentType() != autoFront.ContentType();
   }
   if (surfaceConfigChanged) {
     DestroyFrontBuffer();
     mBounds.SetRect(0, 0, sz.width, sz.height);
   }
 
   mNeedsYFlip = needYFlip;
   // If mFrontBuffer
   if (IsSurfaceDescriptorValid(mFrontSurface)) {
     *aNewBack = mFrontSurface;
   } else {
     *aNewBack = null_t();
   }
-  mFrontSurface = aNewFront.get_SurfaceDescriptor();
+  mFrontSurface = aNewFront;
 }
 
 void
 BasicShadowCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
 
   if (!IsSurfaceDescriptorValid(mFrontSurface)) {
     return;
   }
 
-  nsRefPtr<gfxASurface> surface =
-    BasicManager()->OpenDescriptor(mFrontSurface);
-  nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
+  AutoOpenSurface autoSurface(OPEN_READ_ONLY, mFrontSurface);
+  nsRefPtr<gfxPattern> pat = new gfxPattern(autoSurface.Get());
 
   pat->SetFilter(mFilter);
   pat->SetExtend(gfxPattern::EXTEND_PAD);
 
   gfxRect r(0, 0, mBounds.width, mBounds.height);
 
   gfxMatrix m;
   if (mNeedsYFlip) {
--- a/gfx/layers/basic/BasicImageLayer.cpp
+++ b/gfx/layers/basic/BasicImageLayer.cpp
@@ -36,17 +36,18 @@ public:
   virtual void Paint(gfxContext* aContext, Layer* aMaskLayer);
 
   static void PaintContext(gfxPattern* aPattern,
                            const nsIntRegion& aVisible,
                            float aOpacity,
                            gfxContext* aContext,
                            Layer* aMaskLayer);
 
-  virtual already_AddRefed<gfxASurface> GetAsSurface();
+  virtual bool GetAsSurface(gfxASurface** aSurface,
+                            SurfaceDescriptor* aDescriptor);
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 
   // only paints the image if aContext is non-null
@@ -81,19 +82,16 @@ BasicImageLayer::GetAndPaintCurrentImage
   AutoLockImage autoLock(mContainer, getter_AddRefs(surface));
   Image *image = autoLock.GetImage();
   gfxIntSize size = mSize = autoLock.GetSize();
 
   if (!surface || surface->CairoStatus()) {
     return nsnull;
   }
 
-  NS_ASSERTION(surface->GetContentType() != gfxASurface::CONTENT_ALPHA,
-               "Image layer has alpha image");
-
   nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
   if (!pat) {
     return nsnull;
   }
 
   pat->SetFilter(mFilter);
   gfxIntSize sourceSize = surface->GetSize();
   if (mScaleMode != SCALE_NONE) {
@@ -149,25 +147,28 @@ BasicImageLayer::PaintContext(gfxPattern
   aPattern->SetExtend(extend);
   aContext->SetPattern(aPattern);
   FillWithMask(aContext, aOpacity, aMaskLayer);
 
   // Reset extend mode for callers that need to reuse the pattern
   aPattern->SetExtend(extend);
 }
 
-already_AddRefed<gfxASurface>
-BasicImageLayer::GetAsSurface()
+bool
+BasicImageLayer::GetAsSurface(gfxASurface** aSurface,
+                              SurfaceDescriptor* aDescriptor)
 {
   if (!mContainer) {
-    return nsnull;
+    return false;
   }
 
   gfxIntSize dontCare;
-  return mContainer->GetCurrentAsSurface(&dontCare);
+  nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&dontCare);
+  *aSurface = surface.forget().get();
+  return true;
 }
 
 class BasicShadowableImageLayer : public BasicImageLayer,
                                   public BasicShadowableLayer
 {
 public:
   BasicShadowableImageLayer(BasicShadowLayerManager* aManager) :
     BasicImageLayer(aManager),
@@ -191,57 +192,59 @@ public:
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
 
   virtual void SetBackBuffer(const SurfaceDescriptor& aBuffer)
   {
     mBackBuffer = aBuffer;
   }
 
-  virtual void SetBackBufferYUVImage(gfxSharedImageSurface* aYBuffer,
-                                     gfxSharedImageSurface* aUBuffer,
-                                     gfxSharedImageSurface* aVBuffer)
+  virtual void SetBackBufferYUVImage(const SurfaceDescriptor& aYBuffer,
+                                     const SurfaceDescriptor& aUBuffer,
+                                     const SurfaceDescriptor& aVBuffer)
   {
     mBackBufferY = aYBuffer;
     mBackBufferU = aUBuffer;
     mBackBufferV = aVBuffer;
   }
 
   virtual void Disconnect()
   {
-    mBackBufferY = mBackBufferU = mBackBufferV = nsnull;
+    mBackBufferY = SurfaceDescriptor();
+    mBackBufferU = SurfaceDescriptor();
+    mBackBufferV = SurfaceDescriptor();
     mBackBuffer = SurfaceDescriptor();
     BasicShadowableLayer::Disconnect();
   }
 
   void DestroyBackBuffer()
   {
     if (IsSurfaceDescriptorValid(mBackBuffer)) {
       BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBuffer);
     }
-    if (mBackBufferY) {
-      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBufferY);
-      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBufferU);
-      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBufferV);
-    }
+    if (IsSurfaceDescriptorValid(mBackBufferY)) {
+      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBufferY);
+      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBufferU);
+      BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBufferV);
+}
   }
 
 private:
   BasicShadowLayerManager* BasicManager()
   {
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
   // For YUV Images these are the 3 planes (Y, Cb and Cr),
   // for RGB images only mBackSurface is used.
   SurfaceDescriptor mBackBuffer;
   bool mBufferIsOpaque;
-  nsRefPtr<gfxSharedImageSurface> mBackBufferY;
-  nsRefPtr<gfxSharedImageSurface> mBackBufferU;
-  nsRefPtr<gfxSharedImageSurface> mBackBufferV;
+  SurfaceDescriptor mBackBufferY;
+  SurfaceDescriptor mBackBufferU;
+  SurfaceDescriptor mBackBufferV;
   gfxIntSize mCbCrSize;
 };
  
 void
 BasicShadowableImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
 {
   if (!HasShadow()) {
     BasicImageLayer::Paint(aContext, aMaskLayer);
@@ -266,48 +269,62 @@ BasicShadowableImageLayer::Paint(gfxCont
       ->Paint(aContext, nsnull);
   }
 
   if (image->GetFormat() == Image::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) {
     PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image);
     const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
     NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");
 
-    if (mSize != data->mYSize || mCbCrSize != data->mCbCrSize || !mBackBufferY) {
+    if (mSize != data->mYSize || mCbCrSize != data->mCbCrSize || !IsSurfaceDescriptorValid(mBackBufferY)) {
       DestroyBackBuffer();
       mSize = data->mYSize;
       mCbCrSize = data->mCbCrSize;
 
-      if (!BasicManager()->AllocBuffer(mSize, gfxASurface::CONTENT_ALPHA,
-                                       getter_AddRefs(mBackBufferY)) ||
-          !BasicManager()->AllocBuffer(mCbCrSize, gfxASurface::CONTENT_ALPHA,
-                                       getter_AddRefs(mBackBufferU)) ||
-          !BasicManager()->AllocBuffer(mCbCrSize, gfxASurface::CONTENT_ALPHA,
-                                       getter_AddRefs(mBackBufferV))) {
+      // We either allocate all three planes or none.
+      if (!BasicManager()->AllocBufferWithCaps(mSize,
+                                               gfxASurface::CONTENT_ALPHA,
+                                               MAP_AS_IMAGE_SURFACE,
+                                               &mBackBufferY) ||
+          !BasicManager()->AllocBufferWithCaps(mCbCrSize,
+                                               gfxASurface::CONTENT_ALPHA,
+                                               MAP_AS_IMAGE_SURFACE,
+                                               &mBackBufferU) ||
+          !BasicManager()->AllocBufferWithCaps(mCbCrSize,
+                                               gfxASurface::CONTENT_ALPHA,
+                                               MAP_AS_IMAGE_SURFACE,
+                                               &mBackBufferV)) {
         NS_RUNTIMEABORT("creating ImageLayer 'front buffer' failed!");
       }
     }
 
+    AutoOpenSurface dyas(OPEN_READ_WRITE, mBackBufferY);
+    gfxImageSurface* dy = dyas.GetAsImage();
+
     for (int i = 0; i < data->mYSize.height; i++) {
-      memcpy(mBackBufferY->Data() + i * mBackBufferY->Stride(),
+      memcpy(dy->Data() + i * dy->Stride(),
              data->mYChannel + i * data->mYStride,
              data->mYSize.width);
     }
+
+    AutoOpenSurface duas(OPEN_READ_WRITE, mBackBufferU);
+    gfxImageSurface* du = duas.GetAsImage();
+    AutoOpenSurface dvas(OPEN_READ_WRITE, mBackBufferV);
+    gfxImageSurface* dv = dvas.GetAsImage();
+
     for (int i = 0; i < data->mCbCrSize.height; i++) {
-      memcpy(mBackBufferU->Data() + i * mBackBufferU->Stride(),
+      memcpy(du->Data() + i * du->Stride(),
              data->mCbChannel + i * data->mCbCrStride,
              data->mCbCrSize.width);
-      memcpy(mBackBufferV->Data() + i * mBackBufferV->Stride(),
+      memcpy(dv->Data() + i * dv->Stride(),
              data->mCrChannel + i * data->mCbCrStride,
              data->mCbCrSize.width);
     }
 
-    YUVImage yuv(mBackBufferY->GetShmem(),
-                 mBackBufferU->GetShmem(),
-                 mBackBufferV->GetShmem(),
+    YUVImage yuv(mBackBufferY, mBackBufferU, mBackBufferV,
                  data->GetPictureRect());
 
     BasicManager()->PaintedImage(BasicManager()->Hold(this),
                                  yuv);
     return;
   }
 
   gfxIntSize oldSize = mSize;
@@ -331,19 +348,18 @@ BasicShadowableImageLayer::Paint(gfxCont
         isOpaque) {
       type = gfxASurface::CONTENT_COLOR;
     }
 
     if (!BasicManager()->AllocBuffer(mSize, type, &mBackBuffer))
       NS_RUNTIMEABORT("creating ImageLayer 'front buffer' failed!");
   }
 
-  nsRefPtr<gfxASurface> backSurface =
-    BasicManager()->OpenDescriptor(mBackBuffer);
-  nsRefPtr<gfxContext> tmpCtx = new gfxContext(backSurface);
+  AutoOpenSurface backSurface(OPEN_READ_WRITE, mBackBuffer);
+  nsRefPtr<gfxContext> tmpCtx = new gfxContext(backSurface.Get());
   tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
   PaintContext(pat,
                nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)),
                1.0, tmpCtx, nsnull);
 
   BasicManager()->PaintedImage(BasicManager()->Hold(this),
                                mBackBuffer);
 }
@@ -372,84 +388,85 @@ public:
   virtual void DestroyFrontBuffer()
   {
     if (mAllocator && IsSurfaceDescriptorValid(mFrontBuffer)) {
       mAllocator->DestroySharedSurface(&mFrontBuffer);
     }
   }
 
   virtual void Paint(gfxContext* aContext, Layer* aMaskLayer);
-  already_AddRefed<gfxASurface> GetAsSurface();
+  virtual bool GetAsSurface(gfxASurface** aSurface,
+                            SurfaceDescriptor* aDescriptor);
 
 protected:
   BasicShadowLayerManager* BasicManager()
   {
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
   SurfaceDescriptor mFrontBuffer;
   gfxIntSize mSize;
 };
 
 void
 BasicShadowImageLayer::Swap(const SharedImage& aNewFront,
                             SharedImage* aNewBack)
 {
-  nsRefPtr<gfxASurface> surface =
-    BasicManager()->OpenDescriptor(aNewFront);
+  AutoOpenSurface autoSurface(OPEN_READ_ONLY, aNewFront);
   // Destroy mFrontBuffer if size different or image type is different
-  bool surfaceConfigChanged = surface->GetSize() != mSize;
+  bool surfaceConfigChanged = autoSurface.Size() != mSize;
   if (IsSurfaceDescriptorValid(mFrontBuffer)) {
-    nsRefPtr<gfxASurface> front = BasicManager()->OpenDescriptor(mFrontBuffer);
+    AutoOpenSurface autoFront(OPEN_READ_ONLY, mFrontBuffer);
     surfaceConfigChanged = surfaceConfigChanged ||
-                           surface->GetContentType() != front->GetContentType();
+                           autoSurface.ContentType() != autoFront.ContentType();
   }
   if (surfaceConfigChanged) {
     DestroyFrontBuffer();
-    mSize = surface->GetSize();
+    mSize = autoSurface.Size();
   }
 
   // If mFrontBuffer
   if (IsSurfaceDescriptorValid(mFrontBuffer)) {
     *aNewBack = mFrontBuffer;
   } else {
     *aNewBack = null_t();
   }
-  mFrontBuffer = aNewFront.get_SurfaceDescriptor();
+  mFrontBuffer = aNewFront;
 }
 
 void
 BasicShadowImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
 {
   if (!IsSurfaceDescriptorValid(mFrontBuffer)) {
     return;
   }
 
-  nsRefPtr<gfxASurface> surface =
-    BasicManager()->OpenDescriptor(mFrontBuffer);
-  nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
+  AutoOpenSurface autoSurface(OPEN_READ_ONLY, mFrontBuffer);
+  nsRefPtr<gfxPattern> pat = new gfxPattern(autoSurface.Get());
   pat->SetFilter(mFilter);
 
   // The visible region can extend outside the image, so just draw
   // within the image bounds.
   AutoSetOperator setOperator(aContext, GetOperator());
   BasicImageLayer::PaintContext(pat,
                                 nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height)),
                                 GetEffectiveOpacity(), aContext,
                                 aMaskLayer);
 }
 
-already_AddRefed<gfxASurface>
-BasicShadowImageLayer::GetAsSurface()
+bool
+BasicShadowImageLayer::GetAsSurface(gfxASurface** aSurface,
+                                    SurfaceDescriptor* aDescriptor)
 {
   if (!IsSurfaceDescriptorValid(mFrontBuffer)) {
-    return nsnull;
+    return false;
   }
 
-  return BasicManager()->OpenDescriptor(mFrontBuffer);
+  *aDescriptor = mFrontBuffer;
+  return true;
  }
 
 already_AddRefed<ImageLayer>
 BasicLayerManager::CreateImageLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ImageLayer> layer = new BasicImageLayer(this);
   return layer.forget();
--- a/gfx/layers/basic/BasicImplData.h
+++ b/gfx/layers/basic/BasicImplData.h
@@ -96,21 +96,24 @@ public:
                  aOperator == gfxContext::OPERATOR_SOURCE,
                  "Bad composition operator");
     mOperator = aOperator;
   }
   gfxContext::GraphicsOperator GetOperator() const { return mOperator; }
 
   /**
    * Return a surface for this layer. Will use an existing surface, if
-   * possible, or may create a temporary surface.
-   * Implement this method for any layers that might be used as a mask.
-   * Should only return null if a surface cannor be created.
+   * possible, or may create a temporary surface.  Implement this
+   * method for any layers that might be used as a mask.  Should only
+   * return false if a surface cannot be created.  If true is
+   * returned, only one of |aSurface| or |aDescriptor| is valid.
    */
-  virtual already_AddRefed<gfxASurface> GetAsSurface() { return nsnull; }
+  virtual bool GetAsSurface(gfxASurface** aSurface,
+                            SurfaceDescriptor* aDescriptor)
+  { return false; }
 
   bool GetClipToVisibleRegion() { return mClipToVisibleRegion; }
   void SetClipToVisibleRegion(bool aClip) { mClipToVisibleRegion = aClip; }
 
   void SetDrawAtomically(bool aDrawAtomically) { mDrawAtomically = aDrawAtomically; }
 
 protected:
   bool mHidden;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -5,16 +5,17 @@
 
 #include "mozilla/layers/PLayerChild.h"
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layers/PLayersParent.h"
 
 #include "gfxSharedImageSurface.h"
 #include "gfxImageSurface.h"
 #include "gfxUtils.h"
+#include "nsXULAppAPI.h"
 #include "RenderTrace.h"
 #include "sampler.h"
 
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"
 
 #include "BasicTiledThebesLayer.h"
 #include "BasicLayersImpl.h"
@@ -834,17 +835,16 @@ BasicLayerManager::PaintLayer(gfxContext
     // intersect any other leaf layers, so if the transaction is not yet marked
     // incomplete, the contents of this container layer are the final contents
     // for the window.
     if (!mTransactionIncomplete && !blitComplete) {
       if (needsClipToVisibleRegion) {
         gfxUtils::ClipToRegion(aTarget, aLayer->GetEffectiveVisibleRegion());
       }
       AutoSetOperator setOperator(aTarget, container->GetOperator());
-      gfxMatrix temp = aTarget->CurrentMatrix();
       PaintWithMask(aTarget, aLayer->GetEffectiveOpacity(),
                     HasShadowManager() ? nsnull : aLayer->GetMaskLayer());
     }
   }
 
   if (pushedTargetOpaqueRect) {
     if (aTarget->IsCairo()) {
       currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0));
@@ -946,17 +946,18 @@ BasicShadowLayerManager::BeginTransactio
   // If the last transaction was incomplete (a failed DoEmptyTransaction),
   // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
   // to the previous transaction.
   if (HasShadowManager()) {
     ShadowLayerForwarder::BeginTransaction();
 
     // If we have a non-default target, we need to let our shadow manager draw
     // to it. This will happen at the end of the transaction.
-    if (aTarget && (aTarget != mDefaultTarget)) {
+    if (aTarget && (aTarget != mDefaultTarget) &&
+        XRE_GetProcessType() == GeckoProcessType_Default) {
       mShadowTarget = aTarget;
 
       // Create a temporary target for ourselves, so that mShadowTarget is only
       // drawn to by our shadow manager.
       nsRefPtr<gfxASurface> targetSurface = gfxPlatform::GetPlatform()->
         CreateOffscreenSurface(aTarget->OriginalSurface()->GetSize(),
                                aTarget->OriginalSurface()->GetContentType());
       targetContext = new gfxContext(targetSurface);
@@ -1043,23 +1044,22 @@ BasicShadowLayerManager::ForwardTransact
         const OpImageSwap& ois = reply.get_OpImageSwap();
         BasicShadowableLayer* layer = GetBasicShadowable(ois);
         const SharedImage& newBack = ois.newBackImage();
 
         if (newBack.type() == SharedImage::TSurfaceDescriptor) {
           layer->SetBackBuffer(newBack.get_SurfaceDescriptor());
         } else if (newBack.type() == SharedImage::TYUVImage) {
           const YUVImage& yuv = newBack.get_YUVImage();
-          nsRefPtr<gfxSharedImageSurface> YSurf = gfxSharedImageSurface::Open(yuv.Ydata());
-          nsRefPtr<gfxSharedImageSurface> USurf = gfxSharedImageSurface::Open(yuv.Udata());
-          nsRefPtr<gfxSharedImageSurface> VSurf = gfxSharedImageSurface::Open(yuv.Vdata());
-          layer->SetBackBufferYUVImage(YSurf, USurf, VSurf);
+          layer->SetBackBufferYUVImage(yuv.Ydata(), yuv.Udata(), yuv.Vdata());
         } else {
           layer->SetBackBuffer(SurfaceDescriptor());
-          layer->SetBackBufferYUVImage(nsnull, nsnull, nsnull);
+          layer->SetBackBufferYUVImage(SurfaceDescriptor(),
+                                       SurfaceDescriptor(),
+                                       SurfaceDescriptor());
         }
 
         break;
       }
 
       default:
         NS_RUNTIMEABORT("not reached");
       }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -274,21 +274,21 @@ public:
     mShadow = aShadow;
   }
 
   virtual void SetBackBuffer(const SurfaceDescriptor& aBuffer)
   {
     NS_RUNTIMEABORT("if this default impl is called, |aBuffer| leaks");
   }
   
-  virtual void SetBackBufferYUVImage(gfxSharedImageSurface* aYBuffer,
-                                     gfxSharedImageSurface* aUBuffer,
-                                     gfxSharedImageSurface* aVBuffer)
+  virtual void SetBackBufferYUVImage(const SurfaceDescriptor& aYBuffer,
+                                     const SurfaceDescriptor& aUBuffer,
+                                     const SurfaceDescriptor& aVBuffer)
   {
-    NS_RUNTIMEABORT("if this default impl is called, |aBuffer| leaks");
+    NS_RUNTIMEABORT("if this default impl is called, the buffers leak");
   }
 
   virtual void Disconnect()
   {
     // This is an "emergency Disconnect()", called when the compositing
     // process has died.  |mShadow| and our Shmem buffers are
     // automatically managed by IPDL, so we don't need to explicitly
     // free them here (it's hard to get that right on emergency
--- a/gfx/layers/basic/BasicLayersImpl.cpp
+++ b/gfx/layers/basic/BasicLayersImpl.cpp
@@ -1,73 +1,122 @@
 /* -*- 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 "BasicLayersImpl.h"
+#include "mozilla/layers/PLayers.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
-already_AddRefed<gfxASurface>
-GetMaskSurfaceAndTransform(Layer* aMaskLayer, gfxMatrix* aMaskTransform)
+void
+AutoMaskData::Construct(const gfxMatrix& aTransform,
+                        gfxASurface* aSurface)
+{
+  MOZ_ASSERT(!IsConstructed());
+  mTransform = aTransform;
+  mSurface = aSurface;
+}
+
+void
+AutoMaskData::Construct(const gfxMatrix& aTransform,
+                        const SurfaceDescriptor& aSurface)
+{
+  MOZ_ASSERT(!IsConstructed());
+  mTransform = aTransform;
+  mSurfaceOpener.construct(OPEN_READ_ONLY, aSurface);
+}
+
+gfxASurface*
+AutoMaskData::GetSurface()
+{
+  MOZ_ASSERT(IsConstructed());
+  if (mSurface) {
+    return mSurface.get();
+  }
+  return mSurfaceOpener.ref().Get();
+}
+
+const gfxMatrix&
+AutoMaskData::GetTransform()
 {
-   if (aMaskLayer) {
-     nsRefPtr<gfxASurface> maskSurface =
-       static_cast<BasicImplData*>(aMaskLayer->ImplData())->GetAsSurface();
-     if (maskSurface) {
-       bool maskIs2D =
-         aMaskLayer->GetEffectiveTransform().CanDraw2D(aMaskTransform);
-       NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
-       return maskSurface.forget();
-     }
-   }
-   return nsnull;
+  MOZ_ASSERT(IsConstructed());
+  return mTransform;
+}
+
+bool
+AutoMaskData::IsConstructed()
+{
+  return !!mSurface || !mSurfaceOpener.empty();
+}
+
+
+bool
+GetMaskData(Layer* aMaskLayer, AutoMaskData* aMaskData)
+{
+  if (aMaskLayer) {
+    nsRefPtr<gfxASurface> surface;
+    SurfaceDescriptor descriptor;
+    if (static_cast<BasicImplData*>(aMaskLayer->ImplData())
+        ->GetAsSurface(getter_AddRefs(surface), &descriptor) &&
+        (surface || IsSurfaceDescriptorValid(descriptor))) {
+      gfxMatrix transform;
+      DebugOnly<bool> maskIs2D =
+        aMaskLayer->GetEffectiveTransform().CanDraw2D(&transform);
+      NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
+      if (surface) {
+        aMaskData->Construct(transform, surface);
+      } else {
+        aMaskData->Construct(transform, descriptor);
+      }
+      return true;
+    }
+  }
+  return false;
 }
 
 void
 PaintWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer)
 {
-  gfxMatrix maskTransform;
-  if (nsRefPtr<gfxASurface> maskSurface =
-        GetMaskSurfaceAndTransform(aMaskLayer, &maskTransform)) {
+  AutoMaskData mask;
+  if (GetMaskData(aMaskLayer, &mask)) {
     if (aOpacity < 1.0) {
       aContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
       aContext->Paint(aOpacity);
       aContext->PopGroupToSource();
     }
-    aContext->SetMatrix(maskTransform);
-    aContext->Mask(maskSurface);
+    aContext->SetMatrix(mask.GetTransform());
+    aContext->Mask(mask.GetSurface());
     return;
   }
 
   // if there is no mask, just paint normally
   aContext->Paint(aOpacity);
 }
 
 void
 FillWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer)
 {
-  gfxMatrix maskTransform;
-  if (nsRefPtr<gfxASurface> maskSurface =
-        GetMaskSurfaceAndTransform(aMaskLayer, &maskTransform)) {
+  AutoMaskData mask;
+  if (GetMaskData(aMaskLayer, &mask)) {
     if (aOpacity < 1.0) {
       aContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
       aContext->FillWithOpacity(aOpacity);
       aContext->PopGroupToSource();
-      aContext->SetMatrix(maskTransform);
-      aContext->Mask(maskSurface);
+      aContext->SetMatrix(mask.GetTransform());
+      aContext->Mask(mask.GetSurface());
     } else {
       aContext->Save();
       aContext->Clip();
-      aContext->SetMatrix(maskTransform);
-      aContext->Mask(maskSurface);
+      aContext->SetMatrix(mask.GetTransform());
+      aContext->Mask(mask.GetSurface());
       aContext->NewPath();
       aContext->Restore();
     }
     return;
   }
 
   // if there is no mask, just fill normally
   aContext->FillWithOpacity(aOpacity);
--- a/gfx/layers/basic/BasicLayersImpl.h
+++ b/gfx/layers/basic/BasicLayersImpl.h
@@ -1,16 +1,17 @@
 /* -*- 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_BASICLAYERSIMPL_H
 #define GFX_BASICLAYERSIMPL_H
 
+#include "ipc/AutoOpenSurface.h"
 #include "ipc/ShadowLayerChild.h"
 #include "BasicLayers.h"
 #include "BasicImplData.h"
 #include "ReadbackProcessor.h"
 
 namespace mozilla {
 namespace layers {
 
@@ -57,24 +58,68 @@ public:
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 };
 
+/**
+ * Drawing with a mask requires a mask surface and a transform.
+ * Sometimes the mask surface is a direct gfxASurface, but other times
+ * it's a SurfaceDescriptor.  For SurfaceDescriptor, we need to use a
+ * scoped AutoOpenSurface to get a gfxASurface for the
+ * SurfaceDescriptor.
+ *
+ * This helper class manages the gfxASurface-or-SurfaceDescriptor
+ * logic.
+ */
+class NS_STACK_CLASS AutoMaskData {
+public:
+  AutoMaskData() { }
+  ~AutoMaskData() { }
+
+  /**
+   * Construct this out of either a gfxASurface or a
+   * SurfaceDescriptor.  Construct() must only be called once.
+   * GetSurface() and GetTransform() must not be called until this has
+   * been constructed.
+   */
+
+  void Construct(const gfxMatrix& aTransform,
+                 gfxASurface* aSurface);
+
+  void Construct(const gfxMatrix& aTransform,
+                 const SurfaceDescriptor& aSurface);
+
+  /** The returned surface can't escape the scope of |this|. */
+  gfxASurface* GetSurface();
+  const gfxMatrix& GetTransform();
+
+private:
+  bool IsConstructed();
+
+  gfxMatrix mTransform;
+  nsRefPtr<gfxASurface> mSurface;
+  Maybe<AutoOpenSurface> mSurfaceOpener;
+
+  AutoMaskData(const AutoMaskData&) MOZ_DELETE;
+  AutoMaskData& operator=(const AutoMaskData&) MOZ_DELETE;
+};
+
 /*
  * Extract a mask surface for a mask layer
- * Returns a surface for the mask layer if a mask layer is present and has a
- * valid surface and transform; nsnull otherwise.
- * The transform for the layer will be put in aMaskTransform
+ * Returns true and through outparams a surface for the mask layer if
+ * a mask layer is present and has a valid surface and transform;
+ * false otherwise.
+ * The transform for the layer will be put in aMaskData
  */
-already_AddRefed<gfxASurface>
-GetMaskSurfaceAndTransform(Layer* aMaskLayer, gfxMatrix* aMaskTransform);
+bool
+GetMaskData(Layer* aMaskLayer, AutoMaskData* aMaskData);
 
 // Paint the current source to a context using a mask, if present
 void
 PaintWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer);
 
 // Fill the current path with the current source, using a
 // mask and opacity, if present
 void
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -223,28 +223,82 @@ BasicThebesLayer::PaintThebes(gfxContext
       NS_ASSERTION(opacity == 1.0, "Should only read back opaque layers");
       ctx->Translate(gfxPoint(offset.x, offset.y));
       mBuffer.DrawTo(this, ctx, 1.0, aMaskLayer);
       update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset);
     }
   }
 }
 
+/**
+ * AutoOpenBuffer is a helper that builds on top of AutoOpenSurface,
+ * which we need to get a gfxASurface from a SurfaceDescriptor.  For
+ * other layer types, simple lexical scoping of AutoOpenSurface is
+ * easy.  For ThebesLayers, the lifetime of buffer mappings doesn't
+ * exactly match simple lexical scopes, so naively putting
+ * AutoOpenSurfaces on the stack doesn't always work.  We use this
+ * helper to track openings instead.
+ *
+ * Any surface that's opened while painting this ThebesLayer will
+ * notify this helper and register itself for unmapping.
+ *
+ * We ignore buffer destruction here because the shadow layers
+ * protocol already ensures that destroyed buffers stay alive until
+ * end-of-transaction.
+ */
+struct NS_STACK_CLASS AutoBufferTracker {
+  AutoBufferTracker(BasicShadowableThebesLayer* aLayer)
+    : mLayer(aLayer)
+  {
+    MOZ_ASSERT(!mLayer->mBufferTracker);
+
+    mLayer->mBufferTracker = this;
+    if (IsSurfaceDescriptorValid(mLayer->mBackBuffer)) {
+      mInitialBuffer.construct(OPEN_READ_WRITE, mLayer->mBackBuffer);
+      mLayer->mBuffer.MapBuffer(mInitialBuffer.ref().Get());
+    }
+  }
+
+  ~AutoBufferTracker() {
+    mLayer->mBufferTracker = nsnull;
+    mLayer->mBuffer.UnmapBuffer();
+    // mInitialBuffer and mNewBuffer will clean up after themselves if
+    // they were constructed.
+  }
+
+  gfxASurface*
+  CreatedBuffer(const SurfaceDescriptor& aDescriptor) {
+    Maybe<AutoOpenSurface>* surface = mNewBuffers.AppendElement();
+    surface->construct(OPEN_READ_WRITE, aDescriptor);
+    return surface->ref().Get();
+  }
+
+  Maybe<AutoOpenSurface> mInitialBuffer;
+  nsAutoTArray<Maybe<AutoOpenSurface>, 2> mNewBuffers;
+  BasicShadowableThebesLayer* mLayer;
+
+private:
+  AutoBufferTracker(const AutoBufferTracker&) MOZ_DELETE;
+  AutoBufferTracker& operator=(const AutoBufferTracker&) MOZ_DELETE;
+};
+
 void
 BasicShadowableThebesLayer::PaintThebes(gfxContext* aContext,
                                         Layer* aMaskLayer,
                                         LayerManager::DrawThebesLayerCallback aCallback,
                                         void* aCallbackData,
                                         ReadbackProcessor* aReadback)
 {
   if (!HasShadow()) {
     BasicThebesLayer::PaintThebes(aContext, aMaskLayer, aCallback, aCallbackData, aReadback);
     return;
   }
 
+  AutoBufferTracker tracker(this);
+
   BasicThebesLayer::PaintThebes(aContext, nsnull, aCallback, aCallbackData, aReadback);
   if (aMaskLayer) {
     static_cast<BasicImplData*>(aMaskLayer->ImplData())
       ->Paint(aContext, nsnull);
   }
 }
 
 
@@ -275,28 +329,32 @@ BasicShadowableThebesLayer::SetBackBuffe
 
 void
 BasicShadowableThebesLayer::SyncFrontBufferToBackBuffer()
 {
   if (!mFrontAndBackBufferDiffer) {
     return;
   }
 
-  nsRefPtr<gfxASurface> backBuffer;
+  gfxASurface* backBuffer = mBuffer.GetBuffer();
   if (!IsSurfaceDescriptorValid(mBackBuffer)) {
-    NS_ABORT_IF_FALSE(mROFrontBuffer.type() == OptionalThebesBuffer::TThebesBuffer,
-                      "should have a front RO buffer by now");
+    MOZ_ASSERT(!backBuffer);
+    MOZ_ASSERT(mROFrontBuffer.type() == OptionalThebesBuffer::TThebesBuffer);
     const ThebesBuffer roFront = mROFrontBuffer.get_ThebesBuffer();
-    nsRefPtr<gfxASurface> roFrontBuffer = BasicManager()->OpenDescriptor(roFront.buffer());
-    backBuffer = CreateBuffer(roFrontBuffer->GetContentType(), roFrontBuffer->GetSize());
-  } else {
-    backBuffer = BasicManager()->OpenDescriptor(mBackBuffer);
+    AutoOpenSurface roFrontBuffer(OPEN_READ_ONLY, roFront.buffer());
+    AllocBackBuffer(roFrontBuffer.ContentType(), roFrontBuffer.Size());
   }
   mFrontAndBackBufferDiffer = false;
 
+  Maybe<AutoOpenSurface> autoBackBuffer;
+  if (!backBuffer) {
+    autoBackBuffer.construct(OPEN_READ_WRITE, mBackBuffer);
+    backBuffer = autoBackBuffer.ref().Get();
+  }
+
   if (OptionalThebesBuffer::Tnull_t == mROFrontBuffer.type()) {
     // We didn't get back a read-only ref to our old back buffer (the
     // parent's new front buffer).  If the parent is pushing updates
     // to a texture it owns, then we probably got back the same buffer
     // we pushed in the update and all is well.  If not, ...
     mValidRegion = mFrontValidRegion;
     mBuffer.SetBackingBuffer(backBuffer, mBackBufferRect, mBackBufferRectRotation);
     return;
@@ -305,20 +363,20 @@ BasicShadowableThebesLayer::SyncFrontBuf
   MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
                   this,
                   mFrontUpdatedRegion.GetBounds().x,
                   mFrontUpdatedRegion.GetBounds().y,
                   mFrontUpdatedRegion.GetBounds().width,
                   mFrontUpdatedRegion.GetBounds().height));
 
   const ThebesBuffer roFront = mROFrontBuffer.get_ThebesBuffer();
-  nsRefPtr<gfxASurface> roFrontBuffer = BasicManager()->OpenDescriptor(roFront.buffer());
+  AutoOpenSurface autoROFront(OPEN_READ_ONLY, roFront.buffer());
   mBuffer.SetBackingBufferAndUpdateFrom(
     backBuffer,
-    roFrontBuffer, roFront.rect(), roFront.rotation(),
+    autoROFront.Get(), roFront.rect(), roFront.rotation(),
     mFrontUpdatedRegion);
   mIsNewBuffer = false;
   // Now the new back buffer has the same (interesting) pixels as the
   // new front buffer, and mValidRegion et al. are correct wrt the new
   // back buffer (i.e. as they were for the old back buffer)
 }
 
 void
@@ -359,16 +417,33 @@ BasicShadowableThebesLayer::PaintBuffer(
                     "should have a back buffer by now");
   BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this),
                                       updatedRegion,
                                       mBuffer.BufferRect(),
                                       mBuffer.BufferRotation(),
                                       mBackBuffer);
 }
 
+void
+BasicShadowableThebesLayer::AllocBackBuffer(Buffer::ContentType aType,
+                                            const nsIntSize& aSize)
+{
+  // This function may *not* open the buffer it allocates.
+  if (!BasicManager()->AllocBuffer(gfxIntSize(aSize.width, aSize.height),
+                                   aType,
+                                   &mBackBuffer)) {
+    enum { buflen = 256 };
+    char buf[buflen];
+    PR_snprintf(buf, buflen,
+                "creating ThebesLayer 'back buffer' failed! width=%d, height=%d, type=%x",
+                aSize.width, aSize.height, int(aType));
+    NS_RUNTIMEABORT(buf);
+  }
+}
+
 already_AddRefed<gfxASurface>
 BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType,
                                          const nsIntSize& aSize)
 {
   if (!HasShadow()) {
     return BasicThebesLayer::CreateBuffer(aType, aSize);
   }
 
@@ -377,34 +452,25 @@ BasicShadowableThebesLayer::CreateBuffer
                   aSize.width, aSize.height));
 
   if (IsSurfaceDescriptorValid(mBackBuffer)) {
     BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this),
                                           mBackBuffer);
     mBackBuffer = SurfaceDescriptor();
   }
 
-  // XXX error handling
-  if (!BasicManager()->AllocBuffer(gfxIntSize(aSize.width, aSize.height),
-                                   aType,
-                                   &mBackBuffer)) {
-      enum { buflen = 256 };
-      char buf[buflen];
-      PR_snprintf(buf, buflen,
-                  "creating ThebesLayer 'back buffer' failed! width=%d, height=%d, type=%x",
-                  aSize.width, aSize.height, int(aType));
-      NS_RUNTIMEABORT(buf);
-  }
+  AllocBackBuffer(aType, aSize);
 
   NS_ABORT_IF_FALSE(!mIsNewBuffer,
                     "Bad! Did we create a buffer twice without painting?");
 
   mIsNewBuffer = true;
 
-  return BasicManager()->OpenDescriptor(mBackBuffer);
+  nsRefPtr<gfxASurface> buffer = mBufferTracker->CreatedBuffer(mBackBuffer);
+  return buffer.forget();
 }
 
 void
 BasicShadowableThebesLayer::Disconnect()
 {
   mBackBuffer = SurfaceDescriptor();
   BasicShadowableLayer::Disconnect();
 }
@@ -478,43 +544,40 @@ private:
 void
 BasicShadowThebesLayer::Swap(const ThebesBuffer& aNewFront,
                              const nsIntRegion& aUpdatedRegion,
                              OptionalThebesBuffer* aNewBack,
                              nsIntRegion* aNewBackValidRegion,
                              OptionalThebesBuffer* aReadOnlyFront,
                              nsIntRegion* aFrontUpdatedRegion)
 {
-  nsRefPtr<gfxASurface> newFrontBuffer =
-    BasicManager()->OpenDescriptor(aNewFront.buffer());
-
   if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
-    nsRefPtr<gfxASurface> currentFront = BasicManager()->OpenDescriptor(mFrontBufferDescriptor);
-    if (currentFront->GetSize() != newFrontBuffer->GetSize()) {
+    AutoOpenSurface autoNewFrontBuffer(OPEN_READ_ONLY, aNewFront.buffer());
+    AutoOpenSurface autoCurrentFront(OPEN_READ_ONLY, mFrontBufferDescriptor);
+    if (autoCurrentFront.Size() != autoNewFrontBuffer.Size()) {
       // Current front buffer is obsolete
       DestroyFrontBuffer();
     }
   }
   // This code relies on Swap() arriving *after* attribute mutations.
   if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
     *aNewBack = ThebesBuffer();
     aNewBack->get_ThebesBuffer().buffer() = mFrontBufferDescriptor;
   } else {
     *aNewBack = null_t();
   }
   // We have to invalidate the pixels painted into the new buffer.
   // They might overlap with our old pixels.
   aNewBackValidRegion->Sub(mOldValidRegion, aUpdatedRegion);
 
-  nsRefPtr<gfxASurface> unused;
   nsIntRect backRect;
   nsIntPoint backRotation;
   mFrontBuffer.Swap(
-    newFrontBuffer, aNewFront.rect(), aNewFront.rotation(),
-    getter_AddRefs(unused), &backRect, &backRotation);
+    aNewFront.rect(), aNewFront.rotation(),
+    &backRect, &backRotation);
 
   if (aNewBack->type() != OptionalThebesBuffer::Tnull_t) {
     aNewBack->get_ThebesBuffer().rect() = backRect;
     aNewBack->get_ThebesBuffer().rotation() = backRotation;
   }
 
   mFrontBufferDescriptor = aNewFront.buffer();
 
@@ -529,21 +592,26 @@ BasicShadowThebesLayer::PaintThebes(gfxC
                                     void* aCallbackData,
                                     ReadbackProcessor* aReadback)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
   NS_ASSERTION(BasicManager()->IsRetained(),
                "ShadowThebesLayer makes no sense without retained mode");
 
-  if (!mFrontBuffer.GetBuffer()) {
+  if (!IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
     return;
   }
 
+  AutoOpenSurface autoFrontBuffer(OPEN_READ_ONLY, mFrontBufferDescriptor);
+  mFrontBuffer.MapBuffer(autoFrontBuffer.Get());
+
   mFrontBuffer.DrawTo(this, aContext, GetEffectiveOpacity(), aMaskLayer);
+
+  mFrontBuffer.UnmapBuffer();
 }
 
 already_AddRefed<ThebesLayer>
 BasicLayerManager::CreateThebesLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ThebesLayer> layer = new BasicThebesLayer(this);
   return layer.forget();
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -98,24 +98,29 @@ protected:
     nsIntRegion tmp;
     tmp.Or(mVisibleRegion, aExtendedRegionToDraw);
     mValidRegion.Or(mValidRegion, tmp);
   }
 
   Buffer mBuffer;
 };
 
+struct AutoBufferTracker;
+
 class BasicShadowableThebesLayer : public BasicThebesLayer,
                                    public BasicShadowableLayer
 {
+  friend struct AutoBufferTracker;
+
   typedef BasicThebesLayer Base;
 
 public:
   BasicShadowableThebesLayer(BasicShadowLayerManager* aManager)
     : BasicThebesLayer(aManager)
+    , mBufferTracker(nsnull)
     , mIsNewBuffer(false)
     , mFrontAndBackBufferDiffer(false)
   {
     MOZ_COUNT_CTOR(BasicShadowableThebesLayer);
   }
   virtual ~BasicShadowableThebesLayer()
   {
     DestroyBackBuffer();
@@ -158,16 +163,20 @@ private:
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
               bool aDidSelfCopy,
               LayerManager::DrawThebesLayerCallback aCallback,
               void* aCallbackData) MOZ_OVERRIDE;
 
+  // This function may *not* open the buffer it allocates.
+  void
+  AllocBackBuffer(Buffer::ContentType aType, const nsIntSize& aSize);
+
   virtual already_AddRefed<gfxASurface>
   CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize) MOZ_OVERRIDE;
 
   void DestroyBackBuffer()
   {
     if (IsSurfaceDescriptorValid(mBackBuffer)) {
       BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBuffer);
     }
@@ -175,16 +184,22 @@ private:
 
   // This describes the gfxASurface we hand to mBuffer.  We keep a
   // copy of the descriptor here so that we can call
   // DestroySharedSurface() on the descriptor.
   SurfaceDescriptor mBackBuffer;
   nsIntRect mBackBufferRect;
   nsIntPoint mBackBufferRectRotation;
 
+  // This helper object lives on the stack during its lifetime and
+  // keeps track of buffers we might have mapped and/or allocated.
+  // When it goes out of scope on the stack, it unmaps whichever
+  // buffers have been mapped (if any).
+  AutoBufferTracker* mBufferTracker;
+
   bool mIsNewBuffer;
   OptionalThebesBuffer mROFrontBuffer;
   nsIntRegion mFrontUpdatedRegion;
   nsIntRegion mFrontValidRegion;
   PRPackedBool mFrontAndBackBufferDiffer;
 };
 
 }
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -1,14 +1,15 @@
 /* -*- 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/. */
 
 
+#include "ipc/AutoOpenSurface.h"
 #include "mozilla/layers/PLayers.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "ShadowBufferD3D9.h"
 
 #include "gfxImageSurface.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsPlatform.h"
 
@@ -306,22 +307,21 @@ ShadowCanvasLayerD3D9::Init(bool needYFl
 void
 ShadowCanvasLayerD3D9::Swap(const CanvasSurface& aNewFront,
                             bool needYFlip,
                             CanvasSurface* aNewBack)
 {
   NS_ASSERTION(aNewFront.type() == CanvasSurface::TSurfaceDescriptor, 
     "ShadowCanvasLayerD3D9::Swap expected CanvasSurface surface");
 
-  nsRefPtr<gfxASurface> surf = 
-    ShadowLayerForwarder::OpenDescriptor(aNewFront);
+  AutoOpenSurface surf(OPEN_READ_ONLY, aNewFront);
   if (!mBuffer) {
     Init(needYFlip);
   }
-  mBuffer->Upload(surf, GetVisibleRegion().GetBounds());
+  mBuffer->Upload(surf.Get(), GetVisibleRegion().GetBounds());
 
   *aNewBack = aNewFront;
 }
 
 void
 ShadowCanvasLayerD3D9::DestroyFrontBuffer()
 {
   Destroy();
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -1,13 +1,14 @@
 /* -*- 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/. */
 
+#include "ipc/AutoOpenSurface.h"
 #include "mozilla/layers/PLayers.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "ShadowBufferD3D9.h"
 #include "gfxSharedImageSurface.h"
 
 #include "ImageLayerD3D9.h"
 #include "ThebesLayerD3D9.h"
 #include "gfxPlatform.h"
@@ -546,29 +547,27 @@ ShadowImageLayerD3D9::~ShadowImageLayerD
 void
 ShadowImageLayerD3D9::Swap(const SharedImage& aNewFront,
                            SharedImage* aNewBack)
 {
   if (aNewFront.type() == SharedImage::TSurfaceDescriptor) {
     if (!mBuffer) {
       mBuffer = new ShadowBufferD3D9(this);
     }
-    nsRefPtr<gfxASurface> surf =
-      ShadowLayerForwarder::OpenDescriptor(aNewFront.get_SurfaceDescriptor());
-
-    mBuffer->Upload(surf, GetVisibleRegion().GetBounds());
+    AutoOpenSurface surf(OPEN_READ_ONLY, aNewFront.get_SurfaceDescriptor());
+    mBuffer->Upload(surf.Get(), GetVisibleRegion().GetBounds());
   } else {
     const YUVImage& yuv = aNewFront.get_YUVImage();
 
-    nsRefPtr<gfxSharedImageSurface> surfY =
-      gfxSharedImageSurface::Open(yuv.Ydata());
-    nsRefPtr<gfxSharedImageSurface> surfU =
-      gfxSharedImageSurface::Open(yuv.Udata());
-    nsRefPtr<gfxSharedImageSurface> surfV =
-      gfxSharedImageSurface::Open(yuv.Vdata());
+    AutoOpenSurface asurfY(OPEN_READ_ONLY, yuv.Ydata());
+    AutoOpenSurface asurfU(OPEN_READ_ONLY, yuv.Udata());
+    AutoOpenSurface asurfV(OPEN_READ_ONLY, yuv.Vdata());
+    gfxImageSurface* surfY = asurfY.GetAsImage();
+    gfxImageSurface* surfU = asurfU.GetAsImage();
+    gfxImageSurface* surfV = asurfV.GetAsImage();
 
     PlanarYCbCrImage::Data data;
     data.mYChannel = surfY->Data();
     data.mYStride = surfY->Stride();
     data.mYSize = surfY->GetSize();
     data.mCbChannel = surfU->Data();
     data.mCrChannel = surfV->Data();
     data.mCbCrStride = surfU->Stride();
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -3,16 +3,17 @@
  * 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 "mozilla/layers/PLayers.h"
 
 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
 #include "mozilla/Util.h"
 
+#include "ipc/AutoOpenSurface.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "ShadowBufferD3D9.h"
 
 #include "ThebesLayerD3D9.h"
 #include "gfxPlatform.h"
 
 #include "gfxWindowsPlatform.h"
 #include "gfxTeeSurface.h"
@@ -612,18 +613,18 @@ ShadowThebesLayerD3D9::Swap(const Thebes
                            OptionalThebesBuffer* aReadOnlyFront,
                            nsIntRegion* aFrontUpdatedRegion)
 {
   if (!mBuffer) {
     mBuffer = new ShadowBufferD3D9(this);
   }
 
   if (mBuffer) {
-    nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(aNewFront.buffer());
-    mBuffer->Upload(surf, GetVisibleRegion().GetBounds());
+    AutoOpenSurface surf(OPEN_READ_ONLY, aNewFront.buffer());
+    mBuffer->Upload(surf.Get(), GetVisibleRegion().GetBounds());
   }
 
   *aNewBack = aNewFront;
   *aNewBackValidRegion = mValidRegion;
   *aReadOnlyFront = null_t();
   aFrontUpdatedRegion->SetEmpty();
 }
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/AutoOpenSurface.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef mozilla_layers_AutoOpenSurface_h
+#define mozilla_layers_AutoOpenSurface_h 1
+
+#include "base/basictypes.h"
+
+#include "gfxASurface.h"
+#include "mozilla/layers/PLayers.h"
+#include "ShadowLayers.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * Some surface types can be fairly expensive to open.  This helper
+ * tries to put off opening surfaces as long as it can, until
+ * ahsolutely necessary.  And after being forced to open, it remembers
+ * the mapping so it doesn't need to be redone.
+ */
+class NS_STACK_CLASS AutoOpenSurface
+{
+public:
+  typedef gfxASurface::gfxContentType gfxContentType;
+
+  /** |aDescriptor| must be valid while AutoOpenSurface is
+   * in scope. */
+  AutoOpenSurface(OpenMode aMode, const SurfaceDescriptor& aDescriptor);
+
+  ~AutoOpenSurface();
+
+  /**
+   * These helpers do not necessarily need to open the descriptor to
+   * return an answer.
+   */
+  gfxContentType ContentType();
+  gfxIntSize Size();
+
+  /** This can't escape the scope of AutoOpenSurface. */
+  gfxASurface* Get();
+
+  /**
+   * This can't escape the scope of AutoOpenSurface.
+   *
+   * This method is currently just a convenience wrapper around
+   * gfxASurface::GetAsImageSurface() --- it returns a valid surface
+   * exactly when this->Get()->GetAsImageSurface() would.  Clients
+   * that need guaranteed (fast) ImageSurfaces should allocate the
+   * underlying descriptor with capability MAP_AS_IMAGE_SURFACE, in
+   * which case this helper is guaranteed to succeed.
+   */
+  gfxImageSurface* GetAsImage();
+
+
+private:
+  SurfaceDescriptor mDescriptor;
+  nsRefPtr<gfxASurface> mSurface;
+  nsRefPtr<gfxImageSurface> mSurfaceAsImage;
+  OpenMode mMode;
+
+  AutoOpenSurface(const AutoOpenSurface&) MOZ_DELETE;
+  AutoOpenSurface& operator=(const AutoOpenSurface&) MOZ_DELETE;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_AutoOpenSurface_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PGrallocBuffer.ipdl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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;
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * This is a trivial protocol that's used to track gralloc buffers
+ * across thread contexts.  A live PGrallocBuffer actor always
+ * corresponds 1:1 to a pre-shared gralloc buffer (sharing is done by
+ * the PGrallocBuffer constructor).
+ */
+async protocol PGrallocBuffer {
+  manager PLayers;
+
+  /** Gralloc buffers can be "owned" by either parent or child. */
+both:
+  async __delete__();
+};
+
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -1,30 +1,34 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 PCompositor;
+include protocol PGrallocBuffer;
 include protocol PLayer;
 include protocol PRenderFrame;
 
 include "gfxipc/ShadowLayerUtils.h";
 
 using gfx3DMatrix;
+using gfxIntSize;
 using gfxPoint;
 using gfxRGBA;
 using nsIntPoint;
 using nsIntRect;
 using nsIntRegion;
 using nsIntSize;
+using mozilla::gfxContentType;
 using mozilla::GraphicsFilterType;
 using mozilla::layers::FrameMetrics;
+using mozilla::layers::MagicGrallocBufferHandle;
 using mozilla::layers::SurfaceDescriptorX11;
 using mozilla::null_t;
 using mozilla::WindowsHandle;
 
 /**
  * The layers protocol is spoken between thread contexts that manage
  * layer (sub)trees.  The protocol comprises atomically publishing
  * layer subtrees to a "shadow" thread context (which grafts the
@@ -37,30 +41,40 @@ namespace layers {
 
 // Create a shadow layer for |layer|
 struct OpCreateThebesLayer     { PLayer layer; };
 struct OpCreateContainerLayer  { PLayer layer; };
 struct OpCreateImageLayer      { PLayer layer; };
 struct OpCreateColorLayer      { PLayer layer; };
 struct OpCreateCanvasLayer     { PLayer layer; };
 
+union MaybeMagicGrallocBufferHandle {
+  MagicGrallocBufferHandle;
+  null_t;
+};
+
 struct SurfaceDescriptorD3D10 {
   WindowsHandle handle;
 };
 
+struct SurfaceDescriptorGralloc {
+  PGrallocBuffer buffer;
+};
+
 union SurfaceDescriptor {
   Shmem;
   SurfaceDescriptorD3D10;
+  SurfaceDescriptorGralloc;
   SurfaceDescriptorX11;
 };
 
 struct YUVImage {
-  Shmem Ydata;
-  Shmem Udata;
-  Shmem Vdata;
+  SurfaceDescriptor Ydata;
+  SurfaceDescriptor Udata;
+  SurfaceDescriptor Vdata;
   nsIntRect picture;
 };
 
 union SharedImage {
   SurfaceDescriptor;
   YUVImage;
   null_t;
 };
@@ -201,19 +215,27 @@ union EditReply {
   OpBufferSwap;
   OpThebesBufferSwap;
   OpImageSwap;
 };
 
 
 sync protocol PLayers {
   manager PRenderFrame or PCompositor;
+  manages PGrallocBuffer;
   manages PLayer;
 
 parent:
+  /**
+   * Only the parent side has privileges to allocate the buffer.
+   * Allocation may fail (pmem is a scarce resource), and if so null_t
+   * is returned.
+   */
+  sync PGrallocBuffer(gfxIntSize size, gfxContentType content)
+    returns (MaybeMagicGrallocBufferHandle handle);
   async PLayer();
 
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
   sync Update(Edit[] cset, bool isFirstPaint)
     returns (EditReply[] reply);
 
   // Composite the layer tree to the given surface, and return the surface.
--- a/gfx/layers/ipc/ShadowLayerUtils.h
+++ b/gfx/layers/ipc/ShadowLayerUtils.h
@@ -20,16 +20,26 @@
 #else
 namespace mozilla { namespace layers {
 struct SurfaceDescriptorX11 {
   bool operator==(const SurfaceDescriptorX11&) const { return false; }
 };
 } }
 #endif
 
+#if defined(MOZ_WIDGET_GONK)
+# include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#else
+namespace mozilla { namespace layers {
+struct MagicGrallocBufferHandle {
+  bool operator==(const MagicGrallocBufferHandle&) const { return false; }
+};
+} }
+#endif
+
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::layers::FrameMetrics>
 {
   typedef mozilla::layers::FrameMetrics paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
@@ -57,13 +67,22 @@ struct ParamTraits<mozilla::layers::Fram
 
 #if !defined(MOZ_HAVE_SURFACEDESCRIPTORX11)
 template <>
 struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
   typedef mozilla::layers::SurfaceDescriptorX11 paramType;
   static void Write(Message*, const paramType&) {}
   static bool Read(const Message*, void**, paramType*) { return false; }
 };
-#endif  // !defined(MOZ_HAVE_XSURFACEDESCRIPTOR)
+#endif  // !defined(MOZ_HAVE_XSURFACEDESCRIPTORX11)
+
+#if !defined(MOZ_HAVE_SURFACEDESCRIPTORGRALLOC)
+template <>
+struct ParamTraits<mozilla::layers::MagicGrallocBufferHandle> {
+  typedef mozilla::layers::MagicGrallocBufferHandle paramType;
+  static void Write(Message*, const paramType&) {}
+  static bool Read(const Message*, void**, paramType*) { return false; }
+};
+#endif  // !defined(MOZ_HAVE_XSURFACEDESCRIPTORGRALLOC)
 
 }
 
 #endif // IPC_ShadowLayerUtils_h
--- a/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
@@ -12,38 +12,57 @@
 #include "ShadowLayers.h"
 
 namespace mozilla {
 namespace layers {
 
 // Platform-specific shadow-layers interfaces.  See ShadowLayers.h.
 // D3D10 doesn't need all these yet.
 bool
-ShadowLayerForwarder::PlatformAllocDoubleBuffer(const gfxIntSize&,
-                                                gfxASurface::gfxContentType,
-                                                SurfaceDescriptor*,
-                                                SurfaceDescriptor*)
-{
-  return false;
-}
-
-bool
 ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize&,
                                           gfxASurface::gfxContentType,
+                                          uint32_t,
                                           SurfaceDescriptor*)
 {
   return false;
 }
 
 /*static*/ already_AddRefed<gfxASurface>
-ShadowLayerForwarder::PlatformOpenDescriptor(const SurfaceDescriptor&)
+ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode,
+                                             const SurfaceDescriptor&)
 {
   return nsnull;
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformCloseDescriptor(const SurfaceDescriptor&)
+{
+  return false;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceContentType(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxContentType*,
+  gfxASurface**)
+{
+  return false;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxIntSize*,
+  gfxASurface**)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor*)
 {
   return false;
 }
 
 /*static*/ void
 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -0,0 +1,348 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "mozilla/layers/PGrallocBufferChild.h"
+#include "mozilla/layers/PGrallocBufferParent.h"
+#include "mozilla/layers/PLayersChild.h"
+#include "mozilla/layers/ShadowLayers.h"
+#include "mozilla/unused.h"
+#include "nsXULAppAPI.h"
+
+#include "ShadowLayerUtilsGralloc.h"
+
+#include "gfxImageSurface.h"
+
+using namespace android;
+using namespace base;
+using namespace mozilla::layers;
+
+namespace IPC {
+
+void
+ParamTraits<MagicGrallocBufferHandle>::Write(Message* aMsg,
+                                             const paramType& aParam)
+{
+  Flattenable *flattenable = aParam.mGraphicBuffer.get();
+  size_t nbytes = flattenable->getFlattenedSize();
+  size_t nfds = flattenable->getFdCount();
+
+  char data[nbytes];
+  int fds[nfds];
+  flattenable->flatten(data, nbytes, fds, nfds);
+
+  aMsg->WriteSize(nbytes);
+  aMsg->WriteSize(nfds);
+
+  aMsg->WriteBytes(data, nbytes);
+  for (size_t n = 0; n < nfds; ++n) {
+    // These buffers can't die in transit because they're created
+    // synchonously and the parent-side buffer can only be dropped if
+    // there's a crash.
+    aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
+  }
+}
+
+bool
+ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg,
+                                            void** aIter, paramType* aResult)
+{
+  size_t nbytes;
+  size_t nfds;
+  const char* data;
+
+  if (!aMsg->ReadSize(aIter, &nbytes) ||
+      !aMsg->ReadSize(aIter, &nfds) ||
+      !aMsg->ReadBytes(aIter, &data, nbytes)) {
+    return false;
+  }
+  
+  int fds[nfds];
+
+  for (size_t n = 0; n < nfds; ++n) {
+    FileDescriptor fd;
+    if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
+      return false;
+    }
+    // If the GraphicBuffer was shared cross-process, SCM_RIGHTS does
+    // the right thing and dup's the fd.  If it's shared cross-thread,
+    // SCM_RIGHTS doesn't dup the fd.  That's surprising, but we just
+    // deal with it here.  NB: only the "default" (master) process can
+    // alloc gralloc buffers.
+    bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
+    int dupFd = sameProcess ? dup(fd.fd) : fd.fd;
+    fds[n] = dupFd;
+  }
+
+  sp<GraphicBuffer> buffer(new GraphicBuffer());
+  Flattenable *flattenable = buffer.get();
+
+  if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
+    aResult->mGraphicBuffer = buffer;
+    return true;
+  }
+  return false;
+}
+
+} // namespace IPC
+
+namespace mozilla {
+namespace layers {
+
+MagicGrallocBufferHandle::MagicGrallocBufferHandle(const sp<GraphicBuffer>& aGraphicBuffer)
+  : mGraphicBuffer(aGraphicBuffer)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Parent process
+
+static gfxASurface::gfxImageFormat
+ImageFormatForPixelFormat(android::PixelFormat aFormat)
+{
+  switch (aFormat) {
+  case PIXEL_FORMAT_RGBA_8888:
+    return gfxASurface::ImageFormatARGB32;
+  case PIXEL_FORMAT_RGBX_8888:
+    return gfxASurface::ImageFormatRGB24;
+  case PIXEL_FORMAT_RGB_565:
+    return gfxASurface::ImageFormatRGB16_565;
+  case PIXEL_FORMAT_A_8:
+    return gfxASurface::ImageFormatA8;
+  default:
+    MOZ_NOT_REACHED("Unknown gralloc pixel format");
+  }
+  return gfxASurface::ImageFormatARGB32;
+}
+
+static android::PixelFormat
+PixelFormatForImageFormat(gfxASurface::gfxImageFormat aFormat)
+{
+  switch (aFormat) {
+  case gfxASurface::ImageFormatARGB32:
+    return android::PIXEL_FORMAT_RGBA_8888;
+  case gfxASurface::ImageFormatRGB24:
+    return android::PIXEL_FORMAT_RGBX_8888;
+  case gfxASurface::ImageFormatRGB16_565:
+    return android::PIXEL_FORMAT_RGB_565;
+  case gfxASurface::ImageFormatA8:
+    return android::PIXEL_FORMAT_A_8;
+  default:
+    MOZ_NOT_REACHED("Unknown gralloc pixel format");
+  }
+  return gfxASurface::ImageFormatARGB32;
+}
+
+static android::PixelFormat
+PixelFormatForContentType(gfxASurface::gfxContentType aContentType)
+{
+  return PixelFormatForImageFormat(
+    gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType));
+}
+
+static gfxASurface::gfxContentType
+ContentTypeFromPixelFormat(android::PixelFormat aFormat)
+{
+  return gfxASurface::ContentFromFormat(ImageFormatForPixelFormat(aFormat));
+}
+
+/*static*/ PGrallocBufferParent*
+GrallocBufferActor::Create(const gfxIntSize& aSize,
+                           const gfxContentType& aContent,
+                           MaybeMagicGrallocBufferHandle* aOutHandle)
+{
+  GrallocBufferActor* actor = new GrallocBufferActor();
+  *aOutHandle = null_t();
+  android::PixelFormat format = PixelFormatForContentType(aContent);
+  sp<GraphicBuffer> buffer(
+    new GraphicBuffer(aSize.width, aSize.height, format,
+                      GraphicBuffer::USAGE_SW_READ_OFTEN |
+                      GraphicBuffer::USAGE_SW_WRITE_OFTEN |
+                      GraphicBuffer::USAGE_HW_TEXTURE));
+  if (buffer->initCheck() != OK)
+    return actor;
+
+  actor->mGraphicBuffer = buffer;
+  *aOutHandle = MagicGrallocBufferHandle(buffer);
+  return actor;
+}
+
+bool
+ShadowLayerManager::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aSurface->type()) {
+    return false;
+  }
+
+  PGrallocBufferParent* gbp =
+    aSurface->get_SurfaceDescriptorGralloc().bufferParent();
+  unused << PGrallocBufferParent::Send__delete__(gbp);
+  *aSurface = SurfaceDescriptor();
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// Child process
+
+/*static*/ PGrallocBufferChild*
+GrallocBufferActor::Create()
+{
+  return new GrallocBufferActor();
+}
+
+void
+GrallocBufferActor::InitFromHandle(const MagicGrallocBufferHandle& aHandle)
+{
+  MOZ_ASSERT(!mGraphicBuffer.get());
+  MOZ_ASSERT(aHandle.mGraphicBuffer.get());
+
+  mGraphicBuffer = aHandle.mGraphicBuffer;
+}
+
+bool
+ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize& aSize,
+                                          gfxASurface::gfxContentType aContent,
+                                          uint32_t aCaps,
+                                          SurfaceDescriptor* aBuffer)
+{
+  // Gralloc buffers are efficiently mappable as gfxImageSurface, so
+  // no need to check |aCaps & MAP_AS_IMAGE_SURFACE|.
+  MaybeMagicGrallocBufferHandle handle;
+  PGrallocBufferChild* gc =
+    mShadowManager->SendPGrallocBufferConstructor(aSize, aContent, &handle);
+  if (handle.Tnull_t == handle.type()) {
+    PGrallocBufferChild::Send__delete__(gc);
+    return false;
+  }
+
+  GrallocBufferActor* gba = static_cast<GrallocBufferActor*>(gc);
+  gba->InitFromHandle(handle.get_MagicGrallocBufferHandle());
+
+  *aBuffer = SurfaceDescriptorGralloc(nsnull, gc);
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// Both processes
+
+/*static*/ sp<GraphicBuffer>
+GrallocBufferActor::GetFrom(const SurfaceDescriptorGralloc& aDescriptor)
+{
+  GrallocBufferActor* gba = nsnull;
+  if (PGrallocBufferChild* child = aDescriptor.bufferChild()) {
+    gba = static_cast<GrallocBufferActor*>(child);
+  } else if (PGrallocBufferParent* parent = aDescriptor.bufferParent()) {
+    gba = static_cast<GrallocBufferActor*>(parent);
+  }
+  return gba->mGraphicBuffer;
+}
+
+
+/*static*/ already_AddRefed<gfxASurface>
+ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode aMode,
+                                             const SurfaceDescriptor& aSurface)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aSurface.type()) {
+    return nsnull;
+  }
+
+  sp<GraphicBuffer> buffer =
+    GrallocBufferActor::GetFrom(aSurface.get_SurfaceDescriptorGralloc());
+  uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
+  if (OPEN_READ_WRITE == aMode) {
+    usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+  }
+  void *vaddr;
+  DebugOnly<status_t> status = buffer->lock(usage, &vaddr);
+  // If we fail to lock, we'll just end up aborting anyway.
+  MOZ_ASSERT(status == OK);
+
+  gfxIntSize size = gfxIntSize(buffer->getWidth(), buffer->getHeight());
+  gfxImageFormat format = ImageFormatForPixelFormat(buffer->getPixelFormat());
+  long pixelStride = buffer->getStride();
+  long byteStride = pixelStride * gfxASurface::BytePerPixelFromFormat(format);
+
+  nsRefPtr<gfxASurface> surf =
+    new gfxImageSurface((unsigned char*)vaddr, size, byteStride, format);
+  return surf->CairoStatus() ? nsnull : surf.forget();
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceContentType(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxContentType* aContent,
+  gfxASurface** aSurface)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
+    return false;
+  }
+
+  sp<GraphicBuffer> buffer =
+    GrallocBufferActor::GetFrom(aDescriptor.get_SurfaceDescriptorGralloc());
+  *aContent = ContentTypeFromPixelFormat(buffer->getPixelFormat());
+  return true;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxIntSize* aSize,
+  gfxASurface** aSurface)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
+    return false;
+  }
+
+  sp<GraphicBuffer> buffer =
+    GrallocBufferActor::GetFrom(aDescriptor.get_SurfaceDescriptorGralloc());
+  *aSize = gfxIntSize(buffer->getWidth(), buffer->getHeight());
+  return true;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aSurface->type()) {
+    return false;
+  }
+
+  PGrallocBufferChild* gbp =
+    aSurface->get_SurfaceDescriptorGralloc().bufferChild();
+  PGrallocBufferChild::Send__delete__(gbp);
+  *aSurface = SurfaceDescriptor();
+  return true;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformCloseDescriptor(const SurfaceDescriptor& aDescriptor)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
+    return false;
+  }
+
+  sp<GraphicBuffer> buffer =
+    GrallocBufferActor::GetFrom(aDescriptor);
+  // If the buffer wasn't lock()d, this probably blows up.  But since
+  // PlatformCloseDescriptor() is private and only used by
+  // AutoOpenSurface, we want to know if the logic is wrong there.
+  buffer->unlock();
+  return true;
+}
+
+/*static*/ void
+ShadowLayerForwarder::PlatformSyncBeforeUpdate()
+{
+  // Nothing to be done for gralloc.
+}
+
+/*static*/ void
+ShadowLayerManager::PlatformSyncBeforeReplyUpdate()
+{
+  // Nothing to be done for gralloc.
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef mozilla_layers_ShadowLayerUtilsGralloc_h
+#define mozilla_layers_ShadowLayerUtilsGralloc_h
+
+#include <unistd.h>
+#include <ui/GraphicBuffer.h>
+
+#include "IPC/IPCMessageUtils.h"
+#include "mozilla/layers/PGrallocBufferChild.h"
+#include "mozilla/layers/PGrallocBufferParent.h"
+
+#define MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+#define MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
+
+class gfxASurface;
+
+namespace mozilla {
+namespace layers {
+
+class MaybeMagicGrallocBufferHandle;
+class SurfaceDescriptorGralloc;
+
+/**
+ * This class exists to share the underlying GraphicBuffer resources
+ * from one thread context to another.  This requires going through
+ * slow paths in the kernel so can be somewhat expensive.
+ *
+ * This is not just platform-specific, but also
+ * gralloc-implementation-specific.
+ */
+struct MagicGrallocBufferHandle {
+  typedef android::GraphicBuffer GraphicBuffer;
+
+  MagicGrallocBufferHandle()
+  { }
+
+  MagicGrallocBufferHandle(const android::sp<GraphicBuffer>& aGraphicBuffer);
+
+  // Default copy ctor and operator= are OK
+
+  bool operator==(const MagicGrallocBufferHandle& aOther) const {
+    return mGraphicBuffer == aOther.mGraphicBuffer;
+  }
+
+  android::sp<GraphicBuffer> mGraphicBuffer;
+};
+
+/**
+ * GrallocBufferActor is an "IPC wrapper" for an underlying
+ * GraphicBuffer (pmem region).  It allows us to cheaply and
+ * conveniently share gralloc handles between processes.
+ */
+class GrallocBufferActor : public PGrallocBufferChild
+                         , public PGrallocBufferParent
+{
+  friend class ShadowLayerForwarder;
+  typedef android::GraphicBuffer GraphicBuffer;
+
+public:
+  virtual ~GrallocBufferActor() {}
+
+  static PGrallocBufferParent*
+  Create(const gfxIntSize& aSize, const gfxContentType& aContent,
+         MaybeMagicGrallocBufferHandle* aOutHandle);
+
+  static PGrallocBufferChild*
+  Create();
+
+private:
+  GrallocBufferActor() {}
+
+  void InitFromHandle(const MagicGrallocBufferHandle& aHandle);
+
+  static android::sp<GraphicBuffer>
+  GetFrom(const SurfaceDescriptorGralloc& aDescriptor);
+
+  android::sp<GraphicBuffer> mGraphicBuffer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::layers::MagicGrallocBufferHandle> {
+  typedef mozilla::layers::MagicGrallocBufferHandle paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+};
+
+} // namespace IPC
+
+#endif  // mozilla_layers_ShadowLayerUtilsGralloc_h
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -84,36 +84,32 @@ SurfaceDescriptorX11::OpenForeign() cons
       return nsnull;
 
     surf = new gfxXlibSurface(display, mId, visual, mSize);
   }
   return surf->CairoStatus() ? nsnull : surf.forget();
 }
 
 bool
-ShadowLayerForwarder::PlatformAllocDoubleBuffer(const gfxIntSize& aSize,
-                                                gfxASurface::gfxContentType aContent,
-                                                SurfaceDescriptor* aFrontBuffer,
-                                                SurfaceDescriptor* aBackBuffer)
-{
-  return (PlatformAllocBuffer(aSize, aContent, aFrontBuffer) &&
-          PlatformAllocBuffer(aSize, aContent, aBackBuffer));
-}
-
-bool
 ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize& aSize,
                                           gfxASurface::gfxContentType aContent,
+                                          uint32_t aCaps,
                                           SurfaceDescriptor* aBuffer)
 {
   if (!UsingXCompositing()) {
     // If we're not using X compositing, we're probably compositing on
     // the client side, in which case X surfaces would just slow
     // things down.  Use Shmem instead.
     return false;
   }
+  if (MAP_AS_IMAGE_SURFACE & aCaps) {
+    // We can't efficiently map pixmaps as gfxImageSurface, in
+    // general.  Fall back on Shmem.
+    return false;
+  }
 
   gfxPlatform* platform = gfxPlatform::GetPlatform();
   nsRefPtr<gfxASurface> buffer = platform->CreateOffscreenSurface(aSize, aContent);
   if (!buffer ||
       buffer->GetType() != gfxASurface::SurfaceTypeXlib) {
     NS_ERROR("creating Xlib front/back surfaces failed!");
     return false;
   }
@@ -122,24 +118,50 @@ ShadowLayerForwarder::PlatformAllocBuffe
   // Release Pixmap ownership to the layers model
   bufferX->ReleasePixmap();
 
   *aBuffer = SurfaceDescriptorX11(bufferX);
   return true;
 }
 
 /*static*/ already_AddRefed<gfxASurface>
-ShadowLayerForwarder::PlatformOpenDescriptor(const SurfaceDescriptor& aSurface)
+ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode aMode,
+                                             const SurfaceDescriptor& aSurface)
 {
   if (SurfaceDescriptor::TSurfaceDescriptorX11 != aSurface.type()) {
     return nsnull;
   }
   return aSurface.get_SurfaceDescriptorX11().OpenForeign();
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformCloseDescriptor(const SurfaceDescriptor& aDescriptor)
+{
+  // XIDs don't need to be "closed".
+  return false;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceContentType(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxContentType* aContent,
+  gfxASurface** aSurface)
+{
+  return false;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxIntSize* aSize,
+  gfxASurface** aSurface)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
 {
   if (SurfaceDescriptor::TSurfaceDescriptorX11 != aSurface->type()) {
     return false;
   }
   return TakeAndDestroyXlibSurface(aSurface);
 }
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <set>
 #include <vector>
 
 #include "gfxSharedImageSurface.h"
 #include "gfxPlatform.h"
 
+#include "AutoOpenSurface.h"
 #include "mozilla/ipc/SharedMemorySysV.h"
 #include "mozilla/layers/PLayerChild.h"
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layers/PLayersParent.h"
 #include "ShadowLayers.h"
 #include "ShadowLayerChild.h"
 #include "gfxipc/ShadowLayerUtils.h"
 #include "RenderTrace.h"
@@ -350,17 +351,17 @@ ShadowLayerForwarder::ShadowDrawToTarget
   SurfaceDescriptor descriptorIn, descriptorOut;
   AllocBuffer(aTarget->OriginalSurface()->GetSize(),
               aTarget->OriginalSurface()->GetContentType(),
               &descriptorIn);
   if (!mShadowManager->SendDrawToSurface(descriptorIn, &descriptorOut)) {
     return false;
   }
 
-  nsRefPtr<gfxASurface> surface = OpenDescriptor(descriptorOut);
+  nsRefPtr<gfxASurface> surface = OpenDescriptor(OPEN_READ_WRITE, descriptorOut);
   aTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
   aTarget->DrawSurface(surface, surface->GetSize());
 
   surface = nsnull;
   DestroySharedSurface(&descriptorOut);
 
   return true;
 }
@@ -377,32 +378,16 @@ OptimalShmemType()
   // use for layers.
   return SharedMemory::TYPE_SYSV;
 #else
   return SharedMemory::TYPE_BASIC;
 #endif
 }
 
 bool
-ShadowLayerForwarder::AllocDoubleBuffer(const gfxIntSize& aSize,
-                                        gfxASurface::gfxContentType aContent,
-                                        gfxSharedImageSurface** aFrontBuffer,
-                                        gfxSharedImageSurface** aBackBuffer)
-{
-  return AllocBuffer(aSize, aContent, aFrontBuffer) &&
-         AllocBuffer(aSize, aContent, aBackBuffer);
-}
-
-void
-ShadowLayerForwarder::DestroySharedSurface(gfxSharedImageSurface* aSurface)
-{
-  mShadowManager->DeallocShmem(aSurface->GetShmem());
-}
-
-bool
 ShadowLayerForwarder::AllocBuffer(const gfxIntSize& aSize,
                                   gfxASurface::gfxContentType aContent,
                                   gfxSharedImageSurface** aBuffer)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
 
   SharedMemory::SharedMemoryType shmemType = OptimalShmemType();
   gfxASurface::gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent);
@@ -413,84 +398,107 @@ ShadowLayerForwarder::AllocBuffer(const 
     return false;
 
   *aBuffer = nsnull;
   back.swap(*aBuffer);
   return true;
 }
 
 bool
-ShadowLayerForwarder::AllocDoubleBuffer(const gfxIntSize& aSize,
-                                        gfxASurface::gfxContentType aContent,
-                                        SurfaceDescriptor* aFrontBuffer,
-                                        SurfaceDescriptor* aBackBuffer)
+ShadowLayerForwarder::AllocBuffer(const gfxIntSize& aSize,
+                                  gfxASurface::gfxContentType aContent,
+                                  SurfaceDescriptor* aBuffer)
+{
+  return AllocBufferWithCaps(aSize, aContent, DEFAULT_BUFFER_CAPS, aBuffer);
+}
+
+bool
+ShadowLayerForwarder::AllocBufferWithCaps(const gfxIntSize& aSize,
+                                          gfxASurface::gfxContentType aContent,
+                                          uint32_t aCaps,
+                                          SurfaceDescriptor* aBuffer)
 {
   bool tryPlatformSurface = true;
 #ifdef DEBUG
   tryPlatformSurface = !PR_GetEnv("MOZ_LAYERS_FORCE_SHMEM_SURFACES");
 #endif
   if (tryPlatformSurface &&
-      PlatformAllocDoubleBuffer(aSize, aContent, aFrontBuffer, aBackBuffer)) {
-    return true;
-  }
-
-  nsRefPtr<gfxSharedImageSurface> front;
-  nsRefPtr<gfxSharedImageSurface> back;
-  if (!AllocDoubleBuffer(aSize, aContent,
-                         getter_AddRefs(front), getter_AddRefs(back))) {
-    return false;
-  }
-
-  *aFrontBuffer = front->GetShmem();
-  *aBackBuffer = back->GetShmem();
-  return true;
-}
-
-bool
-ShadowLayerForwarder::AllocBuffer(const gfxIntSize& aSize,
-                                  gfxASurface::gfxContentType aContent,
-                                  SurfaceDescriptor* aBuffer)
-{
-  bool tryPlatformSurface = true;
-#ifdef DEBUG
-  tryPlatformSurface = !PR_GetEnv("MOZ_LAYERS_FORCE_SHMEM_SURFACES");
-#endif
-  if (tryPlatformSurface &&
-      PlatformAllocBuffer(aSize, aContent, aBuffer)) {
+      PlatformAllocBuffer(aSize, aContent, aCaps, aBuffer)) {
     return true;
   }
 
   nsRefPtr<gfxSharedImageSurface> buffer;
   if (!AllocBuffer(aSize, aContent,
                    getter_AddRefs(buffer)))
     return false;
 
   *aBuffer = buffer->GetShmem();
   return true;
 }
 
 /*static*/ already_AddRefed<gfxASurface>
-ShadowLayerForwarder::OpenDescriptor(const SurfaceDescriptor& aSurface)
+ShadowLayerForwarder::OpenDescriptor(OpenMode aMode,
+                                     const SurfaceDescriptor& aSurface)
 {
-  nsRefPtr<gfxASurface> surf = PlatformOpenDescriptor(aSurface);
+  nsRefPtr<gfxASurface> surf = PlatformOpenDescriptor(aMode, aSurface);
   if (surf) {
     return surf.forget();
   }
 
   switch (aSurface.type()) {
   case SurfaceDescriptor::TShmem: {
     surf = gfxSharedImageSurface::Open(aSurface.get_Shmem());
     return surf.forget();
   }
   default:
     NS_RUNTIMEABORT("unexpected SurfaceDescriptor type!");
     return nsnull;
   }
 }
 
+/*static*/ gfxContentType
+ShadowLayerForwarder::GetDescriptorSurfaceContentType(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxASurface** aSurface)
+{
+  gfxContentType content;
+  if (PlatformGetDescriptorSurfaceContentType(aDescriptor, aMode,
+                                              &content, aSurface)) {
+    return content;
+  }
+
+  nsRefPtr<gfxASurface> surface = OpenDescriptor(aMode, aDescriptor);
+  content = surface->GetContentType();
+  *aSurface = surface.forget().get();
+  return content;
+}
+
+/*static*/ gfxIntSize
+ShadowLayerForwarder::GetDescriptorSurfaceSize(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxASurface** aSurface)
+{
+  gfxIntSize size;
+  if (PlatformGetDescriptorSurfaceSize(aDescriptor, aMode, &size, aSurface)) {
+    return size;
+  }
+
+  nsRefPtr<gfxASurface> surface = OpenDescriptor(aMode, aDescriptor);
+  size = surface->GetSize();
+  *aSurface = surface.forget().get();
+  return size;
+}
+
+/*static*/ void
+ShadowLayerForwarder::CloseDescriptor(const SurfaceDescriptor& aDescriptor)
+{
+  PlatformCloseDescriptor(aDescriptor);
+  // There's no "close" needed for Shmem surfaces.
+}
+
 // Destroy the Shmem SurfaceDescriptor |aSurface|.
 template<class ShmemDeallocator>
 static void
 DestroySharedShmemSurface(SurfaceDescriptor* aSurface,
                           ShmemDeallocator* aDeallocator)
 {
   switch (aSurface->type()) {
   case SurfaceDescriptor::TShmem: {
@@ -542,38 +550,57 @@ ShadowLayerManager::DestroySharedSurface
     DestroySharedShmemSurface(aSurface, aDeallocator);
   }
 }
 
 
 #if !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
 
 bool
-ShadowLayerForwarder::PlatformAllocDoubleBuffer(const gfxIntSize&,
-                                                gfxASurface::gfxContentType,
-                                                SurfaceDescriptor*,
-                                                SurfaceDescriptor*)
-{
-  return false;
-}
-
-bool
 ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize&,
                                           gfxASurface::gfxContentType,
+                                          uint32_t,
                                           SurfaceDescriptor*)
 {
   return false;
 }
 
 /*static*/ already_AddRefed<gfxASurface>
-ShadowLayerForwarder::PlatformOpenDescriptor(const SurfaceDescriptor&)
+ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode,
+                                             const SurfaceDescriptor&)
 {
   return nsnull;
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformCloseDescriptor(const SurfaceDescriptor&)
+{
+  return false;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceContentType(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxContentType*,
+  gfxASurface**)
+{
+  return false;
+}
+
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxIntSize*,
+  gfxASurface**)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor*)
 {
   return false;
 }
 
 /*static*/ void
 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
@@ -594,10 +621,65 @@ ShadowLayerManager::PlatformSyncBeforeRe
 #endif  // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
 
 bool
 IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface)
 {
   return SurfaceDescriptor::T__None != aSurface.type();
 }
 
+AutoOpenSurface::AutoOpenSurface(OpenMode aMode,
+                                 const SurfaceDescriptor& aDescriptor)
+  : mDescriptor(aDescriptor)
+  , mMode(aMode)
+{
+  MOZ_ASSERT(IsSurfaceDescriptorValid(mDescriptor));
+}
+
+AutoOpenSurface::~AutoOpenSurface()
+{
+  if (mSurface) {
+    mSurface = nsnull;
+    ShadowLayerForwarder::CloseDescriptor(mDescriptor);
+  }
+}
+
+gfxContentType
+AutoOpenSurface::ContentType()
+{
+  if (mSurface) {
+    return mSurface->GetContentType();
+  }
+  return ShadowLayerForwarder::GetDescriptorSurfaceContentType(
+    mDescriptor, mMode, getter_AddRefs(mSurface));
+}
+
+gfxIntSize
+AutoOpenSurface::Size()
+{
+  if (mSurface) {
+    return mSurface->GetSize();
+  }
+  return ShadowLayerForwarder::GetDescriptorSurfaceSize(
+    mDescriptor, mMode, getter_AddRefs(mSurface));
+}
+
+gfxASurface*
+AutoOpenSurface::Get()
+{
+  if (!mSurface) {
+    mSurface = ShadowLayerForwarder::OpenDescriptor(mMode, mDescriptor);
+  }
+  return mSurface.get();
+}
+
+gfxImageSurface*
+AutoOpenSurface::GetAsImage()
+{
+  if (!mSurfaceAsImage) {
+    mSurfaceAsImage = Get()->GetAsImageSurface();
+  }
+  return mSurfaceAsImage.get();
+}
+
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -33,16 +33,30 @@ class ShadowCanvasLayer;
 class SurfaceDescriptor;
 class ThebesBuffer;
 class TiledLayerComposer;
 class Transaction;
 class SharedImage;
 class CanvasSurface;
 class BasicTiledLayerBuffer;
 
+enum BufferCapabilities {
+  DEFAULT_BUFFER_CAPS = 0,
+  /** 
+   * The allocated buffer must be efficiently mappable as a
+   * gfxImageSurface.
+   */
+  MAP_AS_IMAGE_SURFACE = 1 << 0
+};
+
+enum OpenMode {
+  OPEN_READ_ONLY,
+  OPEN_READ_WRITE
+};
+
 /**
  * We want to share layer trees across thread contexts and address
  * spaces for several reasons; chief among them
  *
  *  - a parent process can paint a child process's layer tree while
  *    the child process is blocked, say on content script.  This is
  *    important on mobile devices where UI responsiveness is key.
  *
@@ -76,17 +90,20 @@ class BasicTiledLayerBuffer;
  *
  * There are only shadow types for layers that have different shadow
  * vs. not-shadow behavior.  ColorLayers and ContainerLayers behave
  * the same way in both regimes (so far).
  */
 
 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.
    */
@@ -222,18 +239,18 @@ public:
    * The following Alloc/Open/Destroy interfaces abstract over the
    * details of working with surfaces that are shared across
    * processes.  They provide the glue between C++ Layers and the
    * ShadowLayer IPC system.
    *
    * The basic lifecycle is
    *
    *  - a Layer needs a buffer.  Its ShadowableLayer subclass calls
-   *    AllocDoubleBuffer(), then calls one of the Created*Buffer()
-   *    methods above to transfer the (temporary) front buffer to its
+   *    AllocBuffer(), then calls one of the Created*Buffer() methods
+   *    above to transfer the (temporary) front buffer to its
    *    ShadowLayer in the other process.  The Layer needs a
    *    gfxASurface to paint, so the ShadowableLayer uses
    *    OpenDescriptor(backBuffer) to get that surface, and hands it
    *    out to the Layer.
    *
    * - a Layer has painted new pixels.  Its ShadowableLayer calls one
    *   of the Painted*Buffer() methods above with the back buffer
    *   descriptor.  This notification is forwarded to the ShadowLayer,
@@ -250,44 +267,27 @@ public:
    *   ShadowLayer also calls DestroySharedSurface() on its front
    *   buffer, and the double-buffer pair is gone.
    */
 
   /**
    * Shmem (gfxSharedImageSurface) buffers are available on all
    * platforms, but they may not be optimal.
    *
-   * NB: this interface is being deprecated in favor of the
-   * SurfaceDescriptor variant below.
-   */
-  bool AllocDoubleBuffer(const gfxIntSize& aSize,
-                           gfxASurface::gfxContentType aContent,
-                           gfxSharedImageSurface** aFrontBuffer,
-                           gfxSharedImageSurface** aBackBuffer);
-  void DestroySharedSurface(gfxSharedImageSurface* aSurface);
-
-  bool AllocBuffer(const gfxIntSize& aSize,
-                     gfxASurface::gfxContentType aContent,
-                     gfxSharedImageSurface** aBuffer);
-
-  /**
    * In the absence of platform-specific buffers these fall back to
    * Shmem/gfxSharedImageSurface.
    */
-  bool AllocDoubleBuffer(const gfxIntSize& aSize,
-                           gfxASurface::gfxContentType aContent,
-                           SurfaceDescriptor* aFrontBuffer,
-                           SurfaceDescriptor* aBackBuffer);
+  bool AllocBuffer(const gfxIntSize& aSize,
+                   gfxASurface::gfxContentType aContent,
+                   SurfaceDescriptor* aBuffer);
 
-  bool AllocBuffer(const gfxIntSize& aSize,
-                     gfxASurface::gfxContentType aContent,
-                     SurfaceDescriptor* aBuffer);
-
-  static already_AddRefed<gfxASurface>
-  OpenDescriptor(const SurfaceDescriptor& aSurface);
+  bool AllocBufferWithCaps(const gfxIntSize& aSize,
+                           gfxASurface::gfxContentType aContent,
+                           uint32_t aCaps,
+                           SurfaceDescriptor* aBuffer);
 
   void DestroySharedSurface(SurfaceDescriptor* aSurface);
 
   /**
    * Construct a shadow of |aLayer| on the "other side", at the
    * ShadowLayerManager.
    */
   PLayerChild* ConstructShadowFor(ShadowableLayer* aLayer);
@@ -306,40 +306,79 @@ public:
   void SetMaxTextureSize(PRInt32 aMaxTextureSize) { mMaxTextureSize = aMaxTextureSize; }
 
 protected:
   ShadowLayerForwarder();
 
   PLayersChild* mShadowManager;
 
 private:
-  bool PlatformAllocDoubleBuffer(const gfxIntSize& aSize,
-                                   gfxASurface::gfxContentType aContent,
-                                   SurfaceDescriptor* aFrontBuffer,
-                                   SurfaceDescriptor* aBackBuffer);
+  bool AllocBuffer(const gfxIntSize& aSize,
+                   gfxASurface::gfxContentType aContent,
+                   gfxSharedImageSurface** aBuffer);
 
   bool PlatformAllocBuffer(const gfxIntSize& aSize,
-                             gfxASurface::gfxContentType aContent,
-                             SurfaceDescriptor* aBuffer);
+                           gfxASurface::gfxContentType aContent,
+                           uint32_t aCaps,
+                           SurfaceDescriptor* aBuffer);
+
+  /**
+   * Try to query the content type efficiently, but at worst map the
+   * surface and return it in *aSurface.
+   */
+  static gfxContentType
+  GetDescriptorSurfaceContentType(const SurfaceDescriptor& aDescriptor,
+                                  OpenMode aMode,
+                                  gfxASurface** aSurface);
+  /**
+   * It can be expensive to open a descriptor just to query its
+   * content type.  If the platform impl can do this cheaply, it will
+   * set *aContent and return true.
+   */
+  static bool
+  PlatformGetDescriptorSurfaceContentType(const SurfaceDescriptor& aDescriptor,
+                                          OpenMode aMode,
+                                          gfxContentType* aContent,
+                                          gfxASurface** aSurface);
+  // (Same as above, but for surface size.)
+  static gfxIntSize
+  GetDescriptorSurfaceSize(const SurfaceDescriptor& aDescriptor,
+                           OpenMode aMode,
+                           gfxASurface** aSurface);
+  static bool
+  PlatformGetDescriptorSurfaceSize(const SurfaceDescriptor& aDescriptor,
+                                   OpenMode aMode,
+                                   gfxIntSize* aSize,
+                                   gfxASurface** aSurface);
 
   static already_AddRefed<gfxASurface>
-  PlatformOpenDescriptor(const SurfaceDescriptor& aDescriptor);
+  OpenDescriptor(OpenMode aMode, const SurfaceDescriptor& aSurface);
+
+  static already_AddRefed<gfxASurface>
+  PlatformOpenDescriptor(OpenMode aMode, const SurfaceDescriptor& aDescriptor);
+
+  /** Make this descriptor unusable for gfxASurface clients.  A
+   * private interface with AutoOpenSurface. */
+  static void
+  CloseDescriptor(const SurfaceDescriptor& aDescriptor);
+
+  static bool
+  PlatformCloseDescriptor(const SurfaceDescriptor& aDescriptor);
 
   bool PlatformDestroySharedSurface(SurfaceDescriptor* aSurface);
 
   static void PlatformSyncBeforeUpdate();
 
   Transaction* mTxn;
   PRInt32 mMaxTextureSize;
   LayersBackend mParentBackend;
 
   bool mIsFirstPaint;
 };
 
-
 class ShadowLayerManager : public LayerManager
 {
 public:
   virtual ~ShadowLayerManager() {}
 
   virtual void GetBackendName(nsAString& name) { name.AssignLiteral("Shadow"); }
 
   void DestroySharedSurface(gfxSharedImageSurface* aSurface,
--- a/gfx/layers/ipc/ShadowLayersChild.cpp
+++ b/gfx/layers/ipc/ShadowLayersChild.cpp
@@ -2,29 +2,55 @@
  * 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 "ShadowLayerChild.h"
 #include "ShadowLayersChild.h"
+#include "ShadowLayerUtils.h"
 
 namespace mozilla {
 namespace layers {
 
 void
 ShadowLayersChild::Destroy()
 {
   NS_ABORT_IF_FALSE(0 == ManagedPLayerChild().Length(),
                     "layers should have been cleaned up by now");
   PLayersChild::Send__delete__(this);
   // WARNING: |this| has gone to the great heap in the sky
 }
 
+PGrallocBufferChild*
+ShadowLayersChild::AllocPGrallocBuffer(const gfxIntSize&,
+                                       const gfxContentType&,
+                                       MaybeMagicGrallocBufferHandle*)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  return GrallocBufferActor::Create();
+#else
+  NS_RUNTIMEABORT("No gralloc buffers for you");
+  return nsnull;
+#endif
+}
+
+bool
+ShadowLayersChild::DeallocPGrallocBuffer(PGrallocBufferChild* actor)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  delete actor;
+  return true;
+#else
+  NS_RUNTIMEABORT("Um, how did we get here?");
+  return false;
+#endif
+}
+
 PLayerChild*
 ShadowLayersChild::AllocPLayer()
 {
   // we always use the "power-user" ctor
   NS_RUNTIMEABORT("not reached");
   return NULL;
 }
 
--- a/gfx/layers/ipc/ShadowLayersChild.h
+++ b/gfx/layers/ipc/ShadowLayersChild.h
@@ -24,16 +24,21 @@ public:
    *
    * It is expected (checked with an assert) that all shadow layers
    * created by this have already been destroyed and
    * Send__delete__()d by the time this method is called.
    */
   void Destroy();
 
 protected:
-  NS_OVERRIDE virtual PLayerChild* AllocPLayer();
-  NS_OVERRIDE virtual bool DeallocPLayer(PLayerChild* actor);
+  virtual PGrallocBufferChild*
+  AllocPGrallocBuffer(const gfxIntSize&, const gfxContentType&,
+                      MaybeMagicGrallocBufferHandle*) MOZ_OVERRIDE;
+  virtual bool
+  DeallocPGrallocBuffer(PGrallocBufferChild* actor) MOZ_OVERRIDE;
+  virtual PLayerChild* AllocPLayer() MOZ_OVERRIDE;
+  virtual bool DeallocPLayer(PLayerChild* actor) MOZ_OVERRIDE;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // ifndef mozilla_layers_ShadowLayersChild_h
--- a/gfx/layers/ipc/ShadowLayersParent.cpp
+++ b/gfx/layers/ipc/ShadowLayersParent.cpp
@@ -2,30 +2,28 @@
  * 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 <vector>
 
-#include "ShadowLayersParent.h"
-#include "ShadowLayerParent.h"
-#include "ShadowLayers.h"
-#include "RenderTrace.h"
-
+#include "AutoOpenSurface.h"
+#include "CompositorParent.h"
+#include "gfxSharedImageSurface.h"
+#include "ImageLayers.h"
+#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/unused.h"
-
-#include "mozilla/layout/RenderFrameParent.h"
-#include "CompositorParent.h"
-
-#include "gfxSharedImageSurface.h"
-
+#include "RenderTrace.h"
+#include "ShadowLayerParent.h"
+#include "ShadowLayersParent.h"
+#include "ShadowLayers.h"
+#include "ShadowLayerUtils.h"
 #include "TiledLayerBuffer.h"
-#include "ImageLayers.h"
 
 typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
 
 using mozilla::layout::RenderFrameParent;
 
 namespace mozilla {
 namespace layers {
 
@@ -415,31 +413,56 @@ bool
 ShadowLayersParent::RecvDrawToSurface(const SurfaceDescriptor& surfaceIn,
                                       SurfaceDescriptor* surfaceOut)
 {
   *surfaceOut = surfaceIn;
   if (mDestroyed || layer_manager()->IsDestroyed()) {
     return true;
   }
 
-  nsRefPtr<gfxASurface> sharedSurface = ShadowLayerForwarder::OpenDescriptor(surfaceIn);
+  AutoOpenSurface sharedSurface(OPEN_READ_WRITE, surfaceIn);
 
   nsRefPtr<gfxASurface> localSurface =
-    gfxPlatform::GetPlatform()->CreateOffscreenSurface(sharedSurface->GetSize(),
-                                                       sharedSurface->GetContentType());
+    gfxPlatform::GetPlatform()->CreateOffscreenSurface(sharedSurface.Size(),
+                                                       sharedSurface.ContentType());
   nsRefPtr<gfxContext> context = new gfxContext(localSurface);
 
   layer_manager()->BeginTransactionWithTarget(context);
   layer_manager()->EndTransaction(NULL, NULL);
-  nsRefPtr<gfxContext> contextForCopy = new gfxContext(sharedSurface);
+  nsRefPtr<gfxContext> contextForCopy = new gfxContext(sharedSurface.Get());
   contextForCopy->SetOperator(gfxContext::OPERATOR_SOURCE);
   contextForCopy->DrawSurface(localSurface, localSurface->GetSize());
   return true;
 }
 
+PGrallocBufferParent*
+ShadowLayersParent::AllocPGrallocBuffer(const gfxIntSize& aSize,
+                                        const gfxContentType& aContent,
+                                        MaybeMagicGrallocBufferHandle* aOutHandle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  return GrallocBufferActor::Create(aSize, aContent, aOutHandle);
+#else
+  NS_RUNTIMEABORT("No gralloc buffers for you");
+  return nsnull;
+#endif
+}
+
+bool
+ShadowLayersParent::DeallocPGrallocBuffer(PGrallocBufferParent* actor)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  delete actor;
+  return true;
+#else
+  NS_RUNTIMEABORT("Um, how did we get here?");
+  return false;
+#endif
+}
+
 PLayerParent*
 ShadowLayersParent::AllocPLayer()
 {
   return new ShadowLayerParent();
 }
 
 bool
 ShadowLayersParent::DeallocPLayer(PLayerParent* actor)
--- a/gfx/layers/ipc/ShadowLayersParent.h
+++ b/gfx/layers/ipc/ShadowLayersParent.h
@@ -39,28 +39,34 @@ public:
   ShadowLayerManager* layer_manager() const { return mLayerManager; }
 
   ContainerLayer* GetRoot() const { return mRoot; }
 
   virtual void DestroySharedSurface(gfxSharedImageSurface* aSurface);
   virtual void DestroySharedSurface(SurfaceDescriptor* aSurface);
 
 protected:
-  NS_OVERRIDE virtual bool RecvUpdate(const EditArray& cset,
-                                      const bool& isFirstPaint,
-                                      EditReplyArray* reply);
+  virtual bool RecvUpdate(const EditArray& cset,
+                          const bool& isFirstPaint,
+                          EditReplyArray* reply) MOZ_OVERRIDE;
+
+  virtual bool RecvDrawToSurface(const SurfaceDescriptor& surfaceIn,
+                                 SurfaceDescriptor* surfaceOut) MOZ_OVERRIDE;
 
-  NS_OVERRIDE virtual bool RecvDrawToSurface(const SurfaceDescriptor& surfaceIn,
-                                             SurfaceDescriptor* surfaceOut);
+  virtual bool RecvUpdateNoSwap(const EditArray& cset,
+                                const bool& isFirstPaint) MOZ_OVERRIDE;
 
-  NS_OVERRIDE virtual bool RecvUpdateNoSwap(const EditArray& cset,
-                                            const bool& isFirstPaint);
+  virtual PGrallocBufferParent*
+  AllocPGrallocBuffer(const gfxIntSize& aSize, const gfxContentType& aContent,
+                      MaybeMagicGrallocBufferHandle* aOutHandle) MOZ_OVERRIDE;
+  virtual bool
+  DeallocPGrallocBuffer(PGrallocBufferParent* actor) MOZ_OVERRIDE;
 
-  NS_OVERRIDE virtual PLayerParent* AllocPLayer();
-  NS_OVERRIDE virtual bool DeallocPLayer(PLayerParent* actor);
+  virtual PLayerParent* AllocPLayer() MOZ_OVERRIDE;
+  virtual bool DeallocPLayer(PLayerParent* actor) MOZ_OVERRIDE;
 
 private:
   nsRefPtr<ShadowLayerManager> mLayerManager;
   ShadowLayersManager* mShadowLayersManager;
   // Hold the root because it might be grafted under various
   // containers in the "real" layer tree
   nsRefPtr<ContainerLayer> mRoot;
   // When the widget/frame/browser stuff in this process begins its
--- a/gfx/layers/ipc/ipdl.mk
+++ b/gfx/layers/ipc/ipdl.mk
@@ -1,9 +1,10 @@
 # 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/.
 
 IPDLSRCS = \
   PCompositor.ipdl \
+  PGrallocBuffer.ipdl \
   PLayer.ipdl \
   PLayers.ipdl \
   $(NULL)
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -1,13 +1,14 @@
 /* -*- 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/. */
 
+#include "ipc/AutoOpenSurface.h"
 #include "mozilla/layers/PLayers.h"
 #include "mozilla/layers/ShadowLayers.h"
 
 #include "gfxSharedImageSurface.h"
 
 #include "CanvasLayerOGL.h"
 
 #include "gfxImageSurface.h"
@@ -300,40 +301,40 @@ void
 ShadowCanvasLayerOGL::Initialize(const Data& aData)
 {
   NS_RUNTIMEABORT("Incompatibe surface type");
 }
 
 void
 ShadowCanvasLayerOGL::Init(const CanvasSurface& aNewFront, bool needYFlip)
 {
-  nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(aNewFront);
+  AutoOpenSurface autoSurf(OPEN_READ_ONLY, aNewFront);
 
   mNeedsYFlip = needYFlip;
 
-  mTexImage = gl()->CreateTextureImage(surf->GetSize(),
-                                       surf->GetContentType(),
+  mTexImage = gl()->CreateTextureImage(autoSurf.Size(),
+                                       autoSurf.ContentType(),
                                        LOCAL_GL_CLAMP_TO_EDGE,
                                        mNeedsYFlip ? TextureImage::NeedsYFlip : TextureImage::NoFlags);
 }
 
 void
 ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront,
                            bool needYFlip,
                            CanvasSurface* aNewBack)
 {
   if (!mDestroyed) {
-    nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(aNewFront);
-    gfxIntSize sz = surf->GetSize();
+    AutoOpenSurface autoSurf(OPEN_READ_ONLY, aNewFront);
+    gfxIntSize sz = autoSurf.Size();
     if (!mTexImage || mTexImage->GetSize() != sz ||
-        mTexImage->GetContentType() != surf->GetContentType()) {
+        mTexImage->GetContentType() != autoSurf.ContentType()) {
       Init(aNewFront, needYFlip);
     }
     nsIntRegion updateRegion(nsIntRect(0, 0, sz.width, sz.height));
-    mTexImage->DirectUpdate(surf, updateRegion);
+    mTexImage->DirectUpdate(autoSurf.Get(), updateRegion);
   }
 
   *aNewBack = aNewFront;
 }
 
 void
 ShadowCanvasLayerOGL::DestroyFrontBuffer()
 {
@@ -360,16 +361,20 @@ ShadowCanvasLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
+  if (!mTexImage) {
+    return;
+  }
+
   mOGLManager->MakeCurrent();
 
   ShaderProgramOGL *program =
     mOGLManager->GetProgram(mTexImage->GetShaderProgramType(),
                             GetMaskLayer());
 
 
   gfx3DMatrix effectiveTransform = GetEffectiveTransform();
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -1,15 +1,16 @@
 /* -*- 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/. */
 
 #include "gfxSharedImageSurface.h"
 
+#include "ipc/AutoOpenSurface.h"
 #include "ImageLayerOGL.h"
 #include "gfxImageSurface.h"
 #include "gfxUtils.h"
 #include "yuv_convert.h"
 #include "GLContextProvider.h"
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
 # include "GLXLibrary.h"
 # include "mozilla/X11Util.h"
@@ -655,39 +656,33 @@ ShadowImageLayerOGL::ShadowImageLayerOGL
 
 ShadowImageLayerOGL::~ShadowImageLayerOGL()
 {}
 
 bool
 ShadowImageLayerOGL::Init(const SharedImage& aFront)
 {
   if (aFront.type() == SharedImage::TSurfaceDescriptor) {
-    SurfaceDescriptor desc = aFront.get_SurfaceDescriptor();
-    nsRefPtr<gfxASurface> surf =
-      ShadowLayerForwarder::OpenDescriptor(desc);
-    mSize = surf->GetSize();
+    AutoOpenSurface autoSurf(OPEN_READ_ONLY, aFront.get_SurfaceDescriptor());
+    mSize = autoSurf.Size();
     mTexImage = gl()->CreateTextureImage(nsIntSize(mSize.width, mSize.height),
-                                         surf->GetContentType(),
+                                         autoSurf.ContentType(),
                                          LOCAL_GL_CLAMP_TO_EDGE,
                                          mForceSingleTile
                                           ? TextureImage::ForceSingleTile
                                           : TextureImage::NoFlags);
     return true;
   } else {
     YUVImage yuv = aFront.get_YUVImage();
 
-    nsRefPtr<gfxSharedImageSurface> surfY =
-      gfxSharedImageSurface::Open(yuv.Ydata());
-    nsRefPtr<gfxSharedImageSurface> surfU =
-      gfxSharedImageSurface::Open(yuv.Udata());
-    nsRefPtr<gfxSharedImageSurface> surfV =
-      gfxSharedImageSurface::Open(yuv.Vdata());
+    AutoOpenSurface surfY(OPEN_READ_ONLY, yuv.Ydata());
+    AutoOpenSurface surfU(OPEN_READ_ONLY, yuv.Udata());
 
-    mSize = surfY->GetSize();
-    mCbCrSize = surfU->GetSize();
+    mSize = surfY.Size();
+    mCbCrSize = surfU.Size();
 
     if (!mYUVTexture[0].IsAllocated()) {
       mYUVTexture[0].Allocate(gl());
       mYUVTexture[1].Allocate(gl());
       mYUVTexture[2].Allocate(gl());
     }
 
     NS_ASSERTION(mYUVTexture[0].IsAllocated() &&
@@ -705,35 +700,34 @@ ShadowImageLayerOGL::Init(const SharedIm
 }
 
 void
 ShadowImageLayerOGL::Swap(const SharedImage& aNewFront,
                           SharedImage* aNewBack)
 {
   if (!mDestroyed) {
     if (aNewFront.type() == SharedImage::TSurfaceDescriptor) {
-      nsRefPtr<gfxASurface> surf =
-        ShadowLayerForwarder::OpenDescriptor(aNewFront.get_SurfaceDescriptor());
-      gfxIntSize size = surf->GetSize();
+      AutoOpenSurface surf(OPEN_READ_ONLY, aNewFront.get_SurfaceDescriptor());
+      gfxIntSize size = surf.Size();
       if (mSize != size || !mTexImage ||
-          mTexImage->GetContentType() != surf->GetContentType()) {
+          mTexImage->GetContentType() != surf.ContentType()) {
         Init(aNewFront);
       }
       // XXX this is always just ridiculously slow
       nsIntRegion updateRegion(nsIntRect(0, 0, size.width, size.height));
-      mTexImage->DirectUpdate(surf, updateRegion);
+      mTexImage->DirectUpdate(surf.Get(), updateRegion);
     } else {
       const YUVImage& yuv = aNewFront.get_YUVImage();
 
-      nsRefPtr<gfxSharedImageSurface> surfY =
-        gfxSharedImageSurface::Open(yuv.Ydata());
-      nsRefPtr<gfxSharedImageSurface> surfU =
-        gfxSharedImageSurface::Open(yuv.Udata());
-      nsRefPtr<gfxSharedImageSurface> surfV =
-        gfxSharedImageSurface::Open(yuv.Vdata());
+      AutoOpenSurface asurfY(OPEN_READ_ONLY, yuv.Ydata());
+      AutoOpenSurface asurfU(OPEN_READ_ONLY, yuv.Udata());
+      AutoOpenSurface asurfV(OPEN_READ_ONLY, yuv.Vdata());
+      nsRefPtr<gfxImageSurface> surfY = asurfY.GetAsImage();
+      nsRefPtr<gfxImageSurface> surfU = asurfU.GetAsImage();
+      nsRefPtr<gfxImageSurface> surfV = asurfV.GetAsImage();
       mPictureRect = yuv.picture();
 
       gfxIntSize size = surfY->GetSize();
       gfxIntSize CbCrSize = surfU->GetSize();
       if (size != mSize || mCbCrSize != CbCrSize || !mYUVTexture[0].IsAllocated()) {
         Init(aNewFront);
       }
 
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -1,13 +1,14 @@
 /* -*- 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/. */
 
+#include "ipc/AutoOpenSurface.h"
 #include "mozilla/layers/PLayers.h"
 #include "TiledLayerBuffer.h"
 
 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
 #include "mozilla/Util.h"
 
 #include "mozilla/layers/ShadowLayers.h"
 
@@ -963,17 +964,17 @@ ShadowThebesLayerOGL::ShadowThebesLayerO
 }
 
 ShadowThebesLayerOGL::~ShadowThebesLayerOGL()
 {}
 
 bool
 ShadowThebesLayerOGL::ShouldDoubleBuffer()
 {
-#ifdef ANDROID
+#ifdef MOZ_JAVA_COMPOSITOR
   /* Enable double-buffering on Android so that we don't block for as long
    * when uploading textures. This is a work-around for the lack of an
    * asynchronous texture upload facility.
    *
    * As the progressive upload relies on tile size, doing this when large
    * tiles are in use is harder to justify.
    *
    * XXX When bug 730718 is fixed, we will likely want this only to apply for
@@ -987,17 +988,18 @@ ShadowThebesLayerOGL::ShouldDoubleBuffer
 }
 
 void
 ShadowThebesLayerOGL::EnsureTextureUpdated()
 {
   if (mRegionPendingUpload.IsEmpty() || !IsSurfaceDescriptorValid(mFrontBufferDescriptor))
     return;
 
-  mBuffer->DirectUpdate(mFrontBuffer.Buffer(), mRegionPendingUpload);
+  AutoOpenSurface frontSurface(OPEN_READ_ONLY, mFrontBuffer.Buffer());
+  mBuffer->DirectUpdate(frontSurface.Get(), mRegionPendingUpload);
   mRegionPendingUpload.SetEmpty();
 }
 
 static bool
 EnsureTextureUpdatedCallback(gl::TextureImage* aImage, int aTileNumber,
                              void *aData)
 {
   // If this tile intersects with the region we asked to update, it will be
@@ -1040,34 +1042,34 @@ ShadowThebesLayerOGL::EnsureTextureUpdat
 
     // Check if any part of the texture that's pending upload intersects with
     // this region.
     updateRegion.And(aRegion, mRegionPendingUpload);
 
     if (updateRegion.IsEmpty())
       continue;
 
+    AutoOpenSurface surface(OPEN_READ_ONLY, mFrontBuffer.Buffer());
     nsRefPtr<TextureImage> texImage;
     if (!gl()->CanUploadSubTextures()) {
       // When sub-textures are unsupported, TiledTextureImage expands the
       // boundaries of DirectUpdate to tile boundaries. So that we don't
       // re-upload texture data, use the tile iteration to monitor how much
       // of the texture was actually uploaded.
-      gfxASurface* surface = mFrontBuffer.Buffer();
-      gfxIntSize size = surface->GetSize();
-      mBuffer->EnsureTexture(size, surface->GetContentType());
+      gfxIntSize size = surface.Size();
+      mBuffer->EnsureTexture(size, surface.ContentType());
       texImage = mBuffer->GetTextureImage().get();
       if (texImage->GetTileCount() > 1)
         texImage->SetIterationCallback(EnsureTextureUpdatedCallback, (void *)&updateRegion);
       else
         updateRegion = nsIntRect(0, 0, size.width, size.height);
     }
 
     // Upload this quadrant of the region.
-    mBuffer->DirectUpdate(mFrontBuffer.Buffer(), updateRegion);
+    mBuffer->DirectUpdate(surface.Get(), updateRegion);
 
     if (!gl()->CanUploadSubTextures())
       texImage->SetIterationCallback(nsnull, nsnull);
 
     // Remove the updated region from the pending-upload region.
     mRegionPendingUpload.Sub(mRegionPendingUpload, updateRegion);
   }
 }
@@ -1097,26 +1099,27 @@ ShadowThebesLayerOGL::ProgressiveUpload(
   // Mark the task as completed
   mUploadTask = nsnull;
 
   if (mRegionPendingUpload.IsEmpty() || mBuffer == nsnull)
     return;
 
   // Set a tile iteration callback so we can cancel the upload after a tile
   // has been uploaded and subtract it from mRegionPendingUpload
-  mBuffer->EnsureTexture(mFrontBuffer.Buffer()->GetSize(),
-                         mFrontBuffer.Buffer()->GetContentType());
+  AutoOpenSurface frontSurface(OPEN_READ_ONLY, mFrontBuffer.Buffer());
+  mBuffer->EnsureTexture(frontSurface.Size(),
+                         frontSurface.ContentType());
   nsRefPtr<gl::TextureImage> tiledImage = mBuffer->GetTextureImage().get();
   if (tiledImage->GetTileCount() > 1)
     tiledImage->SetIterationCallback(ProgressiveUploadCallback, (void *)&mRegionPendingUpload);
   else
     mRegionPendingUpload.SetEmpty();
 
   // Upload a tile
-  mBuffer->DirectUpdate(mFrontBuffer.Buffer(), mRegionPendingUpload);
+  mBuffer->DirectUpdate(frontSurface.Get(), mRegionPendingUpload);
 
   // Remove the iteration callback
   tiledImage->SetIterationCallback(nsnull, nsnull);
 
   if (!mRegionPendingUpload.IsEmpty()) {
     // Schedule another upload task
     mUploadTask = NewRunnableMethod(this, &ShadowThebesLayerOGL::ProgressiveUpload);
     // Post a delayed task to complete more of the upload - give a reasonable delay to allow
@@ -1130,23 +1133,21 @@ ShadowThebesLayerOGL::Swap(const ThebesB
                            const nsIntRegion& aUpdatedRegion,
                            OptionalThebesBuffer* aNewBack,
                            nsIntRegion* aNewBackValidRegion,
                            OptionalThebesBuffer* aReadOnlyFront,
                            nsIntRegion* aFrontUpdatedRegion)
 {
   // The double-buffer path is copied and adapted from BasicLayers.cpp
   if (ShouldDoubleBuffer()) {
-    nsRefPtr<gfxASurface> newFrontBuffer =
-      ShadowLayerForwarder::OpenDescriptor(aNewFront.buffer());
+    AutoOpenSurface newFrontBuffer(OPEN_READ_ONLY, aNewFront.buffer());
 
     if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
-      nsRefPtr<gfxASurface> currentFront =
-        ShadowLayerForwarder::OpenDescriptor(mFrontBufferDescriptor);
-      if (currentFront->GetSize() != newFrontBuffer->GetSize()) {
+      AutoOpenSurface currentFront(OPEN_READ_ONLY, mFrontBufferDescriptor);
+      if (currentFront.Size() != newFrontBuffer.Size()) {
         // Current front buffer is obsolete
         DestroyFrontBuffer();
       }
     }
 
     // This code relies on Swap() arriving *after* attribute mutations.
     if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
       *aNewBack = ThebesBuffer();
@@ -1154,58 +1155,59 @@ ShadowThebesLayerOGL::Swap(const ThebesB
     } else {
       *aNewBack = null_t();
     }
 
     // We have to invalidate the pixels painted into the new buffer.
     // They might overlap with our old pixels.
     aNewBackValidRegion->Sub(mOldValidRegion, aUpdatedRegion);
 
-    nsRefPtr<gfxASurface> unused;
+    SurfaceDescriptor unused;
     nsIntRect backRect;
     nsIntPoint backRotation;
     mFrontBuffer.Swap(
-      newFrontBuffer, aNewFront.rect(), aNewFront.rotation(),
-      getter_AddRefs(unused), &backRect, &backRotation);
+      aNewFront.buffer(), aNewFront.rect(), aNewFront.rotation(),
+      &unused, &backRect, &backRotation);
 
     if (aNewBack->type() != OptionalThebesBuffer::Tnull_t) {
       aNewBack->get_ThebesBuffer().rect() = backRect;
       aNewBack->get_ThebesBuffer().rotation() = backRotation;
     }
 
     mFrontBufferDescriptor = aNewFront.buffer();
 
     // Upload new front-buffer to texture
     if (!mDestroyed) {
       if (!mBuffer) {
         mBuffer = new ShadowBufferOGL(this);
       }
-      nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(mFrontBufferDescriptor);
-      mBuffer->Upload(surf, aUpdatedRegion, aNewFront.rect(), aNewFront.rotation(), true, mRegionPendingUpload);
+      AutoOpenSurface frontSurface(OPEN_READ_ONLY, mFrontBufferDescriptor);
+      mBuffer->Upload(frontSurface.Get(), aUpdatedRegion, aNewFront.rect(), aNewFront.rotation(), true, mRegionPendingUpload);
 
       // Schedule a task to progressively upload the texture
       if (!mUploadTask) {
         mUploadTask = NewRunnableMethod(this, &ShadowThebesLayerOGL::ProgressiveUpload);
+        // XXX magic delay constant
         MessageLoop::current()->PostDelayedTask(FROM_HERE, mUploadTask, 5);
       }
     }
 
     *aReadOnlyFront = aNewFront;
     *aFrontUpdatedRegion = aUpdatedRegion;
 
     return;
   }
 
   // Single-buffer path
   if (!mDestroyed) {
     if (!mBuffer) {
       mBuffer = new ShadowBufferOGL(this);
     }
-    nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(aNewFront.buffer());
-    mBuffer->Upload(surf, aUpdatedRegion, aNewFront.rect(), aNewFront.rotation(), false, mRegionPendingUpload);
+    AutoOpenSurface frontSurface(OPEN_READ_ONLY, aNewFront.buffer());
+    mBuffer->Upload(frontSurface.Get(), aUpdatedRegion, aNewFront.rect(), aNewFront.rotation(), false, mRegionPendingUpload);
   }
 
   *aNewBack = aNewFront;
   *aNewBackValidRegion = mValidRegion;
   *aReadOnlyFront = null_t();
   aFrontUpdatedRegion->SetEmpty();
 }
 
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -62,55 +62,53 @@ public:
     MOZ_COUNT_CTOR(ShadowThebesLayerBufferOGL);
   }
 
   ~ShadowThebesLayerBufferOGL()
   {
     MOZ_COUNT_DTOR(ShadowThebesLayerBufferOGL);
   }
 
-  void Swap(gfxASurface* aNewBuffer,
+  void Swap(const SurfaceDescriptor& aDescriptor,
             const nsIntRect& aNewRect, const nsIntPoint& aNewRotation,
-            gfxASurface** aOldBuffer,
+            SurfaceDescriptor* aOldDescriptor,
             nsIntRect* aOldRect, nsIntPoint* aOldRotation)
   {
+    *aOldDescriptor = mBuffer;
     *aOldRect = mBufferRect;
     *aOldRotation = mBufferRotation;
-    nsRefPtr<gfxASurface> oldBuffer = mBuffer;
 
+    mBuffer = aDescriptor;
     mBufferRect = aNewRect;
     mBufferRotation = aNewRotation;
-    mBuffer = aNewBuffer;
-    oldBuffer.forget(aOldBuffer);
   }
 
   nsIntRect Rect() {
     return mBufferRect;
   }
 
   nsIntPoint Rotation() {
     return mBufferRotation;
   }
 
-  gfxASurface* Buffer() {
+  SurfaceDescriptor Buffer() {
     return mBuffer;
   }
 
   /**
    * Wipe out all retained contents. Call this when the entire
    * buffer becomes invalid.
    */
   void Clear()
   {
-    mBuffer = nsnull;
     mBufferRect.SetEmpty();
   }
 
 protected:
-  nsRefPtr<gfxASurface> mBuffer;
+  SurfaceDescriptor mBuffer;
   nsIntRect mBufferRect;
   nsIntPoint mBufferRotation;
 };
 
 class ShadowThebesLayerOGL : public ShadowThebesLayer,
                              public LayerOGL
 {
 public:
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -90,17 +90,18 @@ public:
         SurfaceTypeSubsurface,
         SurfaceTypeD2D,
         SurfaceTypeMax
     } gfxSurfaceType;
 
     typedef enum {
         CONTENT_COLOR       = 0x1000,
         CONTENT_ALPHA       = 0x2000,
-        CONTENT_COLOR_ALPHA = 0x3000
+        CONTENT_COLOR_ALPHA = 0x3000,
+        CONTENT_SENTINEL    = 0xffff
     } gfxContentType;
 
     /** Wrap the given cairo surface and return a gfxASurface for it.
      * This adds a reference to csurf (owned by the returned gfxASurface).
      */
     static already_AddRefed<gfxASurface> Wrap(cairo_surface_t *csurf);
 
     /*** this DOES NOT addref the surface */
--- a/gfx/thebes/gfxPattern.h
+++ b/gfx/thebes/gfxPattern.h
@@ -83,17 +83,18 @@ public:
     int CairoStatus();
 
     enum GraphicsFilter {
         FILTER_FAST,
         FILTER_GOOD,
         FILTER_BEST,
         FILTER_NEAREST,
         FILTER_BILINEAR,
-        FILTER_GAUSSIAN
+        FILTER_GAUSSIAN,
+        FILTER_SENTINEL
     };
 
     void SetFilter(GraphicsFilter filter);
     GraphicsFilter Filter() const;
 
     /* returns TRUE if it succeeded */
     bool GetSolidColor(gfxRGBA& aColor);
 
--- a/hal/Makefile.in
+++ b/hal/Makefile.in
@@ -19,16 +19,17 @@ VPATH       = \
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE         = hal
 LIBRARY_NAME   = hal_s
 FORCE_STATIC_LIB = 1
 LIBXUL_LIBRARY = 1
 EXPORT_LIBRARY = 1
+FAIL_ON_WARNINGS = 1
 
 EXPORTS_NAMESPACES = mozilla
 EXPORTS_mozilla = \
   Hal.h \
   HalImpl.h \
   HalSandbox.h \
   HalSensor.h \
   HalTypes.h \
--- a/hal/cocoa/smslib.mm
+++ b/hal/cocoa/smslib.mm
@@ -267,17 +267,17 @@ static void prefSynchronize(void);
 // static long getMicroseconds(void);
 float fakeData(NSTimeInterval time);
 
 #pragma mark Static variables
 
 static int debugging = NO;		// True if debugging (synthetic data)
 static io_connect_t connection;	// Connection for reading accel values
 static int running = NO;		// True if we successfully started
-static int sensorNum = 0;		// The current index into sensors[]
+static unsigned int sensorNum = 0;		// The current index into sensors[]
 static const char *serviceName;	// The name of the current service
 static char *iRecord, *oRecord;	// Pointers to read/write records for sensor
 static int recordSize;			// Size of read/write records
 static unsigned int function;	// Which kernel function should be used
 static float zeros[3];			// X, Y and Z zero calibration values
 static float onegs[3];			// X, Y and Z one-g calibration values
 
 #pragma mark Defines
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -39,17 +39,17 @@
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "APKOpen.h"
 #endif
 
 using mozilla::MonitorAutoLock;
 using mozilla::ipc::GeckoChildProcessHost;
 
-#ifdef MOZ_WIDGET_ANDROID
+#ifdef ANDROID
 // Like its predecessor in nsExceptionHandler.cpp, this is
 // the magic number of a file descriptor remapping we must
 // preserve for the child process.
 static const int kMagicAndroidSystemPropFd = 5;
 #endif
 
 static bool
 ShouldHaveDirectoryService()
@@ -248,16 +248,20 @@ void GeckoChildProcessHost::InitWindowsG
     }
   }
 }
 #endif
 
 bool
 GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs, base::ProcessArchitecture arch)
 {
+#ifdef MOZ_CRASHREPORTER
+  CrashReporter::OOPInit();
+#endif
+
 #ifdef XP_WIN
   InitWindowsGroupID();
 #endif
 
   PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ? 
     PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
   NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
@@ -289,16 +293,20 @@ GeckoChildProcessHost::SyncLaunch(std::v
   }
 
   return mLaunched;
 }
 
 bool
 GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
 {
+#ifdef MOZ_CRASHREPORTER
+  CrashReporter::OOPInit();
+#endif
+
 #ifdef XP_WIN
   InitWindowsGroupID();
 #endif
 
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
   ioLoop->PostTask(FROM_HERE,
                    NewRunnableMethod(this,
                                      &GeckoChildProcessHost::PerformAsyncLaunch,
@@ -471,32 +479,34 @@ GeckoChildProcessHost::PerformAsyncLaunc
     mFileMap.push_back(std::pair<int,int>(cache->fd, cache->fd));
     cacheStr.Append(cache->name);
     cacheStr.AppendPrintf(":%d;", cache->fd);
     cache++;
   }
   // fill the last arg with something if there's no cache
   if (cacheStr.IsEmpty())
     cacheStr.AppendLiteral("-");
+#endif  // MOZ_WIDGET_ANDROID
 
+#ifdef ANDROID
   // Remap the Android property workspace to a well-known int,
   // and update the environment to reflect the new value for the
   // child process.
   const char *apws = getenv("ANDROID_PROPERTY_WORKSPACE");
   if (apws) {
     int fd = atoi(apws);
     mFileMap.push_back(std::pair<int, int>(fd, kMagicAndroidSystemPropFd));
 
     char buf[32];
     char *szptr = strchr(apws, ',');
 
     snprintf(buf, sizeof(buf), "%d%s", kMagicAndroidSystemPropFd, szptr);
     newEnvVars["ANDROID_PROPERTY_WORKSPACE"] = buf;
   }
-#endif  // MOZ_WIDGET_ANDROID
+#endif  // ANDROID
 
   // remap the IPC socket fd to a well-known int, as the OS does for
   // STDOUT_FILENO, for example
   int srcChannelFd, dstChannelFd;
   channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
   mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
 
   // no need for kProcessChannelID, the child process inherits the
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -39,20 +39,21 @@
 // FileDescriptor fails to build)
 namespace base { struct FileDescriptor { }; }
 #endif
 
 using mozilla::layers::LayerManager;
 
 namespace mozilla {
 
-typedef gfxPattern::GraphicsFilter GraphicsFilterType;
+typedef gfxASurface::gfxContentType gfxContentType;
+typedef gfxASurface::gfxImageFormat PixelFormat;
 typedef gfxASurface::gfxSurfaceType gfxSurfaceType;
+typedef gfxPattern::GraphicsFilter GraphicsFilterType;
 typedef LayerManager::LayersBackend LayersBackend;
-typedef gfxASurface::gfxImageFormat PixelFormat;
 
 // 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 {
@@ -490,150 +491,50 @@ struct ParamTraits<gfx3DMatrix>
     return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
             Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
             Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
             Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44));
 #undef Rd
   }
 };
 
- template<>
-struct ParamTraits<mozilla::GraphicsFilterType>
-{
-  typedef mozilla::GraphicsFilterType paramType;
-
-  static void Write(Message* msg, const paramType& param)
-  {
-    switch (param) {
-    case gfxPattern::FILTER_FAST:
-    case gfxPattern::FILTER_GOOD:
-    case gfxPattern::FILTER_BEST:
-    case gfxPattern::FILTER_NEAREST:
-    case gfxPattern::FILTER_BILINEAR:
-    case gfxPattern::FILTER_GAUSSIAN:
-      WriteParam(msg, int32(param));
-      return;
-
-    }
-    NS_RUNTIMEABORT("not reached");
-  }
-
-  static bool Read(const Message* msg, void** iter, paramType* result)
-  {
-    int32 filter;
-    if (!ReadParam(msg, iter, &filter))
-      return false;
+template <>
+struct ParamTraits<mozilla::gfxContentType>
+  : public EnumSerializer<mozilla::gfxContentType,
+                          gfxASurface::CONTENT_COLOR,
+                          gfxASurface::CONTENT_SENTINEL>
+{};
 
-    switch (filter) {
-    case gfxPattern::FILTER_FAST:
-    case gfxPattern::FILTER_GOOD:
-    case gfxPattern::FILTER_BEST:
-    case gfxPattern::FILTER_NEAREST:
-    case gfxPattern::FILTER_BILINEAR:
-    case gfxPattern::FILTER_GAUSSIAN:
-      *result = paramType(filter);
-      return true;
-
-    default:
-      return false;
-    }
-  }
-};
-
- template<>
+template <>
 struct ParamTraits<mozilla::gfxSurfaceType>
-{
-  typedef mozilla::gfxSurfaceType paramType;
-
-  static void Write(Message* msg, const paramType& param)
-  {
-    if (gfxASurface::SurfaceTypeImage <= param &&
-        param < gfxASurface::SurfaceTypeMax) {
-      WriteParam(msg, int32(param));
-      return;
-    }
-    NS_RUNTIMEABORT("surface type not reached");
-  }
-
-  static bool Read(const Message* msg, void** iter, paramType* result)
-  {
-    int32 filter;
-    if (!ReadParam(msg, iter, &filter))
-      return false;
+  : public EnumSerializer<gfxASurface::gfxSurfaceType,
+                          gfxASurface::SurfaceTypeImage,
+                          gfxASurface::SurfaceTypeMax>
+{};
 
-    if (gfxASurface::SurfaceTypeImage <= filter &&
-        filter < gfxASurface::SurfaceTypeMax) {
-      *result = paramType(filter);
-      return true;
-    }
-    return false;
-  }
-};
-
-template<>
-struct ParamTraits<mozilla::LayersBackend>
-{
-  typedef mozilla::LayersBackend paramType;
-
-  static void Write(Message* msg, const paramType& param)
-  {
-    if (LayerManager::LAYERS_NONE <= param &&
-        param < LayerManager::LAYERS_LAST) {
-      WriteParam(msg, int32(param));
-      return;
-    }
-    NS_RUNTIMEABORT("backend type not reached");
-  }
-
-  static bool Read(const Message* msg, void** iter, paramType* result)
-  {
-    int32 type;
-    if (!ReadParam(msg, iter, &type))
-      return false;
+template <>
+struct ParamTraits<mozilla::GraphicsFilterType>
+  : public EnumSerializer<mozilla::GraphicsFilterType,
+                          gfxPattern::FILTER_FAST,
+                          gfxPattern::FILTER_SENTINEL>
+{};
 
-    if (LayerManager::LAYERS_NONE <= type &&
-        type < LayerManager::LAYERS_LAST) {
-      *result = paramType(type);
-      return true;
-    }
-    return false;
-  }
-};
-
-template<>
-struct ParamTraits<mozilla::PixelFormat>
-{
-  typedef mozilla::PixelFormat paramType;
-
-  static bool IsLegalPixelFormat(const paramType& format)
-  {
-    return (gfxASurface::ImageFormatARGB32 <= format &&
-            format < gfxASurface::ImageFormatUnknown);
-  }
+template <>
+struct ParamTraits<mozilla::LayersBackend>
+  : public EnumSerializer<mozilla::LayersBackend,
+                          LayerManager::LAYERS_NONE,
+                          LayerManager::LAYERS_LAST>
+{};
 
-  static void Write(Message* msg, const paramType& param)
-  {
-    if (!IsLegalPixelFormat(param)) {
-      NS_RUNTIMEABORT("Unknown pixel format");
-    }
-    WriteParam(msg, int32(param));
-    return;
-  }
-
-  static bool Read(const Message* msg, void** iter, paramType* result)
-  {
-    int32 format;
-    if (!ReadParam(msg, iter, &format) ||
-        !IsLegalPixelFormat(paramType(format))) {
-      return false;
-    }
-    *result = paramType(format);
-    return true;
-  }
-};
+template <>
+struct ParamTraits<mozilla::PixelFormat>
+  : public EnumSerializer<mozilla::PixelFormat,
+                          gfxASurface::ImageFormatARGB32,
+                          gfxASurface::ImageFormatUnknown>
+{};
 
 template<>
 struct ParamTraits<gfxRGBA>
 {
   typedef gfxRGBA paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -325,16 +325,17 @@ Any type, naked or pointer, can be const
                     ptrptr=self.ptrptr, ptrconstptr=self.ptrconstptr,
                     ref=self.ref,
                     T=copy.deepcopy(self.T, memo))
 Type.BOOL = Type('bool')
 Type.INT = Type('int')
 Type.INT32 = Type('int32')
 Type.INTPTR = Type('intptr_t')
 Type.UINT32 = Type('uint32')
+Type.UINT32PTR = Type('uint32', ptr=1)
 Type.SIZE = Type('size_t')
 Type.VOID = Type('void')
 Type.VOIDPTR = Type('void', ptr=1)
 
 class TypeArray(Node):
     def __init__(self, basetype, nmemb):
         '''the type |basetype DECLNAME[nmemb]|.  |nmemb| is an Expr'''
         self.basetype = basetype
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -661,16 +661,19 @@ class _StructField(_CompoundTypeComponen
 
     def memberVar(self):
         return ExprVar(self.name + '_')
 
     def initStmts(self):
         if self.recursive:
             return [ StmtExpr(ExprAssn(self.memberVar(),
                                        ExprNew(self.bareType()))) ]
+        elif self.ipdltype.isIPDL() and self.ipdltype.isActor():
+            return [ StmtExpr(ExprAssn(self.memberVar(),
+                                       ExprLiteral.NULL)) ]
         else:
             return []
 
     def destructStmts(self):
         if self.recursive:
             return [ StmtExpr(ExprDelete(self.memberVar())) ]
         else:
             return []
@@ -3081,26 +3084,28 @@ class _GenerateProtocolActorCode(ipdl.as
                 const=1))
             otherpid.addstmts([
                 StmtReturn(ExprCall(
                     ExprVar('base::GetProcId'),
                     args=[ p.otherProcessVar() ])),
             ])
 
             dumpvar = ExprVar('aDump')
+            seqvar = ExprVar('aSequence')
             getdump = MethodDefn(MethodDecl(
                 'TakeMinidump',
-                params=[ Decl(Type('nsIFile', ptrptr=1), dumpvar.name) ],
+                params=[ Decl(Type('nsIFile', ptrptr=1), dumpvar.name),
+                         Decl(Type.UINT32PTR, seqvar.name)],
                 ret=Type.BOOL,
                 const=1))
             getdump.addstmts([
                 CppDirective('ifdef', 'MOZ_CRASHREPORTER'),
                 StmtReturn(ExprCall(
                     ExprVar('XRE_TakeMinidumpForChild'),
-                    args=[ ExprCall(otherpidvar), dumpvar ])),
+                    args=[ ExprCall(otherpidvar), dumpvar, seqvar ])),
                 CppDirective('else'),
                 StmtReturn.FALSE,
                 CppDirective('endif')
             ])
             self.cls.addstmts([ otherpid, Whitespace.NL,
                                 getdump, Whitespace.NL ])
 
         if (ptype.isToplevel() and self.side is 'parent'
--- a/ipc/ipdl/test/cxx/PTestDataStructures.ipdl
+++ b/ipc/ipdl/test/cxx/PTestDataStructures.ipdl
@@ -34,16 +34,19 @@ parent:
                IntDoubleArrays i3)
         returns (IntDoubleArrays o1,
                  IntDoubleArrays o2,
                  IntDoubleArrays o3);
 
     sync Test6(IntDoubleArrays[] i1)
         returns (IntDoubleArrays[] o1);
 
+    sync Test7_0(ActorWrapper a1)
+        returns (ActorWrapper o1);
+
     sync Test7(Actors i1,
                Actors i2,
                Actors i3)
         returns (Actors o1,
                  Actors o2,
                  Actors o3);
 
     sync Test8(Actors[] i1)
--- a/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
+++ b/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
@@ -23,16 +23,20 @@ union IntDoubleArrays {
 };
 
 struct SIntDoubleArrays {
     int i;
     int[] ai;
     double[] ad;
 };
 
+struct ActorWrapper {
+    PTestDataStructuresSub actor;
+};
+
 union Actors {
     int;
     int[];
     PTestDataStructuresSub[];
 };
 
 struct SActors {
     int i;
--- a/ipc/ipdl/test/cxx/TestDataStructures.cpp
+++ b/ipc/ipdl/test/cxx/TestDataStructures.cpp
@@ -148,16 +148,33 @@ bool TestDataStructuresParent::RecvTest5
 
     *o1 = i1;
     *o2 = i2a;
     *o3 = i3a;
 
     return true;
 }
 
+bool
+TestDataStructuresParent::RecvTest7_0(const ActorWrapper& i1,
+                                      ActorWrapper* o1)
+{
+    if (i1.actorChild() != nsnull)
+        fail("child side actor should always be null");
+
+    if (i1.actorParent() != mKids[0])
+        fail("should have got back same actor on parent side");
+
+    o1->actorParent() = mKids[0];
+    // malicious behavior
+    o1->actorChild() =
+        reinterpret_cast<PTestDataStructuresSubChild*>(0xdeadbeef);
+    return true;
+}
+
 bool TestDataStructuresParent::RecvTest6(
         const InfallibleTArray<IntDoubleArrays>& i1,
         InfallibleTArray<IntDoubleArrays>* o1)
 {
     test_assert(3 == i1.Length(), "wrong length");
 
     IntDoubleArrays id1(i1[0]);
     test_assert(42 == id1.get_int(), "wrong value");
@@ -460,16 +477,17 @@ TestDataStructuresChild::RecvStart()
     puts("[TestDataStructuresChild] starting");
 
     Test1();
     Test2();
     Test3();
     Test4();
     Test5();
     Test6();
+    Test7_0();
     Test7();
     Test8();
     Test9();
     Test10();
     Test11();
     Test12();
     Test13();
     Test14();
@@ -606,16 +624,38 @@ TestDataStructuresChild::Test6()
     test_assert(42 == od1.get_int(), "wrong value");
     assert_arrays_equal(id2, od2);
     assert_arrays_equal(id3, od3);
 
     printf("  passed %s\n", __FUNCTION__);
 }
 
 void
+TestDataStructuresChild::Test7_0()
+{
+    ActorWrapper iaw;
+    if (iaw.actorChild() != nsnull || iaw.actorParent() != nsnull)
+        fail("actor members should be null initially");
+
+    iaw.actorChild() = mKids[0];
+    if (iaw.actorParent() != nsnull)
+        fail("parent should be null on child side after set");
+
+    ActorWrapper oaw;
+    if (!SendTest7_0(iaw, &oaw))
+        fail("sending Test7_0");
+
+    if (oaw.actorParent() != nsnull)
+        fail("parent accessor on actor-struct members should always be null in child");
+
+    if (oaw.actorChild() != mKids[0])
+        fail("should have got back same child-side actor");
+}
+
+void
 TestDataStructuresChild::Test7()
 {
     Actors i1(42);
     InfallibleTArray<int> i2a;
     i2a.AppendElement(1);  i2a.AppendElement(2);  i2a.AppendElement(3);
 
     Actors o1, o2, o3;
     if (!SendTest7(i1, Actors(i2a), Actors(mKids), &o1, &o2, &o3))
--- a/ipc/ipdl/test/cxx/TestDataStructures.h
+++ b/ipc/ipdl/test/cxx/TestDataStructures.h
@@ -86,16 +86,20 @@ protected:
             IntDoubleArrays* o3);
 
     NS_OVERRIDE
     virtual bool RecvTest6(
             const InfallibleTArray<IntDoubleArrays>& i1,
             InfallibleTArray<IntDoubleArrays>* o1);
 
     NS_OVERRIDE
+    virtual bool RecvTest7_0(const ActorWrapper& i1,
+                             ActorWrapper* o1);
+
+    NS_OVERRIDE
     virtual bool RecvTest7(
             const Actors& i1,
             const Actors& i2,
             const Actors& i3,
             Actors* o1,
             Actors* o2,
             Actors* o3);
 
@@ -221,16 +225,17 @@ protected:
 
 private:
     void Test1();
     void Test2();
     void Test3();
     void Test4();
     void Test5();
     void Test6();
+    void Test7_0();
     void Test7();
     void Test8();
     void Test9();
     void Test10();
     void Test11();
     void Test12();
     void Test13();
     void Test14();
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -745,16 +745,18 @@ EXTRA_LIBS += $(MOZ_ZLIB_LIBS)
 ifdef _MSC_VER
 # XXX We should add this to CXXFLAGS, too?
 CFLAGS += -fp:precise
 
 ifeq ($(CPU_ARCH),x86)
 # Workaround compiler bug on PGO (Bug 721284)
 MonoIC.$(OBJ_SUFFIX): CXXFLAGS += -GL-
 Compiler.$(OBJ_SUFFIX): CXXFLAGS += -GL-
+# Ditto (Bug 772303)
+RegExp.$(OBJ_SUFFIX): CXXFLAGS += -GL-
 endif
 endif # _MSC_VER
 
 ifeq ($(OS_ARCH),FreeBSD)
 EXTRA_LIBS	+= -pthread
 endif
 ifeq ($(OS_ARCH),Linux)
 EXTRA_LIBS	+= -ldl
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -5,16 +5,17 @@
  * 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 "jscntxt.h"
 #include "jsonparser.h"
 
 #include "builtin/Eval.h"
 #include "frontend/BytecodeCompiler.h"
+#include "mozilla/HashFunctions.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinterpinlines.h"
 
 using namespace js;
 
 // We should be able to assert this for *any* fp->scopeChain().
 static void
@@ -25,160 +26,100 @@ AssertInnerizedScopeChain(JSContext *cx,
         if (JSObjectOp op = o->getClass()->ext.innerObject) {
             Rooted<JSObject*> obj(cx, o);
             JS_ASSERT(op(cx, obj) == o);
         }
     }
 #endif
 }
 
-void
-EvalCache::purge()
+static bool
+IsEvalCacheCandidate(JSScript *script)
 {
-    // Purge all scripts from the eval cache. In addition to removing them from
-    // table_, null out the evalHashLink field of any script removed. Since
-    // evalHashLink is in a union with globalObject, this allows the GC to
-    // indiscriminately use the union as a nullable globalObject pointer.
-    for (size_t i = 0; i < ArrayLength(table_); ++i) {
-        for (JSScript **listHeadp = &table_[i]; *listHeadp; ) {
-            JSScript *script = *listHeadp;
-            JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
-            *listHeadp = script->evalHashLink();
-            script->evalHashLink() = NULL;
-        }
-    }
-}
-
-JSScript **
-EvalCache::bucket(JSLinearString *str)
-{
-    const jschar *s = str->chars();
-    size_t n = str->length();
-
-    if (n > 100)
-        n = 100;
-    uint32_t h;
-    for (h = 0; n; s++, n--)
-        h = JS_ROTATE_LEFT32(h, 4) ^ *s;
-
-    h *= JS_GOLDEN_RATIO;
-    h >>= 32 - SHIFT;
-    JS_ASSERT(h < ArrayLength(table_));
-    return &table_[h];
+    // Make sure there are no inner objects which might use the wrong parent
+    // and/or call scope by reusing the previous eval's script. Skip the
+    // script's first object, which entrains the eval's scope.
+    return script->savedCallerFun &&
+           !script->hasSingletons &&
+           script->objects()->length == 1 &&
+           !script->hasRegexps();
 }
 
-static JSScript *
-EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, unsigned staticLevel,
-                JSPrincipals *principals, JSObject &scopeobj, JSScript **bucket)
+/* static */ HashNumber
+EvalCacheHashPolicy::hash(const EvalCacheLookup &l)
 {
-    // Cache local eval scripts indexed by source qualified by scope.
-    // 
-    // An eval cache entry should never be considered a hit unless its
-    // strictness matches that of the new eval code. The existing code takes
-    // care of this, because hits are qualified by the function from which
-    // eval was called, whose strictness doesn't change. (We don't cache evals
-    // in eval code, so the calling function corresponds to the calling script,
-    // and its strictness never varies.) Scripts produced by calls to eval from
-    // global code aren't cached.
-    // 
-    // FIXME bug 620141: Qualify hits by calling script rather than function.
-    // Then we wouldn't need the unintuitive !isEvalFrame() hack in EvalKernel
-    // to avoid caching nested evals in functions (thus potentially mismatching
-    // on strict mode), and we could cache evals in global code if desired.
-    unsigned count = 0;
-    JSScript **scriptp = bucket;
+    return AddToHash(HashString(l.str->chars(), l.str->length()),
+                     l.caller,
+                     l.staticLevel,
+                     l.version,
+                     l.compartment);
+}
 
-    JSVersion version = cx->findVersion();
-    JSScript *script;
-    JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals;
-    while ((script = *scriptp) != NULL) {
-        if (script->savedCallerFun &&
-            script->staticLevel == staticLevel &&
-            script->getVersion() == version &&
-            !script->hasSingletons &&
-            (!subsume || script->principals == principals ||
-             (subsume(principals, script->principals) &&
-              subsume(script->principals, principals))))
-        {
-            // Get the prior (cache-filling) eval's saved caller function.
-            // See frontend::CompileScript.
-            JSFunction *fun = script->getCallerFunction();
-
-            if (fun == caller->fun()) {
-                /*
-                 * Get the source string passed for safekeeping in the atom map
-                 * by the prior eval to frontend::CompileScript.
-                 */
-                JSAtom *src = script->atoms[0];
+/* static */ bool
+EvalCacheHashPolicy::match(JSScript *script, const EvalCacheLookup &l)
+{
+    JS_ASSERT(IsEvalCacheCandidate(script));
 
-                if (src == str || EqualStrings(src, str)) {
-                    // Source matches. Make sure there are no inner objects
-                    // which might use the wrong parent and/or call scope by
-                    // reusing the previous eval's script. Skip the script's
-                    // first object, which entrains the eval's scope.
-                    JS_ASSERT(script->objects()->length >= 1);
-                    if (script->objects()->length == 1 &&
-                        !script->hasRegexps()) {
-                        JS_ASSERT(staticLevel == script->staticLevel);
-                        *scriptp = script->evalHashLink();
-                        script->evalHashLink() = NULL;
-                        return script;
-                    }
-                }
-            }
-        }
+    // Get the source string passed for safekeeping in the atom map
+    // by the prior eval to frontend::CompileScript.
+    JSAtom *keyStr = script->atoms[0];
 
-        static const unsigned EVAL_CACHE_CHAIN_LIMIT = 4;
-        if (++count == EVAL_CACHE_CHAIN_LIMIT)
-            return NULL;
-        scriptp = &script->evalHashLink();
-    }
-    return NULL;
+    return EqualStrings(keyStr, l.str) &&
+           script->getCallerFunction() == l.caller &&
+           script->staticLevel == l.staticLevel &&
+           script->getVersion() == l.version &&
+           script->compartment() == l.compartment;
 }
 
 // There are two things we want to do with each script executed in EvalKernel:
 //  1. notify jsdbgapi about script creation/destruction
 //  2. add the script to the eval cache when EvalKernel is finished
 //
 // NB: Although the eval cache keeps a script alive wrt to the JS engine, from
 // a jsdbgapi user's perspective, we want each eval() to create and destroy a
 // script. This hides implementation details and means we don't have to deal
-// with calls to JS_GetScriptObject for scripts in the eval cache (currently,
-// script->object aliases script->evalHashLink()).
+// with calls to JS_GetScriptObject for scripts in the eval cache.
 class EvalScriptGuard
 {
     JSContext *cx_;
-    JSLinearString *str_;
-    JSScript **bucket_;
     Rooted<JSScript*> script_;
 
+    /* These fields are only valid if lookup_.str is non-NULL. */
+    EvalCacheLookup lookup_;
+    EvalCache::AddPtr p_;
+
   public:
-    EvalScriptGuard(JSContext *cx, JSLinearString *str)
-      : cx_(cx),
-        str_(str),
-        script_(cx) {
-        bucket_ = cx->runtime->evalCache.bucket(str);
+    EvalScriptGuard(JSContext *cx)
+      : cx_(cx), script_(cx)
+    {
+        lookup_.str = NULL;
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
-            script_->evalHashLink() = *bucket_;
-            *bucket_ = script_;
+            if (lookup_.str && IsEvalCacheCandidate(script_))
+                cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, script_);
         }
     }
 
-    void lookupInEvalCache(StackFrame *caller, unsigned staticLevel,
-                           JSPrincipals *principals, JSObject &scopeobj) {
-        if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
-                                              principals, scopeobj, bucket_)) {
-            js_CallNewScriptHook(cx_, found, NULL);
-            script_ = found;
+    void lookupInEvalCache(JSLinearString *str, JSFunction *caller, unsigned staticLevel)
+    {
+        lookup_.str = str;
+        lookup_.caller = caller;
+        lookup_.staticLevel = staticLevel;
+        lookup_.version = cx_->findVersion();
+        lookup_.compartment = cx_->compartment;
+        p_ = cx_->runtime->evalCache.lookupForAdd(lookup_);
+        if (p_) {
+            script_ = *p_;
+            cx_->runtime->evalCache.remove(p_);
+            js_CallNewScriptHook(cx_, script_, NULL);
             script_->isCachedEval = false;
             script_->isActiveEval = true;
         }
     }
 
     void setNewScript(JSScript *script) {
         // JSScript::initFromEmitter has already called js_CallNewScriptHook.
         JS_ASSERT(!script_ && script);
@@ -242,21 +183,16 @@ EvalKernel(JSContext *cx, const CallArgs
         staticLevel = caller->script()->staticLevel + 1;
 
         // Direct calls to eval are supposed to see the caller's |this|. If we
         // haven't wrapped that yet, do so now, before we make a copy of it for
         // the eval code to use.
         if (!ComputeThis(cx, caller))
             return false;
         thisv = caller->thisValue();
-
-#ifdef DEBUG
-        jsbytecode *callerPC = caller->pcQuadratic(cx);
-        JS_ASSERT(callerPC && JSOp(*callerPC) == JSOP_EVAL);
-#endif
     } else {
         JS_ASSERT(args.callee().global() == *scopeobj);
         staticLevel = 0;
 
         // Use the global as 'this', modulo outerization.
         JSObject *thisobj = scopeobj->thisObject(cx);
         if (!thisobj)
             return false;
@@ -305,37 +241,36 @@ EvalKernel(JSContext *cx, const CallArgs
                 if (tmp.isU