Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Fri, 20 Jan 2012 10:12:37 -0800
changeset 111892 577a1c24f51942a2deeedaec7bd06125d5fc39f1
parent 111891 9711a0b8495f933f84d0be655874cba75a507e11 (current diff)
parent 87397 49936b49aff3498fecf5b0c87684e135c19199f7 (diff)
child 111893 7685f6b2f00d84c0e32bd85a730957958791c266
push idunknown
push userunknown
push dateunknown
milestone12.0a1
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
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
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;
 }