Merge the last PGO-green changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 05 Sep 2012 22:27:23 -0400
changeset 104386 501f4e46a88c329994803b1d8d49174c69a37db2
parent 104378 3974efe8d5842a7a7d987d60de7923109e589589 (current diff)
parent 104362 72c85979e852baa371bb8a79920e55a1f33b7679 (diff)
child 104387 5d63594c05a9fa801fbbbc8adb38946d8fb77970
push id14486
push userryanvm@gmail.com
push dateThu, 06 Sep 2012 03:03:12 +0000
treeherdermozilla-inbound@ff19aab9d56c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone18.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 the last PGO-green changeset to m-c.
build/macosx/common
config/makefiles/test/check-xpidl.mk
config/makefiles/xpidl.mk
dom/camera/CameraCapabilities.h
dom/camera/CameraControl.cpp
dom/camera/CameraControl.h
dom/camera/CameraPreview.cpp
dom/camera/CameraPreview.h
dom/camera/GonkCameraCapabilities.cpp
dom/camera/GonkCameraPreview.cpp
dom/camera/GonkCameraPreview.h
dom/tests/mochitest/webapps/apphelper.js
dom/tests/mochitest/webapps/apps/bug_765063.xul
dom/tests/mochitest/webapps/apps/include.html
dom/tests/mochitest/webapps/apps/manifest_with_bom.webapp
dom/tests/mochitest/webapps/apps/manifest_with_bom.webapp^headers^
dom/tests/mochitest/webapps/apps/super_crazy.webapp
dom/tests/mochitest/webapps/apps/super_crazy.webapp^headers^
dom/tests/mochitest/webapps/apps/wild_crazy.webapp
dom/tests/mochitest/webapps/apps/wild_crazy.webapp^headers^
dom/tests/mochitest/webapps/jshelper.js
dom/tests/mochitest/webapps/test_cross_domain.xul
editor/idl/nsIEditorLogging.idl
editor/libeditor/html/nsHTMLEditorLog.cpp
editor/libeditor/html/nsHTMLEditorLog.h
js/src/config/makefiles/xpidl.mk
--- a/accessible/src/base/FocusManager.cpp
+++ b/accessible/src/base/FocusManager.cpp
@@ -55,17 +55,17 @@ FocusManager::IsFocused(const Accessible
     // accessible creation for temporary about:blank document. Without this
     // peculiarity we would end up with plain implementation based on
     // FocusedAccessible() method call. Make sure this issue is fixed in
     // bug 638465.
     if (focusedNode->OwnerDoc() == aAccessible->GetNode()->OwnerDoc()) {
       DocAccessible* doc = 
         GetAccService()->GetDocAccessible(focusedNode->OwnerDoc());
       return aAccessible ==
-	(doc ? doc->GetAccessibleOrContainer(focusedNode) : nullptr);
+        (doc ? doc->GetAccessibleOrContainer(focusedNode) : nullptr);
     }
   }
   return false;
 }
 
 bool
 FocusManager::IsFocusWithin(const Accessible* aContainer) const
 {
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -2841,17 +2841,31 @@ bool
 Accessible::IsWidget() const
 {
   return false;
 }
 
 bool
 Accessible::IsActiveWidget() const
 {
-  return FocusMgr()->IsFocused(this);
+  if (FocusMgr()->HasDOMFocus(mContent))
+    return true;
+
+  // If text entry of combobox widget has a focus then the combobox widget is
+  // active.
+  if (mRoleMapEntry && mRoleMapEntry->Is(nsGkAtoms::combobox)) {
+    PRUint32 childCount = ChildCount();
+    for (PRUint32 idx = 0; idx < childCount; idx++) {
+      Accessible* child = mChildren.ElementAt(idx);
+      if (child->Role() == roles::ENTRY)
+        return FocusMgr()->HasDOMFocus(child->GetContent());
+    }
+  }
+
+  return false;
 }
 
 bool
 Accessible::AreItemsOperable() const
 {
   return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant);
 }
 
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1216,21 +1216,21 @@ DocAccessible::ARIAAttributeChanged(nsIC
                                aContent);
     return;
   }
 }
 
 void
 DocAccessible::ARIAActiveDescendantChanged(nsIContent* aElm)
 {
-  if (FocusMgr()->HasDOMFocus(aElm)) {
+  Accessible* widget = GetAccessible(aElm);
+  if (widget && widget->IsActiveWidget()) {
     nsAutoString id;
     if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant, id)) {
-      nsIDocument* DOMDoc = aElm->OwnerDoc();
-      dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
+      dom::Element* activeDescendantElm = aElm->OwnerDoc()->GetElementById(id);
       if (activeDescendantElm) {
         Accessible* activeDescendant = GetAccessible(activeDescendantElm);
         if (activeDescendant) {
           FocusMgr()->ActiveItemChanged(activeDescendant, false);
           A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("ARIA activedescedant changed",
                                                  activeDescendant)
         }
       }
--- a/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html
+++ b/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html
@@ -65,16 +65,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     var gQueue = null;
     function doTest()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new synthFocus("container", new focusChecker("item1")));
       gQueue.push(new changeARIAActiveDescendant("container", "item2"));
+
+      gQueue.push(new synthFocus("combobox_entry", new focusChecker("combobox_entry")));
+      gQueue.push(new changeARIAActiveDescendant("combobox", "combobox_option2"));
+
       todo(false, "No focus for inserted element, bug 687011");
       //gQueue.push(new insertItemNFocus("container", "item3"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
@@ -82,19 +86,32 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=429547"
      title="Support aria-activedescendant usage in nsIAccesible::TakeFocus()">
     Mozilla Bug 429547
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=761102"
+     title="Focus may be missed when ARIA active-descendant is changed on active composite widget">
+    Mozilla Bug 761102
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div role="listbox" aria-activedescendant="item1" id="container" tabindex="1">
     <div role="listitem" id="item1">item1</div>
     <div role="listitem" id="item2">item2</div>
   </div>
+
+  <div role="combobox" id="combobox">
+    <input id="combobox_entry">
+    <ul>
+      <li role="option" id="combobox_option1">option1</li>
+      <li role="option" id="combobox_option2">option2</li>
+    </ul>
+  </div>
 </body>
 </html>
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -39,19 +39,19 @@ pref("network.protocol-handler.warn-exte
 pref("network.protocol-handler.warn-external.vnd.youtube", false);
 
 /* http prefs */
 pref("network.http.pipelining", true);
 pref("network.http.pipelining.ssl", true);
 pref("network.http.proxy.pipelining", true);
 pref("network.http.pipelining.maxrequests" , 6);
 pref("network.http.keep-alive.timeout", 600);
-pref("network.http.max-connections", 6);
-pref("network.http.max-persistent-connections-per-server", 4);
-pref("network.http.max-persistent-connections-per-proxy", 4);
+pref("network.http.max-connections", 20);
+pref("network.http.max-persistent-connections-per-server", 6);
+pref("network.http.max-persistent-connections-per-proxy", 20);
 
 // See bug 545869 for details on why these are set the way they are
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  16384);
 
 /* session history */
 pref("browser.sessionhistory.max_total_viewers", 1);
 pref("browser.sessionhistory.max_entries", 50);
@@ -502,17 +502,17 @@ pref("ui.showHideScrollbars", 1);
 
 // Enable the ProcessPriorityManager, and give processes with no visible
 // documents a 1s grace period before they're eligible to be marked as
 // background.
 pref("dom.ipc.processPriorityManager.enabled", true);
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
 pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
 pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
-pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 2);
+pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 6);
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
 
 #ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelauch.enabled", true);
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -113,23 +113,38 @@ let FormAssistant = {
     let json = msg.json;
     switch (msg.name) {
       case "Forms:Input:Value":
         target.value = json.value;
         break;
 
       case "Forms:Select:Choice":
         let options = target.options;
+        let valueChanged = false;
         if ("index" in json) {
-          options.item(json.index).selected = true;
+          if (options.selectedIndex != json.index) {
+            options.selectedIndex = json.index;
+            valueChanged = true;
+          }
         } else if ("indexes" in json) {
           for (let i = 0; i < options.length; i++) {
-            options.item(i).selected = (json.indexes.indexOf(i) != -1);
+            let newValue = (json.indexes.indexOf(i) != -1);
+            if (options.item(i).selected != newValue) {
+              options.item(i).selected = newValue;
+              valueChanged = true;
+            }
           }
         }
+
+        // only fire onchange event if any selected option is changed
+        if (valueChanged) {
+          let event = content.document.createEvent('HTMLEvents');
+          event.initEvent('change', true, true);
+          target.dispatchEvent(event);
+        }
         break;
     }
   },
 
   observe: function fa_observe(subject, topic, data) {
     switch (topic) {
       case "ime-enabled-state-changed":
         let isOpen = this.isKeyboardOpened;
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -504,16 +504,19 @@ var CustomEventManager = {
         break;
       case 'webapps-install-granted':
       case 'webapps-install-denied':
         WebappsHelper.handleEvent(detail);
         break;
       case 'select-choicechange':
         FormsHelper.handleEvent(detail);
         break;
+      case 'system-message-listener-ready':
+        Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
+        break;
     }
   }
 }
 
 var AlertsHelper = {
   _listeners: {},
   _count: 0,
 
new file mode 100644
--- /dev/null
+++ b/b2g/config/mozconfigs/common
@@ -0,0 +1,7 @@
+# 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/.
+
+# This file is included at the top of all b2g mozconfigs
+
+. "$topsrcdir/build/mozconfig.common"
new file mode 100644
--- /dev/null
+++ b/b2g/config/mozconfigs/common.override
@@ -0,0 +1,7 @@
+# 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/.
+
+# This file is included at the bottom of all b2g mozconfigs
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/b2g/config/mozconfigs/gb_armv7a_gecko/debug
+++ b/b2g/config/mozconfigs/gb_armv7a_gecko/debug
@@ -1,8 +1,10 @@
+. "$topsrcdir/b2g/config/mozconfigs/common"
+
 mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
 
 mk_add_options MOZ_MAKE_FLAGS="-j8"
 
 ac_add_options --enable-application=b2g
 
 ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
@@ -10,8 +12,10 @@ ac_add_options --with-gonk-toolchain-pre
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-debug
 ac_add_options --with-ccache
 ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/gb_armv7a_gecko/nightly
+++ b/b2g/config/mozconfigs/gb_armv7a_gecko/nightly
@@ -1,8 +1,10 @@
+. "$topsrcdir/b2g/config/mozconfigs/common"
+
 mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
 
 mk_add_options MOZ_MAKE_FLAGS="-j8"
 
 ac_add_options --enable-application=b2g
 
 ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
@@ -10,8 +12,10 @@ ac_add_options --with-gonk-toolchain-pre
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-profiling
 ac_add_options --with-ccache
 ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/ics_armv7a_gecko/debug
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/debug
@@ -13,8 +13,10 @@ ac_add_options --with-gonk-toolchain-pre
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-debug
 #ac_add_options --with-ccache
 ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
@@ -1,8 +1,10 @@
+. "$topsrcdir/b2g/config/mozconfigs/common"
+
 mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
 
 mk_add_options MOZ_MAKE_FLAGS="-j8"
 
 ac_add_options --enable-application=b2g
 ac_add_options --enable-b2g-camera
 
 ac_add_options --target=arm-android-eabi
@@ -13,8 +15,10 @@ ac_add_options --with-gonk-toolchain-pre
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-profiling
 #ac_add_options --with-ccache
 ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -1,8 +1,10 @@
+. "$topsrcdir/b2g/config/mozconfigs/common"
+
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-codesighs
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 #ac_add_options --enable-js-diagnostics
 
@@ -31,8 +33,10 @@ mk_add_options MOZ_MAKE_FLAGS="-j4"
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -33,8 +33,10 @@ mk_add_options MOZ_MAKE_FLAGS="-j4"
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/macosx64_gecko/nightly
+++ b/b2g/config/mozconfigs/macosx64_gecko/nightly
@@ -1,9 +1,9 @@
-. $topsrcdir/build/macosx/common
+. $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-codesighs
 ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
@@ -21,8 +21,10 @@ ac_add_options --enable-warnings-as-erro
 
 # B2G Stuff
 ac_add_options --enable-application=b2g
 ac_add_options --enable-debug-symbols
 ac_add_options --with-ccache
 ENABLE_MARIONETTE=1
 
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -1,8 +1,10 @@
+. "$topsrcdir/b2g/config/mozconfigs/common"
+
 # for pgo
 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
@@ -22,8 +24,10 @@ else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # B2G Options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
+
+. "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -121,42 +121,42 @@ endif #}
 endif #}
 endif #}
 
 ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH)))
 
 libs:: 
 	cp -p $(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 
-GARBAGE += $(addprefix $(DIST)/bin/defaults/pref/, firefox.js)
+GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, firefox.js)
 
 endif
 
 endif #} LIBXUL_SDK
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 libs::
-	$(INSTALL) $(IFLAGS1) $(DIST)/branding/mozicon128.png $(DIST)/bin/icons
-	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default16.png  $(DIST)/bin/chrome/icons/default
-	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default32.png  $(DIST)/bin/chrome/icons/default
-	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png  $(DIST)/bin/chrome/icons/default
+	$(INSTALL) $(IFLAGS1) $(DIST)/branding/mozicon128.png $(FINAL_TARGET)/icons
+	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default16.png  $(FINAL_TARGET)/chrome/icons/default
+	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default32.png  $(FINAL_TARGET)/chrome/icons/default
+	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png  $(FINAL_TARGET)/chrome/icons/default
 endif
 
 libs:: $(srcdir)/profile/prefs.js
-	$(INSTALL) $(IFLAGS1) $^ $(DIST)/bin/defaults/profile
+	$(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile
 
 ifndef LIBXUL_SDK
 # channel-prefs.js is handled separate from other prefs due to bug 756325
 libs:: $(srcdir)/profile/channel-prefs.js
-	$(NSINSTALL) -D $(DIST)/bin/defaults/pref
-	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(ACDEFINES) $^ > $(DIST)/bin/defaults/pref/channel-prefs.js
+	$(NSINSTALL) -D $(FINAL_TARGET)/defaults/pref
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(ACDEFINES) $^ > $(FINAL_TARGET)/defaults/pref/channel-prefs.js
 endif
 
 libs:: $(srcdir)/blocklist.xml
-	$(INSTALL) $(IFLAGS1) $^ $(DIST)/bin
+	$(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 
 MAC_APP_NAME = $(MOZ_APP_DISPLAYNAME)
 
 ifdef MOZ_DEBUG
 MAC_APP_NAME := $(MAC_APP_NAME)Debug
 endif
--- a/browser/app/profile/extensions/Makefile.in
+++ b/browser/app/profile/extensions/Makefile.in
@@ -3,17 +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/.
 
 DEPTH      = @DEPTH@
 topsrcdir  = @top_srcdir@
 srcdir     = @srcdir@
 VPATH      = @srcdir@
 
-DISTROEXT = $(call core_abspath,$(DIST))/bin/distribution/extensions
+DISTROEXT = $(call core_abspath,$(FINAL_TARGET))/distribution/extensions
 
 include $(DEPTH)/config/autoconf.mk
 
 DIRS = \
   {972ce4c6-7e08-4474-a285-3208198ce6fd} \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/Makefile.in
+++ b/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/Makefile.in
@@ -12,14 +12,11 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 FILES := \
 	install.rdf \
 	$(NULL)
 
 libs::
 	$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(srcdir)/install.rdf.in > install.rdf
-	$(INSTALL) $(FILES) $(DIST)/bin/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
+	$(INSTALL) $(FILES) $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
  
-install::
-	$(SYSINSTALL) $(IFLAGS1) $(FILES) $(DESTDIR)$(mozappdir)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
-
 GARBAGE += $(FILES)
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -141,24 +141,24 @@ XPCOMUtils.defineLazyGetter(this, "Socia
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
   "resource:///modules/PageThumbs.jsm");
 
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyGetter(this, "SafeBrowsing", function() {
   let tmp = {};
-  Cu.import("resource://gre/modules/SafeBrowsing.jsm", tmp);
+  Cu.import("resource:///modules/SafeBrowsing.jsm", tmp);
   return tmp.SafeBrowsing;
 });
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserNewTabPreloader", function () {
   let tmp = {};
-  Cu.import("resource://gre/modules/BrowserNewTabPreloader.jsm", tmp);
+  Cu.import("resource:///modules/BrowserNewTabPreloader.jsm", tmp);
   return new tmp.BrowserNewTabPreloader();
 });
 
 let gInitialPages = [
   "about:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -394,20 +394,16 @@
                     label="&identity.moreInfoLinkText;"
                     onblur="gIdentityHandler.hideIdentityPopup();"
                     oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
           </hbox>
         </vbox>
       </hbox>
     </panel>
 
-    <tooltip id="urlTooltip">
-      <label crop="center" flex="1" class="tooltip-label"/>
-    </tooltip>
-
     <panel id="ctrlTab-panel" class="KUI-panel" hidden="true" norestorefocus="true" level="top">
       <hbox>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -48,8 +48,18 @@ tabpanels {
 
 .closing-tabs-spacer {
   pointer-events: none;
 }
 
 .tabbrowser-tabs:not(:hover) > .tabbrowser-arrowscrollbox > .closing-tabs-spacer {
   transition: width .15s ease-out;
 }
+
+/**
+ * Optimization for tabs that are restored lazily. We can save a good amount of
+ * memory that to-be-restored tabs would otherwise consume simply by setting
+ * their browsers to 'display: none' as that will prevent them from having to
+ * create a presentation and the like.
+ */
+browser[pending] {
+  display: none;
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -53,18 +53,16 @@
         this._prefs.addObserver("", this, false);
         this.clickSelectsAll = this._prefs.getBoolPref("clickSelectsAll");
         this.doubleClickSelectsAll = this._prefs.getBoolPref("doubleClickSelectsAll");
         this.completeDefaultIndex = this._prefs.getBoolPref("autoFill");
         this.timeout = this._prefs.getIntPref("delay");
         this._formattingEnabled = this._prefs.getBoolPref("formatting.enabled");
         this._mayTrimURLs = this._prefs.getBoolPref("trimURLs");
 
-        this._urlTooltip = document.getElementById("urlTooltip");
-
         this.inputField.controllers.insertControllerAt(0, this._copyCutController);
         this.inputField.addEventListener("mousedown", this, false);
         this.inputField.addEventListener("mousemove", this, false);
         this.inputField.addEventListener("mouseout", this, false);
         this.inputField.addEventListener("overflow", this, false);
         this.inputField.addEventListener("underflow", this, false);
 
         const kXULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
@@ -405,36 +403,23 @@
       </method>
 
       <field name="_contentIsCropped">false</field>
 
       <method name="_initURLTooltip">
         <body><![CDATA[
           if (this.focused || !this._contentIsCropped)
             return;
-          if (this._tooltipTimer)
-            clearTimeout(this._tooltipTimer);
-          this._tooltipTimer = setTimeout(function (self) {
-            self._tooltipTimer = 0;
-            var label = self._urlTooltip.firstChild;
-            label.value = self.value;
-            var bO = self.boxObject;
-            self._urlTooltip.maxWidth = bO.width;
-            self._urlTooltip.showPopup(self, bO.screenX, bO.screenY + bO.height, "tooltip");
-          }, 700, this);
+          this.inputField.setAttribute("tooltiptext", this.value);
         ]]></body>
       </method>
 
       <method name="_hideURLTooltip">
         <body><![CDATA[
-          if (this._tooltipTimer) {
-            clearTimeout(this._tooltipTimer);
-            this._tooltipTimer = 0;
-          }
-          this._urlTooltip.hidePopup();
+          this.inputField.removeAttribute("tooltiptext");
         ]]></body>
       </method>
 
       <method name="onDragOver">
         <parameter name="aEvent"/>
         <body>
           var types = aEvent.dataTransfer.types;
           if (types.contains("application/x-moz-file") ||
--- a/browser/components/safebrowsing/Makefile.in
+++ b/browser/components/safebrowsing/Makefile.in
@@ -1,14 +1,14 @@
 # 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/.
 
 
-DEPTH     = ../../..
+DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 TEST_DIRS += content/test
 
--- a/browser/components/safebrowsing/content/test/Makefile.in
+++ b/browser/components/safebrowsing/content/test/Makefile.in
@@ -1,18 +1,18 @@
 #
 # 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/.
 
-DEPTH		= ../../../../..
+DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
-relativesrcdir  = browser/components/safebrowsing/content/test
+relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 # The browser chrome test for bug 415846 doesn't run on Mac because of its
 # bizarre special-and-unique snowflake of a help menu.
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _NON_MAC_BROWSER_TESTS = browser_bug415846.js
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2982,16 +2982,17 @@ let SessionStoreInternal = {
         this.xulAttributes[name] = true;
 
       browser.__SS_tabStillLoading = true;
 
       // keep the data around to prevent dataloss in case
       // a tab gets closed before it's been properly restored
       browser.__SS_data = tabData;
       browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
+      browser.setAttribute("pending", "true");
       tab.setAttribute("pending", "true");
 
       // Make sure that set/getTabValue will set/read the correct data by
       // wiping out any current value in tab.__SS_extdata.
       delete tab.__SS_extdata;
 
       if (!tabData.entries || tabData.entries.length == 0) {
         // make sure to blank out this tab's content
@@ -3166,16 +3167,17 @@ let SessionStoreInternal = {
     // Make sure that this tab is removed from _tabsToRestore
     this._removeTabFromTabsToRestore(aTab);
 
     // Increase our internal count.
     this._tabsRestoringCount++;
 
     // Set this tab's state to restoring
     browser.__SS_restoreState = TAB_STATE_RESTORING;
+    browser.removeAttribute("pending");
     aTab.removeAttribute("pending");
 
     // Remove the history listener, since we no longer need it once we start restoring
     this._removeSHistoryListener(aTab);
 
     let activeIndex = (tabData.index || tabData.entries.length) - 1;
     if (activeIndex >= tabData.entries.length)
       activeIndex = tabData.entries.length - 1;
@@ -4330,16 +4332,19 @@ let SessionStoreInternal = {
     let browser = aTab.linkedBrowser;
 
     // Keep the tab's previous state for later in this method
     let previousState = browser.__SS_restoreState;
 
     // The browser is no longer in any sort of restoring state.
     delete browser.__SS_restoreState;
 
+    aTab.removeAttribute("pending");
+    browser.removeAttribute("pending");
+
     // We want to decrement window.__SS_tabsToRestore here so that we always
     // decrement it AFTER a tab is done restoring or when a tab gets "reset".
     window.__SS_tabsToRestore--;
 
     // Remove the progress listener if we should.
     this._removeTabsProgressListener(window);
 
     if (previousState == TAB_STATE_RESTORING) {
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/common
@@ -0,0 +1,7 @@
+# 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/.
+
+# This file is included by all browser mozconfigs
+
+. "$topsrcdir/build/mozconfig.common"
--- a/browser/config/mozconfigs/linux32/debug
+++ b/browser/config/mozconfigs/linux32/debug
@@ -17,8 +17,10 @@ mk_add_options MOZ_MAKE_FLAGS="-j4"
 #Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/debug-asan
+++ b/browser/config/mozconfigs/linux32/debug-asan
@@ -11,8 +11,10 @@ ac_add_options --enable-valgrind
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig
@@ -1,7 +1,9 @@
 ac_add_options --with-l10n-base=../../l10n-central
 ac_add_options --enable-official-branding
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
 . $topsrcdir/build/unix/mozconfig.linux
 
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/nightly
+++ b/browser/config/mozconfigs/linux32/nightly
@@ -31,8 +31,10 @@ ac_add_options --enable-warnings-as-erro
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/nightly-asan
+++ b/browser/config/mozconfigs/linux32/nightly-asan
@@ -13,8 +13,10 @@ ac_add_options --enable-codesighs
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/qt
+++ b/browser/config/mozconfigs/linux32/qt
@@ -21,8 +21,10 @@ ac_add_options --with-ccache=/usr/bin/cc
 # QT Options
 export PKG_CONFIG_PATH=/tools/qt-4.6.3/qt/lib/pkgconfig
 ac_add_options --with-qtdir=/tools/qt-4.6.3/qt
 ac_add_options --enable-default-toolkit=cairo-qt
 ac_add_options --disable-crashreporter
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/release
+++ b/browser/config/mozconfigs/linux32/release
@@ -19,8 +19,10 @@ export MOZ_TELEMETRY_REPORTING=1
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/rpm
+++ b/browser/config/mozconfigs/linux32/rpm
@@ -24,8 +24,10 @@ mk_add_options PROFILE_GEN_SCRIPT='$(PYT
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 #Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/debug
+++ b/browser/config/mozconfigs/linux64/debug
@@ -17,8 +17,10 @@ mk_add_options MOZ_MAKE_FLAGS="-j4"
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/debug-asan
+++ b/browser/config/mozconfigs/linux64/debug-asan
@@ -11,8 +11,10 @@ ac_add_options --enable-valgrind
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig
@@ -1,7 +1,9 @@
 ac_add_options --with-l10n-base=../../l10n-central
 ac_add_options --enable-official-branding
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
 . $topsrcdir/build/unix/mozconfig.linux
 
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/nightly
+++ b/browser/config/mozconfigs/linux64/nightly
@@ -31,8 +31,10 @@ ac_add_options --enable-warnings-as-erro
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/nightly-asan
+++ b/browser/config/mozconfigs/linux64/nightly-asan
@@ -13,8 +13,10 @@ ac_add_options --enable-codesighs
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/release
+++ b/browser/config/mozconfigs/linux64/release
@@ -19,8 +19,10 @@ export MOZ_TELEMETRY_REPORTING=1
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/rpm
+++ b/browser/config/mozconfigs/linux64/rpm
@@ -24,8 +24,10 @@ mk_add_options PROFILE_GEN_SCRIPT='$(PYT
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 #Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx-universal/nightly
+++ b/browser/config/mozconfigs/macosx-universal/nightly
@@ -21,8 +21,10 @@ mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx-universal/release
+++ b/browser/config/mozconfigs/macosx-universal/release
@@ -15,8 +15,10 @@ export MOZ_TELEMETRY_REPORTING=1
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx-universal/shark
+++ b/browser/config/mozconfigs/macosx-universal/shark
@@ -19,8 +19,10 @@ ac_add_options --enable-shark
 ac_add_options --enable-dtrace
 
 # Need this to prevent name conflicts with the normal nightly build packages
 export MOZ_PKG_SPECIAL="shark"
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 ac_add_options --with-ccache
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx32/debug
+++ b/browser/config/mozconfigs/macosx32/debug
@@ -1,16 +1,19 @@
 . $topsrcdir/build/macosx/mozconfig.leopard
+
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 ENABLE_MARIONETTE=1
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64/debug
@@ -1,9 +1,9 @@
-. $topsrcdir/build/macosx/common
+. $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-accessibility
 ac_add_options --enable-signmar
 ENABLE_MARIONETTE=1
 
 # Enable parallel compiling
@@ -14,8 +14,10 @@ export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx64/debug-asan
+++ b/browser/config/mozconfigs/macosx64/debug-asan
@@ -7,8 +7,10 @@ ac_add_options --enable-accessibility
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx64/l10n-mozconfig
+++ b/browser/config/mozconfigs/macosx64/l10n-mozconfig
@@ -1,5 +1,9 @@
+. "$topsrcdir/browser/config/mozconfigs/common"
+
 ac_add_options --with-l10n-base=../../l10n-central
 ac_add_options --enable-official-branding
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --with-ccache
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -1,8 +1,10 @@
+. "$topsrcdir/browser/config/mozconfigs/common"
+
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 ENABLE_MARIONETTE=1
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
@@ -15,8 +17,10 @@ fi
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win32/l10n-mozconfig
+++ b/browser/config/mozconfigs/win32/l10n-mozconfig
@@ -1,10 +1,14 @@
+. "$topsrcdir/browser/config/mozconfigs/common"
+
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-official-branding
 ac_add_options --with-l10n-base=../../l10n-central
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win32/nightly
+++ b/browser/config/mozconfigs/win32/nightly
@@ -1,8 +1,10 @@
+. "$topsrcdir/browser/config/mozconfigs/common"
+
 # for pgo
 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 ac_add_options --enable-profiling
@@ -24,8 +26,10 @@ fi
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -1,8 +1,10 @@
+. "$topsrcdir/browser/config/mozconfigs/common"
+
 # for pgo
 mk_add_options MOZ_PGO=1
 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-official-branding
@@ -21,8 +23,10 @@ fi
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -10,8 +10,10 @@ ENABLE_MARIONETTE=1
 export MOZILLA_OFFICIAL=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs2010
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win64/nightly
+++ b/browser/config/mozconfigs/win64/nightly
@@ -19,8 +19,10 @@ export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs2010
+
+. "$topsrcdir/build/mozconfig.common.override"
--- a/browser/devtools/commandline/CmdCmd.jsm
+++ b/browser/devtools/commandline/CmdCmd.jsm
@@ -13,17 +13,17 @@ let prefSvc = "@mozilla.org/preferences-
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
   let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
   return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "console",
-                                  "resource:///modules/devtools/Console.jsm");
+                                  "resource://gre/modules/devtools/Console.jsm");
 
 const PREF_DIR = "devtools.commands.dir";
 
 /**
  * A place to store the names of the commands that we have added as a result of
  * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
  * added commands.
  */
--- a/browser/devtools/commandline/CmdCookie.jsm
+++ b/browser/devtools/commandline/CmdCookie.jsm
@@ -5,17 +5,17 @@
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 let EXPORTED_SYMBOLS = [ ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
-                                  "resource:///modules/devtools/Console.jsm");
+                                  "resource://gre/modules/devtools/Console.jsm");
 
 // We should really be using nsICookieManager so we can read more than just the
 // key/value of cookies. The difficulty is filtering the cookies that are
 // relevant to the current page. See
 // https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
 // For details on how this is done with Firebug
 
 /**
--- a/browser/extensions/Makefile.in
+++ b/browser/extensions/Makefile.in
@@ -2,34 +2,34 @@
 # 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/.
 
 DEPTH      = @DEPTH@
 topsrcdir  = @top_srcdir@
 srcdir     = @srcdir@
 VPATH      = @srcdir@
 
-CHROMEDIR = $(call core_abspath,$(DIST))/bin/chrome
+CHROMEDIR = $(call core_abspath,$(FINAL_TARGET))/chrome
 
 include $(DEPTH)/config/autoconf.mk
 
 TEST_DIRS += pdfjs/test
 
 include $(topsrcdir)/config/rules.mk
 
 exclude_files = \
   test \
   install.rdf \
   bootstrap.js \
   icon.png \
   icon64.png \
   $(NULL)
 
-$(DIST)/bin/chrome/pdfjs.manifest: $(GLOBAL_DEPS)
+$(FINAL_TARGET)/chrome/pdfjs.manifest: $(GLOBAL_DEPS)
 	printf "manifest pdfjs/chrome.manifest" > $@
 
-libs:: $(DIST)/bin/chrome/pdfjs.manifest
+libs:: $(FINAL_TARGET)/chrome/pdfjs.manifest
 	$(PYTHON) $(topsrcdir)/config/nsinstall.py \
 	  $(srcdir)/pdfjs \
           $(foreach exclude,$(exclude_files), -X $(srcdir)/pdfjs/$(exclude)) \
-          $(DIST)/bin/chrome
+          $(FINAL_TARGET)/chrome
 	$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py \
-	  $(DIST)/bin/chrome.manifest "manifest chrome/pdfjs.manifest"
+	  $(FINAL_TARGET)/chrome.manifest "manifest chrome/pdfjs.manifest"
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -193,27 +193,29 @@ langpack: langpack-$(AB_CD)
 # This is a generic target that will make a langpack, repack ZIP (+tarball)
 # builds, and repack an installer if applicable. It is called from the
 # tinderbox scripts. Alter it with caution.
 
 installers-%: clobber-% langpack-% repackage-win32-installer-% repackage-zip-%
 	@echo "repackaging done"
 
 ifdef MOZ_UPDATER
+# Note that we want updater.ini to be in the top directory, not the browser/
+# subdirectory, because that's where the updater is installed and runs.
 libs:: $(call MERGE_FILE,updater/updater.ini)
 ifeq ($(OS_ARCH),WINNT)
 	cat $< $(srcdir)/../installer/windows/nsis/updater_append.ini | \
 	  sed -e "s/^InfoText=/Info=/" -e "s/^TitleText=/Title=/" | \
 	  sed -e "s/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/" > \
-	  $(FINAL_TARGET)/updater.ini
+	  $(DIST)/bin/updater.ini
 else
 	cat $< | \
 	  sed -e "s/^InfoText=/Info=/" -e "s/^TitleText=/Title=/" | \
 	  sed -e "s/%MOZ_APP_DISPLAYNAME%/$(MOZ_APP_DISPLAYNAME)/" > \
-	  $(FINAL_TARGET)/updater.ini
+	  $(DIST)/bin/updater.ini
 endif
 endif
 
 ifdef MOZ_CRASHREPORTER
 libs:: crashreporter-override.ini
 	$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)
 endif
 
deleted file mode 100644
--- a/build/macosx/common
+++ /dev/null
@@ -1,12 +0,0 @@
-if [ -d "$topsrcdir/clang" ]; then
-    # mozilla-central based build
-    export CC=$topsrcdir/clang/bin/clang
-    export CXX=$topsrcdir/clang/bin/clang++
-elif [ -d "$topsrcdir/../clang" ]; then
-    # comm-central based build
-    export CC=$topsrcdir/../clang/bin/clang
-    export CXX=$topsrcdir/../clang/bin/clang++
-fi
-
-ac_add_options --enable-stdcxx-compat
-ac_add_options --with-ccache
new file mode 100644
--- /dev/null
+++ b/build/macosx/mozconfig.common
@@ -0,0 +1,18 @@
+# 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/.
+
+. "$topsrcdir/build/mozconfig.common"
+
+if [ -d "$topsrcdir/clang" ]; then
+    # mozilla-central based build
+    export CC=$topsrcdir/clang/bin/clang
+    export CXX=$topsrcdir/clang/bin/clang++
+elif [ -d "$topsrcdir/../clang" ]; then
+    # comm-central based build
+    export CC=$topsrcdir/../clang/bin/clang
+    export CXX=$topsrcdir/../clang/bin/clang++
+fi
+
+ac_add_options --enable-stdcxx-compat
+ac_add_options --with-ccache
--- a/build/macosx/mozconfig.leopard
+++ b/build/macosx/mozconfig.leopard
@@ -1,11 +1,11 @@
-. $topsrcdir/build/macosx/common
+. $topsrcdir/build/macosx/mozconfig.common
 
-# Mac builds don't nomally have to be handled as cross
+# Mac builds don't normally have to be handled as cross
 # compilation, but some of the libraries on the bots
 # (IDL for example) are built only for one arch.
 
 HOST_CC=$CC
 HOST_CXX=$CXX
 
 # These must be set for cross builds, and don't hurt straight builds.
 RANLIB=ranlib
--- a/build/macosx/universal/mozconfig.common
+++ b/build/macosx/universal/mozconfig.common
@@ -7,17 +7,17 @@ mk_add_options MOZ_UNIFY_BDATE=1
 mk_add_options MOZ_POSTFLIGHT_ALL+=build/macosx/universal/flight.mk
 
 # Note, the version (10) is used by libffi's configure.
 ac_add_app_options i386 --target=i386-apple-darwin10
 ac_add_app_options x86_64 --target=x86_64-apple-darwin10
 
 ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.6.sdk
 
-. $topsrcdir/build/macosx/common
+. $topsrcdir/build/macosx/mozconfig.common
 
 # $MOZ_BUILD_APP is only defined when sourced by configure.  That's not a
 # problem, because the variables it affects only need to be set for
 # configure.
 if test -n "$MOZ_BUILD_APP" ; then
 if test "$MOZ_BUILD_APP" = "i386" -o "$MOZ_BUILD_APP" = "x86_64"; then
   TARGET_CPU=$MOZ_BUILD_APP
 
new file mode 100644
--- /dev/null
+++ b/build/mozconfig.common
@@ -0,0 +1,11 @@
+# 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/.
+
+# Common mozconfig for all users
+#
+# Add options to this file that will be inherited by all in-tree mozconfigs.
+# This is useful for eg try builds with nondefault options that apply to all
+# architectures, though note that if you want to override options set in
+# another mozconfig file, you'll need to use mozconfig.common.override instead
+# of this file.
new file mode 100644
--- /dev/null
+++ b/build/mozconfig.common.override
@@ -0,0 +1,11 @@
+# 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/.
+
+# Common mozconfig for all users
+#
+# Add options to this file that will be inherited by all in-tree mozconfigs.
+# This file is included at the *end* of the mozconfigs, and so may be used
+# to override anything done previously.
+#
+# The common expected usage is for try builds with nondefault options.
--- a/build/pymake/pymake/functions.py
+++ b/build/pymake/pymake/functions.py
@@ -766,19 +766,18 @@ class ShellFunction(Function):
     __slots__ = Function.__slots__
 
     def resolve(self, makefile, variables, fd, setting):
         #TODO: call this once up-front somewhere and save the result?
         shell, msys = util.checkmsyscompat()
         cline = self._arguments[0].resolvestr(makefile, variables, setting)
 
         log.debug("%s: running shell command '%s'" % (self.loc, cline))
-        if msys:
-            cline = [shell, "-c", cline]
-        p = subprocess.Popen(cline, env=makefile.env, shell=not msys,
+        cline = [shell, "-c", cline]
+        p = subprocess.Popen(cline, env=makefile.env, shell=False,
                              stdout=subprocess.PIPE, cwd=makefile.workdir)
         stdout, stderr = p.communicate()
 
         stdout = stdout.replace('\r\n', '\n')
         if stdout.endswith('\n'):
             stdout = stdout[:-1]
         stdout = stdout.replace('\n', ' ')
 
--- a/build/pymake/pymake/process.py
+++ b/build/pymake/pymake/process.py
@@ -83,18 +83,18 @@ def call(cline, env, cwd, loc, cb, conte
         else:
             argv = doglobbing(argv, cwd)
 
     if shellreason is not None:
         _log.debug("%s: using shell: %s: '%s'", loc, shellreason, cline)
         if msys:
             if len(cline) > 3 and cline[1] == ':' and cline[2] == '/':
                 cline = '/' + cline[0] + cline[2:]
-            cline = [shell, "-c", cline]
-        context.call(cline, shell=not msys, env=env, cwd=cwd, cb=cb, echo=echo,
+        cline = [shell, "-c", cline]
+        context.call(cline, shell=False, env=env, cwd=cwd, cb=cb, echo=echo,
                      justprint=justprint)
         return
 
     if not len(argv):
         cb(res=0)
         return
 
     if argv[0] == command.makepypath:
--- a/build/unix/mozconfig.linux
+++ b/build/unix/mozconfig.linux
@@ -1,2 +1,4 @@
+. "$topsrcdir/build/mozconfig.common"
+
 CC=/tools/gcc-4.5-0moz3/bin/gcc
 CXX=/tools/gcc-4.5-0moz3/bin/g++
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -15,25 +15,23 @@ include $(DEPTH)/config/autoconf.mk
 # headers, so that we can use it to set up the wrapped system headers.
 VISIBILITY_FLAGS =
 
 # STDCXX_COMPAT is not needed here, and will actually fail because
 # libstdc++-compat is not built yet.
 STDCXX_COMPAT =
 
 ifneq (WINNT,$(HOST_OS_ARCH))
-HOST_PROGRAM	= nsinstall$(HOST_BIN_SUFFIX)
+HOST_PROGRAM	= nsinstall_real$(HOST_BIN_SUFFIX)
 HOST_CSRCS	= nsinstall.c pathsub.c
 endif
 
-TARGETS		= $(HOST_PROGRAM) $(SIMPLE_PROGRAMS)
-
 ifndef CROSS_COMPILE
 ifdef USE_ELF_DYNSTR_GC
-TARGETS		+= elf-dynstr-gc
+export:: elf-dynstr-gc
 # Compiling the above will create dependency files.
 NEED_MDDEPDIR	= 1
 endif
 endif
 
 # IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have
 # a recursive rule for finding nsinstall and the Perl scripts.
 ifdef NSBUILDROOT
@@ -44,35 +42,46 @@ ifdef GNU_CC
 MODULE_OPTIMIZE_FLAGS = -O3
 endif
 
 include $(topsrcdir)/config/config.mk
 
 # Do not install util programs
 NO_INSTALL=1
 
+ifneq (WINNT,$(HOST_OS_ARCH))
+# Ensure nsinstall is atomically created
+nsinstall$(HOST_BIN_SUFFIX): $(HOST_PROGRAM)
+	cp $^ $@.tmp
+	mv $@.tmp $@
+
+NSINSTALL_FILES := nsinstall$(HOST_BIN_SUFFIX)
+NSINSTALL_DEST := $(DIST)/bin
+NSINSTALL_TARGET := export
+INSTALL_TARGETS += NSINSTALL
+endif
+
+HEADERS_FILES = \
+	$(DEPTH)/mozilla-config.h \
+	$(srcdir)/nsStaticComponents.h \
+	$(NULL)
+HEADERS_DEST := $(DIST)/include
+HEADERS_TARGET := export
+INSTALL_TARGETS += HEADERS
+
 include $(topsrcdir)/config/rules.mk
 
 HOST_CFLAGS += -DUNICODE -D_UNICODE
 
 ifeq ($(OS_CONFIG),SunOS4.1)
 NSPR_CFLAGS	+= -I$(srcdir)/../nsprpub/pr/include/md
 endif
 
-HEADERS = \
-	$(DEPTH)/mozilla-config.h \
-	$(srcdir)/nsStaticComponents.h \
-	$(NULL)
-
-export:: $(TARGETS) $(HEADERS)
-	$(INSTALL) $(IFLAGS1) $(HEADERS) $(DIST)/include
+export::
 	-$(RM) $(FINAL_LINK_COMPS) $(FINAL_LINK_LIBS) $(FINAL_LINK_COMP_NAMES)
-ifdef HOST_PROGRAM
-	$(INSTALL) $(HOST_PROGRAM) $(DIST)/bin
-endif
 
 # Generate a new buildid every time we "export" in config... that's only
 # supposed to be once per-build!
 export::
 ifdef MOZ_BUILD_DATE
 	printf "%s" $(MOZ_BUILD_DATE) > buildid
 else
 	$(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid > buildid
--- a/config/makefiles/target_export.mk
+++ b/config/makefiles/target_export.mk
@@ -22,17 +22,17 @@ export_tier_%:
 #################
 ifdef PARALLEL_DIRS
 export:: $(PARALLEL_DIRS_export)
 
 $(PARALLEL_DIRS_export): %_export: %/Makefile
 	+@$(call SUBMAKE,export,$*)
 endif
 
-export:: $(SUBMAKEFILES) $(MAKE_DIRS) $(if $(XPIDLSRCS),$(IDL_DIR))
+export:: $(SUBMAKEFILES) $(MAKE_DIRS)
 	$(LOOP_OVER_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
 
 
 #
 # Rule to create list of libraries for final link
 #
 # todo: use pre-req deps rather than conditionals
--- a/config/makefiles/test/Makefile.in
+++ b/config/makefiles/test/Makefile.in
@@ -15,34 +15,31 @@ USE_AUTOTARGETS_MK  = 1
 MAKEUTILS_UNIT_TEST = 1
 include $(topsrcdir)/config/makefiles/makeutils.mk
 
 dir-ts = .deps/test
 check-arglist        = $(dir-ts)/arglist.ts
 check-autotargets    = $(dir-ts)/autotargets_mk.ts
 check-export-targets = $(dir-ts)/export-targets-mk.ts
 check-XinY           = $(dir-ts)/check_XinY_mk.ts
-check-xpidl          = $(dir-ts)/xpidl-mk.ts
 check-tests =\
   $(check-arglist) \
   $(check-autotargets) \
   $(check-export-targets) \
   $(check-XinY) \
-  $(check-xpidl) \
   $(NULL)
 
 
 ##------------------_##
 ##---]  TARGETS  [---##
 ##------------------_##
 all::
 
 clean:
 	$(RM) $(check-tests)
-	@$(MAKE) --no-print-directory -f $(srcdir)/check-xpidl.mk clean-xpidl topsrcdir=$(topsrcdir)
 
 ###########################################################################
 ## Logic processed at compile time so be selective about when to test
 ## $(MAKE) check VERBOSE=1
 ifneq ($(NULL),$(findstring check,$(MAKECMDGOALS))) #
 
 check-preqs =\
   $(call mkdir_deps,$(dir-ts)) \
@@ -119,28 +116,9 @@ check-export-targets-preqs=\
 
 # include then test
 checkup: $(eval include $(srcdir)/check-export-targets.mk)
 
 $(check-export-targets): $(check-export-targets-preqs)
 	@$(TOUCH) $@
 # </CHECK: export-targets.mk>
 
-###########################################################################
-##{ <CHECK: xpidl.mk>
-check-xpidl-preqs=\
-  $(call mkdir_deps,$(dir-ts)) \
-  $(topsrcdir)/config/config.mk \
-  $(topsrcdir)/config/makefiles/makeutils.mk \
-  $(topsrcdir)/config/makefiles/xpidl.mk \
-  $(srcdir)/check-xpidl.mk \
-  $(NULL)
-
-check-xpidl-args =\
-  "topsrcdir=$(topsrcdir)" \
-  "srcdir=$(srcdir)" \
-  $(NULL)
-$(check-xpidl): $(check-xpidl-preqs)
-	$(MAKE) -f $(srcdir)/check-xpidl.mk check-xpidl $(check-xpidl-args)
-	@$(TOUCH) $@
-#} </check-xpidl.mk>
-
 endif #} findstring MAKECMDGOAL
deleted file mode 100644
--- a/config/makefiles/test/check-xpidl.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- makefile -*-
-#
-# 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/.
-
-ifdef VERBOSE
-  $(warning loading test)
-endif
-
-# Limit scope, we only need install_cmd= for testing
-INCLUDED_AUTOCONF_MK = 1
-include $(topsrcdir)/config/config.mk
-
-USE_AUTOTARGETS_MK = 1
-include $(topsrcdir)/config/makefiles/makeutils.mk
-
-basedir  = blah
-DIST     = $(basedir)/dist
-DI       = $(DIST)/include
-IDL_DIR  = $(basedir)/idl
-INSTALL := cp
-
-XPIDLSRCS = $(srcdir)/check-xpidl.mk
-
-include $(topsrcdir)/config/makefiles/xpidl.mk
-
-
-$(call requiredfunction,topsrcdir)
-$(call requiredfunction,XPIDL_GEN_DIR)
-
-HIDE=@
-check-xpidl: xpidl-install-src xpidl-install-headers
-	$(HIDE)test -d $(DIST)                   || exit 90
-	$(HIDE)test -f $(DI)/check-xpidl.mk      || exit 91
-	$(HIDE)test -f $(IDL_DIR)/check-xpidl.mk || exit 92
-
-# Declare targets to avoid including rules.mk
-$(DI) $(IDL_DIR):
-	mkdir -p $@
-
-clean-xpidl:
-	$(RM) -r $(basedir)
deleted file mode 100644
--- a/config/makefiles/xpidl.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- makefile -*-
-# vim:set ts=8 sw=8 sts=8 noet:
-#
-# 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/.
-#
-
-# Always declared, general use by:
-# js/xpconnect/tests/idl/Makefile.in:libs
-# toolkit/crashreporter/test/Makefile.in
-XPIDL_GEN_DIR ?= _xpidlgen
-GARBAGE_DIRS  += $(XPIDL_GEN_DIR)
-
-
-###########################################################################
-## Conditional logic
-###########################################################################
-ifndef INCLUDED_XPIDL_MK #{
-  INCLUDED_XPIDL_MK = 1
-
-  ifneq (,$(XPIDLSRCS)) #{
-
-    ifndef NO_DIST_INSTALL #{
-      _xpidl-todo_ += xpidl-install-src
-      _xpidl-todo_ += xpidl-install-headers
-    endif #}
-
-  endif #} XPIDLSRCS
-
-  export:: $(_xpidl-todo_)
-
-  $(call requiredfunction,mkdir_deps)
-endif #} INCLUDED_XPIDL_MK
-
-
-###########################################################################
-## processing targets
-###########################################################################
-ifdef _xpidl-todo_ #{
-
-$(call requiredfunction,install_cmd)
-
-## Logic batch #1
-xpidl-install-src-preqs=\
-  $(XPIDLSRCS) \
-  $(call mkdir_deps,$(IDL_DIR)) \
-  $(NULL)
-
-xpidl-install-src: $(xpidl-install-src-preqs)
-	$(call install_cmd,$(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val))))
-
-xpidl-install-headers-preqs =\
-  $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) \
-  $(call mkdir_deps,$(DIST)/include) \
-  $(NULL)
-xpidl-install-headers: $(xpidl-install-headers-preqs)
-	$(call install_cmd,$(IFLAGS1) $(foreach val,$^,$(call mkdir_stem,$(val))))
-
-endif #} _xpidl-todo_
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -21,20 +21,22 @@ endif
 ifndef INCLUDED_VERSION_MK
 include $(topsrcdir)/config/version.mk
 endif
 
 USE_AUTOTARGETS_MK = 1
 include $(topsrcdir)/config/makefiles/makeutils.mk
 
 ifdef SDK_XPIDLSRCS
-XPIDLSRCS += $(SDK_XPIDLSRCS)
+_EXTRA_XPIDLSRCS := $(filter-out $(XPIDLSRCS),$(SDK_XPIDLSRCS))
+XPIDLSRCS += $(_EXTRA_XPIDLSRCS)
 endif
 ifdef SDK_HEADERS
-EXPORTS += $(SDK_HEADERS)
+_EXTRA_EXPORTS := $(filter-out $(EXPORTS),$(SDK_HEADERS))
+EXPORTS += $(_EXTRA_EXPORTS)
 endif
 
 REPORT_BUILD = $(info $(notdir $<))
 
 ifeq ($(OS_ARCH),OS2)
 EXEC			=
 else
 EXEC			= exec
@@ -1154,25 +1156,29 @@ ifneq ($(XPI_NAME),)
 $(FINAL_TARGET):
 	$(NSINSTALL) -D $@
 
 export:: $(FINAL_TARGET)
 endif
 
 ifndef NO_DIST_INSTALL
 ifneq (,$(EXPORTS))
-export:: $(EXPORTS)
-	$(call install_cmd,$(IFLAGS1) $^ $(DIST)/include)
+EXPORTS_FILES := $(EXPORTS)
+EXPORTS_DEST := $(DIST)/include
+EXPORTS_TARGET := export
+INSTALL_TARGETS += EXPORTS
 endif
 endif # NO_DIST_INSTALL
 
 define EXPORT_NAMESPACE_RULE
 ifndef NO_DIST_INSTALL
-export:: $(EXPORTS_$(namespace))
-	$(call install_cmd,$(IFLAGS1) $$^ $(DIST)/include/$(namespace))
+EXPORTS_$(namespace)_FILES := $$(EXPORTS_$(namespace))
+EXPORTS_$(namespace)_DEST := $$(DIST)/include/$(namespace)
+EXPORTS_$(namespace)_TARGET := export
+INSTALL_TARGETS += EXPORTS_$(namespace)
 endif # NO_DIST_INSTALL
 endef
 
 $(foreach namespace,$(EXPORTS_NAMESPACES),$(eval $(EXPORT_NAMESPACE_RULE)))
 
 ################################################################################
 # Copy each element of PREF_JS_EXPORTS
 
@@ -1198,24 +1204,22 @@ PREF_JS_EXPORTS_FLAGS := $(PREF_PPFLAGS)
 PP_TARGETS += PREF_JS_EXPORTS
 endif
 endif
 
 ################################################################################
 # Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig
 
 ifneq ($(AUTOCFG_JS_EXPORTS),)
-$(FINAL_TARGET)/defaults/autoconfig::
-	$(NSINSTALL) -D $@
-
 ifndef NO_DIST_INSTALL
-export:: $(AUTOCFG_JS_EXPORTS) $(FINAL_TARGET)/defaults/autoconfig
-	$(call install_cmd,$(IFLAGS1) $^)
+AUTOCFG_JS_EXPORTS_FILES := $(AUTOCFG_JS_EXPORTS)
+AUTOCFG_JS_EXPORTS_DEST := $(FINAL_TARGET)/defaults/autoconfig
+AUTOCFG_JS_EXPORTS_TARGET := export
+INSTALL_TARGETS += AUTOCFG_JS_EXPORTS
 endif
-
 endif
 
 ################################################################################
 # Export the elements of $(XPIDLSRCS)
 # generating .h and .xpt files and moving them to the appropriate places.
 
 ifneq ($(XPIDLSRCS),) #{
 
@@ -1266,48 +1270,46 @@ xpidl-preqs = \
 	  $(LIBXUL_DIST)/sdk/bin/typelib.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
 
 # no need to link together if XPIDLSRCS contains only XPIDL_MODULE
 ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
 $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS)
 	$(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
 endif # XPIDL_MODULE.xpt != XPIDLSRCS
 
-libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
 ifndef NO_DIST_INSTALL
-	$(call install_cmd,$(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components)
+XPIDL_MODULE_FILES := $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
+XPIDL_MODULE_DEST := $(FINAL_TARGET)/components
+INSTALL_TARGETS += XPIDL_MODULE
+
 ifndef NO_INTERFACES_MANIFEST
 libs:: $(call mkdir_deps,$(FINAL_TARGET)/components)
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
 GARBAGE_DIRS		+= $(XPIDL_GEN_DIR)
 
+ifndef NO_DIST_INSTALL
+XPIDL_HEADERS_FILES := $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS))
+XPIDL_HEADERS_DEST := $(DIST)/include
+XPIDL_HEADERS_TARGET := export
+INSTALL_TARGETS += XPIDL_HEADERS
+
+XPIDLSRCS_FILES := $(XPIDLSRCS)
+XPIDLSRCS_DEST := $(IDL_DIR)
+XPIDLSRCS_TARGET := export-idl
+INSTALL_TARGETS += XPIDLSRCS
+
+export:: export-idl
+endif
 endif #} XPIDLSRCS
 
-
-ifndef INCLUDED_XPIDL_MK
-  include $(topsrcdir)/config/makefiles/xpidl.mk
-endif
-
-
-# General rules for exporting idl files.
-$(IDL_DIR):
-	$(NSINSTALL) -D $@
-
 export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
-
-ifneq ($(XPIDLSRCS),)
-ifndef NO_DIST_INSTALL
-export-idl:: $(XPIDLSRCS) $(IDL_DIR)
-	$(call install_cmd,$(IFLAGS1) $^)
-endif
-endif
 	$(LOOP_OVER_PARALLEL_DIRS)
 	$(LOOP_OVER_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
 
 ################################################################################
 # Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
 ifneq (,$(filter %.js,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
 ifeq (,$(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
@@ -1315,17 +1317,19 @@ ifndef NO_JS_MANIFEST
 $(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0)
 endif
 endif
 endif
 
 ifdef EXTRA_COMPONENTS
 libs:: $(EXTRA_COMPONENTS)
 ifndef NO_DIST_INSTALL
-	$(call install_cmd,$(IFLAGS1) $^ $(FINAL_TARGET)/components)
+EXTRA_COMPONENTS_FILES := $(EXTRA_COMPONENTS)
+EXTRA_COMPONENTS_DEST := $(FINAL_TARGET)/components
+INSTALL_TARGETS += EXTRA_COMPONENTS
 endif
 
 endif
 
 ifdef EXTRA_PP_COMPONENTS
 ifndef NO_DIST_INSTALL
 EXTRA_PP_COMPONENTS_PATH := $(FINAL_TARGET)/components
 PP_TARGETS += EXTRA_PP_COMPONENTS
@@ -1339,21 +1343,21 @@ libs:: $(call mkdir_deps,$(FINAL_TARGET)
 endif
 
 ################################################################################
 # Copy each element of EXTRA_JS_MODULES to JS_MODULES_PATH, or
 # $(FINAL_TARGET)/modules if that isn't defined.
 JS_MODULES_PATH ?= $(FINAL_TARGET)/modules
 
 ifdef EXTRA_JS_MODULES
-libs:: $(EXTRA_JS_MODULES)
 ifndef NO_DIST_INSTALL
-	$(call install_cmd,$(IFLAGS1) $^ $(JS_MODULES_PATH))
+EXTRA_JS_MODULES_FILES := $(EXTRA_JS_MODULES)
+EXTRA_JS_MODULES_DEST := $(JS_MODULES_PATH)
+INSTALL_TARGETS += EXTRA_JS_MODULES
 endif
-
 endif
 
 ifdef EXTRA_PP_JS_MODULES
 ifndef NO_DIST_INSTALL
 EXTRA_PP_JS_MODULES_PATH := $(JS_MODULES_PATH)
 PP_TARGETS += EXTRA_PP_JS_MODULES
 endif
 endif
@@ -1365,46 +1369,41 @@ endif
 # objdir/_tests/modules/. If TESTING_JS_MODULE_DIR is defined, that path
 # wlll be appended to the output directory.
 
 ifdef TESTING_JS_MODULES
 testmodulesdir = $(DEPTH)/_tests/modules/$(TESTING_JS_MODULE_DIR)
 
 GENERATED_DIRS += $(testmodulesdir)
 
-libs:: $(TESTING_JS_MODULES)
 ifndef NO_DIST_INSTALL
-	$(call install_cmd,$(IFLAGS) $^ $(testmodulesdir))
+TESTING_JS_MODULES_FILES := $(TESTING_JS_MODULES)
+TESTING_JS_MODULES_DEST := $(testmodulesdir)
+INSTALL_TARGETS += TESTING_JS_MODULES
 endif
 
 endif
 
 ################################################################################
 # SDK
 
 ifneq (,$(SDK_LIBRARY))
-$(SDK_LIB_DIR)::
-	$(NSINSTALL) -D $@
-
 ifndef NO_DIST_INSTALL
-libs:: $(SDK_LIBRARY) $(SDK_LIB_DIR)
-	$(call install_cmd,$(IFLAGS2) $^)
+SDK_LIBRARY_FILES := $(SDK_LIBRARY)
+SDK_LIBRARY_DEST := $(SDK_LIB_DIR)
+INSTALL_TARGETS += SDK_LIBRARY
 endif
-
 endif # SDK_LIBRARY
 
 ifneq (,$(strip $(SDK_BINARY)))
-$(SDK_BIN_DIR)::
-	$(NSINSTALL) -D $@
-
 ifndef NO_DIST_INSTALL
-libs:: $(SDK_BINARY) $(SDK_BIN_DIR)
-	$(call install_cmd,$(IFLAGS2) $^)
+SDK_BINARY_FILES := $(SDK_BINARY)
+SDK_BINARY_DEST := $(SDK_BIN_DIR)
+INSTALL_TARGETS += SDK_BINARY
 endif
-
 endif # SDK_BINARY
 
 ################################################################################
 # CHROME PACKAGING
 
 JAR_MANIFEST := $(srcdir)/jar.mn
 
 chrome::
@@ -1530,61 +1529,78 @@ TAGS:: $(CSRCS) $(CPPSRCS) $(HEADERS)
 	$(ETAGS) $(CSRCS) $(CPPSRCS) $(HEADERS)
 endif
 endif
 
 ################################################################################
 # Install/copy rules
 #
 # The INSTALL_TARGETS variable contains a list of all install target
-# categories. Each category defines a list of files, an install destination,
-# and whether the files are executables or not.
+# categories. Each category defines a list of files and executables, and an
+# install destination,
 #
 # FOO_FILES := foo bar
 # FOO_EXECUTABLES := baz
 # FOO_DEST := target_path
 # INSTALL_TARGETS += FOO
+#
+# Additionally, a FOO_TARGET variable may be added to indicate the target for
+# which the files and executables are installed. Default is "libs".
+
+# If we're using binary nsinstall and it's not built yet, fallback to python nsinstall.
+ifneq (,$(filter $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX),$(install_cmd)))
+nsinstall_is_usable = $(if $(wildcard $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX)),$(eval nsinstall_is_usable := yes)yes)
+
+define install_cmd_override
+$(1): install_cmd = $$(if $$(nsinstall_is_usable),$$(INSTALL),$$(NSINSTALL_PY)) $$(1)
+endef
+endif
+
 define install_file_template
-libs:: $(2)/$(notdir $(1))
+$(or $(3),libs):: $(2)/$(notdir $(1))
+$(call install_cmd_override,$(2)/$(notdir $(1)))
 $(2)/$(notdir $(1)): $(1) $$(call mkdir_deps,$(2))
-	$(INSTALL) $(3) $$< $${@D}
+	$$(call install_cmd,$(4) $$< $${@D})
 endef
 $(foreach category,$(INSTALL_TARGETS),\
   $(if $($(category)_DEST),,$(error Missing $(category)_DEST))\
   $(foreach file,$($(category)_FILES),\
-    $(eval $(call install_file_template,$(file),$($(category)_DEST),$(IFLAGS1)))\
+    $(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS1)))\
   )\
   $(foreach file,$($(category)_EXECUTABLES),\
-    $(eval $(call install_file_template,$(file),$($(category)_DEST),$(IFLAGS2)))\
+    $(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS2)))\
   )\
 )
 
 ################################################################################
 # Preprocessing rules
 #
 # The PP_TARGETS variable contains a list of all preprocessing target
 # categories. Each category defines a target path, and optional extra flags
 # like the following:
 #
 # FOO_PATH := target_path
 # FOO_FLAGS := -Dsome_flag
 # PP_TARGETS += FOO
+#
+# Additionally, a FOO_TARGET variable may be added to indicate the target for
+# which the files and executables are installed. Default is "libs".
 
 # preprocess_file_template defines preprocessing rules.
 # $(call preprocess_file_template, source_file, target_path, extra_flags)
 define preprocess_file_template
 $(2)/$(notdir $(1)): $(1) $$(call mkdir_deps,$(2)) $$(GLOBAL_DEPS)
 	$$(RM) $$@
-	$$(PYTHON) $$(topsrcdir)/config/Preprocessor.py $(3) $$(DEFINES) $$(ACDEFINES) $$(XULPPFLAGS) $$< > $$@
-libs:: $(2)/$(notdir $(1))
+	$$(PYTHON) $$(topsrcdir)/config/Preprocessor.py $(4) $$(DEFINES) $$(ACDEFINES) $$(XULPPFLAGS) $$< > $$@
+$(or $(3),libs):: $(2)/$(notdir $(1))
 endef
 
 $(foreach category,$(PP_TARGETS),\
   $(foreach file,$($(category)),\
-    $(eval $(call preprocess_file_template,$(file),$($(category)_PATH),$($(category)_FLAGS)))\
+    $(eval $(call preprocess_file_template,$(file),$($(category)_PATH),$($(category)_TARGET),$($(category)_FLAGS)))\
    )\
  )
 
 ################################################################################
 # Special gmake rules.
 ################################################################################
 
 
--- a/configure.in
+++ b/configure.in
@@ -3849,48 +3849,49 @@ else
         NSPR_CFLAGS=`"${LIBXUL_DIST}"/sdk/bin/nspr-config --prefix="${LIBXUL_DIST}" --includedir="${LIBXUL_DIST}/include/nspr" --cflags`
         NSPR_LIBS=`"${LIBXUL_DIST}"/sdk/bin/nspr-config --prefix="${LIBXUL_DIST}" --libdir="${LIBXUL_DIST}"/lib --libs`
     fi
 fi
 
 dnl system libevent Support
 dnl ========================================================
 MOZ_ARG_WITH_STRING(system-libevent,
-[  --with-system-libevent=[PFX]
+[  --with-system-libevent[=PFX]
                           Use system libevent [installed at prefix PFX]],
     LIBEVENT_DIR=$withval)
 
 _SAVE_CFLAGS=$CFLAGS
 _SAVE_LDFLAGS=$LDFLAGS
 _SAVE_LIBS=$LIBS
 if test -z "$LIBEVENT_DIR" -o "$LIBEVENT_DIR" = no; then
     MOZ_NATIVE_LIBEVENT=
+elif test "$LIBEVENT_DIR" = yes; then
+    PKG_CHECK_MODULES(MOZ_LIBEVENT, libevent,
+        MOZ_NATIVE_LIBEVENT=1,
+        AC_MSG_ERROR([--with-system-libevent requested but libevent package not found]))
 else
-    if test "${LIBEVENT_DIR}" = "yes"; then
-        LIBEVENT_DIR=/usr
-    fi
     CFLAGS="-I${LIBEVENT_DIR}/include $CFLAGS"
     LDFLAGS="-L${LIBEVENT_DIR}/lib $LDFLAGS"
     MOZ_CHECK_HEADER(event.h,
         [if test ! -f "${LIBEVENT_DIR}/include/event.h"; then
              AC_MSG_ERROR([event.h found, but is not in ${LIBEVENT_DIR}/include])
          fi],
         AC_MSG_ERROR([--with-system-libevent requested but event.h not found]))
     AC_CHECK_LIB(event, event_init,
                  [MOZ_NATIVE_LIBEVENT=1
-                  MOZ_LIBEVENT_INCLUDES="${LIBEVENT_DIR}/include"
+                  MOZ_LIBEVENT_CFLAGS="-I${LIBEVENT_DIR}/include"
                   MOZ_LIBEVENT_LIBS="-L${LIBEVENT_DIR}/lib -levent"],
-                 [MOZ_NATIVE_LIBEVENT= MOZ_LIBEVENT_INCLUDES= MOZ_LIBEVENT_LIBS=])
+                 [MOZ_NATIVE_LIBEVENT= MOZ_LIBEVENT_CFLAGS= MOZ_LIBEVENT_LIBS=])
 fi
 CFLAGS=$_SAVE_CFLAGS
 LDFLAGS=$_SAVE_LDFLAGS
 LIBS=$_SAVE_LIBS
 
 AC_SUBST(MOZ_NATIVE_LIBEVENT)
-AC_SUBST(MOZ_LIBEVENT_INCLUDES)
+AC_SUBST(MOZ_LIBEVENT_CFLAGS)
 AC_SUBST(MOZ_LIBEVENT_LIBS)
 
 dnl ========================================================
 dnl = If NSS was not detected in the system,
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3593,31 +3593,49 @@ nsContentUtils::ConvertStringFromCharset
 
   nsCOMPtr<nsIUnicodeDecoder> decoder;
   rv = ccm->GetUnicodeDecoder(PromiseFlatCString(aCharset).get(),
                               getter_AddRefs(decoder));
   if (NS_FAILED(rv))
     return rv;
 
   nsPromiseFlatCString flatInput(aInput);
-  int32_t srcLen = flatInput.Length();
-  int32_t dstLen;
-  rv = decoder->GetMaxLength(flatInput.get(), srcLen, &dstLen);
+  int32_t length = flatInput.Length();
+  int32_t outLen;
+  rv = decoder->GetMaxLength(flatInput.get(), length, &outLen);
   if (NS_FAILED(rv))
     return rv;
 
-  PRUnichar *ustr = (PRUnichar *)nsMemory::Alloc((dstLen + 1) *
+  PRUnichar *ustr = (PRUnichar *)nsMemory::Alloc((outLen + 1) *
                                                  sizeof(PRUnichar));
   if (!ustr)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  rv = decoder->Convert(flatInput.get(), &srcLen, ustr, &dstLen);
-  if (NS_SUCCEEDED(rv)) {
+  const char* data = flatInput.get();
+  aOutput.Truncate();
+  for (;;) {
+    int32_t srcLen = length;
+    int32_t dstLen = outLen;
+    rv = decoder->Convert(data, &srcLen, ustr, &dstLen);
+    // Convert will convert the input partially even if the status
+    // indicates a failure.
     ustr[dstLen] = 0;
-    aOutput.Assign(ustr, dstLen);
+    aOutput.Append(ustr, dstLen);
+    if (rv != NS_ERROR_ILLEGAL_INPUT) {
+      break;
+    }
+    // Emit a decode error manually because some decoders
+    // do not support kOnError_Recover (bug 638379)
+    if (srcLen == -1) {
+      decoder->Reset();
+    } else {
+      data += srcLen + 1;
+      length -= srcLen + 1;
+      aOutput.Append(static_cast<PRUnichar>(0xFFFD));
+    }
   }
 
   nsMemory::Free(ustr);
   return rv;
 }
 
 /* static */
 bool
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -86,16 +86,20 @@
 #include "nsIAppsService.h"
 
 #include "jsapi.h"
 #include "nsHTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
 
 #include "mozilla/dom/StructuredCloneUtils.h"
 
+#ifdef MOZ_XUL
+#include "nsXULPopupManager.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 typedef FrameMetrics::ViewID ViewID;
 
 class nsAsyncDocShellDestroyer : public nsRunnable
 {
@@ -301,16 +305,17 @@ nsFrameLoader::nsFrameLoader(Element* aO
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
   , mDelayRemoteDialogs(false)
   , mRemoteBrowserShown(false)
   , mRemoteFrame(false)
   , mClipSubdocument(true)
   , mClampScrollPosition(true)
   , mRemoteBrowserInitialized(false)
+  , mObservingOwnerContent(false)
   , mCurrentRemoteFrame(nullptr)
   , mRemoteBrowser(nullptr)
   , mRenderMode(RENDER_MODE_DEFAULT)
   , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
 {
 }
 
 nsFrameLoader*
@@ -652,52 +657,47 @@ SetTreeOwnerAndChromeEventHandlerOnDocsh
     aItem->GetChildAt(i, getter_AddRefs(item));
     SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
   }
 }
 
 /**
  * Set the type of the treeitem and hook it up to the treeowner.
  * @param aItem the treeitem we're working with
- * @param aOwningContent the content node that owns aItem
  * @param aTreeOwner the relevant treeowner; might be null
  * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
  * @param aParentNode if non-null, the docshell we should be added as a child to
  *
  * @return whether aItem is top-level content
  */
-static bool
-AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, nsIContent* aOwningContent,
-                       nsIDocShellTreeOwner* aOwner, int32_t aParentType,
-                       nsIDocShellTreeNode* aParentNode)
+bool
+nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
+                                      nsIDocShellTreeOwner* aOwner,
+                                      int32_t aParentType,
+                                      nsIDocShellTreeNode* aParentNode)
 {
   NS_PRECONDITION(aItem, "Must have docshell treeitem");
-  NS_PRECONDITION(aOwningContent, "Must have owning content");
+  NS_PRECONDITION(mOwnerContent, "Must have owning content");
   
   nsAutoString value;
   bool isContent = false;
-
-  if (aOwningContent->IsXUL()) {
-      aOwningContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
-  } else {
-      aOwningContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozframetype, value);
-  }
+  mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
 
   // we accept "content" and "content-xxx" values.
   // at time of writing, we expect "xxx" to be "primary" or "targetable", but
   // someday it might be an integer expressing priority or something else.
 
   isContent = value.LowerCaseEqualsLiteral("content") ||
     StringBeginsWith(value, NS_LITERAL_STRING("content-"),
                      nsCaseInsensitiveStringComparator());
 
   // Force mozbrowser frames to always be typeContent, even if the
   // mozbrowser interfaces are disabled.
   nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
-    do_QueryInterface(aOwningContent);
+    do_QueryInterface(mOwnerContent);
   if (mozbrowser) {
     bool isMozbrowser = false;
     mozbrowser->GetMozbrowser(&isMozbrowser);
     isContent |= isMozbrowser;
   }
 
   if (isContent) {
     // The web shell's type is content.
@@ -720,16 +720,18 @@ AddTreeItemToTreeOwner(nsIDocShellTreeIt
   if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
     retval = true;
 
     bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
 
     if (aOwner) {
       bool is_targetable = is_primary ||
         value.LowerCaseEqualsLiteral("content-targetable");
+      mOwnerContent->AddMutationObserver(this);
+      mObservingOwnerContent = true;
       aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value);
     }
   }
 
   return retval;
 }
 
 static bool
@@ -1200,36 +1202,38 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   otherParentItem->AddChild(ourTreeItem);
 
   // Restore the correct treeowners
   SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourTreeItem, otherOwner,
                                                   otherChromeEventHandler);
   SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherTreeItem, ourOwner,
                                                   ourChromeEventHandler);
 
-  AddTreeItemToTreeOwner(ourTreeItem, otherContent, otherOwner,
-                         otherParentType, nullptr);
-  AddTreeItemToTreeOwner(otherTreeItem, ourContent, ourOwner, ourParentType,
-                         nullptr);
+  // Switch the owner content before we start calling AddTreeItemToTreeOwner.
+  // Note that we rely on this to deal with setting mObservingOwnerContent to
+  // false and calling RemoveMutationObserver as needed.
+  SetOwnerContent(otherContent);
+  aOther->SetOwnerContent(ourContent);
+
+  AddTreeItemToTreeOwner(ourTreeItem, otherOwner, otherParentType, nullptr);
+  aOther->AddTreeItemToTreeOwner(otherTreeItem, ourOwner, ourParentType,
+                                 nullptr);
 
   // SetSubDocumentFor nulls out parent documents on the old child doc if a
   // new non-null document is passed in, so just go ahead and remove both
   // kids before reinserting in the parent subdoc maps, to avoid
   // complications.
   ourParentDocument->SetSubDocumentFor(ourContent, nullptr);
   otherParentDocument->SetSubDocumentFor(otherContent, nullptr);
   ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
   otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
 
   ourWindow->SetFrameElementInternal(otherFrameElement);
   otherWindow->SetFrameElementInternal(ourFrameElement);
 
-  SetOwnerContent(otherContent);
-  aOther->SetOwnerContent(ourContent);
-
   nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
   nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
   // Swap pointers in child message managers.
   if (mChildMessageManager) {
     nsInProcessTabChildGlobal* tabChild =
       static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
     tabChild->SetOwner(otherContent);
     tabChild->SetChromeMessageManager(otherMessageManager);
@@ -1378,16 +1382,20 @@ nsFrameLoader::GetDepthTooGreat(bool* aD
 {
   *aDepthTooGreat = mDepthTooGreat;
   return NS_OK;
 }
 
 void
 nsFrameLoader::SetOwnerContent(Element* aContent)
 {
+  if (mObservingOwnerContent) {
+    mObservingOwnerContent = false;
+    mOwnerContent->RemoveMutationObserver(this);
+  }
   mOwnerContent = aContent;
   if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
     rfp->OwnerContentChanged(aContent);
   }
 }
 
 bool
 nsFrameLoader::OwnerIsBrowserFrame()
@@ -1554,18 +1562,18 @@ nsFrameLoader::MaybeCreateDocShell()
     parentAsItem->GetItemType(&parentType);
 
     // XXXbz why is this in content code, exactly?  We should handle
     // this some other way.....  Not sure how yet.
     nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
     parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
     NS_ENSURE_STATE(parentTreeOwner);
     mIsTopLevelContent =
-      AddTreeItemToTreeOwner(docShellAsItem, mOwnerContent, parentTreeOwner,
-                             parentType, parentAsNode);
+      AddTreeItemToTreeOwner(docShellAsItem, parentTreeOwner, parentType,
+                             parentAsNode);
 
     // Make sure all shells have links back to the content element
     // in the nearest enclosing chrome shell.
     nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
 
     if (parentType == nsIDocShellTreeItem::typeChrome) {
       // Our parent shell is a chrome shell. It is therefore our nearest
       // enclosing chrome shell.
@@ -2399,8 +2407,83 @@ nsFrameLoader::SetDetachedSubdocView(nsI
 
 nsIView*
 nsFrameLoader::GetDetachedSubdocView(nsIDocument** aContainerDoc) const
 {
   NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached);
   return mDetachedSubdocViews;
 }
 
+/* virtual */ void
+nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
+                                mozilla::dom::Element* aElement,
+                                int32_t      aNameSpaceID,
+                                nsIAtom*     aAttribute,
+                                int32_t      aModType)
+{
+  MOZ_ASSERT(mObservingOwnerContent);
+  // TODO: Implement ContentShellAdded for remote browsers (bug 658304)
+  MOZ_ASSERT(!mRemoteBrowser);
+
+  if (aNameSpaceID != kNameSpaceID_None || aAttribute != TypeAttrName()) {
+    return;
+  }
+
+  if (aElement != mOwnerContent) {
+    return;
+  }
+
+  // Note: This logic duplicates a lot of logic in
+  // MaybeCreateDocshell.  We should fix that.
+
+  // Notify our enclosing chrome that our type has changed.  We only do this
+  // if our parent is chrome, since in all other cases we're random content
+  // subframes and the treeowner shouldn't worry about us.
+
+  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
+  if (!docShellAsItem) {
+    return;
+  }
+
+  nsCOMPtr<nsIDocShellTreeItem> parentItem;
+  docShellAsItem->GetParent(getter_AddRefs(parentItem));
+  if (!parentItem) {
+    return;
+  }
+
+  int32_t parentType;
+  parentItem->GetItemType(&parentType);
+
+  if (parentType != nsIDocShellTreeItem::typeChrome) {
+    return;
+  }
+
+  nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
+  parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
+  if (!parentTreeOwner) {
+    return;
+  }
+
+  nsAutoString value;
+  aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
+
+  bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
+
+#ifdef MOZ_XUL
+  // when a content panel is no longer primary, hide any open popups it may have
+  if (!is_primary) {
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm)
+      pm->HidePopupsInDocShell(docShellAsItem);
+  }
+#endif
+
+  parentTreeOwner->ContentShellRemoved(docShellAsItem);
+  if (value.LowerCaseEqualsLiteral("content") ||
+      StringBeginsWith(value, NS_LITERAL_STRING("content-"),
+                       nsCaseInsensitiveStringComparator())) {
+    bool is_targetable = is_primary ||
+      value.LowerCaseEqualsLiteral("content-targetable");
+
+    parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
+                                       is_targetable, value);
+  }
+}
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -17,23 +17,27 @@
 #include "nsPoint.h"
 #include "nsSize.h"
 #include "nsIURI.h"
 #include "nsAutoPtr.h"
 #include "nsFrameMessageManager.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Attributes.h"
 #include "FrameMetrics.h"
+#include "nsStubMutationObserver.h"
 
 class nsIURI;
 class nsSubDocumentFrame;
 class nsIView;
 class nsIInProcessContentFrameMessageManager;
 class AutoResetInShow;
 class nsITabParent;
+class nsIDocShellTreeItem;
+class nsIDocShellTreeOwner;
+class nsIDocShellTreeNode;
 
 namespace mozilla {
 namespace dom {
 class PBrowserParent;
 class TabParent;
 }
 
 namespace layout {
@@ -130,17 +134,18 @@ private:
   nsresult Update(const ViewConfig& aConfig);
 
   ViewID mScrollId;
   ViewConfig mConfig;
 };
 
 
 class nsFrameLoader MOZ_FINAL : public nsIFrameLoader,
-                                public nsIContentViewManager
+                                public nsIContentViewManager,
+                                public nsStubMutationObserver
 {
   friend class AutoResetInShow;
   typedef mozilla::dom::PBrowserParent PBrowserParent;
   typedef mozilla::dom::TabParent TabParent;
   typedef mozilla::layout::RenderFrameParent RenderFrameParent;
 
 protected:
   nsFrameLoader(mozilla::dom::Element* aOwner, bool aNetworkCreated);
@@ -161,16 +166,17 @@ public:
 
   static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
                                bool aNetworkCreated);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
   NS_DECL_NSIFRAMELOADER
   NS_DECL_NSICONTENTVIEWMANAGER
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI);
   nsresult ReallyStartLoading();
   void Finalize();
   nsIDocShell* GetExistingDocShell() { return mDocShell; }
   nsIDOMEventTarget* GetTabChildGlobalAsEventTarget();
   nsresult CreateStaticClone(nsIFrameLoader* aDest);
 
   /**
@@ -332,19 +338,29 @@ private:
   nsresult ReallyStartLoadingInternal();
 
   // Return true if remote browser created; nothing else to do
   bool TryRemoteBrowser();
 
   // Tell the remote browser that it's now "virtually visible"
   bool ShowRemoteFrame(const nsIntSize& size);
 
+  bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
+                              nsIDocShellTreeOwner* aOwner,
+                              int32_t aParentType,
+                              nsIDocShellTreeNode* aParentNode);
+
+  nsIAtom* TypeAttrName() const {
+    return mOwnerContent->IsXUL() ? nsGkAtoms::type : nsGkAtoms::mozframetype;
+  }
+
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURIToLoad;
   mozilla::dom::Element* mOwnerContent; // WEAK
+
 public:
   // public because a callback needs these.
   nsRefPtr<nsFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIInProcessContentFrameMessageManager> mChildMessageManager;
 private:
   // Stores the root view of the subdocument while the subdocument is being
   // reframed. Used to restore the presentation after reframing.
   nsIView* mDetachedSubdocViews;
@@ -368,16 +384,17 @@ private:
   bool mNetworkCreated : 1;
 
   bool mDelayRemoteDialogs : 1;
   bool mRemoteBrowserShown : 1;
   bool mRemoteFrame : 1;
   bool mClipSubdocument : 1;
   bool mClampScrollPosition : 1;
   bool mRemoteBrowserInitialized : 1;
+  bool mObservingOwnerContent : 1;
 
   // XXX leaking
   nsCOMPtr<nsIObserver> mChildHost;
   RenderFrameParent* mCurrentRemoteFrame;
   TabParent* mRemoteBrowser;
 
   // See nsIFrameLoader.idl.  Short story, if !(mRenderMode &
   // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -953,18 +953,17 @@ nsFrameScriptExecutor::InitTabChildGloba
                     (allowXML ? JSOPTION_ALLOW_XML : 0));
   JS_SetVersion(cx, JSVERSION_LATEST);
   JS_SetErrorReporter(cx, ContentScriptErrorReporter);
 
   xpc_LocalizeContext(cx);
 
   JSAutoRequest ar(cx);
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
-  const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
-                         nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
+  const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
 
   
   JS_SetContextPrivate(cx, aScope);
 
   nsresult rv =
     xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
                                          flags, getter_AddRefs(mGlobal));
   NS_ENSURE_SUCCESS(rv, false);
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -682,53 +682,47 @@ nsObjectLoadingContent::~nsObjectLoading
     StopPluginInstance();
   }
   DestroyImageLoadingContent();
 }
 
 nsresult
 nsObjectLoadingContent::InstantiatePluginInstance()
 {
-  if (mType != eType_Plugin || mIsLoading) {
-    LOG(("OBJLC [%p]: Not instantiating loading or non-plugin object, type %u",
-         this, mType));
+  if (mInstanceOwner || mType != eType_Plugin || mIsLoading || mInstantiating) {
+    return NS_OK;
+  }
+  
+  nsCOMPtr<nsIContent> thisContent =
+    do_QueryInterface(static_cast<nsIImageLoadingContent *>(this));
+
+  // Flush layout so that the frame is created if possible and the plugin is
+  // initialized with the latest information.
+  nsIDocument* doc = thisContent->GetCurrentDoc();
+  
+  if (!doc || !InActiveDocument(thisContent)) {
+    NS_ERROR("Shouldn't be calling "
+             "InstantiatePluginInstance without an active document");
+    return NS_ERROR_FAILURE;
+  }
+  doc->FlushPendingNotifications(Flush_Layout);
+  
+  if (!thisContent->GetPrimaryFrame()) {
+    LOG(("OBJLC [%p]: Not instantiating plugin with no frame", this));
     return NS_OK;
   }
 
-  // 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;
-  }
   mInstantiating = true;
   AutoSetInstantiatingToFalse autoInstantiating(this);
 
   // Instantiating an instance can result in script execution, which
   // can destroy this DOM object. Don't allow that for the scope
   // of this method.
   nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
 
-  nsCOMPtr<nsIContent> thisContent =
-    do_QueryInterface(static_cast<nsIImageLoadingContent *>(this));
-  // Flush layout so that the plugin is initialized with the latest information.
-  nsIDocument* doc = thisContent->GetCurrentDoc();
-  if (!doc) {
-    return NS_ERROR_FAILURE;
-  }
-  if (!InActiveDocument(thisContent)) {
-    NS_ERROR("Shouldn't be calling "
-             "InstantiatePluginInstance in an inactive document");
-    return NS_ERROR_FAILURE;
-  }
-  doc->FlushPendingNotifications(Flush_Layout);
-
   nsresult rv = NS_ERROR_FAILURE;
   nsRefPtr<nsPluginHost> pluginHost =
     already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
 
   if (!pluginHost) {
     NS_NOTREACHED("No pluginhost");
     return NS_ERROR_FAILURE;
   }
@@ -1724,16 +1718,24 @@ nsObjectLoadingContent::LoadObject(bool 
           break;
         }
 
         // Force a sync state change now, we need the frame created
         NotifyStateChanged(oldType, oldState, true, aNotify);
         oldType = mType;
         oldState = ObjectState();
 
+        if (!thisContent->GetPrimaryFrame()) {
+          // We're un-rendered, and can't instantiate a plugin. HasNewFrame will
+          // re-start us when we can proceed.
+          LOG(("OBJLC [%p]: Aborting load - plugin-type, but no frame", this));
+          CloseChannel();
+          break;
+        }
+        
         rv = pluginHost->NewEmbeddedPluginStreamListener(mURI, this, nullptr,
                                                          getter_AddRefs(mFinalListener));
         if (NS_SUCCEEDED(rv)) {
           // Note that LoadObject is called from mChannel's OnStartRequest
           // when loading with a channel
 
           mSrcStreamLoading = true;
           rv = mFinalListener->OnStartRequest(mChannel, nullptr);
new file mode 100644
--- /dev/null
+++ b/content/canvas/crashtests/0px-size-font-shadow.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<body>
+<canvas id="canv" width="5" height="5"></canvas>
+<script>
+var canv = document.getElementById("canv");
+var ctx = canv.getContext("2d");
+
+ctx.fillStyle = "red";
+// 0 size font shouldn't assert!
+ctx.font = "0px Arial";
+ctx.shadowColor = '#f00';
+ctx.shadowBlur = 4;
+ctx.fillText("A", 0, 0);
+document.documentElement.className = "";
+</script>
+</body>
+</html>
--- a/content/canvas/crashtests/crashtests.list
+++ b/content/canvas/crashtests/crashtests.list
@@ -1,14 +1,15 @@
 load 360293-1.html
 load 421715-1.html
 load 553938-1.html
 load 647480.html
 load 727547.html
 load 0px-size-font-667225.html
+load 0px-size-font-shadow.html
 load texImage2D.html
 load 729116.html
 load 745699-1.html
 load 746813-1.html
 # this test crashes in a bunch places still
 #load 745818-large-source.html
 load 743499-negative-size.html
 load 767337-1.html
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -4316,32 +4316,38 @@ static uint8_t g2DContextLayerUserData;
 already_AddRefed<CanvasLayer>
 nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                            CanvasLayer *aOldLayer,
                                            LayerManager *aManager)
 {
     // If we don't have anything to draw, don't bother.
     if (!mValid || !mSurface || mSurface->CairoStatus() || !mThebes ||
         !mSurfaceCreated) {
+        // No DidTransactionCallback will be received, so mark the context clean
+        // now so future invalidations will be dispatched.
+        MarkContextClean();
         return nullptr;
     }
 
     if (!mResetLayer && aOldLayer) {
         CanvasRenderingContext2DUserData* userData =
             static_cast<CanvasRenderingContext2DUserData*>(
                     aOldLayer->GetUserData(&g2DContextLayerUserData));
         if (userData && userData->IsForContext(this)) {
             NS_ADDREF(aOldLayer);
             return aOldLayer;
         }
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
+        // No DidTransactionCallback will be received, so mark the context clean
+        // now so future invalidations will be dispatched.
+        MarkContextClean();
         return nullptr;
     }
     CanvasRenderingContext2DUserData *userData = nullptr;
     if (aBuilder->IsPaintingToWindow()) {
       // Make the layer tell us whenever a transaction finishes (including
       // the current transaction), so we can clear our invalidation state and
       // start invalidating again. We need to do this for the layer that is
       // being painted to a window (there shouldn't be more than one at a time,
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -3211,16 +3211,26 @@ nsCanvasRenderingContext2DAzure::DrawOrM
     }
 
     isRTL = canvasStyle->GetStyleVisibility()->mDirection ==
       NS_STYLE_DIRECTION_RTL;
   } else {
     isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL;
   }
 
+  gfxFontGroup* currentFontStyle = GetCurrentFontStyle();
+  NS_ASSERTION(currentFontStyle, "font group is null");
+
+  if (currentFontStyle->GetStyle()->size == 0.0F) {
+    if (aWidth) {
+      *aWidth = 0;
+    }
+    return NS_OK;
+  }
+
   const ContextState &state = CurrentState();
 
   // This is only needed to know if we can know the drawing bounding box easily.
   bool doDrawShadow = aOp == TEXT_DRAW_OPERATION_FILL && NeedToDrawShadow();
 
   nsCanvasBidiProcessorAzure processor;
 
   GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, nullptr);
@@ -3229,21 +3239,18 @@ nsCanvasRenderingContext2DAzure::DrawOrM
     new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
   Matrix matrix = mTarget->GetTransform();
   processor.mThebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, matrix._22, matrix._31, matrix._32));
   processor.mCtx = this;
   processor.mOp = aOp;
   processor.mBoundingBox = gfxRect(0, 0, 0, 0);
   processor.mDoMeasureBoundingBox = doDrawShadow || !mIsEntireFrameInvalid;
   processor.mState = &CurrentState();
+  processor.mFontgrp = currentFontStyle;
     
-
-  processor.mFontgrp = GetCurrentFontStyle();
-  NS_ASSERTION(processor.mFontgrp, "font group is null");
-
   nscoord totalWidthCoord;
 
   // calls bidi algo twice since it needs the full text width and the
   // bounding boxes before rendering anything
   nsBidi bidiEngine;
   rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
                                     textToDraw.Length(),
                                     isRTL ? NSBIDI_RTL : NSBIDI_LTR,
@@ -4621,16 +4628,19 @@ nsCanvasRenderingContext2DAzure::SetMozI
 static uint8_t g2DContextLayerUserData;
 
 already_AddRefed<CanvasLayer>
 nsCanvasRenderingContext2DAzure::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                 CanvasLayer *aOldLayer,
                                                 LayerManager *aManager)
 {
   if (!mValid) {
+    // No DidTransactionCallback will be received, so mark the context clean
+    // now so future invalidations will be dispatched.
+    MarkContextClean();
     return nullptr;
   }
 
   if (mTarget) {
     mTarget->Flush();
   }
 
   if (!mResetLayer && aOldLayer) {
@@ -4641,16 +4651,19 @@ nsCanvasRenderingContext2DAzure::GetCanv
       NS_ADDREF(aOldLayer);
       return aOldLayer;
     }
   }
 
   nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
   if (!canvasLayer) {
     NS_WARNING("CreateCanvasLayer returned null!");
+    // No DidTransactionCallback will be received, so mark the context clean
+    // now so future invalidations will be dispatched.
+    MarkContextClean();
     return nullptr;
   }
   CanvasRenderingContext2DUserDataAzure *userData = nullptr;
   // Make the layer tell us whenever a transaction finishes (including
   // the current transaction), so we can clear our invalidation state and
   // start invalidating again. We need to do this for all layers since
   // callers of DrawWindow may be expecting to receive normal invalidation
   // notifications after this paint.
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -308,16 +308,21 @@ public:
 #endif
 
 #ifdef MOZ_MEDIA_PLUGINS
   static bool IsMediaPluginsEnabled();
   static bool IsMediaPluginsType(const nsACString& aType);
 #endif
 
   /**
+   * Get the mime type for this element.
+   */
+  void GetMimeType(nsCString& aMimeType);
+
+  /**
    * Called when a child source element is added to this media element. This
    * may queue a task to run the select resource algorithm if appropriate.
    */
   void NotifyAddedSource();
 
   /**
    * Called when there's been an error fetching the resource. This decides
    * whether it's appropriate to fire an error event.
@@ -867,11 +872,18 @@ protected:
   // The CORS mode when loading the media element
   mozilla::CORSMode mCORSMode;
 
   // True if the media has an audio track
   bool mHasAudio;
 
   // True if the media's channel's download has been suspended.
   bool mDownloadSuspendedByCache;
+
+  // The Content-Type for this media. When we are sniffing for the Content-Type,
+  // and we are recreating a channel after the initial load, we need that
+  // information to give it as a hint to the channel for it to bypass the
+  // sniffing phase, that would fail because sniffing only works when applied to
+  // the first bytes of the stream.
+  nsCString mMimeType;
 };
 
 #endif
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1055,19 +1055,34 @@ nsHTMLInputElement::SetValue(const nsASt
       const PRUnichar *name = PromiseFlatString(aValue).get();
       return MozSetFileNameArray(&name, 1);
     }
     else {
       ClearFiles(true);
     }
   }
   else {
-    SetValueInternal(aValue, false, true);
     if (IsSingleLineTextControl(false)) {
-      GetValueInternal(mFocusedValue);
+      // If the value has been set by a script, we basically want to keep the
+      // current change event state. If the element is ready to fire a change
+      // event, we should keep it that way. Otherwise, we should make sure the
+      // element will not fire any event because of the script interaction.
+      //
+      // NOTE: this is currently quite expensive work (too much string
+      // manipulation). We should probably optimize that.
+      nsAutoString currentValue;
+      GetValueInternal(currentValue);
+
+      SetValueInternal(aValue, false, true);
+
+      if (mFocusedValue.Equals(currentValue)) {
+        GetValueInternal(mFocusedValue);
+      }
+    } else {
+      SetValueInternal(aValue, false, true);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::GetList(nsIDOMHTMLElement** aValue)
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -1029,16 +1029,21 @@ nsresult nsHTMLMediaElement::LoadResourc
 
   // Set the media element's CORS mode only when loading a resource
   mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
 
   nsHTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
   if (other) {
     // Clone it.
     nsresult rv = InitializeDecoderAsClone(other->mDecoder);
+    // Get the mimetype from the element we clone, since we will not get it via
+    // the channel, and we won't be able to sniff for it, because we will not
+    // open a channel to get the beginning of the media (it is likely to already
+    // be in the cache).
+    mMimeType = other->mMimeType;
     if (NS_SUCCEEDED(rv))
       return rv;
   }
 
   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
   nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_MEDIA,
                                           mLoadingSrc,
                                           NodePrincipal(),
@@ -1067,17 +1072,18 @@ nsresult nsHTMLMediaElement::LoadResourc
     channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA);
   }
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      mLoadingSrc,
                      nullptr,
                      loadGroup,
                      nullptr,
-                     nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
+                     nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
+                     nsIChannel::LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN,
                      channelPolicy);
   NS_ENSURE_SUCCESS(rv,rv);
 
   // The listener holds a strong reference to us.  This creates a
   // reference cycle, once we've set mChannel, which is manually broken
   // in the listener's OnStartRequest method after it is finished with
   // the element. The cycle will also be broken if we get a shutdown
   // notification before OnStartRequest fires.  Necko guarantees that
@@ -2428,29 +2434,31 @@ nsresult nsHTMLMediaElement::InitializeD
 
 nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
                                                          nsIStreamListener **aListener)
 {
   NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
   NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
 
   nsAutoCString mimeType;
-  aChannel->GetContentType(mimeType);
-
-  nsRefPtr<nsMediaDecoder> decoder = CreateDecoder(mimeType);
+
+  aChannel->GetContentType(mMimeType);
+  NS_ASSERTION(!mMimeType.IsEmpty(), "We should have the Content-Type.");
+
+  nsRefPtr<nsMediaDecoder> decoder = CreateDecoder(mMimeType);
   if (!decoder) {
     nsAutoString src;
     GetCurrentSrc(src);
-    NS_ConvertUTF8toUTF16 mimeUTF16(mimeType);
+    NS_ConvertUTF8toUTF16 mimeUTF16(mMimeType);
     const PRUnichar* params[] = { mimeUTF16.get(), src.get() };
     ReportLoadError("MediaLoadUnsupportedMimeType", params, ArrayLength(params));
     return NS_ERROR_FAILURE;
   }
 
-  LOG(PR_LOG_DEBUG, ("%p Created decoder %p for type %s", this, decoder.get(), mimeType.get()));
+  LOG(PR_LOG_DEBUG, ("%p Created decoder %p for type %s", this, decoder.get(), mMimeType.get()));
 
   MediaResource* resource = MediaResource::Create(decoder, aChannel);
   if (!resource)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // stream successfully created, the stream now owns the channel.
   mChannel = nullptr;
 
@@ -3523,14 +3531,19 @@ NS_IMETHODIMP nsHTMLMediaElement::GetMoz
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If there is no end fragment, or the fragment end is greater than the
   // duration, return the duration.
   *aTime = (mFragmentEnd < 0.0 || mFragmentEnd > duration) ? duration : mFragmentEnd;
   return NS_OK;
 }
 
+void nsHTMLMediaElement::GetMimeType(nsCString& aMimeType)
+{
+  aMimeType = mMimeType;
+}
+
 void nsHTMLMediaElement::NotifyAudioAvailableListener()
 {
   if (mDecoder) {
     mDecoder->NotifyAudioAvailableListener();
   }
 }
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -540,18 +540,32 @@ nsHTMLTextAreaElement::SetValueInternal(
   mState.SetValue(aValue, aUserInput, true);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsHTMLTextAreaElement::SetValue(const nsAString& aValue)
 {
+  // If the value has been set by a script, we basically want to keep the
+  // current change event state. If the element is ready to fire a change
+  // event, we should keep it that way. Otherwise, we should make sure the
+  // element will not fire any event because of the script interaction.
+  //
+  // NOTE: this is currently quite expensive work (too much string
+  // manipulation). We should probably optimize that.
+  nsAutoString currentValue;
+  GetValueInternal(currentValue, true);
+
   SetValueInternal(aValue, false);
-  GetValueInternal(mFocusedValue, true);
+
+  if (mFocusedValue.Equals(currentValue)) {
+    GetValueInternal(mFocusedValue, true);
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsHTMLTextAreaElement::SetUserInput(const nsAString& aValue)
 {
   if (!nsContentUtils::IsCallerTrustedForWrite()) {
     return NS_ERROR_DOM_SECURITY_ERR;
--- a/content/html/content/test/forms/test_change_event.html
+++ b/content/html/content/test/forms/test_change_event.html
@@ -101,23 +101,49 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     //focus and blur text input
     input = document.getElementById("input_text");
     input.focus();
     synthesizeKey("f", {});
     input.blur();
     is(textInputChange[0], 2, "text input element should have dispatched change event (2).");
 
+    // value being set while focused
+    input.focus();
+    input.value = 'foo';
+    input.blur();
+    is(textInputChange[0], 2, "text input element should not have dispatched change event (2).");
+
+    // value being set while focused after being modified manually
+    input.focus();
+    synthesizeKey("f", {});
+    input.value = 'bar';
+    input.blur();
+    is(textInputChange[0], 3, "text input element should have dispatched change event (3).");
+
     //focus and blur textarea
     var textarea = document.getElementById("textarea");
     textarea.focus();
     synthesizeKey("f", {});
     textarea.blur();
     is(textareaChange, 1, "Textarea element should have dispatched change event.");
 
+    // value being set while focused
+    textarea.focus();
+    textarea.value = 'foo';
+    textarea.blur();
+    is(textareaChange, 1, "textarea should not have dispatched change event (1).");
+
+    // value being set while focused after being modified manually
+    textarea.focus();
+    synthesizeKey("f", {});
+    textarea.value = 'bar';
+    textarea.blur();
+    is(textareaChange, 2, "textearea should have dispatched change event (2).");
+
     //Non-text input tests:
     for (var i = 0; i < NonTextInputTypes.length; ++i) {
       //button, submit, image and reset input type tests.
       if (i < 4) {
         input = document.getElementById("input_" + NonTextInputTypes[i]);
         input.focus();
         input.click();
         is(NonTextInputChange[i], 0, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element");
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1241,17 +1241,20 @@ nsHTMLDocument::GetCookie(nsAString& aCo
       // Document's principal is not a codebase (may be system), so
       // can't set cookies
 
       return NS_OK;
     }
 
     nsXPIDLCString cookie;
     service->GetCookieString(codebaseURI, mChannel, getter_Copies(cookie));
-    CopyASCIItoUTF16(cookie, aCookie);
+    // CopyUTF8toUTF16 doesn't handle error
+    // because it assumes that the input is valid.
+    nsContentUtils::ConvertStringFromCharset(NS_LITERAL_CSTRING("utf-8"),
+                                             cookie, aCookie);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::SetCookie(const nsAString& aCookie)
 {
@@ -1280,17 +1283,17 @@ nsHTMLDocument::SetCookie(const nsAStrin
 
     if (!codebaseURI) {
       // Document's principal is not a codebase (may be system), so
       // can't set cookies
 
       return NS_OK;
     }
 
-    NS_LossyConvertUTF16toASCII cookie(aCookie);
+    NS_ConvertUTF16toUTF8 cookie(aCookie);
     service->SetCookieString(codebaseURI, prompt, cookie.get(), mChannel);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
--- a/content/html/document/test/Makefile.in
+++ b/content/html/document/test/Makefile.in
@@ -67,16 +67,18 @@ MOCHITEST_FILES = 	test_bug1682.html \
 		test_bug499092.html \
 		bug499092.xml \
 		bug499092.html \
 		test_bug512367.html \
 		test_bug571981.html \
 		test_bug677495.html \
 		test_bug677495-1.html \
 		test_bug741266.html \
+		test_non-ascii-cookie.html \
+		test_non-ascii-cookie.html^headers^ \
 		$(NULL)
 
 ifneq (mobile,$(MOZ_BUILD_APP))
 MOCHITEST_BROWSER_FILES = \
 		browser_bug592641.js \
 		bug592641_img.jpg \
 		$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/content/html/document/test/test_non-ascii-cookie.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=784367
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for non-ASCII document.cookie</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=784367">Mozilla Bug 784367</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for non-ASCII document.cookie **/
+var c = document.cookie;
+is(document.cookie, 'abc=012©ABC\ufffdDEF', "document.cookie should be decoded as UTF-8");
+var newCookie = 'def=∼≩≭≧∯≳≲≣∽≸≸∺≸∠≯≮≥≲≲≯≲∽≡≬≥≲≴∨∱∩∾';
+document.cookie = newCookie;
+is(document.cookie, c + '; ' + newCookie, "document.cookie should be encoded as UTF-8");
+var date1 = new Date();
+date1.setTime(0);
+document.cookie = newCookie + 'def=;expires=' + date1.toGMTString();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/document/test/test_non-ascii-cookie.html^headers^
@@ -0,0 +1,1 @@
+Set-Cookie: abc=012©ABC©DEF
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -699,22 +699,34 @@ ChannelMediaResource::RecreateChannel()
   nsHTMLMediaElement* element = mDecoder->GetMediaElement();
   if (!element) {
     // The decoder is being shut down, so don't bother opening a new channel
     return NS_OK;
   }
   nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
   NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER);
 
-  return NS_NewChannel(getter_AddRefs(mChannel),
-                       mURI,
-                       nullptr,
-                       loadGroup,
-                       nullptr,
-                       loadFlags);
+  nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
+                              mURI,
+                              nullptr,
+                              loadGroup,
+                              nullptr,
+                              loadFlags);
+
+  // We have cached the Content-Type, which should not change. Give a hint to
+  // the channel to avoid a sniffing failure, which would be expected because we
+  // are probably seeking in the middle of the bitstream, and sniffing relies
+  // on the presence of a magic number at the beginning of the stream.
+  nsAutoCString contentType;
+  element->GetMimeType(contentType);
+  NS_ASSERTION(!contentType.IsEmpty(),
+      "When recreating a channel, we should know the Content-Type.");
+  mChannel->SetContentType(contentType);
+
+  return rv;
 }
 
 void
 ChannelMediaResource::DoNotifyDataReceived()
 {
   mDataReceivedEvent.Revoke();
   mDecoder->NotifyBytesDownloaded();
 }
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -122,16 +122,18 @@ MOCHITEST_FILES = \
 		test_autoplay_contentEditable.html \
 		test_buffered.html \
 		test_bug448534.html \
 		test_bug463162.xhtml \
 		test_decoder_disable.html \
 		test_media_selection.html \
 		test_playback.html \
 		test_seekLies.html \
+		test_media_sniffer.html \
+		contentType.sjs \
 		$(NULL)
 
 $(warning test_error_in_video_document.html is disabled for intermittent failures. Bug 608634)
 
 # Disabled on Windows for frequent intermittent failures
 ifneq ($(OS_ARCH), WINNT)
 MOCHITEST_FILES += \
 		test_streams_element_capture.html \
@@ -207,16 +209,19 @@ MOCHITEST_FILES += \
 		seek.yuv \
 		short-video.ogv \
 		small-shot.ogg \
 		sound.ogg \
 		spacestorm-1000Hz-100ms.ogg \
 		video-overhang.ogg \
 		file_a4_tone.ogg \
 		detodos.opus \
+		short.mp4 \
+		notags.mp3 \
+		id3tags.mp3 \
 		$(NULL)
 
 # Wave sample files
 MOCHITEST_FILES += \
 		big.wav \
 		bogus.wav \
 		r11025_msadpcm_c1.wav \
 		r11025_s16_c1.wav \
new file mode 100644
--- /dev/null
+++ b/content/media/test/contentType.sjs
@@ -0,0 +1,77 @@
+// Parse the query string, and give us the value for a certain key, or false if
+// it does not exist.
+function parseQuery(request, key) {
+  var params = request.queryString.split('?')[0].split('&');
+  for (var j = 0; j < params.length; ++j) {
+    var p = params[j];
+    if (p == key)
+      return true;
+    if (p.indexOf(key + "=") == 0)
+      return p.substring(key.length + 1);
+    if (p.indexOf("=") < 0 && key == "")
+      return p;
+  }
+  return false;
+}
+
+function handleRequest(request, response) {
+  try {
+    // Get the filename to send back.
+    var filename = parseQuery(request, "file");
+
+    const CC = Components.Constructor;
+    const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
+                                  "nsIBinaryOutputStream",
+                                  "setOutputStream");
+    var file = Components.classes["@mozilla.org/file/directory_service;1"].
+      getService(Components.interfaces.nsIProperties).
+      get("CurWorkD", Components.interfaces.nsILocalFile);
+    var fis  = Components.classes['@mozilla.org/network/file-input-stream;1'].
+      createInstance(Components.interfaces.nsIFileInputStream);
+    var bis  = Components.classes["@mozilla.org/binaryinputstream;1"].
+      createInstance(Components.interfaces.nsIBinaryInputStream);
+    var paths = "tests/content/media/test/" + filename;
+    dump(paths + '\n');
+    var split = paths.split("/");
+    for(var i = 0; i < split.length; ++i) {
+      file.append(split[i]);
+    }
+    fis.init(file, -1, -1, false);
+
+    // handle range requests
+    var partialstart = 0,
+        partialend = file.fileSize - 1;
+    if (request.hasHeader("Range")) {
+      var range = request.getHeader("Range");
+      var parts = range.replace(/bytes=/, "").split("-");
+      var partialstart = parts[0];
+      var partialend = parts[1];
+      if (!partialend.length) {
+        partialend = file.fileSize - 1;
+      }
+      response.setStatusLine(request.httpVersion, 206, "Partial Content");
+      var contentRange = "bytes " + partialstart + "-" + partialend + "/" + file.fileSize;
+      response.setHeader("Content-Range", contentRange);
+    }
+
+    fis.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, partialstart);
+    bis.setInputStream(fis);
+
+    var sendContentType = parseQuery(request, "nomime");
+    if (sendContentType == false) {
+      var contentType = parseQuery(request, "type");
+      if (contentType == false) {
+        // This should not happen.
+        dump("No type specified without having \'nomime\' in parameters.");
+        return;
+      }
+      response.setHeader("Content-Type", contentType, false);
+    }
+    response.setHeader("Content-Length", ""+bis.available(), false);
+
+    var bytes = bis.readBytes(bis.available());
+    response.write(bytes, bytes.length);
+  } catch (e) {
+    dump ("ERROR : " + e + "\n");
+  }
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bad506cf185478c9c903793d11d95f278148e007
GIT binary patch
literal 3530
zc%1E)X;f3!7RPUrOC|_J41)@iC__NRKoCK&2??_xA;cOhEf7R%D?|oc6(J$WJS!G;
zF)Nd`Dq<gXs0l#^0Tn4!ZEYc?3`Qk_(2@{xoAk+g>%G1Y@6-F#-&%X!efHhw-v9ru
zd(Jw6K2!vt1@##xkmI6F^t2IlB>pgm<?F0XaoPxvjz4@T);lTXU~&q_JD8y@8T_k!
zh<7BOv)7mXZmtW(*@eRl-Suxx{;>&3vCPnr5N&0hHn?0alOG=+n~?IZff)18p%aJA
z+^KEQY0^H26&n6-;Nr|-uyoTw-5obqtvsDt<NuKNryAgI{^oD~C!i(Py}uL#6AtjT
z7b9)x0|2HEFk8WC1>Y4uTp?wJf)(mlxV6IL6{c5!R?xo7BiK8{m+Iu<o&;;q$#Aj+
z00P|_4Aky8be#@a?$f`D{cnDd`!`0UlmRdm>CNXJZ0-Kh|Ha3>UA)%4Ub%p|?K(TZ
zqP5O4Xm#e;qC46`Z2=kz%0b#Ci9j>!F{gka@(eo4-NF!s$dHU3CgTABOE%F<R!-5<
z*8cjMdcSbM^*+@hT=8jig-{CP1A}-Zf<Dr{dB@2OFjDQ_L07j$5YhQN*cHX|=2p_)
z=$Q&7EMW$5tVKwUfjU;*NRs4o-AcPUqIpZu>;VII8M^E!zsjrzQrces<&o9tt3g7&
zO>6IOh`(h3EwS%`Lj4R(!JV%G=VRn6UPHwbRgi3-*Hl8rm1RS-nn4-YZEZS%*}21_
z?2ZidiyZE_y==DNME^OdeWZk1dH53RsLEn8{S)(ZJ?pt|)NMzEZ@65%lH~7GOF2RN
zg>}E%%i2!+d4X-BQhWP=(Q}A7WZ*&x``pNaBY)ROupgmm9>~BbBPWek%fnaC^V!0B
zMs;>L<QV#Ww&6_rgH6!d@1SQdp`R<{&9ejlKxRBgyi)Xj;x=o2$`gWecPI1YL;wS8
z%<?Mg@6;L61N2Xf9~-aSS(jFId0}<Fy_l86El>xUz^#kM8wQjet5EZ+L@u#!kqALH
z0^pOwtS+3Ehi!Ny@7{Rgir)k|D$+63IR7pgCqiww@R3O3?b*TejyZ3$OVmTC<(i3y
z8~`|wiiGbg=cU(XV@Mx<8~v&%^ZC>1VeY86qn)RmV7*%{GvBEyF7U~oH*i$E-INv-
z9jD4ghnD9}Qt-~kCw4QT#tND=!<avp2XzT8xuitRl304GDZ=$s0NjBA1NKCczeyV&
zcxR|8CN+!jfk&$CjMsO0M|15FB?}-`laF|HJh_)~nD8*6lZeB>dFm|8TRO{QIT+kF
z{rb1}EtqNCDJ2(TqJaH;Cgf7Lj(vtOCD@nFNr<D=7XVLg{&eqD$IC-(e<u<V4FF?p
zHlxK=TMwRm9{c4hd?93MP_Ya~Z`L%59&d))=Sn@*5^rDez^{CE7P@!Tphvm4_a_7l
zfhO*gv(MI?DZYB^TGW{2QD<$-V(vP4kf@I0LsJc8Zy=fwg#du3KO=cC-x*4zB~B2I
z%hD+d*H$BbRY|qf+5~dIZ4^ugk5>AuG8MFttFJD#Pg^5FyJ<)As6tt23CA8c?<Uv{
zcO^qSxG@sydf$%r>|BWcBcXS&vjevphp@KEsBO+vj+KEFMrK1G925QMJLV6EsBI<C
z(3(5tPeP~5O7>VLd1aJoXiDpn3ttK56LHEMyx?(<-ICQzj=6zi$rAFn8<6GTKaZrg
z-k)o$RI~(jT8^miL*w>_#fmPh=%jn<@r^<<?pj%(`<7#Fe;N|$x18ZO=BBPm`SSIR
zw!GE?OO&^4^5crjyb>4B^j+%@LSZ(VQ`uqOMuSs=L6DNI5*8viLoVVWA%k|tNN~2F
zR#*6tu}xmAfIi!!kT-8nt=S#B?LD{di!*OtApJ!Eg}|#zc;&uak~_WQB<eTX1U>3$
z&TN1IX&FxZC`4e14l3XeQU%finp`TxsM^XjQPQr{bLS*$XwJQiBOkMb673J}S*0p(
z^iyUMoPC?pCQM_*c^|BXTmrE8T7Uu|cY;j;KT&mtkN~#f)5OWj5ZNB58Fih}MI+1F
zUmXR%)P4p{zXv^*lD4QS5h8}wLl1GERI%(M7!b%=cwfN)?<OrULZQN#;)}kIi>Xp~
zv+ZBE1etHwM=cb1vN-15rAYvqm{Z(bIbPZM@Xdf&*`5126h=I)ma;yz(@3v{6~sZe
z1<h#h5lx0qap+u=vXC6pKHR|Bm|onYx<U5!`0;n1;L@I}FW<)+JKmcq0T*34C_tp$
zov{FT(|=dSj!%Y+=^=H?MlkqWS|4~opfhAB#K!J8s5R8#)4XLqIqz-{1CCqv_qn%D
z-8U+u`=a^74M~Cv?aF*foTr9uF{R02ioX?|42zrKTJ;I@n)K+z9yZo_ny$AY_*6JD
z*?-miIutZ6;kG@#%L$@tSV0&A&E)_av#aVRh%GFD*yXHtjdocKlS@0TRIP=6kaMWA
z86==RS*%@F{RnG!SA$Z}gf|Ev8A1SDbK)h9+e?GO;2=P!r?zkJi&IO=ffU*@0<_Z<
zKxDKnWG@tD)TlfnbcWUfSZCOg#^#V#9}=H(A-}q203@Rsw>qP894ZpYDX4KAVy2@$
z+N|G^fU@}Fy^FxPh)r45o#O)yV4YYaMH_o5RHaZ4oj`W<Q(0sZr3W=p9itlF*&=lx
zo(rS31c~3m46XO6I)EN-!0lNw8N?qAsEJB(ThotVY|T`GI4r~07TwrmpZ`o6u1}kQ
z9qxx7tVajlhR$yvRga~ILav>($=b!ztIHwURjxY!Fiusp6PI^(^zj2G?d_S+Wt?kn
zA*Qb|QfJ6kh?)5C*o|bN^UbebOxX?sPp5<cMu-Mrl<U~SV`maI{$YqO0=~i285=E1
zzU6?W#v558G_y<gV_%Jn{179{b21b5{La%Zl5(ix^4tsa*~Of2xy1<0>1&s=*M2Sg
zhaQ$)xvu!AbZI!@$-vH{)|U(Ik=wrC5qf}}79o3mw}FCWA(r+Det4SZiHTodmPoR>
zXNG#x+`JXW(t|}s;IfLv30q|OrjRDdyLl_J{!2*i5KnNt_CT;ir3#=ng5&M2(5o(e
zeT$!UhHNsi1}~gW%mXlzK@pu&4A`iHu%gRf#rl&-qHHAE-Tzp6kuEX!XV8`$u1k27
zV62IW3BlCV)Ck@|ijGb%-Ou6duC9xY=6Ct-UC`IpPvh0si&@v&1l&t2#~CNrOaBM{
E0HD#jxc~qF
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -151,16 +151,29 @@ var gPlayTests = [
   { name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
 
   { name:"gizmo.mp4", type:"video/mp4", duration:5.0 },
 
   // Invalid file
   { name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
 ];
 
+// A file for each type we can support.
+var gSnifferTests = [
+  { name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444 },
+  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942 },
+  { name:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
+  { name:"short.mp4", type:"video/mp4", duration:0.2, size:29435},
+  // A mp3 file without id3 tags.
+  { name:"notags.mp3", type:"audio/mpeg", duration:0.28, size:2506},
+  // A mp3 file with id3 tags.
+  { name:"id3tags.mp3", type:"audio/mpeg", duration:0.28, size:3530},
+  { name:"bogus.duh", type:"bogus/duh" }
+];
+
 // Converts a path/filename to a file:// URI which we can load from disk.
 // Optionally checks whether the file actually exists on disk at the location
 // we've specified.
 function fileUriToSrc(path, mustExist) {
   // android mochitest doesn't support file://
   if (navigator.appVersion.indexOf("Android") != -1)
     return path;
 
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f298131aa437897eb7ff41b64ddc452ec2a0ef8
GIT binary patch
literal 2506
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
H|AT)6tPzX8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0b9870bdcb500389b78a84e7feb6cce31fd828b4
GIT binary patch
literal 29435
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
MRG|T@ofi2215^f=E&u=k
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_media_sniffer.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Media test: mozStopDownload</title>
+  <meta charset='utf-8'>
+  <script type="text/javascript" src="/MochiKit/Base.js"></script>
+  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+  <script type="text/javascript" src="/MochiKit/Style.js"></script>
+  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+  <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" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function finish_test(element) {
+  if (element.parentNode)
+    element.parentNode.removeChild(element);
+  manager.finished(element.token);
+}
+
+function onApplicationOctetStreamLoaded(e) {
+  var t = e.target;
+  t.removeEventListener('loadedmetadata', onApplicationOctetStreamLoaded);
+  ok(true, "The media loads when served with application/octet-stream.");
+  finish_test(t);
+}
+
+function checkApplicationOctetStream(t) {
+  t.src = t.src.replace("&nomime", "&type=application/octet-stream");
+  t.addEventListener("loadedmetadata", onApplicationOctetStreamLoaded);
+}
+
+function onmetadataloaded(e) {
+  var t = e.target;
+  t.removeEventListener('loadedmetadata', onmetadataloaded)
+  ok(true, "The media loads when served without a Content-Type.");
+  checkApplicationOctetStream(t);
+}
+
+function onerror(e) {
+  var t = e.target;
+  t.removeEventListener('error', onerror);
+  ok(false, "The media could not be loaded." + t.src + "\n");
+  finish_test(t);
+}
+
+function startTest(test, token) {
+  var elemType = /^audio/.test(test.type) ? "audio" : "video";
+  var element = document.createElement(elemType);
+  // This .sjs file serve the media file without Content-Type header, or with a
+  // specific Content-Type header.
+  element.src = 'contentType.sjs?file=' + test.name + "&nomime";
+  element.token = token;
+  element.controls = true;
+  element.preload = "metadata";
+  document.body.appendChild(element);
+  manager.started(token);
+  element.addEventListener("loadedmetadata", onmetadataloaded);
+  element.addEventListener("error", onerror);
+}
+
+manager.runTests(gSnifferTests, startTest);
+</script>
+</pre>
+</body>
+</html>
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6659,36 +6659,27 @@ nsDocShell::EnsureContentViewer()
 {
     if (mContentViewer)
         return NS_OK;
     if (mIsBeingDestroyed)
         return NS_ERROR_FAILURE;
 
     NS_TIME_FUNCTION;
 
-    nsIPrincipal* principal = nullptr;
     nsCOMPtr<nsIURI> baseURI;
-
-    nsCOMPtr<nsPIDOMWindow> piDOMWindow(do_QueryInterface(mScriptGlobal));
-    if (piDOMWindow) {
-        principal = piDOMWindow->GetOpenerScriptPrincipal();
-    }
-
-    if (!principal) {
-        principal = GetInheritedPrincipal(false);
-        nsCOMPtr<nsIDocShellTreeItem> parentItem;
-        GetSameTypeParent(getter_AddRefs(parentItem));
-        if (parentItem) {
-            nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
-            if (domWin) {
-                nsCOMPtr<nsIContent> parentContent =
-                    do_QueryInterface(domWin->GetFrameElementInternal());
-                if (parentContent) {
-                    baseURI = parentContent->GetBaseURI();
-                }
+    nsIPrincipal* principal = GetInheritedPrincipal(false);
+    nsCOMPtr<nsIDocShellTreeItem> parentItem;
+    GetSameTypeParent(getter_AddRefs(parentItem));
+    if (parentItem) {
+        nsCOMPtr<nsPIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
+        if (domWin) {
+            nsCOMPtr<nsIContent> parentContent =
+                do_QueryInterface(domWin->GetFrameElementInternal());
+            if (parentContent) {
+                baseURI = parentContent->GetBaseURI();
             }
         }
     }
 
     nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
 
     if (NS_SUCCEEDED(rv)) {
         nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(this)));
--- a/docshell/base/nsIMarkupDocumentViewer.idl
+++ b/docshell/base/nsIMarkupDocumentViewer.idl
@@ -122,9 +122,17 @@ interface nsIMarkupDocumentViewer : nsIS
   attribute long minFontSize;
 
   /**
    * Append |this| and all of its descendants to the given array,
    * in depth-first pre-order traversal.
    */
   [noscript] void appendSubtree(in nsIMarkupDocumentViewerTArray array);
 
+  /**
+   * Set the maximum line width for the document.
+   * NOTE: This will generate a reflow!
+   *
+   * @param maxLineWidth The maximum width of any line boxes on the page,
+   *        in CSS pixels.
+   */
+  void changeMaxLineBoxWidth(in int32_t maxLineBoxWidth);
 };
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -39,16 +39,17 @@ PARALLEL_DIRS = \
   interfaces/smil \
   interfaces/apps \
   $(NULL)
 
 PARALLEL_DIRS += \
   apps \
   base \
   activities \
+  bindings \
   battery \
   browser-element \
   contacts \
   alarm \
   devicestorage \
   file \
   media \
   messages \
@@ -85,22 +86,16 @@ PARALLEL_DIRS += \
 endif
 
 ifdef MOZ_PAY
 PARALLEL_DIRS += \
   payment \
   $(NULL)
 endif
 
-# Not in PARALLEL_DIRS because we need to make sure it builds before
-# bindings/test, which builds from TEST_DIRS, which gets appended to DIRS.
-DIRS = \
-  bindings \
-  $(NULL)
-
 # bindings/test is here, because it needs to build after bindings/, and
 # we build subdirectories before ourselves.
 TEST_DIRS += \
   tests \
   imptests \
   bindings/test \
   $(NULL)
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -524,18 +524,18 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "BluetoothPropertyEvent.h"
 #endif
 
 #include "nsIDOMNavigatorSystemMessages.h"
 
 #include "mozilla/dom/Activity.h"
 
 #include "DOMCameraManager.h"
-#include "CameraControl.h"
-#include "CameraCapabilities.h"
+#include "DOMCameraControl.h"
+#include "DOMCameraCapabilities.h"
 
 #include "DOMError.h"
 #include "DOMRequest.h"
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 
 #include "DOMFileHandle.h"
 #include "FileRequest.h"
@@ -4634,17 +4634,18 @@ nsDOMClassInfo::Init()
   // Non-proxy bindings
   mozilla::dom::Register(nameSpaceManager);
 
   // This needs to happen after the call to mozilla::dom::Register, because we
   // overwrite some values.
   mozilla::dom::oldproxybindings::Register(nameSpaceManager);
 
   if (!AzureCanvasEnabled()) {
-    nameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING("CanvasRenderingContext2D"), NULL);
+    nameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING("CanvasRenderingContext2D"),
+                                                 nullptr, nullptr);
   }
 
   sIsInitialized = true;
 
   return NS_OK;
 }
 
 // static
@@ -6785,16 +6786,20 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     mozilla::dom::DefineInterface define =
       name_struct->mDefineDOMInterface;
     if (define) {
       if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
           !ConstructorEnabled(name_struct, aWin)) {
         return NS_OK;
       }
 
+      if (name_struct->mPrefEnabled && !(*name_struct->mPrefEnabled)()) {
+        return NS_OK;
+      }
+
       if (mozilla::dom::DefineConstructor(cx, obj, define, &rv)) {
         *did_resolve = NS_SUCCEEDED(rv);
 
         return rv;
       }
     }
   }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1261,17 +1261,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPerformance, nsPerformance)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolder)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOuterWindow)
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mListenerManager,
                                                   nsEventListenerManager)
 
   for (nsTimeout* timeout = tmp->FirstTimeout();
        tmp->IsTimeout(timeout);
        timeout = timeout->Next()) {
     cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
   }
@@ -1311,17 +1310,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPerformance)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolder)
   if (tmp->mOuterWindow) {
     static_cast<nsGlobalWindow*>(tmp->mOuterWindow.get())->MaybeClearInnerWindow(tmp);
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOuterWindow)
   }
 
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLocalStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplicationCache)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
@@ -1459,104 +1457,106 @@ nsGlobalWindow::GetGlobalJSObject()
 }
 
 bool
 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
 {
   // We reuse the inner window when:
   // a. We are currently at our original document.
   // b. At least one of the following conditions are true:
-  // -- We are not currently a content window (i.e., we're currently a chrome
-  //    window).
   // -- The new document is the same as the old document. This means that we're
   //    getting called from document.open().
   // -- The new document has the same origin as what we have loaded right now.
 
   if (!mDoc || !aNewDocument) {
     return false;
   }
 
   if (!mDoc->IsInitialDocument()) {
     return false;
   }
   
   NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
                "How'd this happen?");
-  
+
   // Great, we're the original document, check for one of the other
   // conditions.
+
   if (mDoc == aNewDocument) {
     return true;
   }
 
   bool equal;
   if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
                                                  &equal)) &&
       equal) {
     // The origin is the same.
     return true;
   }
 
-  nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
-
-  if (treeItem) {
-    int32_t itemType = nsIDocShellTreeItem::typeContent;
-    treeItem->GetItemType(&itemType);
-
-    // If we're a chrome window, then we want to reuse the inner window.
-    return itemType == nsIDocShellTreeItem::typeChrome;
-  }
-
-  // No treeItem: don't reuse the current inner window.
   return false;
 }
 
 void
-nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
-{
-  FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
-
+nsGlobalWindow::SetInitialPrincipalToSubject()
+{
+  FORWARD_TO_OUTER_VOID(SetInitialPrincipalToSubject, ());
+
+  // First, grab the subject principal. These methods never fail.
+  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+  nsCOMPtr<nsIPrincipal> newWindowPrincipal, systemPrincipal;
+  ssm->GetSubjectPrincipal(getter_AddRefs(newWindowPrincipal));
+  ssm->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
+  if (!newWindowPrincipal) {
+    newWindowPrincipal = systemPrincipal;
+  }
+
+  // Now, if we're about to use the system principal, make sure we're not using
+  // it for a content docshell.
+  if (newWindowPrincipal == systemPrincipal) {
+    int32_t itemType;
+    nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(GetDocShell());
+    nsresult rv = item->GetItemType(&itemType);
+    if (NS_FAILED(rv) || itemType != nsIDocShellTreeItem::typeChrome) {
+      newWindowPrincipal = nullptr;
+    }
+  }
+
+  // If there's an existing document, bail if it either:
   if (mDoc) {
-    if (!mDoc->IsInitialDocument()) {
-      // We have a document already, and it's not the original one.  Bail out.
-      // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
+    // (a) is not an initial about:blank document, or
+    if (!mDoc->IsInitialDocument())
       return;
-    }
+    // (b) already has the correct principal.
+    if (mDoc->NodePrincipal() == newWindowPrincipal)
+      return;
 
 #ifdef DEBUG
-    // We better have an about:blank document loaded at this point.  Otherwise,
-    // something is really weird.
+    // If we have a document loaded at this point, it had better be about:blank.
+    // Otherwise, something is really weird.
     nsCOMPtr<nsIURI> uri;
     mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
     NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
                  NS_IsAboutBlank(mDoc->GetDocumentURI()),
                  "Unexpected original document");
 #endif
-
-    GetDocShell()->CreateAboutBlankContentViewer(aPrincipal);
-    mDoc->SetIsInitialDocument(true);
-
-    nsCOMPtr<nsIPresShell> shell;
-    GetDocShell()->GetPresShell(getter_AddRefs(shell));
-
-    if (shell && !shell->DidInitialReflow()) {
-      // Ensure that if someone plays with this document they will get
-      // layout happening.
-      nsRect r = shell->GetPresContext()->GetVisibleArea();
-      shell->InitialReflow(r.width, r.height);
-    }
-  }
-}
-
-nsIPrincipal*
-nsGlobalWindow::GetOpenerScriptPrincipal()
-{
-  FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nullptr);
-
-  return mOpenerScriptPrincipal;
+  }
+
+  GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
+  mDoc->SetIsInitialDocument(true);
+
+  nsCOMPtr<nsIPresShell> shell;
+  GetDocShell()->GetPresShell(getter_AddRefs(shell));
+
+  if (shell && !shell->DidInitialReflow()) {
+    // Ensure that if someone plays with this document they will get
+    // layout happening.
+    nsRect r = shell->GetPresContext()->GetVisibleArea();
+    shell->InitialReflow(r.width, r.height);
+  }
 }
 
 PopupControlState
 PushPopupControlState(PopupControlState aState, bool aForce)
 {
   PopupControlState oldState = gPopupControlState;
 
   if (aState < gPopupControlState || aForce) {
@@ -1692,43 +1692,33 @@ nsGlobalWindow::SetOuterObject(JSContext
  * Create a new global object that will be used for an inner window.
  * Return the native global and an nsISupports 'holder' that can be used
  * to manage the lifetime of it.
  */
 static nsresult
 CreateNativeGlobalForInner(JSContext* aCx,
                            nsGlobalWindow* aNewInner,
                            nsIURI* aURI,
-                           bool aIsChrome,
                            nsIPrincipal* aPrincipal,
                            JSObject** aNativeGlobal,
                            nsIXPConnectJSObjectHolder** aHolder)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aNewInner);
   MOZ_ASSERT(aNewInner->IsInnerWindow());
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aNativeGlobal);
   MOZ_ASSERT(aHolder);
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
-  uint32_t flags = aIsChrome ? nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT : 0;
-
-  nsCOMPtr<nsIPrincipal> systemPrincipal;
-  if (aIsChrome) {
-    nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-    ssm->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
-    MOZ_ASSERT(systemPrincipal);
-  }
 
   nsRefPtr<nsIXPConnectJSObjectHolder> jsholder;
   nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
     aCx, static_cast<nsIScriptGlobalObject*>(aNewInner),
-    aIsChrome ? systemPrincipal.get() : aPrincipal, flags,
-    getter_AddRefs(jsholder));
+    aPrincipal, 0, getter_AddRefs(jsholder));
   NS_ENSURE_SUCCESS(rv, rv);
 
   MOZ_ASSERT(jsholder);
   jsholder->GetJSObject(aNativeGlobal);
   jsholder.forget(aHolder);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
@@ -1841,18 +1831,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     currentInner->mNavigator->OnNavigation();
   }
 
   nsRefPtr<nsGlobalWindow> newInnerWindow;
   bool createdInnerWindow = false;
 
   bool thisChrome = IsChromeWindow();
 
-  bool isChrome = false;
-
   nsCxPusher cxPusher;
   if (!cxPusher.Push(cx)) {
     return NS_ERROR_FAILURE;
   }
 
   XPCAutoRequest ar(cx);
 
   nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
@@ -1877,27 +1865,34 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       return NS_ERROR_FAILURE;
     }
 
     // Inner windows are only reused for same-origin principals, but the principals
     // don't necessarily match exactly. Update the principal on the compartment to
     // match the new document.
     // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
     // because we haven't yet set its mDoc to aDocument.
-    JS_SetCompartmentPrincipals(js::GetObjectCompartment(currentInner->mJSObject),
+    JSCompartment *compartment = js::GetObjectCompartment(currentInner->mJSObject);
+#ifdef DEBUG
+    bool sameOrigin = false;
+    nsIPrincipal *existing =
+      nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
+    aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
+    MOZ_ASSERT(sameOrigin);
+#endif
+    JS_SetCompartmentPrincipals(compartment,
                                 nsJSPrincipals::get(aDocument->NodePrincipal()));
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       mInnerWindowHolder = wsh->GetInnerWindowHolder();
 
       NS_ASSERTION(newInnerWindow, "Got a state without inner window");
     } else if (thisChrome) {
       newInnerWindow = new nsGlobalChromeWindow(this);
-      isChrome = true;
     } else if (mIsModalContentWindow) {
       newInnerWindow = new nsGlobalModalWindow(this);
     } else {
       newInnerWindow = new nsGlobalWindow(this);
     }
 
     if (!aState) {
       // Freeze the outer window and null out the inner window so
@@ -1912,17 +1907,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
       mInnerWindow = nullptr;
 
       Freeze();
       mCreatingInnerWindow = true;
       // Every script context we are initialized with must create a
       // new global.
       rv = CreateNativeGlobalForInner(cx, newInnerWindow,
-                                      aDocument->GetDocumentURI(), isChrome,
+                                      aDocument->GetDocumentURI(),
                                       aDocument->NodePrincipal(),
                                       &newInnerWindow->mJSObject,
                                       getter_AddRefs(mInnerWindowHolder));
       NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerWindow->mJSObject && mInnerWindowHolder,
                    "Failed to get script global and holder");
 
       mCreatingInnerWindow = false;
       createdInnerWindow = true;
@@ -2513,17 +2508,17 @@ nsGlobalWindow::PreHandleEvent(nsEventCh
 
 bool
 nsGlobalWindow::DialogsAreBlocked(bool *aBeingAbused)
 {
   *aBeingAbused = false;
 
   nsGlobalWindow *topWindow = GetScriptableTop();
   if (!topWindow) {
-    NS_ERROR("DialogsAreBlocked() called without a top window?");
+    NS_ASSERTION(!mDocShell, "DialogsAreBlocked() called without a top window?");
     return true;
   }
 
   topWindow = topWindow->GetCurrentInnerWindowInternal();
   if (!topWindow) {
     return true;
   }
 
@@ -7649,19 +7644,21 @@ nsGlobalWindow::ActivateOrDeactivate(boo
   } else {
     // This is a workaround for the following problem:
     // When a window with an open sheet loses focus, only the sheet window
     // receives the NS_DEACTIVATE event. However, it's not the sheet that
     // should lose the active styling, but the containing top level window.
 
     // widgetListener should be a nsXULWindow
     nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
-    nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
-    nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
-    topLevelWindow = do_GetInterface(req);
+    if (listener) {
+      nsCOMPtr<nsIXULWindow> window = listener->GetXULWindow();
+      nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
+      topLevelWindow = do_GetInterface(req);
+    }
   }
   if (topLevelWindow) {
     nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
     piWin->SetActive(aActivate);
   }
 }
 
 static bool
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -337,18 +337,17 @@ public:
 
   // nsPIDOMWindow
   virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
   virtual NS_HIDDEN_(void) ActivateOrDeactivate(bool aActivate);
   virtual NS_HIDDEN_(void) SetActive(bool aActive);
   virtual NS_HIDDEN_(void) SetIsBackground(bool aIsBackground);
   virtual NS_HIDDEN_(void) SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler);
 
-  virtual NS_HIDDEN_(void) SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal);
-  virtual NS_HIDDEN_(nsIPrincipal*) GetOpenerScriptPrincipal();
+  virtual NS_HIDDEN_(void) SetInitialPrincipalToSubject();
 
   virtual NS_HIDDEN_(PopupControlState) PushPopupControlState(PopupControlState state, bool aForce) const;
   virtual NS_HIDDEN_(void) PopPopupControlState(PopupControlState state) const;
   virtual NS_HIDDEN_(PopupControlState) GetPopupControlState() const;
 
   virtual NS_HIDDEN_(nsresult) SaveWindowState(nsISupports **aState);
   virtual NS_HIDDEN_(nsresult) RestoreWindowState(nsISupports *aState);
   virtual NS_HIDDEN_(void) SuspendTimeouts(uint32_t aIncrease = 1,
@@ -1009,18 +1008,16 @@ protected:
   nsGlobalWindowObserver*       mObserver;
 #ifndef MOZ_DISABLE_DOMCRYPTO
   nsCOMPtr<nsIDOMCrypto>        mCrypto;
 #endif
   nsCOMPtr<nsIDOMStorage>      mLocalStorage;
   nsCOMPtr<nsIDOMStorage>      mSessionStorage;
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
-  nsCOMPtr<nsIPrincipal> mOpenerScriptPrincipal; // strong; used to determine
-                                                 // whether to clear scope
 
   // These member variable are used only on inner windows.
   nsRefPtr<nsEventListenerManager> mListenerManager;
   // mTimeouts is generally sorted by mWhen, unless mTimeoutInsertionPoint is
   // non-null.  In that case, the dummy timeout pointed to by
   // mTimeoutInsertionPoint may have a later mWhen than some of the timeouts
   // that come after it.
   PRCList                       mTimeouts;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -43,18 +43,18 @@ class nsIDocument;
 class nsIScriptTimeoutHandler;
 struct nsTimeout;
 template <class> class nsScriptObjectHolder;
 class nsXBLPrototypeHandler;
 class nsIArray;
 class nsPIWindowRoot;
 
 #define NS_PIDOMWINDOW_IID \
-{0x66660102, 0xd875, 0x47e2, \
-  {0xa1, 0xf7, 0x12, 0xbc, 0x83, 0xc9, 0x93, 0xa9}}
+{ 0x0c5763c6, 0x5e87, 0x4f6f, \
+  { 0xa2, 0xef, 0xcf, 0x4d, 0xeb, 0xd1, 0xbc, 0xc3 } }
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -275,24 +275,19 @@ public:
       }
 
       win = this;
     }
 
     return win->mIsHandlingResizeEvent;
   }
 
-  // Tell this window who opened it.  This only has an effect if there is
-  // either no document currently in the window or if the document is the
-  // original document this window came with (an about:blank document either
-  // preloaded into it when it was created, or created by
-  // CreateAboutBlankContentViewer()).
-  virtual void SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal) = 0;
-  // Ask this window who opened it.
-  virtual nsIPrincipal* GetOpenerScriptPrincipal() = 0;
+  // Set the window up with an about:blank document with the current subject
+  // principal.
+  virtual void SetInitialPrincipalToSubject() = 0;
 
   virtual PopupControlState PushPopupControlState(PopupControlState aState,
                                                   bool aForce) const = 0;
   virtual void PopPopupControlState(PopupControlState state) const = 0;
   virtual PopupControlState GetPopupControlState() const = 0;
 
   // Returns an object containing the window's state.  This also suspends
   // all running timeouts in the window.
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -776,18 +776,20 @@ nsScriptNameSpaceManager::Observe(nsISup
   // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
   // See bug 600460.
 
   return NS_OK;
 }
 
 void
 nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::DefineInterface aDefineDOMInterface)
+    mozilla::dom::DefineInterface aDefineDOMInterface,
+    mozilla::dom::PrefEnabled aPrefEnabled)
 {
   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
   if (s) {
     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
     }
     s->mDefineDOMInterface = aDefineDOMInterface;
+    s->mPrefEnabled = aPrefEnabled;
   }
 }
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -63,16 +63,17 @@ struct nsGlobalNameStruct
     nsIID mIID; // eTypeInterface, eTypeClassProto
     nsExternalDOMClassInfoData* mData; // eTypeExternalClassInfo
     ConstructorAlias* mAlias; // eTypeExternalConstructorAlias
     nsCID mCID; // All other types except eTypeNewDOMBinding
   };
 
   // For new style DOM bindings.
   mozilla::dom::DefineInterface mDefineDOMInterface;
+  mozilla::dom::PrefEnabled mPrefEnabled; // May be null if not pref controlled
 
 private:
 
   // copy constructor
 };
 
 
 class nsIScriptContext;
@@ -134,17 +135,18 @@ public:
                              const nsIID **aInterfaces,
                              uint32_t aScriptableFlags,
                              bool aHasClassInterface,
                              const nsCID *aConstructorCID);
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
   void RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::DefineInterface aDefineDOMInterface);
+    mozilla::dom::DefineInterface aDefineDOMInterface,
+    mozilla::dom::PrefEnabled aPrefEnabled);
 
 private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
   nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey,
                                 const PRUnichar **aClassName = nullptr);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -291,29 +291,27 @@ DOMInterfaces = {
 'OnlyForUseInConstructor' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
 
 'TestIndexedGetterInterface' : {
         'headerFile': 'TestBindingHeader.h',
-        'register': False,
-        'infallible': [ 'length' ]
+        'register': False
         },
 
 'TestNamedGetterInterface' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
 'TestIndexedAndNamedGetterInterface' : {
         'headerFile': 'TestBindingHeader.h',
-        'register': False,
-        'infallible': [ 'length' ]
+        'register': False
         },
 
 'TestIndexedSetterInterface' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
 'TestNamedSetterInterface' : {
@@ -324,17 +322,16 @@ DOMInterfaces = {
 'TestIndexedAndNamedSetterInterface' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
 'TestIndexedAndNamedGetterAndSetterInterface' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False,
-        'infallible': [ 'length', '__stringifier' ],
         'binaryNames': { '__stringifier': 'Stringify' }
         },
 }
 
 # These are temporary, until they've been converted to use new DOM bindings
 def addExternalIface(iface, nativeType=None, headerFile=None):
     domInterface = {
         'concrete': False
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1333,16 +1333,34 @@ class CGDefineDOMInterfaceMethod(CGAbstr
             getter = "GetConstructorObject"
 
         return ("  JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
                 CheckPref(self.descriptor, "global", "*aEnabled", "false") + 
                 """
   *aEnabled = true;
   return !!%s(aCx, global, aReceiver);""" % (getter))
 
+class CGPrefEnabled(CGAbstractMethod):
+    """
+    A method for testing whether the preference controlling this
+    interface is enabled.  When it's not, the interface should not be
+    visible on the global.
+    """
+    def __init__(self, descriptor):
+        CGAbstractMethod.__init__(self, descriptor, 'PrefEnabled', 'bool', [])
+
+    def declare(self):
+        return CGAbstractMethod.declare(self)
+
+    def define(self):
+        return CGAbstractMethod.define(self)
+
+    def definition_body(self):
+        return "  return %s::PrefEnabled();" % self.descriptor.nativeType
+
 class CGIsMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         args = [Argument('JSObject*', 'obj')]
         CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
 
     def definition_body(self):
         # Non-proxy implementation would check
         #   js::GetObjectJSClass(obj) == &Class.mBase
@@ -2833,22 +2851,27 @@ def getRetvalDeclarationForType(returnTy
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
 class CGCallGenerator(CGThing):
     """
     A class to generate an actual call to a C++ object.  Assumes that the C++
     object is stored in a variable whose name is given by the |object| argument.
+
+    errorReport should be a CGThing for an error report or None if no
+    error reporting is needed.
     """
     def __init__(self, errorReport, arguments, argsPre, returnType,
                  extendedAttributes, descriptorProvider, nativeMethodName,
                  static, object="self", declareResult=True):
         CGThing.__init__(self)
 
+        assert errorReport is None or isinstance(errorReport, CGThing)
+
         isFallible = errorReport is not None
 
         resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
                                                         extendedAttributes)
         (result, resultOutParam) = getRetvalDeclarationForType(returnType,
                                                                descriptorProvider,
                                                                resultAlreadyAddRefed)
 
@@ -2968,18 +2991,21 @@ class CGPerSignatureCall(CGThing):
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
     def wrap_return_value(self):
         isCreator = memberIsCreator(self.idlNode)
         if isCreator:
             # We better be returning addrefed things!
-            assert isResultAlreadyAddRefed(self.descriptor,
-                                           self.extendedAttributes)
+            assert(isResultAlreadyAddRefed(self.descriptor,
+                                           self.extendedAttributes) or
+                   # Workers use raw pointers for new-object return
+                   # values or something
+                   self.descriptor.workers)
 
         resultTemplateValues = { 'jsvalRef': '*vp', 'jsvalPtr': 'vp',
                                  'isCreator': isCreator}
         try:
             return wrapForType(self.returnType, self.descriptor,
                                resultTemplateValues)
         except MethodNotCreatorError, err:
             assert not isCreator
@@ -4820,18 +4846,19 @@ class CGDOMJSProxyHandler_obj_toString(C
         if stringifier:
             name = stringifier.identifier.name
             nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
             signature = stringifier.signatures()[0]
             returnType = signature[0]
             extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
             infallible = 'infallible' in extendedAttributes
             if not infallible:
-                error = ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString")\n' +
-                         "return NULL;") % self.descriptor.interface.identifier.name
+                error = CGGeneric(
+                    ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString");\n' +
+                     "return NULL;") % self.descriptor.interface.identifier.name)
             else:
                 error = None
             call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
             return call.define() + """
 
 JSString* jsresult;
 return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;""" 
 
@@ -4985,16 +5012,21 @@ class CGDescriptor(CGThing):
             if descriptor.concrete and descriptor.proxy:
                 cgThings.append(CGResolveOwnProperty(descriptor))
                 cgThings.append(CGEnumerateOwnProperties(descriptor))
             cgThings.append(CGResolveProperty(descriptor, properties))
             cgThings.append(CGEnumerateProperties(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
+            if (not descriptor.interface.isExternal() and
+                # Workers stuff is never pref-controlled
+                not descriptor.workers and
+                descriptor.interface.getExtendedAttribute("PrefControlled") is not None):
+                cgThings.append(CGPrefEnabled(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGNativePropertyHooks(descriptor))
 
         if descriptor.concrete:
             if descriptor.proxy:
                 cgThings.append(CGProxyIsProxy(descriptor))
                 cgThings.append(CGProxyUnwrap(descriptor))
@@ -5108,19 +5140,20 @@ class CGDictionary(CGThing):
         return (string.Template(
                 "struct ${selfName} ${inheritance}{\n"
                 "  ${selfName}() {}\n"
                 "  bool Init(JSContext* cx, const JS::Value& val);\n"
                 "\n" +
                 "\n".join(memberDecls) + "\n"
                 "private:\n"
                 "  // Disallow copy-construction\n"
-                "  ${selfName}(const ${selfName}&) MOZ_DELETE;\n"
-                "  static bool InitIds(JSContext* cx);\n"
-                "  static bool initedIds;\n" +
+                "  ${selfName}(const ${selfName}&) MOZ_DELETE;\n" +
+                # NOTE: jsids are per-runtime, so don't use them in workers
+                ("  static bool InitIds(JSContext* cx);\n"
+                 "  static bool initedIds;\n" if not self.workers else "") +
                 "\n".join("  static jsid " +
                           self.makeIdName(m.identifier.name) + ";" for
                           m in d.members) + "\n"
                 "};").substitute( { "selfName": self.makeClassName(d),
                                     "inheritance": inheritance }))
 
     def define(self):
         if not self.generatable:
@@ -5142,36 +5175,38 @@ class CGDictionary(CGThing):
         idinit = CGList(idinit, " ||\n")
         idinit = CGWrapper(idinit, pre="if (",
                            post=(") {\n"
                                  "  return false;\n"
                                  "}"),
                            reindent=True)
 
         return string.Template(
-            "bool ${selfName}::initedIds = false;\n" +
-            "\n".join("jsid ${selfName}::%s = JSID_VOID;" %
-                      self.makeIdName(m.identifier.name)
-                      for m in d.members) + "\n"
-            "\n"
-            "bool\n"
-            "${selfName}::InitIds(JSContext* cx)\n"
-            "{\n"
-            "  MOZ_ASSERT(!initedIds);\n"
-            "${idInit}\n"
-            "  initedIds = true;\n"
-            "  return true;\n"
-            "}\n"
-            "\n"
+            # NOTE: jsids are per-runtime, so don't use them in workers
+            ("bool ${selfName}::initedIds = false;\n" +
+             "\n".join("jsid ${selfName}::%s = JSID_VOID;" %
+                       self.makeIdName(m.identifier.name)
+                       for m in d.members) + "\n"
+             "\n"
+             "bool\n"
+             "${selfName}::InitIds(JSContext* cx)\n"
+             "{\n"
+             "  MOZ_ASSERT(!initedIds);\n"
+             "${idInit}\n"
+             "  initedIds = true;\n"
+             "  return true;\n"
+             "}\n"
+             "\n" if not self.workers else "") +
             "bool\n"
             "${selfName}::Init(JSContext* cx, const JS::Value& val)\n"
-            "{\n"
-            "  if (!initedIds && !InitIds(cx)) {\n"
-            "    return false;\n"
-            "  }\n"
+            "{\n" +
+            # NOTE: jsids are per-runtime, so don't use them in workers
+            ("  if (!initedIds && !InitIds(cx)) {\n"
+             "    return false;\n"
+             "  }\n" if not self.workers else "") +
             "${initParent}"
             "  JSBool found;\n"
             "  JS::Value temp;\n"
             "  bool isNull = val.isNullOrUndefined();\n"
             "  if (!isNull && !val.isObject()) {\n"
             "    return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
             "  }\n"
             "\n"
@@ -5221,39 +5256,54 @@ class CGDictionary(CGThing):
                          "holderName": "holder"}
         # We can't handle having a holderType here
         assert holderType is None
         if dealWithOptional:
             replacements["declName"] = "(" + replacements["declName"] + ".Value())"
         if member.defaultValue:
             replacements["haveValue"] = "found"
 
+        # NOTE: jsids are per-runtime, so don't use them in workers
+        if self.workers:
+            propName = member.identifier.name
+            propCheck = ('JS_HasProperty(cx, &val.toObject(), "%s", &found)' %
+                         propName)
+            propGet = ('JS_GetProperty(cx, &val.toObject(), "%s", &temp)' %
+                       propName)
+        else:
+            propId = self.makeIdName(member.identifier.name);
+            propCheck = ("JS_HasPropertyById(cx, &val.toObject(), %s, &found)" %
+                         propId)
+            propGet = ("JS_GetPropertyById(cx, &val.toObject(), %s, &temp)" %
+                       propId)
+
         conversionReplacements = {
-            "propId" : self.makeIdName(member.identifier.name),
             "prop": "(this->%s)" % member.identifier.name,
-            "convert": string.Template(templateBody).substitute(replacements)
+            "convert": string.Template(templateBody).substitute(replacements),
+            "propCheck": propCheck,
+            "propGet": propGet
             }
         conversion = ("if (isNull) {\n"
                       "  found = false;\n"
-                      "} else if (!JS_HasPropertyById(cx, &val.toObject(), ${propId}, &found)) {\n"
+                      "} else if (!${propCheck}) {\n"
                       "  return false;\n"
                       "}\n")
         if member.defaultValue:
             conversion += (
                 "if (found) {\n"
-                "  if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
+                "  if (!${propGet}) {\n"
                 "    return false;\n"
                 "  }\n"
                 "}\n"
                 "${convert}")
         else:
             conversion += (
                 "if (found) {\n"
                 "  ${prop}.Construct();\n"
-                "  if (!JS_GetPropertyById(cx, &val.toObject(), ${propId}, &temp)) {\n"
+                "  if (!${propGet}) {\n"
                 "    return false;\n"
                 "  }\n"
                 "${convert}\n"
                 "}")
             conversionReplacements["convert"] = CGIndenter(
                 CGGeneric(conversionReplacements["convert"])).define()
         
         return CGGeneric(
@@ -5278,22 +5328,26 @@ class CGDictionary(CGThing):
 class CGRegisterProtos(CGAbstractMethod):
     def __init__(self, config):
         CGAbstractMethod.__init__(self, None, 'Register', 'void',
                                   [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
         self.config = config
 
     def _defineMacro(self):
        return """
-#define REGISTER_PROTO(_dom_class) \\
-  aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface);\n\n"""
+#define REGISTER_PROTO(_dom_class, _pref_check) \\
+  aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface, _pref_check);\n\n"""
     def _undefineMacro(self):
         return "\n#undef REGISTER_PROTO"
     def _registerProtos(self):
-        lines = ["REGISTER_PROTO(%s);" % desc.name
+        def getPrefCheck(desc):
+            if desc.interface.getExtendedAttribute("PrefControlled") is None:
+                return "nullptr"
+            return "%sBinding::PrefEnabled" % desc.name
+        lines = ["REGISTER_PROTO(%s, %s);" % (desc.name, getPrefCheck(desc))
                  for desc in self.config.getDescriptors(hasInterfaceObject=True,
                                                         isExternal=False,
                                                         workers=False,
                                                         register=True)]
         return '\n'.join(lines) + '\n'
     def definition_body(self):
         return self._defineMacro() + self._registerProtos() + self._undefineMacro()
 
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -260,17 +260,17 @@ class Descriptor(DescriptorProvider):
                 if config == '*':
                     iface = self.interface
                     while iface:
                         add('all', map(lambda m: m.name, iface.members), attribute)
                         iface = iface.parent
                 else:
                     add('all', [config], attribute)
 
-        for attribute in ['infallible', 'implicitJSContext', 'resultNotAddRefed']:
+        for attribute in ['implicitJSContext', 'resultNotAddRefed']:
             addExtendedAttribute(attribute, desc.get(attribute, {}))
 
         self.binaryNames = desc.get('binaryNames', {})
 
         # Build the prototype chain.
         self.prototypeChain = []
         parent = interface
         while parent:
@@ -285,43 +285,39 @@ class Descriptor(DescriptorProvider):
         # interface prototype object as they're going to use QI (on main thread)
         # or be passed as a JSObject (on worker threads).
         if self.interface.isExternal():
             return False
 
         return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject()
 
     def getExtendedAttributes(self, member, getter=False, setter=False):
-        def ensureValidInfallibleExtendedAttribute(attr):
+        def ensureValidThrowsExtendedAttribute(attr):
             assert(attr is None or attr is True or len(attr) == 1)
             if (attr is not None and attr is not True and
                 'Workers' not in attr and 'MainThread' not in attr):
-                raise TypeError("Unknown value for 'infallible': " + attr[0])
+                raise TypeError("Unknown value for 'Throws': " + attr[0])
+
+        def maybeAppendInfallibleToAttrs(attrs, throws):
+            ensureValidThrowsExtendedAttribute(throws)
+            if (throws is None or
+                (throws is not True and
+                 ('Workers' not in throws or not self.workers) and
+                 ('MainThread' not in throws or self.workers))):
+                attrs.append("infallible")
 
         name = member.identifier.name
         if member.isMethod():
             attrs = self.extendedAttributes['all'].get(name, [])
-            infallible = member.getExtendedAttribute("Infallible")
-            ensureValidInfallibleExtendedAttribute(infallible)
-            if (infallible is not None and
-                (infallible is True or
-                 ('Workers' in infallible and self.workers) or
-                 ('MainThread' in infallible and not self.workers))):
-                attrs.append("infallible")
+            throws = member.getExtendedAttribute("Throws")
+            maybeAppendInfallibleToAttrs(attrs, throws)
             return attrs
 
         assert member.isAttr()
         assert bool(getter) != bool(setter)
         key = 'getterOnly' if getter else 'setterOnly'
         attrs = self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, [])
-        infallible = member.getExtendedAttribute("Infallible")
-        if infallible is None:
-            infallibleAttr = "GetterInfallible" if getter else "SetterInfallible"
-            infallible = member.getExtendedAttribute(infallibleAttr)
-
-        ensureValidInfallibleExtendedAttribute(infallible)
-        if (infallible is not None and
-            (infallible is True or
-             ('Workers' in infallible and self.workers) or
-             ('MainThread' in infallible and not self.workers))):
-            attrs.append("infallible")
-
+        throws = member.getExtendedAttribute("Throws")
+        if throws is None:
+            throwsAttr = "GetterThrows" if getter else "SetterThrows"
+            throws = member.getExtendedAttribute(throwsAttr)
+        maybeAppendInfallibleToAttrs(attrs, throws)
         return attrs
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -3,17 +3,17 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
 import string
 
 propList = eval(sys.stdin.read())
 props = ""
 for [prop, pref] in propList:
-    extendedAttrs = ["TreatNullAs=EmptyString"]
+    extendedAttrs = ["Throws", "TreatNullAs=EmptyString"]
     if pref is not "":
         extendedAttrs.append("Pref=%s" % pref)
     if not prop.startswith("Moz"):
         prop = prop[0].lower() + prop[1:]
     # Unfortunately, even some of the getters here are fallible
     # (e.g. on nsComputedDOMStyle).
     props += "  [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
                                                    prop)
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -671,19 +671,21 @@ class IDLInterface(IDLObjectWithScope):
                 args = attrlist[0] if len(attrlist) else []
 
                 retType = IDLWrapperType(self.location, self)
                 
                 identifier = IDLUnresolvedIdentifier(self.location, "constructor",
                                                      allowForbidden=True)
 
                 method = IDLMethod(self.location, identifier, retType, args)
-                # Constructors are always Creators and never have any
-                # other extended attributes.
-                method.addExtendedAttributes(["Creator"])
+                # Constructors are always Creators and are always
+                # assumed to be able to throw (since there's no way to
+                # indicate otherwise) and never have any other
+                # extended attributes.
+                method.addExtendedAttributes([("Creator",), ("Throws",)])
                 method.resolve(self)
 
             self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
 
     def addImplementedInterface(self, implementedInterface):
         assert(isinstance(implementedInterface, IDLInterface))
         self.implementedInterfaces.add(implementedInterface)
 
@@ -731,16 +733,19 @@ class IDLInterface(IDLObjectWithScope):
         if otherInterface in self.implementedInterfaces:
             return self
         for iface in self.implementedInterfaces:
             loopPoint = iface.findInterfaceLoopPoint(otherInterface)
             if loopPoint:
                 return loopPoint
         return None
 
+    def getExtendedAttribute(self, name):
+        return self._extendedAttrDict.get(name, None)
+
 class IDLDictionary(IDLObjectWithScope):
     def __init__(self, location, parentScope, name, parent, members):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
         assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
 
         self.parent = parent
         self._finished = False
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -45,19 +45,19 @@ class IndirectlyImplementedInterface : p
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_INDIRECTLY_IMPLEMENTED_INTERFACE_IID)
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  bool GetIndirectlyImplementedProperty(ErrorResult&);
-  void SetIndirectlyImplementedProperty(bool, ErrorResult&);
-  void IndirectlyImplementedMethod(ErrorResult&);
+  bool GetIndirectlyImplementedProperty();
+  void SetIndirectlyImplementedProperty(bool);
+  void IndirectlyImplementedMethod();
 };
 
 // IID for the TestExternalInterface
 #define NS_TEST_EXTERNAL_INTERFACE_IID \
 { 0xd5ba0c99, 0x9b1d, 0x4e71, \
  { 0x8a, 0x94, 0x56, 0x38, 0x6c, 0xa3, 0xda, 0x3d } }
 class TestExternalInterface : public nsISupports
 {
@@ -123,539 +123,513 @@ public:
   /*  static
   already_AddRefed<TestInterface> Constructor(nsISupports*,
                                               uint32_t, uint32_t,
                                               const TestInterfaceOrOnlyForUseInConstructor&,
                                               ErrorResult&);
   */
   
   // Integer types
-  int8_t GetReadonlyByte(ErrorResult&);
-  int8_t GetWritableByte(ErrorResult&);
-  void SetWritableByte(int8_t, ErrorResult&);
-  void PassByte(int8_t, ErrorResult&);
-  int8_t ReceiveByte(ErrorResult&);
-  void PassOptionalByte(const Optional<int8_t>&, ErrorResult&);
-  void PassOptionalByteWithDefault(int8_t, ErrorResult&);
-  void PassNullableByte(Nullable<int8_t>&, ErrorResult&);
-  void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&,
-                                ErrorResult&);
+  int8_t GetReadonlyByte();
+  int8_t GetWritableByte();
+  void SetWritableByte(int8_t);
+  void PassByte(int8_t);
+  int8_t ReceiveByte();
+  void PassOptionalByte(const Optional<int8_t>&);
+  void PassOptionalByteWithDefault(int8_t);
+  void PassNullableByte(Nullable<int8_t>&);
+  void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
 
-  int16_t GetReadonlyShort(ErrorResult&);
-  int16_t GetWritableShort(ErrorResult&);
-  void SetWritableShort(int16_t, ErrorResult&);
-  void PassShort(int16_t, ErrorResult&);
-  int16_t ReceiveShort(ErrorResult&);
-  void PassOptionalShort(const Optional<int16_t>&, ErrorResult&);
-  void PassOptionalShortWithDefault(int16_t, ErrorResult&);
+  int16_t GetReadonlyShort();
+  int16_t GetWritableShort();
+  void SetWritableShort(int16_t);
+  void PassShort(int16_t);
+  int16_t ReceiveShort();
+  void PassOptionalShort(const Optional<int16_t>&);
+  void PassOptionalShortWithDefault(int16_t);
 
-  int32_t GetReadonlyLong(ErrorResult&);
-  int32_t GetWritableLong(ErrorResult&);
-  void SetWritableLong(int32_t, ErrorResult&);
-  void PassLong(int32_t, ErrorResult&);
-  int16_t ReceiveLong(ErrorResult&);
-  void PassOptionalLong(const Optional<int32_t>&, ErrorResult&);
-  void PassOptionalLongWithDefault(int32_t, ErrorResult&);
+  int32_t GetReadonlyLong();
+  int32_t GetWritableLong();
+  void SetWritableLong(int32_t);
+  void PassLong(int32_t);
+  int16_t ReceiveLong();
+  void PassOptionalLong(const Optional<int32_t>&);
+  void PassOptionalLongWithDefault(int32_t);
 
-  int64_t GetReadonlyLongLong(ErrorResult&);
-  int64_t GetWritableLongLong(ErrorResult&);
-  void SetWritableLongLong(int64_t, ErrorResult&);
-  void PassLongLong(int64_t, ErrorResult&);
-  int64_t ReceiveLongLong(ErrorResult&);
-  void PassOptionalLongLong(const Optional<int64_t>&, ErrorResult&);
-  void PassOptionalLongLongWithDefault(int64_t, ErrorResult&);
+  int64_t GetReadonlyLongLong();
+  int64_t GetWritableLongLong();
+  void SetWritableLongLong(int64_t);
+  void PassLongLong(int64_t);
+  int64_t ReceiveLongLong();
+  void PassOptionalLongLong(const Optional<int64_t>&);
+  void PassOptionalLongLongWithDefault(int64_t);
 
-  uint8_t GetReadonlyOctet(ErrorResult&);
-  uint8_t GetWritableOctet(ErrorResult&);
-  void SetWritableOctet(uint8_t, ErrorResult&);
-  void PassOctet(uint8_t, ErrorResult&);
-  uint8_t ReceiveOctet(ErrorResult&);
-  void PassOptionalOctet(const Optional<uint8_t>&, ErrorResult&);
-  void PassOptionalOctetWithDefault(uint8_t, ErrorResult&);
+  uint8_t GetReadonlyOctet();
+  uint8_t GetWritableOctet();
+  void SetWritableOctet(uint8_t);
+  void PassOctet(uint8_t);
+  uint8_t ReceiveOctet();
+  void PassOptionalOctet(const Optional<uint8_t>&);
+  void PassOptionalOctetWithDefault(uint8_t);
 
-  uint16_t GetReadonlyUnsignedShort(ErrorResult&);
-  uint16_t GetWritableUnsignedShort(ErrorResult&);
-  void SetWritableUnsignedShort(uint16_t, ErrorResult&);
-  void PassUnsignedShort(uint16_t, ErrorResult&);
-  uint16_t ReceiveUnsignedShort(ErrorResult&);
-  void PassOptionalUnsignedShort(const Optional<uint16_t>&, ErrorResult&);
-  void PassOptionalUnsignedShortWithDefault(uint16_t, ErrorResult&);
+  uint16_t GetReadonlyUnsignedShort();
+  uint16_t GetWritableUnsignedShort();
+  void SetWritableUnsignedShort(uint16_t);
+  void PassUnsignedShort(uint16_t);
+  uint16_t ReceiveUnsignedShort();
+  void PassOptionalUnsignedShort(const Optional<uint16_t>&);
+  void PassOptionalUnsignedShortWithDefault(uint16_t);
 
-  uint32_t GetReadonlyUnsignedLong(ErrorResult&);
-  uint32_t GetWritableUnsignedLong(ErrorResult&);
-  void SetWritableUnsignedLong(uint32_t, ErrorResult&);
-  void PassUnsignedLong(uint32_t, ErrorResult&);
-  uint32_t ReceiveUnsignedLong(ErrorResult&);
-  void PassOptionalUnsignedLong(const Optional<uint32_t>&, ErrorResult&);
-  void PassOptionalUnsignedLongWithDefault(uint32_t, ErrorResult&);
+  uint32_t GetReadonlyUnsignedLong();
+  uint32_t GetWritableUnsignedLong();
+  void SetWritableUnsignedLong(uint32_t);
+  void PassUnsignedLong(uint32_t);
+  uint32_t ReceiveUnsignedLong();
+  void PassOptionalUnsignedLong(const Optional<uint32_t>&);
+  void PassOptionalUnsignedLongWithDefault(uint32_t);
 
-  uint64_t GetReadonlyUnsignedLongLong(ErrorResult&);
-  uint64_t GetWritableUnsignedLongLong(ErrorResult&);
-  void SetWritableUnsignedLongLong(uint64_t, ErrorResult&);
-  void PassUnsignedLongLong(uint64_t, ErrorResult&);
-  uint64_t ReceiveUnsignedLongLong(ErrorResult&);
-  void PassOptionalUnsignedLongLong(const Optional<uint64_t>&, ErrorResult&);
-  void PassOptionalUnsignedLongLongWithDefault(uint64_t, ErrorResult&);
+  uint64_t GetReadonlyUnsignedLongLong();
+  uint64_t GetWritableUnsignedLongLong();
+  void SetWritableUnsignedLongLong(uint64_t);
+  void PassUnsignedLongLong(uint64_t);
+  uint64_t ReceiveUnsignedLongLong();
+  void PassOptionalUnsignedLongLong(const Optional<uint64_t>&);
+  void PassOptionalUnsignedLongLongWithDefault(uint64_t);
 
   // Interface types
-  already_AddRefed<TestInterface> ReceiveSelf(ErrorResult&);
-  already_AddRefed<TestInterface> ReceiveNullableSelf(ErrorResult&);
-  TestInterface* ReceiveWeakSelf(ErrorResult&);
-  TestInterface* ReceiveWeakNullableSelf(ErrorResult&);
-  void PassSelf(TestInterface&, ErrorResult&);
-  void PassSelf2(NonNull<TestInterface>&, ErrorResult&);
-  void PassNullableSelf(TestInterface*, ErrorResult&);
-  already_AddRefed<TestInterface> GetNonNullSelf(ErrorResult&);
-  void SetNonNullSelf(TestInterface&, ErrorResult&);
-  already_AddRefed<TestInterface> GetNullableSelf(ErrorResult&);
-  void SetNullableSelf(TestInterface*, ErrorResult&);
-  void PassOptionalSelf(const Optional<TestInterface*> &, ErrorResult&);
-  void PassOptionalNonNullSelf(const Optional<NonNull<TestInterface> >&, ErrorResult&);
-  void PassOptionalSelfWithDefault(TestInterface*, ErrorResult&);
+  already_AddRefed<TestInterface> ReceiveSelf();
+  already_AddRefed<TestInterface> ReceiveNullableSelf();
+  TestInterface* ReceiveWeakSelf();
+  TestInterface* ReceiveWeakNullableSelf();
+  void PassSelf(TestInterface&);
+  void PassSelf2(NonNull<TestInterface>&);
+  void PassNullableSelf(TestInterface*);
+  already_AddRefed<TestInterface> GetNonNullSelf();
+  void SetNonNullSelf(TestInterface&);
+  already_AddRefed<TestInterface> GetNullableSelf();
+  void SetNullableSelf(TestInterface*);
+  void PassOptionalSelf(const Optional<TestInterface*> &);
+  void PassOptionalNonNullSelf(const Optional<NonNull<TestInterface> >&);
+  void PassOptionalSelfWithDefault(TestInterface*);
 
-  already_AddRefed<TestNonWrapperCacheInterface> ReceiveNonWrapperCacheInterface(ErrorResult&);
-  already_AddRefed<TestNonWrapperCacheInterface> ReceiveNullableNonWrapperCacheInterface(ErrorResult&);
-  void ReceiveNonWrapperCacheInterfaceSequence(nsTArray<nsRefPtr<TestNonWrapperCacheInterface> >&, ErrorResult&);
-  void ReceiveNullableNonWrapperCacheInterfaceSequence(nsTArray<nsRefPtr<TestNonWrapperCacheInterface> >&, ErrorResult&);
-  void ReceiveNonWrapperCacheInterfaceNullableSequence(Nullable<nsTArray<nsRefPtr<TestNonWrapperCacheInterface> > >&, ErrorResult&);
-  void ReceiveNullableNonWrapperCacheInterfaceNullableSequence(Nullable<nsTArray<nsRefPtr<TestNonWrapperCacheInterface> > >&, ErrorResult&);
+  already_AddRefed<TestNonWrapperCacheInterface> ReceiveNonWrapperCacheInterface();
+  already_AddRefed<TestNonWrapperCacheInterface> ReceiveNullableNonWrapperCacheInterface();
+  void ReceiveNonWrapperCacheInterfaceSequence(nsTArray<nsRefPtr<TestNonWrapperCacheInterface> >&);
+  void ReceiveNullableNonWrapperCacheInterfaceSequence(nsTArray<nsRefPtr<TestNonWrapperCacheInterface> >&);
+  void ReceiveNonWrapperCacheInterfaceNullableSequence(Nullable<nsTArray<nsRefPtr<TestNonWrapperCacheInterface> > >&);
+  void ReceiveNullableNonWrapperCacheInterfaceNullableSequence(Nullable<nsTArray<nsRefPtr<TestNonWrapperCacheInterface> > >&);
 
-  already_AddRefed<TestNonCastableInterface> ReceiveOther(ErrorResult&);
-  already_AddRefed<TestNonCastableInterface> ReceiveNullableOther(ErrorResult&);
-  TestNonCastableInterface* ReceiveWeakOther(ErrorResult&);
-  TestNonCastableInterface* ReceiveWeakNullableOther(ErrorResult&);
-  void PassOther(TestNonCastableInterface&, ErrorResult&);
-  void PassOther2(NonNull<TestNonCastableInterface>&, ErrorResult&);
-  void PassNullableOther(TestNonCastableInterface*, ErrorResult&);
-  already_AddRefed<TestNonCastableInterface> GetNonNullOther(ErrorResult&);
-  void SetNonNullOther(TestNonCastableInterface&, ErrorResult&);
-  already_AddRefed<TestNonCastableInterface> GetNullableOther(ErrorResult&);
-  void SetNullableOther(TestNonCastableInterface*, ErrorResult&);
-  void PassOptionalOther(const Optional<TestNonCastableInterface*>&, ErrorResult&);
-  void PassOptionalNonNullOther(const Optional<NonNull<TestNonCastableInterface> >&, ErrorResult&);
-  void PassOptionalOtherWithDefault(TestNonCastableInterface*, ErrorResult&);
+  already_AddRefed<TestNonCastableInterface> ReceiveOther();
+  already_AddRefed<TestNonCastableInterface> ReceiveNullableOther();
+  TestNonCastableInterface* ReceiveWeakOther();
+  TestNonCastableInterface* ReceiveWeakNullableOther();
+  void PassOther(TestNonCastableInterface&);
+  void PassOther2(NonNull<TestNonCastableInterface>&);
+  void PassNullableOther(TestNonCastableInterface*);
+  already_AddRefed<TestNonCastableInterface> GetNonNullOther();
+  void SetNonNullOther(TestNonCastableInterface&);
+  already_AddRefed<TestNonCastableInterface> GetNullableOther();
+  void SetNullableOther(TestNonCastableInterface*);
+  void PassOptionalOther(const Optional<TestNonCastableInterface*>&);
+  void PassOptionalNonNullOther(const Optional<NonNull<TestNonCastableInterface> >&);
+  void PassOptionalOtherWithDefault(TestNonCastableInterface*);
 
-  already_AddRefed<TestExternalInterface> ReceiveExternal(ErrorResult&);
-  already_AddRefed<TestExternalInterface> ReceiveNullableExternal(ErrorResult&);
-  TestExternalInterface* ReceiveWeakExternal(ErrorResult&);
-  TestExternalInterface* ReceiveWeakNullableExternal(ErrorResult&);
-  void PassExternal(TestExternalInterface*, ErrorResult&);
-  void PassExternal2(TestExternalInterface*, ErrorResult&);
-  void PassNullableExternal(TestExternalInterface*, ErrorResult&);
-  already_AddRefed<TestExternalInterface> GetNonNullExternal(ErrorResult&);
-  void SetNonNullExternal(TestExternalInterface*, ErrorResult&);
-  already_AddRefed<TestExternalInterface> GetNullableExternal(ErrorResult&);
-  void SetNullableExternal(TestExternalInterface*, ErrorResult&);
-  void PassOptionalExternal(const Optional<TestExternalInterface*>&, ErrorResult&);
-  void PassOptionalNonNullExternal(const Optional<TestExternalInterface*>&, ErrorResult&);
-  void PassOptionalExternalWithDefault(TestExternalInterface*, ErrorResult&);
+  already_AddRefed<TestExternalInterface> ReceiveExternal();
+  already_AddRefed<TestExternalInterface> ReceiveNullableExternal();
+  TestExternalInterface* ReceiveWeakExternal();
+  TestExternalInterface* ReceiveWeakNullableExternal();
+  void PassExternal(TestExternalInterface*);
+  void PassExternal2(TestExternalInterface*);
+  void PassNullableExternal(TestExternalInterface*);
+  already_AddRefed<TestExternalInterface> GetNonNullExternal();
+  void SetNonNullExternal(TestExternalInterface*);
+  already_AddRefed<TestExternalInterface> GetNullableExternal();
+  void SetNullableExternal(TestExternalInterface*);
+  void PassOptionalExternal(const Optional<TestExternalInterface*>&);
+  void PassOptionalNonNullExternal(const Optional<TestExternalInterface*>&);
+  void PassOptionalExternalWithDefault(TestExternalInterface*);
 
-  already_AddRefed<TestCallbackInterface> ReceiveCallbackInterface(ErrorResult&);
-  already_AddRefed<TestCallbackInterface> ReceiveNullableCallbackInterface(ErrorResult&);
-  TestCallbackInterface* ReceiveWeakCallbackInterface(ErrorResult&);
-  TestCallbackInterface* ReceiveWeakNullableCallbackInterface(ErrorResult&);
-  void PassCallbackInterface(TestCallbackInterface&, ErrorResult&);
-  void PassCallbackInterface2(OwningNonNull<TestCallbackInterface>, ErrorResult&);
-  void PassNullableCallbackInterface(TestCallbackInterface*, ErrorResult&);
-  already_AddRefed<TestCallbackInterface> GetNonNullCallbackInterface(ErrorResult&);
-  void SetNonNullCallbackInterface(TestCallbackInterface&, ErrorResult&);
-  already_AddRefed<TestCallbackInterface> GetNullableCallbackInterface(ErrorResult&);
-  void SetNullableCallbackInterface(TestCallbackInterface*, ErrorResult&);
-  void PassOptionalCallbackInterface(const Optional<nsRefPtr<TestCallbackInterface> >&, ErrorResult&);
-  void PassOptionalNonNullCallbackInterface(const Optional<OwningNonNull<TestCallbackInterface> >&, ErrorResult&);
-  void PassOptionalCallbackInterfaceWithDefault(TestCallbackInterface*, ErrorResult&);
+  already_AddRefed<TestCallbackInterface> ReceiveCallbackInterface();
+  already_AddRefed<TestCallbackInterface> ReceiveNullableCallbackInterface();
+  TestCallbackInterface* ReceiveWeakCallbackInterface();
+  TestCallbackInterface* ReceiveWeakNullableCallbackInterface();
+  void PassCallbackInterface(TestCallbackInterface&);
+  void PassCallbackInterface2(OwningNonNull<TestCallbackInterface>);
+  void PassNullableCallbackInterface(TestCallbackInterface*);
+  already_AddRefed<TestCallbackInterface> GetNonNullCallbackInterface();
+  void SetNonNullCallbackInterface(TestCallbackInterface&);
+  already_AddRefed<TestCallbackInterface> GetNullableCallbackInterface();
+  void SetNullableCallbackInterface(TestCallbackInterface*);
+  void PassOptionalCallbackInterface(const Optional<nsRefPtr<TestCallbackInterface> >&);
+  void PassOptionalNonNullCallbackInterface(const Optional<OwningNonNull<TestCallbackInterface> >&);
+  void PassOptionalCallbackInterfaceWithDefault(TestCallbackInterface*);
 
-  already_AddRefed<IndirectlyImplementedInterface> ReceiveConsequentialInterface(ErrorResult&);
-  void PassConsequentialInterface(IndirectlyImplementedInterface&, ErrorResult&);
+  already_AddRefed<IndirectlyImplementedInterface> ReceiveConsequentialInterface();
+  void PassConsequentialInterface(IndirectlyImplementedInterface&);
 
   // Sequence types
-  void ReceiveSequence(nsTArray<int32_t>&, ErrorResult&);
-  void ReceiveNullableSequence(Nullable< nsTArray<int32_t> >&, ErrorResult&);
-  void ReceiveSequenceOfNullableInts(nsTArray< Nullable<int32_t> >&, ErrorResult&);
-  void ReceiveNullableSequenceOfNullableInts(Nullable< nsTArray< Nullable<int32_t> > >&, ErrorResult&);
-  void PassSequence(const Sequence<int32_t> &, ErrorResult&);
-  void PassNullableSequence(const Nullable< Sequence<int32_t> >&, ErrorResult&);
-  void PassSequenceOfNullableInts(const Sequence<Nullable<int32_t> >&, ErrorResult&);
-  void PassOptionalSequenceOfNullableInts(const Optional<Sequence<Nullable<int32_t> > > &,
-                                          ErrorResult&);
-  void PassOptionalNullableSequenceOfNullableInts(const Optional<Nullable<Sequence<Nullable<int32_t> > > > &,
-                                                  ErrorResult&);
-  void ReceiveCastableObjectSequence(nsTArray< nsRefPtr<TestInterface> > &,
-                                     ErrorResult&);
-  void ReceiveNullableCastableObjectSequence(nsTArray< nsRefPtr<TestInterface> > &,
-                                             ErrorResult&);
-  void ReceiveCastableObjectNullableSequence(Nullable< nsTArray< nsRefPtr<TestInterface> > >&,
-                                             ErrorResult&);
-  void ReceiveNullableCastableObjectNullableSequence(Nullable< nsTArray< nsRefPtr<TestInterface> > >&,
-                                             ErrorResult&);
-  void ReceiveWeakCastableObjectSequence(nsTArray<TestInterface*> &,
-                                         ErrorResult&);
-  void ReceiveWeakNullableCastableObjectSequence(nsTArray<TestInterface*> &,
-                                                 ErrorResult&);
-  void ReceiveWeakCastableObjectNullableSequence(Nullable< nsTArray<TestInterface*> >&,
-                                                 ErrorResult&);
-  void ReceiveWeakNullableCastableObjectNullableSequence(Nullable< nsTArray<TestInterface*> >&,
-                                                         ErrorResult&);
-  void PassCastableObjectSequence(const Sequence< OwningNonNull<TestInterface> >&,
-                                  ErrorResult&);
-  void PassNullableCastableObjectSequence(const Sequence< nsRefPtr<TestInterface> > &,
-                                          ErrorResult&);
-  void PassCastableObjectNullableSequence(const Nullable< Sequence< OwningNonNull<TestInterface> > >&,
-                                          ErrorResult&);
-  void PassNullableCastableObjectNullableSequence(const Nullable< Sequence< nsRefPtr<TestInterface> > >&,
-                                                  ErrorResult&);
-  void PassOptionalSequence(const Optional<Sequence<int32_t> >&,
-                            ErrorResult&);
-  void PassOptionalNullableSequence(const Optional<Nullable<Sequence<int32_t> > >&,
-                                    ErrorResult&);
-  void PassOptionalNullableSequenceWithDefaultValue(const Nullable< Sequence<int32_t> >&,
-                                                    ErrorResult&);
-  void PassOptionalObjectSequence(const Optional<Sequence<OwningNonNull<TestInterface> > >&,
-                                  ErrorResult&);
+  void ReceiveSequence(nsTArray<int32_t>&);
+  void ReceiveNullableSequence(Nullable< nsTArray<int32_t> >&);
+  void ReceiveSequenceOfNullableInts(nsTArray< Nullable<int32_t> >&);
+  void ReceiveNullableSequenceOfNullableInts(Nullable< nsTArray< Nullable<int32_t> > >&);
+  void PassSequence(const Sequence<int32_t> &);
+  void PassNullableSequence(const Nullable< Sequence<int32_t> >&);
+  void PassSequenceOfNullableInts(const Sequence<Nullable<int32_t> >&);
+  void PassOptionalSequenceOfNullableInts(const Optional<Sequence<Nullable<int32_t> > > &);
+  void PassOptionalNullableSequenceOfNullableInts(const Optional<Nullable<Sequence<Nullable<int32_t> > > > &);
+  void ReceiveCastableObjectSequence(nsTArray< nsRefPtr<TestInterface> > &);
+  void ReceiveNullableCastableObjectSequence(nsTArray< nsRefPtr<TestInterface> > &);
+  void ReceiveCastableObjectNullableSequence(Nullable< nsTArray< nsRefPtr<TestInterface> > >&);
+  void ReceiveNullableCastableObjectNullableSequence(Nullable< nsTArray< nsRefPtr<TestInterface> > >&);
+  void ReceiveWeakCastableObjectSequence(nsTArray<TestInterface*> &);
+  void ReceiveWeakNullableCastableObjectSequence(nsTArray<TestInterface*> &);
+  void ReceiveWeakCastableObjectNullableSequence(Nullable< nsTArray<TestInterface*> >&);
+  void ReceiveWeakNullableCastableObjectNullableSequence(Nullable< nsTArray<TestInterface*> >&);
+  void PassCastableObjectSequence(const Sequence< OwningNonNull<TestInterface> >&);
+  void PassNullableCastableObjectSequence(const Sequence< nsRefPtr<TestInterface> > &);
+  void PassCastableObjectNullableSequence(const Nullable< Sequence< OwningNonNull<TestInterface> > >&);
+  void PassNullableCastableObjectNullableSequence(const Nullable< Sequence< nsRefPtr<TestInterface> > >&);
+  void PassOptionalSequence(const Optional<Sequence<int32_t> >&);
+  void PassOptionalNullableSequence(const Optional<Nullable<Sequence<int32_t> > >&);
+  void PassOptionalNullableSequenceWithDefaultValue(const Nullable< Sequence<int32_t> >&);
+  void PassOptionalObjectSequence(const Optional<Sequence<OwningNonNull<TestInterface> > >&);
 
-  void ReceiveStringSequence(nsTArray<nsString>&, ErrorResult&);
-  void PassStringSequence(const Sequence<nsString>&, ErrorResult&);
+  void ReceiveStringSequence(nsTArray<nsString>&);
+  void PassStringSequence(const Sequence<nsString>&);
 
   // Typed array types
-  void PassArrayBuffer(ArrayBuffer&, ErrorResult&);
-  void PassNullableArrayBuffer(ArrayBuffer*, ErrorResult&);
-  void PassOptionalArrayBuffer(const Optional<ArrayBuffer>&, ErrorResult&);
-  void PassOptionalNullableArrayBuffer(const Optional<ArrayBuffer*>&, ErrorResult&);
-  void PassOptionalNullableArrayBufferWithDefaultValue(ArrayBuffer*, ErrorResult&);
-  void PassArrayBufferView(ArrayBufferView&, ErrorResult&);
-  void PassInt8Array(Int8Array&, ErrorResult&);
-  void PassInt16Array(Int16Array&, ErrorResult&);
-  void PassInt32Array(Int32Array&, ErrorResult&);
-  void PassUint8Array(Uint8Array&, ErrorResult&);
-  void PassUint16Array(Uint16Array&, ErrorResult&);
-  void PassUint32Array(Uint32Array&, ErrorResult&);
-  void PassUint8ClampedArray(Uint8ClampedArray&, ErrorResult&);
-  void PassFloat32Array(Float32Array&, ErrorResult&);
-  void PassFloat64Array(Float64Array&, ErrorResult&);
-  JSObject* ReceiveUint8Array(ErrorResult&);
+  void PassArrayBuffer(ArrayBuffer&);
+  void PassNullableArrayBuffer(ArrayBuffer*);
+  void PassOptionalArrayBuffer(const Optional<ArrayBuffer>&);
+  void PassOptionalNullableArrayBuffer(const Optional<ArrayBuffer*>&);
+  void PassOptionalNullableArrayBufferWithDefaultValue(ArrayBuffer*);
+  void PassArrayBufferView(ArrayBufferView&);
+  void PassInt8Array(Int8Array&);
+  void PassInt16Array(Int16Array&);
+  void PassInt32Array(Int32Array&);
+  void PassUint8Array(Uint8Array&);
+  void PassUint16Array(Uint16Array&);
+  void PassUint32Array(Uint32Array&);
+  void PassUint8ClampedArray(Uint8ClampedArray&);
+  void PassFloat32Array(Float32Array&);
+  void PassFloat64Array(Float64Array&);
+  JSObject* ReceiveUint8Array();
 
   // String types
-  void PassString(const nsAString&, ErrorResult&);
-  void PassNullableString(const nsAString&, ErrorResult&);
-  void PassOptionalString(const Optional<nsAString>&, ErrorResult&);
-  void PassOptionalStringWithDefaultValue(const nsAString&, ErrorResult&);
-  void PassOptionalNullableString(const Optional<nsAString>&, ErrorResult&);
-  void PassOptionalNullableStringWithDefaultValue(const nsAString&, ErrorResult&);
+  void PassString(const nsAString&);
+  void PassNullableString(const nsAString&);
+  void PassOptionalString(const Optional<nsAString>&);
+  void PassOptionalStringWithDefaultValue(const nsAString&);
+  void PassOptionalNullableString(const Optional<nsAString>&);
+  void PassOptionalNullableStringWithDefaultValue(const nsAString&);
 
   // Enumarated types
-  void PassEnum(TestEnum, ErrorResult&);
-  void PassOptionalEnum(const Optional<TestEnum>&, ErrorResult&);
-  void PassEnumWithDefault(TestEnum, ErrorResult&);
-  TestEnum ReceiveEnum(ErrorResult&);
-  TestEnum GetEnumAttribute(ErrorResult&);
-  TestEnum GetReadonlyEnumAttribute(ErrorResult&);
-  void SetEnumAttribute(TestEnum, ErrorResult&);
+  void PassEnum(TestEnum);
+  void PassOptionalEnum(const Optional<TestEnum>&);
+  void PassEnumWithDefault(TestEnum);
+  TestEnum ReceiveEnum();
+  TestEnum GetEnumAttribute();
+  TestEnum GetReadonlyEnumAttribute();
+  void SetEnumAttribute(TestEnum);
 
   // Callback types
-  void PassCallback(JSContext*, JSObject*, ErrorResult&);
-  void PassNullableCallback(JSContext*, JSObject*, ErrorResult&);
-  void PassOptionalCallback(JSContext*, const Optional<JSObject*>&,
-                            ErrorResult&);
-  void PassOptionalNullableCallback(JSContext*, const Optional<JSObject*>&,
-                                    ErrorResult&);
-  void PassOptionalNullableCallbackWithDefaultValue(JSContext*, JSObject*,
-                                                    ErrorResult&);
-  JSObject* ReceiveCallback(JSContext*, ErrorResult&);
-  JSObject* ReceiveNullableCallback(JSContext*, ErrorResult&);
+  void PassCallback(JSContext*, JSObject*);
+  void PassNullableCallback(JSContext*, JSObject*);
+  void PassOptionalCallback(JSContext*, const Optional<JSObject*>&);
+  void PassOptionalNullableCallback(JSContext*, const Optional<JSObject*>&);
+  void PassOptionalNullableCallbackWithDefaultValue(JSContext*, JSObject*);
+  JSObject* ReceiveCallback(JSContext*);
+  JSObject* ReceiveNullableCallback(JSContext*);
 
   // Any types
-  void PassAny(JSContext*, JS::Value, ErrorResult&);
-  void PassOptionalAny(JSContext*, const Optional<JS::Value>&, ErrorResult&);
-  void PassAnyDefaultNull(JSContext*, JS::Value, ErrorResult&);
-  JS::Value ReceiveAny(JSContext*, ErrorResult&);
+  void PassAny(JSContext*, JS::Value);
+  void PassOptionalAny(JSContext*, const Optional<JS::Value>&);
+  void PassAnyDefaultNull(JSContext*, JS::Value);
+  JS::Value ReceiveAny(JSContext*);
 
   // object types
-  void PassObject(JSContext*, JSObject&, ErrorResult&);
-  void PassNullableObject(JSContext*, JSObject*, ErrorResult&);
-  void PassOptionalObject(JSContext*, const Optional<NonNull<JSObject> >&, ErrorResult&);
-  void PassOptionalNullableObject(JSContext*, const Optional<JSObject*>&, ErrorResult&);
-  void PassOptionalNullableObjectWithDefaultValue(JSContext*, JSObject*, ErrorResult&);
-  JSObject* ReceiveObject(JSContext*, ErrorResult&);
-  JSObject* ReceiveNullableObject(JSContext*, ErrorResult&);
+  void PassObject(JSContext*, JSObject&);
+  void PassNullableObject(JSContext*, JSObject*);
+  void PassOptionalObject(JSContext*, const Optional<NonNull<JSObject> >&);
+  void PassOptionalNullableObject(JSContext*, const Optional<JSObject*>&);
+  void PassOptionalNullableObjectWithDefaultValue(JSContext*, JSObject*);
+  JSObject* ReceiveObject(JSContext*);
+  JSObject* ReceiveNullableObject(JSContext*);
 
   // Union types
-  void PassUnion(JSContext*, const ObjectOrLong& arg, ErrorResult&);
-  void PassUnionWithNullable(JSContext*, const ObjectOrNullOrLong& arg, ErrorResult&)
+  void PassUnion(JSContext*, const ObjectOrLong& arg);
+  void PassUnionWithNullable(JSContext*, const ObjectOrNullOrLong& arg)
   {
     ObjectOrLong returnValue;
     if (arg.IsNull()) {
     } else if (arg.IsObject()) {
       JSObject& obj = (JSObject&)arg.GetAsObject();
       JS_GetClass(&obj);
       //returnValue.SetAsObject(&obj);
     } else {
       int32_t i = arg.GetAsLong();
       i += 1;
     }
   }
-  void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&, ErrorResult&);
-  void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&, ErrorResult&);
-  void PassOptionalNullableUnion(JSContext*, const Optional<Nullable<ObjectOrLong> >&, ErrorResult&);
-  void PassOptionalNullableUnionWithDefaultValue(JSContext*, const Nullable<ObjectOrLong>&, ErrorResult&);
-  //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg, ErrorResult&);
-  //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg, ErrorResult&);
-  void PassUnionWithArrayBuffer(const ArrayBufferOrLong&, ErrorResult&);
-  void PassUnionWithString(JSContext*, const StringOrObject&, ErrorResult&);
-  //void PassUnionWithEnum(JSContext*, const TestEnumOrObject&, ErrorResult&);
-  void PassUnionWithCallback(JSContext*, const TestCallbackOrLong&, ErrorResult&);
-  void PassUnionWithObject(JSContext*, const ObjectOrLong&, ErrorResult&);
+  void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
+  void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&);
+  void PassOptionalNullableUnion(JSContext*, const Optional<Nullable<ObjectOrLong> >&);
+  void PassOptionalNullableUnionWithDefaultValue(JSContext*, const Nullable<ObjectOrLong>&);
+  //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg);
+  //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg);
+  void PassUnionWithArrayBuffer(const ArrayBufferOrLong&);
+  void PassUnionWithString(JSContext*, const StringOrObject&);
+  //void PassUnionWithEnum(JSContext*, const TestEnumOrObject&);
+  void PassUnionWithCallback(JSContext*, const TestCallbackOrLong&);
+  void PassUnionWithObject(JSContext*, const ObjectOrLong&);
 
   // binaryNames tests
-  void MethodRenamedTo(ErrorResult&);
-  void MethodRenamedTo(int8_t, ErrorResult&);
-  int8_t GetAttributeGetterRenamedTo(ErrorResult&);
-  int8_t GetAttributeRenamedTo(ErrorResult&);
-  void SetAttributeRenamedTo(int8_t, ErrorResult&);
+  void MethodRenamedTo();
+  void MethodRenamedTo(int8_t);
+  int8_t GetAttributeGetterRenamedTo();
+  int8_t GetAttributeRenamedTo();
+  void SetAttributeRenamedTo(int8_t);
 
   // Dictionary tests
-  void PassDictionary(const Dict&, ErrorResult&);
-  void PassOtherDictionary(const GrandparentDict&, ErrorResult&);
-  void PassSequenceOfDictionaries(const Sequence<Dict>&, ErrorResult&);
-  void PassDictionaryOrLong(const Dict&, ErrorResult&);
-  void PassDictionaryOrLong(int32_t, ErrorResult&);
-  void PassDictContainingDict(const DictContainingDict&, ErrorResult&);
+  void PassDictionary(const Dict&);
+  void PassOtherDictionary(const GrandparentDict&);
+  void PassSequenceOfDictionaries(const Sequence<Dict>&);
+  void PassDictionaryOrLong(const Dict&);
+  void PassDictionaryOrLong(int32_t);
+  void PassDictContainingDict(const DictContainingDict&);
 
   // Methods and properties imported via "implements"
-  bool GetImplementedProperty(ErrorResult&);
-  void SetImplementedProperty(bool, ErrorResult&);
-  void ImplementedMethod(ErrorResult&);
-  bool GetImplementedParentProperty(ErrorResult&);
-  void SetImplementedParentProperty(bool, ErrorResult&);
-  void ImplementedParentMethod(ErrorResult&);
-  bool GetIndirectlyImplementedProperty(ErrorResult&);
-  void SetIndirectlyImplementedProperty(bool, ErrorResult&);
-  void IndirectlyImplementedMethod(ErrorResult&);
-  uint32_t GetDiamondImplementedProperty(ErrorResult&);
+  bool GetImplementedProperty();
+  void SetImplementedProperty(bool);
+  void ImplementedMethod();
+  bool GetImplementedParentProperty();
+  void SetImplementedParentProperty(bool);
+  void ImplementedParentMethod();
+  bool GetIndirectlyImplementedProperty();
+  void SetIndirectlyImplementedProperty(bool);
+  void IndirectlyImplementedMethod();
+  uint32_t GetDiamondImplementedProperty();
 
 private:
   // We add signatures here that _could_ start matching if the codegen
   // got data types wrong.  That way if it ever does we'll have a call
   // to these private deleted methods and compilation will fail.
-  void SetReadonlyByte(int8_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyByte(int8_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableByte(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableByte(T) MOZ_DELETE;
   template<typename T>
-  void PassByte(T, ErrorResult&) MOZ_DELETE;
+  void PassByte(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalByte(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalByte(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalByteWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalByteWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyShort(int16_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyShort(int16_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableShort(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableShort(T) MOZ_DELETE;
   template<typename T>
-  void PassShort(T, ErrorResult&) MOZ_DELETE;
+  void PassShort(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalShort(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalShort(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalShortWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalShortWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyLong(int32_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyLong(int32_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableLong(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableLong(T) MOZ_DELETE;
   template<typename T>
-  void PassLong(T, ErrorResult&) MOZ_DELETE;
+  void PassLong(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalLong(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalLong(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalLongWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalLongWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyLongLong(int64_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyLongLong(int64_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableLongLong(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableLongLong(T) MOZ_DELETE;
   template<typename T>
-  void PassLongLong(T, ErrorResult&) MOZ_DELETE;
+  void PassLongLong(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalLongLong(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalLongLong(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalLongLongWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalLongLongWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyOctet(uint8_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyOctet(uint8_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableOctet(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableOctet(T) MOZ_DELETE;
   template<typename T>
-  void PassOctet(T, ErrorResult&) MOZ_DELETE;
+  void PassOctet(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalOctet(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalOctet(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalOctetWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalOctetWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyUnsignedShort(uint16_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyUnsignedShort(uint16_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableUnsignedShort(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableUnsignedShort(T) MOZ_DELETE;
   template<typename T>
-  void PassUnsignedShort(T, ErrorResult&) MOZ_DELETE;
+  void PassUnsignedShort(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalUnsignedShort(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalUnsignedShort(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalUnsignedShortWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalUnsignedShortWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyUnsignedLong(uint32_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyUnsignedLong(uint32_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableUnsignedLong(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableUnsignedLong(T) MOZ_DELETE;
   template<typename T>
-  void PassUnsignedLong(T, ErrorResult&) MOZ_DELETE;
+  void PassUnsignedLong(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalUnsignedLong(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalUnsignedLong(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalUnsignedLongWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalUnsignedLongWithDefault(T) MOZ_DELETE;
 
-  void SetReadonlyUnsignedLongLong(uint64_t, ErrorResult&) MOZ_DELETE;
+  void SetReadonlyUnsignedLongLong(uint64_t) MOZ_DELETE;
   template<typename T>
-  void SetWritableUnsignedLongLong(T, ErrorResult&) MOZ_DELETE;
+  void SetWritableUnsignedLongLong(T) MOZ_DELETE;
   template<typename T>
-  void PassUnsignedLongLong(T, ErrorResult&) MOZ_DELETE;
+  void PassUnsignedLongLong(T) MOZ_DELETE;
   template<typename T>
-  void PassOptionalUnsignedLongLong(const Optional<T>&, ErrorResult&) MOZ_DELETE;
+  void PassOptionalUnsignedLongLong(const Optional<T>&) MOZ_DELETE;
   template<typename T>
-  void PassOptionalUnsignedLongLongWithDefault(T, ErrorResult&) MOZ_DELETE;
+  void PassOptionalUnsignedLongLongWithDefault(T) MOZ_DELETE;
 
   // Enforce that only const things are passed for sequences
-  void PassSequence(Sequence<int32_t> &, ErrorResult&) MOZ_DELETE;
-  void PassNullableSequence(Nullable< Sequence<int32_t> >&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableSequenceWithDefaultValue(Nullable< Sequence<int32_t> >&,
-                                                    ErrorResult&) MOZ_DELETE;
+  void PassSequence(Sequence<int32_t> &) MOZ_DELETE;
+  void PassNullableSequence(Nullable< Sequence<int32_t> >&) MOZ_DELETE;
+  void PassOptionalNullableSequenceWithDefaultValue(Nullable< Sequence<int32_t> >&) MOZ_DELETE;
 
   // Enforce that only const things are passed for optional
-  void PassOptionalByte(Optional<int8_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableByte(Optional<Nullable<int8_t> >&,
-                                ErrorResult&) MOZ_DELETE;
-  void PassOptionalShort(Optional<int16_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalLong(Optional<int32_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalLongLong(Optional<int64_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalOctet(Optional<uint8_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalUnsignedShort(Optional<uint16_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalUnsignedLong(Optional<uint32_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalUnsignedLongLong(Optional<uint64_t>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalSelf(Optional<TestInterface*> &, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNonNullSelf(Optional<NonNull<TestInterface> >&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalOther(Optional<TestNonCastableInterface*>&, ErrorResult&);
-  void PassOptionalNonNullOther(Optional<NonNull<TestNonCastableInterface> >&, ErrorResult&);
-  void PassOptionalExternal(Optional<TestExternalInterface*>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNonNullExternal(Optional<TestExternalInterface*>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalSequence(Optional<Sequence<int32_t> >&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableSequence(Optional<Nullable<Sequence<int32_t> > >&,
-                                    ErrorResult&) MOZ_DELETE;
-  void PassOptionalObjectSequence(Optional<Sequence<OwningNonNull<TestInterface> > >&,
-                                  ErrorResult&) MOZ_DELETE;
-  void PassOptionalArrayBuffer(Optional<ArrayBuffer>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableArrayBuffer(Optional<ArrayBuffer*>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalEnum(Optional<TestEnum>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalCallback(JSContext*, Optional<JSObject*>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableCallback(JSContext*, Optional<JSObject*>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalAny(Optional<JS::Value>&, ErrorResult) MOZ_DELETE;
+  void PassOptionalByte(Optional<int8_t>&) MOZ_DELETE;
+  void PassOptionalNullableByte(Optional<Nullable<int8_t> >&) MOZ_DELETE;
+  void PassOptionalShort(Optional<int16_t>&) MOZ_DELETE;
+  void PassOptionalLong(Optional<int32_t>&) MOZ_DELETE;
+  void PassOptionalLongLong(Optional<int64_t>&) MOZ_DELETE;
+  void PassOptionalOctet(Optional<uint8_t>&) MOZ_DELETE;
+  void PassOptionalUnsignedShort(Optional<uint16_t>&) MOZ_DELETE;
+  void PassOptionalUnsignedLong(Optional<uint32_t>&) MOZ_DELETE;
+  void PassOptionalUnsignedLongLong(Optional<uint64_t>&) MOZ_DELETE;
+  void PassOptionalSelf(Optional<TestInterface*> &) MOZ_DELETE;
+  void PassOptionalNonNullSelf(Optional<NonNull<TestInterface> >&) MOZ_DELETE;
+  void PassOptionalOther(Optional<TestNonCastableInterface*>&);
+  void PassOptionalNonNullOther(Optional<NonNull<TestNonCastableInterface> >&);
+  void PassOptionalExternal(Optional<TestExternalInterface*>&) MOZ_DELETE;
+  void PassOptionalNonNullExternal(Optional<TestExternalInterface*>&) MOZ_DELETE;
+  void PassOptionalSequence(Optional<Sequence<int32_t> >&) MOZ_DELETE;
+  void PassOptionalNullableSequence(Optional<Nullable<Sequence<int32_t> > >&) MOZ_DELETE;
+  void PassOptionalObjectSequence(Optional<Sequence<OwningNonNull<TestInterface> > >&) MOZ_DELETE;
+  void PassOptionalArrayBuffer(Optional<ArrayBuffer>&) MOZ_DELETE;
+  void PassOptionalNullableArrayBuffer(Optional<ArrayBuffer*>&) MOZ_DELETE;
+  void PassOptionalEnum(Optional<TestEnum>&) MOZ_DELETE;
+  void PassOptionalCallback(JSContext*, Optional<JSObject*>&) MOZ_DELETE;
+  void PassOptionalNullableCallback(JSContext*, Optional<JSObject*>&) MOZ_DELETE;
+  void PassOptionalAny(Optional<JS::Value>&) MOZ_DELETE;
 
   // And test that string stuff is always const
-  void PassString(nsAString&, ErrorResult&) MOZ_DELETE;
-  void PassNullableString(nsAString&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
-  void PassOptionalNullableStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
+  void PassString(nsAString&) MOZ_DELETE;
+  void PassNullableString(nsAString&) MOZ_DELETE;
+  void PassOptionalString(Optional<nsAString>&) MOZ_DELETE;
+  void PassOptionalStringWithDefaultValue(nsAString&) MOZ_DELETE;
+  void PassOptionalNullableString(Optional<nsAString>&) MOZ_DELETE;
+  void PassOptionalNullableStringWithDefaultValue(nsAString&) MOZ_DELETE;
 
 };
 
 class TestIndexedGetterInterface : public nsISupports,
                                    public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
-  uint32_t IndexedGetter(uint32_t, ErrorResult&) MOZ_DELETE;
-  uint32_t Item(uint32_t, ErrorResult&);
-  uint32_t Item(uint32_t, bool&, ErrorResult&) MOZ_DELETE;
+  uint32_t IndexedGetter(uint32_t, bool&);
+  uint32_t IndexedGetter(uint32_t&) MOZ_DELETE;
+  uint32_t Item(uint32_t&);
+  uint32_t Item(uint32_t, bool&) MOZ_DELETE;
   uint32_t GetLength();
 };
 
 class TestNamedGetterInterface : public nsISupports,
                                  public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&);
 };
 
 class TestIndexedAndNamedGetterInterface : public nsISupports,
                                            public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
-  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
-  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  uint32_t IndexedGetter(uint32_t, bool&);
+  void NamedGetter(const nsAString&, bool&, nsAString&);
+  void NamedItem(const nsAString&, nsAString&);
   uint32_t GetLength();
 };
 
 class TestIndexedSetterInterface : public nsISupports,
                                    public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&);
-  void SetItem(uint32_t, const nsAString&, ErrorResult&);
+  void IndexedSetter(uint32_t, const nsAString&);
+  void SetItem(uint32_t, const nsAString&);
 };
 
 class TestNamedSetterInterface : public nsISupports,
                                  public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&);
 };
 
 class TestIndexedAndNamedSetterInterface : public nsISupports,
                                            public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
   // We need a GetParentObject to make binding codegen happy
   virtual nsISupports* GetParentObject();
 
-  void IndexedSetter(uint32_t, TestIndexedSetterInterface&, ErrorResult&);
-  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
-  void SetNamedItem(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+  void IndexedSetter(uint32_t, TestIndexedSetterInterface&);
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&);
+  void SetNamedItem(const nsAString&, TestIndexedSetterInterface&);
 };
 
 class TestIndexedAndNamedGetterAndSetterInterface : public TestIndexedSetterInterface
 {
 public:
-  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
-  uint32_t Item(uint32_t, ErrorResult&);
-  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
-  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
-  void IndexedSetter(uint32_t, int32_t&, ErrorResult&);
-  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&) MOZ_DELETE;
-  void NamedSetter(const nsAString&, const nsAString&, ErrorResult&);
+  uint32_t IndexedGetter(uint32_t, bool&);
+  uint32_t Item(uint32_t);
+  void NamedGetter(const nsAString&, bool&, nsAString&);
+  void NamedItem(const nsAString&, nsAString&);
+  void IndexedSetter(uint32_t, int32_t&);
+  void IndexedSetter(uint32_t, const nsAString&) MOZ_DELETE;
+  void NamedSetter(const nsAString&, const nsAString&);
   void Stringify(nsAString&);
   uint32_t GetLength();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* TestBindingHeader_h */
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -31,17 +31,17 @@ interface OnlyForUseInConstructor {
  Constructor(DOMString str),
  Constructor(unsigned long num, boolean? bool),
  Constructor(TestInterface? iface),
  Constructor(TestNonCastableInterface iface)
  // , Constructor(long arg1, long arg2, (TestInterface or OnlyForUseInConstructor) arg3)
  ]
 interface TestInterface {
   // Integer types
-  // XXXbz add tests for infallible versions of all the integer stuff
+  // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
   void passOptionalByteWithDefault(optional byte arg = 0);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
@@ -91,17 +91,17 @@ interface TestInterface {
   readonly attribute unsigned long long readonlyUnsignedLongLong;
   attribute unsigned long long  writableUnsignedLongLong;
   void passUnsignedLongLong(unsigned long long arg);
   unsigned long long receiveUnsignedLongLong();
   void passOptionalUnsignedLongLong(optional unsigned long long arg);
   void passOptionalUnsignedLongLongWithDefault(optional unsigned long long arg = 17);
 
   // Castable interface types
-  // XXXbz add tests for infallible versions of all the castable interface stuff
+  // XXXbz add tests for throwing versions of all the castable interface stuff
   TestInterface receiveSelf();
   TestInterface? receiveNullableSelf();
   TestInterface receiveWeakSelf();
   TestInterface? receiveWeakNullableSelf();
   // A verstion to test for casting to TestInterface&
   void passSelf(TestInterface arg);
   // A version we can use to test for the exact type passed in
   void passSelf2(TestInterface arg);
@@ -371,26 +371,28 @@ dictionary ParentDict : GrandparentDict 
 };
 
 dictionary DictContainingDict {
   Dict memberDict;
 };
 
 interface TestIndexedGetterInterface {
   getter long item(unsigned long index);
+  [Infallible]
   readonly attribute unsigned long length;
 };
 
 interface TestNamedGetterInterface {
   getter DOMString (DOMString name);
 };
 
 interface TestIndexedAndNamedGetterInterface {
   getter long (unsigned long index);
   getter DOMString namedItem(DOMString name);
+  [Infallible]
   readonly attribute unsigned long length;
 };
 
 interface TestIndexedSetterInterface {
   setter creator void setItem(unsigned long index, DOMString item);
 };
 
 interface TestNamedSetterInterface {
@@ -402,11 +404,13 @@ interface TestIndexedAndNamedSetterInter
   setter creator void setNamedItem(DOMString name, TestIndexedSetterInterface item);
 };
 
 interface TestIndexedAndNamedGetterAndSetterInterface : TestIndexedSetterInterface {
   getter long item(unsigned long index);
   getter DOMString namedItem(DOMString name);
   setter creator void (unsigned long index, long item);
   setter creator void (DOMString name, DOMString item);
+  [Infallible]
   stringifier DOMString ();
+  [Infallible]
   readonly attribute unsigned long length;
 };
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -102,16 +102,22 @@ BrowserElementChild.prototype = {
                      /* useCapture = */ true,
                      /* wantsUntrusted = */ false);
 
     addEventListener('DOMLinkAdded',
                      this._iconChangedHandler.bind(this),
                      /* useCapture = */ true,
                      /* wantsUntrusted = */ false);
 
+    this._afterPaintHandlerClosure = this._afterPaintHandler.bind(this);
+    addEventListener('MozAfterPaint',
+                     this._afterPaintHandlerClosure,
+                     /* useCapture = */ true,
+                     /* wantsUntrusted = */ false);
+
     var self = this;
     function addMsgListener(msg, handler) {
       addMessageListener('browser-element-api:' + msg, handler.bind(self));
     }
 
     addMsgListener("get-screenshot", this._recvGetScreenshot);
     addMsgListener("set-visible", this._recvSetVisible);
     addMsgListener("send-mouse-event", this._recvSendMouseEvent);
@@ -346,16 +352,29 @@ BrowserElementChild.prototype = {
         sendAsyncMsg('iconchange', e.target.href);
       }
       else {
         debug("Not top level!");
       }
     }
   },
 
+  _afterPaintHandler: function(e) {
+    let uri = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
+    debug("Got afterpaint event: " + uri.spec);
+    if (uri.spec != "about:blank") {
+      /* this._afterPaintHandlerClosure == arguments.callee, except we're in
+       * strict mode so we don't have arguments.callee. */
+      removeEventListener('MozAfterPaint', this._afterPaintHandlerClosure,
+                          /* useCapture */ true);
+
+      sendAsyncMsg('firstpaint');
+    }
+  },
+
   _closeHandler: function(e) {
     let win = e.target;
     if (win != content || e.defaultPrevented) {
       return;
     }
 
     debug("Closing window " + win);
     sendAsyncMsg('close');
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -190,16 +190,17 @@ function BrowserElementParent(frameLoade
   addMessageListener("loadstart", this._fireEventFromMsg);
   addMessageListener("loadend", this._fireEventFromMsg);
   addMessageListener("titlechange", this._fireEventFromMsg);
   addMessageListener("iconchange", this._fireEventFromMsg);
   addMessageListener("close", this._fireEventFromMsg);
   addMessageListener("securitychange", this._fireEventFromMsg);
   addMessageListener("error", this._fireEventFromMsg);
   addMessageListener("scroll", this._fireEventFromMsg);
+  addMessageListener("firstpaint", this._fireEventFromMsg);
   addMessageListener("keyevent", this._fireKeyEvent);
   addMessageListener("showmodalprompt", this._handleShowModalPrompt);
   addMessageListener('got-screenshot', this._gotDOMRequestResult);
   addMessageListener('got-can-go-back', this._gotDOMRequestResult);
   addMessageListener('got-can-go-forward', this._gotDOMRequestResult);
   addMessageListener('fullscreen-origin-change', this._remoteFullscreenOriginChange);
   addMessageListener('rollback-fullscreen', this._remoteFrameFullscreenReverted);
   addMessageListener('exit-fullscreen', this._exitFullscreen);
--- a/dom/browser-element/mochitest/Makefile.in
+++ b/dom/browser-element/mochitest/Makefile.in
@@ -62,16 +62,18 @@ MOCHITEST_FILES = \
 		file_browserElement_XFrameOptionsDeny.html \
 		browserElement_XFrameOptionsSameOrigin.js \
 		test_browserElement_inproc_XFrameOptionsSameOrigin.html \
 		file_browserElement_XFrameOptionsSameOrigin.html \
 		browserElement_XFrameOptionsAllowFrom.js \
 		test_browserElement_inproc_XFrameOptionsAllowFrom.html \
 		file_browserElement_XFrameOptionsAllowFrom.html \
 		file_browserElement_XFrameOptionsAllowFrom.sjs \
+		browserElement_FirstPaint.js \
+		test_browserElement_inproc_FirstPaint.html \
 		browserElement_Alert.js \
 		test_browserElement_inproc_Alert.html \
 		browserElement_AlertInFrame.js \
 		test_browserElement_inproc_AlertInFrame.html \
 		file_browserElement_AlertInFrame.html \
 		file_browserElement_AlertInFrame_Inner.html \
 		browserElement_TargetTop.js \
 		test_browserElement_inproc_TargetTop.html \
@@ -154,16 +156,17 @@ MOCHITEST_FILES += \
 		test_browserElement_oop_SetVisible.html \
 		test_browserElement_oop_SetVisibleFrames.html \
 		test_browserElement_oop_SetVisibleFrames2.html \
 		test_browserElement_oop_KeyEvents.html \
 		test_browserElement_oop_XFrameOptions.html \
 		test_browserElement_oop_XFrameOptionsDeny.html \
 		test_browserElement_oop_XFrameOptionsSameOrigin.html \
 		test_browserElement_oop_XFrameOptionsAllowFrom.html \
+		test_browserElement_oop_FirstPaint.html \
 		test_browserElement_oop_Alert.html \
 		test_browserElement_oop_AlertInFrame.html \
 		test_browserElement_oop_TargetTop.html \
 		test_browserElement_oop_ForwardName.html \
 		test_browserElement_oop_TargetBlank.html \
 		test_browserElement_oop_PromptCheck.html \
 		test_browserElement_oop_PromptConfirm.html \
 		test_browserElement_oop_Close.html \
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_FirstPaint.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 787378 - Add mozbrowserfirstpaint event.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addPermission();
+
+  var iframe = document.createElement('iframe');
+  iframe.mozbrowser = true;
+
+  var gotFirstPaint = false;
+  var gotFirstLocationChange = false;
+  iframe.addEventListener('mozbrowserfirstpaint', function(e) {
+    ok(!gotFirstPaint, "Got only one first paint.");
+    gotFirstPaint = true;
+
+    if (gotFirstLocationChange) {
+      iframe.src = browserElementTestHelpers.emptyPage1 + '?2';
+    }
+  });
+
+  iframe.addEventListener('mozbrowserlocationchange', function(e) {
+    if (e.detail == browserElementTestHelpers.emptyPage1) {
+      gotFirstLocationChange = true;
+      if (gotFirstPaint) {
+        iframe.src = browserElementTestHelpers.emptyPage1 + '?2';
+      }
+    }
+    else if (e.detail.endsWith('?2')) {
+      SimpleTest.finish();
+    }
+  });
+
+  document.body.appendChild(iframe);
+
+  iframe.src = browserElementTestHelpers.emptyPage1;
+}
+
+runTest();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_FirstPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 787378</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_FirstPaint.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_FirstPaint.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 787378</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_FirstPaint.js">
+</script>
+</body>
+</html>
\ No newline at end of file
deleted file mode 100644
--- a/dom/camera/CameraCapabilities.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* 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 DOM_CAMERA_NSCAMERACAPABILITIES_H
-#define DOM_CAMERA_NSCAMERACAPABILITIES_H
-
-#include "CameraControl.h"
-#include "nsAutoPtr.h"
-#include "mozilla/Attributes.h"
-
-namespace mozilla {
-
-typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JSObject* aArray, uint32_t aIndex, const char* aStart, char** aEnd);
-
-class nsCameraCapabilities MOZ_FINAL : public nsICameraCapabilities
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSICAMERACAPABILITIES
-
-  nsCameraCapabilities(nsCameraControl* aCamera);
-
-  nsresult ParameterListToNewArray(
-    JSContext* cx,
-    JSObject** aArray,
-    uint32_t aKey,
-    ParseItemAndAddFunc aParseItemAndAdd
-  );
-  nsresult StringListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey);
-  nsresult DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey);
-
-private:
-  nsCameraCapabilities(const nsCameraCapabilities&) MOZ_DELETE;
-  nsCameraCapabilities& operator=(const nsCameraCapabilities&) MOZ_DELETE;
-
-protected:
-  /* additional members */
-  ~nsCameraCapabilities();
-  nsCOMPtr<nsCameraControl> mCamera;
-};
-
-} // namespace mozilla
-
-#endif // DOM_CAMERA_NSCAMERACAPABILITIES_H
--- a/dom/camera/CameraCommon.h
+++ b/dom/camera/CameraCommon.h
@@ -16,36 +16,90 @@
 #endif
 
 #ifndef NAN
 #define NAN std::numeric_limits<double>::quiet_NaN()
 #endif
 
 #include "nsThreadUtils.h"
 #include "nsIDOMCameraManager.h"
+#include "prlog.h"
 
-#define DOM_CAMERA_LOG( l, ... )          \
-  do {                                    \
-    if ( DOM_CAMERA_LOG_LEVEL >= (l) ) {  \
-      printf_stderr (__VA_ARGS__);        \
-    }                                     \
-  } while (0)
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* gCameraLog;
+#define DOM_CAMERA_LOG( type, ... ) PR_LOG(gCameraLog, (PRLogModuleLevel)type, ( __VA_ARGS__ ))
+#else
+#define DOM_CAMERA_LOG( type, ... )
+#endif
 
-#define DOM_CAMERA_LOGA( ... )        DOM_CAMERA_LOG( 0, __VA_ARGS__ )
+#define DOM_CAMERA_LOGA( ... )      DOM_CAMERA_LOG( 0, __VA_ARGS__ )
 
+/**
+ * From the least to the most output.
+ */
 enum {
   DOM_CAMERA_LOG_NOTHING,
   DOM_CAMERA_LOG_ERROR,
   DOM_CAMERA_LOG_WARNING,
-  DOM_CAMERA_LOG_INFO
+  DOM_CAMERA_LOG_INFO,
+  DOM_CAMERA_LOG_TRACE,
+  DOM_CAMERA_LOG_REFERENCES
 };
 
-#define DOM_CAMERA_LOGI( ... )        DOM_CAMERA_LOG( DOM_CAMERA_LOG_INFO,  __VA_ARGS__ )
-#define DOM_CAMERA_LOGW( ... )        DOM_CAMERA_LOG( DOM_CAMERA_LOG_WARNING, __VA_ARGS__ )
-#define DOM_CAMERA_LOGE( ... )        DOM_CAMERA_LOG( DOM_CAMERA_LOG_ERROR, __VA_ARGS__ )
+/**
+ * DOM_CAMERA_LOGR() can be called before 'gCameraLog' is set, so
+ * we need to handle this one a little differently.
+ */
+#ifdef PR_LOGGING
+#define DOM_CAMERA_LOGR( ... )                                  \
+  do {                                                          \
+    if (gCameraLog) {                                           \
+      DOM_CAMERA_LOG( DOM_CAMERA_LOG_REFERENCES, __VA_ARGS__ ); \
+    }                                                           \
+  } while (0)
+#else
+#define DOM_CAMERA_LOGR( ... )
+#endif
+#define DOM_CAMERA_LOGT( ... )      DOM_CAMERA_LOG( DOM_CAMERA_LOG_TRACE, __VA_ARGS__ )
+#define DOM_CAMERA_LOGI( ... )      DOM_CAMERA_LOG( DOM_CAMERA_LOG_INFO, __VA_ARGS__ )
+#define DOM_CAMERA_LOGW( ... )      DOM_CAMERA_LOG( DOM_CAMERA_LOG_WARNING, __VA_ARGS__ )
+#define DOM_CAMERA_LOGE( ... )      DOM_CAMERA_LOG( DOM_CAMERA_LOG_ERROR, __VA_ARGS__ )
+
+enum {
+  CAMERA_PARAM_EFFECT,
+  CAMERA_PARAM_WHITEBALANCE,
+  CAMERA_PARAM_SCENEMODE,
+  CAMERA_PARAM_FLASHMODE,
+  CAMERA_PARAM_FOCUSMODE,
+  CAMERA_PARAM_ZOOM,
+  CAMERA_PARAM_METERINGAREAS,
+  CAMERA_PARAM_FOCUSAREAS,
+  CAMERA_PARAM_FOCALLENGTH,
+  CAMERA_PARAM_FOCUSDISTANCENEAR,
+  CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
+  CAMERA_PARAM_FOCUSDISTANCEFAR,
+  CAMERA_PARAM_EXPOSURECOMPENSATION,
+
+  CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
+  CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
+  CAMERA_PARAM_SUPPORTED_PICTURESIZES,
+  CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
+  CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
+  CAMERA_PARAM_SUPPORTED_SCENEMODES,
+  CAMERA_PARAM_SUPPORTED_EFFECTS,
+  CAMERA_PARAM_SUPPORTED_FLASHMODES,
+  CAMERA_PARAM_SUPPORTED_FOCUSMODES,
+  CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
+  CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
+  CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
+  CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
+  CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
+  CAMERA_PARAM_SUPPORTED_ZOOM,
+  CAMERA_PARAM_SUPPORTED_ZOOMRATIOS
+};
 
 class CameraErrorResult : public nsRunnable
 {
 public:
   CameraErrorResult(nsICameraErrorCallback* onError, const nsString& aErrorMsg)
     : mOnErrorCb(onError)
     , mErrorMsg(aErrorMsg)
   { }
@@ -60,9 +114,48 @@ public:
     return NS_OK;
   }
 
 protected:
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
   const nsString mErrorMsg;
 };
 
+#ifdef PR_LOGGING
+
+static inline void nsLogAddRefCamera(const char *file, uint32_t line, void* p, uint32_t count, const char *clazz, uint32_t size)
+{
+  if (count == 1) {
+    DOM_CAMERA_LOGR("++++++++++++++++++++++++++++++++++++++++");
+  }
+  DOM_CAMERA_LOGR("%s:%d : CAMREF-ADD(%s): this=%p, mRefCnt=%d\n", file, line, clazz, p, count);
+}
+
+static inline void nsLogReleaseCamera(const char *file, uint32_t line, void* p, uint32_t count, const char *clazz, bool abortOnDelete)
+{
+  DOM_CAMERA_LOGR("%s:%d : CAMREF-REL(%s): this=%p, mRefCnt=%d\n", file, line, clazz, p, count);
+  if (count == 0) {
+    if (!abortOnDelete) {
+      DOM_CAMERA_LOGR("----------------------------------------");
+    } else {
+      DOM_CAMERA_LOGR("---------- ABORTING ON DELETE ----------");
+      *((uint32_t *)0xdeadbeef) = 0x266230;
+    }
+  }
+}
+
+#ifdef NS_LOG_ADDREF
+#undef NS_LOG_ADDREF
+#endif
+#ifdef NS_LOG_RELEASE
+#undef NS_LOG_RELEASE
+#endif
+
+#define NS_LOG_ADDREF( p, n, c, s ) nsLogAddRefCamera(__FILE__, __LINE__, (p), (n), (c), (s))
+#ifdef DOM_CAMERA_DEBUG_REFS_ABORT_ON_DELETE
+#define NS_LOG_RELEASE( p, n, c )   nsLogReleaseCamera(__FILE__, __LINE__, (p), (n), (c), DOM_CAMERA_DEBUG_REFS_ABORT_ON_DELETE)
+#else
+#define NS_LOG_RELEASE( p, n, c )   nsLogReleaseCamera(__FILE__, __LINE__, (p), (n), (c), false)
+#endif
+
+#endif // PR_LOGGING
+
 #endif // DOM_CAMERA_CAMERACOMMON_H
deleted file mode 100644
--- a/dom/camera/CameraControl.cpp
+++ /dev/null
@@ -1,506 +0,0 @@
-/* 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 "nsCOMPtr.h"
-#include "nsDOMClassInfo.h"
-#include "jsapi.h"
-#include "nsThread.h"
-#include "DOMCameraManager.h"
-#include "CameraControl.h"
-#include "CameraCapabilities.h"
-#include "CameraControl.h"
-#include "mozilla/Services.h"
-#include "nsIObserverService.h"
-
-#define DOM_CAMERA_LOG_LEVEL  3
-#include "CameraCommon.h"
-
-using namespace mozilla;
-using namespace dom;
-
-DOMCI_DATA(CameraControl, nsICameraControl)
-
-NS_INTERFACE_MAP_BEGIN(nsCameraControl)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_INTERFACE_MAP_ENTRY(nsICameraControl)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraControl)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_THREADSAFE_ADDREF(nsCameraControl)
-NS_IMPL_THREADSAFE_RELEASE(nsCameraControl)
-
-// Helpers for string properties.
-nsresult
-nsCameraControl::SetHelper(uint32_t aKey, const nsAString& aValue)
-{
-  SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
-  return NS_OK;
-}
-
-nsresult
-nsCameraControl::GetHelper(uint32_t aKey, nsAString& aValue)
-{
-  const char* value = GetParameterConstChar(aKey);
-  if (!value) {
-    return NS_ERROR_FAILURE;
-  }
-
-  aValue.AssignASCII(value);
-  return NS_OK;
-}
-
-// Helpers for doubles.
-nsresult
-nsCameraControl::SetHelper(uint32_t aKey, double aValue)
-{
-  SetParameter(aKey, aValue);
-  return NS_OK;
-}
-
-nsresult
-nsCameraControl::GetHelper(uint32_t aKey, double* aValue)
-{
-  MOZ_ASSERT(aValue);
-  *aValue = GetParameterDouble(aKey);
-  return NS_OK;
-}
-
-// Helper for weighted regions.
-nsresult
-nsCameraControl::SetHelper(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit)
-{
-  if (aLimit == 0) {
-    DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
-    return NS_OK;
-  }
-
-  if (!aValue.isObject()) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  uint32_t length = 0;
-
-  JSObject* regions = &aValue.toObject();
-  if (!JS_GetArrayLength(aCx, regions, &length)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
-  if (length > aLimit) {
-    length = aLimit;
-  }
-    
-  nsTArray<CameraRegion> regionArray;
-  regionArray.SetCapacity(length);
-
-  for (uint32_t i = 0; i < length; ++i) {
-    JS::Value v;
-
-    if (!JS_GetElement(aCx, regions, i, &v)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    CameraRegion* r = regionArray.AppendElement();
-    /**
-     * These are the default values.  We can remove these when the xpidl
-     * dictionary parser gains the ability to grok default values.
-     */
-    r->top = -1000;
-    r->left = -1000;
-    r->bottom = 1000;
-    r->right = 1000;
-    r->weight = 1000;
-
-    nsresult rv = r->Init(aCx, &v);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%d\n",
-      i,
-      r->top,
-      r->left,
-      r->bottom,
-      r->right,
-      r->weight
-    );
-  }
-  SetParameter(aKey, regionArray);
-  return NS_OK;
-}
-
-nsresult
-nsCameraControl::GetHelper(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
-{
-  nsTArray<CameraRegion> regionArray;
-
-  GetParameter(aKey, regionArray);
-
-  JSObject* array = JS_NewArrayObject(aCx, 0, nullptr);
-  if (!array) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  uint32_t length = regionArray.Length();
-  DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
-
-  for (uint32_t i = 0; i < length; ++i) {
-    CameraRegion* r = &regionArray[i];
-    JS::Value v;
-
-    JSObject* o = JS_NewObject(aCx, nullptr, nullptr, nullptr);
-    if (!o) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    DOM_CAMERA_LOGI("top=%d\n", r->top);
-    v = INT_TO_JSVAL(r->top);
-    if (!JS_SetProperty(aCx, o, "top", &v)) {
-      return NS_ERROR_FAILURE;
-    }
-    DOM_CAMERA_LOGI("left=%d\n", r->left);
-    v = INT_TO_JSVAL(r->left);
-    if (!JS_SetProperty(aCx, o, "left", &v)) {
-      return NS_ERROR_FAILURE;
-    }
-    DOM_CAMERA_LOGI("bottom=%d\n", r->bottom);
-    v = INT_TO_JSVAL(r->bottom);
-    if (!JS_SetProperty(aCx, o, "bottom", &v)) {
-      return NS_ERROR_FAILURE;
-    }
-    DOM_CAMERA_LOGI("right=%d\n", r->right);
-    v = INT_TO_JSVAL(r->right);
-    if (!JS_SetProperty(aCx, o, "right", &v)) {
-      return NS_ERROR_FAILURE;
-    }
-    DOM_CAMERA_LOGI("weight=%d\n", r->weight);
-    v = INT_TO_JSVAL(r->weight);
-    if (!JS_SetProperty(aCx, o, "weight", &v)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    v = OBJECT_TO_JSVAL(o);
-    if (!JS_SetElement(aCx, array, i, &v)) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  *aValue = JS::ObjectValue(*array);
-  return NS_OK;
-}
-
-/* readonly attribute nsICameraCapabilities capabilities; */
-NS_IMETHODIMP
-nsCameraControl::GetCapabilities(nsICameraCapabilities** aCapabilities)
-{
-  if (!mCapabilities) {
-    mCapabilities = new nsCameraCapabilities(this);
-  }
-
-  nsCOMPtr<nsICameraCapabilities> capabilities = mCapabilities;
-  capabilities.forget(aCapabilities);
-  return NS_OK;
-}
-
-/* attribute DOMString effect; */
-NS_IMETHODIMP
-nsCameraControl::GetEffect(nsAString& aEffect)
-{
-  return GetHelper(CAMERA_PARAM_EFFECT, aEffect);
-}
-NS_IMETHODIMP
-nsCameraControl::SetEffect(const nsAString& aEffect)
-{
-  return SetHelper(CAMERA_PARAM_EFFECT, aEffect);
-}
-
-/* attribute DOMString whiteBalanceMode; */
-NS_IMETHODIMP
-nsCameraControl::GetWhiteBalanceMode(nsAString& aWhiteBalanceMode)
-{
-  return GetHelper(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
-}
-NS_IMETHODIMP
-nsCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode)
-{
-  return SetHelper(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
-}
-
-/* attribute DOMString sceneMode; */
-NS_IMETHODIMP
-nsCameraControl::GetSceneMode(nsAString& aSceneMode)
-{
-  return GetHelper(CAMERA_PARAM_SCENEMODE, aSceneMode);
-}
-NS_IMETHODIMP
-nsCameraControl::SetSceneMode(const nsAString& aSceneMode)
-{
-  return SetHelper(CAMERA_PARAM_SCENEMODE, aSceneMode);
-}
-
-/* attribute DOMString flashMode; */
-NS_IMETHODIMP
-nsCameraControl::GetFlashMode(nsAString& aFlashMode)
-{
-  return GetHelper(CAMERA_PARAM_FLASHMODE, aFlashMode);
-}
-NS_IMETHODIMP
-nsCameraControl::SetFlashMode(const nsAString& aFlashMode)
-{
-  return SetHelper(CAMERA_PARAM_FLASHMODE, aFlashMode);
-}
-
-/* attribute DOMString focusMode; */
-NS_IMETHODIMP
-nsCameraControl::GetFocusMode(nsAString& aFocusMode)
-{
-  return GetHelper(CAMERA_PARAM_FOCUSMODE, aFocusMode);
-}
-NS_IMETHODIMP
-nsCameraControl::SetFocusMode(const nsAString& aFocusMode)
-{
-  return SetHelper(CAMERA_PARAM_FOCUSMODE, aFocusMode);
-}
-
-/* attribute double zoom; */
-NS_IMETHODIMP
-nsCameraControl::GetZoom(double* aZoom)
-{
-  return GetHelper(CAMERA_PARAM_ZOOM, aZoom);
-}
-NS_IMETHODIMP
-nsCameraControl::SetZoom(double aZoom)
-{
-  return SetHelper(CAMERA_PARAM_ZOOM, aZoom);
-}
-
-/* attribute jsval meteringAreas; */
-NS_IMETHODIMP
-nsCameraControl::GetMeteringAreas(JSContext* cx, JS::Value* aMeteringAreas)
-{
-  return GetHelper(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas);
-}
-NS_IMETHODIMP
-nsCameraControl::SetMeteringAreas(JSContext* cx, const JS::Value& aMeteringAreas)
-{
-  return SetHelper(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas, mMaxMeteringAreas);
-}
-
-/* attribute jsval focusAreas; */
-NS_IMETHODIMP
-nsCameraControl::GetFocusAreas(JSContext* cx, JS::Value* aFocusAreas)
-{
-  return GetHelper(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas);
-}
-NS_IMETHODIMP
-nsCameraControl::SetFocusAreas(JSContext* cx, const JS::Value& aFocusAreas)
-{
-  return SetHelper(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas, mMaxFocusAreas);
-}
-
-/* readonly attribute double focalLength; */
-NS_IMETHODIMP
-nsCameraControl::GetFocalLength(double* aFocalLength)
-{
-  return GetHelper(CAMERA_PARAM_FOCALLENGTH, aFocalLength);
-}
-
-/* readonly attribute double focusDistanceNear; */
-NS_IMETHODIMP
-nsCameraControl::GetFocusDistanceNear(double* aFocusDistanceNear)
-{
-  return GetHelper(CAMERA_PARAM_FOCUSDISTANCENEAR, aFocusDistanceNear);
-}
-
-/* readonly attribute double focusDistanceOptimum; */
-NS_IMETHODIMP
-nsCameraControl::GetFocusDistanceOptimum(double* aFocusDistanceOptimum)
-{
-  return GetHelper(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, aFocusDistanceOptimum);
-}
-
-/* readonly attribute double focusDistanceFar; */
-NS_IMETHODIMP
-nsCameraControl::GetFocusDistanceFar(double* aFocusDistanceFar)
-{
-  return GetHelper(CAMERA_PARAM_FOCUSDISTANCEFAR, aFocusDistanceFar);
-}
-
-/* void setExposureCompensation (const JS::Value& aCompensation, JSContext* cx); */
-NS_IMETHODIMP
-nsCameraControl::SetExposureCompensation(const JS::Value& aCompensation, JSContext* cx)
-{
-  if (aCompensation.isNullOrUndefined()) {
-    // use NaN to switch the camera back into auto mode
-    return SetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
-  }
-
-  double compensation;
-  if (!JS_ValueToNumber(cx, aCompensation, &compensation)) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  return SetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
-}
-
-/* readonly attribute double exposureCompensation; */
-NS_IMETHODIMP
-nsCameraControl::GetExposureCompensation(double* aExposureCompensation)
-{
-  return GetHelper(CAMERA_PARAM_EXPOSURECOMPENSATION, aExposureCompensation);
-}
-
-/* attribute nsICameraShutterCallback onShutter; */
-NS_IMETHODIMP
-nsCameraControl::GetOnShutter(nsICameraShutterCallback** aOnShutter)
-{
-  *aOnShutter = mOnShutterCb;
-  return NS_OK;
-}
-NS_IMETHODIMP
-nsCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
-{
-  mOnShutterCb = aOnShutter;
-  return NS_OK;
-}
-
-/* void startRecording (in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
-NS_IMETHODIMP
-nsCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
-{
-  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
-
-  CameraSize size;
-  nsresult rv = size.Init(cx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, size, onSuccess, onError);
-  mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
-
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (!obs) {
-    NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
-    return NS_ERROR_FAILURE;
-  }
-
-  obs->NotifyObservers(nullptr,
-                       "recording-device-events",
-                       NS_LITERAL_STRING("starting").get());
-
-  return NS_OK;
-}
-
-/* void stopRecording (); */
-NS_IMETHODIMP
-nsCameraControl::StopRecording()
-{
-  nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
-  mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
-
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (!obs) {
-    NS_WARNING("Could not get the Observer service for CameraControl::StopRecording.");
-    return NS_ERROR_FAILURE;
-  }
-
-  obs->NotifyObservers(nullptr,
-                       "recording-device-events",
-                       NS_LITERAL_STRING("shutdown").get());
-
-  return NS_OK;
-}
-
-/* [implicit_jscontext] void getPreviewStream (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
-NS_IMETHODIMP
-nsCameraControl::GetPreviewStream(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
-{
-  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
-
-  CameraSize size;
-  nsresult rv = size.Init(cx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, size, onSuccess, onError);
-  return NS_DispatchToMainThread(getPreviewStreamTask);
-}
-
-/* void autoFocus (in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
-NS_IMETHODIMP
-nsCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
-{
-  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
-
-  nsCOMPtr<nsIRunnable> autoFocusTask = new AutoFocusTask(this, onSuccess, onError);
-  mCameraThread->Dispatch(autoFocusTask, NS_DISPATCH_NORMAL);
-
-  return NS_OK;
-}
-
-/* void takePicture (in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
-NS_IMETHODIMP nsCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
-{
-  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
-
-  CameraPictureOptions  options;
-  CameraSize            size;
-  CameraPosition        pos;
-
-  nsresult rv = options.Init(cx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = size.Init(cx, &options.pictureSize);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  /**
-   * Default values, until the dictionary parser can handle them.
-   * NaN indicates no value provided.
-   */
-  pos.latitude = NAN;
-  pos.longitude = NAN;
-  pos.altitude = NAN;
-  pos.timestamp = NAN;
-  rv = pos.Init(cx, &options.position);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, size, options.rotation, options.fileFormat, pos, onSuccess, onError);
-  mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
-
-  return NS_OK;
-}
-
-void
-nsCameraControl::AutoFocusComplete(bool aSuccess)
-{
-  /**
-   * Auto focusing can change some of the camera's parameters, so
-   * we need to pull a new set before sending the result to the
-   * main thread.
-   */
-  PullParametersImpl(nullptr);
-
-  nsCOMPtr<nsIRunnable> autoFocusResult = new AutoFocusResult(aSuccess, mAutoFocusOnSuccessCb);
-
-  nsresult rv = NS_DispatchToMainThread(autoFocusResult);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch autoFocus() onSuccess callback to main thread!");
-  }
-}
-
-void
-nsCameraControl::TakePictureComplete(uint8_t* aData, uint32_t aLength)
-{
-  uint8_t* data = new uint8_t[aLength];
-
-  memcpy(data, aData, aLength);
-
-  /**
-   * TODO: pick up the actual specified picture format for the MIME type;
-   * for now, assume we'll be using JPEGs.
-   */
-  nsIDOMBlob* blob = new nsDOMMemoryFile(static_cast<void*>(data), static_cast<uint64_t>(aLength), NS_LITERAL_STRING("image/jpeg"));
-  nsCOMPtr<nsIRunnable> takePictureResult = new TakePictureResult(blob, mTakePictureOnSuccessCb);
-
-  nsresult rv = NS_DispatchToMainThread(takePictureResult);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch takePicture() onSuccess callback to main thread!");
-  }
-}
new file mode 100644
--- /dev/null
+++ b/dom/camera/CameraControlImpl.cpp
@@ -0,0 +1,244 @@
+/* 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 "base/basictypes.h"
+#include "DOMCameraPreview.h"
+#include "CameraControlImpl.h"
+#include "CameraCommon.h"
+
+using namespace mozilla;
+
+// Helpers for string properties.
+nsresult
+CameraControlImpl::Set(uint32_t aKey, const nsAString& aValue)
+{
+  SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
+  return NS_OK;
+}
+
+nsresult
+CameraControlImpl::Get(uint32_t aKey, nsAString& aValue)
+{
+  const char* value = GetParameterConstChar(aKey);
+  if (!value) {
+    return NS_ERROR_FAILURE;
+  }
+
+  aValue.AssignASCII(value);
+  return NS_OK;
+}
+
+// Helpers for doubles.
+nsresult
+CameraControlImpl::Set(uint32_t aKey, double aValue)
+{
+  SetParameter(aKey, aValue);
+  return NS_OK;
+}
+
+nsresult
+CameraControlImpl::Get(uint32_t aKey, double* aValue)
+{
+  MOZ_ASSERT(aValue);
+  *aValue = GetParameterDouble(aKey);
+  return NS_OK;
+}
+
+// Helper for weighted regions.
+nsresult
+CameraControlImpl::Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit)
+{
+  if (aLimit == 0) {
+    DOM_CAMERA_LOGI("%s:%d : aLimit = 0, nothing to do\n", __func__, __LINE__);
+    return NS_OK;
+  }
+
+  if (!aValue.isObject()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  uint32_t length = 0;
+
+  JSObject* regions = &aValue.toObject();
+  if (!JS_GetArrayLength(aCx, regions, &length)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  DOM_CAMERA_LOGI("%s:%d : got %d regions (limited to %d)\n", __func__, __LINE__, length, aLimit);
+  if (length > aLimit) {
+    length = aLimit;
+  }
+
+  nsTArray<CameraRegion> regionArray;
+  regionArray.SetCapacity(length);
+
+  for (uint32_t i = 0; i < length; ++i) {
+    JS::Value v;
+
+    if (!JS_GetElement(aCx, regions, i, &v)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    CameraRegion* r = regionArray.AppendElement();
+    /**
+     * These are the default values.  We can remove these when the xpidl
+     * dictionary parser gains the ability to grok default values.
+     */
+    r->top = -1000;
+    r->left = -1000;
+    r->bottom = 1000;
+    r->right = 1000;
+    r->weight = 1000;
+
+    nsresult rv = r->Init(aCx, &v);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%d\n",
+      i,
+      r->top,
+      r->left,
+      r->bottom,
+      r->right,
+      r->weight
+    );
+  }
+  SetParameter(aKey, regionArray);
+  return NS_OK;
+}
+
+nsresult
+CameraControlImpl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue)
+{
+  nsTArray<CameraRegion> regionArray;
+
+  GetParameter(aKey, regionArray);
+
+  JSObject* array = JS_NewArrayObject(aCx, 0, nullptr);
+  if (!array) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  uint32_t length = regionArray.Length();
+  DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length);
+
+  for (uint32_t i = 0; i < length; ++i) {
+    CameraRegion* r = &regionArray[i];
+    JS::Value v;
+
+    JSObject* o = JS_NewObject(aCx, nullptr, nullptr, nullptr);
+    if (!o) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    DOM_CAMERA_LOGI("top=%d\n", r->top);
+    v = INT_TO_JSVAL(r->top);
+    if (!JS_SetProperty(aCx, o, "top", &v)) {
+      return NS_ERROR_FAILURE;
+    }
+    DOM_CAMERA_LOGI("left=%d\n", r->left);
+    v = INT_TO_JSVAL(r->left);
+    if (!JS_SetProperty(aCx, o, "left", &v)) {
+      return NS_ERROR_FAILURE;
+    }
+    DOM_CAMERA_LOGI("bottom=%d\n", r->bottom);
+    v = INT_TO_JSVAL(r->bottom);
+    if (!JS_SetProperty(aCx, o, "bottom", &v)) {
+      return NS_ERROR_FAILURE;
+    }
+    DOM_CAMERA_LOGI("right=%d\n", r->right);
+    v = INT_TO_JSVAL(r->right);
+    if (!JS_SetProperty(aCx, o, "right", &v)) {
+      return NS_ERROR_FAILURE;
+    }
+    DOM_CAMERA_LOGI("weight=%d\n", r->weight);
+    v = INT_TO_JSVAL(r->weight);
+    if (!JS_SetProperty(aCx, o, "weight", &v)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    v = OBJECT_TO_JSVAL(o);
+    if (!JS_SetElement(aCx, array, i, &v)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  *aValue = JS::ObjectValue(*array);
+  return NS_OK;
+}
+
+nsresult
+CameraControlImpl::GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  /**
+   * The camera preview stream object is DOM-facing, and as such
+   * must be a cycle-collection participant created on the main
+   * thread.
+   */
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIRunnable> getPreviewStreamTask = new GetPreviewStreamTask(this, aSize, onSuccess, onError);
+  return NS_DispatchToCurrentThread(getPreviewStreamTask);
+}
+
+nsresult
+CameraControlImpl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  nsCOMPtr<nsIRunnable> autoFocusTask = new AutoFocusTask(this, onSuccess, onError);
+  return mCameraThread->Dispatch(autoFocusTask, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+CameraControlImpl::TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, aSize, aRotation, aFileFormat, aPosition, onSuccess, onError);
+  return mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+CameraControlImpl::StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, aSize, onSuccess, onError);
+  return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+CameraControlImpl::StopRecording()
+{
+  nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this);
+  return mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+CameraControlImpl::StartPreview(DOMCameraPreview* aDOMPreview)
+{
+  nsCOMPtr<nsIRunnable> startPreviewTask = new StartPreviewTask(this, aDOMPreview);
+  return mCameraThread->Dispatch(startPreviewTask, NS_DISPATCH_NORMAL);
+}
+
+void
+CameraControlImpl::StopPreview()
+{
+  nsCOMPtr<nsIRunnable> stopPreviewTask = new StopPreviewTask(this);
+  mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
+}
+
+void
+CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
+{
+  if (mDOMPreview) {
+    mDOMPreview->ReceiveFrame(aBuffer, aFormat, aBuilder);
+  }
+}
+
+NS_IMETHODIMP
+GetPreviewStreamResult::Run()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mOnSuccessCb) {
+    nsCOMPtr<nsIDOMMediaStream> stream = new DOMCameraPreview(mCameraControl, mWidth, mHeight, mFramesPerSecond);
+    mOnSuccessCb->HandleEvent(stream);
+  }
+  return NS_OK;
+}
rename from dom/camera/CameraControl.h
rename to dom/camera/CameraControlImpl.h
--- a/dom/camera/CameraControl.h
+++ b/dom/camera/CameraControlImpl.h
@@ -1,223 +1,227 @@
 /* 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 DOM_CAMERA_NSCAMERACONTROL_H
-#define DOM_CAMERA_NSCAMERACONTROL_H
+#ifndef DOM_CAMERA_CAMERACONTROLIMPL_H
+#define DOM_CAMERA_CAMERACONTROLIMPL_H
 
-#include "prtypes.h"
 #include "nsCOMPtr.h"
-#include "nsThread.h"
 #include "nsDOMFile.h"
 #include "DictionaryHelpers.h"
-#include "CameraPreview.h"
 #include "nsIDOMCameraManager.h"
-
-#define DOM_CAMERA_LOG_LEVEL 3
+#include "ICameraControl.h"
 #include "CameraCommon.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 class GetPreviewStreamTask;
+class StartPreviewTask;
+class StopPreviewTask;
 class AutoFocusTask;
 class TakePictureTask;
 class StartRecordingTask;
 class StopRecordingTask;
 class SetParameterTask;
 class GetParameterTask;
-class PushParametersTask;
-class PullParametersTask;
 
-// Main camera control.
-class nsCameraControl : public nsICameraControl
+class DOMCameraPreview;
+
+class CameraControlImpl : public ICameraControl
 {
   friend class GetPreviewStreamTask;
+  friend class StartPreviewTask;
+  friend class StopPreviewTask;
   friend class AutoFocusTask;
   friend class TakePictureTask;
   friend class StartRecordingTask;
   friend class StopRecordingTask;
   friend class SetParameterTask;
   friend class GetParameterTask;
-  friend class PushParametersTask;
-  friend class PullParametersTask;
 
 public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSICAMERACONTROL
-
-  enum {
-    CAMERA_PARAM_EFFECT,
-    CAMERA_PARAM_WHITEBALANCE,
-    CAMERA_PARAM_SCENEMODE,
-    CAMERA_PARAM_FLASHMODE,
-    CAMERA_PARAM_FOCUSMODE,
-    CAMERA_PARAM_ZOOM,
-    CAMERA_PARAM_METERINGAREAS,
-    CAMERA_PARAM_FOCUSAREAS,
-    CAMERA_PARAM_FOCALLENGTH,
-    CAMERA_PARAM_FOCUSDISTANCENEAR,
-    CAMERA_PARAM_FOCUSDISTANCEOPTIMUM,
-    CAMERA_PARAM_FOCUSDISTANCEFAR,
-    CAMERA_PARAM_EXPOSURECOMPENSATION,
+  CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread)
+    : mCameraId(aCameraId)
+    , mCameraThread(aCameraThread)
+    , mFileFormat()
+    , mMaxMeteringAreas(0)
+    , mMaxFocusAreas(0)
+    , mDOMPreview(nullptr)
+    , mAutoFocusOnSuccessCb(nullptr)
+    , mAutoFocusOnErrorCb(nullptr)
+    , mTakePictureOnSuccessCb(nullptr)
+    , mTakePictureOnErrorCb(nullptr)
+    , mStartRecordingOnSuccessCb(nullptr)
+    , mStartRecordingOnErrorCb(nullptr)
+    , mOnShutterCb(nullptr)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
-    CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
-    CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
-    CAMERA_PARAM_SUPPORTED_PICTURESIZES,
-    CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
-    CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
-    CAMERA_PARAM_SUPPORTED_SCENEMODES,
-    CAMERA_PARAM_SUPPORTED_EFFECTS,
-    CAMERA_PARAM_SUPPORTED_FLASHMODES,
-    CAMERA_PARAM_SUPPORTED_FOCUSMODES,
-    CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
-    CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
-    CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
-    CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
-    CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
-    CAMERA_PARAM_SUPPORTED_ZOOM,
-    CAMERA_PARAM_SUPPORTED_ZOOMRATIOS
-  };
+  nsresult GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError);
+  nsresult StartPreview(DOMCameraPreview* aDOMPreview);
+  void StopPreview();
+  nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError);
+  nsresult TakePicture(CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError);
+  nsresult StartRecording(CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError);
+  nsresult StopRecording();
+
+  nsresult Set(uint32_t aKey, const nsAString& aValue);
+  nsresult Get(uint32_t aKey, nsAString& aValue);
+  nsresult Set(uint32_t aKey, double aValue);
+  nsresult Get(uint32_t aKey, double* aValue);
+  nsresult Set(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit);
+  nsresult Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue);
+
+  nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue)
+  {
+    return Set(aCx, CAMERA_PARAM_FOCUSAREAS, aValue, mMaxFocusAreas);
+  }
+
+  nsresult SetMeteringAreas(JSContext* aCx, const JS::Value& aValue)
+  {
+    return Set(aCx, CAMERA_PARAM_METERINGAREAS, aValue, mMaxMeteringAreas);
+  }
+
   virtual const char* GetParameter(const char* aKey) = 0;
   virtual const char* GetParameterConstChar(uint32_t aKey) = 0;
   virtual double GetParameterDouble(uint32_t aKey) = 0;
   virtual void GetParameter(uint32_t aKey, nsTArray<CameraRegion>& aRegions) = 0;
   virtual void SetParameter(const char* aKey, const char* aValue) = 0;
   virtual void SetParameter(uint32_t aKey, const char* aValue) = 0;
   virtual void SetParameter(uint32_t aKey, double aValue) = 0;
   virtual void SetParameter(uint32_t aKey, const nsTArray<CameraRegion>& aRegions) = 0;
-  virtual void PushParameters() = 0;
+  virtual nsresult PushParameters() = 0;
 
-  nsCameraControl(uint32_t aCameraId, nsIThread* aCameraThread)
-    : mCameraId(aCameraId)
-    , mCameraThread(aCameraThread)
-    , mCapabilities(nullptr)
-    , mPreview(nullptr)
-    , mFileFormat()
-    , mMaxMeteringAreas(0)
-    , mMaxFocusAreas(0)
-    , mAutoFocusOnSuccessCb(nullptr)
-    , mAutoFocusOnErrorCb(nullptr)
-    , mTakePictureOnSuccessCb(nullptr)
-    , mTakePictureOnErrorCb(nullptr)
-    , mStartRecordingOnSuccessCb(nullptr)
-    , mStartRecordingOnErrorCb(nullptr)
-    , mOnShutterCb(nullptr)
-  { }
-
-  void TakePictureComplete(uint8_t *aData, uint32_t aLength);
-  void AutoFocusComplete(bool aSuccess);
+  void ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
 
 protected:
-  virtual ~nsCameraControl() { }
-
-  nsresult SetHelper(uint32_t aKey, const nsAString& aValue);
-  nsresult GetHelper(uint32_t aKey, nsAString& aValue);
-  nsresult SetHelper(uint32_t aKey, double aValue);
-  nsresult GetHelper(uint32_t aKey, double* aValue);
-  nsresult SetHelper(JSContext* aCx, uint32_t aKey, const JS::Value& aValue, uint32_t aLimit);
-  nsresult GetHelper(JSContext* aCx, uint32_t aKey, JS::Value* aValue);
+  virtual ~CameraControlImpl()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   virtual nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream) = 0;
+  virtual nsresult StartPreviewImpl(StartPreviewTask* aStartPreview) = 0;
+  virtual nsresult StopPreviewImpl(StopPreviewTask* aStopPreview) = 0;
   virtual nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus) = 0;
   virtual nsresult TakePictureImpl(TakePictureTask* aTakePicture) = 0;
   virtual nsresult StartRecordingImpl(StartRecordingTask* aStartRecording) = 0;
   virtual nsresult StopRecordingImpl(StopRecordingTask* aStopRecording) = 0;
-  virtual nsresult PushParametersImpl(PushParametersTask* aPushParameters) = 0;
-  virtual nsresult PullParametersImpl(PullParametersTask* aPullParameters) = 0;
+  virtual nsresult PushParametersImpl() = 0;
+  virtual nsresult PullParametersImpl() = 0;
 
-private:
-  nsCameraControl(const nsCameraControl&) MOZ_DELETE;
-  nsCameraControl& operator=(const nsCameraControl&) MOZ_DELETE;
+  uint32_t            mCameraId;
+  nsCOMPtr<nsIThread> mCameraThread;
+  nsString            mFileFormat;
+  uint32_t            mMaxMeteringAreas;
+  uint32_t            mMaxFocusAreas;
 
-protected:
-  /* additional members */
-  uint32_t                        mCameraId;
-  nsCOMPtr<nsIThread>             mCameraThread;
-  nsCOMPtr<nsICameraCapabilities> mCapabilities;
-  uint32_t                        mPreviewWidth;
-  uint32_t                        mPreviewHeight;
-  nsCOMPtr<CameraPreview>         mPreview;
-  nsString                        mFileFormat;
-  uint32_t                        mMaxMeteringAreas;
-  uint32_t                        mMaxFocusAreas;
+  /**
+   * 'mDOMPreview' is a raw pointer to the object that will receive incoming
+   * preview frames.  This is guaranteed to be valid, or null.
+   *
+   * It is set by a call to StartPreview(), and set to null on StopPreview().
+   * It is up to the caller to ensure that the object will not disappear
+   * out from under this pointer--usually by calling NS_ADDREF().
+   */
+  DOMCameraPreview*   mDOMPreview;
 
   nsCOMPtr<nsICameraAutoFocusCallback>      mAutoFocusOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback>          mAutoFocusOnErrorCb;
   nsCOMPtr<nsICameraTakePictureCallback>    mTakePictureOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback>          mTakePictureOnErrorCb;
   nsCOMPtr<nsICameraStartRecordingCallback> mStartRecordingOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback>          mStartRecordingOnErrorCb;
   nsCOMPtr<nsICameraShutterCallback>        mOnShutterCb;
+
+private:
+  CameraControlImpl(const CameraControlImpl&) MOZ_DELETE;
+  CameraControlImpl& operator=(const CameraControlImpl&) MOZ_DELETE;
 };
 
 // Return the resulting preview stream to JS.  Runs on the main thread.
 class GetPreviewStreamResult : public nsRunnable
 {
 public:
-  GetPreviewStreamResult(nsIDOMMediaStream* aStream, nsICameraPreviewStreamCallback* onSuccess)
-    : mStream(aStream)
+  GetPreviewStreamResult(CameraControlImpl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond, nsICameraPreviewStreamCallback* onSuccess)
+    : mCameraControl(aCameraControl)
+    , mWidth(aWidth)
+    , mHeight(aHeight)
+    , mFramesPerSecond(aFramesPerSecond)
     , mOnSuccessCb(onSuccess)
-  { }
-
-  NS_IMETHOD Run()
   {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (mOnSuccessCb) {
-      mOnSuccessCb->HandleEvent(mStream);
-    }
-    return NS_OK;
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   }
 
+  virtual ~GetPreviewStreamResult()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  // Run() method is implementation specific.
+  NS_IMETHOD Run();
+
 protected:
-  nsCOMPtr<nsIDOMMediaStream> mStream;
+  nsRefPtr<CameraControlImpl> mCameraControl;
+  uint32_t mWidth;
+  uint32_t mHeight;
+  uint32_t mFramesPerSecond;
   nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
 };
 
 // Get the desired preview stream.
 class GetPreviewStreamTask : public nsRunnable
 {
 public:
-  GetPreviewStreamTask(nsCameraControl* aCameraControl, CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
+  GetPreviewStreamTask(CameraControlImpl* aCameraControl, CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
     : mSize(aSize)
     , mCameraControl(aCameraControl)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~GetPreviewStreamTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
     nsresult rv = mCameraControl->GetPreviewStreamImpl(this);
 
     if (NS_FAILED(rv) && mOnErrorCb) {
       rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     return rv;
   }
 
   CameraSize mSize;
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
   nsCOMPtr<nsICameraPreviewStreamCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
 };
 
 // Return the autofocus status to JS.  Runs on the main thread.
 class AutoFocusResult : public nsRunnable
 {
 public:
   AutoFocusResult(bool aSuccess, nsICameraAutoFocusCallback* onSuccess)
     : mSuccess(aSuccess)
     , mOnSuccessCb(onSuccess)
   { }
 
+  virtual ~AutoFocusResult() { }
+
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (mOnSuccessCb) {
       mOnSuccessCb->HandleEvent(mSuccess);
     }
     return NS_OK;
@@ -227,92 +231,115 @@ protected:
   bool mSuccess;
   nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
 };
 
 // Autofocus the camera.
 class AutoFocusTask : public nsRunnable
 {
 public:
-  AutoFocusTask(nsCameraControl* aCameraControl, nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
+  AutoFocusTask(CameraControlImpl* aCameraControl, nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
     : mCameraControl(aCameraControl)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~AutoFocusTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
     nsresult rv = mCameraControl->AutoFocusImpl(this);
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
     if (NS_FAILED(rv) && mOnErrorCb) {
       rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     return rv;
   }
 
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
   nsCOMPtr<nsICameraAutoFocusCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
 };
 
 // Return the captured picture to JS.  Runs on the main thread.
 class TakePictureResult : public nsRunnable
 {
 public:
   TakePictureResult(nsIDOMBlob* aImage, nsICameraTakePictureCallback* onSuccess)
     : mImage(aImage)
     , mOnSuccessCb(onSuccess)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~TakePictureResult()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
     if (mOnSuccessCb) {
       mOnSuccessCb->HandleEvent(mImage);
     }
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
     return NS_OK;
   }
 
 protected:
   nsCOMPtr<nsIDOMBlob> mImage;
   nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
 };
 
 // Capture a still image with the camera.
 class TakePictureTask : public nsRunnable
 {
 public:
-  TakePictureTask(nsCameraControl* aCameraControl, CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
+  TakePictureTask(CameraControlImpl* aCameraControl, CameraSize aSize, int32_t aRotation, const nsAString& aFileFormat, CameraPosition aPosition, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError)
     : mCameraControl(aCameraControl)
     , mSize(aSize)
     , mRotation(aRotation)
     , mFileFormat(aFileFormat)
     , mPosition(aPosition)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~TakePictureTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
     nsresult rv = mCameraControl->TakePictureImpl(this);
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
     if (NS_FAILED(rv) && mOnErrorCb) {
       rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     return rv;
   }
 
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
   CameraSize mSize;
   int32_t mRotation;
   nsString mFileFormat;
   CameraPosition mPosition;
   nsCOMPtr<nsICameraTakePictureCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
 };
 
@@ -320,16 +347,18 @@ public:
 class StartRecordingResult : public nsRunnable
 {
 public:
   StartRecordingResult(nsIDOMMediaStream* aStream, nsICameraStartRecordingCallback* onSuccess)
     : mStream(aStream)
     , mOnSuccessCb(onSuccess)
   { }
 
+  virtual ~StartRecordingResult() { }
+
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (mOnSuccessCb) {
       mOnSuccessCb->HandleEvent(mStream);
     }
     return NS_OK;
@@ -339,100 +368,129 @@ protected:
   nsCOMPtr<nsIDOMMediaStream> mStream;
   nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
 };
 
 // Start video recording.
 class StartRecordingTask : public nsRunnable
 {
 public:
-  StartRecordingTask(nsCameraControl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
+  StartRecordingTask(CameraControlImpl* aCameraControl, CameraSize aSize, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError)
     : mSize(aSize)
     , mCameraControl(aCameraControl)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~StartRecordingTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
     nsresult rv = mCameraControl->StartRecordingImpl(this);
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
     if (NS_FAILED(rv) && mOnErrorCb) {
       rv = NS_DispatchToMainThread(new CameraErrorResult(mOnErrorCb, NS_LITERAL_STRING("FAILURE")));
       NS_ENSURE_SUCCESS(rv, rv);
     }
     return rv;
   }
 
   CameraSize mSize;
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
   nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
 };
 
 // Stop video recording.
 class StopRecordingTask : public nsRunnable
 {
 public:
-  StopRecordingTask(nsCameraControl* aCameraControl)
+  StopRecordingTask(CameraControlImpl* aCameraControl)
     : mCameraControl(aCameraControl)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~StopRecordingTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
     nsresult rv = mCameraControl->StopRecordingImpl(this);
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
 
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
 };
 
-// Pushes all camera parameters to the camera.
-class PushParametersTask : public nsRunnable
+// Start the preview.
+class StartPreviewTask : public nsRunnable
 {
 public:
-  PushParametersTask(nsCameraControl* aCameraControl)
+  StartPreviewTask(CameraControlImpl* aCameraControl, DOMCameraPreview* aDOMPreview)
     : mCameraControl(aCameraControl)
-  { }
+    , mDOMPreview(aDOMPreview)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~StartPreviewTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
-    nsresult rv = mCameraControl->PushParametersImpl(this);
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
+    nsresult rv = mCameraControl->StartPreviewImpl(this);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
 
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
+  DOMCameraPreview* mDOMPreview; // DOMCameraPreview NS_ADDREFs itself for us
 };
 
-// Get all camera parameters from the camera.
-class PullParametersTask : public nsRunnable
+// Stop the preview.
+class StopPreviewTask : public nsRunnable
 {
 public:
-  PullParametersTask(nsCameraControl* aCameraControl)
+  StopPreviewTask(CameraControlImpl* aCameraControl)
     : mCameraControl(aCameraControl)
-  { }
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual ~StopPreviewTask()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
 
   NS_IMETHOD Run()
   {
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
-    nsresult rv = mCameraControl->PullParametersImpl(this);
-    DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
+    mCameraControl->StopPreviewImpl(this);
+    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
-    NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
 
-  nsCOMPtr<nsCameraControl> mCameraControl;
+  nsRefPtr<CameraControlImpl> mCameraControl;
 };
 
 } // namespace mozilla
 
-#endif // DOM_CAMERA_NSCAMERACONTROL_H
+#endif // DOM_CAMERA_CAMERACONTROLIMPL_H
deleted file mode 100644
--- a/dom/camera/CameraPreview.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/* 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 "CameraPreview.h"
-#include "Layers.h"
-#include "ImageContainer.h"
-#define DOM_CAMERA_LOG_LEVEL  3
-#include "CameraCommon.h"
-
-using namespace mozilla;
-
-NS_IMPL_THREADSAFE_ISUPPORTS1(CameraPreview, CameraPreview)
-
-class CameraPreviewListener : public MediaStreamListener
-{
-public:
-  CameraPreviewListener(CameraPreview* aPreview) :
-    mPreview(aPreview)
-  {
-    DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
-  }
-
-  ~CameraPreviewListener()
-  {
-    DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
-  }
-
-  void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
-  {
-    const char* state;
-
-    DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
-
-    switch (aConsuming) {
-      case NOT_CONSUMED:
-        state = "not consuming";
-        break;
-
-      case CONSUMED:
-        state = "consuming";
-        break;
-
-      default:
-        state = "unknown";
-        break;
-    }
-
-    DOM_CAMERA_LOGA("camera viewfinder is %s\n", state);
-
-    switch (aConsuming) {
-      case NOT_CONSUMED:
-        mPreview->Stop();
-        break;
-
-      case CONSUMED:
-        mPreview->Start();
-        break;
-    }
-  }
-
-protected:
-  nsCOMPtr<CameraPreview> mPreview;
-};
-
-CameraPreview::CameraPreview(nsIThread* aCameraThread, uint32_t aWidth, uint32_t aHeight)
-  : nsDOMMediaStream()
-  , mWidth(aWidth)
-  , mHeight(aHeight)
-  , mFramesPerSecond(0)
-  , mFrameCount(0)
-  , mCameraThread(aCameraThread)
-{
-  DOM_CAMERA_LOGI("%s:%d : mWidth=%d, mHeight=%d : this=%p\n", __func__, __LINE__, mWidth, mHeight, this);
-
-  mImageContainer = LayerManager::CreateImageContainer();
-  MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
-  mStream = gm->CreateInputStream(this);
-  mInput = GetStream()->AsSourceStream();
-  mInput->AddListener(new CameraPreviewListener(this));
-}
-
-void
-CameraPreview::SetFrameRate(uint32_t aFramesPerSecond)
-{
-  mFramesPerSecond = aFramesPerSecond;
-  mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment());
-  mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX);
-}
-
-void
-CameraPreview::Start()
-{
-  nsCOMPtr<nsIRunnable> cameraPreviewControl = NS_NewRunnableMethod(this, &CameraPreview::StartImpl);
-  nsresult rv = mCameraThread->Dispatch(cameraPreviewControl, NS_DISPATCH_NORMAL);
-  if (NS_FAILED(rv)) {
-    DOM_CAMERA_LOGE("failed to start camera preview (%d)\n", rv);
-  }
-}
-
-void
-CameraPreview::Stop()
-{
-  nsCOMPtr<nsIRunnable> cameraPreviewControl = NS_NewRunnableMethod(this, &CameraPreview::StopImpl);
-  nsresult rv = mCameraThread->Dispatch(cameraPreviewControl, NS_DISPATCH_NORMAL);
-  if (NS_FAILED(rv)) {
-    DOM_CAMERA_LOGE("failed to stop camera preview (%d)\n", rv);
-  }
-}
-
-CameraPreview::~CameraPreview()
-{
-  DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
-}
deleted file mode 100644
--- a/dom/camera/CameraPreview.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* 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 DOM_CAMERA_CAMERAPREVIEW_H
-#define DOM_CAMERA_CAMERAPREVIEW_H
-
-#include "MediaStreamGraph.h"
-#include "StreamBuffer.h"
-#include "nsDOMMediaStream.h"
-
-#define DOM_CAMERA_LOG_LEVEL  3
-#include "CameraCommon.h"
-
-using namespace mozilla;
-using namespace mozilla::layers;
-
-namespace mozilla {
-
-class CameraPreview : public nsDOMMediaStream
-                    , public MediaStreamListener
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  CameraPreview(nsIThread* aCameraThread, uint32_t aWidth, uint32_t aHeight);
-
-  void SetFrameRate(uint32_t aFramesPerSecond);
-
-  NS_IMETHODIMP
-  GetCurrentTime(double* aCurrentTime) {
-    return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
-  }
-
-  void Start();
-  void Stop();
-
-  virtual nsresult StartImpl() = 0;
-  virtual nsresult StopImpl() = 0;
-
-protected:
-  virtual ~CameraPreview();
-
-  uint32_t mWidth;
-  uint32_t mHeight;
-  uint32_t mFramesPerSecond;
-  SourceMediaStream* mInput;
-  nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
-  VideoSegment mVideoSegment;
-  uint32_t mFrameCount;
-  nsCOMPtr<nsIThread> mCameraThread;
-
-  enum { TRACK_VIDEO = 1 };
-
-private:
-  CameraPreview(const CameraPreview&) MOZ_DELETE;
-  CameraPreview& operator=(const CameraPreview&) MOZ_DELETE;
-};
-
-} // namespace mozilla
-
-#endif // DOM_CAMERA_CAMERAPREVIEW_H
rename from dom/camera/GonkCameraCapabilities.cpp
rename to dom/camera/DOMCameraCapabilities.cpp
--- a/dom/camera/GonkCameraCapabilities.cpp
+++ b/dom/camera/DOMCameraCapabilities.cpp
@@ -1,61 +1,52 @@
 /* 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 <string.h>
-#include <stdlib.h>
+#include <cstring>
+#include <cstdlib>
+#include "base/basictypes.h"
 #include "nsDOMClassInfo.h"
 #include "jsapi.h"
-#include "camera/CameraParameters.h"
-#include "CameraControl.h"
-#include "CameraCapabilities.h"
-
-#define DOM_CAMERA_LOG_LEVEL  3
+#include "DOMCameraControl.h"
+#include "DOMCameraCapabilities.h"
 #include "CameraCommon.h"
 
-using namespace android;
 using namespace mozilla;
 
 DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
 
-NS_INTERFACE_MAP_BEGIN(nsCameraCapabilities)
+NS_IMPL_CYCLE_COLLECTION_0(DOMCameraCapabilities)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCameraCapabilities)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(nsCameraCapabilities)
-NS_IMPL_RELEASE(nsCameraCapabilities)
-
-
-nsCameraCapabilities::nsCameraCapabilities(nsCameraControl* aCamera)
-  : mCamera(aCamera)
-{
-  // member initializers and constructor code
-  DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
-}
-
-nsCameraCapabilities::~nsCameraCapabilities()
-{
-  // destructor code
-  DOM_CAMERA_LOGI("%s:%d : this=%p, mCamera=%p\n", __func__, __LINE__, this, mCamera.get());
-}
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraCapabilities)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraCapabilities)
 
 static nsresult
 ParseZoomRatioItemAndAdd(JSContext* aCx, JSObject* aArray, uint32_t aIndex, const char* aStart, char** aEnd)
 {
   if (!*aEnd) {
     // make 'aEnd' follow the same semantics as strchr().
     aEnd = nullptr;
   }
 
+  /**
+   * The by-100 divisor is Gonk-specific.  For now, assume other platforms
+   * return actual fractoinal multipliers.
+   */
   double d = strtod(aStart, aEnd);
+#if MOZ_WIDGET_GONK
   d /= 100;
+#endif
 
   jsval v = JS_NumberValue(d);
 
   if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
@@ -112,17 +103,17 @@ ParseDimensionItemAndAdd(JSContext* aCx,
   if (!JS_SetElement(aCx, aArray, aIndex, &v)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsCameraCapabilities::ParameterListToNewArray(JSContext* aCx, JSObject** aArray, uint32_t aKey, ParseItemAndAddFunc aParseItemAndAdd)
+DOMCameraCapabilities::ParameterListToNewArray(JSContext* aCx, JSObject** aArray, uint32_t aKey, ParseItemAndAddFunc aParseItemAndAdd)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
   const char* value = mCamera->GetParameterConstChar(aKey);
   if (!value) {
     // in case we get nonsense data back
     *aArray = nullptr;
     return NS_OK;
@@ -134,217 +125,226 @@ nsCameraCapabilities::ParameterListToNew
   }
 
   const char* p = value;
   uint32_t index = 0;
   nsresult rv;
   char* q;
 
   while (p) {
-    q = strchr(p, ',');
+    /**
+     * In C's string.h, strchr() is declared as returning 'char*'; in C++'s
+     * cstring, it is declared as returning 'const char*', _except_ in MSVC,
+     * where the C version is declared to return const like the C++ version.
+     *
+     * Unfortunately, for both cases, strtod() and strtol() take a 'char**' as
+     * the end-of-conversion pointer, so we need to cast away strchr()'s
+     * const-ness here to make the MSVC build everything happy.
+     */
+    q = const_cast<char*>(strchr(p, ','));
     if (q != p) { // skip consecutive delimiters, just in case
       rv = aParseItemAndAdd(aCx, *aArray, index, p, &q);
       NS_ENSURE_SUCCESS(rv, rv);
       ++index;
     }
     p = q;
     if (p) {
       ++p;
     }
   }
 
   return JS_FreezeObject(aCx, *aArray) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
-nsCameraCapabilities::StringListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey)
+DOMCameraCapabilities::StringListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey)
 {
   JSObject* array;
 
   nsresult rv = ParameterListToNewArray(aCx, &array, aKey, ParseStringItemAndAdd);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aArray = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
-nsCameraCapabilities::DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey)
+DOMCameraCapabilities::DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey)
 {
   JSObject* array;
   nsresult rv;
 
   rv = ParameterListToNewArray(aCx, &array, aKey, ParseDimensionItemAndAdd);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aArray = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 /* readonly attribute jsval previewSizes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
+DOMCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
 {
-  return DimensionListToNewObject(cx, aPreviewSizes, nsCameraControl::CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
+  return DimensionListToNewObject(cx, aPreviewSizes, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
 }
 
 /* readonly attribute jsval pictureSizes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
+DOMCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
 {
-  return DimensionListToNewObject(cx, aPictureSizes, nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTURESIZES);
+  return DimensionListToNewObject(cx, aPictureSizes, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
 }
 
 /* readonly attribute jsval fileFormats; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
+DOMCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
 {
-  return StringListToNewObject(cx, aFileFormats, nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
+  return StringListToNewObject(cx, aFileFormats, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
 }
 
 /* readonly attribute jsval whiteBalanceModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
+DOMCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
 {
-  return StringListToNewObject(cx, aWhiteBalanceModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
+  return StringListToNewObject(cx, aWhiteBalanceModes, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
 }
 
 /* readonly attribute jsval sceneModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
+DOMCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
 {
-  return StringListToNewObject(cx, aSceneModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_SCENEMODES);
+  return StringListToNewObject(cx, aSceneModes, CAMERA_PARAM_SUPPORTED_SCENEMODES);
 }
 
 /* readonly attribute jsval effects; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
+DOMCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
 {
-  return StringListToNewObject(cx, aEffects, nsCameraControl::CAMERA_PARAM_SUPPORTED_EFFECTS);
+  return StringListToNewObject(cx, aEffects, CAMERA_PARAM_SUPPORTED_EFFECTS);
 }
 
 /* readonly attribute jsval flashModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
+DOMCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
 {
-  return StringListToNewObject(cx, aFlashModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_FLASHMODES);
+  return StringListToNewObject(cx, aFlashModes, CAMERA_PARAM_SUPPORTED_FLASHMODES);
 }
 
 /* readonly attribute jsval focusModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
+DOMCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
 {
-  return StringListToNewObject(cx, aFocusModes, nsCameraControl::CAMERA_PARAM_SUPPORTED_FOCUSMODES);
+  return StringListToNewObject(cx, aFocusModes, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
 }
 
 /* readonly attribute long maxFocusAreas; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMaxFocusAreas(JSContext* cx, int32_t* aMaxFocusAreas)
+DOMCameraCapabilities::GetMaxFocusAreas(JSContext* cx, int32_t* aMaxFocusAreas)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
-  const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
+  const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
   if (!value) {
     // in case we get nonsense data back
     *aMaxFocusAreas = 0;
     return NS_OK;
   }
 
   *aMaxFocusAreas = atoi(value);
   return NS_OK;
 }
 
 /* readonly attribute double minExposureCompensation; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
+DOMCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
-  const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
+  const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
   if (!value) {
     // in case we get nonsense data back
     *aMinExposureCompensation = 0;
     return NS_OK;
   }
 
   *aMinExposureCompensation = atof(value);
   return NS_OK;
 }
 
 /* readonly attribute double maxExposureCompensation; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
+DOMCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
-  const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
+  const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
   if (!value) {
     // in case we get nonsense data back
     *aMaxExposureCompensation = 0;
     return NS_OK;
   }
 
   *aMaxExposureCompensation = atof(value);
   return NS_OK;
 }
 
 /* readonly attribute double stepExposureCompensation; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
+DOMCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
-  const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
+  const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
   if (!value) {
     // in case we get nonsense data back
     *aStepExposureCompensation = 0;
     return NS_OK;
   }
 
   *aStepExposureCompensation = atof(value);
   return NS_OK;
 }
 
 /* readonly attribute long maxMeteringAreas; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, int32_t* aMaxMeteringAreas)
+DOMCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, int32_t* aMaxMeteringAreas)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
-  const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
+  const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
   if (!value) {
     // in case we get nonsense data back
     *aMaxMeteringAreas = 0;
     return NS_OK;
   }
 
   *aMaxMeteringAreas = atoi(value);
   return NS_OK;
 }
 
 /* readonly attribute jsval zoomRatios; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
+DOMCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
 {
   NS_ENSURE_TRUE(mCamera, NS_ERROR_NOT_AVAILABLE);
 
-  const char* value = mCamera->GetParameterConstChar(nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOM);
-  if (!value || strcmp(value, CameraParameters::TRUE) != 0) {
+  const char* value = mCamera->GetParameterConstChar(CAMERA_PARAM_SUPPORTED_ZOOM);
+  if (!value || strcmp(value, "true") != 0) {
     // if zoom is not supported, return a null object
     *aZoomRatios = JSVAL_NULL;
     return NS_OK;
   }
 
   JSObject* array;
 
-  nsresult rv = ParameterListToNewArray(cx, &array, nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, ParseZoomRatioItemAndAdd);
+  nsresult rv = ParameterListToNewArray(cx, &array, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, ParseZoomRatioItemAndAdd);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aZoomRatios = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 /* readonly attribute jsval videoSizes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
+DOMCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
 {
-  return DimensionListToNewObject(cx, aVideoSizes, nsCameraControl::CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
+  return DimensionListToNewObject(cx, aVideoSizes, CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
 }
new file mode 100644
--- /dev/null
+++ b/dom/camera/DOMCameraCapabilities.h
@@ -0,0 +1,56 @@
+/* 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 DOM_CAMERA_DOMCAMERACAPABILITIES_H
+#define DOM_CAMERA_DOMCAMERACAPABILITIES_H
+
+#include "nsCycleCollectionParticipant.h"
+#include "ICameraControl.h"
+#include "nsAutoPtr.h"
+#include "CameraCommon.h"
+
+namespace mozilla {
+
+typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JSObject* aArray, uint32_t aIndex, const char* aStart, char** aEnd);
+
+class DOMCameraCapabilities MOZ_FINAL : public nsICameraCapabilities
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMCameraCapabilities)
+  NS_DECL_NSICAMERACAPABILITIES
+
+  DOMCameraCapabilities(ICameraControl* aCamera)
+    : mCamera(aCamera)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  nsresult ParameterListToNewArray(
+    JSContext* cx,
+    JSObject** aArray,
+    uint32_t aKey,
+    ParseItemAndAddFunc aParseItemAndAdd
+  );
+  nsresult StringListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey);
+  nsresult DimensionListToNewObject(JSContext* aCx, JS::Value* aArray, uint32_t aKey);
+
+private:
+  DOMCameraCapabilities(const DOMCameraCapabilities&) MOZ_DELETE;
+  DOMCameraCapabilities& operator=(const DOMCameraCapabilities&) MOZ_DELETE;
+
+protected:
+  /* additional members */
+  ~DOMCameraCapabilities()
+  {
+    // destructor code
+    DOM_CAMERA_LOGT("%s:%d : this=%p, mCamera=%p\n", __func__, __LINE__, this, mCamera.get());
+  }
+
+  nsRefPtr<ICameraControl> mCamera;
+};
+
+} // namespace mozilla
+
+#endif // DOM_CAMERA_DOMCAMERACAPABILITIES_H
new file mode 100644
--- /dev/null
+++ b/dom/camera/DOMCameraControl.cpp
@@ -0,0 +1,370 @@
+/* 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 "base/basictypes.h"
+#include "nsCOMPtr.h"
+#include "nsDOMClassInfo.h"
+#include "jsapi.h"
+#include "nsThread.h"
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
+#include "DOMCameraManager.h"
+#include "DOMCameraCapabilities.h"
+#include "DOMCameraControl.h"
+#include "CameraCommon.h"
+
+using namespace mozilla;
+using namespace dom;
+
+DOMCI_DATA(CameraControl, nsICameraControl)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMCameraControl)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMCameraControl)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMCapabilities)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMCameraControl)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDOMCapabilities)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraControl)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsICameraControl)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraControl)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraControl)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCameraControl)
+
+nsDOMCameraControl::~nsDOMCameraControl()
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+}
+
+/* readonly attribute nsICameraCapabilities capabilities; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetCapabilities(nsICameraCapabilities** aCapabilities)
+{
+  if (!mDOMCapabilities) {
+    mDOMCapabilities = new DOMCameraCapabilities(mCameraControl);
+  }
+
+  nsCOMPtr<nsICameraCapabilities> capabilities = mDOMCapabilities;
+  capabilities.forget(aCapabilities);
+  return NS_OK;
+}
+
+/* attribute DOMString effect; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetEffect(nsAString& aEffect)
+{
+  return mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetEffect(const nsAString& aEffect)
+{
+  return mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
+}
+
+/* attribute DOMString whiteBalanceMode; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetWhiteBalanceMode(nsAString& aWhiteBalanceMode)
+{
+  return mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode)
+{
+  return mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
+}
+
+/* attribute DOMString sceneMode; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetSceneMode(nsAString& aSceneMode)
+{
+  return mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode)
+{
+  return mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
+}
+
+/* attribute DOMString flashMode; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFlashMode(nsAString& aFlashMode)
+{
+  return mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode)
+{
+  return mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
+}
+
+/* attribute DOMString focusMode; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFocusMode(nsAString& aFocusMode)
+{
+  return mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode)
+{
+  return mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
+}
+
+/* attribute double zoom; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetZoom(double* aZoom)
+{
+  return mCameraControl->Get(CAMERA_PARAM_ZOOM, aZoom);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetZoom(double aZoom)
+{
+  return mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
+}
+
+/* attribute jsval meteringAreas; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetMeteringAreas(JSContext* cx, JS::Value* aMeteringAreas)
+{
+  return mCameraControl->Get(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetMeteringAreas(JSContext* cx, const JS::Value& aMeteringAreas)
+{
+  return mCameraControl->SetMeteringAreas(cx, aMeteringAreas);
+}
+
+/* attribute jsval focusAreas; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFocusAreas(JSContext* cx, JS::Value* aFocusAreas)
+{
+  return mCameraControl->Get(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas);
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetFocusAreas(JSContext* cx, const JS::Value& aFocusAreas)
+{
+  return mCameraControl->SetFocusAreas(cx, aFocusAreas);
+}
+
+/* readonly attribute double focalLength; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFocalLength(double* aFocalLength)
+{
+  return mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, aFocalLength);
+}
+
+/* readonly attribute double focusDistanceNear; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFocusDistanceNear(double* aFocusDistanceNear)
+{
+  return mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, aFocusDistanceNear);
+}
+
+/* readonly attribute double focusDistanceOptimum; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFocusDistanceOptimum(double* aFocusDistanceOptimum)
+{
+  return mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, aFocusDistanceOptimum);
+}
+
+/* readonly attribute double focusDistanceFar; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetFocusDistanceFar(double* aFocusDistanceFar)
+{
+  return mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, aFocusDistanceFar);
+}
+
+/* void setExposureCompensation (const JS::Value& aCompensation, JSContext* cx); */
+NS_IMETHODIMP
+nsDOMCameraControl::SetExposureCompensation(const JS::Value& aCompensation, JSContext* cx)
+{
+  if (aCompensation.isNullOrUndefined()) {
+    // use NaN to switch the camera back into auto mode
+    return mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
+  }
+
+  double compensation;
+  if (!JS_ValueToNumber(cx, aCompensation, &compensation)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  return mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
+}
+
+/* readonly attribute double exposureCompensation; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetExposureCompensation(double* aExposureCompensation)
+{
+  return mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, aExposureCompensation);
+}
+
+/* attribute nsICameraShutterCallback onShutter; */
+NS_IMETHODIMP
+nsDOMCameraControl::GetOnShutter(nsICameraShutterCallback** aOnShutter)
+{
+  // TODO: see bug 779138.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP
+nsDOMCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
+{
+  // TODO: see bug 779138.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void startRecording (in jsval aOptions, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
+NS_IMETHODIMP
+nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
+{
+  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
+
+  CameraSize size;
+  nsresult rv = size.Init(cx, &aOptions);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (!obs) {
+    NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
+    return NS_ERROR_FAILURE;
+  }
+
+  obs->NotifyObservers(nullptr,
+                       "recording-device-events",
+                       NS_LITERAL_STRING("starting").get());
+
+  return mCameraControl->StartRecording(size, onSuccess, onError);
+}
+
+/* void stopRecording (); */
+NS_IMETHODIMP
+nsDOMCameraControl::StopRecording()
+{
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (!obs) {
+    NS_WARNING("Could not get the Observer service for CameraControl::StopRecording.");
+    return NS_ERROR_FAILURE;
+  }
+
+  obs->NotifyObservers(nullptr,
+                       "recording-device-events",
+                       NS_LITERAL_STRING("shutdown").get());
+
+  return mCameraControl->StopRecording();
+}
+
+/* [implicit_jscontext] void getPreviewStream (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
+NS_IMETHODIMP
+nsDOMCameraControl::GetPreviewStream(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
+{
+  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
+
+  CameraSize size;
+  nsresult rv = size.Init(cx, &aOptions);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return mCameraControl->GetPreviewStream(size, onSuccess, onError);
+}
+
+/* void resumePreview(); */
+NS_IMETHODIMP
+nsDOMCameraControl::ResumePreview()
+{
+  return mCameraControl->StartPreview(nullptr);
+}
+
+/* void autoFocus (in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
+NS_IMETHODIMP
+nsDOMCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
+  return mCameraControl->AutoFocus(onSuccess, onError);
+}
+
+/* void takePicture (in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
+NS_IMETHODIMP
+nsDOMCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
+{
+  NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
+
+  CameraPictureOptions  options;
+  CameraSize            size;
+  CameraPosition        pos;
+
+  nsresult rv = options.Init(cx, &aOptions);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = size.Init(cx, &options.pictureSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  /**
+   * Default values, until the dictionary parser can handle them.
+   * NaN indicates no value provided.
+   */
+  pos.latitude = NAN;
+  pos.longitude = NAN;
+  pos.altitude = NAN;
+  pos.timestamp = NAN;
+  rv = pos.Init(cx, &options.position);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return mCameraControl->TakePicture(size, options.rotation, options.fileFormat, pos, onSuccess, onError);
+}
+
+class GetCameraResult : public nsRunnable
+{
+public:
+  GetCameraResult(nsDOMCameraControl* aDOMCameraControl, nsresult aResult, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+    : mDOMCameraControl(aDOMCameraControl)
+    , mResult(aResult)
+    , mOnSuccessCb(onSuccess)
+    , mOnErrorCb(onError)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    DOM_CAMERA_LOGT("%s : this=%p -- BEFORE CALLBACK\n", __func__, this);
+    if (NS_FAILED(mResult)) {
+      if (mOnErrorCb) {
+        mOnErrorCb->HandleEvent(NS_LITERAL_STRING("FAILURE"));
+      }
+    } else {
+      if (mOnSuccessCb) {
+        mOnSuccessCb->HandleEvent(mDOMCameraControl);
+      }
+    }
+    DOM_CAMERA_LOGT("%s : this=%p -- AFTER CALLBACK\n", __func__, this);
+
+    /**
+     * Finally, release the extra reference to the DOM-facing camera control.
+     * See the nsDOMCameraControl constructor for the corresponding call to
+     * NS_ADDREF_THIS().
+     */
+    NS_RELEASE(mDOMCameraControl);
+    return NS_OK;
+  }
+
+protected:
+  /**
+   * 'mDOMCameraControl' is a raw pointer to a previously ADDREF()ed object,
+   * which is released in Run().
+   */
+  nsDOMCameraControl* mDOMCameraControl;
+  nsresult mResult;
+  nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
+  nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
+};
+
+nsresult
+nsDOMCameraControl::Result(nsresult aResult, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+  nsCOMPtr<GetCameraResult> getCameraResult = new GetCameraResult(this, aResult, onSuccess, onError);
+  return NS_DispatchToMainThread(getCameraResult);
+}
new file mode 100644
--- /dev/null
+++ b/dom/camera/DOMCameraControl.h
@@ -0,0 +1,50 @@
+/* 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 DOM_CAMERA_DOMCAMERACONTROL_H
+#define DOM_CAMERA_DOMCAMERACONTROL_H
+
+#include "base/basictypes.h"
+#include "prtypes.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "DictionaryHelpers.h"
+#include "ICameraControl.h"
+#include "DOMCameraPreview.h"
+#include "nsIDOMCameraManager.h"
+#include "CameraCommon.h"
+
+namespace mozilla {
+
+using namespace mozilla;
+using namespace dom;
+
+// Main camera control.
+class nsDOMCameraControl : public nsICameraControl
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMCameraControl)
+  NS_DECL_NSICAMERACONTROL
+
+  nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError);
+  nsresult Result(nsresult aResult, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError);
+
+protected:
+  virtual ~nsDOMCameraControl();
+
+private:
+  nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
+  nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
+
+protected:
+  /* additional members */
+  nsRefPtr<ICameraControl>        mCameraControl; // non-DOM camera control
+  nsCOMPtr<nsICameraCapabilities> mDOMCapabilities;
+};
+
+} // namespace mozilla
+
+#endif // DOM_CAMERA_DOMCAMERACONTROL_H
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -1,65 +1,77 @@
 /* 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 "CameraControl.h"
+#include "DOMCameraControl.h"
 #include "DOMCameraManager.h"
 #include "nsDOMClassInfo.h"
 #include "DictionaryHelpers.h"
-
-#undef DOM_CAMERA_LOG_LEVEL
-#define DOM_CAMERA_LOG_LEVEL  DOM_CAMERA_LOG_NOTHING
 #include "CameraCommon.h"
 
 using namespace mozilla;
 
 DOMCI_DATA(CameraManager, nsIDOMCameraManager)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMCameraManager)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCameraManager)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraManager)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsDOMCameraManager)
 NS_IMPL_RELEASE(nsDOMCameraManager)
 
 /**
+ * Global camera logging object
+ *
+ * Set the NSPR_LOG_MODULES environment variable to enable logging
+ * in a debug build, e.g. NSPR_LOG_MODULES=Camera:5
+ */
+#ifdef PR_LOGGING
+PRLogModuleInfo* gCameraLog;
+#endif
+
+/**
  * nsDOMCameraManager::GetListOfCameras
  * is implementation-specific, and can be found in (e.g.)
  * GonkCameraManager.cpp and FallbackCameraManager.cpp.
  */
 
 nsDOMCameraManager::nsDOMCameraManager(uint64_t aWindowId)
   : mWindowId(aWindowId)
 {
   /* member initializers and constructor code */
-  DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+  DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%llx\n", __func__, __LINE__, this, mWindowId);
 }
 
 nsDOMCameraManager::~nsDOMCameraManager()
 {
   /* destructor code */
-  DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
 
 void
 nsDOMCameraManager::OnNavigation(uint64_t aWindowId)
 {
-  // TODO: implement -- see getUserMedia() implementation
+  // TODO: see bug 779145.
 }
 
 // static creator
 already_AddRefed<nsDOMCameraManager>
 nsDOMCameraManager::Create(uint64_t aWindowId)
 {
-  // TODO: check for permissions here to access cameras
+  // TODO: see bug 776934.
 
+#ifdef PR_LOGGING
+  if (!gCameraLog) {
+    gCameraLog = PR_LOG_DEFINE("Camera");
+  }
+#endif
   nsRefPtr<nsDOMCameraManager> cameraManager = new nsDOMCameraManager(aWindowId);
   return cameraManager.forget();
 }
 
 /* [implicit_jscontext] void getCamera ([optional] in jsval aOptions, in nsICameraGetCameraCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
 NS_IMETHODIMP
 nsDOMCameraManager::GetCamera(const JS::Value& aOptions, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
 {
@@ -76,15 +88,15 @@ nsDOMCameraManager::GetCamera(const JS::
   }
 
   // reuse the same camera thread to conserve resources
   if (!mCameraThread) {
     rv = NS_NewThread(getter_AddRefs(mCameraThread));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+  DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
-  nsCOMPtr<nsIRunnable> getCameraTask = new GetCameraTask(cameraId, onSuccess, onError, mCameraThread);
-  mCameraThread->Dispatch(getCameraTask, NS_DISPATCH_NORMAL);
+  // Creating this object will trigger the onSuccess handler
+  nsCOMPtr<nsICameraControl> cameraControl = new nsDOMCameraControl(cameraId, mCameraThread, onSuccess, onError);
 
   return NS_OK;
 }
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -31,17 +31,16 @@ private:
   nsDOMCameraManager& operator=(const nsDOMCameraManager&) MOZ_DELETE;
   ~nsDOMCameraManager();
 
 protected:
   uint64_t mWindowId;
   nsCOMPtr<nsIThread> mCameraThread;
 };
 
-
 class GetCameraTask : public nsRunnable
 {
 public:
   GetCameraTask(uint32_t aCameraId, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsIThread* aCameraThread)
     : mCameraId(aCameraId)
     , mOnSuccessCb(onSuccess)
     , mOnErrorCb(onError)
     , mCameraThread(aCameraThread)
@@ -51,33 +50,9 @@ public:
 
 protected:
   uint32_t mCameraId;
   nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
   nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
   nsCOMPtr<nsIThread> mCameraThread;
 };
 
-class GetCameraResult : public nsRunnable
-{
-public:
-  GetCameraResult(nsICameraControl* aCameraControl, nsICameraGetCameraCallback* onSuccess)
-    : mCameraControl(aCameraControl)
-    , mOnSuccessCb(onSuccess)
-  { }
-
-  NS_IMETHOD Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    // TODO: window management stuff
-    if (mOnSuccessCb) {
-      mOnSuccessCb->HandleEvent(mCameraControl);
-    }
-    return NS_OK;
-  }
-
-protected:
-  nsCOMPtr<nsICameraControl> mCameraControl;
-  nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
-};
-
 #endif // DOM_CAMERA_DOMCAMERAMANAGER_H
new file mode 100644
--- /dev/null
+++ b/dom/camera/DOMCameraPreview.cpp
@@ -0,0 +1,289 @@
+/* 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 "base/basictypes.h"
+#include "Layers.h"
+#include "VideoUtils.h"
+#include "DOMCameraPreview.h"
+#include "CameraCommon.h"
+
+using namespace mozilla;
+
+/**
+ * 'PreviewControl' is a helper class that dispatches preview control
+ * events from the main thread.
+ *
+ * NS_NewRunnableMethod() can't be used because it AddRef()s the method's
+ * object, which can't be done off the main thread for cycle collection
+ * participants.
+ *
+ * Before using this class, 'aDOMPreview' must be appropriately AddRef()ed.
+ */
+class PreviewControl : public nsRunnable
+{
+public:
+  enum {
+    START,
+    STOP,
+    STARTED,
+    STOPPED
+  };
+  PreviewControl(DOMCameraPreview* aDOMPreview, uint32_t aControl)
+    : mDOMPreview(aDOMPreview)
+    , mControl(aControl)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    NS_ASSERTION(NS_IsMainThread(), "PreviewControl not run on main thread");
+
+    switch (mControl) {
+      case START:
+        mDOMPreview->Start();
+        break;
+
+      case STOP:
+        mDOMPreview->Stop();
+        break;
+
+      case STARTED:
+        mDOMPreview->SetStateStarted();
+        break;
+
+      case STOPPED:
+        mDOMPreview->SetStateStopped();
+        break;
+
+      default:
+        DOM_CAMERA_LOGE("PreviewControl: invalid control %d\n", mControl);
+        break;
+    }
+
+    return NS_OK;
+  }
+
+protected:
+  /**
+   * This must be a raw pointer because this class is not created on the
+   * main thread, and DOMCameraPreview is not threadsafe.  Prior to
+   * issuing a preview control event, the caller must ensure that
+   * mDOMPreview will not disappear.
+   */
+  DOMCameraPreview* mDOMPreview;
+  uint32_t mControl;
+};
+
+class DOMCameraPreviewListener : public MediaStreamListener
+{
+public:
+  DOMCameraPreviewListener(DOMCameraPreview* aDOMPreview) :
+    mDOMPreview(aDOMPreview)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  ~DOMCameraPreviewListener()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  void NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming)
+  {
+    const char* state;
+
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+
+    switch (aConsuming) {
+      case NOT_CONSUMED:
+        state = "not consuming";
+        break;
+
+      case CONSUMED:
+        state = "consuming";
+        break;
+
+      default:
+        state = "unknown";
+        break;
+    }
+
+    DOM_CAMERA_LOGA("camera viewfinder is %s\n", state);
+    nsCOMPtr<nsIRunnable> previewControl;
+
+    switch (aConsuming) {
+      case NOT_CONSUMED:
+        previewControl = new PreviewControl(mDOMPreview, PreviewControl::STOP);
+        break;
+
+      case CONSUMED:
+        previewControl = new PreviewControl(mDOMPreview, PreviewControl::START);
+        break;
+
+      default:
+        return;
+    }
+
+    nsresult rv = NS_DispatchToMainThread(previewControl);
+    if (NS_FAILED(rv)) {
+      DOM_CAMERA_LOGE("Failed to dispatch preview control (%d)!\n", rv);
+    }
+  }
+
+protected:
+  // Raw pointer; if we exist, 'mDOMPreview' exists as well
+  DOMCameraPreview* mDOMPreview;
+};
+
+DOMCameraPreview::DOMCameraPreview(ICameraControl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFrameRate)
+  : nsDOMMediaStream()
+  , mState(STOPPED)
+  , mWidth(aWidth)
+  , mHeight(aHeight)
+  , mFramesPerSecond(aFrameRate)
+  , mFrameCount(0)
+  , mCameraControl(aCameraControl)
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p : mWidth=%d, mHeight=%d, mFramesPerSecond=%d\n", __func__, __LINE__, this, mWidth, mHeight, mFramesPerSecond);
+
+  mImageContainer = LayerManager::CreateImageContainer();
+  MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
+  mStream = gm->CreateInputStream(this);
+  mInput = GetStream()->AsSourceStream();
+
+  mListener = new DOMCameraPreviewListener(this);
+  mInput->AddListener(mListener);
+
+  mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment());
+  mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX);
+}
+
+DOMCameraPreview::~DOMCameraPreview()
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p, mListener=%p\n", __func__, __LINE__, this, mListener);
+  mInput->RemoveListener(mListener);
+}
+
+bool
+DOMCameraPreview::HaveEnoughBuffered()
+{
+  return mInput->HaveEnoughBuffered(TRACK_VIDEO);
+}
+
+void
+DOMCameraPreview::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  if (!aBuffer || !aBuilder) {
+    return;
+  }
+  if (mState != STARTED) {
+    return;
+  }
+
+  ImageFormat format = aFormat;
+  nsRefPtr<Image> image = mImageContainer->CreateImage(&format, 1);
+  aBuilder(image, aBuffer, mWidth, mHeight);
+
+  // AppendFrame() takes over image's reference
+  mVideoSegment.AppendFrame(image.forget(), 1, gfxIntSize(mWidth, mHeight));
+  mInput->AppendToTrack(TRACK_VIDEO, &mVideoSegment);
+}
+
+void
+DOMCameraPreview::Start()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Start() not called from main thread");
+  if (mState != STOPPED) {
+    return;
+  }
+
+  DOM_CAMERA_LOGI("Starting preview stream\n");
+
+  /**
+   * Add a reference to ourselves to make sure we stay alive while
+   * the preview is running, as the CameraControlImpl object holds a
+   * weak reference to us.
+   *
+   * This reference is removed in SetStateStopped().
+   */
+  NS_ADDREF_THIS();
+  mState = STARTING;
+  mCameraControl->StartPreview(this);
+}
+
+void
+DOMCameraPreview::SetStateStarted()
+{
+  NS_ASSERTION(NS_IsMainThread(), "SetStateStarted() not called from main thread");
+
+  mState = STARTED;
+  DOM_CAMERA_LOGI("Preview stream started\n");
+}
+
+void
+DOMCameraPreview::Started()
+{
+  if (mState != STARTING) {
+    return;
+  }
+
+  DOM_CAMERA_LOGI("Dispatching preview stream started\n");
+  nsCOMPtr<nsIRunnable> started = new PreviewControl(this, PreviewControl::STARTED);
+  nsresult rv = NS_DispatchToMainThread(started);
+  if (NS_FAILED(rv)) {
+    DOM_CAMERA_LOGE("failed to set statrted state (%d), POTENTIAL MEMORY LEAK!\n", rv);
+  }
+}
+
+void
+DOMCameraPreview::Stop()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Stop() not called from main thread");
+  if (mState != STARTED) {
+    return;
+  }
+
+  DOM_CAMERA_LOGI("Stopping preview stream\n");
+  mState = STOPPING;
+  mCameraControl->StopPreview();
+  mInput->EndTrack(TRACK_VIDEO);
+  mInput->Finish();
+}
+
+void
+DOMCameraPreview::SetStateStopped()
+{
+  NS_ASSERTION(NS_IsMainThread(), "SetStateStopped() not called from main thread");
+
+  mState = STOPPED;
+  DOM_CAMERA_LOGI("Preview stream stopped\n");
+
+  /**
+   * Only remove the reference added in Start() once the preview
+   * has stopped completely.
+   */
+  NS_RELEASE_THIS();
+}
+
+void
+DOMCameraPreview::Stopped(bool aForced)
+{
+  if (mState != STOPPING && !aForced) {
+    return;
+  }
+
+  DOM_CAMERA_LOGI("Dispatching preview stream stopped\n");
+  nsCOMPtr<nsIRunnable> stopped = new PreviewControl(this, PreviewControl::STOPPED);
+  nsresult rv = NS_DispatchToMainThread(stopped);
+  if (NS_FAILED(rv)) {
+    DOM_CAMERA_LOGE("failed to decrement reference count (%d), MEMORY LEAK!\n", rv);
+  }
+}
+
+void
+DOMCameraPreview::Error()
+{
+  DOM_CAMERA_LOGE("Error occurred changing preview state!\n");
+  Stopped(true);
+}
new file mode 100644
--- /dev/null
+++ b/dom/camera/DOMCameraPreview.h
@@ -0,0 +1,81 @@
+/* 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 DOM_CAMERA_DOMCAMERAPREVIEW_H
+#define DOM_CAMERA_DOMCAMERAPREVIEW_H
+
+#include "nsCycleCollectionParticipant.h"
+#include "MediaStreamGraph.h"
+#include "StreamBuffer.h"
+#include "ICameraControl.h"
+#include "nsDOMMediaStream.h"
+#include "CameraCommon.h"
+
+using namespace mozilla;
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+typedef void (*FrameBuilder)(Image* aImage, void* aBuffer, uint32_t aWidth, uint32_t aHeight);
+
+/**
+ * DOMCameraPreview is only exposed to the DOM as an nsDOMMediaStream,
+ * which is a cycle-collection participant already.
+ */
+class DOMCameraPreview : public nsDOMMediaStream
+{
+protected:
+  enum { TRACK_VIDEO = 1 };
+
+public:
+  DOMCameraPreview(ICameraControl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond = 30);
+  void ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
+  bool HaveEnoughBuffered();
+
+  NS_IMETHODIMP
+  GetCurrentTime(double* aCurrentTime) {
+    return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
+  }
+
+  void Start();   // called by the MediaStreamListener to start preview
+  void Started(); // called by the CameraControl when preview is started
+  void Stop();    // called by the MediaStreamListener to stop preview
+  void Stopped(bool aForced = false);
+                  // called by the CameraControl when preview is stopped
+  void Error();   // something went wrong, NS_RELEASE needed
+
+  void SetStateStarted();
+  void SetStateStopped();
+
+protected:
+  virtual ~DOMCameraPreview();
+
+  enum {
+    STOPPED,
+    STARTING,
+    STARTED,
+    STOPPING
+  };
+  uint32_t mState;
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+  uint32_t mFramesPerSecond;
+  SourceMediaStream* mInput;
+  nsRefPtr<ImageContainer> mImageContainer;
+  VideoSegment mVideoSegment;
+  uint32_t mFrameCount;
+  nsRefPtr<ICameraControl> mCameraControl;
+
+  // Raw pointer; AddListener() keeps the reference for us
+  MediaStreamListener* mListener;
+
+private:
+  DOMCameraPreview(const DOMCameraPreview&) MOZ_DELETE;
+  DOMCameraPreview& operator=(const DOMCameraPreview&) MOZ_DELETE;
+};
+
+} // namespace mozilla
+
+#endif // DOM_CAMERA_DOMCAMERAPREVIEW_H
--- a/dom/camera/FallbackCameraCapabilities.cpp
+++ b/dom/camera/FallbackCameraCapabilities.cpp
@@ -1,140 +1,128 @@
 /* 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 "nsDOMClassInfoID.h"
-#include "CameraControl.h"
-#include "CameraCapabilities.h"
-
-#define DOM_CAMERA_LOG_LEVEL  3
+#include "DOMCameraControl.h"
+#include "DOMCameraCapabilities.h"
 #include "CameraCommon.h"
 
 using namespace mozilla;
 
 DOMCI_DATA(CameraCapabilities, nsICameraCapabilities)
 
-NS_INTERFACE_MAP_BEGIN(nsCameraCapabilities)
+NS_IMPL_CYCLE_COLLECTION_0(DOMCameraCapabilities)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCameraCapabilities)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsICameraCapabilities)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraCapabilities)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(nsCameraCapabilities)
-NS_IMPL_RELEASE(nsCameraCapabilities)
-
-nsCameraCapabilities::nsCameraCapabilities(nsCameraControl* aCamera)
-  : mCamera(aCamera)
-{
-  /* member initializers and constructor code */
-  DOM_CAMERA_LOGI("%s:%d : FALLBACK CAMERA CAPABILITIES\n", __func__, __LINE__);
-}
-
-nsCameraCapabilities::~nsCameraCapabilities()
-{
-  /* destructor code */
-}
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraCapabilities)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraCapabilities)
 
 /* [implicit_jscontext] readonly attribute jsval previewSizes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
+DOMCameraCapabilities::GetPreviewSizes(JSContext* cx, JS::Value* aPreviewSizes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval pictureSizes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
+DOMCameraCapabilities::GetPictureSizes(JSContext* cx, JS::Value* aPictureSizes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval fileFormats; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
+DOMCameraCapabilities::GetFileFormats(JSContext* cx, JS::Value* aFileFormats)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval whiteBalanceModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
+DOMCameraCapabilities::GetWhiteBalanceModes(JSContext* cx, JS::Value* aWhiteBalanceModes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval sceneModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
+DOMCameraCapabilities::GetSceneModes(JSContext* cx, JS::Value* aSceneModes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval effects; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
+DOMCameraCapabilities::GetEffects(JSContext* cx, JS::Value* aEffects)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval flashModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
+DOMCameraCapabilities::GetFlashModes(JSContext* cx, JS::Value* aFlashModes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval focusModes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
+DOMCameraCapabilities::GetFocusModes(JSContext* cx, JS::Value* aFocusModes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute long maxFocusAreas; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMaxFocusAreas(JSContext* cx, int32_t* aMaxFocusAreas)
+DOMCameraCapabilities::GetMaxFocusAreas(JSContext* cx, int32_t* aMaxFocusAreas)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute double minExposureCompensation; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
+DOMCameraCapabilities::GetMinExposureCompensation(JSContext* cx, double* aMinExposureCompensation)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute double maxExposureCompensation; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
+DOMCameraCapabilities::GetMaxExposureCompensation(JSContext* cx, double* aMaxExposureCompensation)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute double stepExposureCompensation; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
+DOMCameraCapabilities::GetStepExposureCompensation(JSContext* cx, double* aStepExposureCompensation)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute long maxMeteringAreas; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, int32_t* aMaxMeteringAreas)
+DOMCameraCapabilities::GetMaxMeteringAreas(JSContext* cx, int32_t* aMaxMeteringAreas)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval zoomRatios; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
+DOMCameraCapabilities::GetZoomRatios(JSContext* cx, JS::Value* aZoomRatios)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* [implicit_jscontext] readonly attribute jsval videoSizes; */
 NS_IMETHODIMP
-nsCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
+DOMCameraCapabilities::GetVideoSizes(JSContext* cx, JS::Value* aVideoSizes)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
--- a/dom/camera/FallbackCameraControl.cpp
+++ b/dom/camera/FallbackCameraControl.cpp
@@ -1,65 +1,80 @@
 /* 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 "nsDOMClassInfoID.h"
-#include "DOMCameraManager.h"
-#include "CameraControl.h"
+#include "DOMCameraControl.h"
+#include "CameraControlImpl.h"
 
 using namespace mozilla;
 
 /**
  * Fallback camera control subclass.  Can be used as a template for the
  * definition of new camera support classes.
  */
-class nsFallbackCameraControl : public nsCameraControl
+class nsFallbackCameraControl : public CameraControlImpl
 {
 public:
-  nsFallbackCameraControl(uint32_t aCameraId, nsIThread* aCameraThread);
+  nsFallbackCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError);
 
   const char* GetParameter(const char* aKey);
   const char* GetParameterConstChar(uint32_t aKey);
   double GetParameterDouble(uint32_t aKey);
   void GetParameter(uint32_t aKey, nsTArray<dom::CameraRegion>& aRegions);
   void SetParameter(const char* aKey, const char* aValue);
   void SetParameter(uint32_t aKey, const char* aValue);
   void SetParameter(uint32_t aKey, double aValue);
   void SetParameter(uint32_t aKey, const nsTArray<dom::CameraRegion>& aRegions);
-  void PushParameters();
+  nsresult PushParameters();
 
 protected:
   ~nsFallbackCameraControl();
 
   nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream);
+  nsresult StartPreviewImpl(StartPreviewTask* aStartPreview);
+  nsresult StopPreviewImpl(StopPreviewTask* aStopPreview);
   nsresult AutoFocusImpl(AutoFocusTask* aAutoFocus);
   nsresult TakePictureImpl(TakePictureTask* aTakePicture);
   nsresult StartRecordingImpl(StartRecordingTask* aStartRecording);
   nsresult StopRecordingImpl(StopRecordingTask* aStopRecording);
-  nsresult PushParametersImpl(PushParametersTask* aPushParameters);
-  nsresult PullParametersImpl(PullParametersTask* aPullParameters);
+  nsresult PushParametersImpl();
+  nsresult PullParametersImpl();
 
 private:
   nsFallbackCameraControl(const nsFallbackCameraControl&) MOZ_DELETE;
   nsFallbackCameraControl& operator=(const nsFallbackCameraControl&) MOZ_DELETE;
 };
 
 /**
+ * Stub implementation of the DOM-facing camera control constructor.
+ *
+ * This should never get called--it exists to keep the linker happy; if
+ * implemented, it should construct (e.g.) nsFallbackCameraControl and
+ * store a reference in the 'mCameraControl' member (which is why it is
+ * defined here).
+ */
+nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+{
+}
+
+/**
  * Stub implemetations of the fallback camera control.
  *
  * None of these should ever get called--they exist to keep the linker happy,
  * and may be used as templates for new camera support classes.
  */
-nsFallbackCameraControl::nsFallbackCameraControl(uint32_t aCameraId, nsIThread* aCameraThread)
-  : nsCameraControl(aCameraId, aCameraThread)
-{ }
+nsFallbackCameraControl::nsFallbackCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+  : CameraControlImpl(aCameraId, aCameraThread)
+{
+}
 
 nsFallbackCameraControl::~nsFallbackCameraControl()
-{ }
+{
+}
 
 const char*
 nsFallbackCameraControl::GetParameter(const char* aKey)
 {
   return nullptr;
 }
 
 const char*
@@ -94,28 +109,41 @@ nsFallbackCameraControl::SetParameter(ui
 {
 }
 
 void
 nsFallbackCameraControl::SetParameter(uint32_t aKey, const nsTArray<dom::CameraRegion>& aRegions)
 {
 }
 
-void
+nsresult
 nsFallbackCameraControl::PushParameters()
 {
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
 nsFallbackCameraControl::GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
+nsFallbackCameraControl::StartPreviewImpl(StartPreviewTask* aGetPreviewStream)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsFallbackCameraControl::StopPreviewImpl(StopPreviewTask* aGetPreviewStream)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
 nsFallbackCameraControl::AutoFocusImpl(AutoFocusTask* aAutoFocus)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
 nsFallbackCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
 {
@@ -130,18 +158,18 @@ nsFallbackCameraControl::StartRecordingI
 
 nsresult
 nsFallbackCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
-nsFallbackCameraControl::PushParametersImpl(PushParametersTask* aPushParameters)
+nsFallbackCameraControl::PushParametersImpl()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
-nsFallbackCameraControl::PullParametersImpl(PullParametersTask* aPullParameters)
+nsFallbackCameraControl::PullParametersImpl()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
--- a/dom/camera/FallbackCameraManager.cpp
+++ b/dom/camera/FallbackCameraManager.cpp
@@ -7,16 +7,8 @@
 // From nsDOMCameraManager.
 
 /* [implicit_jscontext] jsval getListOfCameras (); */
 NS_IMETHODIMP
 nsDOMCameraManager::GetListOfCameras(JSContext* cx, JS::Value* _retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
-
-using namespace mozilla;
-
-NS_IMETHODIMP
-GetCameraTask::Run()
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -21,132 +21,226 @@
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsMemory.h"
 #include "jsapi.h"
 #include "nsThread.h"
 #include "nsPrintfCString.h"
 #include "DOMCameraManager.h"
 #include "GonkCameraHwMgr.h"
-#include "CameraCapabilities.h"
+#include "DOMCameraCapabilities.h"
+#include "DOMCameraControl.h"
 #include "GonkCameraControl.h"
-#include "GonkCameraPreview.h"
-
-#define DOM_CAMERA_LOG_LEVEL  3
 #include "CameraCommon.h"
 
 using namespace mozilla;
+using namespace android;
 
 static const char* getKeyText(uint32_t aKey)
 {
   switch (aKey) {
-    case nsCameraControl::CAMERA_PARAM_EFFECT:
+    case CAMERA_PARAM_EFFECT:
       return CameraParameters::KEY_EFFECT;
-    case nsCameraControl::CAMERA_PARAM_WHITEBALANCE:
+    case CAMERA_PARAM_WHITEBALANCE:
       return CameraParameters::KEY_WHITE_BALANCE;
-    case nsCameraControl::CAMERA_PARAM_SCENEMODE:
+    case CAMERA_PARAM_SCENEMODE:
       return CameraParameters::KEY_SCENE_MODE;
-    case nsCameraControl::CAMERA_PARAM_FLASHMODE:
+    case CAMERA_PARAM_FLASHMODE:
       return CameraParameters::KEY_FLASH_MODE;
-    case nsCameraControl::CAMERA_PARAM_FOCUSMODE:
+    case CAMERA_PARAM_FOCUSMODE:
       return CameraParameters::KEY_FOCUS_MODE;
-    case nsCameraControl::CAMERA_PARAM_ZOOM:
+    case CAMERA_PARAM_ZOOM:
       return CameraParameters::KEY_ZOOM;
-    case nsCameraControl::CAMERA_PARAM_METERINGAREAS:
+    case CAMERA_PARAM_METERINGAREAS:
       return CameraParameters::KEY_METERING_AREAS;
-    case nsCameraControl::CAMERA_PARAM_FOCUSAREAS:
+    case CAMERA_PARAM_FOCUSAREAS:
       return CameraParameters::KEY_FOCUS_AREAS;
-    case nsCameraControl::CAMERA_PARAM_FOCALLENGTH:
+    case CAMERA_PARAM_FOCALLENGTH:
       return CameraParameters::KEY_FOCAL_LENGTH;
-    case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCENEAR:
+    case CAMERA_PARAM_FOCUSDISTANCENEAR:
       return CameraParameters::KEY_FOCUS_DISTANCES;
-    case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
+    case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
       return CameraParameters::KEY_FOCUS_DISTANCES;
-    case nsCameraControl::CAMERA_PARAM_FOCUSDISTANCEFAR:
+    case CAMERA_PARAM_FOCUSDISTANCEFAR:
       return CameraParameters::KEY_FOCUS_DISTANCES;
-    case nsCameraControl::CAMERA_PARAM_EXPOSURECOMPENSATION:
+    case CAMERA_PARAM_EXPOSURECOMPENSATION:
       return CameraParameters::KEY_EXPOSURE_COMPENSATION;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
+    case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
       return CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
+    case CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
       return CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTURESIZES:
+    case CAMERA_PARAM_SUPPORTED_PICTURESIZES:
       return CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
+    case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
       return CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
+    case CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
       return CameraParameters::KEY_SUPPORTED_WHITE_BALANCE;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_SCENEMODES:
+    case CAMERA_PARAM_SUPPORTED_SCENEMODES:
       return CameraParameters::KEY_SUPPORTED_SCENE_MODES;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_EFFECTS:
+    case CAMERA_PARAM_SUPPORTED_EFFECTS:
       return CameraParameters::KEY_SUPPORTED_EFFECTS;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_FLASHMODES:
+    case CAMERA_PARAM_SUPPORTED_FLASHMODES:
       return CameraParameters::KEY_SUPPORTED_FLASH_MODES;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_FOCUSMODES:
+    case CAMERA_PARAM_SUPPORTED_FOCUSMODES:
       return CameraParameters::KEY_SUPPORTED_FOCUS_MODES;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
+    case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
       return CameraParameters::KEY_MAX_NUM_FOCUS_AREAS;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
+    case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
       return CameraParameters::KEY_MAX_NUM_METERING_AREAS;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
+    case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
       return CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
+    case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
       return CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
+    case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
       return CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOM:
+    case CAMERA_PARAM_SUPPORTED_ZOOM:
       return CameraParameters::KEY_ZOOM_SUPPORTED;
-    case nsCameraControl::CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
+    case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
       return CameraParameters::KEY_ZOOM_RATIOS;
     default:
       return nullptr;
   }
 }
 
+// nsDOMCameraControl implementation-specific constructor
+nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+  : mDOMCapabilities(nullptr)
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+
+  /**
+   * nsDOMCameraControl is a cycle-collection participant, which means it is
+   * not threadsafe--so we need to bump up its reference count here to make
+   * sure that it exists long enough to be initialized.
+   *
+   * Once it is initialized, the GetCameraResult main-thread runnable will
+   * decrement it again to make sure it can be cleaned up.
+   *
+   * nsGonkCameraControl MUST NOT hold a strong reference to this
+   * nsDOMCameraControl or memory will leak!
+   */
+  NS_ADDREF_THIS();
+  mCameraControl = new nsGonkCameraControl(aCameraId, aCameraThread, this, onSuccess, onError);
+}
+
 // Gonk-specific CameraControl implementation.
 
-nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId, nsIThread* aCameraThread)
-  : nsCameraControl(aCameraId, aCameraThread)
+// Initialize nsGonkCameraControl instance--runs on camera thread.
+class InitGonkCameraControl : public nsRunnable
+{
+public:
+  InitGonkCameraControl(nsGonkCameraControl* aCameraControl, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+    : mCameraControl(aCameraControl)
+    , mDOMCameraControl(aDOMCameraControl)
+    , mOnSuccessCb(onSuccess)
+    , mOnErrorCb(onError)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  ~InitGonkCameraControl()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  NS_IMETHOD Run()
+  {
+    nsresult rv = mCameraControl->Init();
+    return mDOMCameraControl->Result(rv, mOnSuccessCb, mOnErrorCb);
+  }
+
+  nsRefPtr<nsGonkCameraControl> mCameraControl;
+  // Raw pointer to DOM-facing camera control--it must NS_ADDREF itself for us
+  nsDOMCameraControl* mDOMCameraControl;
+  nsCOMPtr<nsICameraGetCameraCallback> mOnSuccessCb;
+  nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
+};
+
+// Construct nsGonkCameraControl on the main thread.
+nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsDOMCameraControl* aDOMCameraControl, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError)
+  : CameraControlImpl(aCameraId, aCameraThread)
   , mHwHandle(0)
   , mExposureCompensationMin(0.0)
   , mExposureCompensationStep(0.0)
   , mDeferConfigUpdate(false)
+  , mWidth(0)
+  , mHeight(0)
+  , mFormat(PREVIEW_FORMAT_UNKNOWN)
+  , mDiscardedFrameCount(0)
 {
-  // Constructor runs on the camera thread--see DOMCameraManager.cpp::GetCameraImpl().
-  DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
+  // Constructor runs on the main thread...
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  mRwLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraControl.Parameters.Lock");
+
+  // ...but initialization is carried out on the camera thread.
+  nsCOMPtr<nsIRunnable> init = new InitGonkCameraControl(this, aDOMCameraControl, onSuccess, onError);
+  mCameraThread->Dispatch(init, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+nsGonkCameraControl::Init()
+{
   mHwHandle = GonkCameraHardware::GetHandle(this, mCameraId);
-  DOM_CAMERA_LOGI("%s:%d : this = %p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
+  DOM_CAMERA_LOGI("Initializing camera %d (this=%p, mHwHandle=%d)\n", mCameraId, this, mHwHandle);
 
   // Initialize our camera configuration database.
-  mRwLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraControl.Parameters.Lock");
-  PullParametersImpl(nullptr);
+  PullParametersImpl();
+
+  // Try to set preferred image format and frame rate
+  DOM_CAMERA_LOGI("Camera preview formats: %s\n", mParams.get(mParams.KEY_SUPPORTED_PREVIEW_FORMATS));
+  const char* const PREVIEW_FORMAT = "yuv420p";
+  const char* const BAD_PREVIEW_FORMAT = "yuv420sp";
+  mParams.setPreviewFormat(PREVIEW_FORMAT);
+  mParams.setPreviewFrameRate(mFps);
 
-  // Grab any settings we'll need later.
-  mExposureCompensationMin = mParams.getFloat(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION);
-  mExposureCompensationStep = mParams.getFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP);
-  mMaxMeteringAreas = mParams.getInt(CameraParameters::KEY_MAX_NUM_METERING_AREAS);
-  mMaxFocusAreas = mParams.getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS);
+  // Check that our settings stuck
+  PullParametersImpl();
+  const char* format = mParams.getPreviewFormat();
+  if (strcmp(format, PREVIEW_FORMAT) == 0) {
+    mFormat = PREVIEW_FORMAT_YUV420P;  /* \o/ */
+  } else if (strcmp(format, BAD_PREVIEW_FORMAT) == 0) {
+    mFormat = PREVIEW_FORMAT_YUV420SP;
+    DOM_CAMERA_LOGA("Camera ignored our request for '%s' preview, will have to convert (from %d)\n", PREVIEW_FORMAT, mFormat);
+  } else {
+    mFormat = PREVIEW_FORMAT_UNKNOWN;
+    DOM_CAMERA_LOGE("Camera ignored our request for '%s' preview, returned UNSUPPORTED format '%s'\n", PREVIEW_FORMAT, format);
+  }
 
-  DOM_CAMERA_LOGI("minimum exposure compensation = %f\n", mExposureCompensationMin);
-  DOM_CAMERA_LOGI("exposure compensation step = %f\n", mExposureCompensationStep);
-  DOM_CAMERA_LOGI("maximum metering areas = %d\n", mMaxMeteringAreas);
-  DOM_CAMERA_LOGI("maximum focus areas = %d\n", mMaxFocusAreas);
+  // Check the frame rate and log if the camera ignored our setting
+  uint32_t fps = mParams.getPreviewFrameRate();
+  if (fps != mFps) {
+    DOM_CAMERA_LOGA("We asked for %d fps but camera returned %d fps, using that", mFps, fps);
+    mFps = fps;
+  }
+
+  // Grab any other settings we'll need later.
+  mExposureCompensationMin = mParams.getFloat(mParams.KEY_MIN_EXPOSURE_COMPENSATION);
+  mExposureCompensationStep = mParams.getFloat(mParams.KEY_EXPOSURE_COMPENSATION_STEP);
+  mMaxMeteringAreas = mParams.getInt(mParams.KEY_MAX_NUM_METERING_AREAS);
+  mMaxFocusAreas = mParams.getInt(mParams.KEY_MAX_NUM_FOCUS_AREAS);
+
+  DOM_CAMERA_LOGI(" - minimum exposure compensation: %f\n", mExposureCompensationMin);
+  DOM_CAMERA_LOGI(" - exposure compensation step:    %f\n", mExposureCompensationStep);
+  DOM_CAMERA_LOGI(" - maximum metering areas:        %d\n", mMaxMeteringAreas);
+  DOM_CAMERA_LOGI(" - maximum focus areas:           %d\n", mMaxFocusAreas);
+
+  return mHwHandle != 0 ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsGonkCameraControl::~nsGonkCameraControl()
 {
-  DOM_CAMERA_LOGI("%s:%d : this = %p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
+  DOM_CAMER