Merge m-c to m-i.
authorRichard Newman <rnewman@mozilla.com>
Thu, 23 Feb 2012 18:37:12 -0800
changeset 87605 f2b33e6f0981744e516d876344a281abf9b403bb
parent 87604 62c8bf0d48bbd99cab6afb5f8eac1e6e64a3498a (current diff)
parent 87566 d23600a1d4a7be931888752767978407df29edb0 (diff)
child 87606 52fe920f26851ec313712b4e1c6b21d18fc7d27a
push id22133
push usermak77@bonardo.net
push dateFri, 24 Feb 2012 10:23:30 +0000
treeherdermozilla-central@fbcdc2c87df8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to m-i.
b2g/chrome/content/webapi.js
b2g/chrome/jar.mn
new file mode 100644
index 0000000000000000000000000000000000000000..9f2e4a6e7366abd9123ad34ed8d369c387111fee
GIT binary patch
literal 850
zc$@)J1FigtP)<h;3K|Lk000e1NJLTq002Ay002A)1^@s6I{evk0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!^hrcPRCwC#n(J|+Fc5$tlLAx%>3|YQ
z2c&|K4x9?2tH33Y4t%MAbl`M=J0Kl!=tj;k8cFP~Ry<;MM&myQ^l6`3Dee0{xhYY=
zGeVc@lgtCm_@8rTU?s;}0~W(**8q(DP&1622%RqloL;q?rs??Miykg1^zY{|9*NL$
z7;g*~lR|)h{_Fr&@<&g~WtJWEgC05QcZJ9!26)P(mDy&l_drc*Et$w?(qs7^#_KTN
zEx@4~u00F7h=#|*G`~;{*IS6v=Mi)WaJ8khbO;3IOi5_qdt%`bBDu~0S9x0`f+1E^
zGDqolP7U9!AZvUDJo^{>z#4!*W_@-ACY|W$k2U2prSMpThLybN0tYJUzfW@ot!A{R
z?HHkRpr#vab;h+l>@_&IR2s@w=~bb%^cYwoG%R(yW>ak}TgRi&W(o;f$rgdlN=t3%
z9|F4>zNSIJ{LXiyQBmkh@Z!wxo}Si`Ny8<;YAB;NzLOc>`B56CiD#QE2Dpv@YVO*u
z^}Q{^tGQ=Wz``&;GhIL<<slMmXK^>*!qz_E%Ft-1wJbEiVWBPHc$CP!b>{*uner`n
z-`O{h91<T~z*CcKfP3L4qTeO}zXbzR{m1Mz$MRc24Tw|?+uA&4o`p^x3tWT*M2Zi)
z@}Mvp^N`Lb)(T{3K%9!wSigeqa$3DG7~m5}K%C0Md8EoHNBVhd@!J#S+mK32Fh|>p
z5ZH3ALIzV>$_O>DL@rQpA%i^-4=Mi77PFMd1rnhyM!5ly5gKi-oGp<H6zp2mD-Qy>
z`zeubVp|}VLMHT%M+GpkBcU2AiG@sb;A;?RiTz>;SRlcf8o6%q2tCoxQGG#yo7fwW
z7}u6CCyH`nQ^0+Xt6%z_mh@~2V%*eQ4e(*23HPgjPfQ1Dn*c87@LLz~_}bD^2LqX<
zoTQ{l;W>FoA&vMgNdwjJU2<b`bHGdZu&TwMncoTa;rj&^Ig4<LxSRA2yaVsRJMa#?
cMfoSd04yL1uj;}d)c^nh07*qoM6N<$g2EqxIsgCw
new file mode 100644
index 0000000000000000000000000000000000000000..fc153c7314e82e12a75ac2589c63db3344a5eb34
GIT binary patch
literal 886
zc$@)t1Bv{JP)<h;3K|Lk000e1NJLTq002Ay002A)1^@s6I{evk0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU#7)eAyRCwC#T8nX`Fc8I=6hH}12c&}F
z4oC$@I&dlosep8VJ0Mqqa}}5l><(}ToJjU&G&%`Mt6d`}yqTR0j*axR`&O&ZY8Zy(
zC*fv>HVa_`u|-YzUD(@P9$w89(y6e6ur(DAtcQI=X)i28bnq<fF$NFI4<|4aa`^ip
zY=dmS683UQ4^I&u@d}+Xg=O#Cpaw0xD+C)V!v8$@WbpPtKscI^RyFr5Y{x*jAxK^u
zYQplA@&p4wL3kuv#-w2#IvCM&AmI`S&pIu+AS3WfMo88Rw*iGiDB)M>`6YJ3p-_|G
zFT$!Tx?0+l7eZ?Dt0VmTQooIb@DAzaP9u-2Ae<=kJKF*TOZY)pEj3J~<Bg-I$8z`H
zvbfP>EIcH`pjO^NVWqIWrmYtKhkmzOX}K=f#u5Gl-gr;037S#Jh4mJ%Rt#Rfh}{~z
zcNegmkythja)u0lQrbx2v(ClCveiT$E*zo;gGOm*t+X@dflU4mwzEEjn}G)hVX4$k
z3ZJRyVIU?6r=aB=o-^fTu9<SnM7CEwXBpULig2lTv<EMzKw#@gHXHa*X!>j$AT8m7
zXucf>=g361)(osme$W!Ob#kxh#$<a&-6jsYbta6}k8BmAZqtB-i1M(Et)Xaf?YuAY
zz=Y_nVN>=?rSNhg(juauB1njnS=v`unWL7DFfcxZTcU(GIS*$8Pi2&O>inqDZHsLC
z^Y=FsYtuWZt0@=wzPlQa%6fa7d>yEhu9i5mZi9GdNnFS{*V3WI|3MR$mFEDZ1QMGJ
zY28-nJt8E}h`p)~4(_OrRK54KPO#^+W7Mr~fGW~8bikgIEyQX>UMP@-47r9)Q`gb4
z=5--lGw2qrVUyNIUB4+IxJ&%+e0*@~mLjB0OG4N0R+dFU%~13NdsvrnFi?w&0t$?8
zd3yM)RC8<YgYr2E>#iX3=r#hv9n7~fYKDFA|1X0?a($R0lru|otYRWefxV?7Tg7%h
zd=dOO!gGamnS9;cp@fr$=eoAEW;jJ$LV6**5MBr`gcrishQ9&~07cZf+~wI#>Hq)$
M07*qoM6N<$f|_oW82|tP
new file mode 100644
index 0000000000000000000000000000000000000000..8bf9d8e7decc3642be80e0d6dc615c2f50f64a79
GIT binary patch
literal 631
zc$@)u0*L*IP)<h;3K|Lk000e1NJLTq002Ay002A)1^@s6I{evk0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!8A(JzRCwC#o9%6bFc5~J>i=d0kH83w
zzzA$mHYgj=PQVDX6L^GlgN(okG)P8DBRkml;n>NY^h%KkwjZ5+zB?u5vMj|j*-P<c
zCcpwLzyd750-TV&x*n8e$u*}st2Lj0&-&(=#F<d74{TzxW}Wg%BNwohD<bgWtl0v*
zs(wV^(E+>a^k~4<4cJZnBLQm<;MoMU?15Vk*iBRJz_$X`!WqEs1v~`8t~%xltN^f^
zx*UNu0(dsZAsgTZ0ZWpB#RNW>L}G8t*5<sj1hAOEeSqio&bdw<*e6g`SMN+a-)~a}
zo;-j<cLXSa#Q?5>cdXBQLyEvBkA-U>u<a;-fT>zMy=UT&xmyR4l@fSZ1?J1w)&;!V
zq~PHXq~{KSUPfhLSl}9ZZ6L0_?w(uvScIpHq1Td4>K<FV3yqu?Ub?h5V1F#CharW%
zD?ipm<FI-d6FjONkMnvN;Nhykm3<T8SbdC4OBeWBS9$cReH#Ue6SyUS-E!)VXsn3~
z7!#<tRdWCjiNac|Ff6blT-;=G;@Siqs$J7j0&Aj0X~wwluTg*jZV0{Wx<;tRAF;qb
z9mo(3j$lY0z@WfA@nU96rZp1Jp`pNvDWc8>vIkaMK58MrDPKc-Izftus>s(ASH~ke
zy9NA}G1sT-LFp<K%n#Gn5dV&CoJF>u71+roe*q9+0Ty5Z7GMDu;8^x2zyNbwkV-1)
R8RGx|002ovPDHLkV1nb47!m*g
new file mode 100644
--- /dev/null
+++ b/b2g/chrome/content/netError.css
@@ -0,0 +1,127 @@
+/*
+ *  This defines the look-and-feel styling of the error pages.
+ *  (see: netError.xhtml)
+ *
+ *  Original styling by William Price <bugzilla@mob.rice.edu>
+ *  Updated for mobile by: Wes Johnston <wjohnston@mozilla.com>
+ */
+
+body {
+  margin: 0;
+  padding: 0 8px 8px;
+  font-family: "Nokia Sans", Tahoma, sans-serif !important;
+}
+
+h1 {
+  font-size: 22px;
+}
+
+h2 {
+  font-size: 16px;
+}
+
+ul {
+  margin: 0px;
+  padding: 0px 0px 0px 1em;
+}
+
+li {
+  margin: 0px;
+  padding: 8px 0px;
+}
+
+#errorPage {
+  background-color: #CEE6F4;
+}
+
+#errorPage.certerror {
+  background-color: #EFD400;
+}
+
+#errorPage.blockedsite {
+  background-color: #BF0000;
+}
+
+#errorTitle {
+  background: url("chrome://browser/content/images/errorpage-warning.png") left center no-repeat;
+  /* Scaled by .666 of their actual size */
+  background-size: 40px 40px;
+  background-origin: content-box;
+  min-height: 60px;
+  margin-left: auto;
+  margin-right: auto;
+  max-width: 500px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#errorPage.certerror #errorTitle {
+  background-image: url("chrome://browser/content/images/errorpage-larry-black.png");
+}
+
+#errorPage.blockedsite #errorTitle {
+  background-image: url("chrome://browser/content/images/errorpage-larry-white.png");
+  color: white;
+}
+
+.errorTitleText {
+  padding: 0px 0px 0px 50px;
+  display: inline-block;
+  vertical-align: middle
+}
+
+#errorPageContainer {
+  background-color: white;
+  border: 1px solid #999999;
+  border-radius: 6px;
+  padding: 6px 20px 20px;
+  font-size: 14px;
+  max-width: 500px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#errorShortDesc > p:empty {
+  display: none;
+}
+
+#errorShortDesc > p {
+  overflow: auto;
+  border-bottom: 1px solid #999999;
+  padding-bottom: 1em;
+}
+
+#errorPage.blockedsite #errorShortDesc > p {
+  font-weight: bold;
+  border-bottom: none;
+  padding-bottom: 0px;
+}
+
+#securityOverrideDiv {
+  padding-top: 10px;
+}
+
+div[collapsed] {
+  padding-left: 15px;
+  background-image: url("chrome://browser/skin/images/arrowright-16.png");
+  background-size: 11px 11px;
+  background-repeat: no-repeat;
+  background-position: left 0.3em;  
+}
+
+div[collapsed="true"] {
+  background-image: url("chrome://browser/skin/images/arrowright-16.png");
+}
+
+div[collapsed="false"] {
+  background-image: url("chrome://browser/skin/images/arrowdown-16.png");
+}
+
+div[collapsed="true"] > p,
+div[collapsed="true"] > div {
+  display: none;
+}
+
+button {
+  padding: 0.3em !important;
+}
--- a/b2g/chrome/content/netError.xhtml
+++ b/b2g/chrome/content/netError.xhtml
@@ -299,30 +299,30 @@
       function endsWith(haystack, needle) {
         return haystack.slice(-needle.length) == needle;
       }
 
     ]]></script>
   </head>
 
   <body id="errorPage" dir="&locale.dir;">
-
     <!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
     <div id="errorContainer">
       <div id="errorTitlesContainer">
         <h1 id="et_generic">&generic.title;</h1>
         <h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
         <h1 id="et_fileNotFound">&fileNotFound.title;</h1>
         <h1 id="et_malformedURI">&malformedURI.title;</h1>
         <h1 id="et_protocolNotFound">&protocolNotFound.title;</h1>
         <h1 id="et_connectionFailure">&connectionFailure.title;</h1>
         <h1 id="et_netTimeout">&netTimeout.title;</h1>
         <h1 id="et_redirectLoop">&redirectLoop.title;</h1>
         <h1 id="et_unknownSocketType">&unknownSocketType.title;</h1>
         <h1 id="et_netReset">&netReset.title;</h1>
+        <h1 id="et_notCached">&notCached.title;</h1>
         <h1 id="et_netOffline">&netOffline.title;</h1>
         <h1 id="et_netInterrupt">&netInterrupt.title;</h1>
         <h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1>
         <h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1>
         <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1>
         <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1>
         <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1>
         <h1 id="et_nssFailure2">&nssFailure2.title;</h1>
@@ -337,16 +337,17 @@
         <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
         <div id="ed_malformedURI">&malformedURI.longDesc;</div>
         <div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
         <div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
         <div id="ed_netTimeout">&netTimeout.longDesc;</div>
         <div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
         <div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div>
         <div id="ed_netReset">&netReset.longDesc;</div>
+        <div id="ed_notCached">&notCached.longDesc;</div>
         <div id="ed_netOffline">&netOffline.longDesc2;</div>
         <div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
         <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
         <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc2;</div>
         <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
         <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
         <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
         <div id="ed_nssFailure2">&nssFailure2.longDesc;</div>
--- a/b2g/chrome/content/webapi.js
+++ b/b2g/chrome/content/webapi.js
@@ -79,16 +79,28 @@ XPCOMUtils.defineLazyGetter(Services, 'f
   let isKeyboardOpened = false;
   
   function fireEvent(type, details) {
     let event = content.document.createEvent('CustomEvent');
     event.initCustomEvent(type, true, true, details ? details : {});
     content.dispatchEvent(event);
   }
 
+  function maybeShowIme(targetElement) {
+    // FIXME/bug 729623: work around apparent bug in the IME manager
+    // in gecko.
+    let readonly = targetElement.getAttribute('readonly');
+    if (readonly)
+      return false;
+
+    let type = targetElement.type;
+    fireEvent('showime', { type: type });
+    return true;
+  }
+
   let constructor = {
     handleEvent: function vkm_handleEvent(evt) {
       switch (evt.type) {
         case 'keypress':
           if (evt.keyCode != evt.DOM_VK_ESCAPE || !isKeyboardOpened)
             return;
 
           fireEvent('hideime');
@@ -97,31 +109,28 @@ XPCOMUtils.defineLazyGetter(Services, 'f
           evt.preventDefault();
           evt.stopPropagation();
           break;
 
         case 'mousedown':
           if (evt.target != activeElement || isKeyboardOpened)
             return;
 
-          let type = activeElement.type;
-          fireEvent('showime', { type: type });
-          isKeyboardOpened = true;
+          isKeyboardOpened = maybeShowIme(activeElement);
           break;
       }
     },
     observe: function vkm_observe(subject, topic, data) {
       let shouldOpen = parseInt(data);
       if (shouldOpen && !isKeyboardOpened) {
         activeElement = Services.fm.focusedElement;
-        if (!activeElement)
+        if (!activeElement || !maybeShowIme(activeElement)) {
+          activeElement = null;
           return;
-
-        let type = activeElement.type;
-        fireEvent('showime', { type: type });
+        }
       } else if (!shouldOpen && isKeyboardOpened) {
         fireEvent('hideime');
       }
       isKeyboardOpened = shouldOpen;
     }
   };
 
   Services.obs.addObserver(constructor, 'ime-enabled-state-changed', false);
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -12,9 +12,14 @@ chrome.jar:
   content/commandUtil.js                (content/commandUtil.js)
 #ifndef MOZ_WIDGET_GONK
   content/httpd.js                      (content/httpd.js)
 #endif
   content/webapi.js                     (content/webapi.js)
   content/content.css                   (content/content.css)
 
 % override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
+% override chrome://global/skin/netError.css chrome://browser/content/netError.css
   content/netError.xhtml                (content/netError.xhtml)
+  content/netError.css                  (content/netError.css)
+  content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png)
+  content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png)
+  content/images/errorpage-warning.png (content/images/errorpage-warning.png)
\ No newline at end of file
--- a/browser/components/sessionstore/test/browser_579868.js
+++ b/browser/components/sessionstore/test/browser_579868.js
@@ -30,26 +30,26 @@
  * 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 ***** */
 
 function test() {
-  let tab1 = gBrowser.addTab("about:robots");
+  let tab1 = gBrowser.addTab("about:rights");
   let tab2 = gBrowser.addTab("about:mozilla");
   tab1.linkedBrowser.addEventListener("load", mainPart, true);
   waitForExplicitFinish();
 
   function mainPart() {
     tab1.linkedBrowser.removeEventListener("load", mainPart, true);
 
     // Tell the session storer that the tab is pinned
-    let newTabState = '{"entries":[{"url":"about:robots"}],"pinned":true,"userTypedValue":"Hello World!"}';
+    let newTabState = '{"entries":[{"url":"about:rights"}],"pinned":true,"userTypedValue":"Hello World!"}';
     ss.setTabState(tab1, newTabState);
 
     // Undo pinning
     gBrowser.unpinTab(tab1);
 
     is(tab1.linkedBrowser.__SS_tabStillLoading, true,
        "_tabStillLoading should be true.");
 
--- a/browser/components/sessionstore/test/browser_588426.js
+++ b/browser/components/sessionstore/test/browser_588426.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let state = { windows: [{ tabs: [
       {entries: [{url: "about:mozilla"}], hidden: true},
-      {entries: [{url: "about:robots"}], hidden: true}
+      {entries: [{url: "about:rights"}], hidden: true}
   ] }] };
 
   waitForExplicitFinish();
 
   newWindowWithState(state, function (win) {
     registerCleanupFunction(function () win.close());
 
     is(win.gBrowser.tabs.length, 2, "two tabs were restored");
--- a/browser/components/sessionstore/test/browser_589246.js
+++ b/browser/components/sessionstore/test/browser_589246.js
@@ -247,17 +247,17 @@ function onLastWindowClosed(aSubject, aT
 // which should actually trigger the bug.
 function onWindowUnloaded() {
   info("test #" + testNum + ": onWindowClosed");
   ok(gotLastWindowClosedTopic, "test #" + testNum + ": browser-lastwindow-close-granted was notified prior");
 
   let previousClosedWindowData = ss.getClosedWindowData();
 
   // Now we want to open a new window
-  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:robots");
+  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:mozilla");
   newWin.addEventListener("load", function(aEvent) {
     newWin.removeEventListener("load", arguments.callee, false);
 
     newWin.gBrowser.selectedBrowser.addEventListener("load", function () {
       newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
       // Good enough for checking the state
       afterTestCallback(previousClosedWindowData, ss.getClosedWindowData());
--- a/browser/components/sessionstore/test/browser_590563.js
+++ b/browser/components/sessionstore/test/browser_590563.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let oldState = {
     windows: [{
       tabs: [
-        { entries: [{ url: "about:robots" }], hidden: true },
+        { entries: [{ url: "about:mozilla" }], hidden: true },
         { entries: [{ url: "about:blank" }], hidden: false }
       ]
     }]
   };
   let pageData = {
     url: "about:sessionrestore",
     formdata: { "#sessionData": oldState }
   };
--- a/browser/components/sessionstore/test/browser_615394-SSWindowState_events.js
+++ b/browser/components/sessionstore/test/browser_615394-SSWindowState_events.js
@@ -35,17 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 const stateBackup = ss.getBrowserState();
 const testState = {
   windows: [{
     tabs: [
       { entries: [{ url: "about:blank" }] },
-      { entries: [{ url: "about:robots" }] }
+      { entries: [{ url: "about:rights" }] }
     ]
   }]
 };
 const lameMultiWindowState = { windows: [
     {
       tabs: [
         { entries: [{ url: "http://example.org#1" }], extData: { "uniq": r() } },
         { entries: [{ url: "http://example.org#2" }], extData: { "uniq": r() } },
@@ -169,17 +169,17 @@ function test_duplicateTab() {
     is(ss.getTabValue(newTab, "foo"), "bar");
     ss.setTabValue(newTab, "baz", "qux");
   }
 
   function onSSTabRestored(aEvent) {
     is(busyEventCount, 1);
     is(readyEventCount, 1);
     is(ss.getTabValue(newTab, "baz"), "qux");
-    is(newTab.linkedBrowser.currentURI.spec, "about:robots");
+    is(newTab.linkedBrowser.currentURI.spec, "about:rights");
 
     window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false);
     window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false);
     gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false);
 
     runNextTest();
   }
 
@@ -210,17 +210,17 @@ function test_undoCloseTab() {
     is(ss.getTabValue(reopenedTab, "foo"), "bar");
     ss.setTabValue(reopenedTab, "baz", "qux");
   }
 
   function onSSTabRestored(aEvent) {
     is(busyEventCount, 1);
     is(readyEventCount, 1);
     is(ss.getTabValue(reopenedTab, "baz"), "qux");
-    is(reopenedTab.linkedBrowser.currentURI.spec, "about:robots");
+    is(reopenedTab.linkedBrowser.currentURI.spec, "about:rights");
 
     window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false);
     window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false);
     gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false);
 
     runNextTest();
   }
 
--- a/browser/components/sessionstore/test/browser_618151.js
+++ b/browser/components/sessionstore/test/browser_618151.js
@@ -35,17 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 const stateBackup = ss.getBrowserState();
 const testState = {
   windows: [{
     tabs: [
       { entries: [{ url: "about:blank" }] },
-      { entries: [{ url: "about:robots" }] }
+      { entries: [{ url: "about:mozilla" }] }
     ]
   }]
 };
 
 
 function test() {
   /** Test for Bug 618151 - Overwriting state can lead to unrestored tabs **/
   waitForExplicitFinish();
--- a/browser/components/sessionstore/test/browser_625016.js
+++ b/browser/components/sessionstore/test/browser_625016.js
@@ -23,17 +23,17 @@ function test() {
   // forgetClosedWindow doesn't trigger a delayed save
   while (ss.getClosedWindowCount()) {
     ss.forgetClosedWindow(0);
   }
   is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
 
   // Open a new window, which should trigger a save event soon.
   waitForSaveState(onSaveState);
-  newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:robots");
+  newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:rights");
 }
 
 function onSaveState() {
   // Double check that we have no closed windows
   is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
 
   Services.obs.addObserver(observe1, "sessionstore-state-write", false);
 
--- a/browser/components/sessionstore/test/browser_628270.js
+++ b/browser/components/sessionstore/test/browser_628270.js
@@ -15,32 +15,32 @@ function test() {
   }
 
   waitForExplicitFinish();
 
   // check prerequisites
   assertNumberOfTabs(1, "we start off with one tab");
 
   // setup
-  let tab = gBrowser.addTab("about:robots");
+  let tab = gBrowser.addTab("about:mozilla");
 
   whenTabIsLoaded(tab, function () {
     // hide the newly created tab
     assertNumberOfVisibleTabs(2, "there are two visible tabs");
     gBrowser.showOnlyTheseTabs([gBrowser.tabs[0]]);
     assertNumberOfVisibleTabs(1, "there is one visible tab");
     ok(tab.hidden, "newly created tab is now hidden");
 
     // close and restore hidden tab
     gBrowser.removeTab(tab);
     tab = ss.undoCloseTab(window, 0);
 
     // check that everything was restored correctly, clean up and finish
     whenTabIsLoaded(tab, function () {
-      is(tab.linkedBrowser.currentURI.spec, "about:robots", "restored tab has correct url");
+      is(tab.linkedBrowser.currentURI.spec, "about:mozilla", "restored tab has correct url");
 
       gBrowser.removeTab(tab);
       finish();
     });
   });
 }
 
 function whenTabIsLoaded(tab, callback) {
--- a/browser/components/sessionstore/test/browser_694378.js
+++ b/browser/components/sessionstore/test/browser_694378.js
@@ -6,17 +6,16 @@
 // 1a. ensure that it doesn't throw.
 
 function test() {
   waitForExplicitFinish();
 
   let brokenState = {
     windows: [
       { tabs: [{ entries: [{ url: "about:mozilla" }] }] }
-      //{ tabs: [{ entries: [{ url: "about:robots" }] }] },
     ],
     selectedWindow: 2
   };
   let brokenStateString = JSON.stringify(brokenState);
 
   let gotError = false;
   try {
     ss.setWindowState(window, brokenStateString, true);
@@ -27,9 +26,8 @@ function test() {
   }
 
   ok(!gotError, "ss.setWindowState did not throw an error");
 
   // Make sure that we reset the state. Use a full state just in case things get crazy.
   let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]};
   waitForBrowserState(blankState, finish);
 }
-
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -844,25 +844,21 @@ nsTextInputListener::EditAction()
   nsTextControlFrame* frame = static_cast<nsTextControlFrame*> (frameBase);
   NS_ASSERTION(frame, "Where is our frame?");
   //
   // Update the undo / redo menus
   //
   nsCOMPtr<nsIEditor> editor;
   frame->GetEditor(getter_AddRefs(editor));
 
-  nsCOMPtr<nsITransactionManager> manager;
-  editor->GetTransactionManager(getter_AddRefs(manager));
-  NS_ENSURE_TRUE(manager, NS_ERROR_FAILURE);
-
   // Get the number of undo / redo items
   PRInt32 numUndoItems = 0;
   PRInt32 numRedoItems = 0;
-  manager->GetNumberOfUndoItems(&numUndoItems);
-  manager->GetNumberOfRedoItems(&numRedoItems);
+  editor->GetNumberOfUndoItems(&numUndoItems);
+  editor->GetNumberOfRedoItems(&numRedoItems);
   if ((numUndoItems && !mHadUndoItems) || (!numUndoItems && mHadUndoItems) ||
       (numRedoItems && !mHadRedoItems) || (!numRedoItems && mHadRedoItems)) {
     // Modify the menu if undo or redo items are different
     UpdateTextInputCommands(NS_LITERAL_STRING("undo"));
 
     mHadUndoItems = numUndoItems != 0;
     mHadRedoItems = numRedoItems != 0;
   }
--- a/dom/system/b2g/ril_worker.js
+++ b/dom/system/b2g/ril_worker.js
@@ -490,17 +490,17 @@ let Buf = {
 
   /**
    * Start a new outgoing parcel.
    *
    * @param type
    *        Integer specifying the request type.
    * @param options [optional]
    *        Object containing information about the request, e.g. the
-   *        original main thread message object that led to the RIL request. 
+   *        original main thread message object that led to the RIL request.
    */
   newParcel: function newParcel(type, options) {
     if (DEBUG) debug("New outgoing parcel of type " + type);
     // We're going to leave room for the parcel size at the beginning.
     this.outgoingIndex = PARCEL_SIZE_SIZE;
     this.writeUint32(type);
     let token = this.token;
     this.writeUint32(token);
@@ -527,18 +527,18 @@ let Buf = {
     // This assumes that postRILMessage will make a copy of the ArrayBufferView
     // right away!
     let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex);
     if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel));
     postRILMessage(parcel);
     this.outgoingIndex = PARCEL_SIZE_SIZE;
   },
 
-  simpleRequest: function simpleRequest(type) {
-    this.newParcel(type);
+  simpleRequest: function simpleRequest(type, options) {
+    this.newParcel(type, options);
     this.sendParcel();
   }
 };
 
 
 /**
  * Provide a high-level API representing the RIL's capabilities. This is
  * where parcels are sent and received from and translated into API calls.
@@ -565,17 +565,17 @@ let RIL = {
 
     this.rilQuirksInitialized = true;
   },
 
   /**
    * Parse an integer from a string, falling back to a default value
    * if the the provided value is not a string or does not contain a valid
    * number.
-   * 
+   *
    * @param string
    *        String to be parsed.
    * @param defaultValue
    *        Default value to be used.
    */
   parseInt: function RIL_parseInt(string, defaultValue) {
     let number = parseInt(string, 10);
     if (!isNaN(number)) {
@@ -843,19 +843,22 @@ let RIL = {
   sendTone: function sendTone(dtmfChar) {
     Buf.newParcel(REQUEST_DTMF);
     Buf.writeString(dtmfChar);
     Buf.sendParcel();
   },
 
   /**
    * Get the Short Message Service Center address.
+   *
+   * @param pendingSMS
+   *        Object containing the parameters of an SMS waiting to be sent.
    */
-  getSMSCAddress: function getSMSCAddress() {
-    Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS);
+  getSMSCAddress: function getSMSCAddress(pendingSMS) {
+    Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS, pendingSMS);
   },
 
   /**
    * Set the Short Message Service Center address.
    *
    * @param smsc
    *        Short Message Service Center address in PDU format.
    */
@@ -1220,19 +1223,19 @@ RIL[REQUEST_GSM_SMS_BROADCAST_ACTIVATION
 RIL[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null;
 RIL[REQUEST_CDMA_SUBSCRIPTION] = null;
 RIL[REQUEST_CDMA_WRITE_SMS_TO_RUIM] = null;
 RIL[REQUEST_CDMA_DELETE_SMS_ON_RUIM] = null;
 RIL[REQUEST_DEVICE_IDENTITY] = null;
 RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = null;
-RIL[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS() {
+RIL[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS(length, options) {
   let smsc = Buf.readString();
-  Phone.onGetSMSCAddress(smsc);
+  Phone.onGetSMSCAddress(smsc, options);
 };
 RIL[REQUEST_SET_SMSC_ADDRESS] = function REQUEST_SET_SMSC_ADDRESS() {
   Phone.onSetSMSCAddress();
 };
 RIL[REQUEST_REPORT_SMS_MEMORY_STATUS] = null;
 RIL[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null;
 RIL[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED() {
   let newState = Buf.readUint32();
@@ -1772,18 +1775,27 @@ let Phone = {
   },
 
   onStartTone: function onStartTone() {
   },
 
   onStopTone: function onStopTone() {
   },
 
-  onGetSMSCAddress: function onGetSMSCAddress(smsc) {
+  onGetSMSCAddress: function onGetSMSCAddress(smsc, options) {
+    //TODO: notify main thread if we fail retrieving the SMSC, especially
+    // if there was a pending SMS (bug 727319).
     this.SMSC = smsc;
+    // If the SMSC was not retrieved on RIL initialization, an attempt to
+    // get it is triggered from this.sendSMS followed by the 'options'
+    // parameter of the SMS, so that we can send it after successfully
+    // retrieving the SMSC.
+    if (smsc && options.body) {
+      this.sendSMS(options);
+    }
   },
 
   onSetSMSCAddress: function onSetSMSCAddress() {
   },
 
   onSendSMS: function onSendSMS(options) {
     options.type = "sms-sent";
     this.sendDOMMessage(options);
@@ -2048,34 +2060,30 @@ let Phone = {
    * @param requestId
    *        String identifying the sms request used by the SmsRequestManager.
    * @param processId
    *        String containing the processId for the SmsRequestManager.
    */
   sendSMS: function sendSMS(options) {
     // Get the SMS Center address
     if (!this.SMSC) {
-      //TODO: we shouldn't get here, but if we do, we might want to hold on
-      // to the message and retry once we know the SMSC... or just notify an
-      // error to the mainthread and let them deal with retrying?
-      if (DEBUG) {
-        debug("Cannot send the SMS. Need to get the SMSC address first.");
-      }
+      // We request the SMS center address again, passing it the SMS options
+      // in order to try to send it again after retrieving the SMSC number.
+      RIL.getSMSCAddress(options);
       return;
     }
     // We explicitly save this information on the options object so that we
     // can refer to it later, in particular on the main thread (where this
     // object may get sent eventually.)
     options.SMSC = this.SMSC;
 
     //TODO: verify values on 'options'
     //TODO: the data encoding and length in octets should eventually be
     // computed on the mainthread and passed down to us.
-    options.dcs = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
-    options.bodyLengthInOctets = Math.ceil(options.body.length * 7 / 8);
+    GsmPDUHelper.calculateUserDataLength(options);
     RIL.sendSMS(options);
   },
 
   /**
    * Setup a data call (PDP).
    */
   setupDataCall: function setupDataCall(options) {
     if (DEBUG) debug("setupDataCall: " + JSON.stringify(options));
@@ -2336,40 +2344,85 @@ let GsmPDUHelper = {
       this.writeHexOctet(left | right);
       right = (septet & right_mask) >> shift;
     }
   },
 
   /**
    * Read user data and decode as a UCS2 string.
    *
-   * @param length
-   *        XXX TODO
+   * @param numOctets
+   *        num of octets to read as UCS2 string.
    *
    * @return a string.
    */
-  readUCS2String: function readUCS2String(length) {
-    //TODO bug 712804
+  readUCS2String: function readUCS2String(numOctets) {
+    let str = "";
+    let length = numOctets / 2;
+    for (let i = 0; i < length; ++i) {
+      let code = (this.readHexOctet() << 8) | this.readHexOctet();
+      str += String.fromCharCode(code);
+    }
+
+    if (DEBUG) debug("Read UCS2 string: " + str);
+
+    return str;
   },
 
   /**
    * Write user data as a UCS2 string.
    *
    * @param message
    *        Message string to encode as UCS2 in hex-encoded octets.
    */
   writeUCS2String: function writeUCS2String(message) {
-    //TODO bug 712804
+    for (let i = 0; i < message.length; ++i) {
+      let code = message.charCodeAt(i);
+      this.writeHexOctet((code >> 8) & 0xFF);
+      this.writeHexOctet(code & 0xFF);
+    }
+  },
+
+  /**
+   * Calculate user data length and its encoding.
+   *
+   * The `options` parameter object should contain the `body` attribute, and
+   * the `dcs`, `bodyLengthInOctets` attributes will be set as return:
+   *
+   * @param body
+   *        String containing the message body.
+   * @param dcs
+   *        Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
+   *        constants.
+   * @param bodyLengthInOctets
+   *        Byte length of the message body when encoded with the given DCS.
+   */
+  calculateUserDataLength: function calculateUserDataLength(options) {
+    //TODO: support language tables, see bug 729876
+    //TODO: support multipart SMS, see bug 712933
+    let needUCS2 = false;
+    for (let i = 0; i < options.body.length; ++i) {
+      if (options.body.charCodeAt(i) >= 128) {
+        needUCS2 = true;
+        break;
+      }
+    }
+
+    if (needUCS2) {
+      options.dcs = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
+      options.bodyLengthInOctets = options.body.length * 2;
+    } else {
+      options.dcs = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
+      options.bodyLengthInOctets = Math.ceil(options.body.length * 7 / 8);
+    }
   },
 
   /**
    * User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit
    * (UCS2) data.
-   *
-   * TODO: This function currently supports only the default alphabet.
    */
   readUserData: function readUserData(length, codingScheme) {
     if (DEBUG) {
       debug("Reading " + length + " bytes of user data.");
       debug("Coding scheme: " + codingScheme);
     }
     // 7 bit is the default fallback encoding.
     let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
--- a/dom/wifi/nsWifiWorker.js
+++ b/dom/wifi/nsWifiWorker.js
@@ -478,45 +478,47 @@ var WifiManager = (function() {
     var handler = manager["on" + eventName];
     if (handler) {
       if (!eventObject)
         eventObject = ({});
       handler.call(eventObject);
     }
   }
 
-  function parseStatus(status) {
+  function notifyStateChange(fields) {
+    fields.prevState = manager.state;
+    manager.state = fields.state;
+    notify("statechange", fields);
+  }
+
+  function parseStatus(status, reconnected) {
     if (status === null) {
       debug("Unable to get wpa supplicant's status");
       return;
     }
 
     var lines = status.split("\n");
     for (let i = 0; i < lines.length; ++i) {
       let [key, value] = lines[i].split("=");
       if (key === "wpa_state") {
-        notify("statechange", { state: value });
+        notifyStateChange({ state: value });
         if (value === "COMPLETED")
-          onconnected();
+          onconnected(reconnected);
       }
     }
   }
 
   // try to connect to the supplicant
   var connectTries = 0;
   var retryTimer = null;
   function connectCallback(ok) {
     if (ok === 0) {
       // Tell the event worker to start waiting for events.
       retryTimer = null;
-      waitForEvent();
-      notify("supplicantconnection");
-
-      // Load up the supplicant state.
-      statusCommand(parseStatus);
+      didConnectSupplicant(false, function(){});
       return;
     }
     if (connectTries++ < 3) {
       // try again in 5 seconds
       if (!retryTimer)
         retryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
       retryTimer.initWithCallback(function(timer) {
@@ -525,20 +527,24 @@ var WifiManager = (function() {
       return;
     }
 
     retryTimer = null;
     notify("supplicantlost");
   }
 
   manager.start = function() {
-    connectToSupplicant(connectCallback);
+    // If we reconnected to an already-running supplicant, then manager.state
+    // will have already been updated to the supplicant's state. Otherwise, we
+    // started the supplicant ourselves and need to connect.
+    if (manager.state === "UNINITIALIZED")
+      connectToSupplicant(connectCallback);
   }
 
-  function onconnected() {
+  function dhcpAfterConnect() {
     runDhcp(manager.ifname, function (data) {
       if (!data) {
         debug("DHCP failed to run");
         return;
       }
       setProperty("net.dns1", ipToString(data.dns1), function(ok) {
         if (!ok) {
           debug("Unable to set net.dns1");
@@ -559,16 +565,40 @@ var WifiManager = (function() {
                 debug("Unable to set net.dnschange");
             });
           });
         });
       });
     });
   }
 
+  function onconnected(reconnected) {
+    if (!reconnected) {
+      dhcpAfterConnect();
+      return;
+    }
+
+    // We're in the process of reconnecting to a pre-existing wpa_supplicant.
+    // Check to see if there was already a DHCP process:
+    getProperty("init.svc.dhcpcd_" + manager.ifname, "stopped", function(value) {
+      if (value === "running") {
+        return;
+      }
+
+      // Some phones use a different property name for the dhcpcd daemon.
+      getProperty("init.svc.dhcpcd", "stopped", function(value) {
+        if (value === "running") {
+          return;
+        }
+
+        dhcpAfterConnect();
+      });
+    });
+  }
+
   var supplicantStatesMap = ["DISCONNECTED", "INACTIVE", "SCANNING", "ASSOCIATING",
                              "ASSOCIATED", "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE",
                              "COMPLETED", "DORMANT", "UNINITIALIZED"];
   var driverEventMap = { STOPPED: "driverstopped", STARTED: "driverstarted", HANGED: "driverhung" };
 
   // handle events sent to us by the event worker
   function handleEvent(event) {
     debug("Event coming in: " + event);
@@ -590,17 +620,17 @@ var WifiManager = (function() {
       for (var n = 0; n < tokens.length; ++n) {
         var kv = tokens[n].split("=");
         if (kv.length === 2)
           fields[kv[0]] = kv[1];
       }
       if (!("state" in fields))
         return true;
       fields.state = supplicantStatesMap[fields.state];
-      notify("statechange", fields);
+      notifyStateChange(fields);
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-DRIVER-STATE") === 0) {
       var handlerName = driverEventMap[eventData];
       if (handlerName)
         notify(handlerName);
       return true;
     }
@@ -615,74 +645,113 @@ var WifiManager = (function() {
       // will keep going for a bit longer
       if (eventData.indexOf("recv error") !== -1 && ++recvErrors < 10)
         return true;
 
       notify("supplicantlost");
       return false;
     }
     if (eventData.indexOf("CTRL-EVENT-DISCONNECTED") === 0) {
-      notify("statechange", { state: "DISCONNECTED" });
+      notifyStateChange({ state: "DISCONNECTED" });
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-CONNECTED") === 0) {
       // Format: CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]
       var bssid = eventData.split(" ")[4];
       var id = eventData.substr(eventData.indexOf("id=")).split(" ")[0];
-      notify("statechange", { state: "CONNECTED", BSSID: bssid, id: id });
-      onconnected();
+      notifyStateChange({ state: "CONNECTED", BSSID: bssid, id: id });
+      onconnected(false);
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) {
       debug("Notifying of scan results available");
       notify("scanresultsavailable");
       return true;
     }
     // unknown event
     return true;
   }
 
+  const SUPP_PROP = "init.svc.wpa_supplicant";
   function killSupplicant(callback) {
     // It is interesting to note that this function does exactly what
     // wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung
     // changed that function in a way that means that it doesn't recognize
     // wpa_supplicant as already running. Therefore, we have to roll our own
     // version here.
     var count = 0;
     var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     function tick() {
-      getProperty("init.svc.wpa_supplicant", "stopped", function (result) {
+      getProperty(SUPP_PROP, "stopped", function (result) {
         if (result === null) {
-          callback(false);
+          callback();
           return;
         }
         if (result === "stopped" || ++count >= 5) {
           // Either we succeeded or ran out of time.
           timer = null;
-          callback(count < 5);
+          callback();
           return;
         }
 
         // Else it's still running, continue waiting.
         timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
       });
     }
 
     setProperty("ctl.stop", "wpa_supplicant", tick);
   }
 
+  function didConnectSupplicant(reconnected, callback) {
+    waitForEvent();
+    notify("supplicantconnection");
+
+    // Load up the supplicant state.
+    statusCommand(function(status) {
+      parseStatus(status, reconnected);
+      callback();
+    });
+  }
+
   function prepareForStartup(callback) {
-    stopDhcp(manager.ifname, function() {
-      // Ignore any errors.
-      killSupplicant(callback);
+    // First, check to see if there's a wpa_supplicant running that we can
+    // connect to.
+    getProperty(SUPP_PROP, "stopped", function (value) {
+      debug(SUPP_PROP + " was " + value);
+      if (value !== "running") {
+        stopDhcp(manager.ifname, function() { callback(false) });
+        return;
+      }
+
+      debug(SUPP_PROP + " was running, trying to connect");
+      // It's running, try to reconnect to it.
+      connectToSupplicant(function (retval) {
+        if (retval === 0) {
+          // Successfully reconnected! Don't do anything else.
+          debug("Successfully connected!");
+
+          // It is important that we call parseStatus (in
+          // didConnectSupplicant) before calling the callback here.
+          // Otherwise, WifiManager.start will reconnect to it.
+          didConnectSupplicant(true, function() { callback(true) });
+          return;
+        }
+
+        debug("Didn't connect, trying other method.");
+        stopDhcp(manager.ifname, function() {
+          // Ignore any errors.
+          killSupplicant(function() { callback(false); });
+        });
+      });
     });
   }
 
   // Initial state
   var airplaneMode = false;
+  manager.state = "UNINITIALIZED";
 
   // Public interface of the wifi service
   manager.setWifiEnabled = function(enable, callback) {
     var targetState = enable ? "ENABLED" : "DISABLED";
     if (enable == targetState)
       return true;
     if (enable && airplaneMode)
       return false;
@@ -690,18 +759,22 @@ var WifiManager = (function() {
       // Kill any existing connections if necessary.
       getProperty("wifi.interface", "tiwlan0", function (ifname) {
         if (!ifname) {
           callback(-1);
           return;
         }
         manager.ifname = ifname;
 
-        prepareForStartup(function() {
-          // Ignore errors...
+        prepareForStartup(function(already_connected) {
+          if (already_connected) {
+            callback(0);
+            return;
+          }
+
           loadDriver(function (status) {
             if (status < 0) {
               callback(status);
               return;
             }
             startSupplicant(function (status) {
               if (status < 0) {
                 callback(status);
@@ -850,32 +923,27 @@ function WifiNetwork(ssid, bssid, flags,
 WifiNetwork.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.nsIWifiNetwork]);
 
 function nsWifiWorker() {
   WifiManager.onsupplicantconnection = function() {
     debug("Connected to supplicant");
     WifiManager.getMacAddress(function (mac) {
       debug("Got mac: " + mac);
     });
+    connectToMozilla();
   }
   WifiManager.onsupplicantlost = function() {
     debug("Couldn't connect to supplicant");
   }
 
   var self = this;
 
-  this.state = null;
   this.networks = Object.create(null);
   WifiManager.onstatechange = function() {
-    debug("State change: " + self.state + " -> " + this.state);
-    self.state = this.state;
-
-    // TODO Worth adding a more generic API for this?
-    if (self.state === "INACTIVE")
-      connectToMozilla();
+    debug("State change: " + this.prevState + " -> " + this.state);
   }
 
   function connectToMozilla() {
     // We're not trying to connect so try to find an open Mozilla network.
     // TODO Don't do this for pre-existing networks.
     // TODO Remove me in favor of UI and a way to select a network.
 
     debug("Haven't connected to a network, trying a default (for now)");
--- a/editor/idl/nsIEditor.idl
+++ b/editor/idl/nsIEditor.idl
@@ -50,17 +50,17 @@ interface nsIDocumentStateListener;
 interface nsIOutputStream;
 interface nsITransactionManager;
 interface nsITransaction;
 interface nsIEditorObserver;
 interface nsIEditActionListener;
 interface nsIInlineSpellChecker;
 interface nsITransferable;
 
-[scriptable, uuid(94479B76-7FD7-47D3-BB1E-5B77846339D2)]
+[scriptable, uuid(656005d2-d900-4839-81bf-6274a3c38537)]
 
 interface nsIEditor  : nsISupports
 {
 %{C++
   typedef short EDirection;
 %}
   const short eNone = 0;
   const short eNext = 1;
@@ -200,16 +200,26 @@ interface nsIEditor  : nsISupports
     *                 if PR_FALSE the undo system is turned off if it
     *                 was previously on
     * @return         if aEnable is PR_TRUE, returns NS_OK if
     *                 the undo system could be initialized properly
     *                 if aEnable is PR_FALSE, returns NS_OK.
     */
   void enableUndo(in boolean enable);
 
+  /**
+   * The number of items on the undo stack.
+   */
+  readonly attribute long numberOfUndoItems;
+
+  /**
+   * The number of items on the redo stack.
+   */
+  readonly attribute long numberOfRedoItems;
+
   /** undo reverses the effects of the last Do operation,
     * if Undo is enabled in the editor.
     * It is provided here so clients need no knowledge of whether
     * the editor has a transaction manager or not.
     * If a transaction manager is present, it is told to undo,
     * and the result of that undo is returned.  
     * Otherwise, the Undo request is ignored and an
     * error NS_ERROR_NOT_AVAILABLE is returned.
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -745,16 +745,29 @@ nsEditor::EnableUndo(bool aEnable)
       mTxnMgr->Clear();
       mTxnMgr->SetMaxTransactionCount(0);
     }
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsEditor::GetNumberOfUndoItems(PRInt32* aNumItems)
+{
+  *aNumItems = 0;
+  return mTxnMgr ? mTxnMgr->GetNumberOfUndoItems(aNumItems) : NS_OK;
+}
+
+NS_IMETHODIMP
+nsEditor::GetNumberOfRedoItems(PRInt32* aNumItems)
+{
+  *aNumItems = 0;
+  return mTxnMgr ? mTxnMgr->GetNumberOfRedoItems(aNumItems) : NS_OK;
+}
 
 NS_IMETHODIMP
 nsEditor::GetTransactionManager(nsITransactionManager* *aTxnManager)
 {
   NS_ENSURE_ARG_POINTER(aTxnManager);
   
   *aTxnManager = NULL;
   NS_ENSURE_TRUE(mTxnMgr, NS_ERROR_FAILURE);
--- a/gfx/angle/README.mozilla
+++ b/gfx/angle/README.mozilla
@@ -4,16 +4,17 @@ Current revision: r963
 
 == Applied local patches ==
 
 In this order:
   angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
   angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
   angle-limit-identifiers-to-250-chars.patch - see bug 675625
   angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
+  angle-castrate-bug-241.patch - see bug 699033 / angle bug 241
 
 In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
 
 == How to update this ANGLE copy ==
 
 1. Unapply patches
 2. Apply diff with new ANGLE version
 3. Reapply patches.
new file mode 100644
--- /dev/null
+++ b/gfx/angle/angle-castrate-bug-241.patch
@@ -0,0 +1,47 @@
+# HG changeset patch
+# User Benoit Jacob <bjacob@mozilla.com>
+# Parent 7dcbce54a953090ae8e537f93c6c99ab8eb0dc62
+
+diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla
+--- a/gfx/angle/README.mozilla
++++ b/gfx/angle/README.mozilla
+@@ -4,16 +4,17 @@ Current revision: r963
+ 
+ == Applied local patches ==
+ 
+ In this order:
+   angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
+   angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
+   angle-limit-identifiers-to-250-chars.patch - see bug 675625
+   angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
++  angle-castrate-bug-241.patch - see bug 699033 / angle bug 241
+ 
+ In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
+ 
+ == How to update this ANGLE copy ==
+ 
+ 1. Unapply patches
+ 2. Apply diff with new ANGLE version
+ 3. Reapply patches.
+diff --git a/gfx/angle/src/compiler/Types.h b/gfx/angle/src/compiler/Types.h
+--- a/gfx/angle/src/compiler/Types.h
++++ b/gfx/angle/src/compiler/Types.h
+@@ -203,17 +203,17 @@ public:
+     bool isVector() const { return size > 1 && !matrix; }
+     bool isScalar() const { return size == 1 && !matrix && !structure; }
+ 
+     TTypeList* getStruct() const { return structure; }
+     void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); }
+ 
+     const TString& getTypeName() const
+     {
+-        assert(typeName);
++        if(!typeName) abort();
+         return *typeName;
+     }
+     void setTypeName(const TString& n)
+     {
+         typeName = NewPoolTString(n.c_str());
+     }
+ 
+     bool isField() const { return fieldName != 0; }
--- a/gfx/angle/src/compiler/Types.h
+++ b/gfx/angle/src/compiler/Types.h
@@ -203,17 +203,17 @@ public:
     bool isVector() const { return size > 1 && !matrix; }
     bool isScalar() const { return size == 1 && !matrix && !structure; }
 
     TTypeList* getStruct() const { return structure; }
     void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); }
 
     const TString& getTypeName() const
     {
-        assert(typeName);
+        if(!typeName) abort();
         return *typeName;
     }
     void setTypeName(const TString& n)
     {
         typeName = NewPoolTString(n.c_str());
     }
 
     bool isField() const { return fieldName != 0; }
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -407,16 +407,17 @@ SetScreenBrightness(double brightness)
   uint32_t color = (0xff<<24) + (val<<16) + (val<<8) + val;
 
   hal::LightConfiguration aConfig;
   aConfig.mode() = hal::eHalLightMode_User;
   aConfig.flash() = hal::eHalLightFlash_None;
   aConfig.flashOnMS() = aConfig.flashOffMS() = 0;
   aConfig.color() = color;
   hal::SetLight(hal::eHalLightID_Backlight, aConfig);
+  hal::SetLight(hal::eHalLightID_Buttons, aConfig);
 }
 
 static light_device_t* sLights[hal::eHalLightID_Count];	// will be initialized to NULL
 
 light_device_t* GetDevice(hw_module_t* module, char const* name)
 {
   int err;
   hw_device_t* device;
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1755,16 +1755,20 @@ main(int argc, char **argv, char **envp)
     nsresult rv;
 
 #ifdef HAVE_SETBUF
     // unbuffer stdout so that output is in the correct order; note that stderr
     // is unbuffered by default
     setbuf(stdout, 0);
 #endif
 
+#ifdef XRE_HAS_DLL_BLOCKLIST
+    XRE_SetupDllBlocklist();
+#endif
+
     gErrFile = stderr;
     gOutFile = stdout;
     gInFile = stdin;
 
     NS_LogInit();
 
     nsCOMPtr<nsILocalFile> appFile;
     rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile));
--- a/toolkit/xre/nsWindowsDllBlocklist.cpp
+++ b/toolkit/xre/nsWindowsDllBlocklist.cpp
@@ -45,16 +45,17 @@
 
 #ifdef XRE_WANT_DLL_BLOCKLIST
 #define XRE_SetupDllBlocklist SetupDllBlocklist
 #else
 #include "nsXULAppAPI.h"
 #endif
 
 #include "nsAutoPtr.h"
+#include "nsThreadUtils.h"
 
 #include "prlog.h"
 
 #include "nsWindowsDllInterceptor.h"
 
 #if defined(MOZ_CRASHREPORTER) && !defined(NO_BLOCKLIST_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #endif
@@ -146,22 +147,86 @@ static DllBlockInfo sWindowsDllBlocklist
 
 #ifndef STATUS_DLL_NOT_FOUND
 #define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
 #endif
 
 // define this for very verbose dll load debug spew
 #undef DEBUG_very_verbose
 
+extern bool gInXPCOMLoadOnMainThread;
+
 namespace {
 
 typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle);
 
 static LdrLoadDll_func stub_LdrLoadDll = 0;
 
+template <class T>
+struct RVAMap {
+  RVAMap(HANDLE map, DWORD offset) {
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+
+    DWORD alignedOffset = (offset / info.dwAllocationGranularity) *
+                          info.dwAllocationGranularity;
+
+    NS_ASSERTION(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
+
+    mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset,
+                                sizeof(T) + (offset - alignedOffset));
+
+    mMappedView = reinterpret_cast<T*>((char*)mRealView + (offset - alignedOffset));
+  }
+  ~RVAMap() {
+    if (mRealView) {
+      ::UnmapViewOfFile(mRealView);
+    }
+  }
+  operator const T*() const { return mMappedView; }
+  const T* operator->() const { return mMappedView; }
+private:
+  const T* mMappedView;
+  void* mRealView;
+};
+
+bool
+CheckASLR(const wchar_t* path)
+{
+  bool retval = false;
+
+  HANDLE file = ::CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
+                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+                              NULL);
+  if (file != INVALID_HANDLE_VALUE) {
+    HANDLE map = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
+    if (map) {
+      RVAMap<IMAGE_DOS_HEADER> peHeader(map, 0);
+      if (peHeader) {
+        RVAMap<IMAGE_NT_HEADERS> ntHeader(map, peHeader->e_lfanew);
+        if (ntHeader) {
+          // If the DLL has no code, permit it regardless of ASLR status.
+          if (ntHeader->OptionalHeader.SizeOfCode == 0) {
+            retval = true;
+          }
+          // Check to see if the DLL supports ASLR
+          else if ((ntHeader->OptionalHeader.DllCharacteristics &
+                    IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0) {
+            retval = true;
+          }
+        }
+      }
+      ::CloseHandle(map);
+    }
+    ::CloseHandle(file);
+  }
+
+  return retval;
+}
+
 /**
  * Some versions of Windows call LoadLibraryEx to get the version information
  * for a DLL, which causes our patched LdrLoadDll implementation to re-enter
  * itself and cause infinite recursion and a stack-exhaustion crash. We protect
  * against reentrancy by allowing recursive loads of the same DLL.
  *
  * Note that we don't use __declspec(thread) because that doesn't work in DLLs
  * loaded via LoadLibrary and there can be a limited number of TLS slots, so
@@ -220,16 +285,39 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
 #define DLLNAME_MAX 128
   char dllName[DLLNAME_MAX+1];
   wchar_t *dll_part;
   DllBlockInfo *info;
 
   int len = moduleFileName->Length / 2;
   wchar_t *fname = moduleFileName->Buffer;
 
+  // In Windows 8, the first parameter seems to be used for more than just the
+  // path name.  For example, its numerical value can be 1.  Passing a non-valid
+  // pointer to SearchPathW will cause a crash, so we need to check to see if we
+  // are handed a valid pointer, and otherwise just pass NULL to SearchPathW.
+  PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? NULL : filePath;
+
+  // figure out the length of the string that we need
+  DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, NULL, NULL);
+  if (pathlen == 0) {
+    // uh, we couldn't find the DLL at all, so...
+    printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
+    return STATUS_DLL_NOT_FOUND;
+  }
+
+  nsAutoArrayPtr<wchar_t> full_fname(new wchar_t[pathlen+1]);
+  if (!full_fname) {
+    // couldn't allocate memory?
+    return STATUS_DLL_NOT_FOUND;
+  }
+
+  // now actually grab it
+  SearchPathW(sanitizedFilePath, fname, L".dll", pathlen+1, full_fname, NULL);
+
   // The filename isn't guaranteed to be null terminated, but in practice
   // it always will be; ensure that this is so, and bail if not.
   // This is done instead of the more robust approach because of bug 527122,
   // where lots of weird things were happening when we tried to make a copy.
   if (moduleFileName->MaximumLength < moduleFileName->Length+2 ||
       fname[len] != 0)
   {
 #ifdef DEBUG
@@ -300,39 +388,16 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
 #endif
 
     if (info->maxVersion != ALL_VERSIONS) {
       ReentrancySentinel sentinel(dllName);
       if (sentinel.BailOut()) {
         goto continue_loading;
       }
 
-      // In Windows 8, the first parameter seems to be used for more than just the
-      // path name.  For example, its numerical value can be 1.  Passing a non-valid
-      // pointer to SearchPathW will cause a crash, so we need to check to see if we
-      // are handed a valid pointer, and otherwise just pass NULL to SearchPathW.
-      PWCHAR sanitizedFilePath = (intptr_t(filePath) < 1024) ? NULL : filePath;
-
-      // figure out the length of the string that we need
-      DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, NULL, NULL);
-      if (pathlen == 0) {
-        // uh, we couldn't find the DLL at all, so...
-        printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
-        return STATUS_DLL_NOT_FOUND;
-      }
-
-      wchar_t *full_fname = (wchar_t*) malloc(sizeof(wchar_t)*(pathlen+1));
-      if (!full_fname) {
-        // couldn't allocate memory?
-        return STATUS_DLL_NOT_FOUND;
-      }
-
-      // now actually grab it
-      SearchPathW(sanitizedFilePath, fname, L".dll", pathlen+1, full_fname, NULL);
-
       DWORD zero;
       DWORD infoSize = GetFileVersionInfoSizeW(full_fname, &zero);
 
       // If we failed to get the version information, we block.
 
       if (infoSize != 0) {
         nsAutoArrayPtr<unsigned char> infoData(new unsigned char[infoSize]);
         VS_FIXEDFILEINFO *vInfo;
@@ -346,33 +411,39 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
             ((unsigned long long)vInfo->dwFileVersionLS);
 
           // finally do the version check, and if it's greater than our block
           // version, keep loading
           if (fVersion > info->maxVersion)
             load_ok = true;
         }
       }
-
-      free(full_fname);
     }
 
     if (!load_ok) {
       printf_stderr("LdrLoadDll: Blocking load of '%s' -- see http://www.mozilla.com/en-US/blocklist/\n", dllName);
       return STATUS_DLL_NOT_FOUND;
     }
   }
 
 continue_loading:
 #ifdef DEBUG_very_verbose
   printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
 #endif
 
   NS_SetHasLoadedNewDLLs();
 
+  if (gInXPCOMLoadOnMainThread && NS_IsMainThread()) {
+    // Check to ensure that the DLL has ASLR.
+    if (!CheckASLR(full_fname)) {
+      printf_stderr("LdrLoadDll: Blocking load of '%s'.  XPCOM components must support ASLR.\n", dllName);
+      return STATUS_DLL_NOT_FOUND;
+    }
+  }
+
   return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
 }
 
 WindowsDllInterceptor NtDllIntercept;
 
 } // anonymous namespace
 
 void
--- a/xpcom/components/nsNativeComponentLoader.cpp
+++ b/xpcom/components/nsNativeComponentLoader.cpp
@@ -82,16 +82,18 @@
 #define IMPLEMENT_BREAK_AFTER_LOAD
 #endif
 
 using namespace mozilla;
 
 static PRLogModuleInfo *nsNativeModuleLoaderLog =
     PR_NewLogModule("nsNativeModuleLoader");
 
+bool gInXPCOMLoadOnMainThread = false;
+
 #define LOG(level, args) PR_LOG(nsNativeModuleLoaderLog, level, args)
 
 NS_IMPL_QUERY_INTERFACE1(nsNativeModuleLoader, 
                          mozilla::ModuleLoader)
 
 NS_IMPL_ADDREF_USING_AGGREGATOR(nsNativeModuleLoader,
                                 nsComponentManagerImpl::gComponentManager)
 NS_IMPL_RELEASE_USING_AGGREGATOR(nsNativeModuleLoader,
@@ -162,17 +164,19 @@ nsNativeModuleLoader::LoadModule(FileLoc
         LOG(PR_LOG_DEBUG,
             ("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache",
              filePath.get()));
         return data.module;
     }
 
     // We haven't loaded this module before
 
+    gInXPCOMLoadOnMainThread = true;
     rv = file->Load(&data.library);
+    gInXPCOMLoadOnMainThread = false;
 
     if (NS_FAILED(rv)) {
         char errorMsg[1024] = "<unknown; can't get error from NSPR>";
 
         if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
             PR_GetErrorText(errorMsg);
 
         LogMessage("Failed to load native module at path '%s': (%lx) %s",
--- a/xpcom/tests/Makefile.in
+++ b/xpcom/tests/Makefile.in
@@ -40,17 +40,22 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir = xpcom/tests
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xpcom
 
-DIRS		= external component bug656331_component
+DIRS		= \
+  external \
+  component \
+  bug656331_component \
+  component_no_aslr \
+  $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 DIRS		+= windows
 endif
 
 ifdef DEHYDRA_PATH
 DIRS += static-checker
 endif
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/component_no_aslr/Makefile.in
@@ -0,0 +1,81 @@
+#
+# ***** 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
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Benjamin Smedberg <benjamin@smedbergs.us>
+#
+# 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 *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME	= testcompnoaslr
+IS_COMPONENT	= 1
+CPPSRCS	= TestComponent.cpp
+NO_DIST_INSTALL = 1
+FORCE_SHARED_LIB = 1
+
+include $(topsrcdir)/config/config.mk
+
+MANIFEST_FILE = testcompnoaslr.manifest
+
+EXTRA_DSO_LDOPTS = \
+		$(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
+		$(XPCOM_FROZEN_LDOPTS) \
+		$(NSPR_LIBS) \
+		$(NULL)
+
+# Need to link with CoreFoundation on Mac
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+EXTRA_DSO_LDOPTS += \
+		$(TK_LIBS) \
+		$(NULL)
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+LDFLAGS := $(filter-out -DYNAMICBASE,$(LDFLAGS)) -DYNAMICBASE:NO
+
+DEFINES += -DLIBRARY_FILENAME="$(SHARED_LIBRARY)"
+
+unittestlocation = xpcom/tests/unit
+
+libs:: $(SHARED_LIBRARY)
+	$(INSTALL) $^ $(testxpcobjdir)/$(unittestlocation)
+
+libs:: $(MANIFEST_FILE)
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $< > $(testxpcobjdir)/$(unittestlocation)/$(<F)
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/component_no_aslr/TestComponent.cpp
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 8; 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
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Suresh Duddu <dp@netscape.com>
+ *
+ * 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 "mozilla/ModuleUtils.h"
+
+#define NS_TESTING_CID \
+{ 0x335fb596, 0xe52d, 0x418f, \
+  { 0xb0, 0x1c, 0x1b, 0xf1, 0x6c, 0xe5, 0xe7, 0xe4 } }
+
+NS_DEFINE_NAMED_CID(NS_TESTING_CID);
+
+static nsresult
+DummyConstructorFunc(nsISupports* aOuter, const nsIID& aIID, void** aResult)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+static const mozilla::Module::CIDEntry kTestCIDs[] = {
+  { &kNS_TESTING_CID, false, NULL, DummyConstructorFunc },
+  { NULL }
+};
+
+static const mozilla::Module kTestModule = {
+  mozilla::Module::kVersion,
+  kTestCIDs
+};
+
+NSMODULE_DEFN(dummy) = &kTestModule;
+
+  
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/component_no_aslr/testcompnoaslr.manifest
@@ -0,0 +1,2 @@
+#filter substitution
+binary-component @LIBRARY_FILENAME@
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/unit/test_comp_no_aslr.js
@@ -0,0 +1,10 @@
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function run_test() {
+  let manifest = do_get_file('testcompnoaslr.manifest');
+  Components.manager.autoRegister(manifest);
+  do_check_false("{335fb596-e52d-418f-b01c-1bf16ce5e7e4}" in Components.classesByID);
+}
--- a/xpcom/tests/unit/xpcshell.ini
+++ b/xpcom/tests/unit/xpcshell.ini
@@ -37,8 +37,10 @@ skip-if = os == "win" # See bug: 676412
 [test_stringstream.js]
 [test_symlinks.js]
 # Bug 676998: test fails consistently on Android
 fail-if = os == "android"
 [test_systemInfo.js]
 # Bug 676998: test fails consistently on Android
 fail-if = os == "android"
 [test_versioncomparator.js]
+[test_comp_no_aslr.js]
+fail-if = os != "win"