Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Fri, 20 Jan 2012 10:12:37 -0800
changeset 105641 577a1c24f51942a2deeedaec7bd06125d5fc39f1
parent 105640 9711a0b8495f933f84d0be655874cba75a507e11 (current diff)
parent 85039 49936b49aff3498fecf5b0c87684e135c19199f7 (diff)
child 105642 7685f6b2f00d84c0e32bd85a730957958791c266
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/tests/mochitest/events.js
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/base/jar.mn
browser/devtools/jar.mn
content/html/content/src/nsHTMLMediaElement.cpp
content/media/nsBuiltinDecoder.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsBuiltinDecoderStateMachine.h
dom/Makefile.in
dom/src/geolocation/nsGeolocation.cpp
dom/telephony/nsITelephone.idl
dom/telephony/nsTelephonyWorker.h
dom/telephony/nsTelephonyWorker.js
dom/telephony/nsTelephonyWorker.manifest
dom/telephony/ril_consts.js
dom/telephony/ril_worker.js
embedding/android/GeckoAppShell.java
gfx/layers/d3d10/ImageLayerD3D10.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/ipc/ShadowLayersParent.h
layout/base/FrameLayerBuilder.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
layout/reftests/bugs/reftest.list
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mozglue/android/APKOpen.cpp
mozglue/android/Makefile.in
uriloader/exthandler/mac/nsOSHelperAppService.mm
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
xpcom/glue/nsDeque.cpp
xpcom/glue/nsDeque.h
xpcom/glue/nsHashKeys.h
--- a/accessible/src/mac/nsRoleMap.h
+++ b/accessible/src/mac/nsRoleMap.h
@@ -69,17 +69,17 @@ static const NSString* AXRoles [] = {
   NSAccessibilityGroupRole,                     // ROLE_TABLE
   NSAccessibilityGroupRole,                     // ROLE_COLUMNHEADER
   NSAccessibilityGroupRole,                     // ROLE_ROWHEADER
   NSAccessibilityColumnRole,                    // ROLE_COLUMN
   NSAccessibilityRowRole,                       // ROLE_ROW
   NSAccessibilityGroupRole,                     // ROLE_CELL
   @"AXLink",                                    // ROLE_LINK. 10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
   @"AXHelpTag",                                 // ROLE_HELPBALLOON
-  NSAccessibilityUnknownRole,                   // ROLE_CHARACTER. unusued on OS X
+  NSAccessibilityUnknownRole,                   // ROLE_CHARACTER. unused on OS X
   NSAccessibilityListRole,                      // ROLE_LIST
   NSAccessibilityRowRole,                       // ROLE_LISTITEM
   NSAccessibilityOutlineRole,                   // ROLE_OUTLINE
   NSAccessibilityRowRole,                       // ROLE_OUTLINEITEM. XXX: use OutlineRow as subrole.
   NSAccessibilityGroupRole,                     // ROLE_PAGETAB
   NSAccessibilityGroupRole,                     // ROLE_PROPERTYPAGE
   NSAccessibilityUnknownRole,                   // ROLE_INDICATOR
   NSAccessibilityImageRole,                     // ROLE_GRAPHIC
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -26,16 +26,18 @@ const EVENT_TEXT_CARET_MOVED = nsIAccess
 const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED;
 const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED;
 const EVENT_TEXT_SELECTION_CHANGED = nsIAccessibleEvent.EVENT_TEXT_SELECTION_CHANGED;
 const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
 
 ////////////////////////////////////////////////////////////////////////////////
 // General
 
+Components.utils.import("resource://gre/modules/Services.jsm");
+
 /**
  * Set up this variable to dump events into DOM.
  */
 var gA11yEventDumpID = "";
 
 /**
  * Set up this variable to dump event processing into console.
  */
@@ -1409,34 +1411,28 @@ function expandedStateChecker(aIsEnabled
 ////////////////////////////////////////////////////////////////////////////////
 // General
 
 var gA11yEventListeners = {};
 var gA11yEventApplicantsCount = 0;
 
 var gA11yEventObserver =
 {
-  // The service reference needs to live in the observer, instead of as a global var,
-  //   to be available in observe() catch case too.
-  observerService :
-    Components.classes["@mozilla.org/observer-service;1"]
-              .getService(nsIObserverService),
-
   observe: function observe(aSubject, aTopic, aData)
   {
     if (aTopic != "accessible-event")
       return;
 
     var event;
     try {
       event = aSubject.QueryInterface(nsIAccessibleEvent);
     } catch (ex) {
       // After a test is aborted (i.e. timed out by the harness), this exception is soon triggered.
       // Remove the leftover observer, otherwise it "leaks" to all the following tests.
-      this.observerService.removeObserver(this, "accessible-event");
+      Services.obs.removeObserver(this, "accessible-event");
       // Forward the exception, with added explanation.
       throw "[accessible/events.js, gA11yEventObserver.observe] This is expected if a previous test has been aborted... Initial exception was: [ " + ex + " ]";
     }
     var listenersArray = gA11yEventListeners[event.eventType];
 
     var eventFromDumpArea = false;
     if (gLogger.isEnabled()) { // debug stuff
       eventFromDumpArea = true;
@@ -1480,24 +1476,22 @@ var gA11yEventObserver =
   }
 };
 
 function listenA11yEvents(aStartToListen)
 {
   if (aStartToListen) {
     // Add observer when adding the first applicant only.
     if (!(gA11yEventApplicantsCount++))
-      gA11yEventObserver.observerService
-                        .addObserver(gA11yEventObserver, "accessible-event", false);
+      Services.obs.addObserver(gA11yEventObserver, "accessible-event", false);
   } else {
     // Remove observer when there are no more applicants only.
     // '< 0' case should not happen, but just in case: removeObserver() will throw.
     if (--gA11yEventApplicantsCount <= 0)
-      gA11yEventObserver.observerService
-                        .removeObserver(gA11yEventObserver, "accessible-event");
+      Services.obs.removeObserver(gA11yEventObserver, "accessible-event");
   }
 }
 
 function addA11yEventListener(aEventType, aEventHandler)
 {
   if (!(aEventType in gA11yEventListeners))
     gA11yEventListeners[aEventType] = new Array();
 
@@ -1604,21 +1598,18 @@ var gLogger =
   },
 
   /**
    * Log message to error console.
    */
   logToAppConsole: function logger_logToAppConsole(aMsg)
   {
     if (gA11yEventDumpToAppConsole)
-      consoleService.logStringMessage("events: " + aMsg);
-  },
-
-  consoleService: Components.classes["@mozilla.org/consoleservice;1"].
-    getService(Components.interfaces.nsIConsoleService)
+      Services.console.logStringMessage("events: " + aMsg);
+  }
 };
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Sequence
 
 /**
  * Base class of sequence item.
--- a/accessible/tests/mochitest/events/test_focus_autocomplete.xul
+++ b/accessible/tests/mochitest/events/test_focus_autocomplete.xul
@@ -1,15 +1,19 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                  type="text/css"?>
 
+<!-- Firefox searchbar -->
 <?xml-stylesheet href="chrome://browser/content/browser.css"
                  type="text/css"?>
+<!-- SeaMonkey searchbar -->
+<?xml-stylesheet href="chrome://navigator/content/navigator.css"
+                 type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="Accessible focus event testing">
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
--- a/accessible/tests/mochitest/focus/test_takeFocus.xul
+++ b/accessible/tests/mochitest/focus/test_takeFocus.xul
@@ -1,16 +1,13 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                  type="text/css"?>
 
-<?xml-stylesheet href="chrome://browser/content/browser.css"
-                 type="text/css"?>
-
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="Accessible focus testing">
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
 
--- a/accessible/tests/mochitest/states/test_expandable.xul
+++ b/accessible/tests/mochitest/states/test_expandable.xul
@@ -1,14 +1,19 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                  type="text/css"?>
+
+<!-- Firefox searchbar -->
 <?xml-stylesheet href="chrome://browser/content/browser.css"
                  type="text/css"?>
+<!-- SeaMonkey searchbar -->
+<?xml-stylesheet href="chrome://navigator/content/navigator.css"
+                 type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="Expanded state change events tests for comboboxes and autocompletes.">
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1036,16 +1036,17 @@ pref("devtools.tilt.enabled", true);
 // Enable the rules view
 pref("devtools.ruleview.enabled", true);
 
 // Enable the Scratchpad tool.
 pref("devtools.scratchpad.enabled", true);
 
 // Enable the Style Editor.
 pref("devtools.styleeditor.enabled", true);
+pref("devtools.styleeditor.transitions", true);
 
 // Enable tools for Chrome development.
 pref("devtools.chrome.enabled", false);
 
 // Disable the GCLI enhanced command line.
 pref("devtools.gcli.enable", true);
 
 // The last Web Console height. This is initially 0 which means that the Web
--- a/browser/base/content/test/browser_bug416661.js
+++ b/browser/base/content/test/browser_bug416661.js
@@ -38,17 +38,18 @@ function test() {
   gBrowser.selectedTab = tabElm;
 
   afterZoomAndLoad(start_test_prefNotSet);
   content.location = 
     "http://mochi.test:8888/browser/browser/base/content/test/zoom_test.html";
 }
 
 function afterZoomAndLoad(cb) {
-  let didLoad = didZoom = false;
+  let didLoad = false;
+  let didZoom = false;
   tabElm.linkedBrowser.addEventListener("load", function() {
     tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true);
     didLoad = true;
     if (didZoom)
       executeSoon(cb);
   }, true);
   let oldSZFB = ZoomManager.setZoomForBrowser;
   ZoomManager.setZoomForBrowser = function(browser, value) {
--- a/browser/base/content/test/browser_bug555224.js
+++ b/browser/base/content/test/browser_bug555224.js
@@ -32,17 +32,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 const TEST_PAGE = "/browser/browser/base/content/test/dummy_page.html";
 var gTestTab, gBgTab, gTestZoom;
 
 function afterZoomAndLoad(aCallback, aTab) {
-  let didLoad = didZoom = false;
+  let didLoad = false;
+  let didZoom = false;
   aTab.linkedBrowser.addEventListener("load", function() {
     aTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     didLoad = true;
     if (didZoom)
       executeSoon(aCallback);
   }, true);
   let oldAPTS = FullZoom._applyPrefToSetting;
   FullZoom._applyPrefToSetting = function(value, browser) {
--- a/browser/base/content/test/browser_bug592338.js
+++ b/browser/base/content/test/browser_bug592338.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
 
-Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm");
+var tempScope = {};
+Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
+var LightweightThemeManager = tempScope.LightweightThemeManager;
 
 function wait_for_notification(aCallback) {
   PopupNotifications.panel.addEventListener("popupshown", function() {
     PopupNotifications.panel.removeEventListener("popupshown", arguments.callee, false);
     aCallback(PopupNotifications.panel);
   }, false);
 }
 
--- a/browser/base/content/test/browser_bug623155.js
+++ b/browser/base/content/test/browser_bug623155.js
@@ -38,16 +38,18 @@ 6. The redirected URI is <https://www.ba
    a cert-error page.
 
 7. Check the URLbar's value, expecting <https://www.bank1.com/#FG>
 
 8. End.
 
  */
 
+var gNewTab;
+
 function test() {
   waitForExplicitFinish();
 
   // Load a URI in the background.
   gNewTab = gBrowser.addTab(REDIRECT_FROM + "#BG");
   gBrowser.getBrowserForTab(gNewTab)
           .webProgress
           .addProgressListener(gWebProgressListener,
--- a/browser/base/content/test/browser_gestureSupport.js
+++ b/browser/base/content/test/browser_gestureSupport.js
@@ -378,17 +378,17 @@ function test_latchedGesture(gesture, in
   };
 
   // Test the gestures in each direction.
   test_emitLatchedEvents(eventPrefix, 500, cmd);
   test_emitLatchedEvents(eventPrefix, -500, cmd);
 
   // Restore the gesture to its original configuration.
   gPrefService.setBoolPref(branch + "latched", oldLatchedValue);
-  for (dir in cmd)
+  for (let dir in cmd)
     test_removeCommand(cmd[dir]);
 }
 
 // Test whether non-latched events are triggered upon sufficient motion.
 function test_thresholdGesture(gesture, inc, dec, eventPrefix)
 {
   let branch = test_prefBranch + gesture + ".";
 
--- a/browser/base/content/test/browser_identity_UI.js
+++ b/browser/base/content/test/browser_identity_UI.js
@@ -63,17 +63,17 @@ var tests = [
   {
     name: "IP address",
     location: "http://127.0.0.1:8888/",
     host: "127.0.0.1:8888",
     effectiveHost: "127.0.0.1"
   },
 ]
 
-let gCurrentTest, gCurrentTestIndex = -1;
+let gCurrentTest, gCurrentTestIndex = -1, gTestDesc;
 // Go through the tests in both directions, to add additional coverage for
 // transitions between different states.
 let gForward = true;
 function nextTest() {
   if (gForward)
     gCurrentTestIndex++;
   else
     gCurrentTestIndex--;
--- a/browser/devtools/styleeditor/StyleEditor.jsm
+++ b/browser/devtools/styleeditor/StyleEditor.jsm
@@ -54,16 +54,33 @@ const SAVE_ERROR = "error-save";
 
 // max update frequency in ms (avoid potential typing lag and/or flicker)
 // @see StyleEditor.updateStylesheet
 const UPDATE_STYLESHEET_THROTTLE_DELAY = 500;
 
 // @see StyleEditor._persistExpando
 const STYLESHEET_EXPANDO = "-moz-styleeditor-stylesheet-";
 
+const TRANSITIONS_PREF = "devtools.styleeditor.transitions";
+
+const TRANSITION_CLASS = "moz-styleeditor-transitioning";
+const TRANSITION_DURATION_MS = 500;
+const TRANSITION_RULE = "\
+:root.moz-styleeditor-transitioning, :root.moz-styleeditor-transitioning * {\
+-moz-transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
+-moz-transition-delay: 0ms !important;\
+-moz-transition-timing-function: ease-out !important;\
+-moz-transition-property: all !important;\
+}";
+
+/**
+ * Style Editor module-global preferences
+ */
+const TRANSITIONS_ENABLED = Services.prefs.getBoolPref(TRANSITIONS_PREF);
+
 
 /**
  * StyleEditor constructor.
  *
  * The StyleEditor is initialized 'headless', it does not display source
  * or receive input. Setting inputElement attaches a DOMElement to handle this.
  *
  * An editor can be created stand-alone or created by StyleEditorChrome to
@@ -102,16 +119,19 @@ function StyleEditor(aDocument, aStyleSh
 
   this._errorMessage = null;  // @see errorMessage
 
   // listeners for significant editor actions. @see addActionListener
   this._actionListeners = [];
 
   // this is to perform pending updates before editor closing
   this._onWindowUnloadBinding = this._onWindowUnload.bind(this);
+
+  this._transitionRefCount = 0;
+
   this._focusOnSourceEditorReady = false;
 }
 
 StyleEditor.prototype = {
   /**
    * Retrieve the content document this editor will apply changes to.
    *
    * @return DOMDocument
@@ -400,18 +420,23 @@ StyleEditor.prototype = {
    *   onAttach:               Called when an input element has been attached.
    *                           Arguments: (StyleEditor editor)
    *                           @see inputElement
    *
    *   onDetach:               Called when input element has been detached.
    *                           Arguments: (StyleEditor editor)
    *                           @see inputElement
    *
-   *   onCommit:               Called when changes have been committed/applied
-   *                           to the live DOM style sheet.
+   *   onUpdate:               Called when changes are being applied to the live
+   *                           DOM style sheet but might not be complete from
+   *                           a WYSIWYG perspective (eg. transitioned update).
+   *                           Arguments: (StyleEditor editor)
+   *
+   *   onCommit:               Called when changes have been completely committed
+   *                           /applied to the live DOM style sheet.
    *                           Arguments: (StyleEditor editor)
    * }
    *
    * All listener methods are optional.
    *
    * @param IStyleEditorActionListener aListener
    * @see removeActionListener
    */
@@ -635,25 +660,60 @@ StyleEditor.prototype = {
                              // when it is enabled back. @see enableStylesheet
 
     if (this.sourceEditor) {
       this._state.text = this.sourceEditor.getText();
     }
     let source = this._state.text;
     let oldNode = this.styleSheet.ownerNode;
     let oldIndex = this.styleSheetIndex;
-
-    let newNode = this.contentDocument.createElement("style");
+    let content = this.contentDocument;
+    let newNode = content.createElement("style");
     newNode.setAttribute("type", "text/css");
-    newNode.appendChild(this.contentDocument.createTextNode(source));
+    newNode.appendChild(content.createTextNode(source));
     oldNode.parentNode.replaceChild(newNode, oldNode);
 
-    this._styleSheet = this.contentDocument.styleSheets[oldIndex];
+    this._styleSheet = content.styleSheets[oldIndex];
     this._persistExpando();
 
+    if (!TRANSITIONS_ENABLED) {
+      this._triggerAction("Update");
+      this._triggerAction("Commit");
+      return;
+    }
+
+    // Insert the global transition rule
+    // Use a ref count to make sure we do not add it multiple times.. and remove
+    // it only when all pending StyleEditor-generated transitions ended.
+    if (!this._transitionRefCount) {
+      this._styleSheet.insertRule(TRANSITION_RULE, 0);
+      content.documentElement.classList.add(TRANSITION_CLASS);
+    }
+
+    this._transitionRefCount++;
+
+    // Set up clean up and commit after transition duration (+10% buffer)
+    // @see _onTransitionEnd
+    content.defaultView.setTimeout(this._onTransitionEnd.bind(this),
+                                   Math.floor(TRANSITION_DURATION_MS * 1.1));
+
+    this._triggerAction("Update");
+  },
+
+  /**
+    * This cleans up class and rule added for transition effect and then trigger
+    * Commit as the changes have been completed.
+    */
+  _onTransitionEnd: function SE__onTransitionEnd()
+  {
+    if (--this._transitionRefCount == 0) {
+      this.contentDocument.documentElement.classList.remove(TRANSITION_CLASS);
+      this.styleSheet.deleteRule(0);
+    }
+
     this._triggerAction("Commit");
   },
 
   /**
    * Show file picker and return the file user selected.
    *
    * @param mixed aFile
    *        Optional nsIFile or string representing the filename to auto-select.
--- a/browser/devtools/styleeditor/StyleEditorChrome.jsm
+++ b/browser/devtools/styleeditor/StyleEditorChrome.jsm
@@ -151,21 +151,24 @@ StyleEditorChrome.prototype = {
       aContentWindow.removeEventListener("unload", onContentUnload, false);
       if (this.contentWindow == aContentWindow) {
         this.contentWindow = null; // detach
       }
     }.bind(this);
     aContentWindow.addEventListener("unload", onContentUnload, false);
 
     if (aContentWindow.document.readyState == "complete") {
+      this._root.classList.remove("loading");
       this._populateChrome();
       return;
     } else {
+      this._root.classList.add("loading");
       let onContentReady = function () {
         aContentWindow.removeEventListener("load", onContentReady, false);
+        this._root.classList.remove("loading");
         this._populateChrome();
       }.bind(this);
       aContentWindow.addEventListener("load", onContentReady, false);
     }
   },
 
   /**
    * Retrieve the content document attached to this chrome.
@@ -294,26 +297,32 @@ StyleEditorChrome.prototype = {
       let editor = new StyleEditor(this.contentDocument);
       this._editors.push(editor);
       editor.addActionListener(this);
       editor.importFromFile(this._mockImportFile || null, this._window);
     }.bind(this));
   },
 
   /**
-   * Reset the chrome UI to an empty state.
+   * Reset the chrome UI to an empty and ready state.
    */
   _resetChrome: function SEC__resetChrome()
   {
     this._editors.forEach(function (aEditor) {
       aEditor.removeActionListener(this);
     }.bind(this));
     this._editors = [];
 
     this._view.removeAll();
+
+    // (re)enable UI
+    let matches = this._root.querySelectorAll("toolbarbutton,input,select");
+    for (let i = 0; i < matches.length; ++i) {
+      matches[i].removeAttribute("disabled");
+    }
   },
 
   /**
    * Populate the chrome UI according to the content document.
    *
    * @see StyleEditor._setupShadowStyleSheet
    */
   _populateChrome: function SEC__populateChrome()
--- a/browser/devtools/styleeditor/splitview.css
+++ b/browser/devtools/styleeditor/splitview.css
@@ -41,16 +41,20 @@ box,
   -moz-box-flex: 1;
   -moz-box-orient: vertical;
 }
 
 .splitview-nav-container {
   -moz-box-pack: center;
 }
 
+.loading .splitview-nav-container > .placeholder {
+  display: none !important;
+}
+
 .splitview-controller,
 .splitview-main {
   -moz-box-flex: 0;
 }
 
 .splitview-controller {
   min-height: 3em;
   max-height: 14em;
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -49,28 +49,30 @@
         xmlns="http://www.w3.org/1999/xhtml"
         id="style-editor-chrome-window"
         title="&window.title;"
         windowtype="Tools:StyleEditor"
         width="800" height="280"
         persist="screenX screenY width height sizemode">
 <xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 
-<xul:box id="style-editor-chrome" class="splitview-root">
+<xul:box id="style-editor-chrome" class="splitview-root loading">
   <xul:box class="splitview-controller" id="stylesheets-controller" persist="width height">
     <xul:box class="splitview-main">
       <xul:toolbar class="devtools-toolbar">
         <xul:toolbarbutton class="style-editor-newButton devtools-toolbarbutton"
                     accesskey="&newButton.accesskey;"
                     tooltiptext="&newButton.tooltip;"
-                    label="&newButton.label;"/>
+                    label="&newButton.label;"
+                    disabled="true"/>
         <xul:toolbarbutton class="style-editor-importButton devtools-toolbarbutton"
                     accesskey="&importButton.accesskey;"
                     tooltiptext="&importButton.tooltip;"
-                    label="&importButton.label;"/>
+                    label="&importButton.label;"
+                    disabled="true"/>
         <xul:spacer flex="1"/>
         <xul:textbox class="splitview-filter devtools-searchinput"
                      type="search" flex="1"
                      tooltiptext="&searchInput.tooltip;"
                      placeholder="&searchInput.placeholder;"/>
       </xul:toolbar>
     </xul:box>
     <xul:box class="splitview-nav-container">
--- a/browser/devtools/styleeditor/test/browser_styleeditor_loading.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_loading.js
@@ -13,16 +13,28 @@ function test()
 
   // launch Style Editor right when the tab is created (before load)
   // this checks that the Style Editor still launches correctly when it is opened
   // *while* the page is still loading
   launchStyleEditorChrome(function (aChrome) {
     isnot(gBrowser.selectedBrowser.contentWindow.document.readyState, "complete",
           "content document is still loading");
 
+    let root = gChromeWindow.document.querySelector(".splitview-root");
+    ok(root.classList.contains("loading"),
+       "style editor root element has 'loading' class name");
+
+    let button = gChromeWindow.document.querySelector(".style-editor-newButton");
+    ok(button.hasAttribute("disabled"),
+       "new style sheet button is disabled");
+
+    button = gChromeWindow.document.querySelector(".style-editor-importButton");
+    ok(button.hasAttribute("disabled"),
+       "import button is disabled");
+
     if (!aChrome.isContentAttached) {
       aChrome.addChromeListener({
         onContentAttach: run
       });
     } else {
       run(aChrome);
     }
   });
@@ -30,10 +42,22 @@ function test()
   content.location = TESTCASE_URI;
 }
 
 function run(aChrome)
 {
   is(aChrome.contentWindow.document.readyState, "complete",
      "content document is complete");
 
+  let root = gChromeWindow.document.querySelector(".splitview-root");
+  ok(!root.classList.contains("loading"),
+     "style editor root element does not have 'loading' class name anymore");
+
+  let button = gChromeWindow.document.querySelector(".style-editor-newButton");
+  ok(!button.hasAttribute("disabled"),
+     "new style sheet button is enabled");
+
+  button = gChromeWindow.document.querySelector(".style-editor-importButton");
+  ok(!button.hasAttribute("disabled"),
+     "import button is enabled");
+
   finish();
 }
--- a/browser/devtools/styleeditor/test/browser_styleeditor_new.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_new.js
@@ -1,14 +1,16 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TESTCASE_URI = TEST_BASE + "simple.html";
 
+const TRANSITION_CLASS = "moz-styleeditor-transitioning";
+
 
 function test()
 {
   waitForExplicitFinish();
 
   addTabAndLaunchStyleEditorChromeWhenLoaded(function (aChrome) {
     aChrome.addChromeListener({
       onContentAttach: run,
@@ -25,16 +27,17 @@ function test()
 function run(aChrome)
 {
   is(aChrome.editors.length, 2,
      "there is 2 stylesheets initially");
 }
 
 let gAddedCount = 0;  // to add new stylesheet after the 2 initial stylesheets
 let gNewEditor;       // to make sure only one new stylesheet got created
+let gUpdateCount = 0; // to make sure only one Update event is triggered
 let gCommitCount = 0; // to make sure only one Commit event is triggered
 
 function testEditorAdded(aChrome, aEditor)
 {
   gAddedCount++;
   if (gAddedCount == 2) {
     waitForFocus(function () { // create a new style sheet
       let newButton = gChromeWindow.document.querySelector(".style-editor-newButton");
@@ -77,16 +80,23 @@ function testEditorAdded(aChrome, aEdito
            "content's background color is initially white");
 
         for each (let c in "body{background-color:red;}") {
           EventUtils.synthesizeKey(c, {}, gChromeWindow);
         }
       }, gChromeWindow) ;
     },
 
+    onUpdate: function (aEditor) {
+      gUpdateCount++;
+
+      ok(content.document.documentElement.classList.contains(TRANSITION_CLASS),
+         "StyleEditor's transition class has been added to content");
+    },
+
     onCommit: function (aEditor) {
       gCommitCount++;
 
       ok(aEditor.hasFlag("new"),
          "new editor still has NEW flag");
       ok(aEditor.hasFlag("unsaved"),
          "new editor has UNSAVED flag after modification");
 
@@ -94,17 +104,21 @@ function testEditorAdded(aChrome, aEdito
       let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
       is(parseInt(ruleCount), 1,
          "new editor shows 1 rule after modification");
 
       let computedStyle = content.getComputedStyle(content.document.body, null);
       is(computedStyle.backgroundColor, "rgb(255, 0, 0)",
          "content's background color has been updated to red");
 
+      ok(!content.document.documentElement.classList.contains(TRANSITION_CLASS),
+         "StyleEditor's transition class has been removed from content");
+
       executeSoon(function () {
+        is(gUpdateCount, 1, "received only one Update event (throttle)");
         is(gCommitCount, 1, "received only one Commit event (throttle)");
 
         aEditor.removeActionListener(listener);
 
         gNewEditor = null;
         finish();
       });
     }
--- a/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js
+++ b/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js
@@ -32,17 +32,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_REPLACED_API_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console-replaced-api.html";
+const TEST_REPLACED_API_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-replaced-api.html";
 
 function test() {
   waitForExplicitFinish();
 
   // First test that the warning does not appear on a normal page (about:blank)
   addTab("about:blank");
   browser.addEventListener("load", function() {
     browser.removeEventListener("load", arguments.callee, true);
--- a/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js
@@ -36,17 +36,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the page's resources are displayed in the console as they're
 // loaded
 
-const TEST_NETWORK_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-network.html" + "?_date=" + Date.now();
+const TEST_NETWORK_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network.html" + "?_date=" + Date.now();
 
 function test() {
   addTab("data:text/html,Web Console basic network logging test");
   browser.addEventListener("load", onLoad, true);
 }
 
 function onLoad(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js
@@ -34,17 +34,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the console object still exists after a page reload.
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", onLoad, false);
 }
 
 function onLoad() {
   browser.removeEventListener("DOMContentLoaded", onLoad, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_580030_errors_after_page_reload.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580030_errors_after_page_reload.js
@@ -35,17 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that errors still show up in the Web Console after a page reload.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-error.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-error.html";
 
 function test() {
   expectUncaughtException();
   addTab(TEST_URI);
   browser.addEventListener("load", onLoad, true);
 }
 
 // see bug 580030: the error handler fails silently after page reload.
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js
@@ -7,17 +7,17 @@
  *  Patrick Walton <pcwalton@mozilla.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that appropriately-localized timestamps are printed.
 
 Cu.import("resource:///modules/HUDService.jsm");
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testTimestamp, false);
 
   function testTimestamp()
   {
     browser.removeEventListener("DOMContentLoaded", testTimestamp, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_581231_close_button.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_581231_close_button.js
@@ -5,17 +5,17 @@
  *
  * Contributor(s):
  *  Patrick Walton <pcwalton@mozilla.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the Web Console close button functions.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testCloseButton, false);
 }
 
 function testCloseButton() {
   browser.removeEventListener("DOMContentLoaded", testCloseButton, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js
@@ -7,17 +7,17 @@
  *  Patrick Walton <pcwalton@mozilla.com>
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the Web Console limits the number of lines displayed according to
 // the user's preferences.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testLineLimit,
                                             false);
 }
 
 function testLineLimit() {
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js
@@ -31,17 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-585956-console-trace.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-585956-console-trace.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("load", tabLoaded, true);
 }
 
 function tabLoaded() {
   browser.removeEventListener("load", tabLoaded, true);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js
@@ -35,17 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that adding text to one of the output labels doesn't cause errors.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testTextNodeInsertion,
                            false);
 }
 
 // Test for bug 588730: Adding a text node to an existing label element causes
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js
@@ -31,21 +31,21 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-593003-iframe-wrong-hud.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html";
 
-const TEST_IFRAME_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-593003-iframe-wrong-hud-iframe.html";
+const TEST_IFRAME_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html";
 
-const TEST_DUMMY_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_DUMMY_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 let tab1, tab2;
 
 function test() {
   addTab(TEST_URI);
   tab1 = tab;
   browser.addEventListener("load", tab1Loaded, true);
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 let tab1, tab2, win1, win2;
 let noErrors = true;
 
 function tab1Loaded(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
 
   win2 = OpenBrowserWindow();
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-network.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network.html";
 
 function tabLoad(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
 
   openConsole();
 
   let hudId = HUDService.getHudIdByWindow(content);
   hud = HUDService.hudReferences[hudId];
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-597756-reopen-closed-tab.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html";
 
 let newTabIsOpen = false;
 
 function tabLoaded(aEvent) {
   gBrowser.selectedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
 
   HUDService.activateHUDForContext(gBrowser.selectedTab);
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-599725-response-headers.sjs";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs";
 
 let lastFinishedRequest = null;
 
 function requestDoneCallback(aHttpRequest)
 {
   lastFinishedRequest = aHttpRequest;
 }
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-600183-charset.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html";
 
 let lastFinishedRequest = null;
 
 function requestDoneCallback(aHttpRequest)
 {
   lastFinishedRequest = aHttpRequest;
 }
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-601177-log-levels.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-601177-log-levels.html";
 
 let msgs;
 
 function onContentLoaded()
 {
   let hudId = HUDService.getHudIdByWindow(content);
   let HUD = HUDService.hudReferences[hudId];
   msgs = HUD.outputNode.querySelectorAll(".hud-msg-node");
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-603750-websocket.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-603750-websocket.html";
 const pref_ws = "network.websocket.enabled";
 const pref_block = "network.websocket.override-security-block";
 
 let errors = 0;
 let lastWindowId = 0;
 let oldPref_ws;
 
 let TestObserver = {
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js
@@ -3,17 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-613013-console-api-iframe.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html";
 
 let TestObserver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   observe: function test_observe(aMessage, aTopic, aData)
   {
     if (aTopic == "console-api-log-event") {
       executeSoon(performTest);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
@@ -2,17 +2,17 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * Contributor(s):
  *   Mihai Sucan <mihai.sucan@gmail.com>
  */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-bug-630733-response-redirect-headers.sjs";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs";
 
 let lastFinishedRequests = {};
 
 function requestDoneCallback(aHttpRequest)
 {
   let status = aHttpRequest.response.status.
                replace(/^HTTP\/\d\.\d (\d+).+$/, "$1");
   lastFinishedRequests[status] = aHttpRequest;
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
@@ -1,17 +1,17 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that network log messages bring up the network panel.
 
-const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-network-request.html";
+const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html";
 
-const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test//test-image.png";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
 
 const TEST_DATA_JSON_CONTENT =
   '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }';
 
 let lastRequest = null;
 let requestCallback = null;
 
 function test()
--- a/browser/devtools/webconsole/test/browser_webconsole_console_extras.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_extras.js
@@ -32,17 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the basic console.log()-style APIs and filtering work.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console-extras.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-extras.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", onLoad, false);
 }
 
 function onLoad() {
   browser.removeEventListener("DOMContentLoaded", onLoad, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js
@@ -35,17 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the message type filter checkboxes work.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded",
                               testLiveFilteringOfMessageTypes, false);
 }
 
 function testLiveFilteringOfMessageTypes() {
--- a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js
@@ -35,17 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the text filter box works.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded",
                            testLiveFilteringOnSearchStrings, false);
 }
 
 function testLiveFilteringOnSearchStrings() {
--- a/browser/devtools/webconsole/test/browser_webconsole_log_node_classes.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_log_node_classes.js
@@ -36,17 +36,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that console logging via the console API produces nodes of the correct
 // CSS classes.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testLogNodeClasses, false);
 }
 
 function testLogNodeClasses() {
   browser.removeEventListener("DOMContentLoaded", testLogNodeClasses,
--- a/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js
@@ -30,17 +30,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", onLoad, false);
 }
 
 function onLoad() {
   browser.removeEventListener("DOMContentLoaded", onLoad, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
@@ -7,19 +7,19 @@
  *  Julian Viereck <jviereck@mozilla.com>
  *  Patrick Walton <pcwalton@mozilla.com>
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that network log messages bring up the network panel.
 
-const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-network-request.html";
+const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html";
 
-const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test//test-image.png";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
 
 const TEST_DATA_JSON_CONTENT =
   '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }';
 
 let lastRequest = null;
 let requestCallback = null;
 
 function test()
--- a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
@@ -36,19 +36,19 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the network panel works.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
-const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test//test-image.png";
-const TEST_ENCODING_ISO_8859_1 = "http://example.com/browser/browser/devtools/webconsole/test//test-encoding-ISO-8859-1.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
+const TEST_ENCODING_ISO_8859_1 = "http://example.com/browser/browser/devtools/webconsole/test/test-encoding-ISO-8859-1.html";
 
 let testDriver;
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testNetworkPanel, false);
 }
 
--- a/browser/devtools/webconsole/test/browser_webconsole_registries.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_registries.js
@@ -36,17 +36,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the HUD service keeps an accurate registry of all the Web Console
 // instances.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-console.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testRegistries, false);
 }
 
 function testRegistries() {
   browser.removeEventListener("DOMContentLoaded", testRegistries, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_view_source.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_view_source.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that source URLs in the Web Console can be clicked to display the
 // standard View Source window.
 
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//test-error.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-error.html";
 
 function test() {
   expectUncaughtException();
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testViewSource, false);
 }
 
 function testViewSource() {
--- a/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html
+++ b/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html
@@ -3,11 +3,11 @@
   <head>
     <title>WebConsole test: iframe associated to the wrong HUD</title>
 <!-- Any copyright is dedicated to the Public Domain.
      http://creativecommons.org/publicdomain/zero/1.0/ -->
    </head>
    <body>
      <p>WebConsole test: iframe associated to the wrong HUD.</p>
      <iframe 
-       src="http://example.com/browser/browser/devtools/webconsole/test//test-bug-593003-iframe-wrong-hud-iframe.html"></iframe>
+       src="http://example.com/browser/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html"></iframe>
    </body>
  </html>
--- a/browser/devtools/webconsole/test/test-network-request.html
+++ b/browser/devtools/webconsole/test/test-network-request.html
@@ -22,14 +22,14 @@
         makeXhr('post', 'test-data.json', "Hello world!", aCallback);
       }
     // --></script>
   </head>
   <body>
     <h1>Heads Up Display HTTP Logging Testpage</h1>
     <h2>This page is used to test the HTTP logging.</h2>
 
-    <form action="http://example.com/browser/browser/devtools/webconsole/test//test-network-request.html" method="post">
+    <form action="http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html" method="post">
       <input name="name" type="text" value="foo bar"><br>
       <input name="age" type="text" value="144"><br>
     </form>
   </body>
 </html>
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -87,16 +87,20 @@ endif
 
 include $(topsrcdir)/ipc/app/defs.mk
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 ifneq (,$(filter aurora beta,$(MOZ_UPDATE_CHANNEL)))
 DEFINES += -DSHIP_FEEDBACK=1
 endif
 
+ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
+DEFINES += -DMOZ_SHARED_MOZGLUE=1
+endif
+
 ifdef MOZ_PKG_MANIFEST_P
 MOZ_PKG_MANIFEST = package-manifest
 
 $(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS)
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@
 
 GARBAGE += $(MOZ_PKG_MANIFEST)
 endif
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -44,17 +44,19 @@
 #ifndef MOZ_STATIC_JS
 @BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
 #endif
 @BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
+#ifdef MOZ_SHARED_MOZGLUE
 @BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
+#endif
 #ifdef XP_MACOSX
 @BINPATH@/XUL
 #else
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 @BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -927,16 +927,18 @@ xpicleanup@BIN_SUFFIX@
   components/nsTelephonyWorker.js
   components/Telephony.manifest
   components/Telephony.js
   components/nsWifiWorker.js
   components/nsWifiWorker.manifest
 #endif
   components/txEXSLTRegExFunctions.js
   components/Weave.js
+  components/Webapps.js
+  components/Webapps.manifest
   components/WebContentConverter.js
   defaults/autoconfig/platform.js
   defaults/autoconfig/prefcalls.js
   defaults/pref/firefox-branding.js
   defaults/pref/firefox.js
   defaults/pref/firefox-l10n.js
   defaults/pref/services-sync.js
   defaults/profile/bookmarks.html
@@ -1052,16 +1054,17 @@ xpicleanup@BIN_SUFFIX@
   modules/services-sync/type_records/passwords.js
   modules/services-sync/type_records/prefs.js
   modules/services-sync/type_records/tabs.js
   modules/services-sync/util.js
   modules/stylePanel.jsm
   modules/tabview/AllTabs.jsm
   modules/tabview/groups.jsm
   modules/tabview/utils.jsm
+  modules/Webapps.jsm
   modules/WindowDraggingUtils.jsm
   #ifdef XP_WIN
     modules/WindowsJumpLists.jsm
     modules/WindowsPreviewPerTab.jsm
   #endif
   modules/XPCOMUtils.jsm
   modules/XPIProvider.jsm
   res/contenteditable.css
@@ -1142,16 +1145,17 @@ xpicleanup@BIN_SUFFIX@
   components/content_xslt.xpt
   components/content_xtf.xpt
   components/contentprefs.xpt
   components/cookie.xpt
   components/crashreporter.xpt
   components/directory.xpt
   components/docshell.xpt
   components/dom.xpt
+  components/dom_apps.xpt
   components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
   components/dom_telephony.xpt
   components/dom_wifi.xpt
   components/dom_system_b2g.xpt
 #endif
   components/dom_canvas.xpt
   components/dom_core.xpt
--- a/browser/themes/gnomestripe/devtools/splitview.css
+++ b/browser/themes/gnomestripe/devtools/splitview.css
@@ -36,16 +36,22 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 .splitview-nav-container {
   background-color: hsl(208,11%,27%);
   color: white;
 }
 
+.loading .splitview-nav-container {
+  background-image: url(chrome://global/skin/icons/loading_16.png);
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+
 .splitview-nav {
   -moz-appearance: none;
   margin: 0;
   box-shadow: inset -1px 0 0 #222426;
 }
 
 .splitview-nav > li {
   color: white;
@@ -65,17 +71,16 @@
 
 .splitview-nav > li {
   outline: 0;
   vertical-align: bottom;
 }
 
 .placeholder {
   -moz-box-flex: 1;
-  -moz-box-back: center;
   text-align: center;
 }
 
 .splitview-nav > li.splitview-active {
   background-image: url(itemArrow-ltr.png),
                     -moz-linear-gradient(left, black, black),
                     -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%));
   background-repeat: no-repeat, no-repeat, repeat-x;
--- a/browser/themes/gnomestripe/devtools/styleeditor.css
+++ b/browser/themes/gnomestripe/devtools/styleeditor.css
@@ -31,16 +31,20 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#style-editor-chrome {
+  background-color: hsl(208,11%,27%);
+}
+
 .stylesheet-title,
 .stylesheet-name {
   text-decoration: none;
   color: hsl(207,17%,88%);
 }
 
 .stylesheet-name {
   font-size: 13px;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2527df6e72b5c80b91e180af9644ba96a5c148d6
GIT binary patch
literal 2552
zc$@+F2?zFxP)<h;3K|Lk000e1NJLTq001HY001)x1^@s6^3B@(00001b5ch_0Itp)
z=>Px#32;bRa{vGf6951U69E94oEQKA37ttqK~z}7?U`F_9Mu`e|8w1)*`1xe#PRwb
zU)F4FCw7c#CxD=l;(`e63&B*XAkITy`a(e!uN5!t6GBy=s!|b9i$sNFpiO8Jz`@|y
z-oV;UoMOk`Bn~!a?cLeSOuXLRnK^y1cky*IG^x}F&dX{?=lkt{&iT&w{f`a&F#gNY
z-{0TyzvNR^CVlwfhd&ksVIZH+pYG}DId!-By}iBrIga~fHk*Cr-FM$j6`nu+^wWaf
zZvUOG>u<mF&O4Vk#?V%TNRpJSsi{GAb#>psz`z@&=05k_bFD2cEoZvAx?XH-Z2Vhq
zZ?6LYPMkQw*4Nknxx2gj*9Q(9_-9{VU)RPs)`}2O6kqUqy<ivy48!yd3=H7t(W5)A
zOjA?SuO5B$(fW#t3e3*V9%os$|K!P&C;fi^AC4S3@=P!oL@XBDOVjjA0Diu!koVtz
ze;>mzeT0y4LdZpz%k`Su?e4SN?cjMHe!m~4Y4%;XaN*6Ko}P<a<9$BgZ!0S+8)|E7
zpK!a~;Ca4hZf<V0va+(Ky}cbipAQ_zUD~r}&u_Nn2r<oKu6!~u&>_omn5JnELLkdB
z_U_#aQ50bq#`x;$>Pw2ExEB`}FCIC3I0*n0O_Pn#GiT0-4?g(dKRh1KQB_qbRaN11
zI^lA;kWQzE$H&Ki+SAh$zw1`qxN)N|9*>h`GD%ieR*0_aWMyS#Y<_;;ZS@qKKY!jG
zi^b-2T_?J(6T>iwq9{urfBf;@o#yYDtPKqfrzwhh#p!fH5Cj;80Yy<>tgfz3S`qR5
z^Uu>aZ{GY<I-RZp0ES@z0II6`Zr!@|ms6)s36_Km4i0vxs`^4cpT9^5K`xg=GMThg
zM^2nLA^H9Ox2meDdYw)uLs1k6AqoIE91gmws_LnVii*EK`|Pv6l0wd&J=-A&!hmU-
z?+Jo%R8`eehG76eyA>hz_4U7h=%I&x(b3TXS(cGbr$-kS7JigWCeKNdgo6hU;^BuM
zeyX9N;g7otIeYeOhtKC5kY)M3`uh4)03gfq=~OCp)HKaEtq7^Bt9v^b490vuAJXac
zrSb9cr)p|yZiK_(XA+6Tzr0>Ag2CXO`uh6QyFx}rMiSSrUw`dh%k|LEP<JE}dF%Z7
z^ZqR_>WM@me+`8~JtYC*aCqMjUG@KEPyo=`*~#-f|1*YRyjBDA`TTe&6bco--z$Ua
z?Cg{)Dk>h6W%*T}=bI?Xk~4s=>&u#^o$l}NfBAkesKbX3Khe<8@Vdw2sbbmPo3WxO
z@Or;{S<^J3sw$$<Xm=u!@LFMP9UB=mMNtgT^Cbb%XcXtpox||(@OK4>ronL>Se7l@
z%1EVB_~MH%kjv#ZaSX%2<;#~5i^aAvXaKm|Qrc`bIGqxfmX<I&I=XYRtuvCzBtHA>
zbKJT$hvDH7=(-L7AcP<k3Sn;UHim|ViekQ(Lz|tAz-F_-;cy}vjqWN203wkapeU-)
z^6~lSL&#(@xOC|fmX~92xm@5l9y2quDCy8NO+zFSf!FIrd3ia;#>TL;v<!#C0h*>E
ziVl4H?YD?VqmU$Nn~=7)R!|g>N~OUt3^Yx{#fzUp*L8@Z2!>(c@wm~})>c|bKA*?T
z%q%DhAOx`4cnE?Bnx^4!IMCG8h-@|skH=G7_O094-rkOhi7QB_(+~s!rfGubc`ytE
zr_+gp2M>Vf`ORBH)AXhU@pwGw?(Tvlxgg6jM9~43Wg&_JIy&0n@p$0(`-`Bh@df{J
z;6NKVjswFmg@gpdFguC>0NON7vh`t2O${0w8;Srz2pSt3!ExM9M{rv_Ap~P%W5{GO
zn-V#j&Em^1zr?z&xO=iD5(z{iHz3O{5JF%W1`>&+)oO{6kr70rOQ0wU6h)zMtSO2@
zJRZl;&=9iOY-u5iqF``v5as22ap=$?G&cu82tg{9vLs|;Vgk#{F$jVHhGF1vIMCU7
z2(m1LVHnu$0#d0o!r}1l$+{-uGt|}9p}l?0kX2Sz!e+B!haK3>p+QwO0N9k6ZEdZX
zoV<o)G6{!6L_<U4?m|BObP$0+)3&4K^Z6{7ZJ*DFLx(yrKR=H^AW%$9mSxe}+Jfon
zY54sW*t2IdlQj%u*)WWpX`1}wkN*UsD1NVAVVb647=}_{&@>IV+YPsS`^|&nxNR?4
zV6dT3C{$ft{WileeH_POb#?Ww0tg{6O%s}?-OgsS!=X?pwUJ?^`)*|vBc6Qn$u5rL
zI%t}<1krU}SzTTI;G>T|%H0nJ4FJcE9ph=5uC?kT*5Bs#MiKYQppG3oCTp7Zm?(;`
zavaxWby*F=Sk7cJr-z1yUcMg;>iF^FPpq!4zV387s|r`coklvHhRfyJlw_Gq28l$X
zyR59tYlX2>vKJUMP16j^vLykEqF{71gvrUtO~z=wf0S)yXqtwpsi|#E(J%~5O-&Vx
z<0gg`W5jVBY&IL>aRt||{kx<w(liZMu3W)4-z;Ksa<bT02qF0DtFN%QxQHuPu5PQ;
zmW<K-{K5t?v0cRgz{0`;Ow)uQ*pW`Fn3$MAHk-xd<Rla&0lVD}ilXrK*Yl<QNG6lP
z!omV1NrKnw#r5kmP?R`$-Ugbc!Sgo6VlgO60uG0`)1Ne8ngpt<f}&{LxwC?BI1F9a
z!Sg(5nua8a2n3o+3(<8Qw{L%4G)64Tg6DZq6a_)Bqqepd`FtKOm$YL$=Qs`zJkX4(
zscC4M2A=2Fjgbu$MZw{4pt-pj9LJX48cCAS+S&rU-3~zzV6&~QgdhkA27_?9T=4mP
z*y#GVnj@N~(cByW$8p7kT>E6!pR?BdNO^fVs;g_jFbvkJBtdO$4R*V7Y&A!O5KK>B
z-{v`Txg4gZrmPzyRaLRDFkdvsg*~@;d&9MB*AS1#izn$jV?-mFOyTO)tH|f`rG==f
zim|bAc)dRC-yg)jeRUv&K-2D65;8j*fubaec_oS>T3Yr)k|a<R1&-sOsw$?Zr*}`*
zH4$SdFZZLlIRF4CD=P!f^B}~UF{-HWLsiot1aLYX2n5!0B@k%B%*-s(=`?uWhRVvy
z?LrDa5)O}{y1ELDjho$*EX$U9M`3O-7(_H0MQv?u(Qq>igQliN+`M@UWo3J|`4v{z
z^<~pEbA%ASySoc^yZw9h3POmX>$*~4P!t78l6Jg&u`Ii-eiRrK06g-@BX2mJ&OU}=
zV6}~}H>}&KRO(<j98TRUqZrZE)z!suoaO(?7>1$ba=8z};c)JLF#ZGF^_>(SrRH7$
O0000<MNUMnLSTaa5%5U>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..389f689aa2a7611f53977594c048f79c4991affd
GIT binary patch
literal 1538
zc$@(O2L1VoP)<h;3K|Lk000e1NJLTq001BW001Ni1^@s6=<7J*00001b5ch_0Itp)
z=>Px#32;bRa{vGf6951U69E94oEQKA1*b_wK~z}7z1Lk#Q)e8<@o%-;l_RE+GhM_8
z&Z*1|BRcVpq)WWhXf)~+B`Co`d;xW!BVJ5kIGwy`!52``xw)t_CD}4`B+G6vOo(iX
zAqGoCN3E_gn~4eZ{GVOW9(rnfS}x{EPSW4gp8lWbJkL3wb8G-7F1F?XH@0n9?j>wH
zak13_tlYL?d9&;MH5F<v+O*OZFO$I5_>H^6-f+R4E27Q<y$u)K&cd7(UVw%RZik4v
z4rDf5a8DA^O$RHbEHi-X{I$7&8<-8)fMK8?SO=UGku1B2{xi@Aqyz28TYhi?!y@{1
zAQN~9v?`@)$J2ph=dPBDNEI+4tocn~9?%nNumRMaxjYs46_^9`0x!dgXYb5g<6#_I
z-I>dCfxE%t1Hjgud28D1&Ros{egobxbpYV#=}Y0AAXL00f1L-Qw)uNwh`Y9|wOM7Q
z)V<(H2a30@OAWQxG+pWdvcfxS4}H+}z%cM4?7J7iGXa2zm_})pm8kcEAJ>Q4zCQVF
zhv<?OdA95T)vgwYuAAokWoS)QyIP!OMVq}UqM%h4k%<6%Kh3!rYTI4#$<k=kWvi-h
zb^zhUvx6N7UlY##JGOWeT?5swmXYA#J}xWT+-~(-yXdkuym)zWz6YS9=5%(j6X`(i
zp@x<(LkE=>Znhn2Xi>4U9?<^)J_ODIDUn61>d!d#@5u85OeinTZxkiFMTt=ypu9NW
zD@w9O$-eU9{AwjaXb+w8SXqhWDG{YardQTBJ+7>6S_M#9+qAK=wrNO-JgKa0sxa2T
zfs%rw(N52Sk^(PKoyc_`o<HBUwd-KbslC8q;2q%V!J1QuGS-O#{xV&L|Ht;l(UVy~
zV{jVZ1pW@*A4(3C6m%IKNNe-w05={ibC?!dTASYitbDM{(VW)iH-`9NnZp(@C(^-p
ze|g?vPiyn%0%w8Vv^Kvp)QMp6>p*5&n|~4!mtEXE`XAO7=#phuy4ix%pPo8_VP(EA
zv?37}=n?mUh@ASPuT%vBiCK{99<sE+vtrt~ESTvYdc}f)71P>hx`$$0F!Rb_R0{@H
zr+9+j8*@CcI>ly{1q=%wu1+y5m~mw=wgqZ<#L@y4h<F~b$f91gVET8S4jBnVw_wJ(
zK8G3}iE6=&bA8T-xpTY(0_GzvvJy2B;PIx}h6Rt-r$)CR<@B9|EEvq6pRfhfn(rAF
z3~iZbZ2=>?$%4Vc3=cp`LyyUVl%~6e1%q4Px1}`QRk89&91EtNyyNf|%pbL2urQ-h
z>H2P^>qc>a!NLr$()Dbm>-z=^GpY&b7&~B<C7|a?Kvxpbr)#dB$C|5W6@cdI*{HdC
zh9sar(Of-a7ChR%FscQQwl5sBAkK9ko_$3Nx{~X<O%^2Ab%!t1*JHtynp-g~cvie<
z%mU5Tp99?R70og&G|koT09N{nW;JWBel<42S+;mNkq*Ay=;^R)u71M;&DHM=bs|{&
zI*_Tk`X>?j+#fHG{)eRnN+ipU5|ahm@%v6-7$s&4BHjy75%@&p<YV_sRif_&T793T
z1->0~#$`crecvk<Jl!#;J-NOwwgp;UZ&V9>JJUVE@5knNXS&TQiyE`w*{*cMf+@AV
zu`NK?EiD+&^FTBU97q4`5YeMspdGpGK%&1FXh&{4eR~#o<ITA#2QBdL$uKPNmwXW2
z0_|{DLKgV;W+rUG<gdC73!Z<rFpdRcelPHqE*_opL%*9W&<=MS7Wnoqv}uRCRjfR$
zi=_pVt8Y1;mn|B#z*oAs5hc4(ViX7Pl`i(8BpW6Be5H%4QG&6DPI-(hB6%XBL}YqW
zRp;ZRs?JpaNmZR2ld3w0MC3_QRp*!mzOp4zE%22sF)SF*8u(}bM_ox3H%%5KRoo0;
osISL@w<<bfTJUfA(k_7i0M-VmrtThlf&c&j07*qoM6N<$f_IMEO8@`>
--- a/browser/themes/pinstripe/devtools/splitview.css
+++ b/browser/themes/pinstripe/devtools/splitview.css
@@ -36,16 +36,22 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 .splitview-nav-container {
   background-color: hsl(208,11%,27%);
   color: white;
 }
 
+.loading .splitview-nav-container {
+  background-image: url(chrome://global/skin/icons/loading_16.png);
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+
 .splitview-nav {
   -moz-appearance: none;
   margin: 0;
   box-shadow: inset -1px 0 0 #222426;
 }
 
 .splitview-nav > li {
   color: white;
@@ -65,17 +71,16 @@
 
 .splitview-nav > li {
   outline: 0;
   vertical-align: bottom;
 }
 
 .placeholder {
   -moz-box-flex: 1;
-  -moz-box-back: center;
   text-align: center;
 }
 
 .splitview-nav > li.splitview-active {
   background-image: url(itemArrow-ltr.png),
                     -moz-linear-gradient(left, black, black),
                     -moz-linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%));
   background-repeat: no-repeat, no-repeat, repeat-x;
--- a/browser/themes/pinstripe/devtools/styleeditor.css
+++ b/browser/themes/pinstripe/devtools/styleeditor.css
@@ -31,16 +31,20 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#style-editor-chrome {
+  background-color: hsl(208,11%,27%);
+}
+
 .stylesheet-title,
 .stylesheet-name {
   text-decoration: none;
   color: hsl(207,17%,88%);
 }
 
 .stylesheet-name {
   font-size: 13px;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2527df6e72b5c80b91e180af9644ba96a5c148d6
GIT binary patch
literal 2552
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
O0000<MNUMnLSTaa5%5U>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..75d6f13d8c6e6a1cfc0d5766cfec91378e0b60c0
GIT binary patch
literal 1568
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
Su_w;}0000<MNUMnLSTY9P~RW`
--- a/browser/themes/winstripe/devtools/splitview.css
+++ b/browser/themes/winstripe/devtools/splitview.css
@@ -36,16 +36,22 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 .splitview-nav-container {
   background-color: hsl(211,21%,26%);
   color: white;
 }
 
+.loading .splitview-nav-container {
+  background-image: url(chrome://global/skin/icons/loading_16.png);
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+
 .splitview-nav {
   -moz-appearance: none;
   margin: 0;
   box-shadow: inset -1px 0 0 #222426;
 }
 
 .splitview-nav > li {
   color: white;
@@ -65,17 +71,16 @@
 
 .splitview-nav > li {
   outline: 0;
   vertical-align: bottom;
 }
 
 .placeholder {
   -moz-box-flex: 1;
-  -moz-box-back: center;
   text-align: center;
 }
 
 .splitview-nav > li.splitview-active {
   background-image: url(itemArrow-ltr.png),
                     -moz-linear-gradient(left, black, black),
                     -moz-linear-gradient(hsl(200,100%,33%), hsl(200,100%,25%));
   background-repeat: no-repeat, no-repeat, repeat-x;
--- a/browser/themes/winstripe/devtools/styleeditor.css
+++ b/browser/themes/winstripe/devtools/styleeditor.css
@@ -31,16 +31,20 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#style-editor-chrome {
+  background-color: hsl(211,21%,26%);
+}
+
 .stylesheet-title,
 .stylesheet-name {
   text-decoration: none;
   color: hsl(210,30%,85%);
 }
 
 .stylesheet-name {
   font-size: 13px;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2527df6e72b5c80b91e180af9644ba96a5c148d6
GIT binary patch
literal 2552
zc$@+F2?zFxP)<h;3K|Lk000e1NJLTq001HY001)x1^@s6^3B@(00001b5ch_0Itp)
z=>Px#32;bRa{vGf6951U69E94oEQKA37ttqK~z}7?U`F_9Mu`e|8w1)*`1xe#PRwb
zU)F4FCw7c#CxD=l;(`e63&B*XAkITy`a(e!uN5!t6GBy=s!|b9i$sNFpiO8Jz`@|y
z-oV;UoMOk`Bn~!a?cLeSOuXLRnK^y1cky*IG^x}F&dX{?=lkt{&iT&w{f`a&F#gNY
z-{0TyzvNR^CVlwfhd&ksVIZH+pYG}DId!-By}iBrIga~fHk*Cr-FM$j6`nu+^wWaf
zZvUOG>u<mF&O4Vk#?V%TNRpJSsi{GAb#>psz`z@&=05k_bFD2cEoZvAx?XH-Z2Vhq
zZ?6LYPMkQw*4Nknxx2gj*9Q(9_-9{VU)RPs)`}2O6kqUqy<ivy48!yd3=H7t(W5)A
zOjA?SuO5B$(fW#t3e3*V9%os$|K!P&C;fi^AC4S3@=P!oL@XBDOVjjA0Diu!koVtz
ze;>mzeT0y4LdZpz%k`Su?e4SN?cjMHe!m~4Y4%;XaN*6Ko}P<a<9$BgZ!0S+8)|E7
zpK!a~;Ca4hZf<V0va+(Ky}cbipAQ_zUD~r}&u_Nn2r<oKu6!~u&>_omn5JnELLkdB
z_U_#aQ50bq#`x;$>Pw2ExEB`}FCIC3I0*n0O_Pn#GiT0-4?g(dKRh1KQB_qbRaN11
zI^lA;kWQzE$H&Ki+SAh$zw1`qxN)N|9*>h`GD%ieR*0_aWMyS#Y<_;;ZS@qKKY!jG
zi^b-2T_?J(6T>iwq9{urfBf;@o#yYDtPKqfrzwhh#p!fH5Cj;80Yy<>tgfz3S`qR5
z^Uu>aZ{GY<I-RZp0ES@z0II6`Zr!@|ms6)s36_Km4i0vxs`^4cpT9^5K`xg=GMThg
zM^2nLA^H9Ox2meDdYw)uLs1k6AqoIE91gmws_LnVii*EK`|Pv6l0wd&J=-A&!hmU-
z?+Jo%R8`eehG76eyA>hz_4U7h=%I&x(b3TXS(cGbr$-kS7JigWCeKNdgo6hU;^BuM
zeyX9N;g7otIeYeOhtKC5kY)M3`uh4)03gfq=~OCp)HKaEtq7^Bt9v^b490vuAJXac
zrSb9cr)p|yZiK_(XA+6Tzr0>Ag2CXO`uh6QyFx}rMiSSrUw`dh%k|LEP<JE}dF%Z7
z^ZqR_>WM@me+`8~JtYC*aCqMjUG@KEPyo=`*~#-f|1*YRyjBDA`TTe&6bco--z$Ua
z?Cg{)Dk>h6W%*T}=bI?Xk~4s=>&u#^o$l}NfBAkesKbX3Khe<8@Vdw2sbbmPo3WxO
z@Or;{S<^J3sw$$<Xm=u!@LFMP9UB=mMNtgT^Cbb%XcXtpox||(@OK4>ronL>Se7l@
z%1EVB_~MH%kjv#ZaSX%2<;#~5i^aAvXaKm|Qrc`bIGqxfmX<I&I=XYRtuvCzBtHA>
zbKJT$hvDH7=(-L7AcP<k3Sn;UHim|ViekQ(Lz|tAz-F_-;cy}vjqWN203wkapeU-)
z^6~lSL&#(@xOC|fmX~92xm@5l9y2quDCy8NO+zFSf!FIrd3ia;#>TL;v<!#C0h*>E
ziVl4H?YD?VqmU$Nn~=7)R!|g>N~OUt3^Yx{#fzUp*L8@Z2!>(c@wm~})>c|bKA*?T
z%q%DhAOx`4cnE?Bnx^4!IMCG8h-@|skH=G7_O094-rkOhi7QB_(+~s!rfGubc`ytE
zr_+gp2M>Vf`ORBH)AXhU@pwGw?(Tvlxgg6jM9~43Wg&_JIy&0n@p$0(`-`Bh@df{J
z;6NKVjswFmg@gpdFguC>0NON7vh`t2O${0w8;Srz2pSt3!ExM9M{rv_Ap~P%W5{GO
zn-V#j&Em^1zr?z&xO=iD5(z{iHz3O{5JF%W1`>&+)oO{6kr70rOQ0wU6h)zMtSO2@
zJRZl;&=9iOY-u5iqF``v5as22ap=$?G&cu82tg{9vLs|;Vgk#{F$jVHhGF1vIMCU7
z2(m1LVHnu$0#d0o!r}1l$+{-uGt|}9p}l?0kX2Sz!e+B!haK3>p+QwO0N9k6ZEdZX
zoV<o)G6{!6L_<U4?m|BObP$0+)3&4K^Z6{7ZJ*DFLx(yrKR=H^AW%$9mSxe}+Jfon
zY54sW*t2IdlQj%u*)WWpX`1}wkN*UsD1NVAVVb647=}_{&@>IV+YPsS`^|&nxNR?4
zV6dT3C{$ft{WileeH_POb#?Ww0tg{6O%s}?-OgsS!=X?pwUJ?^`)*|vBc6Qn$u5rL
zI%t}<1krU}SzTTI;G>T|%H0nJ4FJcE9ph=5uC?kT*5Bs#MiKYQppG3oCTp7Zm?(;`
zavaxWby*F=Sk7cJr-z1yUcMg;>iF^FPpq!4zV387s|r`coklvHhRfyJlw_Gq28l$X
zyR59tYlX2>vKJUMP16j^vLykEqF{71gvrUtO~z=wf0S)yXqtwpsi|#E(J%~5O-&Vx
z<0gg`W5jVBY&IL>aRt||{kx<w(liZMu3W)4-z;Ksa<bT02qF0DtFN%QxQHuPu5PQ;
zmW<K-{K5t?v0cRgz{0`;Ow)uQ*pW`Fn3$MAHk-xd<Rla&0lVD}ilXrK*Yl<QNG6lP
z!omV1NrKnw#r5kmP?R`$-Ugbc!Sgo6VlgO60uG0`)1Ne8ngpt<f}&{LxwC?BI1F9a
z!Sg(5nua8a2n3o+3(<8Qw{L%4G)64Tg6DZq6a_)Bqqepd`FtKOm$YL$=Qs`zJkX4(
zscC4M2A=2Fjgbu$MZw{4pt-pj9LJX48cCAS+S&rU-3~zzV6&~QgdhkA27_?9T=4mP
z*y#GVnj@N~(cByW$8p7kT>E6!pR?BdNO^fVs;g_jFbvkJBtdO$4R*V7Y&A!O5KK>B
z-{v`Txg4gZrmPzyRaLRDFkdvsg*~@;d&9MB*AS1#izn$jV?-mFOyTO)tH|f`rG==f
zim|bAc)dRC-yg)jeRUv&K-2D65;8j*fubaec_oS>T3Yr)k|a<R1&-sOsw$?Zr*}`*
zH4$SdFZZLlIRF4CD=P!f^B}~UF{-HWLsiot1aLYX2n5!0B@k%B%*-s(=`?uWhRVvy
z?LrDa5)O}{y1ELDjho$*EX$U9M`3O-7(_H0MQv?u(Qq>igQliN+`M@UWo3J|`4v{z
z^<~pEbA%ASySoc^yZw9h3POmX>$*~4P!t78l6Jg&u`Ii-eiRrK06g-@BX2mJ&OU}=
zV6}~}H>}&KRO(<j98TRUqZrZE)z!suoaO(?7>1$ba=8z};c)JLF#ZGF^_>(SrRH7$
O0000<MNUMnLSTaa5%5U>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..33bb4a320e76cc7a346ca4beb60e89a85a48aa2c
GIT binary patch
literal 1704
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
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -1994,34 +1994,37 @@ nsresult nsHTMLMediaElement::InitializeD
     return NS_ERROR_FAILURE;
   nsRefPtr<nsMediaDecoder> decoder = aOriginal->Clone();
   if (!decoder)
     return NS_ERROR_FAILURE;
 
   LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
 
   if (!decoder->Init(this)) {
+    LOG(PR_LOG_DEBUG, ("%p Failed to init cloned decoder %p", this, decoder.get()));
     return NS_ERROR_FAILURE;
   }
 
   double duration = aOriginal->GetDuration();
   if (duration >= 0) {
     decoder->SetDuration(duration);
     decoder->SetSeekable(aOriginal->IsSeekable());
   }
 
   nsMediaStream* stream = originalStream->CloneData(decoder);
   if (!stream) {
+    LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
     return NS_ERROR_FAILURE;
   }
 
   mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
 
   nsresult rv = decoder->Load(stream, nsnull, aOriginal);
   if (NS_FAILED(rv)) {
+    LOG(PR_LOG_DEBUG, ("%p Failed to load decoder/stream for decoder %p", this, decoder.get()));
     return rv;
   }
 
   return FinishDecoderSetup(decoder);
 }
 
 nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
                                                          nsIStreamListener **aListener)
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -188,16 +188,17 @@ nsresult nsBuiltinDecoder::Load(nsMediaS
   {
     // Hold the lock while we do this to set proper lock ordering
     // expectations for dynamic deadlock detectors: decoder lock(s)
     // should be grabbed before the cache lock
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
     nsresult rv = aStream->Open(aStreamListener);
     if (NS_FAILED(rv)) {
+      LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
       delete aStream;
       return rv;
     }
 
     mStream = aStream;
   }
 
   mDecoderStateMachine = CreateStateMachine();
@@ -240,29 +241,31 @@ nsresult nsBuiltinDecoder::RequestFrameB
   return res;
 }
 
 nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   NS_ASSERTION(mDecoderStateMachine,
                "Must have state machine to start state machine thread");
+  NS_ENSURE_STATE(mDecoderStateMachine);
 
   if (mShuttingDown)
     return NS_OK;
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   nsBuiltinDecoderStateMachine* m =
     static_cast<nsBuiltinDecoderStateMachine*>(mDecoderStateMachine.get());
   return m->ScheduleStateMachine();
 }
 
 nsresult nsBuiltinDecoder::Play()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  NS_ASSERTION(mDecoderStateMachine != nsnull, "Should have state machine.");
   nsresult res = ScheduleStateMachineThread();
   NS_ENSURE_SUCCESS(res,res);
   if (mPlayState == PLAY_STATE_SEEKING) {
     mNextState = PLAY_STATE_PLAYING;
     return NS_OK;
   }
   if (mPlayState == PLAY_STATE_ENDED)
     return Seek(0);
@@ -827,39 +830,29 @@ void nsBuiltinDecoder::ChangeState(PlayS
   }
 
   if (mPlayState == PLAY_STATE_SHUTDOWN) {
     mReentrantMonitor.NotifyAll();
     return;
   }
 
   mPlayState = aState;
-  switch (aState) {
-  case PLAY_STATE_PAUSED:
-    /* No action needed */
-    break;
-  case PLAY_STATE_PLAYING:
-    mDecoderStateMachine->Play();
-    break;
-  case PLAY_STATE_SEEKING:
-    mDecoderStateMachine->Seek(mRequestedSeekTime);
-    mRequestedSeekTime = -1.0;
-    break;
-  case PLAY_STATE_LOADING:
-    /* No action needed */
-    break;
-  case PLAY_STATE_START:
-    /* No action needed */
-    break;
-  case PLAY_STATE_ENDED:
-    /* No action needed */
-    break;
-  case PLAY_STATE_SHUTDOWN:
-    /* No action needed */
-    break;
+  if (mDecoderStateMachine) {
+    switch (aState) {
+    case PLAY_STATE_PLAYING:
+      mDecoderStateMachine->Play();
+      break;
+    case PLAY_STATE_SEEKING:
+      mDecoderStateMachine->Seek(mRequestedSeekTime);
+      mRequestedSeekTime = -1.0;
+      break;
+    default:
+      /* No action needed */
+      break;
+    }
   }
   mReentrantMonitor.NotifyAll();
 }
 
 void nsBuiltinDecoder::PlaybackPositionChanged()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mShuttingDown)
@@ -968,17 +961,19 @@ void nsBuiltinDecoder::Suspend()
 void nsBuiltinDecoder::Resume(bool aForceBuffering)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mStream) {
     mStream->Resume();
   }
   if (aForceBuffering) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mDecoderStateMachine->StartBuffering();
+    if (mDecoderStateMachine) {
+      mDecoderStateMachine->StartBuffering();
+    }
   }
 }
 
 void nsBuiltinDecoder::StopProgressUpdates()
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
   GetReentrantMonitor().AssertCurrentThreadIn();
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -40,16 +40,17 @@
 #include "nsAudioStream.h"
 #include "nsTArray.h"
 #include "nsBuiltinDecoder.h"
 #include "nsBuiltinDecoderReader.h"
 #include "nsBuiltinDecoderStateMachine.h"
 #include "mozilla/mozalloc.h"
 #include "VideoUtils.h"
 #include "nsTimeRanges.h"
+#include "nsDeque.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/StdInt.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 
 #ifdef PR_LOGGING
@@ -224,35 +225,47 @@ public:
   // Return the global state machine thread. Call from any thread.
   nsIThread* GetGlobalStateMachineThread()
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     NS_ASSERTION(mStateMachineThread, "Should have non-null state machine thread!");
     return mStateMachineThread;
   }
 
+  // Requests that a decode thread be created for aStateMachine. The thread
+  // may be created immediately, or after some delay, once a thread becomes
+  // available. The request can be cancelled using CancelCreateDecodeThread().
+  // It's the callers responsibility to not call this more than once for any
+  // given state machine.
+  nsresult RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
+
+  // Cancels a request made by RequestCreateDecodeThread to create a decode
+  // thread for aStateMachine.
+  nsresult CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
+
   // Maximum number of active decode threads allowed. When more
   // than this number are active the thread creation will fail.
   static const PRUint32 MAX_DECODE_THREADS = 25;
 
   // Returns the number of active decode threads.
   // Call on any thread. Holds the internal monitor so don't
   // call with any other monitor held to avoid deadlock.
   PRUint32 GetDecodeThreadCount();
 
-  // Keep track of the fact that a decode thread was created.
-  // Call on any thread. Holds the internal monitor so don't
-  // call with any other monitor held to avoid deadlock.
-  void NoteDecodeThreadCreated();
-
   // Keep track of the fact that a decode thread was destroyed.
   // Call on any thread. Holds the internal monitor so don't
   // call with any other monitor held to avoid deadlock.
   void NoteDecodeThreadDestroyed();
 
+#ifdef DEBUG
+  // Returns true if aStateMachine has a pending request for a
+  // decode thread.
+  bool IsQueued(nsBuiltinDecoderStateMachine* aStateMachine);
+#endif
+
 private:
   // Holds global instance of StateMachineTracker.
   // Writable on main thread only.
   static StateMachineTracker* mInstance;
 
   // Reentrant monitor that must be obtained to access
   // the decode thread count member and methods.
   ReentrantMonitor mMonitor;
@@ -266,16 +279,20 @@ private:
   // currently instantiated. Access only with the
   // mMonitor lock held. Can be used from any thread.
   PRUint32 mDecodeThreadCount;
 
   // Global state machine thread. Write on the main thread
   // only, read from the decoder threads. Synchronized via
   // the mMonitor.
   nsIThread* mStateMachineThread;
+
+  // Queue of state machines waiting for decode threads. Entries at the front
+  // get their threads first.
+  nsDeque mPending;
 };
 
 StateMachineTracker* StateMachineTracker::mInstance = nsnull;
 
 StateMachineTracker& StateMachineTracker::Instance()
 {
   if (!mInstance) {
     NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@@ -291,57 +308,119 @@ void StateMachineTracker::EnsureGlobalSt
   if (mStateMachineCount == 0) {
     NS_ASSERTION(!mStateMachineThread, "Should have null state machine thread!");
     nsresult res = NS_NewThread(&mStateMachineThread,
                                 nsnull);
     NS_ABORT_IF_FALSE(NS_SUCCEEDED(res), "Can't create media state machine thread");
   }
   mStateMachineCount++;
 }
- 
+
+#ifdef DEBUG
+bool StateMachineTracker::IsQueued(nsBuiltinDecoderStateMachine* aStateMachine)
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  PRInt32 size = mPending.GetSize();
+  for (int i = 0; i < size; ++i) {
+    nsBuiltinDecoderStateMachine* m =
+      static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
+    if (m == aStateMachine) {
+      return true;
+    }
+  }
+  return false;
+}
+#endif
+
 void StateMachineTracker::CleanupGlobalStateMachine() 
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   NS_ABORT_IF_FALSE(mStateMachineCount > 0,
     "State machine ref count must be > 0");
   mStateMachineCount--;
   if (mStateMachineCount == 0) {
     LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
+    NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
     {
       ReentrantMonitorAutoEnter mon(mMonitor);
       nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mStateMachineThread);
       NS_RELEASE(mStateMachineThread);
       mStateMachineThread = nsnull;
       NS_DispatchToMainThread(event);
 
       NS_ASSERTION(mDecodeThreadCount == 0, "Decode thread count must be zero.");
       mInstance = nsnull;
     }
     delete this;
   }
 }
 
-void StateMachineTracker::NoteDecodeThreadCreated()
-{
-  ReentrantMonitorAutoEnter mon(mMonitor);
-  ++mDecodeThreadCount;
-}
-
 void StateMachineTracker::NoteDecodeThreadDestroyed()
 {
   ReentrantMonitorAutoEnter mon(mMonitor);
   --mDecodeThreadCount;
+  while (mDecodeThreadCount < MAX_DECODE_THREADS && mPending.GetSize() > 0) {
+    nsBuiltinDecoderStateMachine* m =
+      static_cast<nsBuiltinDecoderStateMachine*>(mPending.PopFront());
+    nsresult rv;
+    {
+      ReentrantMonitorAutoExit exitMon(mMonitor);
+      rv = m->StartDecodeThread();
+    }
+    if (NS_SUCCEEDED(rv)) {
+      ++mDecodeThreadCount;
+    }
+  }
 }
 
 PRUint32 StateMachineTracker::GetDecodeThreadCount()
 {
   ReentrantMonitorAutoEnter mon(mMonitor);
   return mDecodeThreadCount;
 }
 
+nsresult StateMachineTracker::CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine) {
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  PRInt32 size = mPending.GetSize();
+  for (PRInt32 i = 0; i < size; ++i) {
+    void* m = static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
+    if (m == aStateMachine) {
+      mPending.RemoveObjectAt(i);
+      break;
+    }
+  }
+  NS_ASSERTION(!IsQueued(aStateMachine), "State machine should no longer have queued request.");
+  return NS_OK;
+}
+
+nsresult StateMachineTracker::RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine)
+{
+  NS_ENSURE_STATE(aStateMachine);
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  if (mPending.GetSize() > 0 || mDecodeThreadCount + 1 >= MAX_DECODE_THREADS) {
+    // If there's already state machines in the queue, or we've exceeded the
+    // limit, append the state machine to the queue of state machines waiting
+    // for a decode thread. This ensures state machines already waiting get
+    // their threads first.
+    mPending.Push(aStateMachine);
+    return NS_OK;
+  }
+  nsresult rv;
+  {
+    ReentrantMonitorAutoExit exitMon(mMonitor);
+    rv = aStateMachine->StartDecodeThread();
+  }
+  if (NS_SUCCEEDED(rv)) {
+    ++mDecodeThreadCount;
+  }
+  NS_ASSERTION(mDecodeThreadCount <= MAX_DECODE_THREADS,
+                "Should keep to thread limit!");
+  return NS_OK;
+}
+
 nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder,
                                                            nsBuiltinDecoderReader* aReader,
                                                            bool aRealTime) :
   mDecoder(aDecoder),
   mState(DECODER_STATE_DECODING_METADATA),
   mCbCrSize(0),
   mPlayDuration(0),
   mStartTime(-1),
@@ -362,16 +441,17 @@ nsBuiltinDecoderStateMachine::nsBuiltinD
   mDecodeThreadIdle(false),
   mStopAudioThread(true),
   mQuickBuffering(false),
   mIsRunning(false),
   mRunAgain(false),
   mDispatchedRunEvent(false),
   mDecodeThreadWaiting(false),
   mRealTime(aRealTime),
+  mRequestedNewDecodeThread(false),
   mEventManager(aDecoder)
 {
   MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   StateMachineTracker::Instance().EnsureGlobalStateMachine();
 
   // only enable realtime mode when "media.realtime_decoder.enabled" is true.
@@ -381,16 +461,20 @@ nsBuiltinDecoderStateMachine::nsBuiltinD
   mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT;
   mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
 }
 
 nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
+  NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
+    "Should not have a pending request for a new decode thread");
+  NS_ASSERTION(!mRequestedNewDecodeThread,
+    "Should not have (or flagged) a pending request for a new decode thread");
   if (mTimer)
     mTimer->Cancel();
   mTimer = nsnull;
  
   StateMachineTracker::Instance().CleanupGlobalStateMachine();
 }
 
 bool nsBuiltinDecoderStateMachine::HasFutureAudio() const {
@@ -1186,28 +1270,40 @@ void nsBuiltinDecoderStateMachine::Seek(
   mState = DECODER_STATE_SEEKING;
   ScheduleStateMachine();
 }
 
 void nsBuiltinDecoderStateMachine::StopDecodeThread()
 {
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
+  if (mRequestedNewDecodeThread) {
+    // We've requested that the decode be created, but it hasn't been yet.
+    // Cancel that request.
+    NS_ASSERTION(!mDecodeThread,
+      "Shouldn't have a decode thread until after request processed");
+    StateMachineTracker::Instance().CancelCreateDecodeThread(this);
+    mRequestedNewDecodeThread = false;
+  }
   mStopDecodeThread = true;
   mDecoder->GetReentrantMonitor().NotifyAll();
   if (mDecodeThread) {
     LOG(PR_LOG_DEBUG, ("%p Shutdown decode thread", mDecoder.get()));
     {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       mDecodeThread->Shutdown();
       StateMachineTracker::Instance().NoteDecodeThreadDestroyed();
     }
     mDecodeThread = nsnull;
     mDecodeThreadIdle = false;
   }
+  NS_ASSERTION(!mRequestedNewDecodeThread,
+    "Any pending requests for decode threads must be canceled and unflagged");
+  NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
+    "Any pending requests for decode threads must be canceled");
 }
 
 void nsBuiltinDecoderStateMachine::StopAudioThread()
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   mStopAudioThread = true;
   mDecoder->GetReentrantMonitor().NotifyAll();
   if (mAudioThread) {
@@ -1216,77 +1312,94 @@ void nsBuiltinDecoderStateMachine::StopA
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       mAudioThread->Shutdown();
     }
     mAudioThread = nsnull;
   }
 }
 
 nsresult
-nsBuiltinDecoderStateMachine::StartDecodeThread()
+nsBuiltinDecoderStateMachine::ScheduleDecodeThread()
 {
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
-  PRUint32 count = 0;
-  bool created = false;
-  {
+ 
+  mStopDecodeThread = false;
+  if (mState >= DECODER_STATE_COMPLETED) {
+    return NS_OK;
+  }
+  if (mDecodeThread) {
+    NS_ASSERTION(!mRequestedNewDecodeThread,
+      "Shouldn't have requested new decode thread when we have a decode thread");
+    // We already have a decode thread...
+    if (mDecodeThreadIdle) {
+      // ... and it's not been shutdown yet, wake it up.
+      nsCOMPtr<nsIRunnable> event =
+        NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
+      mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
+      mDecodeThreadIdle = false;
+    }
+    return NS_OK;
+  } else if (!mRequestedNewDecodeThread) {
+  // We don't already have a decode thread, request a new one.
+    mRequestedNewDecodeThread = true;
     ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
-    count = StateMachineTracker::Instance().GetDecodeThreadCount();
+    StateMachineTracker::Instance().RequestCreateDecodeThread(this);
+  }
+  return NS_OK;
+}
+
+nsresult
+nsBuiltinDecoderStateMachine::StartDecodeThread()
+{
+  NS_ASSERTION(StateMachineTracker::Instance().GetDecodeThreadCount() <
+               StateMachineTracker::MAX_DECODE_THREADS,
+               "Should not have reached decode thread limit");
+
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
+    "Should not already have a pending request for a new decode thread.");
+  NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
+  NS_ASSERTION(!mDecodeThread, "Should not have decode thread yet");
+  NS_ASSERTION(mRequestedNewDecodeThread, "Should have requested this...");
+
+  mRequestedNewDecodeThread = false;
+
+  nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
+                              nsnull,
+                              MEDIA_THREAD_STACK_SIZE);
+  if (NS_FAILED(rv)) {
+    // Give up, report error to media element.
+    nsCOMPtr<nsIRunnable> event =
+      NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::DecodeError);
+    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+    return rv;
   }
 
-  mStopDecodeThread = false;
-  if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
-    return NS_OK;
-
-  if (!mDecodeThread && count > StateMachineTracker::MAX_DECODE_THREADS) {
-    // Have to run one iteration of the state machine loop to ensure the
-    // shutdown state is processed.
-    ScheduleStateMachine();
-    mState = DECODER_STATE_SHUTDOWN;
-    return NS_ERROR_FAILURE;
-  }
-
-  if (!mDecodeThread) {
-    nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
-                               nsnull,
-                               MEDIA_THREAD_STACK_SIZE);
-    if (NS_FAILED(rv)) {
-      // Have to run one iteration of the state machine loop to ensure the
-      // shutdown state is processed.
-      ScheduleStateMachine();
-      mState = DECODER_STATE_SHUTDOWN;
-      return rv;
-    }
-    created = true;
-  }
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
   mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
   mDecodeThreadIdle = false;
 
-  if (created) {
-    ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
-    StateMachineTracker::Instance().NoteDecodeThreadCreated();
-  }
-
   return NS_OK;
 }
 
 nsresult
 nsBuiltinDecoderStateMachine::StartAudioThread()
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   mStopAudioThread = false;
   if (HasAudio() && !mAudioThread) {
     nsresult rv = NS_NewThread(getter_AddRefs(mAudioThread),
                                nsnull,
                                MEDIA_THREAD_STACK_SIZE);
     if (NS_FAILED(rv)) {
+      LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
       mState = DECODER_STATE_SHUTDOWN;
       return rv;
     }
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::AudioLoop);
     mAudioThread->Dispatch(event, NS_DISPATCH_NORMAL);
   }
   return NS_OK;
@@ -1634,17 +1747,17 @@ nsresult nsBuiltinDecoderStateMachine::R
       // dispatch an event to the main thread to release the decoder and
       // state machine.
       NS_DispatchToCurrentThread(new nsDispatchDisposeEvent(mDecoder, this));
       return NS_OK;
     }
 
     case DECODER_STATE_DECODING_METADATA: {
       // Ensure we have a decode thread to decode metadata.
-      return StartDecodeThread();
+      return ScheduleDecodeThread();
     }
   
     case DECODER_STATE_DECODING: {
       if (mDecoder->GetState() != nsBuiltinDecoder::PLAY_STATE_PLAYING &&
           IsPlaying())
       {
         // We're playing, but the element/decoder is in paused state. Stop
         // playing! Note we do this before StopDecodeThread() below because
@@ -1658,17 +1771,17 @@ nsresult nsBuiltinDecoderStateMachine::R
         // The decode buffers are full, and playback is paused. Shutdown the
         // decode thread.
         StopDecodeThread();
         return NS_OK;
       }
 
       // We're playing and/or our decode buffers aren't full. Ensure we have
       // an active decode thread.
-      if (NS_FAILED(StartDecodeThread())) {
+      if (NS_FAILED(ScheduleDecodeThread())) {
         NS_WARNING("Failed to start media decode thread!");
         return NS_ERROR_FAILURE;
       }
 
       AdvanceFrame();
       NS_ASSERTION(mDecoder->GetState() != nsBuiltinDecoder::PLAY_STATE_PLAYING ||
                    IsStateMachineScheduled(), "Must have timer scheduled");
       return NS_OK;
@@ -1723,17 +1836,17 @@ nsresult nsBuiltinDecoderStateMachine::R
         StartPlayback();
       }
       NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
       return NS_OK;
     }
 
     case DECODER_STATE_SEEKING: {
       // Ensure we have a decode thread to perform the seek.
-     return StartDecodeThread();
+     return ScheduleDecodeThread();
     }
 
     case DECODER_STATE_COMPLETED: {
       StopDecodeThread();
 
       if (mState != DECODER_STATE_COMPLETED) {
         // While we're waiting for the decode thread to shutdown, we can
         // change state, for example to seeking or shutdown state.
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -248,16 +248,22 @@ public:
   // machine again.
   nsresult ScheduleStateMachine();
 
   // Schedules the shared state machine thread to run the state machine
   // in aUsecs microseconds from now, if it's not already scheduled to run
   // earlier, in which case the request is discarded.
   nsresult ScheduleStateMachine(PRInt64 aUsecs);
 
+  // Creates and starts a new decode thread. Don't call this directly,
+  // request a new decode thread by calling
+  // StateMachineTracker::RequestCreateDecodeThread().
+  // The decoder monitor must not be held. Called on the state machine thread.
+  nsresult StartDecodeThread();
+
   // Timer function to implement ScheduleStateMachine(aUsecs).
   void TimeoutExpired();
 
   // Set the media fragment end time. aEndTime is in microseconds.
   void SetFragmentEndTime(PRInt64 aEndTime);
 
   // Drop reference to decoder.  Only called during shutdown dance.
   void ReleaseDecoder() { mDecoder = nsnull; }
@@ -347,27 +353,30 @@ protected:
                        PRUint32 aChannels,
                        PRUint64 aFrameOffset);
 
   // Pops an audio chunk from the front of the audio queue, and pushes its
   // audio data to the audio hardware. MozAudioAvailable data is also queued
   // here. Called on the audio thread.
   PRUint32 PlayFromAudioQueue(PRUint64 aFrameOffset, PRUint32 aChannels);
 
-  // Stops the decode thread. The decoder monitor must be held with exactly
+  // Stops the decode thread, and if we have a pending request for a new
+  // decode thread it is canceled. The decoder monitor must be held with exactly
   // one lock count. Called on the state machine thread.
   void StopDecodeThread();
 
   // Stops the audio thread. The decoder monitor must be held with exactly
   // one lock count. Called on the state machine thread.
   void StopAudioThread();
 
-  // Starts the decode thread. The decoder monitor must be held with exactly
-  // one lock count. Called on the state machine thread.
-  nsresult StartDecodeThread();
+  // Ensures the decode thread is running if it already exists, or requests
+  // a new decode thread be started if there currently is no decode thread.
+  // The decoder monitor must be held with exactly one lock count. Called on
+  // the state machine thread.
+  nsresult ScheduleDecodeThread();
 
   // Starts the audio thread. The decoder monitor must be held with exactly
   // one lock count. Called on the state machine thread.
   nsresult StartAudioThread();
 
   // The main loop for the audio thread. Sent to the thread as
   // an nsRunnableMethod. This continually does blocking writes to
   // to audio stream to play audio data.
@@ -620,16 +629,20 @@ protected:
 
   // True if the decode thread has gone filled its buffers and is now
   // waiting to be awakened before it continues decoding. Synchronized
   // by the decoder monitor.
   bool mDecodeThreadWaiting;
 
   // True is we are decoding a realtime stream, like a camera stream
   bool mRealTime;
+
+  // True if we've requested a new decode thread, but it has not yet been
+  // created. Synchronized by the decoder monitor.
+  bool mRequestedNewDecodeThread;
   
   PRUint32 mBufferingWait;
   PRInt64  mLowDataThresholdUsecs;
 
 private:
   // Manager for queuing and dispatching MozAudioAvailable events.  The
   // event manager is accessed from the state machine and audio threads,
   // and takes care of synchronizing access to its internal queue.
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -145,16 +145,17 @@ include $(topsrcdir)/config/rules.mk
 		test_seek.html \
 		test_seek2.html \
 		test_seekLies.html \
 		test_seek_out_of_range.html \
 		test_source.html \
 		test_source_write.html \
 		test_standalone.html \
 		test_timeupdate_small_files.html \
+		test_too_many_elements.html \
 		test_volume.html \
 		test_video_to_canvas.html \
 		use_large_cache.js \
 		test_audiowrite.html \
 		$(NULL)
 
 # Don't run in suite
 ifndef MOZ_SUITE
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -3,9 +3,9 @@ load 466607-1.html
 load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
 load 493915-1.html
 skip-if(Android) load 495794-1.html
 load 492286-1.xhtml
 load 576612-1.html
-load 691096-1.html
+skip-if(Android) load 691096-1.html # Android sound API can't handle playing large number of sounds at once.
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -1,18 +1,18 @@
 // In each list of tests below, test file types that are not supported should
 // be ignored. To make sure tests respect that, we include a file of type
 // "bogus/duh" in each list.
 
 // These are small test files, good for just seeing if something loads. We
 // really only need one test file per backend here.
 var gSmallTests = [
+  { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
   { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
   { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233 },
-  { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
   { name:"seek.webm", type:"video/webm", duration:3.966 },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // Used by test_progress to ensure we get the correct progress information
 // during resource download.
 var gProgressTests = [
   { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0, size:11069 },
@@ -294,16 +294,24 @@ function checkMetadata(msg, e, test) {
 function getPlayableVideo(candidates) {
   var v = document.createElement("video");
   var resources = candidates.filter(function(x){return /^video/.test(x.type) && v.canPlayType(x.type);});
   if (resources.length > 0)
     return resources[0];
   return null;
 }
 
+function getPlayableAudio(candidates) {
+  var v = document.createElement("audio");
+  var resources = candidates.filter(function(x){return /^audio/.test(x.type) && v.canPlayType(x.type);});
+  if (resources.length > 0)
+    return resources[0];
+  return null;
+}
+
 // Number of tests to run in parallel. Warning: Each media element requires
 // at least 3 threads (4 on Linux), and on Linux each thread uses 10MB of
 // virtual address space. Beware!
 var PARALLEL_TESTS = 2;
 
 // When true, we'll loop forever on whatever test we run. Use this to debug
 // intermittent test failures.
 const DEBUG_TEST_LOOP_FOREVER = false;
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_too_many_elements.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=713381
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 713381</title>
+  <script type="application/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>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=713381">Mozilla Bug 713381</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<p>Received loadeddata event for <span id="result">0</span> <span id="expected"></span>audio elements.</p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 713381 **/
+
+const num = 500;
+var loadeddata = 0;
+
+var result = document.getElementById("result");
+document.getElementById("expected").innerHTML = " of " + num + " ";
+
+var finish = function(testNum) {
+  return function() {
+    ok(true, "Received loadeddata event for instance " + testNum );
+    loadeddata++;
+    if (loadeddata == num) {
+      ok(true, "Should receive loadeddata events for all " + num + " elements.");
+      SimpleTest.finish();
+    }
+  }
+};
+
+var resource = getPlayableAudio(gSmallTests);
+
+if (resource == null) {
+  todo(false, "No types supported");
+} else {
+  SimpleTest.waitForExplicitFinish();
+  // Load the resource, and play it to ensure it's entirely downloaded.
+  // Once it's played through, create a large number of audio elements which
+  // are the same resource. These will share data with the other resource, and
+  // so be really cheap to create.
+  var res = new Audio(resource.name);
+  res.addEventListener("ended",
+    function() {  
+      for (var i=0; i<num; ++i) {
+        var a = new Audio(resource.name);
+        a.addEventListener("loadeddata", finish(i), false);
+      }
+    }, false);
+  res.play();
+}
+
+setInterval(function() { result.innerHTML = loadeddata; }, 1000);
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -61,18 +61,23 @@ DIRS = \
   interfaces/xul \
   interfaces/storage \
   interfaces/json \
   interfaces/offline \
   interfaces/geolocation \
   interfaces/notification \
   interfaces/svg \
   interfaces/smil \
+  $(NULL)
+
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+DIRS += \
   interfaces/apps \
   $(NULL)
+endif
 
 DIRS += \
   base \
   battery \
   sms \
   src \
   locales \
   network \
copy from dom/sms/src/fallback/SmsDatabaseService.cpp
copy to dom/sms/src/ril/SmsDatabaseService.cpp
copy from dom/sms/src/fallback/SmsDatabaseService.h
copy to dom/sms/src/ril/SmsDatabaseService.h
--- a/dom/sms/src/ril/SmsService.cpp
+++ b/dom/sms/src/ril/SmsService.cpp
@@ -75,17 +75,20 @@ SmsService::GetNumberOfMessagesForText(c
     return NS_OK;
   }
 
   mRIL->GetNumberOfMessagesForText(aText, aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
+SmsService::Send(const nsAString& aNumber,
+                 const nsAString& aMessage,
+                 PRInt32 aRequestId,
+                 PRUint64 aProcessId)
 {
   if (!mRIL) {
     return NS_OK;
   }
 
   mRIL->SendSMS(aNumber, aMessage);
   return NS_OK;
 }
--- a/dom/sms/src/ril/SmsService.h
+++ b/dom/sms/src/ril/SmsService.h
@@ -35,30 +35,30 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_sms_SmsService_h
 #define mozilla_dom_sms_SmsService_h
 
 #include "nsISmsService.h"
 #include "nsCOMPtr.h"
-#include "nsITelephone.h"
+#include "nsIRadioInterfaceLayer.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 class SmsService : public nsISmsService
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISMSSERVICE
   SmsService();
 
 protected:
-  nsCOMPtr<nsITelephone> mRIL;
+  nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
 };
 
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_sms_SmsService_h
--- a/dom/src/geolocation/Makefile.in
+++ b/dom/src/geolocation/Makefile.in
@@ -74,15 +74,20 @@ LOCAL_INCLUDES  += $(MOZ_QT_CFLAGS) \
                    $(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),android)
 LOCAL_INCLUDES  += -I$(topsrcdir)/dom/system/android \
                    $(NULL)
 endif
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
+LOCAL_INCLUDES  += -I$(topsrcdir)/dom/system/b2g \
+                   $(NULL)
+endif
+
 EXPORTS         += nsGeoPositionIPCSerialiser.h
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -83,16 +83,20 @@
 #ifdef MOZ_ENABLE_QTMOBILITY
 #include "QTMLocationProvider.h"
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidLocationProvider.h"
 #endif
 
+#ifdef MOZ_WIDGET_GONK
+#include "GonkGPSGeolocationProvider.h"
+#endif
+
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 
 // Some limit to the number of get or watch geolocation requests
 // that a window can make.
 #define MAX_GEO_REQUESTS_PER_WINDOW  1500
 
 using mozilla::unused;          // <snicker>
@@ -572,16 +576,23 @@ nsresult nsGeolocationService::Init()
     mProviders.AppendObject(provider);
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
   provider = new AndroidLocationProvider();
   if (provider)
     mProviders.AppendObject(provider);
 #endif
+
+#ifdef MOZ_WIDGET_GONK
+  provider = GonkGPSGeolocationProvider::GetSingleton();
+  if (provider)
+    mProviders.AppendObject(provider);
+#endif
+
   return NS_OK;
 }
 
 nsGeolocationService::~nsGeolocationService()
 {
 }
 
 NS_IMETHODIMP
new file mode 100644
--- /dev/null
+++ b/dom/system/b2g/GonkGPSGeolocationProvider.cpp
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <pthread.h>
+#include <hardware/gps.h>
+
+#include "mozilla/Preferences.h"
+#include "nsGeoPosition.h"
+#include "GonkGPSGeolocationProvider.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS1(GonkGPSGeolocationProvider, nsIGeolocationProvider)
+
+GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton;
+
+static void
+LocationCallback(GpsLocation* location)
+{
+  nsRefPtr<GonkGPSGeolocationProvider> provider =
+    GonkGPSGeolocationProvider::GetSingleton();
+  nsCOMPtr<nsIGeolocationUpdate> callback = provider->GetLocationCallback();
+  
+  if (!callback)
+    return;
+
+  nsRefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude,
+                                                        location->longitude,
+                                                        location->altitude,
+                                                        location->accuracy,
+                                                        location->accuracy,
+                                                        location->bearing,
+                                                        location->speed,
+                                                        location->timestamp);
+  callback->Update(somewhere);
+}
+
+typedef void *(*pthread_func)(void *);
+
+/** Callback for creating a thread that can call into the JS codes.
+ */
+static pthread_t
+CreateThreadCallback(const char* name, void (*start)(void *), void* arg)
+{
+  pthread_t thread;
+  pthread_attr_t attr;
+
+  pthread_attr_init(&attr);
+
+  /* Unfortunately pthread_create and the callback disagreed on what
+   * start function should return.
+   */
+  pthread_create(&thread, &attr, reinterpret_cast<pthread_func>(start), arg);
+
+  return thread;
+}
+
+static GpsCallbacks gCallbacks = {
+  sizeof(GpsCallbacks),
+  LocationCallback,
+  NULL, /* StatusCallback */
+  NULL, /* SvStatusCallback */
+  NULL, /* NmeaCallback */
+  NULL, /* SetCapabilitiesCallback */
+  NULL, /* AcquireWakelockCallback */
+  NULL, /* ReleaseWakelockCallback */
+  CreateThreadCallback,
+};
+
+GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
+  : mStarted(false)
+{
+  mGpsInterface = GetGPSInterface();
+}
+
+GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider()
+{
+  Shutdown();
+  sSingleton = NULL;
+}
+
+/* static */ already_AddRefed<GonkGPSGeolocationProvider>
+GonkGPSGeolocationProvider::GetSingleton()
+{
+  if (!sSingleton)
+    sSingleton = new GonkGPSGeolocationProvider();
+
+  NS_ADDREF(sSingleton);
+  return sSingleton;
+}
+
+already_AddRefed<nsIGeolocationUpdate>
+GonkGPSGeolocationProvider::GetLocationCallback()
+{
+  nsCOMPtr<nsIGeolocationUpdate> callback = mLocationCallback;
+  return callback.forget();
+}
+
+const GpsInterface*
+GonkGPSGeolocationProvider::GetGPSInterface()
+{
+  hw_module_t* module;
+
+  if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module))
+    return NULL;
+
+  hw_device_t* device;
+  if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device))
+    return NULL;
+
+  gps_device_t* gps_device = (gps_device_t *)device;
+  return gps_device->get_gps_interface(gps_device);
+}
+
+NS_IMETHODIMP
+GonkGPSGeolocationProvider::Startup()
+{
+  if (mStarted)
+    return NS_OK;
+
+  NS_ENSURE_TRUE(mGpsInterface, NS_ERROR_FAILURE);
+
+  PRInt32 update = Preferences::GetInt("geo.default.update", 1000);
+
+  mGpsInterface->init(&gCallbacks);
+  mGpsInterface->start();
+  mGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE,
+                                   GPS_POSITION_RECURRENCE_PERIODIC,
+                                   update, 0, 0);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
+{
+  mLocationCallback = aCallback;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GonkGPSGeolocationProvider::Shutdown()
+{
+  if (!mStarted)
+    return NS_OK;
+
+  mGpsInterface->stop();
+  mGpsInterface->cleanup();
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/system/b2g/GonkGPSGeolocationProvider.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef GonkGPSGeolocationProvider_h
+#define GonkGPSGeolocationProvider_h
+
+#include <hardware/gps.h> // for GpsInterface
+#include "nsIGeolocationProvider.h"
+
+class GonkGPSGeolocationProvider : public nsIGeolocationProvider
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIGEOLOCATIONPROVIDER
+
+  static already_AddRefed<GonkGPSGeolocationProvider> GetSingleton();
+
+  already_AddRefed<nsIGeolocationUpdate> GetLocationCallback();
+
+private:
+
+  /* Client should use GetSingleton() to get the provider instance. */
+  GonkGPSGeolocationProvider();
+  GonkGPSGeolocationProvider(const GonkGPSGeolocationProvider &);
+  GonkGPSGeolocationProvider & operator = (const GonkGPSGeolocationProvider &);
+  ~GonkGPSGeolocationProvider();
+
+  const GpsInterface* GetGPSInterface();
+
+  static GonkGPSGeolocationProvider* sSingleton;
+
+  bool mStarted;
+  const GpsInterface* mGpsInterface;
+  nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
+};
+
+#endif /* GonkGPSGeolocationProvider_h */
--- a/dom/system/b2g/Makefile.in
+++ b/dom/system/b2g/Makefile.in
@@ -50,24 +50,39 @@ FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 CPPSRCS = \
   SystemWorkerManager.cpp \
   $(NULL)
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
-CPPSRCS += AudioManager.cpp
+CPPSRCS += \
+  AudioManager.cpp \
+  GonkGPSGeolocationProvider.cpp \
+  $(NULL)
 endif
 
 XPIDLSRCS = \
   nsIAudioManager.idl \
+  nsIRadioInterfaceLayer.idl \
   nsIWorkerHolder.idl \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/dom/base \
+  -I$(topsrcdir)/dom/src/geolocation \
   -I$(topsrcdir)/dom/telephony \
   -I$(topsrcdir)/dom/wifi \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
+EXTRA_COMPONENTS = \
+  RadioInterfaceLayer.manifest \
+  RadioInterfaceLayer.js \
+  $(NULL)
+
+EXTRA_JS_MODULES = \
+  ril_consts.js \
+  ril_worker.js \
+  $(NULL)
+
 include $(topsrcdir)/config/rules.mk
rename from dom/telephony/nsTelephonyWorker.js
rename to dom/system/b2g/RadioInterfaceLayer.js
--- a/dom/telephony/nsTelephonyWorker.js
+++ b/dom/system/b2g/RadioInterfaceLayer.js
@@ -9,23 +9,24 @@
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Telephony.
  *
  * The Initial Developer of the Original Code is
- *   The Mozilla Foundation.
+ * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
  *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Sinker Li <thinker@codemud.net>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -43,45 +44,45 @@ const {classes: Cc, interfaces: Ci, util
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 var RIL = {};
 Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
 const DEBUG = true; // set to false to suppress debug messages
 
-const TELEPHONYWORKER_CID =
+const RADIOINTERFACELAYER_CID =
   Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
 const DATACALLINFO_CID =
   Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
 
 const nsIAudioManager = Ci.nsIAudioManager;
-const nsITelephone = Ci.nsITelephone;
+const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
 
 const kSmsReceivedObserverTopic          = "sms-received";
 const DOM_SMS_DELIVERY_RECEIVED          = "received";
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/smsservice;1",
                                    "nsISmsService");
 
 function convertRILCallState(state) {
   switch (state) {
     case RIL.CALL_STATE_ACTIVE:
-      return nsITelephone.CALL_STATE_CONNECTED;
+      return nsIRadioInterfaceLayer.CALL_STATE_CONNECTED;
     case RIL.CALL_STATE_HOLDING:
-      return nsITelephone.CALL_STATE_HELD;
+      return nsIRadioInterfaceLayer.CALL_STATE_HELD;
     case RIL.CALL_STATE_DIALING:
-      return nsITelephone.CALL_STATE_DIALING;
+      return nsIRadioInterfaceLayer.CALL_STATE_DIALING;
     case RIL.CALL_STATE_ALERTING:
-      return nsITelephone.CALL_STATE_RINGING;
+      return nsIRadioInterfaceLayer.CALL_STATE_RINGING;
     case RIL.CALL_STATE_INCOMING:
-      return nsITelephone.CALL_STATE_INCOMING;
+      return nsIRadioInterfaceLayer.CALL_STATE_INCOMING;
     case RIL.CALL_STATE_WAITING:
-      return nsITelephone.CALL_STATE_HELD; // XXX This may not be right...
+      return nsIRadioInterfaceLayer.CALL_STATE_HELD; // XXX This may not be right...
     default:
       throw new Error("Unknown rilCallState: " + state);
   }
 }
 
 /**
  * Fake nsIAudioManager implementation so that we can run the telephony
  * code in a non-Gonk build.
@@ -121,38 +122,38 @@ DataCallInfo.protoptype = {
   classID:      DATACALLINFO_CID,
   classInfo:    XPCOMUtils.generateCI({classID: DATACALLINFO_CID,
                                        classDescription: "DataCallInfo",
                                        interfaces: [Ci.nsIDataCallInfo]}),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInfo]),
 };
 
 
-function nsTelephonyWorker() {
+function RadioInterfaceLayer() {
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
   debug("Starting Worker\n");
   this.currentState = {
     signalStrength: null,
     operator:       null,
     radioState:     null,
     cardState:      null
   };
 }
-nsTelephonyWorker.prototype = {
+RadioInterfaceLayer.prototype = {
 
-  classID:   TELEPHONYWORKER_CID,
-  classInfo: XPCOMUtils.generateCI({classID: TELEPHONYWORKER_CID,
-                                    classDescription: "Telephone",
+  classID:   RADIOINTERFACELAYER_CID,
+  classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
+                                    classDescription: "RadioInterfaceLayer",
                                     interfaces: [Ci.nsIWorkerHolder,
-                                                 Ci.nsITelephone]}),
+                                                 Ci.nsIRadioInterfaceLayer]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
-                                         Ci.nsITelephone]),
+                                         Ci.nsIRadioInterfaceLayer]),
 
   onerror: function onerror(event) {
     debug("Got an error: " + event.filename + ":" +
           event.lineno + ": " + event.message + "\n");
     event.preventDefault();
   },
 
   /**
@@ -214,38 +215,38 @@ nsTelephonyWorker.prototype = {
   updateCallAudioState: function updateCallAudioState() {
     if (!this._activeCall) {
       // Disable audio.
       gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
       debug("No active call, put audio system into PHONE_STATE_NORMAL.");
       return;
     }
     switch (this._activeCall.state) {
-      case nsITelephone.CALL_STATE_INCOMING:
+      case nsIRadioInterfaceLayer.CALL_STATE_INCOMING:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
         debug("Incoming call, put audio system into PHONE_STATE_RINGTONE.");
         break;
-      case nsITelephone.CALL_STATE_DIALING: // Fall through...
-      case nsITelephone.CALL_STATE_CONNECTED:
+      case nsIRadioInterfaceLayer.CALL_STATE_DIALING: // Fall through...
+      case nsIRadioInterfaceLayer.CALL_STATE_CONNECTED:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
         gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
                                      nsIAudioManager.FORCE_NONE);
         debug("Active call, put audio system into PHONE_STATE_IN_CALL.");
         break;
     }
   },
 
   /**
    * Handle call state changes by updating our current state and the audio
    * system.
    */
   handleCallStateChange: function handleCallStateChange(call) {
     debug("handleCallStateChange: " + JSON.stringify(call));
     call.state = convertRILCallState(call.state);
-    if (call.state == nsITelephone.CALL_STATE_CONNECTED) {
+    if (call.state == nsIRadioInterfaceLayer.CALL_STATE_CONNECTED) {
       // This is now the active call.
       this._activeCall = call;
     }
     this.updateCallAudioState();
     this._deliverCallback("callStateChanged",
                           [call.callIndex, call.state, call.number]);
   },
 
@@ -254,17 +255,18 @@ nsTelephonyWorker.prototype = {
    */
   handleCallDisconnected: function handleCallDisconnected(call) {
     debug("handleCallDisconnected: " + JSON.stringify(call));
     if (this._activeCall.callIndex == call.callIndex) {
       this._activeCall = null;
     }
     this.updateCallAudioState();
     this._deliverCallback("callStateChanged",
-                          [call.callIndex, nsITelephone.CALL_STATE_DISCONNECTED,
+                          [call.callIndex,
+                           nsIRadioInterfaceLayer.CALL_STATE_DISCONNECTED,
                            call.number]);
   },
 
   /**
    * Handle calls delivered in response to a 'enumerateCalls' request.
    */
   handleEnumerateCalls: function handleEnumerateCalls(calls) {
     debug("handleEnumerateCalls: " + JSON.stringify(calls));
@@ -322,17 +324,17 @@ nsTelephonyWorker.prototype = {
     this._deliverDataCallCallback("receiveDataCallList",
                                   [datacalls, datacalls.length]);
   },
 
   // nsIRadioWorker
 
   worker: null,
 
-  // nsITelephone
+  // nsIRadioInterfaceLayer
 
   currentState: null,
 
   dial: function dial(number) {
     debug("Dialing " + number);
     this.worker.postMessage({type: "dial", number: number});
   },
 
@@ -535,18 +537,18 @@ nsTelephonyWorker.prototype = {
   },
 
   getDataCallList: function getDataCallList() {
     this.worker.postMessage({type: "getDataCallList"});
   },
 
 };
 
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTelephonyWorker]);
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
-    dump("-*- TelephonyWorker component: " + s + "\n");
+    dump("-*- RadioInterfaceLayer: " + s + "\n");
   };
 } else {
   debug = function (s) {};
 }
rename from dom/telephony/nsTelephonyWorker.manifest
rename to dom/system/b2g/RadioInterfaceLayer.manifest
--- a/dom/telephony/nsTelephonyWorker.manifest
+++ b/dom/system/b2g/RadioInterfaceLayer.manifest
@@ -1,1 +1,1 @@
-component {2d831c8d-6017-435b-a80c-e5d422810cea} nsTelephonyWorker.js
+component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js
--- a/dom/system/b2g/SystemWorkerManager.cpp
+++ b/dom/system/b2g/SystemWorkerManager.cpp
@@ -36,37 +36,37 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "SystemWorkerManager.h"
 
 #include "nsIObserverService.h"
 #include "nsIJSContextStack.h"
-#include "nsITelephone.h"
+#include "nsIRadioInterfaceLayer.h"
 #include "nsIWifi.h"
 #include "nsIWorkerHolder.h"
 #include "nsIXPConnect.h"
 
 #include "jstypedarray.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ipc/Ril.h"
 #include "nsContentUtils.h"
 #include "nsServiceManagerUtils.h"
-#include "nsTelephonyWorker.h"
 #include "nsThreadUtils.h"
+#include "nsRadioInterfaceLayer.h"
 #include "nsWifiWorker.h"
 
 USING_TELEPHONY_NAMESPACE
 USING_WORKERS_NAMESPACE
 using namespace mozilla::ipc;
 
 namespace {
 
-NS_DEFINE_CID(kTelephonyWorkerCID, NS_TELEPHONYWORKER_CID);
+NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID);
 NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
 
 // Doesn't carry a reference, we're owned by services.
 SystemWorkerManager *gInstance = nsnull;
 
 class ConnectWorkerToRIL : public WorkerTask
 {
 public:
@@ -219,17 +219,17 @@ SystemWorkerManager::Init()
   nsresult rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCxPusher pusher;
   if (!cx || !pusher.Push(cx, false)) {
     return NS_ERROR_FAILURE;
   }
 
-  rv = InitTelephone(cx);
+  rv = InitRIL(cx);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = InitWifi(cx);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIObserverService> obs =
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   if (!obs) {
@@ -247,17 +247,17 @@ void
 SystemWorkerManager::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mShutdown = true;
 
   StopRil();
 
-  mTelephoneWorker = nsnull;
+  mRILWorker = nsnull;
   mWifiWorker = nsnull;
 
   nsCOMPtr<nsIObserverService> obs =
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   if (obs) {
     obs->RemoveObserver(this, WORKERS_SHUTDOWN_TOPIC);
   }
 }
@@ -290,37 +290,37 @@ SystemWorkerManager::GetInterfaceRequest
   return gInstance;
 }
 
 NS_IMETHODIMP
 SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (aIID.Equals(NS_GET_IID(nsITelephone))) {
-    return CallQueryInterface(mTelephoneWorker,
-                              reinterpret_cast<nsITelephone**>(aResult));
+  if (aIID.Equals(NS_GET_IID(nsIRadioInterfaceLayer))) {
+    return CallQueryInterface(mRILWorker,
+                              reinterpret_cast<nsIRadioInterfaceLayer**>(aResult));
   }
 
   if (aIID.Equals(NS_GET_IID(nsIWifi))) {
     return CallQueryInterface(mWifiWorker,
                               reinterpret_cast<nsIWifi**>(aResult));
   }
 
   NS_WARNING("Got nothing for the requested IID!");
   return NS_ERROR_NO_INTERFACE;
 }
 
 nsresult
-SystemWorkerManager::InitTelephone(JSContext *cx)
+SystemWorkerManager::InitRIL(JSContext *cx)
 {
   // We're keeping as much of this implementation as possible in JS, so the real
-  // worker lives in nsTelephonyWorker.js. All we do here is hold it alive and
+  // worker lives in RadioInterfaceLayer.js. All we do here is hold it alive and
   // hook it up to the RIL thread.
-  nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kTelephonyWorkerCID);
+  nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kRadioInterfaceLayerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
 
   jsval workerval;
   nsresult rv = worker->GetWorker(&workerval);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(workerval), NS_ERROR_UNEXPECTED);
 
@@ -340,17 +340,17 @@ SystemWorkerManager::InitTelephone(JSCon
   if (!wctd->PostTask(connection)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   // Now that we're set up, connect ourselves to the RIL thread.
   mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
   StartRil(receiver);
 
-  mTelephoneWorker = worker;
+  mRILWorker = worker;
   return NS_OK;
 }
 
 nsresult
 SystemWorkerManager::InitWifi(JSContext *cx)
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
--- a/dom/system/b2g/SystemWorkerManager.h
+++ b/dom/system/b2g/SystemWorkerManager.h
@@ -65,20 +65,20 @@ public:
 
   static nsIInterfaceRequestor*
   GetInterfaceRequestor();
 
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
-  nsresult InitTelephone(JSContext *cx);
+  nsresult InitRIL(JSContext *cx);
   nsresult InitWifi(JSContext *cx);
 
-  nsCOMPtr<nsIWorkerHolder> mTelephoneWorker;
+  nsCOMPtr<nsIWorkerHolder> mRILWorker;
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
   bool mShutdown;
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif // mozilla_dom_system_b2g_systemworkermanager_h__
rename from dom/telephony/nsITelephone.idl
rename to dom/system/b2g/nsIRadioInterfaceLayer.idl
--- a/dom/telephony/nsITelephone.idl
+++ b/dom/system/b2g/nsIRadioInterfaceLayer.idl
@@ -14,17 +14,19 @@
  * The Original Code is Telephony.
  *
  * The Initial Developer of the Original Code is
  * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *  Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Ben Turner <bent.mozilla@gmail.com>
+ *   Sinker Li <thinker@codemud.net>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -32,58 +34,95 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
-interface nsITelephoneCallback : nsISupports
+[scriptable, uuid(03eafd60-d138-4f09-81b4-90cd4996b3c7)]
+interface nsIRILTelephonyCallback : nsISupports
 {
-  // 'callState' uses the CALL_STATE values from nsITelephone.
+  /**
+   * Notified when a telephony call changes state.
+   *
+   * @param callIndex
+   *        Call identifier assigned by the RIL.
+   * @param callState
+   *        One of the nsIRadioInterfaceLayer::CALL_STATE_* values.
+   * @param number
+   *        Number of the other party.
+   */
   void callStateChanged(in unsigned long callIndex,
                         in unsigned short callState,
                         in AString number);
 
-  // 'callState' uses the CALL_STATE values from nsITelephone. Return true to
-  // continue enumeration or false to cancel.
+  /**
+   * Called when nsIRadioInterfaceLayer is asked to enumerate the current
+   * telephony call state (nsIRadioInterfaceLayer::enumerateCalls). This is
+   * called once per call that is currently managed by the RIL.
+   *
+   * @param callIndex
+   *        Call identifier assigned by the RIL.
+   * @param callState
+   *        One of the nsIRadioInterfaceLayer::CALL_STATE_* values.
+   * @param number
+   *        Number of the other party.
+   * @param isActive
+   *        Indicates whether this call is the active one.
+   *
+   * @return true to continue enumeration or false to cancel.
+   */
   boolean enumerateCallState(in unsigned long callIndex,
                              in unsigned short callState,
                              in AString number,
                              in boolean isActive);
 };
 
-[scriptable, uuid(8399fddd-471c-41ac-8f35-99f7dbb738ec)]
-interface nsIDataCallInfo : nsISupports
+[scriptable, uuid(66a55943-e63b-4731-aece-9c04bfc14019)]
+interface nsIRILDataCallInfo : nsISupports
 {
   readonly attribute unsigned long callState;
   readonly attribute AString cid;
   readonly attribute AString apn;
 };
 
-[scriptable, uuid(36cc4b89-0338-4ff7-a3c2-d78e60f2ea98)]
-interface nsIPhoneDataCallCallback : nsISupports
+[scriptable, uuid(cea91bcb-3cfb-42bb-8638-dae89e8870fc)]
+interface nsIRILDataCallback : nsISupports
 {
   /**
-   * This method is called when the state of a data call is changed.
+   * Notified when a data call changes state.
    *
-   * @param dataState use DATACALL_STATE_* values from nsITelephone.
+   * @param cid
+   *        The CID of the data call.
+   * @param interfaceName
+   *        Name of the associated network interface.
+   * @param dataState
+   *        One of the nsIRadioInterfaceLayer::DATACALL_STATE_* values.
    */
   void dataCallStateChanged(in AString cid,
                             in AString interfaceName,
                             in unsigned short callState);
 
-  void receiveDataCallList([array,size_is(aLength)] in nsIDataCallInfo aDataCalls,
-                           in unsigned long aLength);
+  /**
+   * Called when nsIRadioInterfaceLayer is asked to enumerate the current
+   * data call state.
+   *
+   * @param datacalls
+   *        Array of nsIRILDataCallInfo objects.
+   * @param length
+   *        Lenght of the aforementioned array.
+   */
+  void receiveDataCallList([array,size_is(length)] in nsIRILDataCallInfo dataCalls,
+                           in unsigned long length);
 };
 
-[scriptable, uuid(78ed0beb-d6ad-42f8-929a-8d003285784f)]
-interface nsITelephone : nsISupports
+[scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
+interface nsIRadioInterfaceLayer : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_RINGING = 2;
   const unsigned short CALL_STATE_BUSY = 3;
   const unsigned short CALL_STATE_CONNECTING = 4;
   const unsigned short CALL_STATE_CONNECTED = 5;
   const unsigned short CALL_STATE_HOLDING = 6;
@@ -97,52 +136,54 @@ interface nsITelephone : nsISupports
   const unsigned short DATACALL_STATE_UNKNOWN = 0;
   const unsigned short DATACALL_STATE_CONNECTING = 1;
   const unsigned short DATACALL_STATE_CONNECTED = 2;
   const unsigned short DATACALL_STATE_DISCONNECTING = 3;
   const unsigned short DATACALL_STATE_DISCONNECTED = 4;
 
   readonly attribute jsval currentState;
 
-  void registerCallback(in nsITelephoneCallback callback);
-  void unregisterCallback(in nsITelephoneCallback callback);
+  void registerCallback(in nsIRILTelephonyCallback callback);
+  void unregisterCallback(in nsIRILTelephonyCallback callback);
 
   /**
    * Will continue calling callback.enumerateCallState until the callback
    * returns false.
    */
-  void enumerateCalls(in nsITelephoneCallback callback);
+  void enumerateCalls(in nsIRILTelephonyCallback callback);
 
   /**
    * Functionality for making and managing phone calls.
    */
   void dial(in DOMString number);
   void hangUp(in unsigned long callIndex);
 
   void startTone(in DOMString dtmfChar);
   void stopTone();
 
   void answerCall(in unsigned long callIndex);
   void rejectCall(in unsigned long callIndex);
 
   attribute bool microphoneMuted;
   attribute bool speakerEnabled;
 
-  // PDP APIs
+  /**
+   * PDP APIs
+   */
   void setupDataCall(in long radioTech,
                      in DOMString apn,
                      in DOMString user,
                      in DOMString passwd,
                      in long chappap,
                      in DOMString pdptype);
   void deactivateDataCall(in DOMString cid,
                           in DOMString reason);
   void getDataCallList();
   
-  void registerDataCallCallback(in nsIPhoneDataCallCallback callback);
-  void unregisterDataCallCallback(in nsIPhoneDataCallCallback callback);
+  void registerDataCallCallback(in nsIRILDataCallback callback);
+  void unregisterDataCallCallback(in nsIRILDataCallback callback);
 
   /**
    * SMS-related functionality.
    */
   unsigned short getNumberOfMessagesForText(in DOMString text);
   void sendSMS(in DOMString number, in DOMString message);
 };
rename from dom/telephony/nsTelephonyWorker.h
rename to dom/system/b2g/nsRadioInterfaceLayer.h
--- a/dom/telephony/nsTelephonyWorker.h
+++ b/dom/system/b2g/nsRadioInterfaceLayer.h
@@ -30,12 +30,12 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-// This must always match the CID given in nsTelephonyWorker.manifest!
-#define NS_TELEPHONYWORKER_CID \
+// This must always match the CID given in RadioInterfaceLayer.manifest!
+#define NS_RADIOINTERFACELAYER_CID \
     { 0x2d831c8d, 0x6017, 0x435b, \
       { 0xa8, 0x0c, 0xe5, 0xd4, 0x22, 0x81, 0x0c, 0xea } }
rename from dom/telephony/ril_consts.js
rename to dom/system/b2g/ril_consts.js
rename from dom/telephony/ril_worker.js
rename to dom/system/b2g/ril_worker.js
--- a/dom/telephony/Makefile.in
+++ b/dom/telephony/Makefile.in
@@ -56,23 +56,17 @@ CPPSRCS = \
   CallEvent.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorTelephony.idl \
   nsIDOMTelephony.idl \
   nsIDOMTelephonyCall.idl \
   nsIDOMCallEvent.idl \
-  nsITelephone.idl \
-  $(NULL)
-
-EXTRA_COMPONENTS = \
-  nsTelephonyWorker.manifest \
-  nsTelephonyWorker.js \
   $(NULL)
 
-EXTRA_JS_MODULES = \
-  ril_consts.js \
-  ril_worker.js \
-  $(NULL)
+#LOCAL_INCLUDES = \
+#  -I$(topsrcdir)/dom/base \
+#  -I$(topsrcdir)/dom/system/b2g \
+#  -I$(topsrcdir)/content/events/src \
+#  $(NULL)
 
 include $(topsrcdir)/config/rules.mk
-
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -107,49 +107,49 @@ nsTArrayToJSArray(JSContext* aCx, JSObje
   *aResultArray = arrayObj;
   return NS_OK;
 }
 
 } // anonymous namespace
 
 Telephony::~Telephony()
 {
-  if (mTelephone && mTelephoneCallback) {
-    mTelephone->UnregisterCallback(mTelephoneCallback);
+  if (mRIL && mRILTelephonyCallback) {
+    mRIL->UnregisterCallback(mRILTelephonyCallback);
   }
 
   if (mRooted) {
     NS_DROP_JS_OBJECTS(this, Telephony);
   }
 }
 
 // static
 already_AddRefed<Telephony>
-Telephony::Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone)
+Telephony::Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL)
 {
   NS_ASSERTION(aOwner, "Null owner!");
-  NS_ASSERTION(aTelephone, "Null telephone!");
+  NS_ASSERTION(aRIL, "Null RIL!");
 
   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
   NS_ENSURE_TRUE(sgo, nsnull);
 
   nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
   NS_ENSURE_TRUE(scriptContext, nsnull);
 
   nsRefPtr<Telephony> telephony = new Telephony();
 
   telephony->mOwner = aOwner;
   telephony->mScriptContext.swap(scriptContext);
-  telephony->mTelephone = aTelephone;
-  telephony->mTelephoneCallback = new TelephoneCallback(telephony);
+  telephony->mRIL = aRIL;
+  telephony->mRILTelephonyCallback = new RILTelephonyCallback(telephony);
 
-  nsresult rv = aTelephone->EnumerateCalls(telephony->mTelephoneCallback);
+  nsresult rv = aRIL->EnumerateCalls(telephony->mRILTelephonyCallback);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
-  rv = aTelephone->RegisterCallback(telephony->mTelephoneCallback);
+  rv = aRIL->RegisterCallback(telephony->mRILTelephonyCallback);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
   return telephony.forget();
 }
 
 void
 Telephony::SwitchActiveCall(TelephonyCall* aCall)
 {
@@ -190,78 +190,78 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Telephony)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
 
 NS_IMPL_ADDREF_INHERITED(Telephony, nsDOMEventTargetWrapperCache)
 NS_IMPL_RELEASE_INHERITED(Telephony, nsDOMEventTargetWrapperCache)
 
 DOMCI_DATA(Telephony, Telephony)
 
-NS_IMPL_ISUPPORTS1(Telephony::TelephoneCallback, nsITelephoneCallback)
+NS_IMPL_ISUPPORTS1(Telephony::RILTelephonyCallback, nsIRILTelephonyCallback)
 
 NS_IMETHODIMP
 Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
 {
   NS_ENSURE_ARG(!aNumber.IsEmpty());
 
   for (PRUint32 index = 0; index < mCalls.Length(); index++) {
     const nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
     if (tempCall->IsOutgoing() &&
-        tempCall->CallState() < nsITelephone::CALL_STATE_CONNECTED) {
+        tempCall->CallState() < nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
       // One call has been dialed already and we only support one outgoing call
       // at a time.
       NS_WARNING("Only permitted to dial one call at a time!");
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
-  nsresult rv = mTelephone->Dial(aNumber);
+  nsresult rv = mRIL->Dial(aNumber);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<TelephonyCall> call =
-    TelephonyCall::Create(this, aNumber, nsITelephone::CALL_STATE_DIALING);
+    TelephonyCall::Create(this, aNumber, nsIRadioInterfaceLayer::CALL_STATE_DIALING);
   NS_ASSERTION(call, "This should never fail!");
 
   NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
 
   call.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::GetMuted(bool* aMuted)
 {
-  nsresult rv = mTelephone->GetMicrophoneMuted(aMuted);
+  nsresult rv = mRIL->GetMicrophoneMuted(aMuted);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::SetMuted(bool aMuted)
 {
-  nsresult rv = mTelephone->SetMicrophoneMuted(aMuted);
+  nsresult rv = mRIL->SetMicrophoneMuted(aMuted);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::GetSpeakerEnabled(bool* aSpeakerEnabled)
 {
-  nsresult rv = mTelephone->GetSpeakerEnabled(aSpeakerEnabled);
+  nsresult rv = mRIL->GetSpeakerEnabled(aSpeakerEnabled);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::SetSpeakerEnabled(bool aSpeakerEnabled)
 {
-  nsresult rv = mTelephone->SetSpeakerEnabled(aSpeakerEnabled);
+  nsresult rv = mRIL->SetSpeakerEnabled(aSpeakerEnabled);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::GetActive(jsval* aActive)
 {
@@ -334,26 +334,26 @@ Telephony::StartTone(const nsAString& aD
     NS_WARNING("Empty tone string will be ignored");
     return NS_OK;
   }
 
   if (aDTMFChar.Length() > 1) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  nsresult rv = mTelephone->StartTone(aDTMFChar);
+  nsresult rv = mRIL->StartTone(aDTMFChar);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::StopTone()
 {
-  nsresult rv = mTelephone->StopTone();
+  nsresult rv = mRIL->StopTone();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::SendTones(const nsAString& aTones, PRUint32 aToneDuration,
                      PRUint32 aIntervalDuration)
@@ -373,53 +373,53 @@ Telephony::CallStateChanged(PRUint32 aCa
 
   nsRefPtr<TelephonyCall> modifiedCall;
   nsRefPtr<TelephonyCall> outgoingCall;
 
   for (PRUint32 index = 0; index < mCalls.Length(); index++) {
     nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
     if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
       NS_ASSERTION(!outgoingCall, "More than one outgoing call not supported!");
-      NS_ASSERTION(tempCall->CallState() == nsITelephone::CALL_STATE_DIALING,
+      NS_ASSERTION(tempCall->CallState() == nsIRadioInterfaceLayer::CALL_STATE_DIALING,
                    "Something really wrong here!");
       // Stash this for later, we may need it if aCallIndex doesn't match one of
       // our other calls.
       outgoingCall = tempCall;
     } else if (tempCall->CallIndex() == aCallIndex) {
       // We already know about this call so just update its state.
       modifiedCall = tempCall;
       outgoingCall = nsnull;
       break;
     }
   }
 
   // If nothing matched above and the call state isn't incoming but we do have
   // an outgoing call then we must be seeing a status update for our outgoing
   // call.
   if (!modifiedCall &&
-      aCallState != nsITelephone::CALL_STATE_INCOMING &&
+      aCallState != nsIRadioInterfaceLayer::CALL_STATE_INCOMING &&
       outgoingCall) {
     outgoingCall->UpdateCallIndex(aCallIndex);
     modifiedCall.swap(outgoingCall);
   }
 
   if (modifiedCall) {
     // Change state.
     modifiedCall->ChangeState(aCallState);
 
     // See if this should replace our current active call.
-    if (aCallState == nsITelephone::CALL_STATE_CONNECTED) {
+    if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
       SwitchActiveCall(modifiedCall);
     }
 
     return NS_OK;
   }
 
   // Didn't know anything about this call before now, must be incoming.
-  NS_ASSERTION(aCallState == nsITelephone::CALL_STATE_INCOMING,
+  NS_ASSERTION(aCallState == nsIRadioInterfaceLayer::CALL_STATE_INCOMING,
                "Serious logic problem here!");
 
   nsRefPtr<TelephonyCall> call =
     TelephonyCall::Create(this, aNumber, aCallState, aCallIndex);
   NS_ASSERTION(call, "This should never fail!");
 
   NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
 
@@ -506,17 +506,17 @@ NS_NewTelephony(nsPIDOMWindow* aWindow, 
       return NS_OK;
     }
   }
 
   // Security checks passed, make a telephony object.
   nsIInterfaceRequestor* ireq = SystemWorkerManager::GetInterfaceRequestor();
   NS_ENSURE_TRUE(ireq, NS_ERROR_UNEXPECTED);
 
-  nsCOMPtr<nsITelephone> telephone = do_GetInterface(ireq);
-  NS_ENSURE_TRUE(telephone, NS_ERROR_UNEXPECTED);
+  nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetInterface(ireq);
+  NS_ENSURE_TRUE(ril, NS_ERROR_UNEXPECTED);
 
-  nsRefPtr<Telephony> telephony = Telephony::Create(innerWindow, telephone);
+  nsRefPtr<Telephony> telephony = Telephony::Create(innerWindow, ril);
   NS_ENSURE_TRUE(telephony, NS_ERROR_UNEXPECTED);
 
   telephony.forget(aTelephony);
   return NS_OK;
 }
--- a/dom/telephony/Telephony.h
+++ b/dom/telephony/Telephony.h
@@ -39,51 +39,51 @@
 
 #ifndef mozilla_dom_telephony_telephony_h__
 #define mozilla_dom_telephony_telephony_h__
 
 #include "TelephonyCommon.h"
 
 #include "nsIDOMTelephony.h"
 #include "nsIDOMTelephonyCall.h"
-#include "nsITelephone.h"
+#include "nsIRadioInterfaceLayer.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_TELEPHONY_NAMESPACE
 
 class Telephony : public nsDOMEventTargetWrapperCache,
                   public nsIDOMTelephony
 {
-  nsCOMPtr<nsITelephone> mTelephone;
-  nsCOMPtr<nsITelephoneCallback> mTelephoneCallback;
+  nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
+  nsCOMPtr<nsIRILTelephonyCallback> mRILTelephonyCallback;
 
   NS_DECL_EVENT_HANDLER(incoming);
 
   TelephonyCall* mActiveCall;
   nsTArray<nsRefPtr<TelephonyCall> > mCalls;
 
   // Cached calls array object. Cleared whenever mCalls changes and then rebuilt
   // once a page looks for the liveCalls attribute.
   JSObject* mCallsArray;
 
   bool mRooted;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMTELEPHONY
-  NS_DECL_NSITELEPHONECALLBACK
+  NS_DECL_NSIRILTELEPHONYCALLBACK
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
                                                    Telephony,
                                                    nsDOMEventTargetWrapperCache)
 
   static already_AddRefed<Telephony>
-  Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone);
+  Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL);
 
   nsIDOMEventTarget*
   ToIDOMEventTarget() const
   {
     return static_cast<nsDOMEventTargetWrapperCache*>(
              const_cast<Telephony*>(this));
   }
 
@@ -104,20 +104,20 @@ public:
   void
   RemoveCall(TelephonyCall* aCall)
   {
     NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!");
     mCalls.RemoveElement(aCall);
     mCallsArray = nsnull;
   }
 
-  nsITelephone*
-  Telephone() const
+  nsIRadioInterfaceLayer*
+  RIL() const
   {
-    return mTelephone;
+    return mRIL;
   }
 
   nsPIDOMWindow*
   Owner() const
   {
     return mOwner;
   }
 
@@ -132,25 +132,25 @@ private:
   : mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false)
   { }
 
   ~Telephony();
 
   void
   SwitchActiveCall(TelephonyCall* aCall);
 
-  class TelephoneCallback : public nsITelephoneCallback
+  class RILTelephonyCallback : public nsIRILTelephonyCallback
   {
     Telephony* mTelephony;
 
   public:
     NS_DECL_ISUPPORTS
-    NS_FORWARD_NSITELEPHONECALLBACK(mTelephony->)
+    NS_FORWARD_NSIRILTELEPHONYCALLBACK(mTelephony->)
 
-    TelephoneCallback(Telephony* aTelephony)
+    RILTelephonyCallback(Telephony* aTelephony)
     : mTelephony(aTelephony)
     {
       NS_ASSERTION(mTelephony, "Null pointer!");
     }
   };
 };
 
 END_TELEPHONY_NAMESPACE
--- a/dom/telephony/TelephonyCall.cpp
+++ b/dom/telephony/TelephonyCall.cpp
@@ -70,61 +70,61 @@ TelephonyCall::Create(Telephony* aTeleph
 
 void
 TelephonyCall::ChangeStateInternal(PRUint16 aCallState, bool aFireEvents)
 {
   nsRefPtr<TelephonyCall> kungFuDeathGrip(this);
 
   nsString stateString;
   switch (aCallState) {
-    case nsITelephone::CALL_STATE_DIALING:
+    case nsIRadioInterfaceLayer::CALL_STATE_DIALING:
       stateString.AssignLiteral("dialing");
       break;
-    case nsITelephone::CALL_STATE_RINGING:
+    case nsIRadioInterfaceLayer::CALL_STATE_RINGING:
       stateString.AssignLiteral("ringing");
       break;
-    case nsITelephone::CALL_STATE_BUSY:
+    case nsIRadioInterfaceLayer::CALL_STATE_BUSY:
       stateString.AssignLiteral("busy");
       break;
-    case nsITelephone::CALL_STATE_CONNECTING:
+    case nsIRadioInterfaceLayer::CALL_STATE_CONNECTING:
       stateString.AssignLiteral("connecting");
       break;
-    case nsITelephone::CALL_STATE_CONNECTED:
+    case nsIRadioInterfaceLayer::CALL_STATE_CONNECTED:
       stateString.AssignLiteral("connected");
       break;
-    case nsITelephone::CALL_STATE_HOLDING:
+    case nsIRadioInterfaceLayer::CALL_STATE_HOLDING:
       stateString.AssignLiteral("holding");
       break;
-    case nsITelephone::CALL_STATE_HELD:
+    case nsIRadioInterfaceLayer::CALL_STATE_HELD:
       stateString.AssignLiteral("held");
       break;
-    case nsITelephone::CALL_STATE_RESUMING:
+    case nsIRadioInterfaceLayer::CALL_STATE_RESUMING:
       stateString.AssignLiteral("resuming");
       break;
-    case nsITelephone::CALL_STATE_DISCONNECTING:
+    case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING:
       stateString.AssignLiteral("disconnecting");
       break;
-    case nsITelephone::CALL_STATE_DISCONNECTED:
+    case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED:
       stateString.AssignLiteral("disconnected");
       break;
-    case nsITelephone::CALL_STATE_INCOMING:
+    case nsIRadioInterfaceLayer::CALL_STATE_INCOMING:
       stateString.AssignLiteral("incoming");
       break;
     default:
       NS_NOTREACHED("Unknown state!");
   }
 
   mState = stateString;
   mCallState = aCallState;
 
-  if (aCallState == nsITelephone::CALL_STATE_DIALING) {
+  if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_DIALING) {
     mOutgoing = true;
   }
 
-  if (aCallState == nsITelephone::CALL_STATE_DISCONNECTED) {
+  if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED) {
     NS_ASSERTION(mLive, "Should be live!");
     mTelephony->RemoveCall(this);
     mLive = false;
   } else if (!mLive) {
     mTelephony->AddCall(this);
     mLive = true;
   }
 
@@ -203,43 +203,43 @@ TelephonyCall::GetState(nsAString& aStat
 {
   aState.Assign(mState);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyCall::Answer()
 {
-  if (mCallState != nsITelephone::CALL_STATE_INCOMING) {
+  if (mCallState != nsIRadioInterfaceLayer::CALL_STATE_INCOMING) {
     NS_WARNING("Answer on non-incoming call ignored!");
     return NS_OK;
   }
 
-  nsresult rv = mTelephony->Telephone()->AnswerCall(mCallIndex);
+  nsresult rv = mTelephony->RIL()->AnswerCall(mCallIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  ChangeStateInternal(nsITelephone::CALL_STATE_CONNECTING, true);
+  ChangeStateInternal(nsIRadioInterfaceLayer::CALL_STATE_CONNECTING, true);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyCall::HangUp()
 {
-  if (mCallState == nsITelephone::CALL_STATE_DISCONNECTING ||
-      mCallState == nsITelephone::CALL_STATE_DISCONNECTED) {
+  if (mCallState == nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING ||
+      mCallState == nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED) {
     NS_WARNING("HangUp on previously disconnected call ignored!");
     return NS_OK;
   }
 
-  nsresult rv = mCallState == nsITelephone::CALL_STATE_INCOMING ?
-                mTelephony->Telephone()->RejectCall(mCallIndex) :
-                mTelephony->Telephone()->HangUp(mCallIndex);
+  nsresult rv = mCallState == nsIRadioInterfaceLayer::CALL_STATE_INCOMING ?
+                mTelephony->RIL()->RejectCall(mCallIndex) :
+                mTelephony->RIL()->HangUp(mCallIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  ChangeStateInternal(nsITelephone::CALL_STATE_DISCONNECTING, true);
+  ChangeStateInternal(nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING, true);
   return NS_OK;
 }
 
 NS_IMPL_EVENT_HANDLER(TelephonyCall, statechange)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, dialing)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, ringing)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, busy)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, connecting)
--- a/dom/telephony/TelephonyCall.h
+++ b/dom/telephony/TelephonyCall.h
@@ -38,17 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_telephony_telephonycall_h__
 #define mozilla_dom_telephony_telephonycall_h__
 
 #include "TelephonyCommon.h"
 
 #include "nsIDOMTelephonyCall.h"
-#include "nsITelephone.h"
+#include "nsIRadioInterfaceLayer.h"
 
 class nsPIDOMWindow;
 
 BEGIN_TELEPHONY_NAMESPACE
 
 class TelephonyCall : public nsDOMEventTargetWrapperCache,
                       public nsIDOMTelephonyCall
 {
@@ -126,17 +126,17 @@ public:
   IsOutgoing() const
   {
     return mOutgoing;
   }
 
 private:
   TelephonyCall()
   : mCallIndex(kOutgoingPlaceholderCallIndex),
-    mCallState(nsITelephone::CALL_STATE_UNKNOWN), mLive(false), mOutgoing(false)
+    mCallState(nsIRadioInterfaceLayer::CALL_STATE_UNKNOWN), mLive(false), mOutgoing(false)
   { }
 
   ~TelephonyCall()
   { }
 
   void
   ChangeStateInternal(PRUint16 aCallState, bool aFireEvents);
 };
--- a/dom/tests/mochitest/chrome/focus_frameset.html
+++ b/dom/tests/mochitest/chrome/focus_frameset.html
@@ -9,14 +9,14 @@ SimpleTest.waitForFocus(function () open
 <frameset rows="30%, 70%">
   <frame src="data:text/html,&lt;html id='f1' &gt;&lt;body id='framebody1'&gt;&lt;input id='f2'&gt;&lt;body&gt;&lt;/html&gt;">
   <frameset cols="30%, 33%, 34%">
     <frame src="data:text/html,&lt;html id='f3'&gt;&lt;body id='framebody2'&gt;&lt;input id='f4'&gt;&lt;body&gt;&lt;/html&gt;">
     <frame src="data:text/html,&lt;html id='f5'&gt;&lt;body id='framebody3'&gt;&lt;input id='f6' tabindex='2'&gt;&lt;body&gt;&lt;/html&gt;">
     <frame src="data:text/html,&lt;html id='f7'&gt;&lt;body id='framebody4'&gt;&lt;input id='f8'&gt;&lt;body&gt;&lt;/html&gt;">
   </frameset>
   <noframes>
-    <input id="unusued1"/>
-    <input id="unusued2" tabindex="1"/>
+    <input id="unused1"/>
+    <input id="unused2" tabindex="1"/>
   </noframes>
 </frameset>
 
 </html>
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -108,17 +108,18 @@ public class GeckoAppShell
 
     // helper methods
     public static native void setSurfaceView(GeckoSurfaceView sv);
     public static native void putenv(String map);
     public static native void onResume();
     public static native void onLowMemory();
     public static native void callObserver(String observerKey, String topic, String data);
     public static native void removeObserver(String observerKey);
-    public static native void loadLibs(String apkName, boolean shouldExtract);
+    public static native void loadGeckoLibsNative(String apkName);
+    public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
     public static native void onChangeNetworkLinkStatus(String status);
     public static native void reportJavaCrash(String stack);
 
     public static native void processNextNativeEvent();
 
     public static native void notifyBatteryChange(double aLevel, boolean aCharging, double aRemainingTime);
 
     public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp);
@@ -391,17 +392,18 @@ public class GeckoAppShell
                 Iterator cacheFiles = Arrays.asList(files).iterator();
                 while (cacheFiles.hasNext()) {
                     File libFile = (File)cacheFiles.next();
                     if (libFile.getName().endsWith(".so"))
                         libFile.delete();
                 }
             }
         }
-        loadLibs(apkName, extractLibs);
+        loadSQLiteLibsNative(apkName, extractLibs);
+        loadGeckoLibsNative(apkName);
     }
 
     private static void putLocaleEnv() {
         GeckoAppShell.putenv("LANG=" + Locale.getDefault().toString());
         NumberFormat nf = NumberFormat.getInstance();
         if (nf instanceof DecimalFormat) {
             DecimalFormat df = (DecimalFormat)nf;
             DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -111,16 +111,17 @@ DrawTargetCG::DrawTargetCG()
 
 DrawTargetCG::~DrawTargetCG()
 {
   // We need to conditionally release these because Init can fail without initializing these.
   if (mColorSpace)
     CGColorSpaceRelease(mColorSpace);
   if (mCg)
     CGContextRelease(mCg);
+  free(mData);
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCG::Snapshot()
 {
   RefPtr<SourceSurfaceCG> newSurf = new SourceSurfaceCG(CGBitmapContextCreateImage(mCg));
   return newSurf;
 }
@@ -840,17 +841,16 @@ DrawTargetCG::Init(const IntSize &aSize,
 
   CGBitmapInfo bitinfo;
 
   bitinfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
 
   // XXX: currently we allocate ourselves so that we can easily return a gfxImageSurface
   // we might not need to later if once we don't need to support gfxImageSurface
   //XXX: currently Init implicitly clears, that can often be a waste of time
-  // XXX: leaked
   mData = calloc(mSize.height * stride, 1);
   // XXX: what should we do if this fails?
   mCg = CGBitmapContextCreate (mData,
                                mSize.width,
                                mSize.height,
                                bitsPerComponent,
                                stride,
                                mColorSpace,
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -126,22 +126,29 @@ CPPSRCS += \
         ThebesLayerD3D10.cpp \
         $(NULL)
 endif
 endif
 
 EXPORTS_NAMESPACES = gfxipc mozilla/layers
 EXPORTS_gfxipc = ShadowLayerUtils.h
 EXPORTS_mozilla/layers =\
+        CompositorCocoaWidgetHelper.h \
+        CompositorChild.h \
+        CompositorParent.h \
         ShadowLayers.h \
         ShadowLayersChild.h \
         ShadowLayersParent.h \
+        ShadowLayersManager.h \
         $(NULL)
 
 CPPSRCS += \
+        CompositorCocoaWidgetHelper.cpp \
+        CompositorChild.cpp \
+        CompositorParent.cpp \
         ShadowLayers.cpp \
         ShadowLayerChild.cpp \
         ShadowLayersChild.cpp \
         ShadowLayerParent.cpp \
         ShadowLayersParent.cpp \
         $(NULL)
 
 ifdef MOZ_X11 #{
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -45,48 +45,52 @@
 namespace mozilla {
 namespace layers {
 
 static already_AddRefed<ID3D10Texture2D>
 SurfaceToTexture(ID3D10Device *aDevice,
                  gfxASurface *aSurface,
                  const gfxIntSize &aSize)
 {
-  if (aSurface && aSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
+  if (!aSurface) {
+    return NULL;
+  }
+
+  if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
     void *data = aSurface->GetData(&gKeyD3D10Texture);
     if (data) {
       nsRefPtr<ID3D10Texture2D> texture = static_cast<ID3D10Texture2D*>(data);
       ID3D10Device *dev;
       texture->GetDevice(&dev);
       if (dev == aDevice) {
         return texture.forget();
       }
     }
   }
 
   nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
 
   if (!imageSurface) {
     imageSurface = new gfxImageSurface(aSize,
                                        gfxASurface::ImageFormatARGB32);
-    
+
     nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
     context->SetSource(aSurface);
     context->SetOperator(gfxContext::OPERATOR_SOURCE);
     context->Paint();
   }
 
   D3D10_SUBRESOURCE_DATA data;
-  
+
   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
                              imageSurface->GetSize().width,
                              imageSurface->GetSize().height,
                              1, 1);
   desc.Usage = D3D10_USAGE_IMMUTABLE;
-  
+
   data.pSysMem = imageSurface->Data();
   data.SysMemPitch = imageSurface->Stride();
 
   nsRefPtr<ID3D10Texture2D> texture;
   HRESULT hr = aDevice->CreateTexture2D(&desc, &data, getter_AddRefs(texture));
 
   if (FAILED(hr)) {
     LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for image surface"),
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=2 ts=2 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "CompositorChild.h"
+#include "CompositorParent.h"
+#include "LayerManagerOGL.h"
+#include "mozilla/layers/ShadowLayersChild.h"
+
+using mozilla::layers::ShadowLayersChild;
+
+namespace mozilla {
+namespace layers {
+
+CompositorChild::CompositorChild(LayerManager *aLayerManager)
+  : mLayerManager(aLayerManager)
+{
+  MOZ_COUNT_CTOR(CompositorChild);
+}
+
+CompositorChild::~CompositorChild()
+{
+  MOZ_COUNT_DTOR(CompositorChild);
+}
+
+void
+CompositorChild::Destroy()
+{
+  mLayerManager = NULL;
+  size_t numChildren = ManagedPLayersChild().Length();
+  NS_ABORT_IF_FALSE(0 == numChildren || 1 == numChildren,
+                    "compositor must only have 0 or 1 layer forwarder");
+
+  if (numChildren) {
+    ShadowLayersChild* layers =
+      static_cast<ShadowLayersChild*>(ManagedPLayersChild()[0]);
+    layers->Destroy();
+  }
+  SendStop();
+}
+
+PLayersChild*
+CompositorChild::AllocPLayers(const LayersBackend &backend)
+{
+  return new ShadowLayersChild();
+}
+
+bool
+CompositorChild::DeallocPLayers(PLayersChild* actor)
+{
+  delete actor;
+  return true;
+}
+
+} // namespace layers
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_layers_CompositorChild_h
+#define mozilla_layers_CompositorChild_h
+
+#include "mozilla/layers/PCompositorChild.h"
+
+namespace mozilla {
+namespace layers {
+
+class LayerManager;
+class CompositorParent;
+
+class CompositorChild : public PCompositorChild
+{
+  NS_INLINE_DECL_REFCOUNTING(CompositorChild)
+public:
+  CompositorChild(LayerManager *aLayerManager);
+  virtual ~CompositorChild();
+
+  void Destroy();
+
+protected:
+  virtual PLayersChild* AllocPLayers(const LayersBackend &aBackend);
+  virtual bool DeallocPLayers(PLayersChild *aChild);
+
+private:
+  nsRefPtr<LayerManager> mLayerManager;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CompositorChild);
+};
+
+} // layers
+} // mozilla
+
+#endif // mozilla_layers_CompositorChild_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorCocoaWidgetHelper.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "CompositorParent.h"
+#include "CompositorCocoaWidgetHelper.h"
+#include "nsDebug.h"
+
+namespace mozilla {
+namespace layers {
+namespace compositor {
+
+LayerManager*
+GetLayerManager(CompositorParent* aParent)
+{
+  return aParent->GetLayerManager();
+}
+
+
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorCocoaWidgetHelper.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_layers_CompositorCocoaWidgetHelper_h
+#define mozilla_layers_CompositorCocoaWidgetHelper_h
+
+// Note we can't include IPDL-generated headers here, since this file is being
+// used as a workaround for Bug 719036.
+
+namespace mozilla {
+namespace layers {
+
+class CompositorParent;
+class LayerManager;
+
+namespace compositor {
+
+// Needed when we cannot directly include CompositorParent.h since it includes
+// an IPDL-generated header (e.g. in widget/cocoa/nsChildView.mm; see Bug 719036).
+LayerManager* GetLayerManager(CompositorParent* aParent);
+
+}
+}
+}
+#endif // mozilla_layers_CompositorCocoaWidgetHelper_h
+
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=2 ts=2 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "CompositorParent.h"
+#include "ShadowLayersParent.h"
+#include "LayerManagerOGL.h"
+#include "nsIWidget.h"
+
+namespace mozilla {
+namespace layers {
+
+CompositorParent::CompositorParent(nsIWidget* aWidget)
+  : mStopped(false), mWidget(aWidget)
+{
+  MOZ_COUNT_CTOR(CompositorParent);
+}
+
+CompositorParent::~CompositorParent()
+{
+  MOZ_COUNT_DTOR(CompositorParent);
+}
+
+void
+CompositorParent::Destroy()
+{
+  NS_ABORT_IF_FALSE(ManagedPLayersParent().Length() == 0,
+                    "CompositorParent destroyed before managed PLayersParent");
+
+  // Ensure that the layer manager is destroyed on the compositor thread.
+  mLayerManager = NULL;
+}
+
+bool
+CompositorParent::RecvStop()
+{
+  mStopped = true;
+  Destroy();
+  return true;
+}
+
+void
+CompositorParent::ScheduleComposition()
+{
+  CancelableTask *composeTask = NewRunnableMethod(this, &CompositorParent::Composite);
+  MessageLoop::current()->PostTask(FROM_HERE, composeTask);
+}
+
+void
+CompositorParent::Composite()
+{
+  if (mStopped || !mLayerManager) {
+    return;
+  }
+
+  mLayerManager->EndEmptyTransaction();
+}
+
+// Go down shadow layer tree, setting properties to match their non-shadow
+// counterparts.
+static void
+SetShadowProperties(Layer* aLayer)
+{
+  // FIXME: Bug 717688 -- Do these updates in ShadowLayersParent::RecvUpdate.
+  ShadowLayer* shadow = aLayer->AsShadowLayer();
+  shadow->SetShadowTransform(aLayer->GetTransform());
+  shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
+  shadow->SetShadowClipRect(aLayer->GetClipRect());
+
+  for (Layer* child = aLayer->GetFirstChild();
+      child; child = child->GetNextSibling()) {
+    SetShadowProperties(child);
+  }
+}
+
+void
+CompositorParent::ShadowLayersUpdated()
+{
+  const nsTArray<PLayersParent*>& shadowParents = ManagedPLayersParent();
+  NS_ABORT_IF_FALSE(shadowParents.Length() <= 1,
+                    "can only support at most 1 ShadowLayersParent");
+  if (shadowParents.Length()) {
+    Layer* root = static_cast<ShadowLayersParent*>(shadowParents[0])->GetRoot();
+    mLayerManager->SetRoot(root);
+    SetShadowProperties(root);
+  }
+  ScheduleComposition();
+}
+
+PLayersParent*
+CompositorParent::AllocPLayers(const LayersBackend &backendType)
+{
+  if (backendType == LayerManager::LAYERS_OPENGL) {
+    nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(mWidget);
+    mWidget = NULL;
+    mLayerManager = layerManager;
+
+    if (!layerManager->Initialize()) {
+      NS_ERROR("Failed to init OGL Layers");
+      return NULL;
+    }
+
+    ShadowLayerManager* slm = layerManager->AsShadowManager();
+    if (!slm) {
+      return NULL;
+    }
+    return new ShadowLayersParent(slm, this);
+  } else {
+    NS_ERROR("Unsupported backend selected for Async Compositor");
+    return NULL;
+  }
+}
+
+bool
+CompositorParent::DeallocPLayers(PLayersParent* actor)
+{
+  delete actor;
+  return true;
+}
+
+} // namespace layers
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_layers_CompositorParent_h
+#define mozilla_layers_CompositorParent_h
+
+#include "mozilla/layers/PCompositorParent.h"
+#include "mozilla/layers/PLayersParent.h"
+#include "ShadowLayersManager.h"
+
+class nsIWidget;
+
+namespace mozilla {
+namespace layers {
+
+class LayerManager;
+
+class CompositorParent : public PCompositorParent,
+                         public ShadowLayersManager
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorParent)
+public:
+  CompositorParent(nsIWidget* aWidget);
+  virtual ~CompositorParent();
+
+  virtual bool RecvStop() MOZ_OVERRIDE;
+
+  virtual void ShadowLayersUpdated() MOZ_OVERRIDE;
+  void Destroy();
+
+  LayerManager* GetLayerManager() { return mLayerManager; }
+
+protected:
+  virtual PLayersParent* AllocPLayers(const LayersBackend &backendType);
+  virtual bool DeallocPLayers(PLayersParent* aLayers);
+
+private:
+  void ScheduleComposition();
+  void Composite();
+
+  nsRefPtr<LayerManager> mLayerManager;
+  bool mStopped;
+  nsIWidget* mWidget;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
+};
+
+} // layers
+} // mozilla
+
+#endif // mozilla_layers_CompositorParent_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <bgirard@mozilla.com>
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+include protocol PLayers;
+
+using mozilla::LayersBackend;
+using mozilla::null_t;
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * The PCompositor protocol is used to manage communication between
+ * the main thread and the compositor thread context. It's primary
+ * purpose is to manage the PLayers sub protocol.
+ */
+// This should really be 'sync', but we're using 'rpc' as a workaround
+// for Bug 716631.
+rpc protocol PCompositor
+{
+  // A Compositor manages a single Layer Manager (PLayers)
+  manages PLayers;
+
+parent:  
+
+  // Clean up in preparation for destruction.
+  sync Stop();
+
+  sync PLayers(LayersBackend backend);
+};
+
+} // layers
+} // mozilla
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -33,17 +33,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-//include protocol PCompositor;
+include protocol PCompositor;
 include protocol PLayer;
 include protocol PRenderFrame;
 
 include "gfxipc/ShadowLayerUtils.h";
 
 using gfx3DMatrix;
 using gfxRGBA;
 using nsIntPoint;
@@ -221,17 +221,17 @@ struct OpThebesBufferSwap {
 union EditReply {
   OpBufferSwap;
   OpThebesBufferSwap;
   OpImageSwap;
 };
 
 
 sync protocol PLayers {
-  manager PRenderFrame /*or PCompositor or PMedia or PPlugin*/;
+  manager PRenderFrame or PCompositor;
   manages PLayer;
 
 parent:
   async PLayer();
 
   sync Update(Edit[] cset)
     returns (EditReply[] reply);
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayersManager.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ali Juma <ajuma@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_layers_ShadowLayersManager_h
+#define mozilla_layers_ShadowLayersManager_h
+
+namespace mozilla {
+
+namespace layout {
+class RenderFrameParent;
+}
+
+namespace layers {
+
+class CompositorParent;
+
+class ShadowLayersManager
+{
+
+public:
+  virtual void ShadowLayersUpdated() = 0;
+};
+
+} // layers
+} // mozilla
+
+#endif // mozilla_layers_ShadowLayersManager_h
--- a/gfx/layers/ipc/ShadowLayersParent.cpp
+++ b/gfx/layers/ipc/ShadowLayersParent.cpp
@@ -42,16 +42,17 @@
 
 #include "ShadowLayersParent.h"
 #include "ShadowLayerParent.h"
 #include "ShadowLayers.h"
 
 #include "mozilla/unused.h"
 
 #include "mozilla/layout/RenderFrameParent.h"
+#include "CompositorParent.h"
 
 #include "gfxSharedImageSurface.h"
 
 #include "ImageLayers.h"
 
 typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
 
 using mozilla::layout::RenderFrameParent;
@@ -116,21 +117,21 @@ ShadowContainer(const OpRemoveChild& op)
 static ShadowLayerParent*
 ShadowChild(const OpRemoveChild& op)
 {
   return cast(op.childLayerParent());
 }
 
 //--------------------------------------------------
 // ShadowLayersParent
-ShadowLayersParent::ShadowLayersParent(ShadowLayerManager* aManager)
-  : mDestroyed(false)
+ShadowLayersParent::ShadowLayersParent(ShadowLayerManager* aManager,
+                                       ShadowLayersManager* aLayersManager)
+  : mLayerManager(aManager), mShadowLayersManager(aLayersManager), mDestroyed(false)
 {
   MOZ_COUNT_CTOR(ShadowLayersParent);
-  mLayerManager = aManager;
 }
 
 ShadowLayersParent::~ShadowLayersParent()
 {
   MOZ_COUNT_DTOR(ShadowLayersParent);
 }
 
 void
@@ -377,17 +378,17 @@ ShadowLayersParent::RecvUpdate(const Inf
     reply->AppendElements(&replyv.front(), replyv.size());
   }
 
   // Ensure that any pending operations involving back and front
   // buffers have completed, so that neither process stomps on the
   // other's buffer contents.
   ShadowLayerManager::PlatformSyncBeforeReplyUpdate();
 
-  Frame()->ShadowLayersUpdated();
+  mShadowLayersManager->ShadowLayersUpdated();
 
   return true;
 }
 
 PLayerParent*
 ShadowLayersParent::AllocPLayer()
 {
   return new ShadowLayerParent();
@@ -395,22 +396,16 @@ ShadowLayersParent::AllocPLayer()
 
 bool
 ShadowLayersParent::DeallocPLayer(PLayerParent* actor)
 {
   delete actor;
   return true;
 }
 
-RenderFrameParent*
-ShadowLayersParent::Frame()
-{
-  return static_cast<RenderFrameParent*>(Manager());
-}
-
 void
 ShadowLayersParent::DestroySharedSurface(gfxSharedImageSurface* aSurface)
 {
   layer_manager()->DestroySharedSurface(aSurface, this);
 }
 
 void
 ShadowLayersParent::DestroySharedSurface(SurfaceDescriptor* aSurface)
--- a/gfx/layers/ipc/ShadowLayersParent.h
+++ b/gfx/layers/ipc/ShadowLayersParent.h
@@ -38,16 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_layers_ShadowLayersParent_h
 #define mozilla_layers_ShadowLayersParent_h
 
 #include "mozilla/layers/PLayersParent.h"
 #include "ShadowLayers.h"
+#include "ShadowLayersManager.h"
 
 namespace mozilla {
 
 namespace layout {
 class RenderFrameParent;
 }
 
 namespace layers {
@@ -58,17 +59,17 @@ class ShadowLayerManager;
 class ShadowLayersParent : public PLayersParent,
                            public ISurfaceDeAllocator
 {
   typedef mozilla::layout::RenderFrameParent RenderFrameParent;
   typedef InfallibleTArray<Edit> EditArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
 
 public:
-  ShadowLayersParent(ShadowLayerManager* aManager);
+  ShadowLayersParent(ShadowLayerManager* aManager, ShadowLayersManager* aLayersManager);
   ~ShadowLayersParent();
 
   void Destroy();
 
   ShadowLayerManager* layer_manager() const { return mLayerManager; }
 
   ContainerLayer* GetRoot() const { return mRoot; }
 
@@ -78,19 +79,18 @@ public:
 protected:
   NS_OVERRIDE virtual bool RecvUpdate(const EditArray& cset,
                                       EditReplyArray* reply);
 
   NS_OVERRIDE virtual PLayerParent* AllocPLayer();
   NS_OVERRIDE virtual bool DeallocPLayer(PLayerParent* actor);
 
 private:
-  RenderFrameParent* Frame();
-
   nsRefPtr<ShadowLayerManager> mLayerManager;
+  ShadowLayersManager* mShadowLayersManager;
   // Hold the root because it might be grafted under various
   // containers in the "real" layer tree
   nsRefPtr<ContainerLayer> mRoot;
   // When the widget/frame/browser stuff in this process begins its
   // destruction process, we need to Disconnect() all the currently
   // live shadow layers, because some of them might be orphaned from
   // the layer tree.  This happens in Destroy() above.  After we
   // Destroy() ourself, there's a window in which that information
--- a/gfx/layers/ipc/ipdl.mk
+++ b/gfx/layers/ipc/ipdl.mk
@@ -1,4 +1,5 @@
 IPDLSRCS = \
+  PCompositor.ipdl \
   PLayer.ipdl \
   PLayers.ipdl \
   $(NULL)
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1405,18 +1405,16 @@ ContainerState::ProcessDisplayItems(cons
       // Note that items without their own layers can't be skipped this
       // way, since their ThebesLayer may decide it wants to draw them
       // into its buffer even if they're currently covered.
       if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
         InvalidateForLayerChange(item, nsnull);
         continue;
       }
 
-      aClip.RemoveRoundedCorners();
-
       // Just use its layer.
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
         InvalidateForLayerChange(item, ownLayer);
         continue;
       }
 
       // If it's not a ContainerLayer, we need to apply the scale transform
@@ -1430,20 +1428,23 @@ ContainerState::ProcessDisplayItems(cons
 
       ownLayer->SetIsFixedPosition(!nsLayoutUtils::ScrolledByViewportScrolling(
                                       activeScrolledRoot, mBuilder));
 
       // Update that layer's clip and visible rects.
       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
       NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
+      NS_ASSERTION(aClip.mHaveClipRect ||
+                     aClip.mRoundedClipRects.IsEmpty(),
+                   "If we have rounded rects, we must have a clip rect");
       // It has its own layer. Update that layer's clip and visible rects.
       if (aClip.mHaveClipRect) {
         ownLayer->IntersectClipRect(
-            aClip.mClipRect.ScaleToNearestPixels(
+            aClip.NonRoundedIntersection().ScaleToNearestPixels(
                 mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel));
       }
       ThebesLayerData* data = GetTopThebesLayerData();
       if (data) {
         data->mVisibleAboveRegion.Or(data->mVisibleAboveRegion, itemVisibleRect);
         data->mVisibleAboveRegion.SimplifyOutward(4);
         // Add the entire bounds rect to the mDrawAboveRegion.
         // The visible region may be excluding opaque content above the
@@ -2359,17 +2360,16 @@ FrameLayerBuilder::Clip::IsRectClippedBy
     }
   }
   return false;
 }
 
 nsRect
 FrameLayerBuilder::Clip::NonRoundedIntersection() const
 {
-  NS_ASSERTION(!mRoundedClipRects.IsEmpty(), "no rounded clip rects?");
   nsRect result = mClipRect;
   for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
        i < iEnd; ++i) {
     result.IntersectRect(result, mRoundedClipRects[i].mRect);
   }
   return result;
 }
 
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -643,17 +643,17 @@ RenderFrameParent::AllocPLayers(LayerMan
   }
   LayerManager* lm = GetLayerManager();
   ShadowLayerManager* slm = lm->AsShadowManager();
   if (!slm) {
     *aBackendType = LayerManager::LAYERS_NONE;
      return nsnull;
   }
   *aBackendType = lm->GetBackendType();
-  return new ShadowLayersParent(slm);
+  return new ShadowLayersParent(slm, this);
 }
 
 bool
 RenderFrameParent::DeallocPLayers(PLayersParent* aLayers)
 {
   delete aLayers;
   return true;
 }
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -37,16 +37,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_layout_RenderFrameParent_h
 #define mozilla_layout_RenderFrameParent_h
 
 #include "mozilla/layout/PRenderFrameParent.h"
+#include "mozilla/layers/ShadowLayersManager.h"
 
 #include <map>
 #include "nsDisplayList.h"
 #include "Layers.h"
 
 class nsContentView;
 class nsFrameLoader;
 class nsSubDocumentFrame;
@@ -54,17 +55,18 @@ class nsSubDocumentFrame;
 namespace mozilla {
 
 namespace layers {
 class ShadowLayersParent;
 }
 
 namespace layout {
 
-class RenderFrameParent : public PRenderFrameParent
+class RenderFrameParent : public PRenderFrameParent,
+                          public mozilla::layers::ShadowLayersManager
 {
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ContainerLayer ContainerLayer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ShadowLayersParent ShadowLayersParent;
   typedef FrameMetrics::ViewID ViewID;
 
@@ -79,17 +81,17 @@ public:
   /**
    * Helper function for getting a non-owning reference to a scrollable.
    * @param aId The ID of the frame.
    */
   nsContentView* GetContentView(ViewID aId = FrameMetrics::ROOT_SCROLL_ID);
 
   void ContentViewScaleChanged(nsContentView* aView);
 
-  void ShadowLayersUpdated();
+  virtual void ShadowLayersUpdated() MOZ_OVERRIDE;
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
                               nsSubDocumentFrame* aFrame,
                               const nsRect& aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/718521-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Rounded rectangle clipping test</title>
+<style>
+.clipround {
+  left:100px;
+  top:100px;
+  position:absolute;
+  width:700px;
+  height:380px;
+  overflow:hidden;
+  border-radius:45px;
+}
+.greendiv {
+  width:300px;
+  height:230px;
+  background-color:#008000;
+  position:absolute;
+}
+#nrcDiv0 {
+  left:0px;
+  top:0px;
+}
+#nrcDiv1 {
+  left:320px;
+  top:0px;
+}
+#nrcDiv2 {
+  left:0px;
+  top:240px;
+}
+</style>
+</head>
+
+<body>
+<div class="clipround">
+<div id="nrcDiv0" class="greendiv"></div>
+</div>
+<div class="clipround">
+<div id="nrcDiv1" class="greendiv"></div>
+</div>
+<div class="clipround">
+<div id="nrcDiv2" class="greendiv"></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/718521.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Rounded rectangle clipping test</title>
+<style>
+.clipround {
+  left:100px;
+  top:100px;
+  position:absolute;
+  width:700px;
+  height:380px;
+  overflow:hidden;
+  border-radius:45px;
+}
+canvas {
+  position:absolute;
+}
+#nrcCanvas0 {
+  left:0px;
+  top:0px;
+}
+#nrcCanvas1 {
+  left:320px;
+  top:0px;
+}
+#nrcCanvas2 {
+  left:0px;
+  top:240px;
+}
+</style>
+</head>
+
+<body>
+<div class="clipround">
+<canvas id="nrcCanvas0" width="320" height="260"></canvas> 
+<canvas id="nrcCanvas1" width="320" height="260"></canvas>
+<canvas id="nrcCanvas2" width="320" height="260"></canvas> 
+</div>
+
+<script>
+  drawShapes('nrcCanvas0');
+  drawShapes('nrcCanvas1');
+  drawShapes('nrcCanvas2');
+    
+  function drawShapes(elName) {
+    var ctxt = document.getElementById(elName).getContext('2d');
+    ctxt.fillStyle = '#008000';
+    ctxt.fillRect(0, 0, 300, 230);
+  }
+</script>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1683,8 +1683,9 @@ needs-focus != 703186-1.html 703186-2.ht
 == 711359-1.html 711359-1-ref.html
 == 712849-1.html 712849-1-ref.html
 == 713856-static.html  713856-ref.html
 == 713856-dynamic.html 713856-ref.html
 == 714519-1-as.html 714519-1-ref.html
 == 714519-1-q.html 714519-1-ref.html
 == 714519-2-as.html 714519-2-ref.html
 == 714519-2-q.html 714519-2-ref.html
+fuzzy == 718521.html 718521-ref.html
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -168,17 +168,17 @@ public class AboutHomeContent extends Sc
     void init(final Activity activity) {
         mInflater.inflate(R.layout.abouthome_content, this);
         final Runnable generateCursorsRunnable = new Runnable() {
             public void run() {
                 if (mCursor != null)
                     activity.stopManagingCursor(mCursor);
 
                 ContentResolver resolver = GeckoApp.mAppContext.getContentResolver();
-                mCursor = BrowserDB.filter(resolver, "", NUMBER_OF_TOP_SITES_PORTRAIT, "about:%");
+                mCursor = BrowserDB.getTopSites(resolver, NUMBER_OF_TOP_SITES_PORTRAIT);
                 activity.startManagingCursor(mCursor);
 
                 mTopSitesAdapter = new TopSitesCursorAdapter(activity,
                                                              R.layout.abouthome_topsite_item,
                                                              mCursor,
                                                              new String[] { URLColumns.TITLE,
                                                                             URLColumns.THUMBNAIL },
                                                              new int[] { R.id.title, R.id.thumbnail });
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -888,17 +888,18 @@ abstract public class GeckoApp
                 handleSecurityChange(tabId, mode);
             } else if (event.equals("Content:StateChange")) {
                 final int tabId = message.getInt("tabID");
                 int state = message.getInt("state");
                 Log.i(LOGTAG, "State - " + state);
                 if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
                     if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
                         Log.i(LOGTAG, "Got a document start");
-                        handleDocumentStart(tabId);
+                        final boolean showProgress = message.getBoolean("showProgress");
+                        handleDocumentStart(tabId, showProgress);
                     } else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
                         Log.i(LOGTAG, "Got a document stop");
                         handleDocumentStop(tabId);
                     }
                 }
             } else if (event.equals("Content:LoadError")) {
                 final int tabId = message.getInt("tabID");
                 final String uri = message.getString("uri");
@@ -1176,29 +1177,30 @@ abstract public class GeckoApp
                     mBrowserToolbar.setProgressVisibility(tab.isLoading());
                     mDoorHangerPopup.updatePopup();
                     mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
                 }
             }
         });
     }
 
-    void handleDocumentStart(int tabId) {
+    void handleDocumentStart(int tabId, final boolean showProgress) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
             return;
 
         tab.setLoading(true);
         tab.updateSecurityMode("unknown");
 
         mMainHandler.post(new Runnable() {
             public void run() {
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
-                    mBrowserToolbar.setProgressVisibility(true);
+                    if (showProgress)
+                        mBrowserToolbar.setProgressVisibility(true);
                 }
                 onTabsChanged(tab);
             }
         });
     }
 
     void handleDocumentStop(int tabId) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
@@ -2094,19 +2096,20 @@ abstract public class GeckoApp
         }
         return status;
     }
 
     private void checkMigrateProfile() {
         File profileDir = getProfileDir();
         if (profileDir != null) {
             Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath());
+            final GeckoApp app = GeckoApp.mAppContext;
+            GeckoAppShell.ensureSQLiteLibsLoaded(app.getApplication().getPackageResourcePath());
             ProfileMigrator profileMigrator =
-                new ProfileMigrator(GeckoApp.mAppContext.getContentResolver(),
-                                    profileDir);
+                new ProfileMigrator(app.getContentResolver(), profileDir);
             profileMigrator.launchBackground();
         }
     }
 
     private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue<String>();
     public String showFilePicker(String aMimeType) {
         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
         intent.addCategory(Intent.CATEGORY_OPENABLE);
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -107,16 +107,17 @@ public class GeckoAppShell
     static public final int WPL_STATE_STOP = 0x00000010;
     static public final int WPL_STATE_IS_DOCUMENT = 0x00020000;
     static public final int WPL_STATE_IS_NETWORK = 0x00040000;
 
     static private File sCacheFile = null;
     static private int sFreeSpace = -1;
     static File sHomeDir = null;
     static private int sDensityDpi = 0;
+    private static Boolean sSQLiteLibsLoaded = false;
 
     private static HashMap<String, ArrayList<GeckoEventListener>> mEventListeners;
 
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void nativeInit();
     public static native void nativeRun(String args);
@@ -124,17 +125,18 @@ public class GeckoAppShell
     // helper methods
     //    public static native void setSurfaceView(GeckoSurfaceView sv);
     public static native void setSoftwareLayerClient(GeckoSoftwareLayerClient client);
     public static native void putenv(String map);
     public static native void onResume();
     public static native void onLowMemory();
     public static native void callObserver(String observerKey, String topic, String data);
     public static native void removeObserver(String observerKey);
-    public static native void loadLibs(String apkName, boolean shouldExtract);
+    public static native void loadGeckoLibsNative(String apkName);
+    public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
     public static native void onChangeNetworkLinkStatus(String status);
     public static native void reportJavaCrash(String stack);
     public static void notifyUriVisited(String uri) {
         sendEventToGecko(new GeckoEvent(GeckoEvent.VISTITED, uri));
     }
 
     public static native void processNextNativeEvent();
 
@@ -305,17 +307,17 @@ public class GeckoAppShell
             from.delete();
         } catch(Exception e) {
             Log.e(LOGTAG, "error trying to move file", e);
         }
         return retVal;
     }
 
     // java-side stuff
-    public static void loadGeckoLibs(String apkName) {
+    public static boolean loadLibsSetup(String apkName) {
         // The package data lib directory isn't placed in ld.so's
         // search path, so we have to manually load libraries that
         // libxul will depend on.  Not ideal.
         GeckoApp geckoApp = GeckoApp.mAppContext;
         String homeDir;
         sHomeDir = GeckoDirProvider.getFilesDir(geckoApp);
         homeDir = sHomeDir.getPath();
 
@@ -410,17 +412,33 @@ public class GeckoAppShell
                 Iterator cacheFiles = Arrays.asList(files).iterator();
                 while (cacheFiles.hasNext()) {
                     File libFile = (File)cacheFiles.next();
                     if (libFile.getName().endsWith(".so"))
                         libFile.delete();
                 }
             }
         }
-        loadLibs(apkName, extractLibs);
+        return extractLibs;
+    }
+
+    public static void ensureSQLiteLibsLoaded(String apkName) {
+        if (sSQLiteLibsLoaded)
+            return;
+        synchronized(sSQLiteLibsLoaded) {
+            if (sSQLiteLibsLoaded)
+                return;
+            loadSQLiteLibsNative(apkName, loadLibsSetup(apkName));
+            sSQLiteLibsLoaded = true;
+        }
+    }
+
+    public static void loadGeckoLibs(String apkName) {
+        boolean extractLibs = loadLibsSetup(apkName);
+        loadGeckoLibsNative(apkName);
     }
 
     private static void putLocaleEnv() {
         GeckoAppShell.putenv("LANG=" + Locale.getDefault().toString());
         NumberFormat nf = NumberFormat.getInstance();
         if (nf instanceof DecimalFormat) {
             DecimalFormat df = (DecimalFormat)nf;
             DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
--- a/mobile/android/base/GeckoThread.java
+++ b/mobile/android/base/GeckoThread.java
@@ -81,18 +81,19 @@ public class GeckoThread extends Thread 
                     libs[i].delete();
                 }
             }
         }
 
         // At some point while loading the gecko libs our default locale gets set
         // so just save it to locale here and reset it as default after the join
         Locale locale = Locale.getDefault();
-        GeckoAppShell.loadGeckoLibs(
-            app.getApplication().getPackageResourcePath());
+        String resourcePath = app.getApplication().getPackageResourcePath();
+        GeckoAppShell.ensureSQLiteLibsLoaded(resourcePath);
+        GeckoAppShell.loadGeckoLibs(resourcePath);
         Locale.setDefault(locale);
         Resources res = app.getBaseContext().getResources();
         Configuration config = res.getConfiguration();
         config.locale = locale;
         res.updateConfiguration(config, res.getDisplayMetrics());
 
         Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko");
 
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -84,16 +84,19 @@ FENNEC_JAVA_FILES = \
   GeckoInputConnection.java \
   GeckoPreferences.java \
   GeckoStateListDrawable.java \
   GeckoThread.java \
   GlobalHistory.java \
   LinkPreference.java \
   ProfileMigrator.java \
   PromptService.java \
+  sqlite/ByteBufferInputStream.java \
+  sqlite/SQLiteBridge.java \
+  sqlite/SQLiteBridgeException.java \
   SurfaceLockInfo.java \
   Tab.java \
   Tabs.java \
   TabsTray.java \
   gfx/BitmapUtils.java \
   gfx/BufferedCairoImage.java \
   gfx/CairoGLInfo.java \
   gfx/CairoImage.java \
--- a/mobile/android/base/ProfileMigrator.java
+++ b/mobile/android/base/ProfileMigrator.java
@@ -10,17 +10,17 @@
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Mozilla Android code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009-2010
+ * Portions created by the Initial Developer are Copyright (C) 2011-2012
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -33,100 +33,93 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.sqlite.ByteBufferInputStream;
+import org.mozilla.gecko.sqlite.SQLiteBridge;
+import org.mozilla.gecko.sqlite.SQLiteBridgeException;
 
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteStatement;
 import android.content.ContentResolver;
 import android.database.Cursor;
+import android.database.SQLException;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.provider.Browser;
 import android.util.Log;
-import android.webkit.WebIconDatabase;
 
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.File;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Date;
 import java.util.List;
 import java.util.Iterator;
 
 
 public class ProfileMigrator {
     private static final String LOGTAG = "ProfMigr";
     private File mProfileDir;
     private ContentResolver mCr;
-    private SQLiteDatabase mDb;
 
     /*
       Amount of Android history entries we will remember
       to prevent moving their last access date backwards.
     */
     private static final int MAX_HISTORY_TO_CHECK = 1000;
 
     /*
        These queries are derived from the low-level Places schema
        https://developer.mozilla.org/en/The_Places_database
     */
-    final String bookmarkQuery = "SELECT places.url AS a_url, "
+    private final String bookmarkQuery = "SELECT places.url AS a_url, "
         + "places.title AS a_title FROM "
         + "(moz_places as places JOIN moz_bookmarks as bookmarks ON "
         + "places.id = bookmarks.fk) WHERE places.hidden <> 1 "
         + "ORDER BY bookmarks.dateAdded";
-    // Don't ask why. Just curse along at the Android devs.
-    final String bookmarkUrl = "a_url";
-    final String bookmarkTitle = "a_title";
+    // Result column of relevant data
+    private final String bookmarkUrl   = "a_url";
+    private final String bookmarkTitle = "a_title";
 
-    final String historyQuery =
+    private final String historyQuery =
         "SELECT places.url AS a_url, places.title AS a_title, "
         + "history.visit_date AS a_date FROM "
         + "(moz_historyvisits AS history JOIN moz_places AS places ON "
         + "places.id = history.place_id) WHERE places.hidden <> 1 "
         + "ORDER BY history.visit_date DESC";
-    final String historyUrl = "a_url";
-    final String historyTitle = "a_title";
-    final String historyDate = "a_date";
+    private final String historyUrl   = "a_url";
+    private final String historyTitle = "a_title";
+    private final String historyDate  = "a_date";
 
-    final String faviconQuery =
+    private final String faviconQuery =
         "SELECT places.url AS a_url, favicon.data AS a_data, "
         + "favicon.mime_type AS a_mime FROM (moz_places AS places JOIN "
         + "moz_favicons AS favicon ON places.favicon_id = favicon.id)";
-    final String faviconUrl = "a_url";
-    final String faviconData = "a_data";
-    final String faviconMime = "a_mime";
+    private final String faviconUrl  = "a_url";
+    private final String faviconData = "a_data";
+    private final String faviconMime = "a_mime";
 
     public ProfileMigrator(ContentResolver cr, File profileDir) {
         mProfileDir = profileDir;
         mCr = cr;
     }
 
     public void launchBackground() {
         // Work around http://code.google.com/p/android/issues/detail?id=11291
-        // The WebIconDatabase needs to be initialized within the UI thread so
-        // just request the instance here.
-        WebIconDatabase.getInstance();
-
-        PlacesTask placesTask = new PlacesTask();
-        new Thread(placesTask).start();
+        // WebIconDatabase needs to be initialized within a looper thread.
+        GeckoAppShell.getHandler().post(new PlacesTask());
     }
 
     private class PlacesTask implements Runnable {
         // Get a list of the last times an URL was accessed
         protected Map<String, Long> gatherAndroidHistory() {
             Map<String, Long> history = new HashMap<String, Long>();
 
             Cursor cursor = BrowserDB.getRecentHistory(mCr, MAX_HISTORY_TO_CHECK);
@@ -172,47 +165,34 @@ public class ProfileMigrator {
                 BrowserDB.updateVisitedHistory(mCr, url);
                 BrowserDB.updateHistoryDate(mCr, url, date);
                 if (title != null) {
                     BrowserDB.updateHistoryTitle(mCr, url, title);
                 }
             }
         }
 
-        protected void migrateHistory(SQLiteDatabase db) {
+        protected void migrateHistory(SQLiteBridge db) {
             Map<String, Long> androidHistory = gatherAndroidHistory();
             final ArrayList<String> placesHistory = new ArrayList<String>();
 
-            Cursor cursor = null;
             try {
-                cursor =
-                    db.rawQuery(historyQuery, new String[] { });
-                final int urlCol =
-                    cursor.getColumnIndexOrThrow(historyUrl);
-                final int titleCol =
-                    cursor.getColumnIndexOrThrow(historyTitle);
-                final int dateCol =
-                    cursor.getColumnIndexOrThrow(historyDate);
+                ArrayList<Object[]> queryResult = db.query(historyQuery);
+                final int urlCol = db.getColumnIndex(historyUrl);
+                final int titleCol = db.getColumnIndex(historyTitle);
+                final int dateCol = db.getColumnIndex(historyDate);
 
-                cursor.moveToFirst();
-                while (!cursor.isAfterLast()) {
-                    String url = cursor.getString(urlCol);
-                    String title = cursor.getString(titleCol);
-                    // Convert from us (Places) to ms (Java, Android)
-                    long date = cursor.getLong(dateCol) / (long)1000;
+                for (Object[] resultRow: queryResult) {
+                    String url = (String)resultRow[urlCol];
+                    String title = (String)resultRow[titleCol];
+                    long date = Long.parseLong((String)(resultRow[dateCol])) / (long)1000;
                     addHistory(androidHistory, url, title, date);
                     placesHistory.add(url);
-                    cursor.moveToNext();
                 }
-
-                cursor.close();
-            } catch (SQLiteException e) {
-                if (cursor != null) {
-                    cursor.close();
-                }
+            } catch (SQLiteBridgeException e) {
                 Log.i(LOGTAG, "Failed to get bookmarks: " + e.getMessage());
                 return;
             }
             // GlobalHistory access communicates with Gecko
             // and must run on its thread
             GeckoAppShell.getHandler().post(new Runnable() {
                     public void run() {
                         for (String url : placesHistory) {
@@ -226,129 +206,94 @@ public class ProfileMigrator {
             if (!BrowserDB.isBookmark(mCr, url)) {
                 if (title == null) {
                     title = url;
                 }
                 BrowserDB.addBookmark(mCr, title, url);
             }
         }
 
-        protected void migrateBookmarks(SQLiteDatabase db) {
-            Cursor cursor = null;
+        protected void migrateBookmarks(SQLiteBridge db) {
             try {
-                cursor = db.rawQuery(bookmarkQuery,
-                                     new String[] {});
-                if (cursor.getCount() > 0) {
-                    final int urlCol =
-                        cursor.getColumnIndexOrThrow(bookmarkUrl);
-                    final int titleCol =
-                        cursor.getColumnIndexOrThrow(bookmarkTitle);
+                ArrayList<Object[]> queryResult = db.query(bookmarkQuery);
+                final int urlCol = db.getColumnIndex(bookmarkUrl);
+                final int titleCol = db.getColumnIndex(bookmarkTitle);
 
-                    cursor.moveToFirst();
-                    while (!cursor.isAfterLast()) {
-                        String url = cursor.getString(urlCol);
-                        String title = cursor.getString(titleCol);
-                        addBookmark(url, title);
-                        cursor.moveToNext();
-                    }
+                for (Object[] resultRow: queryResult) {
+                    String url = (String)resultRow[urlCol];
+                    String title = (String)resultRow[titleCol];
+                    addBookmark(url, title);
                 }
-                cursor.close();
-            } catch (SQLiteException e) {
-                if (cursor != null) {
-                    cursor.close();
-                }
+            } catch (SQLiteBridgeException e) {
                 Log.i(LOGTAG, "Failed to get bookmarks: " + e.getMessage());
                 return;
             }
         }
 
-        protected void addFavicon(String url, String mime, byte[] data) {
-            ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
+        protected void addFavicon(String url, String mime, ByteBuffer data) {
+            ByteBufferInputStream byteStream = new ByteBufferInputStream(data);
             BitmapDrawable image = (BitmapDrawable) Drawable.createFromStream(byteStream, "src");
             if (image != null) {
                 try {
                     BrowserDB.updateFaviconForUrl(mCr, url, image);
-                } catch (SQLiteException e) {
+                } catch (SQLException e) {
                     Log.i(LOGTAG, "Migrating favicon failed: " + mime + " URL: " + url
                           + " error:" + e.getMessage());
                 }
             }
         }
 
-        protected void migrateFavicons(SQLiteDatabase db) {
-            Cursor cursor = null;
+        protected void migrateFavicons(SQLiteBridge db) {
             try {
-                cursor = db.rawQuery(faviconQuery,
-                                     new String[] {});
-                if (cursor.getCount() > 0) {
-                    final int urlCol =
-                        cursor.getColumnIndexOrThrow(faviconUrl);
-                    final int dataCol =
-                        cursor.getColumnIndexOrThrow(faviconData);
-                    final int mimeCol =
-                        cursor.getColumnIndexOrThrow(faviconMime);
+                ArrayList<Object[]> queryResult = db.query(faviconQuery);
+                final int urlCol = db.getColumnIndex(faviconUrl);
+                final int mimeCol = db.getColumnIndex(faviconMime);
+                final int dataCol = db.getColumnIndex(faviconData);
 
-                    cursor.moveToFirst();
-                    while (!cursor.isAfterLast()) {
-                        String url = cursor.getString(urlCol);
-                        String mime = cursor.getString(mimeCol);
-                        byte[] data = cursor.getBlob(dataCol);
-                        addFavicon(url, mime, data);
-                        cursor.moveToNext();
-                    }
+                for (Object[] resultRow: queryResult) {
+                    String url = (String)resultRow[urlCol];
+                    String mime = (String)resultRow[mimeCol];
+                    ByteBuffer dataBuff = (ByteBuffer)resultRow[dataCol];
+                    addFavicon(url, mime, dataBuff);
                 }
-                cursor.close();
-            } catch (SQLiteException e) {
-                if (cursor != null) {
-                    cursor.close();
-                }
+            } catch (SQLiteBridgeException e) {
                 Log.i(LOGTAG, "Failed to get favicons: " + e.getMessage());
                 return;
             }
         }
 
-        SQLiteDatabase openPlaces(String dbPath) throws SQLiteException {
-            /* http://stackoverflow.com/questions/2528489/no-such-table-android-metadata-whats-the-problem */
-            SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath,
-                                                            null,
-                                                            SQLiteDatabase.OPEN_READONLY |
-                                                            SQLiteDatabase.NO_LOCALIZED_COLLATORS);
-
-            return db;
-        }
-
         protected void migratePlaces(File aFile) {
             String dbPath = aFile.getPath() + "/places.sqlite";
             String dbPathWal = aFile.getPath() + "/places.sqlite-wal";
             String dbPathShm = aFile.getPath() + "/places.sqlite-shm";
             Log.i(LOGTAG, "Opening path: " + dbPath);
 
             File dbFile = new File(dbPath);
             if (!dbFile.exists()) {
                 Log.i(LOGTAG, "No database");
                 return;
             }
             File dbFileWal = new File(dbPathWal);
             File dbFileShm = new File(dbPathShm);
 
-            SQLiteDatabase db = null;
+            SQLiteBridge db = null;
             try {
-                db = openPlaces(dbPath);
+                db = new SQLiteBridge(dbPath);
                 migrateBookmarks(db);
                 migrateHistory(db);
                 migrateFavicons(db);
                 db.close();
 
                 // Clean up
                 dbFile.delete();
                 dbFileWal.delete();
                 dbFileShm.delete();
 
                 Log.i(LOGTAG, "Profile migration finished");
-            } catch (SQLiteException e) {
+            } catch (SQLiteBridgeException e) {
                 if (db != null) {
                     db.close();
                 }
                 Log.i(LOGTAG, "Error on places database:" + e.getMessage());
                 return;
             }
         }
 
--- a/mobile/android/base/db/AndroidBrowserDB.java
+++ b/mobile/android/base/db/AndroidBrowserDB.java
@@ -58,39 +58,57 @@ public class AndroidBrowserDB implements
     private static final String URL_COLUMN_ID = "_id";
     private static final String URL_COLUMN_THUMBNAIL = "thumbnail";
 
     // Only available on Android >= 11
     private static final String URL_COLUMN_DELETED = "deleted";
 
     private static final Uri BOOKMARKS_CONTENT_URI_POST_11 = Uri.parse("content://com.android.browser/bookmarks");
 
-    public Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter) {
+    private Cursor filterAllSites(ContentResolver cr, String[] projection, CharSequence constraint, int limit, CharSequence urlFilter) {
         Cursor c = cr.query(Browser.BOOKMARKS_URI,
-                            new String[] { URL_COLUMN_ID,
-                                           BookmarkColumns.URL,
-                                           BookmarkColumns.TITLE,
-                                           BookmarkColumns.FAVICON,
-                                           URL_COLUMN_THUMBNAIL },
+                            projection,
                             // The length restriction on URL is for the same reason as in the general bookmark query
                             // (see comment earlier in this file).
                             (urlFilter != null ? "(" + Browser.BookmarkColumns.URL + " NOT LIKE ? ) AND " : "" ) + 
                             "(" + Browser.BookmarkColumns.URL + " LIKE ? OR " + Browser.BookmarkColumns.TITLE + " LIKE ?)"
                             + " AND LENGTH(" + Browser.BookmarkColumns.URL + ") > 0",
                             urlFilter == null ? new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%"} :
                             new String[] {urlFilter.toString(), "%" + constraint.toString() + "%", "%" + constraint.toString() + "%"},
                             // ORDER BY is number of visits times a multiplier from 1 - 120 of how recently the site
                             // was accessed with a site accessed today getting 120 and a site accessed 119 or more
                             // days ago getting 1
                             Browser.BookmarkColumns.VISITS + " * MAX(1, (" +
                             Browser.BookmarkColumns.DATE + " - " + System.currentTimeMillis() + ") / 86400000 + 120) DESC LIMIT " + limit);
 
         return new AndroidDBCursor(c);
     }
 
+    public Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
+        return filterAllSites(cr,
+                              new String[] { URL_COLUMN_ID,
+                                             BookmarkColumns.URL,
+                                             BookmarkColumns.TITLE,
+                                             BookmarkColumns.FAVICON },
+                              constraint,
+                              limit,
+                              null);
+    }
+
+    public Cursor getTopSites(ContentResolver cr, int limit) {
+        return filterAllSites(cr,
+                              new String[] { URL_COLUMN_ID,
+                                             BookmarkColumns.URL,
+                                             BookmarkColumns.TITLE,
+                                             URL_COLUMN_THUMBNAIL },
+                              "",
+                              limit,
+                              BrowserDB.ABOUT_PAGES_URL_FILTER);
+    }
+
     public void updateVisitedHistory(ContentResolver cr, String uri) {
         Browser.updateVisitedHistory(cr, uri, true);
     }
 
     public void updateHistoryTitle(ContentResolver cr, String uri, String title) {
         ContentValues values = new ContentValues();
         values.put(Browser.BookmarkColumns.TITLE, title);
 
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -37,28 +37,32 @@
 
 package org.mozilla.gecko.db;
 
 import android.content.ContentResolver;
 import android.database.Cursor;
 import android.graphics.drawable.BitmapDrawable;
 
 public class BrowserDB {
+    public static String ABOUT_PAGES_URL_FILTER = "about:%";
+
     public static interface URLColumns {
         public static String URL = "url";
         public static String TITLE = "title";
         public static String FAVICON = "favicon";
         public static String THUMBNAIL = "thumbnail";
         public static String DATE_LAST_VISITED = "date-last-visited";
     }
 
     private static BrowserDBIface sDb;
 
     public interface BrowserDBIface {
-        public Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter);
+        public Cursor filter(ContentResolver cr, CharSequence constraint, int limit);
+
+        public Cursor getTopSites(ContentResolver cr, int limit);
 
         public void updateVisitedHistory(ContentResolver cr, String uri);
 
         public void updateHistoryTitle(ContentResolver cr, String uri, String title);
 
         public void updateHistoryDate(ContentResolver cr, String uri, long date);
 
         public Cursor getAllVisitedHistory(ContentResolver cr);
@@ -82,22 +86,22 @@ public class BrowserDB {
         public void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
     }
 
     static {
         // Forcing local DB no option to switch to Android DB for now
         sDb = new LocalBrowserDB(BrowserContract.DEFAULT_PROFILE);
     }
 
-    public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter) {
-        return sDb.filter(cr, constraint, limit, urlFilter);
+    public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
+        return sDb.filter(cr, constraint, limit);
     }
 
-    public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
-        return sDb.filter(cr, constraint, limit, null);
+    public static Cursor getTopSites(ContentResolver cr, int limit) {
+        return sDb.getTopSites(cr, limit);
     }
 
     public static void updateVisitedHistory(ContentResolver cr, String uri) {
         sDb.updateVisitedHistory(cr, uri);
     }
 
     public static void updateHistoryTitle(ContentResolver cr, String uri, String title) {
         sDb.updateHistoryTitle(cr, uri, title);
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -75,36 +75,54 @@ public class LocalBrowserDB implements B
         return uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile).
                 appendQueryParameter(BrowserContract.PARAM_LIMIT, String.valueOf(limit)).build();
     }
 
     private Uri appendProfile(Uri uri) {
         return uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile).build();
     }
 
-    public Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter) {
+    private Cursor filterAllSites(ContentResolver cr, String[] projection, CharSequence constraint, int limit, CharSequence urlFilter) {
         Cursor c = cr.query(appendProfileAndLimit(History.CONTENT_URI, limit),
-                            new String[] { History._ID,
-                                           History.URL,
-                                           History.TITLE,
-                                           History.FAVICON,
-                                           History.THUMBNAIL },
+                            projection,
                             (urlFilter != null ? "(" + History.URL + " NOT LIKE ? ) AND " : "" ) + 
                             "(" + History.URL + " LIKE ? OR " + History.TITLE + " LIKE ?)",
                             urlFilter == null ? new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%"} :
                             new String[] {urlFilter.toString(), "%" + constraint.toString() + "%", "%" + constraint.toString() + "%"},
                             // ORDER BY is number of visits times a multiplier from 1 - 120 of how recently the site
                             // was accessed with a site accessed today getting 120 and a site accessed 119 or more
                             // days ago getting 1
                             History.VISITS + " * MAX(1, (" +
                             History.DATE_LAST_VISITED + " - " + System.currentTimeMillis() + ") / 86400000 + 120) DESC");
 
         return new LocalDBCursor(c);
     }
 
+    public Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
+        return filterAllSites(cr,
+                              new String[] { History._ID,
+                                             History.URL,
+                                             History.TITLE,
+                                             History.FAVICON },
+                              constraint,
+                              limit,
+                              null);
+    }
+
+    public Cursor getTopSites(ContentResolver cr, int limit) {
+        return filterAllSites(cr,
+                              new String[] { History._ID,
+                                             History.URL,
+                                             History.TITLE,
+                                             History.THUMBNAIL },
+                              "",
+                              limit,
+                              BrowserDB.ABOUT_PAGES_URL_FILTER);
+    }
+
     private void truncateHistory(ContentResolver cr) {
         Cursor cursor = null;
 
         try {
             cursor = cr.query(appendProfile(History.CONTENT_URI),
                               new String[] { History._ID },
                               null,
                               null,
--- a/mobile/android/base/resources/layout/awesomebar_search.xml
+++ b/mobile/android/base/resources/layout/awesomebar_search.xml
@@ -7,17 +7,17 @@
           android:id="@+id/awesomebar_text"
           style="@style/AddressBar.Button"
           android:layout_width="fill_parent"
           android:layout_alignParentBottom="true"
           android:layout_centerVertical="true"
           android:paddingLeft="15dip"
           android:paddingRight="40dip"
           android:hint="@string/awesomebar_default_text"
-          android:inputType="textUri"
+          android:inputType="textUri|textNoSuggestions"
           android:imeOptions="actionSearch"
           android:singleLine="true"
           android:gravity="center_vertical|left">
          <requestFocus/>
     </view>
 
     <ImageButton android:id="@+id/awesomebar_button"
                  style="@style/AddressBar.ImageButton"
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sqlite/ByteBufferInputStream.java
@@ -0,0 +1,71 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.sqlite;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/*
+ * Helper class to make the ByteBuffers returned by SQLite BLOB
+ * easier to use.
+ */
+public class ByteBufferInputStream extends InputStream {
+    private ByteBuffer mByteBuffer;
+
+    public ByteBufferInputStream(ByteBuffer aByteBuffer) {
+        mByteBuffer = aByteBuffer;
+    }
+
+    @Override
+    public synchronized int read() throws IOException {
+        if (!mByteBuffer.hasRemaining()) {
+            return -1;
+        }
+        return mByteBuffer.get();
+    }
+
+    @Override
+    public synchronized int read(byte[] aBytes, int aOffset, int aLen)
+        throws IOException {
+        int toRead = Math.min(aLen, mByteBuffer.remaining());
+        mByteBuffer.get(aBytes, aOffset, toRead);
+        return toRead;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sqlite/SQLiteBridge.java
@@ -0,0 +1,101 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.sqlite;
+
+import org.mozilla.gecko.sqlite.SQLiteBridgeException;
+import android.util.Log;
+
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/*
+ * This class allows using the mozsqlite3 library included with Firefox
+ * to read SQLite databases, instead of the Android SQLiteDataBase API,
+ * which might use whatever outdated DB is present on the Android system.
+ */
+public class SQLiteBridge {
+    private static final String LOGTAG = "SQLiteBridge";
+    // Path to the database. We reopen it every query.
+    private String mDb;
+    // Remember column names from last query result.
+    private ArrayList<String> mColumns;
+
+    // JNI code in $(topdir)/mozglue/android/..
+    private static native void sqliteCall(String aDb, String aQuery,
+                                          String[] aParams,
+                                          ArrayList<String> aColumns,
+                                          ArrayList<Object[]> aRes)
+        throws SQLiteBridgeException;
+
+    // Takes the path to the database we want to access.
+    public SQLiteBridge(String aDb) throws SQLiteBridgeException {
+        mDb = aDb;
+    }
+
+    // Do an SQL query without parameters
+    public ArrayList<Object[]> query(String aQuery) throws SQLiteBridgeException {
+        String[] params = new String[0];
+        return query(aQuery, params);
+    }
+
+    // Do an SQL query, substituting the parameters in the query with the passed
+    // parameters. The parameters are subsituded in order, so named parameters
+    // are not supported.
+    // The result is returned as an ArrayList<Object[]>, with each
+    // row being an entry in the ArrayList, and each column being one Object
+    // in the Object[] array. The columns are of type null,
+    // direct ByteBuffer (BLOB), or String (everything else).
+    public ArrayList<Object[]> query(String aQuery, String[] aParams)
+        throws SQLiteBridgeException {
+        ArrayList<Object[]> result = new ArrayList<Object[]>();
+        mColumns = new ArrayList<String>();
+        sqliteCall(mDb, aQuery, aParams, mColumns, result);
+        return result;
+    }
+
+    // Gets the index in the row Object[] for the given column name.
+    // Returns -1 if not found.
+    public int getColumnIndex(String aColumnName) {
+        return mColumns.lastIndexOf(aColumnName);
+    }
+
+    public void close() {
+        // nop, provided for API compatibility with SQLiteDatabase.
+    }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sqlite/SQLiteBridgeException.java
@@ -0,0 +1,47 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.sqlite;
+
+public class SQLiteBridgeException extends Exception {
+    static final long serialVersionUID = 1L;
+
+    public SQLiteBridgeException() {}
+    public SQLiteBridgeException(String msg) {
+        super(msg);
+    }
+}
\ No newline at end of file
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -421,16 +421,22 @@ var BrowserApp = {
 
     aParams = aParams || {};
 
     let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
     let postData = ("postData" in aParams && aParams.postData) ? aParams.postData.value : null;
     let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null;
     let charset = "charset" in aParams ? aParams.charset : null;
 
+    if ("showProgress" in aParams) {
+      let tab = this.getTabForBrowser(aBrowser);
+      if (tab)
+        tab.showProgress = aParams.showProgress;
+    }
+
     try {
       aBrowser.loadURIWithFlags(aURI, flags, referrerURI, charset, postData);
     } catch(e) {
       let tab = this.getTabForBrowser(aBrowser);
       if (tab) {
         let message = {
           gecko: {
             type: "Content:LoadError",
@@ -820,16 +826,21 @@ var BrowserApp = {
       // inheriting the currently loaded document's principal.
       let params = {
         selected: true,
         parentId: ("parentId" in data) ? data.parentId : -1,
         flags: Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER
       };
 
       let url = this.getSearchOrFixupURI(data);
+
+      // Don't show progress throbber for about:home
+      if (url == "about:home")
+        params.showProgress = false;
+
       if (aTopic == "Tab:Add")
         this.addTab(url, params);
       else
         this.loadURI(url, browser, params);
     } else if (aTopic == "Tab:Select") {
       this.selectTab(this.getTabForId(parseInt(aData)));
     } else if (aTopic == "Tab:Close") {
       this.closeTab(this.getTabForId(parseInt(aData)));
@@ -1292,16 +1303,17 @@ let gTabIDFactory = 0;
 // get created with the right size rather than being 1x1
 let gScreenWidth = 1;
 let gScreenHeight = 1;
 
 function Tab(aURL, aParams) {
   this.browser = null;
   this.vbox = null;
   this.id = 0;
+  this.showProgress = true;
   this.create(aURL, aParams);
   this._viewport = { x: 0, y: 0, width: gScreenWidth, height: gScreenHeight, offsetX: 0, offsetY: 0,
                      pageWidth: gScreenWidth, pageHeight: gScreenHeight, zoom: 1.0 };
   this.viewportExcess = { x: 0, y: 0 };
   this.documentIdForCurrentViewport = null;
   this.userScrollPos = { x: 0, y: 0 };
   this._pluginsToPlay = [];
   this._pluginOverlayShowing = false;
@@ -1363,16 +1375,19 @@ Tab.prototype = {
     Services.obs.addObserver(this, "document-shown", false);
 
     if (!aParams.delayLoad) {
       let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
       let postData = ("postData" in aParams && aParams.postData) ? aParams.postData.value : null;
       let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null;
       let charset = "charset" in aParams ? aParams.charset : null;
 
+      // This determines whether or not we show the progress throbber in the urlbar
+      this.showProgress = "showProgress" in aParams ? aParams.showProgress : true;
+
       try {
         this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData);
       } catch(e) {
         let message = {
           gecko: {
             type: "Content:LoadError",
             tabID: this.id,
             uri: this.browser.currentURI.spec,
@@ -1744,21 +1759,24 @@ Tab.prototype = {
       if (browser)
         uri = browser.currentURI.spec;
 
       let message = {
         gecko: {
           type: "Content:StateChange",
           tabID: this.id,
           uri: uri,
-          state: aStateFlags
+          state: aStateFlags,
+          showProgress: this.showProgress
         }
       };
-
       sendMessageToJava(message);
+
+      // Reset showProgress after state change
+      this.showProgress = true;
     }
   },
 
   onLocationChange: function(aWebProgress, aRequest, aLocationURI, aFlags) {
     let contentWin = aWebProgress.DOMWindow;
     if (contentWin != contentWin.top)
         return;
 
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -57,16 +57,18 @@
 #include <unistd.h>
 #include <zlib.h>
 #include <linux/ashmem.h>
 #include "dlfcn.h"
 #include "APKOpen.h"
 #include <sys/time.h>
 #include <sys/resource.h>
 #include "Zip.h"
+#include "sqlite3.h"
+#include "SQLiteBridge.h"
 
 /* Android headers don't define RUSAGE_THREAD */
 #ifndef RUSAGE_THREAD
 #define RUSAGE_THREAD 1
 #endif
 
 enum StartupEvent {
 #define mozilla_StartupTimeline_Event(ev, z) ev,
@@ -279,33 +281,34 @@ SHELL_WRAPPER1(setSoftwareLayerClient, j
 SHELL_WRAPPER0(onResume)
 SHELL_WRAPPER0(onLowMemory)
 SHELL_WRAPPER3(callObserver, jstring, jstring, jstring)
 SHELL_WRAPPER1(removeObserver, jstring)
 SHELL_WRAPPER1(onChangeNetworkLinkStatus, jstring)
 SHELL_WRAPPER1(reportJavaCrash, jstring)
 SHELL_WRAPPER0(executeNextRunnable)
 SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray)
-SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble);
-SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong);
-SHELL_WRAPPER0(bindWidgetTexture);
-SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong);
-SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong);
-SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong);
-SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong);
-SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong);
-SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong);
-SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong);
-SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong);
-SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong);
-SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong);
-SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong);
-SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong);
+SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble)
+SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong)
+SHELL_WRAPPER0(bindWidgetTexture)
+SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong)
+SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong)
+SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong)
+SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong)
+SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong)
+SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong)
+SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong)
+SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong)
+SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong)
+SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong)
+SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong)
+SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong)
 
 static void * xul_handle = NULL;
+static void * sqlite_handle = NULL;
 static time_t apk_mtime = 0;
 #ifdef DEBUG
 extern "C" int extractLibs = 1;
 #else
 extern "C" int extractLibs = 0;
 #endif
 
 static void
@@ -613,44 +616,40 @@ report_mapping(char *name, void *base, u
   char * entry = strstr(file_ids, name);
   if (entry)
     info->file_id = strndup(entry + strlen(name) + 1, 32);
 }
 
 extern "C" void simple_linker_init(void);
 
 static void
-loadLibs(const char *apkName)
+loadGeckoLibs(const char *apkName)
 {
   chdir(getenv("GRE_HOME"));
 
-  simple_linker_init();
-
   struct stat status;
   if (!stat(apkName, &status))
     apk_mtime = status.st_mtime;
 
   struct timeval t0, t1;
   gettimeofday(&t0, 0);
   struct rusage usage1;
   getrusage(RUSAGE_THREAD, &usage1);
   
   Zip *zip = new Zip(apkName);
 
-  lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
 #ifdef MOZ_CRASHREPORTER
   file_ids = (char *)extractBuf("lib.id", zip);
 #endif
 
 #define MOZLOAD(name) mozload("lib" name ".so", zip)
   MOZLOAD("mozalloc");
   MOZLOAD("nspr4");
   MOZLOAD("plc4");
   MOZLOAD("plds4");
-  MOZLOAD("mozsqlite3");
   MOZLOAD("nssutil3");
   MOZLOAD("nss3");
   MOZLOAD("ssl3");
   MOZLOAD("smime3");
   xul_handle = MOZLOAD("xul");
   MOZLOAD("xpcom");
   MOZLOAD("nssckbi");
   MOZLOAD("freebl3");
@@ -707,30 +706,77 @@ loadLibs(const char *apkName)
                       (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000,
                       (usage2.ru_stime.tv_sec - usage1.ru_stime.tv_sec)*1000 + (usage2.ru_stime.tv_usec - usage1.ru_stime.tv_usec)/1000,
                       usage2.ru_majflt-usage1.ru_majflt);
 
   StartupTimeline_Record(LINKER_INITIALIZED, &t0);
   StartupTimeline_Record(LIBRARIES_LOADED, &t1);
 }
 
-extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_loadLibs(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract)
+static void loadSQLiteLibs(const char *apkName)
 {
-  if (jShouldExtract)
-    extractLibs = 1;
+  chdir(getenv("GRE_HOME"));
+
+  simple_linker_init();
+
+  struct stat status;
+  if (!stat(apkName, &status))
+    apk_mtime = status.st_mtime;
+
+  Zip *zip = new Zip(apkName);
+  lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
+
+#ifdef MOZ_CRASHREPORTER
+  file_ids = (char *)extractBuf("lib.id", zip);
+#endif
+
+#define MOZLOAD(name) mozload("lib" name ".so", zip)
+  sqlite_handle = MOZLOAD("mozsqlite3");
+#undef MOZLOAD
 
+  delete zip;
+
+#ifdef MOZ_CRASHREPORTER
+  free(file_ids);
+  file_ids = NULL;
+#endif
+
+  if (!sqlite_handle)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libmozsqlite3!");
+
+  setup_sqlite_functions(sqlite_handle);
+}
+
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
+{
   const char* str;
-  // XXX: java doesn't give us true UTF8, we should figure out something 
+  // XXX: java doesn't give us true UTF8, we should figure out something
   // better to do here
   str = jenv->GetStringUTFChars(jApkName, NULL);
   if (str == NULL)
     return;
 
-  loadLibs(str);
+  loadGeckoLibs(str);
+  jenv->ReleaseStringUTFChars(jApkName, str);
+}
+
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
+  if (jShouldExtract)
+    extractLibs = 1;
+
+  const char* str;
+  // XXX: java doesn't give us true UTF8, we should figure out something
+  // better to do here
+  str = jenv->GetStringUTFChars(jApkName, NULL);
+  if (str == NULL)
+    return;
+
+  loadSQLiteLibs(str);
   jenv->ReleaseStringUTFChars(jApkName, str);
 }
 
 typedef int GeckoProcessType;
 typedef int nsresult;
 
 extern "C" NS_EXPORT int
 ChildProcessInit(int argc, char* argv[])
@@ -740,17 +786,18 @@ ChildProcessInit(int argc, char* argv[])
     if (strcmp(argv[i], "-greomni"))
       continue;
 
     i = i + 1;
     break;
   }
 
   fillLibCache(argv[argc - 1]);
-  loadLibs(argv[i]);
+  loadSQLiteLibs(argv[i]);
+  loadGeckoLibs(argv[i]);
 
   // don't pass the last arg - it's only recognized by the lib cache
   argc--;
 
   typedef GeckoProcessType (*XRE_StringToChildProcessType_t)(char*);
   typedef nsresult (*XRE_InitChildProcess_t)(int, char**, GeckoProcessType);
   XRE_StringToChildProcessType_t fXRE_StringToChildProcessType =
     (XRE_StringToChildProcessType_t)__wrap_dlsym(xul_handle, "XRE_StringToChildProcessType");
--- a/mozglue/android/Makefile.in
+++ b/mozglue/android/Makefile.in
@@ -48,20 +48,22 @@ FORCE_STATIC_LIB = 1
 
 DEFINES += \
   -DANDROID_PACKAGE_NAME='"$(ANDROID_PACKAGE_NAME)"' \
   $(NULL)
 
 CPPSRCS = \
   nsGeckoUtils.cpp \
   APKOpen.cpp \
+  SQLiteBridge.cpp \
   $(NULL)
 
 LOCAL_INCLUDES += -I$(srcdir)/../linker
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/startup
+LOCAL_INCLUDES += -I$(topsrcdir)/db/sqlite3/src
 ifdef MOZ_OLD_LINKER
 LOCAL_INCLUDES += -I$(topsrcdir)/other-licenses/android
 ifeq ($(CPU_ARCH),arm)
 DEFINES += -DANDROID_ARM_LINKER
 endif
 endif
 
 EXPORTS = APKOpen.h
new file mode 100644
--- /dev/null
+++ b/mozglue/android/SQLiteBridge.cpp
@@ -0,0 +1,312 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include <jni.h>
+#include <android/log.h>
+#include "dlfcn.h"
+#include "APKOpen.h"
+#include "SQLiteBridge.h"
+
+#ifdef DEBUG
+#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
+#else
+#define LOG(x...)
+#endif
+
+#define SQLITE_WRAPPER_INT(name) name ## _t f_ ## name;
+
+SQLITE_WRAPPER_INT(sqlite3_open)
+SQLITE_WRAPPER_INT(sqlite3_errmsg)
+SQLITE_WRAPPER_INT(sqlite3_prepare_v2)
+SQLITE_WRAPPER_INT(sqlite3_bind_parameter_count)
+SQLITE_WRAPPER_INT(sqlite3_bind_text)
+SQLITE_WRAPPER_INT(sqlite3_step)
+SQLITE_WRAPPER_INT(sqlite3_column_count)
+SQLITE_WRAPPER_INT(sqlite3_finalize)
+SQLITE_WRAPPER_INT(sqlite3_close)
+SQLITE_WRAPPER_INT(sqlite3_column_name)
+SQLITE_WRAPPER_INT(sqlite3_column_type)
+SQLITE_WRAPPER_INT(sqlite3_column_blob)
+SQLITE_WRAPPER_INT(sqlite3_column_bytes)
+SQLITE_WRAPPER_INT(sqlite3_column_text)
+
+void setup_sqlite_functions(void *sqlite_handle)
+{
+#define GETFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(sqlite_handle, #name)
+  GETFUNC(sqlite3_open);
+  GETFUNC(sqlite3_errmsg);
+  GETFUNC(sqlite3_prepare_v2);
+  GETFUNC(sqlite3_bind_parameter_count);
+  GETFUNC(sqlite3_bind_text);
+  GETFUNC(sqlite3_step);
+  GETFUNC(sqlite3_column_count);
+  GETFUNC(sqlite3_finalize);
+  GETFUNC(sqlite3_close);
+  GETFUNC(sqlite3_column_name);
+  GETFUNC(sqlite3_column_type);
+  GETFUNC(sqlite3_column_blob);
+  GETFUNC(sqlite3_column_bytes);
+  GETFUNC(sqlite3_column_text);
+#undef GETFUNC
+}
+
+static bool initialized = false;
+static jclass stringClass;
+static jclass objectClass;
+static jclass byteBufferClass;
+static jclass arrayListClass;
+static jmethodID jByteBufferAllocateDirect;
+static jmethodID jArrayListAdd;
+static jobject jNull;
+
+static void
+JNI_Throw(JNIEnv* jenv, const char* name, const char* msg)
+{
+    jclass cls = jenv->FindClass(name);
+    if (cls == NULL) {
+        LOG("Couldn't find exception class (or exception pending)\n");
+        return;
+    }
+    int rc = jenv->ThrowNew(cls, msg);
+    if (rc < 0) {
+        LOG("Error throwing exception\n");
+    }
+    jenv->DeleteLocalRef(cls);
+}
+
+static void
+JNI_Setup(JNIEnv* jenv)
+{
+    if (initialized) return;
+
+    objectClass     = jenv->FindClass("java/lang/Object");
+    stringClass     = jenv->FindClass("java/lang/String");
+    byteBufferClass = jenv->FindClass("java/nio/ByteBuffer");
+    arrayListClass  = jenv->FindClass("java/util/ArrayList");
+    jNull           = jenv->NewGlobalRef(NULL);
+
+    if (stringClass == NULL || objectClass == NULL
+        || byteBufferClass == NULL || arrayListClass == NULL) {
+        LOG("Error finding classes");
+        JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException",
+                  "FindClass error");
+        return;
+    }
+
+    // public static ByteBuffer allocateDirect(int capacity)
+    jByteBufferAllocateDirect =
+        jenv->GetStaticMethodID(byteBufferClass, "allocateDirect", "(I)Ljava/nio/ByteBuffer;");
+    // boolean add(Object o)
+    jArrayListAdd =
+        jenv->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
+
+    if (jByteBufferAllocateDirect == NULL || jArrayListAdd == NULL) {
+        LOG("Error finding methods");
+        JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException",
+                  "GetMethodId error");
+        return;
+    }
+
+    initialized = true;
+}
+
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
+                                                      jstring jDb,
+                                                      jstring jQuery,
+                                                      jobjectArray jParams,
+                                                      jobject jColumns,
+                                                      jobject jArrayList)
+{
+    JNI_Setup(jenv);
+
+    const char* queryStr;
+    queryStr = jenv->GetStringUTFChars(jQuery, NULL);
+
+    const char* dbPath;
+    dbPath = jenv->GetStringUTFChars(jDb, NULL);
+
+    const char *pzTail;
+    sqlite3_stmt *ppStmt;
+    sqlite3 *db;
+    int rc;
+    rc = f_sqlite3_open(dbPath, &db);
+    jenv->ReleaseStringUTFChars(jDb, dbPath);
+
+    if (rc != SQLITE_OK) {
+        LOG("Can't open database: %s\n", f_sqlite3_errmsg(db));
+        goto error_close;
+    }
+
+    rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail);
+    if (rc != SQLITE_OK || ppStmt == NULL) {
+        LOG("Can't prepare statement: %s\n", f_sqlite3_errmsg(db));
+        goto error_close;
+    }
+    jenv->ReleaseStringUTFChars(jQuery, queryStr);
+
+    // Check if number of parameters matches
+    jsize numPars;
+    numPars = jenv->GetArrayLength(jParams);
+    int sqlNumPars;
+    sqlNumPars = f_sqlite3_bind_parameter_count(ppStmt);
+    if (numPars != sqlNumPars) {
+        LOG("Passed parameter count (%d) doesn't match SQL parameter count (%d)\n",
+            numPars, sqlNumPars);
+        goto error_close;
+    }
+    // Bind parameters, if any
+    if (numPars > 0) {
+        for (int i = 0; i < numPars; i++) {
+            jobject jObjectParam = jenv->GetObjectArrayElement(jParams, i);
+            // IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf
+            // should be OK.
+            jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass);
+            if (isString != JNI_TRUE) {
+                LOG("Parameter is not of String type");
+                goto error_close;
+            }
+            jstring jStringParam = (jstring)jObjectParam;
+            const char* paramStr = jenv->GetStringUTFChars(jStringParam, NULL);
+            // SQLite parameters index from 1.
+            rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
+            jenv->ReleaseStringUTFChars(jStringParam, paramStr);
+            if (rc != SQLITE_OK) {
+                LOG("Error binding query parameter");
+                goto error_close;
+            }
+        }
+    }
+
+    // Execute the query and step through the results
+    rc = f_sqlite3_step(ppStmt);
+    if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
+        LOG("Can't step statement: (%d) %s\n", rc, f_sqlite3_errmsg(db));
+        goto error_close;
+    }
+
+    // Get the column names
+    int cols;
+    cols = f_sqlite3_column_count(ppStmt);
+    for (int i = 0; i < cols; i++) {
+        const char* colName = f_sqlite3_column_name(ppStmt, i);
+        jstring jStr = jenv->NewStringUTF(colName);
+        jenv->CallBooleanMethod(jColumns, jArrayListAdd, jStr);
+        jenv->DeleteLocalRef(jStr);
+    }
+
+    // For each row, add an Object[] to the passed ArrayList,
+    // with that containing either String or ByteArray objects
+    // containing the columns
+    do {
+        // Process row
+        // Construct Object[]
+        jobjectArray jRow = jenv->NewObjectArray(cols,
+                                                 objectClass,
+                                                 NULL);
+        if (jRow == NULL) {
+            LOG("Can't allocate jRow Object[]\n");
+            goto error_close;
+        }
+
+        for (int i = 0; i < cols; i++) {
+            int colType = f_sqlite3_column_type(ppStmt, i);
+            if (colType == SQLITE_BLOB) {
+                // Treat as blob
+                const void* blob = f_sqlite3_column_blob(ppStmt, i);
+                int colLen = f_sqlite3_column_bytes(ppStmt, i);
+
+                // Construct ByteBuffer of correct size
+                jobject jByteBuffer =
+                    jenv->CallStaticObjectMethod(byteBufferClass,
+                                                 jByteBufferAllocateDirect,
+                                                 colLen);
+                if (jByteBuffer == NULL) {
+                    goto error_close;
+                }
+
+                // Get its backing array
+                void* bufferArray = jenv->GetDirectBufferAddress(jByteBuffer);
+                if (bufferArray == NULL) {
+                    LOG("Failure calling GetDirectBufferAddress\n");
+                    goto error_close;
+                }
+                memcpy(bufferArray, blob, colLen);
+
+                jenv->SetObjectArrayElement(jRow, i, jByteBuffer);
+                jenv->DeleteLocalRef(jByteBuffer);
+            } else if (colType == SQLITE_NULL) {
+                jenv->SetObjectArrayElement(jRow, i, jNull);
+            } else {
+                // Treat everything else as text
+                const char* txt = (const char*)f_sqlite3_column_text(ppStmt, i);
+                jstring jStr = jenv->NewStringUTF(txt);
+                jenv->SetObjectArrayElement(jRow, i, jStr);
+                jenv->DeleteLocalRef(jStr);
+            }
+        }
+
+        // Append Object[] to ArrayList<Object[]>
+        // JNI doesn't know about the generic, so use Object[] as Object
+        jenv->CallBooleanMethod(jArrayList, jArrayListAdd, jRow);
+
+        // Clean up
+        jenv->DeleteLocalRef(jRow);
+
+        // Get next row
+        rc = f_sqlite3_step(ppStmt);
+        // Real error?
+        if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
+            LOG("Can't re-step statement:(%d) %s\n", rc, f_sqlite3_errmsg(db));
+            goto error_close;
+        }
+    } while (rc != SQLITE_DONE);
+
+    rc = f_sqlite3_finalize(ppStmt);
+    if (rc != SQLITE_OK) {
+        LOG("Can't finalize statement: %s\n", f_sqlite3_errmsg(db));
+        goto error_close;
+    }
+
+    f_sqlite3_close(db);
+    return;
+
+error_close:
+    f_sqlite3_close(db);
+    JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", "SQLite error");
+    return;
+}
new file mode 100644
--- /dev/null
+++ b/mozglue/android/SQLiteBridge.h
@@ -0,0 +1,63 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef SQLiteBridge_h
+#define SQLiteBridge_h
+
+#include "sqlite3.h"
+
+void setup_sqlite_functions(void *sqlite_handle);
+
+#define SQLITE_WRAPPER(name, return_type, args...) \
+typedef return_type (*name ## _t)(args);  \
+extern name ## _t f_ ## name;
+
+SQLITE_WRAPPER(sqlite3_open, int, const char*, sqlite3**)
+SQLITE_WRAPPER(sqlite3_errmsg, const char*, sqlite3*)
+SQLITE_WRAPPER(sqlite3_prepare_v2, int, sqlite3*, const char*, int, sqlite3_stmt**, const char**)
+SQLITE_WRAPPER(sqlite3_bind_parameter_count, int, sqlite3_stmt*)
+SQLITE_WRAPPER(sqlite3_bind_text, int, sqlite3_stmt*, int, const char*, int, void(*)(void*))
+SQLITE_WRAPPER(sqlite3_step, int, sqlite3_stmt*)
+SQLITE_WRAPPER(sqlite3_column_count, int, sqlite3_stmt*)
+SQLITE_WRAPPER(sqlite3_finalize, int, sqlite3_stmt*)
+SQLITE_WRAPPER(sqlite3_close, int, sqlite3*)
+SQLITE_WRAPPER(sqlite3_column_name, const char*, sqlite3_stmt*, int)
+SQLITE_WRAPPER(sqlite3_column_type, int, sqlite3_stmt*, int)
+SQLITE_WRAPPER(sqlite3_column_blob, const void*, sqlite3_stmt*, int)
+SQLITE_WRAPPER(sqlite3_column_bytes, int, sqlite3_stmt*, int)
+SQLITE_WRAPPER(sqlite3_column_text, const unsigned char*, sqlite3_stmt*, int)
+
+#endif /* SQLiteBridge_h */
--- a/mozglue/build/Makefile.in
+++ b/mozglue/build/Makefile.in
@@ -51,16 +51,17 @@ ifdef MOZ_MEMORY
 SHARED_LIBRARY_LIBS = $(call EXPAND_LIBNAME_PATH,jemalloc,$(DEPTH)/memory/jemalloc)
 else
 # Temporary, until bug 662814 lands
 VISIBILITY_FLAGS =
 CPPSRCS = dummy.cpp
 endif
  
 # Build mozglue as a shared lib on Windows, OSX and Android.
+# If this is ever changed, update MOZ_SHARED_MOZGLUE in browser/installer/Makefile.in
 ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
 FORCE_SHARED_LIB = 1
 else
 FORCE_STATIC_LIB = 1
 endif
 
 MOZ_GLUE_LDFLAGS = # Don't link against ourselves
 
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -606,17 +606,17 @@ SimpleTest.waitForClipboard = function(a
         if (++SimpleTest.waitForClipboard_polls > 50) {
             // Log the failure.
             SimpleTest.ok(false, "Timed out while polling clipboard for pasted data.");
             reset();
             failureFn();
             return;
         }
 
-        data = SpecialPowers.getClipboardData(flavor);
+        var data = SpecialPowers.getClipboardData(flavor);
 
         if (validatorFn(data)) {
             // Don't show the success message when waiting for preExpectedVal
             if (preExpectedVal)
                 preExpectedVal = null;
             else
                 SimpleTest.ok(true, "Clipboard has the correct value");
             reset();
--- a/testing/mochitest/tests/SimpleTest/specialpowersAPI.js
+++ b/testing/mochitest/tests/SimpleTest/specialpowersAPI.js
@@ -929,17 +929,17 @@ SpecialPowersAPI.prototype = {
   },
 
   openDialog: function(win, args) {
     return win.openDialog.apply(win, args);
   },
 
   // :jdm gets credit for this.  ex: getPrivilegedProps(window, 'location.href');
   getPrivilegedProps: function(obj, props) {
-    parts = props.split('.');
+    var parts = props.split('.');
 
     for (var i = 0; i < parts.length; i++) {
       var p = parts[i];
       if (obj[p]) {
         obj = obj[p];
       } else {
         return null;
       }
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -419,16 +419,17 @@ ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += -lGLESv2
 endif
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += \
   -lui \
   -lmedia \
   -lhardware_legacy \
+  -lhardware \
   $(NULL)
 endif
 
 EXTRA_DEPS += \
   $(topsrcdir)/intl/unicharutil/util/objs.mk \
   $(topsrcdir)/rdf/util/src/objs.mk \
   $(NULL)
 
--- a/toolkit/mozapps/update/common/uachelper.cpp
+++ b/toolkit/mozapps/update/common/uachelper.cpp
@@ -43,19 +43,23 @@ typedef BOOL (WINAPI *LPWTSQueryUserToke
 
 // See the MSDN documentation with title: Privilege Constants
 // At the time of this writing, this documentation is located at: 
 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716%28v=vs.85%29.aspx
 LPCTSTR UACHelper::PrivsToDisable[] = { 
   SE_ASSIGNPRIMARYTOKEN_NAME,
   SE_AUDIT_NAME,
   SE_BACKUP_NAME,
-  // From testing ReadDirectoryChanges still succeeds even with a low
-  // integrity process with the following privilege disabled.
-  SE_CHANGE_NOTIFY_NAME,
+  // CreateProcess will succeed but the app will fail to launch on some WinXP 
+  // machines if SE_CHANGE_NOTIFY_NAME is disabled.  In particular this happens
+  // for limited user accounts on those machines.  The define is kept here as a
+  // reminder that it should never be re-added.  
+  // This permission is for directory watching but also from MSDN: "This
+  // privilege also causes the system to skip all traversal access checks."
+  // SE_CHANGE_NOTIFY_NAME,
   SE_CREATE_GLOBAL_NAME,
   SE_CREATE_PAGEFILE_NAME,
   SE_CREATE_PERMANENT_NAME,
   SE_CREATE_SYMBOLIC_LINK_NAME,
   SE_CREATE_TOKEN_NAME,
   SE_DEBUG_NAME,
   SE_ENABLE_DELEGATION_NAME,
   SE_IMPERSONATE_NAME,
--- a/uriloader/exthandler/mac/nsOSHelperAppService.mm
+++ b/uriloader/exthandler/mac/nsOSHelperAppService.mm
@@ -243,16 +243,87 @@ nsresult nsOSHelperAppService::GetFileTo
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo ** aMIMEInfo)
 {
   return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo);
 }
 
+// Returns the MIME types an application bundle explicitly claims to handle.
+// Returns NULL if aAppRef doesn't explicitly claim to handle any MIME types.
+// If the return value is non-NULL, the caller is responsible for freeing it.
+// This isn't necessarily the same as the MIME types the application bundle
+// is registered to handle in the Launch Services database.  (For example
+// the Preview application is normally registered to handle the application/pdf
+// MIME type, even though it doesn't explicitly claim to handle *any* MIME
+// types in its Info.plist.  This is probably because Preview does explicitly
+// claim to handle the com.adobe.pdf UTI, and Launch Services somehow
+// translates this into a claim to support the application/pdf MIME type.
+// Launch Services doesn't provide any APIs (documented or undocumented) to
+// query which MIME types a given application is registered to handle.  So any
+// app that wants this information (e.g. the Default Apps pref pane) needs to
+// iterate through the entire Launch Services database -- a process which can
+// take several seconds.)
+static CFArrayRef GetMIMETypesHandledByApp(FSRef *aAppRef)
+{
+  CFURLRef appURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aAppRef);
+  if (!appURL) {
+    return NULL;
+  }
+  CFDictionaryRef infoDict = ::CFBundleCopyInfoDictionaryForURL(appURL);
+  ::CFRelease(appURL);
+  if (!infoDict) {
+    return NULL;
+  }
+  CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
+  ::CFRelease(infoDict);
+  if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
+    return NULL;
+  }
+
+  CFArrayRef docTypes = static_cast<CFArrayRef>(cfObject);
+  CFIndex docTypesCount = ::CFArrayGetCount(docTypes);
+  if (docTypesCount == 0) {
+    return NULL;
+  }
+
+  CFMutableArrayRef mimeTypes =
+    ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+  for (CFIndex i = 0; i < docTypesCount; ++i) {
+    cfObject = ::CFArrayGetValueAtIndex(docTypes, i);
+    if (!cfObject || (::CFGetTypeID(cfObject) != ::CFDictionaryGetTypeID())) {
+      continue;
+    }
+    CFDictionaryRef typeDict = static_cast<CFDictionaryRef>(cfObject);
+
+    // When this key is present (on OS X 10.5 and later), its contents
+    // take precedence over CFBundleTypeMIMETypes (and CFBundleTypeExtensions
+    // and CFBundleTypeOSTypes).
+    cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("LSItemContentTypes"));
+    if (cfObject && (::CFGetTypeID(cfObject) == ::CFArrayGetTypeID())) {
+      continue;
+    }
+
+    cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("CFBundleTypeMIMETypes"));
+    if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
+      continue;
+    }
+    CFArrayRef mimeTypeHolder = static_cast<CFArrayRef>(cfObject);
+    CFArrayAppendArray(mimeTypes, mimeTypeHolder,
+                       ::CFRangeMake(0, ::CFArrayGetCount(mimeTypeHolder)));
+  }
+
+  if (!::CFArrayGetCount(mimeTypes)) {
+    ::CFRelease(mimeTypes);
+    mimeTypes = NULL;
+  }
+  return mimeTypes;
+}
+
 // aMIMEType and aFileExt might not match,  If they don't we set *aFound to
 // false and return a minimal nsIMIMEInfo structure.
 already_AddRefed<nsIMIMEInfo>
 nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
                                         const nsACString& aFileExt,
                                         bool * aFound)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
@@ -276,71 +347,113 @@ nsOSHelperAppService::GetMIMEInfoFromOS(
   OSStatus err;
   bool haveAppForType = false;
   bool haveAppForExt = false;
   bool typeAppIsDefault = false;
   bool extAppIsDefault = false;
   FSRef typeAppFSRef;
   FSRef extAppFSRef;
 
+  CFStringRef cfMIMEType = NULL;
+
   if (!aMIMEType.IsEmpty()) {
     CFURLRef appURL = NULL;
     // CFStringCreateWithCString() can fail even if we're not out of memory --
     // for example if the 'cStr' parameter is something very wierd (like "~"
     // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
     // specified in the 'encoding' parameter.  See bug 548719.
-    CFStringRef CFType = ::CFStringCreateWithCString(NULL, flatType.get(), kCFStringEncodingUTF8);
-    if (CFType) {
-      err = ::LSCopyApplicationForMIMEType(CFType, kLSRolesAll, &appURL);
+    cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(),
+                                             kCFStringEncodingUTF8);
+    if (cfMIMEType) {
+      err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
       if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) {
         haveAppForType = true;
         PR_LOG(mLog, PR_LOG_DEBUG, ("LSCopyApplicationForMIMEType found a default application\n"));
       }
-      if (appURL)
+      if (appURL) {
         ::CFRelease(appURL);
-      ::CFRelease(CFType);
+      }
     }
   }
   if (!aFileExt.IsEmpty()) {
     // CFStringCreateWithCString() can fail even if we're not out of memory --
     // for example if the 'cStr' parameter is something very wierd (like "~"
     // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
     // specified in the 'encoding' parameter.  See bug 548719.
-    CFStringRef CFExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
-    if (CFExt) {
-      err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFExt,
+    CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
+    if (cfExt) {
+      err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt,
                                       kLSRolesAll, &extAppFSRef, nsnull);
       if (err == noErr) {
         haveAppForExt = true;
         PR_LOG(mLog, PR_LOG_DEBUG, ("LSGetApplicationForInfo found a default application\n"));
       }
-      ::CFRelease(CFExt);
+      ::CFRelease(cfExt);
     }
   }
 
   if (haveAppForType && haveAppForExt) {
     // Do aMIMEType and aFileExt match?
     if (::FSCompareFSRefs((const FSRef *) &typeAppFSRef, (const FSRef *) &extAppFSRef) == noErr) {
       typeAppIsDefault = true;
       *aFound = true;
     }
   } else if (haveAppForType) {
     // If aFileExt isn't empty, it doesn't match aMIMEType.
     if (aFileExt.IsEmpty()) {
       typeAppIsDefault = true;
       *aFound = true;
     }
   } else if (haveAppForExt) {
-    // If aMIMEType isn't empty, it doesn't match aFileExt.
+    // If aMIMEType isn't empty, it doesn't match aFileExt, which should mean
+    // that we haven't found a matching app.  But make an exception for an app
+    // that also explicitly claims to handle aMIMEType, or which doesn't claim
+    // to handle any MIME types.  This helps work around the following Apple
+    // design flaw:
+    //
+    // Launch Services is somewhat unreliable about registering Apple apps to
+    // handle MIME types.  Probably this is because Apple has officially
+    // deprecated support for MIME types (in favor of UTIs).  As a result,
+    // most of Apple's own apps don't explicitly claim to handle any MIME
+    // types (instead they claim to handle one or more UTIs).  So Launch
+    // Services must contain logic to translate support for a given UTI into
+    // support for one or more MIME types, and it doesn't always do this
+    // correctly.  For example DiskImageMounter isn't (by default) registered
+    // to handle the application/x-apple-diskimage MIME type.  See bug 675356.
+    //
+    // Apple has also deprecated support for file extensions, and Apple apps
+    // also don't register to handle them.  But for some reason Launch Services
+    // is (apparently) better about translating support for a given UTI into
+    // support for one or more file extensions.  It's not at all clear why.
     if (aMIMEType.IsEmpty()) {
       extAppIsDefault = true;
       *aFound = true;
+    } else {
+      CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
+      if (extAppMIMETypes) {
+        if (cfMIMEType) {
+          if (::CFArrayContainsValue(extAppMIMETypes,
+                                     ::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
+                                     cfMIMEType)) {
+            extAppIsDefault = true;
+            *aFound = true;
+          }
+        }
+        ::CFRelease(extAppMIMETypes);
+      } else {
+        extAppIsDefault = true;
+        *aFound = true;
+      }
     }
   }
 
+  if (cfMIMEType) {
+    ::CFRelease(cfMIMEType);
+  }
+
   if (aMIMEType.IsEmpty()) {
     if (haveAppForExt) {
       // If aMIMEType is empty and we've found a default app for aFileExt, try
       // to get the MIME type from aFileExt.  (It might also be worth doing
       // this when aMIMEType isn't empty but haveAppForType is false -- but
       // the doc for this method says that if we have a MIME type (in
       // aMIMEType), we need to give it preference.)
       NSURLFileTypeMappings *map = [NSURLFileTypeMappings sharedMappings];
@@ -377,36 +490,36 @@ nsOSHelperAppService::GetMIMEInfoFromOS(
 
     nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
     if (!app) {
       NS_RELEASE(mimeInfoMac);
       [localPool release];
       return nsnull;
     }
 
-    CFStringRef CFAppName = NULL;
+    CFStringRef cfAppName = NULL;
     if (typeAppIsDefault) {
       app->InitWithFSRef(&typeAppFSRef);
       ::LSCopyItemAttribute((const FSRef *) &typeAppFSRef, kLSRolesAll,
-                            kLSItemDisplayName, (CFTypeRef *) &CFAppName);
+                            kLSItemDisplayName, (CFTypeRef *) &cfAppName);
     } else {
       app->InitWithFSRef(&extAppFSRef);
       ::LSCopyItemAttribute((const FSRef *) &extAppFSRef, kLSRolesAll,
-                            kLSItemDisplayName, (CFTypeRef *) &CFAppName);
+                            kLSItemDisplayName, (CFTypeRef *) &cfAppName);
     }
-    if (CFAppName) {
+    if (cfAppName) {
       nsAutoTArray<UniChar, 255> buffer;
-      CFIndex appNameLength = ::CFStringGetLength(CFAppName);
+      CFIndex appNameLength = ::CFStringGetLength(cfAppName);
       buffer.SetLength(appNameLength);
-      ::CFStringGetCharacters(CFAppName, CFRangeMake(0, appNameLength),
+      ::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength),
                               buffer.Elements());
       nsAutoString appName;
       appName.Assign(buffer.Elements(), appNameLength);
       mimeInfoMac->SetDefaultDescription(appName);
-      ::CFRelease(CFAppName);
+      ::CFRelease(cfAppName);
     }
 
     mimeInfoMac->SetDefaultApplication(app);
     mimeInfoMac->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
   } else {
     mimeInfoMac->SetPreferredAction(nsIMIMEInfo::saveToDisk);
   }
 
@@ -419,31 +532,32 @@ nsOSHelperAppService::GetMIMEInfoFromOS(
     NSString *typeStr = [NSString stringWithCString:mimeType.get() encoding:NSASCIIStringEncoding];
     NSString *extStr = map ? [map preferredExtensionForMIMEType:typeStr] : NULL;
     if (extStr) {
       nsCAutoString preferredExt;
       preferredExt.Assign((char *)[extStr cStringUsingEncoding:NSASCIIStringEncoding]);
       mimeInfoMac->AppendExtension(preferredExt);
     }
 
-    CFStringRef CFType = ::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8);
-    CFStringRef CFTypeDesc = NULL;
-    if (::LSCopyKindStringForMIMEType(CFType, &CFTypeDesc) == noErr) {
+    CFStringRef cfType = ::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8);
+    CFStringRef cfTypeDesc = NULL;
+    if (::LSCopyKindStringForMIMEType(cfType, &cfTypeDesc) == noErr) {
       nsAutoTArray<UniChar, 255> buffer;
-      CFIndex typeDescLength = ::CFStringGetLength(CFTypeDesc);
+      CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
       buffer.SetLength(typeDescLength);
-      ::CFStringGetCharacters(CFTypeDesc, CFRangeMake(0, typeDescLength),
+      ::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength),
                               buffer.Elements());
       nsAutoString typeDesc;
       typeDesc.Assign(buffer.Elements(), typeDescLength);
       mimeInfoMac->SetDescription(typeDesc);
     }
-    if (CFTypeDesc)
-      ::CFRelease(CFTypeDesc);
-    ::CFRelease(CFType);
+    if (cfTypeDesc) {
+      ::CFRelease(cfTypeDesc);
+    }
+    ::CFRelease(cfType);
   }
 
   PR_LOG(mLog, PR_LOG_DEBUG, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound));
 
   [localPool release];
   return mimeInfoMac;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -114,16 +114,20 @@ class gfxASurface;
 class nsChildView;
 class nsCocoaWindow;
 union nsPluginPort;
 
 namespace mozilla {
 namespace gl {
 class TextureImage;
 }
+
+namespace layers {
+class LayerManagerOGL;
+}
 }
 
 #ifndef NP_NO_CARBON
 enum {
   // Currently focused ChildView (while this TSM document is active).
   // Transient (only set while TSMProcessRawKeyEvent() is processing a key
   // event), and the ChildView will be retained and released around the call
   // to TSMProcessRawKeyEvent() -- so it can be weak.
@@ -290,16 +294,19 @@ typedef NSInteger NSEventGestureAxis;
   float mCumulativeRotation;
 
   BOOL mDidForceRefreshOpenGL;
 
   // Support for fluid swipe tracking.
 #ifdef __LP64__
   BOOL *mSwipeAnimationCancelled;
 #endif
+
+  // Whether this uses off-main-thread compositing.
+  BOOL mUsingOMTCompositor;
 }
 
 // class initialization
 + (void)initialize;
 
 // these are sent to the first responder when the window key status changes
 - (void)viewsWindowDidBecomeKey;
 - (void)viewsWindowDidResignKey;
@@ -322,16 +329,18 @@ typedef NSInteger NSEventGestureAxis;
 - (void) _surfaceNeedsUpdate:(NSNotification*)notification;
 
 - (BOOL)isPluginView;
 
 // Are we processing an NSLeftMouseDown event that will fail to click through?
 // If so, we shouldn't focus or unfocus a plugin.
 - (BOOL)isInFailingLeftClickThrough;
 
+- (void)setGLContext:(NSOpenGLContext *)aGLContext;
+
 // Simple gestures support
 //
 // XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
 // rotateWithEvent, and endGestureWithEvent methods are part of a
 // PRIVATE interface exported by nsResponder and reverse-engineering
 // was necessary to obtain the methods' prototypes. Thus, Apple may
 // change the interface in the future without notice.
 //
@@ -343,16 +352,18 @@ typedef NSInteger NSEventGestureAxis;
 - (void)rotateWithEvent:(NSEvent *)anEvent;
 - (void)endGestureWithEvent:(NSEvent *)anEvent;
 
 // Support for fluid swipe tracking.
 #ifdef __LP64__
 - (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
                       scrollOverflow:(PRInt32)overflow;
 #endif
+
+- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
 @end
 
 class ChildViewMouseTracker {
 
 public:
 
   static void MouseMoved(NSEvent* aEvent);
   static void MouseScrolled(NSEvent* aEvent);
@@ -428,17 +439,17 @@ public:
   static  bool            ConvertStatus(nsEventStatus aStatus)
                           { return aStatus == nsEventStatus_eConsumeNoDefault; }
   NS_IMETHOD              DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus);
 
   virtual bool            GetShouldAccelerate();
 
   NS_IMETHOD        SetCursor(nsCursor aCursor);
   NS_IMETHOD        SetCursor(imgIContainer* aCursor, PRUint32 aHotspotX, PRUint32 aHotspotY);
-  
+
   NS_IMETHOD        CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture, bool aConsumeRollupEvent);
   NS_IMETHOD        SetTitle(const nsAString& title);
 
   NS_IMETHOD        GetAttention(PRInt32 aCycleCount);
 
   virtual bool HasPendingInputEvent();
 
   NS_IMETHOD        ActivateNativeMenuItemAt(const nsAString& indexString);
@@ -481,16 +492,17 @@ public:
   // Mac specific methods
   
   virtual bool      DispatchWindowEvent(nsGUIEvent& event);
   
 #ifdef ACCESSIBILITY
   already_AddRefed<nsAccessible> GetDocumentAccessible();
 #endif
 
+  virtual void CreateCompositor();
   virtual gfxASurface* GetThebesSurface();
   virtual void DrawOver(LayerManager* aManager, nsIntRect aRect);
 
   virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries);
 
   NS_IMETHOD BeginSecureKeyboardInput();
   NS_IMETHOD EndSecureKeyboardInput();
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -82,16 +82,17 @@
 #endif
 
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 #include "nsRegion.h"
 #include "Layers.h"
 #include "LayerManagerOGL.h"
 #include "GLContext.h"
+#include "mozilla/layers/CompositorCocoaWidgetHelper.h"
 
 #include "mozilla/Preferences.h"
 
 #include <dlfcn.h>
 
 #include <ApplicationServices/ApplicationServices.h>
 
 #include "sampler.h"
@@ -1767,16 +1768,32 @@ NSView<mozView>* nsChildView::GetEditorV
     if (view)
       editorView = view;
   }
   return editorView;
 }
 
 #pragma mark -
 
+void
+nsChildView::CreateCompositor()
+{
+  nsBaseWidget::CreateCompositor();
+  if (mCompositorChild) {
+    LayerManagerOGL *manager =
+      static_cast<LayerManagerOGL*>(compositor::GetLayerManager(mCompositorParent));
+
+    NSOpenGLContext *glContext =
+      (NSOpenGLContext *) manager->gl()->GetNativeData(GLContext::NativeGLContext);
+
+    [(ChildView *)mView setGLContext:glContext];
+    [(ChildView *)mView setUsingOMTCompositor:true];
+  }
+}
+
 gfxASurface*
 nsChildView::GetThebesSurface()
 {
   if (!mTempThebesSurface) {
     mTempThebesSurface = new gfxQuartzSurface(gfxSize(1, 1), gfxASurface::ImageFormatARGB32);
   }
 
   return mTempThebesSurface;
@@ -2091,16 +2108,26 @@ NSEvent* gLastDragMouseDownEvent = nil;
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [mGLContext clearDrawable];
   [mGLContext setView:self];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+- (void)setGLContext:(NSOpenGLContext *)aGLContext
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  mGLContext = aGLContext;
+  [mGLContext retain];
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
 - (void)dealloc
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [mGLContext release];
   [mPendingDirtyRects release];
   [mLastMouseDownEvent release];
   [mClickThroughMouseDownEvent release];
@@ -2541,23 +2568,28 @@ NSEvent* gLastDragMouseDownEvent = nil;
     if ([cview isPluginView] && [cview pluginDrawingModel] == NPDrawingModelQuickDraw) {
       NSRect frame = [view frame];
       paintEvent.region.Sub(paintEvent.region,
         nsIntRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height));
     }
   }
 #endif
 
-  if (mGeckoChild->GetLayerManager(nsnull)->GetBackendType() == LayerManager::LAYERS_OPENGL) {
-    LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(mGeckoChild->GetLayerManager(nsnull));
-    manager->SetClippingRegion(paintEvent.region); 
+  LayerManager *layerManager = mGeckoChild->GetLayerManager(nsnull);
+  if (layerManager->GetBackendType() == LayerManager::LAYERS_OPENGL) {
+    NSOpenGLContext *glContext;
+
+    LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(layerManager);
+    manager->SetClippingRegion(paintEvent.region);
+    glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
+
     if (!mGLContext) {
-      mGLContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
-      [mGLContext retain];
+      [self setGLContext:glContext];
     }
+
     mGeckoChild->DispatchWindowEvent(paintEvent);
 
     // Force OpenGL to refresh the very first time we draw. This works around a
     // Mac OS X bug that stops windows updating on OS X when we use OpenGL.
     if (!mDidForceRefreshOpenGL) {
       [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
       mDidForceRefreshOpenGL = YES;
     }
@@ -2587,16 +2619,26 @@ NSEvent* gLastDragMouseDownEvent = nil;
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
   bool painted;
   {
     nsBaseWidget::AutoLayerManagerSetup
       setupLayerManager(mGeckoChild, targetContext, BasicLayerManager::BUFFER_NONE);
     painted = mGeckoChild->DispatchWindowEvent(paintEvent);
   }
 
+  // Force OpenGL to refresh the very first time we draw. This works around a
+  // Mac OS X bug that stops windows updating on OS X when we use OpenGL.
+  if (painted && !mDidForceRefreshOpenGL &&
+      layerManager->AsShadowManager() && mUsingOMTCompositor) {
+    if (!mDidForceRefreshOpenGL) {
+      [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
+      mDidForceRefreshOpenGL = YES;
+    }
+  }
+
   if (!painted && [self isOpaque]) {
     // Gecko refused to draw, but we've claimed to be opaque, so we have to
     // draw something--fill with white.
     CGContextSetRGBFillColor(aContext, 1, 1, 1, 1);
     CGContextFillRect(aContext, CGRectMake(aRect.origin.x, aRect.origin.y,
                                            aRect.size.width, aRect.size.height));
   }
 
@@ -3124,16 +3166,22 @@ NSEvent* gLastDragMouseDownEvent = nil;
   // We keep a pointer to the __block variable (animationCanceled) so we
   // can cancel our block handler at any time.  Note: We must assign
   // &animationCanceled after our block creation and copy -- its address
   // isn't resolved until then!
   mSwipeAnimationCancelled = &animationCancelled;
 }
 #endif // #ifdef __LP64__
 
+- (void)setUsingOMTCompositor:(BOOL)aUseOMTC
+{
+  mUsingOMTCompositor = aUseOMTC;
+}
+
+
 // Returning NO from this method only disallows ordering on mousedown - in order
 // to prevent it for mouseup too, we need to call [NSApp preventWindowOrdering]
 // when handling the mousedown event.
 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent*)aEvent
 {
   // Always using system-provided window ordering for normal windows.
   if (![[self window] isKindOfClass:[PopupWindow class]])
     return NO;
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -33,16 +33,18 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/Util.h"
 
+#include "mozilla/layers/CompositorChild.h"
+#include "mozilla/layers/CompositorParent.h"
 #include "nsBaseWidget.h"
 #include "nsDeviceContext.h"
 #include "nsCOMPtr.h"
 #include "nsGfxCIID.h"
 #include "nsWidgetsCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIScreenManager.h"
 #include "nsAppDirectoryServiceDefs.h"
@@ -50,31 +52,34 @@
 #include "nsIContent.h"
 #include "nsIServiceManager.h"
 #include "mozilla/Preferences.h"
 #include "BasicLayers.h"
 #include "LayerManagerOGL.h"
 #include "nsIXULRuntime.h"
 #include "nsIGfxInfo.h"
 #include "npapi.h"
+#include "base/thread.h"
 
 #ifdef DEBUG
 #include "nsIObserver.h"
 
 static void debug_RegisterPrefCallbacks();
 
 static bool debug_InSecureKeyboardInputMode = false;
 #endif
 
 #ifdef NOISY_WIDGET_LEAKS
 static PRInt32 gNumWidgets;
 #endif
 
 using namespace mozilla::layers;
 using namespace mozilla;
+using base::Thread;
+using mozilla::ipc::AsyncChannel;
 
 nsIContent* nsBaseWidget::mLastRollup = nsnull;
 
 // nsBaseWidget
 NS_IMPL_ISUPPORTS1(nsBaseWidget, nsIWidget)
 
 
 nsAutoRollup::nsAutoRollup()
@@ -99,16 +104,17 @@ nsAutoRollup::~nsAutoRollup()
 //-------------------------------------------------------------------------
 
 nsBaseWidget::nsBaseWidget()
 : mClientData(nsnull)
 , mViewWrapperPtr(nsnull)
 , mEventCallback(nsnull)
 , mViewCallback(nsnull)
 , mContext(nsnull)
+, mCompositorThread(nsnull)
 , mCursor(eCursor_standard)
 , mWindowType(eWindowType_child)
 , mBorderStyle(eBorderStyle_none)
 , mOnDestroyCalled(false)
 , mUseAcceleratedRendering(false)
 , mTemporarilyUseBasicLayerManager(false)
 , mBounds(0,0,0,0)
 , mOriginalBounds(nsnull)
@@ -137,16 +143,22 @@ nsBaseWidget::~nsBaseWidget()
 {
   if (mLayerManager &&
       mLayerManager->GetBackendType() == LayerManager::LAYERS_BASIC) {
     static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
   }
 
   if (mLayerManager) {
     mLayerManager->Destroy();
+    mLayerManager = nsnull;
+  }
+
+  if (mCompositorChild) {
+    mCompositorChild->Destroy();
+    delete mCompositorThread;
   }
 
 #ifdef NOISY_WIDGET_LEAKS
   gNumWidgets--;
   printf("WIDGETS- = %d\n", gNumWidgets);
 #endif
 
   NS_IF_RELEASE(mContext);
@@ -809,36 +821,81 @@ nsBaseWidget::GetShouldAccelerate()
 
   if (accelerateByDefault)
     return true;
 
   /* use the window acceleration flag */
   return mUseAcceleratedRendering;
 }
 
+void nsBaseWidget::CreateCompositor()
+{
+  mCompositorParent = new CompositorParent(this);
+  mCompositorThread = new Thread("CompositorThread");
+  if (mCompositorThread->Start()) {
+    LayerManager* lm = CreateBasicLayerManager();
+    MessageLoop *childMessageLoop = mCompositorThread->message_loop();
+    mCompositorChild = new CompositorChild(lm);
+    AsyncChannel *parentChannel = mCompositorParent->GetIPCChannel();
+    AsyncChannel::Side childSide = mozilla::ipc::AsyncChannel::Child;
+    mCompositorChild->Open(parentChannel, childMessageLoop, childSide);
+    PLayersChild* shadowManager =
+      mCompositorChild->SendPLayersConstructor(LayerManager::LAYERS_OPENGL);
+
+    if (shadowManager) {
+      ShadowLayerForwarder* lf = lm->AsShadowForwarder();
+      if (!lf) {
+        delete lm;
+        mCompositorChild = nsnull;
+      }
+      lf->SetShadowManager(shadowManager);
+      lf->SetParentBackendType(LayerManager::LAYERS_OPENGL);
+
+      mLayerManager = lm;
+    } else {
+      NS_WARNING("fail to construct LayersChild");
+      delete lm;
+      mCompositorChild = nsnull;
+    }
+  }
+}
+
 LayerManager* nsBaseWidget::GetLayerManager(PLayersChild* aShadowManager,
                                             LayersBackend aBackendHint,
                                             LayerManagerPersistence aPersistence,
                                             bool* aAllowRetaining)
 {
   if (!mLayerManager) {
 
     mUseAcceleratedRendering = GetShouldAccelerate();
 
     if (mUseAcceleratedRendering) {
-      nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(this);
-      /**
-       * XXX - On several OSes initialization is expected to fail for now.
-       * If we'd get a none-basic layer manager they'd crash. This is ok though
-       * since on those platforms it will fail. Anyone implementing new
-       * platforms on LayerManagerOGL should ensure their widget is able to
-       * deal with it though!
-       */
-      if (layerManager->Initialize()) {
-        mLayerManager = layerManager;
+
+      // Try to use an async compositor first, if possible
+      bool useCompositor =
+        Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
+      if (useCompositor) {
+        // e10s uses the parameter to pass in the shadow manager from the TabChild
+        // so we don't expect to see it there since this doesn't support e10s.
+        NS_ASSERTION(aShadowManager == nsnull, "Async Compositor not supported with e10s");
+        CreateCompositor();
+      }
+
+      if (!mLayerManager) {
+        nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(this);
+        /**
+         * XXX - On several OSes initialization is expected to fail for now.
+         * If we'd get a non-basic layer manager they'd crash. This is ok though
+         * since on those platforms it will fail. Anyone implementing new
+         * platforms on LayerManagerOGL should ensure their widget is able to
+         * deal with it though!
+         */
+        if (layerManager->Initialize()) {
+          mLayerManager = layerManager;
+        }
       }
     }
     if (!mLayerManager) {
       mBasicLayerManager = mLayerManager = CreateBasicLayerManager();
     }
   }
   if (mTemporarilyUseBasicLayerManager && !mBasicLayerManager) {
     mBasicLayerManager = CreateBasicLayerManager();
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -46,31 +46,45 @@
 #include "nsGUIEvent.h"
 #include "nsAutoPtr.h"
 #include "BasicLayers.h"
 
 class nsIContent;
 class nsAutoRollup;
 class gfxContext;
 
+namespace mozilla {
+namespace layers {
+class CompositorChild;
+class CompositorParent;
+}
+}
+
+namespace base {
+class Thread;
+}
+
 /**
  * Common widget implementation used as base class for native
  * or crossplatform implementations of Widgets. 
  * All cross-platform behavior that all widgets need to implement 
  * should be placed in this class. 
  * (Note: widget implementations are not required to use this
  * class, but it gives them a head start.)
  */
 
 class nsBaseWidget : public nsIWidget
 {
   friend class nsAutoRollup;
 
 protected:
   typedef mozilla::layers::BasicLayerManager BasicLayerManager;
+  typedef mozilla::layers::CompositorChild CompositorChild;
+  typedef mozilla::layers::CompositorParent CompositorParent;
+  typedef base::Thread Thread;
 
 public:
   nsBaseWidget();
   virtual ~nsBaseWidget();
   
   NS_DECL_ISUPPORTS
   
   // nsIWidget interface
@@ -112,16 +126,17 @@ public:
   NS_IMETHOD              HideWindowChrome(bool aShouldHide);
   NS_IMETHOD              MakeFullScreen(bool aFullScreen);
   virtual nsDeviceContext* GetDeviceContext();
   virtual LayerManager*   GetLayerManager(PLayersChild* aShadowManager = nsnull,
                                           LayersBackend aBackendHint = LayerManager::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nsnull);
 
+  virtual void            CreateCompositor();
   virtual void            DrawOver(LayerManager* aManager, nsIntRect aRect) {}
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}
   virtual gfxASurface*    GetThebesSurface();
   NS_IMETHOD              SetModal(bool aModal); 
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType);
   NS_IMETHOD              MoveClient(PRInt32 aX, PRInt32 aY);
   NS_IMETHOD              ResizeClient(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint);
   NS_IMETHOD              ResizeClient(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool aRepaint);
@@ -263,16 +278,19 @@ protected:
 protected:
   void*             mClientData;
   ViewWrapper*      mViewWrapperPtr;
   EVENT_CALLBACK    mEventCallback;
   EVENT_CALLBACK    mViewCallback;
   nsDeviceContext* mContext;
   nsRefPtr<LayerManager> mLayerManager;
   nsRefPtr<LayerManager> mBasicLayerManager;
+  nsRefPtr<CompositorChild> mCompositorChild;
+  nsRefPtr<CompositorParent> mCompositorParent;
+  Thread*           mCompositorThread;
   nscolor           mBackground;
   nscolor           mForeground;
   nsCursor          mCursor;
   nsWindowType      mWindowType;
   nsBorderStyle     mBorderStyle;
   bool              mOnDestroyCalled;
   bool              mUseAcceleratedRendering;
   bool              mTemporarilyUseBasicLayerManager;
--- a/xpcom/glue/nsDeque.cpp
+++ b/xpcom/glue/nsDeque.cpp
@@ -345,16 +345,32 @@ void* nsDeque::PeekFront() {
 void* nsDeque::ObjectAt(PRInt32 aIndex) const {
   void* result=0;
   if ((aIndex>=0) && (aIndex<mSize)) {
     result=mData[modulus(mOrigin + aIndex, mCapacity)];
   }
   return result;
 }
 
+void* nsDeque::RemoveObjectAt(PRInt32 aIndex) {
+  if ((aIndex<0) || (aIndex>=mSize)) {
+    return 0;
+  }
+  void* result=mData[modulus(mOrigin + aIndex, mCapacity)];
+
+  // "Shuffle down" all elements in the array by 1, overwritting the element
+  // being removed.
+  for (PRInt32 i=aIndex; i<mSize; i++) {
+    mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)];
+  }
+  mSize--;
+
+  return result;
+}
+
 /**
  * Create and return an iterator pointing to
  * the beginning of the queue. Note that this
  * takes the circular buffer semantics into account.
  *
  * @return  new deque iterator, init'ed to 1st item
  */
 nsDequeIterator nsDeque::Begin() const{
--- a/xpcom/glue/nsDeque.h
+++ b/xpcom/glue/nsDeque.h
@@ -148,16 +148,24 @@ class NS_COM_GLUE nsDeque {
    * Retrieve the i'th member from the deque without removing it.
    *
    * @param   index of desired item
    * @return  i'th element in list
    */
   void* ObjectAt(int aIndex) const;
 
   /**
+   * Removes and returns the i'th member from the deque.
+   *
+   * @param   index of desired item
+   * @return  the element which was removed
+   */
+  void* RemoveObjectAt(int aIndex);
+
+  /**
    * Remove all items from container without destroying them.
    *
    * @return  *this
    */
   nsDeque& Empty();
 
   /**
    * Remove and delete all items from container.
--- a/xpcom/glue/nsHashKeys.h
+++ b/xpcom/glue/nsHashKeys.h
@@ -219,16 +219,49 @@ public:
   }
   enum { ALLOW_MEMMOVE = true };
 
 private:
   nsCOMPtr<nsISupports> mSupports;
 };
 
 /**
+ * hashkey wrapper using refcounted * KeyType
+ *
+ * @see nsTHashtable::EntryType for specification
+ */
+template<class T>
+class nsRefPtrHashKey : public PLDHashEntryHdr
+{
+public:
+  typedef T* KeyType;
+  typedef const T* KeyTypePointer;
+
+  nsRefPtrHashKey(const T* key) :
+    mKey(const_cast<T*>(key)) { }
+  nsRefPtrHashKey(const nsRefPtrHashKey& toCopy) :
+    mKey(toCopy.mKey) { }
+  ~nsRefPtrHashKey() { }
+
+  KeyType GetKey() const { return mKey; }
+  
+  bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
+
+  static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
+  static PLDHashNumber HashKey(KeyTypePointer aKey)
+  {
+    return NS_PTR_TO_INT32(aKey) >>2;
+  }
+  enum { ALLOW_MEMMOVE = true };
+
+private:
+  nsRefPtr<T> mKey;
+};
+
+/**
  * hashkey wrapper using T* KeyType
  *
  * @see nsTHashtable::EntryType for specification
  */
 template<class T>
 class nsPtrHashKey : public PLDHashEntryHdr
 {
  public:
--- a/xpcom/tests/Makefile.in
+++ b/xpcom/tests/Makefile.in
@@ -84,16 +84,17 @@ SIMPLE_PROGRAMS	:= $(CPPSRCS:.cpp=$(BIN_
 
 CPP_UNIT_TESTS = \
                  ShowAlignments.cpp \
                  ShowSSEConfig.cpp \
                  TestAutoPtr.cpp \
                  TestCOMArray.cpp \
                  TestCOMPtr.cpp \
                  TestCOMPtrEq.cpp \
+                 TestDeque.cpp \
                  TestFile.cpp \
                  TestHashtables.cpp \
                  TestID.cpp \
                  TestObserverArray.cpp \
                  TestObserverService.cpp \
                  TestPipe.cpp \
                  TestRefPtr.cpp \
                  TestTextFormatter.cpp \
@@ -104,17 +105,16 @@ CPP_UNIT_TESTS = \
 ifdef MOZ_MEMORY
 CPP_UNIT_TESTS += TestJemalloc.cpp
 endif
 
 # XXX Make this tests work in libxul builds.
 #CPP_UNIT_TESTS += \
 #                  TestArray.cpp \
 #                  TestCRT.cpp \
-#                  TestDeque.cpp \
 #                  TestEncoding.cpp \
 #                  TestExpirationTracker.cpp \
 #                  TestPipes.cpp \
 #                  TestPriorityQueue.cpp \
 #                  TestStorageStream.cpp \
 #                  TestStrings.cpp \
 #                  TestSynchronization.cpp \
 #                  TestTArray.cpp \
--- a/xpcom/tests/TestDeque.cpp
+++ b/xpcom/tests/TestDeque.cpp
@@ -30,126 +30,244 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "TestHarness.h"
 #include "nsDeque.h"
 #include "nsCRT.h"
 #include <stdio.h>
 
 /**************************************************************
   Now define the token deallocator class...
  **************************************************************/
 class _TestDeque {
 public:
-  _TestDeque() {
-    SelfTest();
-  }
-  int SelfTest();
-  nsresult OriginalTest();
-  nsresult OriginalFlaw();
-  nsresult AssignFlaw();
+  int Test();
+private:
+  int OriginalTest();
+  int OriginalFlaw();
+  int AssignFlaw();
+  int TestRemove();
 };
 static _TestDeque sTestDeque;
 
 class _Dealloc: public nsDequeFunctor {
   virtual void* operator()(void* aObject) {
     return 0;
   }
 };
 
+#define TEST(aCondition, aMsg) \
+  if (!(aCondition)) { fail("TestDeque: "#aMsg); return 1; }
+
+
 /**
  * conduct automated self test for this class
  *
  * @param
  * @return
  */
-int _TestDeque::SelfTest() {
+int _TestDeque::Test() {
   /* the old deque should have failed a bunch of these tests */
   int results=0;
   results+=OriginalTest();
   results+=OriginalFlaw();
   results+=AssignFlaw();
+  results+=TestRemove();
   return results;
 }
 
-nsresult _TestDeque::OriginalTest() {
-  int ints[200];
-  int count=sizeof(ints)/sizeof(int);
+int _TestDeque::OriginalTest() {
+  const int size = 200;
+  int ints[size];
   int i=0;
-  int* temp;
+  int temp;
   nsDeque theDeque(new _Dealloc); //construct a simple one...
  
-  for (i=0;i<count;i++) { //initialize'em
-    ints[i]=10*(1+i);
+  // ints = [0...199]
+  for (i=0;i<size;i++) { //initialize'em
+    ints[i]=i;
   }
+  // queue = [0...69]
   for (i=0;i<70;i++) {
     theDeque.Push(&ints[i]);
+    temp=*(int*)theDeque.Peek();
+    TEST(temp == i, "Verify end after push #1");
+    TEST(theDeque.GetSize() == i + 1, "Verify size after push #1");
   }
-  for (i=0;i<56;i++) {
-    temp=(int*)theDeque.Pop();
+  TEST(theDeque.GetSize() == 70, "Verify overall size after pushes #1");
+  // queue = [0...14]
+  for (i=1;i<=55;i++) {
+    temp=*(int*)theDeque.Pop();
+    TEST(temp == 70-i, "Verify end after pop # 1");
+    TEST(theDeque.GetSize() == 70 - i, "Verify size after pop # 1");
   }
+  TEST(theDeque.GetSize() == 15, "Verify overall size after pops");
+
+  // queue = [0...14,0...54]
   for (i=0;i<55;i++) {
     theDeque.Push(&ints[i]);
+    temp=*(int*)theDeque.Peek();
+    TEST(temp == i, "Verify end after push #2");
+    TEST(theDeque.GetSize() == i + 15 + 1, "Verify size after push # 2");
   }
-  for (i=0;i<35;i++) {
-    temp=(int*)theDeque.Pop();
+  TEST(theDeque.GetSize() == 70, "Verify size after end of all pushes #2");
+
+  // queue = [0...14,0...19]
+  for (i=1;i<=35;i++) {
+    temp=*(int*)theDeque.Pop();
+    TEST(temp == 55-i, "Verify end after pop # 2");
+    TEST(theDeque.GetSize() == 70 - i, "Verify size after pop #2");
   }
+  TEST(theDeque.GetSize() == 35, "Verify overall size after end of all pops #2");
+
+  // queue = [0...14,0...19,0...34]
   for (i=0;i<35;i++) {
     theDeque.Push(&ints[i]);
+    temp = *(int*)theDeque.Peek();
+    TEST(temp == i, "Verify end after push # 3");
+    TEST(theDeque.GetSize() == 35 + 1 + i, "Verify size after push #3");
   }
-  for (i=0;i<38;i++) {
-    temp=(int*)theDeque.Pop();
+
+  // queue = [0...14,0...19]
+  for (i=0;i<35;i++) {
+    temp=*(int*)theDeque.Pop();
+    TEST(temp == 34 - i, "Verify end after pop # 3");
   }
-  return NS_OK;
+
+  // queue = [0...14]
+  for (i=0;i<20;i++) {
+    temp=*(int*)theDeque.Pop();
+    TEST(temp == 19 - i, "Verify end after pop # 4");
+  }
+
+  // queue = []
+  for (i=0;i<15;i++) {
+    temp=*(int*)theDeque.Pop();
+    TEST(temp == 14 - i, "Verify end after pop # 5");
+  }
+
+  TEST(theDeque.GetSize() == 0, "Deque should finish empty.");
+
+  return 0;
 }
 
-nsresult _TestDeque::OriginalFlaw() {
+int _TestDeque::OriginalFlaw() {
   int ints[200];
   int i=0;
-  int* temp;
-  nsDeque secondDeque(new _Dealloc);
+  int temp;
+  nsDeque d(new _Dealloc);
   /**
    * Test 1. Origin near end, semi full, call Peek().
    * you start, mCapacity is 8
    */
   printf("fill array\n");
-  for (i=32; i; --i)
-    ints[i]=i*3+10;
-  printf("push 6 times\n");
-  for (i=0; i<6; i++)
-    secondDeque.Push(&ints[i]);
-  printf("popfront 4 times:\n");
-  for (i=4; i; --i) {
-    temp=(int*)secondDeque.PopFront();
-    printf("%d\t",*temp);
+  for (i=0; i<30; i++)
+    ints[i]=i;
+
+  for (i=0; i<6; i++) {
+    d.Push(&ints[i]);
+    temp = *(int*)d.Peek();
+    TEST(temp == i, "OriginalFlaw push #1");
+  }
+  TEST(d.GetSize() == 6, "OriginalFlaw size check #1");
+
+  for (i=0; i<4; i++) {
+    temp=*(int*)d.PopFront();
+    TEST(temp == i, "PopFront test");
+  }
+  // d = [4,5]
+  TEST(d.GetSize() == 2, "OriginalFlaw size check #2");
+
+  for (i=0; i<4; i++) {
+    d.Push(&ints[6 + i]);
   }
-  printf("push 4 times\n");
-  for (int j=4; j; --j)
-    secondDeque.Push(&ints[++i]);
-  printf("origin should now be about 4\n");
-  printf("and size should be 6\n");
-  printf("origin+size>capacity\n");
+  // d = [4...9]
+
+  for (i=4; i<=9; i++) {
+    temp=*(int*)d.PopFront();
+    TEST(temp == i, "OriginalFlaw empty check");
+  }
+
+  return 0;
+}
 
-   /*<akk> Oh, I see ... it's a circular buffer */
-  printf("but the old code wasn't behaving accordingly.\n");
+int _TestDeque::AssignFlaw() {
+  nsDeque src(new _Dealloc),dest(new _Dealloc);
+  return 0;
+}
 
-   /*right*/
-  printf("we shouldn't crash or anything interesting, ");
-
-  temp=(int*)secondDeque.Peek();
-  printf("peek: %d\n",*temp);
-  return NS_OK;
+static bool VerifyContents(const nsDeque& aDeque, const int* aContents, int aLength) {
+  for (int i=0; i<aLength; ++i) {
+    if (*(int*)aDeque.ObjectAt(i) != aContents[i]) {
+      return false;
+    }
+  }
+  return true;
 }
 
-nsresult _TestDeque::AssignFlaw() {
-  nsDeque src(new _Dealloc),dest(new _Dealloc);
-  return NS_OK;
+int _TestDeque::TestRemove() {
+  nsDeque d;
+  const int count = 10;
+  int ints[count];
+  for (int i=0; i<count; i++) {
+    ints[i] = i;
+  }
+
+  for (int i=0; i<6; i++) {
+    d.Push(&ints[i]);
+  }
+  // d = [0...5]
+  d.PopFront();
+  d.PopFront();
+
+  // d = [2,5]
+  for (int i=2; i<=5; i++) {
+    int t = *(int*)d.ObjectAt(i-2);
+    TEST(t == i, "Verify ObjectAt()");
+  }
+
+  d.RemoveObjectAt(1);
+  // d == [2,4,5]
+  static const int t1[] = {2,4,5};
+  TEST(VerifyContents(d, t1, 3), "verify contents t1");
+
+  d.PushFront(&ints[1]);
+  d.PushFront(&ints[0]);
+  d.PushFront(&ints[7]);
+  d.PushFront(&ints[6]);
+  //  d == [6,7,0,1,2,4,5] // (0==mOrigin)
+  static const int t2[] = {6,7,0,1,2,4,5};
+  TEST(VerifyContents(d, t2, 7), "verify contents t2");
+
+  d.RemoveObjectAt(1);
+  //  d == [6,0,1,2,4,5] // (1==mOrigin)
+  static const int t3[] = {6,0,1,2,4,5};
+  TEST(VerifyContents(d, t3, 6), "verify contents t3");
+
+  d.RemoveObjectAt(5);
+  //  d == [6,0,1,2,4] // (1==mOrigin)
+  static const int t4[] = {6,0,1,2,4};
+  TEST(VerifyContents(d, t4, 5), "verify contents t4");
+
+  d.RemoveObjectAt(0);
+  //  d == [0,1,2,4] // (2==mOrigin)
+  static const int t5[] = {0,1,2,4};
+  TEST(VerifyContents(d, t5, 4), "verify contents t5");
+
+
+  return 0;
 }
 
 int main (void) {
+  ScopedXPCOM xpcom("TestTimers");
+  NS_ENSURE_FALSE(xpcom.failed(), 1);
+
   _TestDeque test;
+  int result = test.Test();
+  TEST(result == 0, "All tests pass");
   return 0;
 }