Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Sun, 26 Feb 2012 22:42:25 -0800
changeset 88460 ab7d7c53d6182b5099303d5eb16eb88032814ae7
parent 88459 c5c097be263023c8a4b21e29964db2d46c383491 (current diff)
parent 87963 2a18bd58aae2df507fe52a1bd18811a8d7796eec (diff)
child 88461 54f2d811e79aea6fa09777e0e8e3a42f7d50552f
push id157
push userMs2ger@gmail.com
push dateWed, 07 Mar 2012 19:27:10 +0000
milestone13.0a1
Merge m-c to s-c.
browser/themes/pinstripe/livemark-item.png
browser/themes/winstripe/livemark-item-aero.png
browser/themes/winstripe/livemark-item.png
gfx/thebes/genUnicodeScriptData.pl
gfx/thebes/gfxUnicodeProperties.cpp
gfx/thebes/gfxUnicodeProperties.h
gfx/thebes/gfxUnicodePropertyData.cpp
gfx/thebes/gfxUnicodeScriptCodes.h
intl/unicharutil/public/nsIUGenDetailCategory.h
intl/unicharutil/src/cattable.h
intl/unicharutil/tools/gencattable.pl
layout/reftests/transform-3d/scale3d-2-ref.html
mobile/android/base/GeckoDirProvider.java
mobile/android/base/resources/layout/gecko_menu.xml
toolkit/components/places/tests/autocomplete/test_livemarks.js
toolkit/components/places/tests/chrome/test_329534.xul
toolkit/components/places/tests/unit/test_exclude_livemarks.js
toolkit/components/places/tests/unit/test_livemarkService_getLivemarkIdForFeedURI.js
xpcom/ds/nsCheapSets.cpp
--- a/accessible/src/base/Statistics.h
+++ b/accessible/src/base/Statistics.h
@@ -55,31 +55,31 @@ namespace statistics {
 
   /**
    * Report that ISimpleDOM* has been used.
    */
   inline void ISimpleDOMUsed()
   {
     static bool firstTime = true;
     if (firstTime) {
-      Telemetry::Accumulate(Telemetry::ISIMPLE_DOM_USAGE, 1);
+      Telemetry::Accumulate(Telemetry::A11Y_ISIMPLEDOM_USAGE, 1);
       firstTime = false;
     }
   }
 
   /**
    * Report that IAccessibleTable has been used.
    */
   inline void IAccessibleTableUsed()
-    { Telemetry::Accumulate(Telemetry::IACCESSIBLE_TABLE_USAGE, 1); }
+    { Telemetry::Accumulate(Telemetry::A11Y_IATABLE_USAGE, 1); }
 
   /**
    * Report that XForms accessibility has been instantiated.
    */
   inline void XFormsAccessibleUsed()
-    { Telemetry::Accumulate(Telemetry::XFORMS_ACCESSIBLE_USED, 1); }
+    { Telemetry::Accumulate(Telemetry::A11Y_XFORMS_USAGE, 1); }
 
 } // namespace statistics
 } // namespace a11y
 } // namespace mozilla
 
 #endif
 
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -131,17 +131,17 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] 
     kNoReqStates,
     eARIASelectable,
     eARIAReadonly
   },
   {
     "combobox",
     roles::COMBOBOX,
     kUseMapRole,
-    eHasValueMinMax,
+    eNoValue,
     eOpenCloseAction,
     eNoLiveAttr,
     states::COLLAPSED | states::HASPOPUP,
     eARIAAutoComplete,
     eARIAReadonly
   },
   {
     "dialog",
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -848,16 +848,22 @@ nsAccessible::ChildAtPoint(PRInt32 aX, P
   nsIContent* content = nsnull;
   if (!foundFrame || !(content = foundFrame->GetContent()))
     return fallbackAnswer;
 
   // Get accessible for the node with the point or the first accessible in
   // the DOM parent chain.
   nsDocAccessible* contentDocAcc = GetAccService()->
     GetDocAccessible(content->OwnerDoc());
+
+  // contentDocAcc in some circumstances can be NULL. See bug 729861
+  NS_ASSERTION(contentDocAcc, "could not get the document accessible");
+  if (!contentDocAcc)
+    return fallbackAnswer;
+
   nsAccessible* accessible = contentDocAcc->GetAccessibleOrContainer(content);
   if (!accessible)
     return fallbackAnswer;
 
   if (accessible == this) {
     // Manually walk through accessible children and see if the are within this
     // point. Skip offscreen or invisible accessibles. This takes care of cases
     // where layout won't walk into things for us, such as image map areas and
--- a/accessible/src/msaa/Compatibility.cpp
+++ b/accessible/src/msaa/Compatibility.cpp
@@ -112,16 +112,26 @@ Compatibility::Init()
     statistics::A11yConsumers(SEROTEK);
 
   if (::GetModuleHandleW(L"nvdaHelperRemote"))
     statistics::A11yConsumers(NVDA);
 
   if (::GetModuleHandleW(L"OsmHooks"))
     statistics::A11yConsumers(COBRA);
 
+  if (::GetModuleHandleW(L"WebFinderRemote"))
+    statistics::A11yConsumers(ZOOMTEXT);
+
+  if (::GetModuleHandleW(L"Kazahook"))
+    statistics::A11yConsumers(KAZAGURU);
+
+  if (::GetModuleHandleW(L"TextExtractorImpl32") ||
+      ::GetModuleHandleW(L"TextExtractorImpl64"))
+    statistics::A11yConsumers(YOUDAO);
+
   // Turn off new tab switching for Jaws and WE.
   if (sMode & JAWSMode || sMode & WEMode) {
     // Check to see if the pref for disallowing CtrlTab is already set. If so,
     // bail out (respect the user settings). If not, set it.
     if (!Preferences::HasUserValue("browser.ctrlTab.disallowForScreenReaders"))
       Preferences::SetBool("browser.ctrlTab.disallowForScreenReaders", true);
   }
 }
--- a/accessible/src/msaa/Compatibility.h
+++ b/accessible/src/msaa/Compatibility.h
@@ -102,17 +102,20 @@ private:
    */
   enum {
     NVDA = 0,
     JAWS = 1,
     OLDJAWS = 2,
     WE = 3,
     DOLPHIN = 4,
     SEROTEK = 5,
-    COBRA = 6
+    COBRA = 6,
+    ZOOMTEXT = 7,
+    KAZAGURU = 8,
+    YOUDAO = 9
   };
 
 private:
   static PRUint32 sMode;
 };
 
 } // a11y namespace
 } // mozilla namespace
--- a/accessible/tests/mochitest/events/test_focus_general.html
+++ b/accessible/tests/mochitest/events/test_focus_general.html
@@ -101,20 +101,24 @@
         // other platforms requires setting a ui.key.menuAccessKeyFocuses
         // preference.
         gQueue.push(new toggleTopMenu(editableDoc, new topMenuChecker()));
         gQueue.push(new toggleTopMenu(editableDoc, new focusChecker(editableDoc)));
       }
       gQueue.push(new synthContextMenu(editableDoc, new contextMenuChecker()));
       gQueue.push(new synthDownKey(editableDoc, new focusContextMenuItemChecker()));
       gQueue.push(new synthEscapeKey(editableDoc, new focusChecker(editableDoc)));
+      if (SEAMONKEY) {
+        todo(false, "shift tab from editable document fails on (Windows) SeaMonkey! (Bug 718235)");
+      } else {
       if (LINUX)
-        todo(false, "shift tab from editable document Fails on linux!");
+        todo(false, "shift tab from editable document fails on linux!");
       else
         gQueue.push(new synthShiftTab("link", new focusChecker("link")));
+      } // ! SEAMONKEY
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -50,18 +50,19 @@ pref("dom.telephony.app.phone.url", "htt
 
 // Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
 pref("browser.viewport.scaleRatio", -1);
 
 /* disable text selection */
 pref("browser.ignoreNativeFrameTextSelection", true);
 
 /* cache prefs */
-pref("browser.cache.disk.enable", false);
-pref("browser.cache.disk.capacity", 0); // kilobytes
+pref("browser.cache.disk.enable", true);
+pref("browser.cache.disk.capacity", 55000); // kilobytes
+pref("browser.cache.disk.parent_directory", "/cache");
 pref("browser.cache.disk.smart_size.enabled", false);
 pref("browser.cache.disk.smart_size.first_run", false);
 
 pref("browser.cache.memory.enable", true);
 pref("browser.cache.memory.capacity", 1024); // kilobytes
 
 /* image cache prefs */
 pref("image.cache.size", 1048576); // bytes
@@ -101,16 +102,17 @@ pref("browser.sessionstore.resume_from_c
 pref("browser.sessionstore.interval", 10000); // milliseconds
 pref("browser.sessionstore.max_tabs_undo", 1);
 
 /* these should help performance */
 pref("mozilla.widget.force-24bpp", true);
 pref("mozilla.widget.use-buffer-pixmap", true);
 pref("mozilla.widget.disable-native-theme", true);
 pref("layout.reflow.synthMouseMove", false);
+pref("dom.send_after_paint_to_content", true);
 
 /* download manager (don't show the window or alert) */
 pref("browser.download.useDownloadDir", true);
 pref("browser.download.folderList", 1); // Default to ~/Downloads
 pref("browser.download.manager.showAlertOnComplete", false);
 pref("browser.download.manager.showAlertInterval", 2000);
 pref("browser.download.manager.retention", 2);
 pref("browser.download.manager.showWhenStarting", false);
@@ -384,16 +386,17 @@ pref("security.fileuri.strict_origin_pol
 // Temporarily force-enable GL compositing.  This is default-disabled
 // deep within the bowels of the widgetry system.  Remove me when GL
 // compositing isn't default disabled in widget/android.
 pref("layers.acceleration.force-enabled", true);
 
 // screen.enabled and screen.brightness properties.
 pref("dom.screenEnabledProperty.enabled", true);
 pref("dom.screenBrightnessProperty.enabled", true);
+pref("dom.mozScreenWhitelist", "http://localhost:7777");
 
 // handle links targeting new windows
 // 1=current window/tab, 2=new window, 3=new tab in most recent window
 pref("browser.link.open_newwindow", 3);
 
 // 0: no restrictions - divert everything
 // 1: don't divert window.open at all
 // 2: don't divert window.open with features
@@ -422,14 +425,18 @@ pref("media.realtime_decoder.enabled", t
 // secondary bug isn't really worth investigating since it's obseleted
 // by bug 710563.
 pref("layout.frame_rate.precise", true);
 
 // Temporary remote js console hack
 pref("b2g.remote-js.enabled", true);
 pref("b2g.remote-js.port", 9999);
 
+// Handle hardware buttons in the b2g chrome package
+pref("b2g.keys.menu.enabled", true);
+pref("b2g.keys.search.enabled", false);
+
 // Screen timeout in minutes
 pref("power.screen.timeout", 60);
 
 pref("full-screen-api.enabled", true);
 
 pref("media.volume.steps", 10);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -32,16 +32,33 @@ XPCOMUtils.defineLazyGetter(Services, 'i
            .getService(Ci.nsIIdleService);
 });
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function(){
   return Cc['@mozilla.org/focus-managr;1']
            .getService(Ci.nsFocusManager);
 });
 
+
+#ifndef MOZ_WIDGET_GONK
+// In order to use http:// scheme instead of file:// scheme
+// (that is much more restricted) the following code kick-off
+// a local http server listening on http://127.0.0.1:7777 and
+// http://localhost:7777.
+function startupHttpd(baseDir, port) {
+  const httpdURL = 'chrome://browser/content/httpd.js';
+  let httpd = {};
+  Services.scriptloader.loadSubScript(httpdURL, httpd);
+  let server = new httpd.nsHttpServer();
+  server.registerDirectory('/', new LocalFile(baseDir));
+  server.registerContentType('appcache', 'text/cache-manifest');
+  server.start(port);
+}
+#endif
+
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'content-camera'
   ];
@@ -100,17 +117,31 @@ var shell = {
     window.addEventListener('mozfullscreenchange', this);
     this.contentBrowser.addEventListener('load', this, true);
 
     try {
       Services.io.offline = false;
 
       let fileScheme = 'file://';
       if (homeURL.substring(0, fileScheme.length) == fileScheme) {
+#ifndef MOZ_WIDGET_GONK
+        homeURL = homeURL.replace(fileScheme, '');
+
+        let baseDir = homeURL.split('/');
+        baseDir.pop();
+        baseDir = baseDir.join('/');
+
+        const SERVER_PORT = 7777;
+        startupHttpd(baseDir, SERVER_PORT);
+
+        let baseHost = 'http://localhost';
+        homeURL = homeURL.replace(baseDir, baseHost + ':' + SERVER_PORT);
+#else
         homeURL = 'http://localhost:7777' + homeURL.replace(fileScheme, '');
+#endif
       }
       addPermissions([homeURL]);
     } catch (e) {
       let msg = 'Fatal error during startup: [' + e + '[' + homeURL + ']';
       return alert(msg);
     }
 
     // Load webapi.js as a frame script
@@ -208,20 +239,22 @@ var shell = {
               return;
             this.doCommand('cmd_close');
             break;
         }
         break;
       case 'AppCommand':
         switch (evt.command) {
           case 'Menu':
-            this.sendEvent(content, 'menu');
+            if (Services.prefs.getBoolPref('b2g.keys.menu.enabled'))
+              this.sendEvent(content, 'menu');
             break;
           case 'Search':
-            this.toggleDebug();
+            if (Services.prefs.getBoolPref('b2g.keys.search.enabled'))
+              this.toggleDebug();
             break;
           case 'VolumeUp':
             this.changeVolume(1);
             break;
           case 'VolumeDown':
             this.changeVolume(-1);
             break;
         }
--- a/b2g/chrome/content/shell.xul
+++ b/b2g/chrome/content/shell.xul
@@ -15,16 +15,23 @@
         onload="shell.start();"
         onunload="shell.stop();">
 
   <script type="application/javascript" src="chrome://browser/content/commandUtil.js"/>
   <script type="application/javascript" src="chrome://browser/content/shell.js"/>
 #ifndef MOZ_TOUCH
   <script type="application/javascript" src="chrome://browser/content/touch.js"/>
 #endif
+#ifndef MOZ_WIDGET_GONK
+  <script type="application/javascript" src="chrome://browser/content/httpd.js"/>
+#endif
 
   <commandset id="mainCommandSet">
     <command id="cmd_close" oncommand="CommandUpdater.doCommand(this.id);"/>
   </commandset>
 
-  <browser id="homescreen" type="content-primary" flex="1" style="overflow: hidden;"/>
+  <browser id="homescreen"
+           type="content-primary"
+           flex="1"
+           style="overflow: hidden;"
+           src="data:text/html,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/>
 </window>
 
--- a/b2g/chrome/content/webapi.js
+++ b/b2g/chrome/content/webapi.js
@@ -317,17 +317,17 @@ const KineticPanning = {
   _position: new Point(0, 0),
   _velocity: new Point(0, 0),
   _acceleration: new Point(0, 0),
 
   get active() {
     return this.target !== null;
   },
 
-  _target: null,
+  target: null,
   start: function kp_start(target) {
     this.target = target;
 
     // Calculate the initial velocity of the movement based on user input
     let momentums = this.momentums.slice(-kSamples);
 
     let distance = new Point(0, 0);
     momentums.forEach(function(momentum) {
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -1,21 +1,23 @@
 #filter substitution
 
 chrome.jar:
 % content branding %content/branding/
 % content browser %content/
 
 * content/shell.xul                     (content/shell.xul)
-  content/shell.js                      (content/shell.js)
+* content/shell.js                      (content/shell.js)
 #ifndef MOZ_TOUCH
   content/touch.js                      (content/touch.js)
 #endif
   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)
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1329176667000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1330033499000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -106,27 +106,33 @@
       <emItem  blockID="i53" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
                         <versionRange  minVersion="2.0.3" maxVersion="2.0.3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i59" id="ghostviewer@youtube2.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i51" id="admin@youtubeplayer.com">
-                        <versionRange  minVersion="0" maxVersion="*">
+      <emItem  blockID="i70" id="psid-vhvxQHMZBOzUZA@jetpack">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
+                        </emItem>
       <emItem  blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
                         <versionRange  minVersion="0.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="9.0a1" maxVersion="9.0" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i67" id="youtube2@youtube2.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i60" id="youtb3@youtb3.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i23" id="firefox@bandoo.com">
                         <versionRange  minVersion="5.0" maxVersion="5.0" severity="1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1pre" maxVersion="*" />
@@ -156,30 +162,38 @@
                     </versionRange>
                   </emItem>
       <emItem  blockID="i44" id="sigma@labs.mozilla">
                         </emItem>
       <emItem  blockID="i5" id="support@daemon-tools.cc">
                         <versionRange  minVersion=" " maxVersion="1.0.0.5">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i69" id="{977f3b97-5461-4346-92c8-a14c749b77c9}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i6" id="{3f963a5b-e555-4543-90e2-c3908898db71}">
                         <versionRange  minVersion=" " maxVersion="8.5">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i12" id="masterfiler@gmail.com">
                         <versionRange  severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i48" id="admin@youtubespeedup.com">
                         </emItem>
       <emItem  blockID="i20" id="{AB2CE124-6272-4b12-94A9-7303C7397BD1}">
                         <versionRange  minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i68" id="flashupdate@adobe.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i47" id="youtube@youtube2.com">
                         </emItem>
       <emItem  blockID="i62" id="jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
                         <versionRange  minVersion="2.2" maxVersion="2.2">
@@ -199,18 +213,20 @@
       <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
                         <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i3" id="langpack-vi-VN@firefox.mozilla.org">
                         <versionRange  minVersion="2.0" maxVersion="2.0">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
-                        </emItem>
+      <emItem  blockID="i51" id="admin@youtubeplayer.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i52" id="ff-ext@youtube">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
                         <versionRange  minVersion="0.1" maxVersion="1.3.328.4" severity="1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1pre" maxVersion="*" />
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -794,17 +794,17 @@ pref("browser.sessionstore.max_windows_u
 // number of crashes that can occur before the about:sessionrestore page is displayed
 // (this pref has no effect if more than 6 hours have passed since the last crash)
 pref("browser.sessionstore.max_resumed_crashes", 1);
 // restore_on_demand overrides MAX_CONCURRENT_TAB_RESTORES (sessionstore constant)
 // and restore_hidden_tabs. When true, tabs will not be restored until they are
 // focused (also applies to tabs that aren't visible). When false, the values
 // for MAX_CONCURRENT_TAB_RESTORES and restore_hidden_tabs are respected.
 // Selected tabs are always restored regardless of this pref.
-pref("browser.sessionstore.restore_on_demand", false);
+pref("browser.sessionstore.restore_on_demand", true);
 // Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
 pref("browser.sessionstore.restore_hidden_tabs", false);
 // If restore_on_demand is set, pinned tabs are restored on startup by default.
 // When set to true, this pref overrides that behavior, and pinned tabs will only
 // be restored when they are focused.
 pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
 
 // allow META refresh by default
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -160,50 +160,44 @@ var StarUI = {
     if (this._overlayLoading)
       return;
 
     if (this._overlayLoaded) {
       this._doShowEditBookmarkPanel(aItemId, aAnchorElement, aPosition);
       return;
     }
 
-    var loadObserver = {
-      _self: this,
-      _itemId: aItemId,
-      _anchorElement: aAnchorElement,
-      _position: aPosition,
-      observe: function (aSubject, aTopic, aData) {
+    this._overlayLoading = true;
+    document.loadOverlay(
+      "chrome://browser/content/places/editBookmarkOverlay.xul",
+      (function (aSubject, aTopic, aData) {
         //XXX We just caused localstore.rdf to be re-applied (bug 640158)
         retrieveToolbarIconsizesFromTheme();
 
-        this._self._overlayLoading = false;
-        this._self._overlayLoaded = true;
-        this._self._doShowEditBookmarkPanel(this._itemId, this._anchorElement,
-                                            this._position);
-      }
-    };
-    this._overlayLoading = true;
-    document.loadOverlay("chrome://browser/content/places/editBookmarkOverlay.xul",
-                         loadObserver);
+        // Move the header (star, title, button) into the grid,
+        // so that it aligns nicely with the other items (bug 484022).
+        let header = this._element("editBookmarkPanelHeader");
+        let rows = this._element("editBookmarkPanelGrid").lastChild;
+        rows.insertBefore(header, rows.firstChild);
+        header.hidden = false;
+
+        this._overlayLoading = false;
+        this._overlayLoaded = true;
+        this._doShowEditBookmarkPanel(aItemId, aAnchorElement, aPosition);
+      }).bind(this)
+    );
   },
 
   _doShowEditBookmarkPanel:
   function SU__doShowEditBookmarkPanel(aItemId, aAnchorElement, aPosition) {
     if (this.panel.state != "closed")
       return;
 
     this._blockCommands(); // un-done in the popuphiding handler
 
-    // Move the header (star, title, possibly a button) into the grid,
-    // so that it aligns nicely with the other items (bug 484022).
-    var rows = this._element("editBookmarkPanelGrid").lastChild;
-    var header = this._element("editBookmarkPanelHeader");
-    rows.insertBefore(header, rows.firstChild);
-    header.hidden = false;
-
     // Set panel title:
     // if we are batching, i.e. the bookmark has been added now,
     // then show Page Bookmarked, else if the bookmark did already exist,
     // we are about editing it, then use Edit This Bookmark.
     this._element("editBookmarkPanelTitle").value =
       this._batching ?
         gNavigatorBundle.getString("editBookmarkPanel.pageBookmarkedTitle") :
         gNavigatorBundle.getString("editBookmarkPanel.editBookmarkTitle");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1648,22 +1648,16 @@ function delayedStartup(isLoadingBlank, 
   }
 
   PlacesToolbarHelper.init();
 
   ctrlTab.readPref();
   gPrefService.addObserver(ctrlTab.prefName, ctrlTab, false);
   gPrefService.addObserver(allTabs.prefName, allTabs, false);
 
-  // Delayed initialization of the livemarks update timer.
-  // Livemark updates don't need to start until after bookmark UI
-  // such as the toolbar has initialized. Starting 5 seconds after
-  // delayedStartup in order to stagger this before the download manager starts.
-  setTimeout(function() PlacesUtils.livemarks.start(), 5000);
-
   // Initialize the download manager some time after the app starts so that
   // auto-resume downloads begin (such as after crashing or quitting with
   // active downloads) and speeds up the first-load of the download manager UI.
   // If the user manually opens the download manager before the timeout, the
   // downloads will start right away, and getting the service again won't hurt.
   setTimeout(function() {
     gDownloadMgr = Cc["@mozilla.org/download-manager;1"].
                    getService(Ci.nsIDownloadManager);
@@ -3625,22 +3619,22 @@ function FillHistoryMenu(aParent) {
     let entry = sessionHistory.getEntryAtIndex(j, false);
     let uri = entry.URI.spec;
 
     item.setAttribute("uri", uri);
     item.setAttribute("label", entry.title || uri);
     item.setAttribute("index", j);
 
     if (j != index) {
-      try {
-        let iconURL = Cc["@mozilla.org/browser/favicon-service;1"]
-                         .getService(Ci.nsIFaviconService)
-                         .getFaviconForPage(entry.URI).spec;
+      function FHM_getFaviconURLCallback(aURI) {
+        let iconURL = PlacesUtils.favicons.getFaviconLinkForIcon(aURI).spec;
         item.style.listStyleImage = "url(" + iconURL + ")";
-      } catch (ex) {}
+      }
+      PlacesUtils.favicons.getFaviconURLForPage(entry.URI,
+                                                FHM_getFaviconURLCallback);
     }
 
     if (j < index) {
       item.className = "unified-nav-back menuitem-iconic menuitem-with-favicon";
       item.setAttribute("tooltiptext", tooltipBack);
     } else if (j == index) {
       item.setAttribute("type", "radio");
       item.setAttribute("checked", "true");
--- a/browser/base/content/newtab/grid.js
+++ b/browser/base/content/newtab/grid.js
@@ -18,18 +18,20 @@ let gGrid = {
    * The cached DOM fragment for sites.
    */
   _siteFragment: null,
 
   /**
    * All cells contained in the grid.
    */
   get cells() {
+    let cells = [];
     let children = this.node.querySelectorAll("li");
-    let cells = [new Cell(this, child) for each (child in children)];
+    for (let i = 0; i < children.length; i++)
+      cells.push(new Cell(this, children[i]));
 
     // Replace the getter with our cached value.
     Object.defineProperty(this, "cells", {value: cells, enumerable: true});
 
     return cells;
   },
 
   /**
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -688,18 +688,18 @@
         <body>
           <![CDATA[
             var browser = this.getBrowserForTab(aTab);
             browser.mIconURL = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
 
             if (aURI && this.mFaviconService) {
               if (!(aURI instanceof Ci.nsIURI))
                 aURI = makeURI(aURI);
-              this.mFaviconService.setAndLoadFaviconForPage(browser.currentURI,
-                                                            aURI, false);
+              this.mFaviconService.setAndFetchFaviconForPage(browser.currentURI,
+                                                             aURI, false);
             }
 
             if ((browser.mIconURL || "") != aTab.getAttribute("image")) {
               if (browser.mIconURL)
                 aTab.setAttribute("image", browser.mIconURL);
               else
                 aTab.removeAttribute("image");
               this._tabAttrModified(aTab);
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -220,16 +220,17 @@ endif
                  browser_tab_dragdrop.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
                  browser_tabs_isActive.js \
                  browser_tabs_owner.js \
                  browser_urlbarCopying.js \
                  browser_urlbarEnter.js \
+                 browser_urlbarRevert.js \
                  browser_urlbarTrimURLs.js \
                  browser_urlHighlight.js \
                  browser_visibleFindSelection.js \
                  browser_visibleTabs.js \
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
--- a/browser/base/content/test/browser_bug422590.js
+++ b/browser/base/content/test/browser_bug422590.js
@@ -3,18 +3,18 @@ function test() {
   ignoreAllUncaughtExceptions();
   
   // test the main (normal) browser window
   testCustomize(window, testChromeless);
 }
 
 function testChromeless() {
   // test a chromeless window
-  var newWin = openDialog("chrome://browser/content/", "_blank",
-                      "chrome,dialog=no,toolbar=no", "about:blank");
+  var newWin = openDialog(getBrowserURL(), "_blank",
+                          "chrome,dialog=no,toolbar=no", "about:blank");
   ok(newWin, "got new window");
 
   function runWindowTest() {
     // Check that the search bar is hidden
     var searchBar = newWin.BrowserSearch.searchBar;
     ok(searchBar, "got search bar");
 
     var searchBarBO = searchBar.boxObject;
--- a/browser/base/content/test/browser_tabMatchesInAwesomebar.js
+++ b/browser/base/content/test/browser_tabMatchesInAwesomebar.js
@@ -72,34 +72,35 @@ var gTestSteps = [
       loadTab(gBrowser.tabs[i], TEST_URL_BASES[0] + gTabCounter);
   },
   function() {
     info("Running step 4");
     let ps = Services.prefs;
     ps.setBoolPref("browser.privatebrowsing.keep_current_session", true);
     ps.setBoolPref("browser.tabs.warnOnClose", false);
 
+    // Make sure that all restored tabs are loaded without waiting for the user
+    // to bring them to the foreground. We ensure this by resetting the
+    // related preference (see the "firefox.js" defaults file for details).
+    ps.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
     gPrivateBrowsing.privateBrowsingEnabled = true;
 
     executeSoon(function() {
       ensure_opentabs_match_db(nextStep);
     });
   },
   function() {
     info("Running step 5");
     gPrivateBrowsing.privateBrowsingEnabled = false;
 
     executeSoon(function() {
       let ps = Services.prefs;
-      try {
-        ps.clearUserPref("browser.privatebrowsing.keep_current_session");
-      } catch (ex) {}
-      try {
-        ps.clearUserPref("browser.tabs.warnOnClose");
-      } catch (ex) {}
+      ps.clearUserPref("browser.privatebrowsing.keep_current_session");
+      ps.clearUserPref("browser.tabs.warnOnClose");
 
       ensure_opentabs_match_db(nextStep);
     });
   },
   function() {
     info("Running step 6 - ensure we don't register subframes as open pages");
     let tab = gBrowser.addTab();
     tab.linkedBrowser.addEventListener("load", function () {
@@ -164,32 +165,31 @@ var gTestSteps = [
   },
   function() {
     info("Running step 12 - leave private browsing mode");
 
     Services.obs.addObserver(function(aSubject, aTopic, aData) {
       Services.obs.removeObserver(arguments.callee, "private-browsing-transition-complete");
 
       let ps = Services.prefs;
-      try {
-        ps.clearUserPref("browser.privatebrowsing.keep_current_session");
-      } catch (ex) {}
-      try {
-        ps.clearUserPref("browser.tabs.warnOnClose");
-      } catch (ex) {}
+      ps.clearUserPref("browser.privatebrowsing.keep_current_session");
+      ps.clearUserPref("browser.tabs.warnOnClose");
 
       for (let i = 1; i < gBrowser.tabs.length; i++)
         waitForRestoredTab(gBrowser.tabs[i]);
 
     }, "private-browsing-transition-complete", false);
 
     gPrivateBrowsing.privateBrowsingEnabled = false;
   },
   function() {
     info("Running step 13 - close all tabs");
+
+    Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
+
     gBrowser.addTab("about:blank", {skipAnimation: true});
     while (gBrowser.tabs.length > 1) {
       info("Removing tab: " + gBrowser.tabs[0].linkedBrowser.currentURI.spec);
       gBrowser.selectTabAtIndex(0);
       gBrowser.removeCurrentTab();
     }
     ensure_opentabs_match_db(nextStep);
   }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_urlbarRevert.js
@@ -0,0 +1,29 @@
+function test() {
+  waitForExplicitFinish();
+
+  let tab = gBrowser.addTab("http://example.com");
+  gBrowser.selectedTab = tab;
+
+  onLoad(function () {
+    let originalValue = gURLBar.value;
+
+    gBrowser.userTypedValue = "foobar";
+    gBrowser.selectedTab = gBrowser.tabs[0];
+    gBrowser.selectedTab = tab;
+    is(gURLBar.value, "foobar", "location bar displays typed value");
+
+    gURLBar.focus();
+    EventUtils.synthesizeKey("VK_ESCAPE", {});
+    is(gURLBar.value, originalValue, "ESC reverted the location bar value");
+
+    gBrowser.removeTab(tab);
+    finish();
+  });
+}
+
+function onLoad(callback) {
+  gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
+    executeSoon(callback);
+  });
+}
--- a/browser/components/distribution.js
+++ b/browser/components/distribution.js
@@ -40,16 +40,20 @@ EXPORTED_SYMBOLS = [ "DistributionCustom
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC =
   "distribution-customization-complete";
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+                                  "resource://gre/modules/PlacesUtils.jsm");
+
 function DistributionCustomizer() {
   let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                getService(Ci.nsIProperties);
   let iniFile = dirSvc.get("XCurProcD", Ci.nsIFile);
   iniFile.append("distribution");
   iniFile.append("distribution.ini");
   if (iniFile.exists())
     this._iniFile = iniFile;
@@ -73,37 +77,16 @@ DistributionCustomizer.prototype = {
     }
     catch (e) {
       locale = "en-US";
     }
     this.__defineGetter__("_locale", function() locale);
     return this._locale;
   },
 
-  get _bmSvc() {
-    let svc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-              getService(Ci.nsINavBookmarksService);
-    this.__defineGetter__("_bmSvc", function() svc);
-    return this._bmSvc;
-  },
-
-  get _annoSvc() {
-    let svc = Cc["@mozilla.org/browser/annotation-service;1"].
-              getService(Ci.nsIAnnotationService);
-    this.__defineGetter__("_annoSvc", function() svc);
-    return this._annoSvc;
-  },
-
-  get _livemarkSvc() {
-    let svc = Cc["@mozilla.org/browser/livemark-service;2"].
-              getService(Ci.nsILivemarkService);
-    this.__defineGetter__("_livemarkSvc", function() svc);
-    return this._livemarkSvc;
-  },
-
   get _prefSvc() {
     let svc = Cc["@mozilla.org/preferences-service;1"].
               getService(Ci.nsIPrefService);
     this.__defineGetter__("_prefSvc", function() svc);
     return this._prefSvc;
   },
 
   get _prefs() {
@@ -162,73 +145,75 @@ DistributionCustomizer.prototype = {
       }
     }
 
     let prependIndex = 0;
     for (let iid = 0; iid <= maxItemId; iid++) {
       if (!items[iid])
         continue;
 
-      let index = this._bmSvc.DEFAULT_INDEX;
+      let index = PlacesUtils.bookmarks.DEFAULT_INDEX;
       let newId;
 
       switch (items[iid]["type"]) {
       case "default":
         break;
 
       case "folder":
         if (iid < defaultItemId)
           index = prependIndex++;
 
-        newId = this._bmSvc.createFolder(parentId, items[iid]["title"], index);
+        newId = PlacesUtils.bookmarks.createFolder(parentId,
+                                                   items[iid]["title"],
+                                                   index);
 
         this._parseBookmarksSection(newId, "BookmarksFolder-" +
                                     items[iid]["folderId"]);
 
         if (items[iid]["description"])
-          this._annoSvc.setItemAnnotation(newId,
-                                          "bookmarkProperties/description",
-                                          items[iid]["description"], 0,
-                                          this._annoSvc.EXPIRE_NEVER);
+          PlacesUtils.annotations.setItemAnnotation(newId,
+                                                    "bookmarkProperties/description",
+                                                    items[iid]["description"], 0,
+                                                    PlacesUtils.annotations.EXPIRE_NEVER);
 
         break;
 
       case "separator":
         if (iid < defaultItemId)
           index = prependIndex++;
-        this._bmSvc.insertSeparator(parentId, index);
+        PlacesUtils.bookmarks.insertSeparator(parentId, index);
         break;
 
       case "livemark":
         if (iid < defaultItemId)
           index = prependIndex++;
 
         // Don't bother updating the livemark contents on creation.
-        newId = this._livemarkSvc.
-          createLivemarkFolderOnly(parentId,
-                                   items[iid]["title"],
-                                   this._makeURI(items[iid]["siteLink"]),
-                                   this._makeURI(items[iid]["feedLink"]),
-                                   index);
+        PlacesUtils.livemarks.addLivemark({ title: items[iid]["title"]
+                                          , parentId: parentId
+                                          , index: index
+                                          , feedURI: this._makeURI(items[iid]["feedLink"])
+                                          , siteURI: this._makeURI(items[iid]["siteLink"])
+                                          });
         break;
 
       case "bookmark":
       default:
         if (iid < defaultItemId)
           index = prependIndex++;
 
-        newId = this._bmSvc.insertBookmark(parentId,
-                                           this._makeURI(items[iid]["link"]),
-                                           index, items[iid]["title"]);
+        newId = PlacesUtils.bookmarks.insertBookmark(parentId,
+                                                     this._makeURI(items[iid]["link"]),
+                                                     index, items[iid]["title"]);
 
         if (items[iid]["description"])
-          this._annoSvc.setItemAnnotation(newId,
-                                          "bookmarkProperties/description",
-                                          items[iid]["description"], 0,
-                                          this._annoSvc.EXPIRE_NEVER);
+          PlacesUtils.annotations.setItemAnnotation(newId,
+                                                    "bookmarkProperties/description",
+                                                    items[iid]["description"], 0,
+                                                    PlacesUtils.annotations.EXPIRE_NEVER);
 
         break;
       }
     }
   },
 
   _customizationsApplied: false,
   applyCustomizations: function DIST_applyCustomizations() {
@@ -272,20 +257,20 @@ DistributionCustomizer.prototype = {
     let bmProcessed = false;
     try {
       bmProcessed = this._prefs.getBoolPref(bmProcessedPref);
     }
     catch (e) {}
 
     if (!bmProcessed) {
       if (sections["BookmarksMenu"])
-        this._parseBookmarksSection(this._bmSvc.bookmarksMenuFolder,
+        this._parseBookmarksSection(PlacesUtils.bookmarksMenuFolderId,
                                     "BookmarksMenu");
       if (sections["BookmarksToolbar"])
-        this._parseBookmarksSection(this._bmSvc.toolbarFolder,
+        this._parseBookmarksSection(PlacesUtils.toolbarFolderId,
                                     "BookmarksToolbar");
       this._prefs.setBoolPref(bmProcessedPref, true);
     }
     return this._checkCustomizationComplete();
   },
 
   _prefDefaultsApplied: false,
   applyPrefDefaults: function DIST_applyPrefDefaults() {
--- a/browser/components/migration/src/FirefoxProfileMigrator.js
+++ b/browser/components/migration/src/FirefoxProfileMigrator.js
@@ -219,17 +219,16 @@ FirefoxProfileMigrator.prototype = {
    * @param   aStartup
    *          non-null if called during startup.
    * @param   aProfile
    *          profile directory path to migrate from
    */
   migrate : function Firefox_migrate(aItems, aStartup, aProfile)
   {
     if (aStartup) {
-      aStartup.doStartup();
       this._replaceBookmarks = true;
     }
 
     Services.obs.notifyObservers(null, "Migration:Started", null);
 
     // Reset pending count.  If this count becomes 0, "Migration:Ended"
     // notification is sent
     this._pendingCount = 1;
@@ -241,16 +240,21 @@ FirefoxProfileMigrator.prototype = {
       this._migrateCookies();
 
     if (aItems & MIGRATOR.BOOKMARKS)
       this._migrateBookmarks();
 
     if (aItems & MIGRATOR.PASSWORDS)
       this._migratePasswords();
 
+    // The password manager encryption key must be copied before startup.
+    if (aStartup) {
+      aStartup.doStartup();
+    }
+
     if (aItems & MIGRATOR.FORMDATA)
       this._migrateFormData();
 
     if (--this._pendingCount == 0) {
       // When async imports are immediately completed unfortunately,
       // this will be called.
       // Usually, this notification is sent by _notifyCompleted()
       Services.obs.notifyObservers(null, "Migration:Ended", null);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -772,16 +772,25 @@ BrowserGlue.prototype = {
     const PREF_TELEMETRY_PROMPTED = "toolkit.telemetry.prompted";
     const PREF_TELEMETRY_ENABLED  = "toolkit.telemetry.enabled";
     const PREF_TELEMETRY_REJECTED  = "toolkit.telemetry.rejected";
     const PREF_TELEMETRY_INFOURL  = "toolkit.telemetry.infoURL";
     const PREF_TELEMETRY_SERVER_OWNER = "toolkit.telemetry.server_owner";
     // This is used to reprompt users when privacy message changes
     const TELEMETRY_PROMPT_REV = 2;
 
+    function appendTelemetryNotification(notifyBox, message, buttons, hideclose) {
+      let notification = notifyBox.appendNotification(message, "telemetry", null,
+						      notifyBox.PRIORITY_INFO_LOW,
+						      buttons);
+      notification.setAttribute("hideclose", hideclose);
+      notification.persistence = -1;  // Until user closes it
+      return notification;
+    }
+
     var telemetryPrompted = null;
     try {
       telemetryPrompted = Services.prefs.getIntPref(PREF_TELEMETRY_PROMPTED);
     } catch(e) {}
     // If the user has seen the latest telemetry prompt, do not prompt again
     // else clear old prefs and reprompt
     if (telemetryPrompted === TELEMETRY_PROMPT_REV)
       return;
@@ -818,33 +827,30 @@ BrowserGlue.prototype = {
                         Services.prefs.setBoolPref(PREF_TELEMETRY_REJECTED, true);
                       }
                     }
                   ];
 
     // Set pref to indicate we've shown the notification.
     Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV);
 
-    var notification = notifyBox.appendNotification(telemetryPrompt, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons);
-    notification.setAttribute("hideclose", true);
-    notification.persistence = -1;  // Until user closes it
-
+    let notification = appendTelemetryNotification(notifyBox, telemetryPrompt,
+						   buttons, true);
     let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     let link = notification.ownerDocument.createElementNS(XULNS, "label");
     link.className = "text-link telemetry-text-link";
     link.setAttribute("value", browserBundle.GetStringFromName("telemetryLinkLabel"));
     link.addEventListener('click', function() {
       // Open the learn more url in a new tab
       browser.selectedTab = browser.addTab(Services.prefs.getCharPref(PREF_TELEMETRY_INFOURL));
       // Remove the notification on which the user clicked
       notification.parentNode.removeNotification(notification, true);
       // Add a new notification to that tab, with no "Learn more" link
       notifyBox = browser.getNotificationBox();
-      notification = notifyBox.appendNotification(telemetryPrompt, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons);
-      notification.persistence = -1; // Until user closes it
+      appendTelemetryNotification(notifyBox, telemetryPrompt, buttons, true);
     }, false);
     let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
     description.appendChild(link);
   },
 #endif
 
   _showPluginUpdatePage: function BG__showPluginUpdatePage() {
     Services.prefs.setBoolPref(PREF_PLUGINS_NOTIFYUSER, false);
@@ -1295,17 +1301,17 @@ BrowserGlue.prototype = {
   ensurePlacesDefaultQueriesInitialized:
   function BG_ensurePlacesDefaultQueriesInitialized() {
     // This is actual version of the smart bookmarks, must be increased every
     // time smart bookmarks change.
     // When adding a new smart bookmark below, its newInVersion property must
     // be set to the version it has been added in, we will compare its value
     // to users' smartBookmarksVersion and add new smart bookmarks without
     // recreating old deleted ones.
-    const SMART_BOOKMARKS_VERSION = 2;
+    const SMART_BOOKMARKS_VERSION = 3;
     const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
     const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
 
     // TODO bug 399268: should this be a pref?
     const MAX_RESULTS = 10;
 
     // Get current smart bookmarks version.  If not set, create them.
     let smartBookmarksCurrentVersion = 0;
@@ -1341,17 +1347,16 @@ BrowserGlue.prototype = {
             title: bundle.GetStringFromName("recentlyBookmarkedTitle"),
             uri: NetUtil.newURI("place:folder=BOOKMARKS_MENU" +
                                 "&folder=UNFILED_BOOKMARKS" +
                                 "&folder=TOOLBAR" +
                                 "&queryType=" +
                                 Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
                                 "&sort=" +
                                 Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
-                                "&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" +
                                 "&maxResults=" + MAX_RESULTS +
                                 "&excludeQueries=1"),
             parent: PlacesUtils.bookmarksMenuFolderId,
             position: menuIndex++,
             newInVersion: 1
           },
           RecentTags: {
             title: bundle.GetStringFromName("recentTagsTitle"),
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -276,23 +276,36 @@ var BookmarkPropertiesPanel = {
                                      .getKeywordForBookmark(this._itemId);
           // Load In Sidebar
           this._loadInSidebar = PlacesUtils.annotations
                                            .itemHasAnnotation(this._itemId,
                                                               PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
           break;
 
         case "folder":
-          if (PlacesUtils.itemIsLivemark(this._itemId)) {
-            this._itemType = LIVEMARK_CONTAINER;
-            this._feedURI = PlacesUtils.livemarks.getFeedURI(this._itemId);
-            this._siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
-          }
-          else
-            this._itemType = BOOKMARK_FOLDER;
+          this._itemType = BOOKMARK_FOLDER;
+          PlacesUtils.livemarks.getLivemark(
+            { id: this._itemId },
+            (function (aStatus, aLivemark) {
+              if (Components.isSuccessCode(aStatus)) {
+                this._itemType = LIVEMARK_CONTAINER;
+                this._feedURI = aLivemark.feedURI;
+                this._siteURI = aLivemark.siteURI;
+                this._fillEditProperties();
+
+                let acceptButton = document.documentElement.getButton("accept");
+                acceptButton.disabled = !this._inputIsValid();
+
+                let newHeight = window.outerHeight +
+                                this._element("descriptionField").boxObject.height;
+                window.resizeTo(window.outerWidth, newHeight);
+              }
+            }).bind(this)
+          );
+
           break;
       }
 
       // Description
       if (PlacesUtils.annotations
                      .itemHasAnnotation(this._itemId, PlacesUIUtils.DESCRIPTION_ANNO)) {
         this._description = PlacesUtils.annotations
                                        .getItemAnnotation(this._itemId,
@@ -336,18 +349,17 @@ var BookmarkPropertiesPanel = {
       case ACTION_EDIT:
         this._fillEditProperties();
         acceptButton.disabled = this._readOnly;
         break;
       case ACTION_ADD:
         this._fillAddProperties();
         // if this is an uri related dialog disable accept button until
         // the user fills an uri value.
-        if (this._itemType == BOOKMARK_ITEM ||
-            this._itemType == LIVEMARK_CONTAINER)
+        if (this._itemType == BOOKMARK_ITEM)
           acceptButton.disabled = !this._inputIsValid();
         break;
     }
 
     // When collapsible elements change their collapsed attribute we must
     // resize the dialog.
     // sizeToContent is not usable due to bug 90276, so we'll use resizeTo
     // instead and cache the element size. See WSucks in the legacy
@@ -513,26 +525,16 @@ var BookmarkPropertiesPanel = {
    */
   _inputIsValid: function BPP__inputIsValid() {
     if (this._itemType == BOOKMARK_ITEM &&
         !this._containsValidURI("locationField"))
       return false;
     if (this._isAddKeywordDialog && !this._element("keywordField").value.length)
       return false;
 
-    // Feed Location has to be a valid URI;
-    // Site Location has to be a valid URI or empty
-    if (this._itemType == LIVEMARK_CONTAINER) {
-      if (!this._containsValidURI("feedLocationField"))
-        return false;
-      if (!this._containsValidURI("siteLocationField") &&
-          (this._element("siteLocationField").value.length > 0))
-        return false;
-    }
-
     return true;
   },
 
   /**
    * Determines whether the XUL textbox with the given ID contains a
    * string that can be converted into an nsIURI.
    *
    * @param aTextboxID
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1,49 +1,11 @@
-/* -*- 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 Places Frontend Code.
- *
- * The Initial Developer of the Original Code is
- * Google Inc.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Annie Sullivan <annie.sullivan@gmail.com>
- *   Ben Goodger <beng@google.com>
- *   Myk Melez <myk@mozilla.org>
- *   Marco Bonardo <mak77@bonardo.net>
- *   Asaf Romano <mano@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 ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 /**
  * The base view implements everything that's common to the toolbar and
  * menu views.
  */
@@ -165,17 +127,18 @@ PlacesViewBase.prototype = {
     let index = PlacesUtils.bookmarks.DEFAULT_INDEX;
     let container = this._resultNode;
     let orientation = Ci.nsITreeView.DROP_BEFORE;
     let isTag = false;
 
     let selectedNode = this.selectedNode;
     if (selectedNode) {
       let popup = document.popupNode;
-      if (!popup._placesNode || popup._placesNode == this._resultNode) {
+      if (!popup._placesNode || popup._placesNode == this._resultNode ||
+          popup._placesNode.itemId == -1) {
         // If a static menuitem is selected, or if the root node is selected,
         // the insertion point is inside the folder, at the end.
         container = selectedNode;
         orientation = Ci.nsITreeView.DROP_ON;
       }
       else {
         // In all other cases the insertion point is before that node.
         container = selectedNode.parent;
@@ -205,63 +168,72 @@ PlacesViewBase.prototype = {
 
   _cleanPopup: function PVB_cleanPopup(aPopup) {
     // Remove places popup children and update markers to keep track of
     // their indices.
     let start = aPopup._startMarker != -1 ? aPopup._startMarker + 1 : 0;
     let end = aPopup._endMarker != -1 ? aPopup._endMarker :
                                         aPopup.childNodes.length;
     let items = [];
-    let placesNodeFound = false;
+
+    // Automatically adjust the start and the end markers.
+    let firstNonStaticNodeFound = false;
     for (let i = start; i < end; ++i) {
       let item = aPopup.childNodes[i];
       if (item.getAttribute("builder") == "end") {
         // we need to do this for menus that have static content at the end but
         // are initially empty, eg. the history menu, we need to know where to
         // start inserting new items.
         aPopup._endMarker = i;
         break;
       }
+
       if (item._placesNode) {
         items.push(item);
-        placesNodeFound = true;
+        firstNonStaticNodeFound = true;
       }
       else {
-        // This is static content...
-        if (!placesNodeFound)
-          // ...at the start of the popup
-          // Initialized in menu.xml, in the base binding
+        // This is static content.
+        if (!firstNonStaticNodeFound) {
+          // We are at the beginning of the popup, in static content.
+          // The markers are initialized in menu.xml, in the base binding.
           aPopup._startMarker++;
+        }
         else {
-          // ...after places nodes
+          // We are at the end of the popup, after places nodes
           aPopup._endMarker = i;
           break;
         }
       }
     }
 
     for (let i = 0; i < items.length; ++i) {
       aPopup.removeChild(items[i]);
       if (aPopup._endMarker != -1)
         aPopup._endMarker--;
     }
   },
 
   _rebuildPopup: function PVB__rebuildPopup(aPopup) {
     this._cleanPopup(aPopup);
 
-    // If this is a livemark container check if the status menuitem has
-    // to be added or removed.
-    if (PlacesUtils.nodeIsLivemarkContainer(aPopup._placesNode))
-      this._ensureLivemarkStatusMenuItem(aPopup);
-
     let resultNode = aPopup._placesNode;
     if (!resultNode.containerOpen)
       return;
 
+    if (resultNode._feedURI) {
+      aPopup.removeAttribute("emptyplacesresult");
+      if (aPopup._emptyMenuItem) {
+        aPopup._emptyMenuItem.hidden = true;
+      }
+      aPopup._built = true;
+      this._populateLivemarkPopup(aPopup);
+      return;
+    }
+
     let cc = resultNode.childCount;
     if (cc > 0) {
       aPopup.removeAttribute("emptyplacesresult");
       if (aPopup._emptyMenuItem)
         aPopup._emptyMenuItem.hidden = true;
 
       for (let i = 0; i < cc; ++i) {
         let child = resultNode.getChild(i);
@@ -298,21 +270,24 @@ PlacesViewBase.prototype = {
     aPopup._emptyMenuItem = document.createElement("menuitem");
     aPopup._emptyMenuItem.setAttribute("label", label);
     aPopup._emptyMenuItem.setAttribute("disabled", true);
     aPopup.appendChild(aPopup._emptyMenuItem);
   },
 
   _createMenuItemForPlacesNode:
   function PVB__createMenuItemForPlacesNode(aPlacesNode) {
+    delete aPlacesNode._DOMElement;
     let element;
     let type = aPlacesNode.type;
-    if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
+    if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
       element = document.createElement("menuseparator");
+    }
     else {
+      let itemId = aPlacesNode.itemId;
       if (PlacesUtils.uriTypes.indexOf(type) != -1) {
         element = document.createElement("menuitem");
         element.className = "menuitem-iconic bookmark-item menuitem-with-favicon";
         element.setAttribute("scheme",
                              PlacesUIUtils.guessUrlSchemeForUI(aPlacesNode.uri));
       }
       else if (PlacesUtils.containerTypes.indexOf(type) != -1) {
         element = document.createElement("menu");
@@ -322,19 +297,29 @@ PlacesViewBase.prototype = {
           element.setAttribute("query", "true");
           if (PlacesUtils.nodeIsTagQuery(aPlacesNode))
             element.setAttribute("tagContainer", "true");
           else if (PlacesUtils.nodeIsDay(aPlacesNode))
             element.setAttribute("dayContainer", "true");
           else if (PlacesUtils.nodeIsHost(aPlacesNode))
             element.setAttribute("hostContainer", "true");
         }
-        else if (aPlacesNode.itemId != -1) {
-          if (PlacesUtils.nodeIsLivemarkContainer(aPlacesNode))
-            element.setAttribute("livemark", "true");
+        else if (itemId != -1) {
+          PlacesUtils.livemarks.getLivemark(
+            { id: itemId },
+            function (aStatus, aLivemark) {
+              if (Components.isSuccessCode(aStatus)) {
+                element.setAttribute("livemark", "true");
+                // Set an expando on the node, controller will use it to build
+                // its metadata.
+                aPlacesNode._feedURI = aLivemark.feedURI;
+                aPlacesNode._siteURI = aLivemark.siteURI;
+              }
+            }
+          );
         }
 
         let popup = document.createElement("menupopup");
         popup._placesNode = PlacesUtils.asContainer(aPlacesNode);
         if (this._nativeView) {
           popup._startMarker = -1;
           popup._endMarker = -1;
         }
@@ -387,52 +372,94 @@ PlacesViewBase.prototype = {
     }
 
     if (aPopup._endMarker != -1)
       aPopup._endMarker++;
 
     return element;
   },
 
+  _setLivemarkSiteURIMenuItem:
+  function PVB__setLivemarkSiteURIMenuItem(aPopup) {
+    let siteUrl = aPopup._placesNode._siteURI ? aPopup._placesNode._siteURI.spec
+                                              : null;
+    if (!siteUrl && aPopup._siteURIMenuitem) {
+      aPopup.removeChild(aPopup._siteURIMenuitem);
+      aPopup._siteURIMenuitem = null;
+      aPopup._startMarker--;
+      aPopup.removeChild(aPopup._siteURIMenuseparator);
+      aPopup._siteURIMenuseparator = null;
+      aPopup._startMarker--;
+    }
+    else if (siteUrl && !aPopup._siteURIMenuitem) {
+      // Add "Open (Feed Name)" menuitem.
+      aPopup._siteURIMenuitem = document.createElement("menuitem");
+      aPopup._siteURIMenuitem.className = "openlivemarksite-menuitem";
+      aPopup._siteURIMenuitem.setAttribute("targetURI", siteUrl);
+      aPopup._siteURIMenuitem.setAttribute("oncommand",
+        "openUILink(this.getAttribute('targetURI'), event);");
+
+      // If a user middle-clicks this item we serve the oncommand event.
+      // We are using checkForMiddleClick because of Bug 246720.
+      // Note: stopPropagation is needed to avoid serving middle-click
+      // with BT_onClick that would open all items in tabs.
+      aPopup._siteURIMenuitem.setAttribute("onclick",
+        "checkForMiddleClick(this, event); event.stopPropagation();");
+      let label =
+        PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label",
+                                         [aPopup.parentNode.getAttribute("label")])
+      aPopup._siteURIMenuitem.setAttribute("label", label);
+      aPopup.insertBefore(aPopup._siteURIMenuitem,
+                          aPopup.childNodes.item(aPopup._startMarker + 1));
+      aPopup._startMarker++;
+
+      aPopup._siteURIMenuseparator = document.createElement("menuseparator");
+      aPopup.insertBefore(aPopup._siteURIMenuseparator,
+                         aPopup.childNodes.item(aPopup._startMarker + 1));
+      aPopup._startMarker++;
+    }
+  },
+
   /**
    * Add, update or remove the livemark status menuitem.
    * @param aPopup
    *        The livemark container popup
+   * @param aStatus
+   *        The livemark status
    */
-  _ensureLivemarkStatusMenuItem:
-  function PVB_ensureLivemarkStatusMenuItem(aPopup) {
+  _setLivemarkStatusMenuItem:
+  function PVB_setLivemarkStatusMenuItem(aPopup, aStatus) {
     let itemId = aPopup._placesNode.itemId;
-    let as = PlacesUtils.annotations;
+    let statusMenuitem = aPopup._statusMenuitem;
+    let stringId = "";
+    if (aStatus == Ci.mozILivemark.STATUS_LOADING)
+      stringId = "bookmarksLivemarkLoading";
+    else if (aStatus == Ci.mozILivemark.STATUS_FAILED)
+      stringId = "bookmarksLivemarkFailed";
 
-    let lmStatus = null;
-    if (as.itemHasAnnotation(itemId, PlacesUtils.LMANNO_LOADFAILED))
-      lmStatus = "bookmarksLivemarkFailed";
-    else if (as.itemHasAnnotation(itemId, PlacesUtils.LMANNO_LOADING))
-      lmStatus = "bookmarksLivemarkLoading";
-
-    let lmStatusElt = aPopup._lmStatusMenuItem;
-    if (lmStatus && !lmStatusElt) {
+    if (stringId && !statusMenuitem) {
       // Create the status menuitem and cache it in the popup object.
-      lmStatusElt = document.createElement("menuitem");
-      lmStatusElt.setAttribute("lmStatus", lmStatus);
-      lmStatusElt.setAttribute("label", PlacesUIUtils.getString(lmStatus));
-      lmStatusElt.setAttribute("disabled", true);
-      aPopup.insertBefore(lmStatusElt,
+      statusMenuitem = document.createElement("menuitem");
+      statusMenuitem.setAttribute("livemarkStatus", stringId);
+      statusMenuitem.setAttribute("label", PlacesUIUtils.getString(stringId));
+      statusMenuitem.setAttribute("disabled", true);
+      aPopup.insertBefore(statusMenuitem,
                           aPopup.childNodes.item(aPopup._startMarker + 1));
-      aPopup._lmStatusMenuItem = lmStatusElt;
+      aPopup._statusMenuitem = statusMenuitem;
       aPopup._startMarker++;
     }
-    else if (lmStatus && lmStatusElt.getAttribute("lmStatus") != lmStatus) {
+    else if (stringId &&
+             statusMenuitem.getAttribute("livemarkStatus") != stringId) {
       // Status has changed, update the cached status menuitem.
-      lmStatusElt.setAttribute("label", this.getString(lmStatus));
+      statusMenuitem.setAttribute("label", PlacesUIUtils.getString(stringId));
     }
-    else if (!lmStatus && lmStatusElt) {
-      // No status, remove the cached menuitem.
-      aPopup.removeChild(aPopup._lmStatusMenuItem);
-      aPopup._lmStatusMenuItem = null;
+    else if (!stringId && statusMenuitem) {
+      // The livemark has finished loading.
+      aPopup.removeChild(aPopup._statusMenuitem);
+      aPopup._statusMenuitem = null;
       aPopup._startMarker--;
     }
   },
 
   toggleCutNode: function PVB_toggleCutNode(aNode, aValue) {
     let elt = aNode._DOMElement;
     if (elt) {
       // We may get the popup for menus, but we need the menu itself.
@@ -483,24 +510,32 @@ PlacesViewBase.prototype = {
     let elt = aPlacesNode._DOMElement;
     if (!elt)
       throw "aPlacesNode must have _DOMElement set";
 
     // All livemarks have a feedURI, so use it as our indicator of a livemark
     // being modified.
     if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
       let menu = elt.parentNode;
-      if (!menu.hasAttribute("livemark"))
+      if (!menu.hasAttribute("livemark")) {
         menu.setAttribute("livemark", "true");
-    }
+      }
 
-    if ([PlacesUtils.LMANNO_LOADING,
-         PlacesUtils.LMANNO_LOADFAILED].indexOf(aAnno) != -1) {
-      // Loading status changed, update the livemark status menuitem.
-      this._ensureLivemarkStatusMenuItem(elt);
+      PlacesUtils.livemarks.getLivemark(
+        { id: aPlacesNode.itemId },
+        (function (aStatus, aLivemark) {
+          if (Components.isSuccessCode(aStatus)) {
+            // Set an expando on the node, controller will use it to build
+            // its metadata.
+            aPlacesNode._feedURI = aLivemark.feedURI;
+            aPlacesNode._siteURI = aLivemark.siteURI;
+            this.invalidateContainer(aPlacesNode);
+          }
+        }).bind(this)
+      );
     }
   },
 
   nodeTitleChanged:
   function PVB_nodeTitleChanged(aPlacesNode, aNewTitle) {
     let elt = aPlacesNode._DOMElement;
     if (!elt)
       throw "aPlacesNode must have _DOMElement set";
@@ -575,17 +610,34 @@ PlacesViewBase.prototype = {
       // No worries: If elt is the last item (i.e. no nextSibling),
       // _insertNewItem/_insertNewItemToPopup will insert the new element as
       // the last item.
       let nextElt = elt.nextSibling;
       this._insertNewItemToPopup(aNewPlacesNode, parentElt, nextElt);
     }
   },
 
-  nodeHistoryDetailsChanged: function() { },
+  nodeHistoryDetailsChanged:
+  function PVB_nodeHistoryDetailsChanged(aPlacesNode, aTime, aCount) {
+    if (aPlacesNode.parent && aPlacesNode.parent._feedURI) {
+      // Find the node in the parent.
+      let popup = aPlacesNode.parent._DOMElement;
+      for (let i = popup._startMarker; i < popup.childNodes.length; i++) {
+        let child = popup.childNodes[i];
+        if (child._placesNode && child._placesNode.uri == aPlacesNode.uri) {
+          if (aCount)
+            child.setAttribute("visited", "true");
+          else
+            child.removeAttribute("visited");
+          break;
+        }
+      }
+    }
+  },
+
   nodeTagsChanged: function() { },
   nodeDateAddedChanged: function() { },
   nodeLastModifiedChanged: function() { },
   nodeKeywordChanged: function() { },
   sortingChanged: function() { },
   batching: function() { },
 
   nodeInserted:
@@ -637,20 +689,70 @@ PlacesViewBase.prototype = {
     }
   },
 
   containerStateChanged:
   function PVB_containerStateChanged(aPlacesNode, aOldState, aNewState) {
     if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED ||
         aNewState == Ci.nsINavHistoryContainerResultNode.STATE_CLOSED) {
       this.invalidateContainer(aPlacesNode);
+
+      if (PlacesUtils.nodeIsFolder(aPlacesNode)) {
+        let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
+        if (queryOptions.excludeItems) {
+          return;
+        }
+
+        PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId },
+          (function (aStatus, aLivemark) {
+            if (Components.isSuccessCode(aStatus)) {
+              let shouldInvalidate = !aPlacesNode._feedURI;
+              aPlacesNode._feedURI = aLivemark.feedURI;
+              aPlacesNode._siteURI = aLivemark.siteURI;
+              if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
+                aLivemark.registerForUpdates(aPlacesNode, this);
+                aLivemark.reload();
+                if (shouldInvalidate)
+                  this.invalidateContainer(aPlacesNode);
+              }
+              else {
+                aLivemark.unregisterForUpdates(aPlacesNode);
+              }
+            }
+          }).bind(this)
+        );
+      }
     }
-    else {
-      throw "Unexpected state passed to containerStateChanged";
-    }
+  },
+
+  _populateLivemarkPopup: function PVB__populateLivemarkPopup(aPopup)
+  {
+    this._setLivemarkSiteURIMenuItem(aPopup);
+    this._setLivemarkStatusMenuItem(aPopup, Ci.mozILivemark.STATUS_LOADING);
+
+    PlacesUtils.livemarks.getLivemark({ id: aPopup._placesNode.itemId },
+      (function (aStatus, aLivemark) {
+        let placesNode = aPopup._placesNode;
+        if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen)
+          return;
+
+        this._setLivemarkStatusMenuItem(aPopup, aLivemark.status);
+        this._cleanPopup(aPopup);
+
+        let children = aLivemark.getNodesForContainer(placesNode);
+        for (let i = 0; i < children.length; i++) {
+          let child = children[i];
+          this.nodeInserted(placesNode, child, i);
+          if (child.accessCount)
+            child._DOMElement.setAttribute("visited", true);
+          else
+            child._DOMElement.removeAttribute("visited");
+        }
+      }).bind(this)
+    );
   },
 
   invalidateContainer: function PVB_invalidateContainer(aPlacesNode) {
     let elt = aPlacesNode._DOMElement;
     if (!elt)
       throw "aPlacesNode must have _DOMElement set";
 
     elt._built = false;
@@ -691,97 +793,65 @@ PlacesViewBase.prototype = {
    * @param aPopup
    *        a Places popup.
    */
   _mayAddCommandsItems: function PVB__mayAddCommandsItems(aPopup) {
     // The command items are never added to the root popup.
     if (aPopup == this._rootElt)
       return;
 
-    // Check if the popup contains at least 2 menuitems with places nodes
-    let numURINodes = 0;
-    let currentChild = aPopup.firstChild;
-    while (currentChild) {
-      if (currentChild.localName == "menuitem" && currentChild._placesNode) {
-        if (++numURINodes == 2)
-          break;
+    let hasMultipleURIs = false;
+
+    // Check if the popup contains at least 2 menuitems with places nodes.
+    // We don't currently support opening multiple uri nodes when they are not
+    // populated by the result.
+    if (aPopup._placesNode.childCount > 0) {
+      let currentChild = aPopup.firstChild;
+      let numURINodes = 0;
+      while (currentChild) {
+        if (currentChild.localName == "menuitem" && currentChild._placesNode) {
+          if (++numURINodes == 2)
+            break;
+        }
+        currentChild = currentChild.nextSibling;
       }
-      currentChild = currentChild.nextSibling;
-    }
-
-    let hasMultipleURIs = numURINodes > 1;
-    let itemId = aPopup._placesNode.itemId;
-    let siteURIString = "";
-    if (itemId != -1 && PlacesUtils.itemIsLivemark(itemId)) {
-      let siteURI = PlacesUtils.livemarks.getSiteURI(itemId);
-      if (siteURI)
-        siteURIString = siteURI.spec;
+      hasMultipleURIs = numURINodes > 1;
     }
 
-    if (!siteURIString && aPopup._endOptOpenSiteURI) {
-      aPopup.removeChild(aPopup._endOptOpenSiteURI);
-      aPopup._endOptOpenSiteURI = null;
-    }
+    if (!hasMultipleURIs) {
+      // We don't have to show any option.
+      if (aPopup._endOptOpenAllInTabs) {
+        aPopup.removeChild(aPopup._endOptOpenAllInTabs);
+        aPopup._endOptOpenAllInTabs = null;
+        aPopup._endMarker--;
 
-    if (!hasMultipleURIs && aPopup._endOptOpenAllInTabs) {
-      aPopup.removeChild(aPopup._endOptOpenAllInTabs);
-      aPopup._endOptOpenAllInTabs = null;
-    }
-
-    if (!(hasMultipleURIs || siteURIString)) {
-      // We don't have to show any option.
-      if (aPopup._endOptSeparator) {
         aPopup.removeChild(aPopup._endOptSeparator);
         aPopup._endOptSeparator = null;
-        aPopup._endMarker = -1;
+        aPopup._endMarker--;
       }
-      return;
     }
-
-    if (!aPopup._endOptSeparator) {
+    else if (!aPopup._endOptOpenAllInTabs) {
       // Create a separator before options.
       aPopup._endOptSeparator = document.createElement("menuseparator");
       aPopup._endOptSeparator.className = "bookmarks-actions-menuseparator";
-      aPopup._endMarker = aPopup.childNodes.length;
       aPopup.appendChild(aPopup._endOptSeparator);
-    }
-
-    if (siteURIString && !aPopup._endOptOpenSiteURI) {
-      // Add "Open (Feed Name)" menuitem if it's a livemark with a siteURI.
-      aPopup._endOptOpenSiteURI = document.createElement("menuitem");
-      aPopup._endOptOpenSiteURI.className = "openlivemarksite-menuitem";
-      aPopup._endOptOpenSiteURI.setAttribute("targetURI", siteURIString);
-      aPopup._endOptOpenSiteURI.setAttribute("oncommand",
-          "openUILink(this.getAttribute('targetURI'), event);");
+      aPopup._endMarker++;
 
-      // If a user middle-clicks this item we serve the oncommand event
-      // We are using checkForMiddleClick because of Bug 246720
-      // Note: stopPropagation is needed to avoid serving middle-click
-      // with BT_onClick that would open all items in tabs.
-      aPopup._endOptOpenSiteURI.setAttribute("onclick",
-          "checkForMiddleClick(this, event); event.stopPropagation();");
-      aPopup._endOptOpenSiteURI.setAttribute("label",
-          PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label",
-          [aPopup.parentNode.getAttribute("label")]));
-      aPopup.appendChild(aPopup._endOptOpenSiteURI);
-    }
-
-    if (hasMultipleURIs && !aPopup._endOptOpenAllInTabs) {
-      // Add the "Open All in Tabs" menuitem if there are
-      // at least two menuitems with places result nodes.
+      // Add the "Open All in Tabs" menuitem.
       aPopup._endOptOpenAllInTabs = document.createElement("menuitem");
       aPopup._endOptOpenAllInTabs.className = "openintabs-menuitem";
       aPopup._endOptOpenAllInTabs.setAttribute("oncommand",
         "PlacesUIUtils.openContainerNodeInTabs(this.parentNode._placesNode, event, " +
                                                "PlacesUIUtils.getViewForNode(this));");
       aPopup._endOptOpenAllInTabs.setAttribute("onclick",
         "checkForMiddleClick(this, event); event.stopPropagation();");
       aPopup._endOptOpenAllInTabs.setAttribute("label",
         gNavigatorBundle.getString("menuOpenAllInTabs.label"));
       aPopup.appendChild(aPopup._endOptOpenAllInTabs);
+      aPopup._endMarker++;
     }
   },
 
   _onPopupShowing: function PVB__onPopupShowing(aEvent) {
     // Avoid handling popupshowing of inner views.
     let popup = aEvent.originalTarget;
     if (popup._placesNode && PlacesUIUtils.getViewForNode(popup) == this) {
       if (!popup._placesNode.containerOpen)
@@ -896,16 +966,17 @@ PlacesToolbar.prototype = {
       // a rebuild of the toolbar, it has to be rebuilt.
       // Otherwise, it will be initialized when the toolbar overflows.
       this._chevronPopup.place = this.place;
     }
   },
 
   _insertNewItem:
   function PT__insertNewItem(aChild, aBefore) {
+    delete aChild._DOMElement;
     let type = aChild.type;
     let button;
     if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
       button = document.createElement("toolbarseparator");
     }
     else {
       button = document.createElement("toolbarbutton");
       button.className = "bookmark-item";
@@ -918,18 +989,29 @@ PlacesToolbar.prototype = {
         button.setAttribute("type", "menu");
         button.setAttribute("container", "true");
 
         if (PlacesUtils.nodeIsQuery(aChild)) {
           button.setAttribute("query", "true");
           if (PlacesUtils.nodeIsTagQuery(aChild))
             button.setAttribute("tagContainer", "true");
         }
-        else if (PlacesUtils.nodeIsLivemarkContainer(aChild)) {
-          button.setAttribute("livemark", "true");
+        else if (PlacesUtils.nodeIsFolder(aChild)) {
+          PlacesUtils.livemarks.getLivemark(
+            { id: aChild.itemId },
+            function (aStatus, aLivemark) {
+              if (Components.isSuccessCode(aStatus)) {
+                button.setAttribute("livemark", "true");
+                // Set an expando on the node, controller will use it to build
+                // its metadata.
+                aChild._feedURI = aLivemark.feedURI;
+                aChild._siteURI = aLivemark.siteURI;
+              }
+            }
+          );
         }
 
         let popup = document.createElement("menupopup");
         popup.setAttribute("placespopup", "true");
         button.appendChild(popup);
         popup._placesNode = PlacesUtils.asContainer(aChild);
 #ifndef XP_MACOSX
         popup.setAttribute("context", "placesContext");
@@ -1183,22 +1265,29 @@ PlacesToolbar.prototype = {
       elt = elt.parentNode;
 
     if (elt.parentNode == this._rootElt) {
       // Node is on the toolbar.
 
       // All livemarks have a feedURI, so use it as our indicator.
       if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
         elt.setAttribute("livemark", true);
-      }
 
-      if ([PlacesUtils.LMANNO_LOADING,
-           PlacesUtils.LMANNO_LOADFAILED].indexOf(aAnno) != -1) {
-        // Loading status changed, update the livemark status menuitem.
-        this._ensureLivemarkStatusMenuItem(elt.firstChild);
+        PlacesUtils.livemarks.getLivemark(
+          { id: aPlacesNode.itemId },
+          (function (aStatus, aLivemark) {
+            if (Components.isSuccessCode(aStatus)) {
+              // Set an expando on the node, controller will use it to build
+              // its metadata.
+              aPlacesNode._feedURI = aLivemark.feedURI;
+              aPlacesNode._siteURI = aLivemark.siteURI;
+              this.invalidateContainer(aPlacesNode);
+            }
+          }).bind(this)
+        );
       }
     }
     else {
       // Node is in a submenu.
       PlacesViewBase.prototype.nodeAnnotationChanged.apply(this, arguments);
     }
   },
 
@@ -1618,23 +1707,26 @@ PlacesToolbar.prototype = {
     if (parent.localName == "toolbarbutton")
       this._openedMenuButton = parent;
 
     return PlacesViewBase.prototype._onPopupShowing.apply(this, arguments);
   },
 
   _onPopupHidden: function PT__onPopupHidden(aEvent) {
     let popup = aEvent.target;
-
+    let placesNode = popup._placesNode;
     // Avoid handling popuphidden of inner views
-    if (popup._placesNode && PlacesUIUtils.getViewForNode(popup) == this) {
+    if (placesNode && PlacesUIUtils.getViewForNode(popup) == this) {
       // UI performance: folder queries are cheap, keep the resultnode open
       // so we don't rebuild its contents whenever the popup is reopened.
-      if (!PlacesUtils.nodeIsFolder(popup._placesNode))
-        popup._placesNode.containerOpen = false;
+      // Though, we want to always close feed containers so their expiration
+      // status will be checked at next opening.
+      if (!PlacesUtils.nodeIsFolder(placesNode) || placesNode._feedURI) {
+        placesNode.containerOpen = false;
+      }
     }
 
     let parent = popup.parentNode;
     if (parent.localName == "toolbarbutton") {
       this._openedMenuButton = null;
       // Clear the dragover attribute if present, if we are dragging into a
       // folder in the hierachy of current opened popup we don't clear
       // this attribute on clearOverFolder.  See Notify for closeTimer.
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -39,17 +39,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 
 // XXXmano: we should move most/all of these constants to PlacesUtils
 const ORGANIZER_ROOT_BOOKMARKS = "place:folder=BOOKMARKS_MENU&excludeItems=1&queryType=1";
-const ORGANIZER_SUBSCRIPTIONS_QUERY = "place:annotation=livemark%2FfeedURI";
 
 // No change to the view, preserve current selection
 const RELOAD_ACTION_NOTHING = 0;
 // Inserting items new to the view, select the inserted rows
 const RELOAD_ACTION_INSERT = 1;
 // Removing items from the view, select the first item after the last selected
 const RELOAD_ACTION_REMOVE = 2;
 // Moving items within a view, don't treat the dropped items as additional
@@ -203,25 +202,21 @@ PlacesController.prototype = {
       return this._canInsert();
     case "placesCmd_new:separator":
       return this._canInsert() &&
              !PlacesUtils.asQuery(this._view.result.root).queryOptions.excludeItems &&
              this._view.result.sortingMode ==
                  Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
     case "placesCmd_show:info":
       var selectedNode = this._view.selectedNode;
-      if (selectedNode &&
-          PlacesUtils.getConcreteItemId(selectedNode) != -1  &&
-          !PlacesUtils.nodeIsLivemarkItem(selectedNode))
-        return true;
-      return false;
+      return selectedNode && PlacesUtils.getConcreteItemId(selectedNode) != -1
     case "placesCmd_reload":
       // Livemark containers
       var selectedNode = this._view.selectedNode;
-      return selectedNode && PlacesUtils.nodeIsLivemarkContainer(selectedNode);
+      return selectedNode && !!selectedNode._feedURI;
     case "placesCmd_sortBy:name":
       var selectedNode = this._view.selectedNode;
       return selectedNode &&
              PlacesUtils.nodeIsFolder(selectedNode) &&
              !PlacesUtils.nodeIsReadOnly(selectedNode) &&
              this._view.result.sortingMode ==
                  Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
     case "placesCmd_createBookmark":
@@ -504,17 +499,17 @@ PlacesController.prototype = {
           if (PlacesUtils.nodeIsBookmark(node)) {
             nodeData["bookmark"] = true;
             PlacesUtils.nodeIsTagQuery(node.parent)
 
             var parentNode = node.parent;
             if (parentNode) {
               if (PlacesUtils.nodeIsTagQuery(parentNode))
                 nodeData["tagChild"] = true;
-              else if (PlacesUtils.nodeIsLivemarkContainer(parentNode))
+              else if (parentNode._feedURI)
                 nodeData["livemarkChild"] = true;
             }
           }
           break;
       }
 
       // annotations
       if (uri) {
@@ -729,18 +724,27 @@ PlacesController.prototype = {
            "This method should be passed a URI as a nsIURI object, not as a string.");
   },
 
   /**
    * Reloads the selected livemark if any.
    */
   reloadSelectedLivemark: function PC_reloadSelectedLivemark() {
     var selectedNode = this._view.selectedNode;
-    if (selectedNode && PlacesUtils.nodeIsLivemarkContainer(selectedNode))
-      PlacesUtils.livemarks.reloadLivemarkFolder(selectedNode.itemId);
+    if (selectedNode) {
+      let itemId = selectedNode.itemId;
+      PlacesUtils.livemarks.getLivemark(
+        { id: itemId },
+        (function(aStatus, aLivemark) {
+          if (Components.isSuccessCode(aStatus)) {
+            aLivemark.reload(true);
+          }
+        }).bind(this)
+      );
+    }
   },
 
   /**
    * Opens the links in the selected folder, or the selected links in new tabs.
    */
   openSelectionInTabs: function PC_openLinksInTabs(aEvent) {
     var node = this._view.selectedNode;
     if (node && PlacesUtils.nodeIsContainer(node))
@@ -1060,20 +1064,22 @@ PlacesController.prototype = {
           addData(PlacesUtils.TYPE_HTML, index, overrideURI);
         }
 
         // This order is _important_! It controls how this and other
         // applications select data to be inserted based on type.
         addData(PlacesUtils.TYPE_X_MOZ_PLACE, i);
 
         // Drop the feed uri for livemark containers
-        if (PlacesUtils.nodeIsLivemarkContainer(node))
-          addURIData(i, PlacesUtils.livemarks.getFeedURI(node.itemId).spec);
-        else if (node.uri)
+        if (node._feedURI) {
+          addURIData(i, node._feedURI.spec);
+        }
+        else if (node.uri) {
           addURIData(i);
+        }
       }
     }
     finally {
       if (!didSuppressNotifications)
         result.suppressNotifications = false;
     }
   },
 
@@ -1133,18 +1139,17 @@ PlacesController.prototype = {
     // of them automatically.
     let copiedFolders = [];
     aNodes.forEach(function (node) {
       if (this._shouldSkipNode(node, copiedFolders))
         return;
       if (PlacesUtils.nodeIsFolder(node))
         copiedFolders.push(node);
 
-      let overrideURI = PlacesUtils.nodeIsLivemarkContainer(node) ?
-        PlacesUtils.livemarks.getFeedURI(node.itemId).spec : null;
+      let overrideURI = node._feedURI ? node._feedURI.spec : null;
       let resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node);
 
       contents.forEach(function (content) {
         content.entries.push(
           PlacesUtils.wrapNode(node, content.type, overrideURI, resolveShortcuts)
         );
       });
     }, this);
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -1,44 +1,11 @@
-/* -*- 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 the Places Bookmark Properties dialog.
- *
- * The Initial Developer of the Original Code is Google Inc.
- * Portions created by the Initial Developer are Copyright (C) 2006
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Asaf Romano <mano@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 ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const LAST_USED_ANNO = "bookmarkPropertiesDialog/folderLastUsed";
 const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
 
 var gEditItemOverlay = {
   _uri: null,
   _itemId: -1,
   _itemIds: [],
@@ -47,16 +14,17 @@ var gEditItemOverlay = {
   _allTags: [],
   _multiEdit: false,
   _itemType: -1,
   _readOnly: false,
   _hiddenRows: [],
   _observersAdded: false,
   _staticFoldersListBuilt: false,
   _initialized: false,
+  _titleOverride: "",
 
   // the first field which was edited after this panel was initialized for
   // a certain item
   _firstEditedField: "",
 
   get itemId() {
     return this._itemId;
   },
@@ -75,16 +43,18 @@ var gEditItemOverlay = {
   _determineInfo: function EIO__determineInfo(aInfo) {
     // hidden rows
     if (aInfo && aInfo.hiddenRows)
       this._hiddenRows = aInfo.hiddenRows;
     else
       this._hiddenRows.splice(0, this._hiddenRows.length);
     // force-read-only
     this._readOnly = aInfo && aInfo.forceReadOnly;
+    this._titleOverride = aInfo && aInfo.titleOverride ? aInfo.titleOverride
+                                                       : "";
   },
 
   _showHideRows: function EIO__showHideRows() {
     var isBookmark = this._itemId != -1 &&
                      this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK;
     var isQuery = false;
     if (this._uri)
       isQuery = this._uri.schemeIs("place");
@@ -155,42 +125,44 @@ var gEditItemOverlay = {
     this._determineInfo(aInfo);
     if (aFor instanceof Ci.nsIURI) {
       this._itemId = -1;
       this._uri = aFor;
       this._readOnly = true;
     }
     else {
       this._itemId = aFor;
+      // We can't store information on invalid itemIds.
+      this._readOnly = this._readOnly || this._itemId == -1;
+
       var containerId = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
       this._itemType = PlacesUtils.bookmarks.getItemType(this._itemId);
       if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
         this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
-        if (!this._readOnly) // If readOnly wasn't forced through aInfo
-          this._readOnly = PlacesUtils.itemIsLivemark(containerId);
         this._initTextField("keywordField",
                             PlacesUtils.bookmarks
                                        .getKeywordForBookmark(this._itemId));
-        // Load In Sidebar checkbox
         this._element("loadInSidebarCheckbox").checked =
           PlacesUtils.annotations.itemHasAnnotation(this._itemId,
                                                     PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
       }
       else {
-        if (!this._readOnly) // If readOnly wasn't forced through aInfo
-          this._readOnly = false;
-
         this._uri = null;
-        this._isLivemark = PlacesUtils.itemIsLivemark(this._itemId);
-        if (this._isLivemark) {
-          var feedURI = PlacesUtils.livemarks.getFeedURI(this._itemId);
-          var siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
-          this._initTextField("feedLocationField", feedURI.spec);
-          this._initTextField("siteLocationField", siteURI ? siteURI.spec : "");
-        }
+        this._isLivemark = false;
+        PlacesUtils.livemarks.getLivemark(
+          {id: this._itemId },
+          (function (aStatus, aLivemark) {
+            if (Components.isSuccessCode(aStatus)) {
+              this._isLivemark = true;
+              this._initTextField("feedLocationField", aLivemark.feedURI.spec, true);
+              this._initTextField("siteLocationField", aLivemark.siteURI ? aLivemark.siteURI.spec : "", true);
+              this._showHideRows();
+            }
+          }).bind(this)
+        );
       }
 
       // folder picker
       this._initFolderMenuList(containerId);
 
       // description field
       this._initTextField("descriptionField", 
                           PlacesUIUtils.getItemDescription(this._itemId));
@@ -374,20 +346,27 @@ var gEditItemOverlay = {
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
 
   _element: function EIO__element(aID) {
     return document.getElementById("editBMPanel_" + aID);
   },
 
   _getItemStaticTitle: function EIO__getItemStaticTitle() {
-    if (this._itemId == -1)
-      return PlacesUtils.history.getPageTitle(this._uri);
+    if (this._titleOverride)
+      return this._titleOverride;
 
-    return PlacesUtils.bookmarks.getItemTitle(this._itemId);
+    let title = "";
+    if (this._itemId == -1) {
+      title = PlacesUtils.history.getPageTitle(this._uri);
+    }
+    else {
+      title = PlacesUtils.bookmarks.getItemTitle(this._itemId);
+    }
+    return title;
   },
 
   _initNamePicker: function EIO_initNamePicker() {
     var namePicker = this._element("namePicker");
     namePicker.value = this._getItemStaticTitle();
     namePicker.readOnly = this._readOnly;
 
     // clear the undo stack
@@ -420,16 +399,18 @@ var gEditItemOverlay = {
     this._uri = null;
     this._uris = [];
     this._tags = [];
     this._allTags = [];
     this._itemIds = [];
     this._multiEdit = false;
     this._firstEditedField = "";
     this._initialized = false;
+    this._titleOverride = "";
+    this._readOnly = false;
   },
 
   onTagsFieldBlur: function EIO_onTagsFieldBlur() {
     if (this._updateTags()) // if anything has changed
       this._mayUpdateFirstEditField("tagsField");
   },
 
   _updateTags: function EIO__updateTags() {
@@ -592,46 +573,16 @@ var gEditItemOverlay = {
   onKeywordFieldBlur: function EIO_onKeywordFieldBlur() {
     var keyword = this._element("keywordField").value;
     if (keyword != PlacesUtils.bookmarks.getKeywordForBookmark(this._itemId)) {
       var txn = PlacesUIUtils.ptm.editBookmarkKeyword(this._itemId, keyword);
       PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
-  onFeedLocationFieldBlur: function EIO_onFeedLocationFieldBlur() {
-    var uri;
-    try {
-      uri = PlacesUIUtils.createFixedURI(this._element("feedLocationField").value);
-    }
-    catch(ex) { return; }
-
-    var currentFeedURI = PlacesUtils.livemarks.getFeedURI(this._itemId);
-    if (!currentFeedURI.equals(uri)) {
-      var txn = PlacesUIUtils.ptm.editLivemarkFeedURI(this._itemId, uri);
-      PlacesUIUtils.ptm.doTransaction(txn);
-    }
-  },
-
-  onSiteLocationFieldBlur: function EIO_onSiteLocationFieldBlur() {
-    var uri = null;
-    try {
-      uri = PlacesUIUtils.createFixedURI(this._element("siteLocationField").value);
-    }
-    catch(ex) {  }
-
-    var currentSiteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
-    if ((!uri && !currentSiteURI) ||
-        (uri && currentSiteURI && currentSiteURI.equals(uri))) {
-      return;
-    }
-    var txn = PlacesUIUtils.ptm.editLivemarkSiteURI(this._itemId, uri);
-    PlacesUIUtils.ptm.doTransaction(txn);
-  },
-
   onLoadInSidebarCheckboxCommand:
   function EIO_onLoadInSidebarCheckboxCommand() {
     var loadInSidebarChecked = this._element("loadInSidebarCheckbox").checked;
     var txn = PlacesUIUtils.ptm.setLoadInSidebar(this._itemId,
                                                  loadInSidebarChecked);
     PlacesUIUtils.ptm.doTransaction(txn);
   },
 
@@ -1014,25 +965,29 @@ var gEditItemOverlay = {
                           PlacesUIUtils.getItemDescription(this._itemId));
       break;
     case PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO:
       this._element("loadInSidebarCheckbox").checked =
         PlacesUtils.annotations.itemHasAnnotation(this._itemId,
                                                   PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
       break;
     case PlacesUtils.LMANNO_FEEDURI:
-      var feedURISpec = PlacesUtils.livemarks.getFeedURI(this._itemId).spec;
-      this._initTextField("feedLocationField", feedURISpec);
+      let feedURISpec =
+        PlacesUtils.annotations.getItemAnnotation(this._itemId,
+                                                  PlacesUtils.LMANNO_FEEDURI);
+      this._initTextField("feedLocationField", feedURISpec, true);
       break;
     case PlacesUtils.LMANNO_SITEURI:
-      var siteURISpec = "";
-      var siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
-      if (siteURI)
-        siteURISpec = siteURI.spec;
-      this._initTextField("siteLocationField", siteURISpec);
+      let siteURISpec = "";
+      try {
+        siteURISpec =
+          PlacesUtils.annotations.getItemAnnotation(this._itemId,
+                                                    PlacesUtils.LMANNO_SITEURI);
+      } catch (ex) {}
+      this._initTextField("siteLocationField", siteURISpec, true);
       break;
     }
   },
 
   onItemMoved: function EIO_onItemMoved(aItemId, aOldParent, aOldIndex,
                                         aNewParent, aNewIndex, aItemType) {
     if (aItemId != this._itemId ||
         aNewParent == this._getFolderIdFromMenuList())
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -595,19 +595,17 @@ var PlacesOrganizer = {
     var infoBoxExpanderWrapper = document.getElementById("infoBoxExpanderWrapper");
     var additionalInfoBroadcaster = document.getElementById("additionalInfoBroadcaster");
 
     if (!aNode) {
       infoBoxExpanderWrapper.hidden = true;
       return;
     }
     if (aNode.itemId != -1 &&
-        ((PlacesUtils.nodeIsFolder(aNode) &&
-          !PlacesUtils.nodeIsLivemarkContainer(aNode)) ||
-         PlacesUtils.nodeIsLivemarkItem(aNode))) {
+        PlacesUtils.nodeIsFolder(aNode) && !aNode._feedURI) {
       if (infoBox.getAttribute("minimal") == "true")
         infoBox.setAttribute("wasminimal", "true");
       infoBox.removeAttribute("minimal");
       infoBoxExpanderWrapper.hidden = true;
     }
     else {
       if (infoBox.getAttribute("wasminimal") == "true")
         infoBox.setAttribute("minimal", "true");
@@ -683,18 +681,20 @@ var PlacesOrganizer = {
       var itemId = -1;
       if (concreteId != -1 && useConcreteId)
         itemId = concreteId;
       else if (aSelectedNode.itemId != -1)
         itemId = aSelectedNode.itemId;
       else
         itemId = PlacesUtils._uri(aSelectedNode.uri);
 
-      gEditItemOverlay.initPanel(itemId, { hiddenRows: ["folderPicker"],
-                                           forceReadOnly: readOnly });
+      gEditItemOverlay.initPanel(itemId, { hiddenRows: ["folderPicker"]
+                                         , forceReadOnly: readOnly
+                                         , titleOverride: aSelectedNode.title
+                                         });
 
       // Dynamically generated queries, like history date containers, have
       // itemId !=0 and do not exist in history.  For them the panel is
       // read-only, but empty, since it can't get a valid title for the object.
       // In such a case we force the title using the selectedNode one, for UI
       // polishness.
       if (aSelectedNode.itemId == -1 &&
           (PlacesUtils.nodeIsDay(aSelectedNode) ||
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -1,46 +1,11 @@
-/* -*- 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 History System
- *
- * The Initial Developer of the Original Code is
- * Google Inc.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Brett Wilson <brettw@gmail.com> (Original author)
- *   Asaf Romano <mano@mozilla.com> (JavaScript version)
- *
- * 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 ***** */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 function PlacesTreeView(aFlatList, aOnOpenFlatContainer) {
   this._tree = null;
   this._result = null;
   this._selection = null;
   this._rootNode = null;
   this._rows = [];
   this._flatList = aFlatList;
@@ -124,16 +89,20 @@ PlacesTreeView.prototype = {
    *        A container result node.
    *
    * @return true if aContainer is a plain container, false otherwise.
    */
   _isPlainContainer: function PTV__isPlainContainer(aContainer) {
     if (aContainer._plainContainer !== undefined)
       return aContainer._plainContainer;
 
+    // Livemarks are always plain containers.
+    if (aContainer._feedURI)
+      return aContainer._plainContainer = true;
+
     // We don't know enough about non-query containers.
     if (!(aContainer instanceof Ci.nsINavHistoryQueryResultNode))
       return aContainer._plainContainer = false;
 
     switch (aContainer.queryOptions.resultType) {
       case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY:
       case Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY:
       case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY:
@@ -323,17 +292,18 @@ PlacesTreeView.prototype = {
         }
       }
 
       this._rows[row] = curChild;
       rowsInserted++;
 
       // Recursively do containers.
       if (!this._flatList &&
-          curChild instanceof Ci.nsINavHistoryContainerResultNode) {
+          curChild instanceof Ci.nsINavHistoryContainerResultNode &&
+          !curChild._feedURI) {
         let resource = this._getResourceForNode(curChild);
         let isopen = resource != null &&
                      PlacesUIUtils.localStore.HasAssertion(resource,
                                                            openLiteral,
                                                            trueLiteral, true);
         if (isopen != curChild.containerOpen)
           aToOpen.push(curChild);
         else if (curChild.containerOpen && curChild.childCount > 0)
@@ -620,30 +590,30 @@ PlacesTreeView.prototype = {
 
       // Update parent when inserting the first item, since twisty has changed.
       if (aParentNode.childCount == 1)
         this._tree.invalidateRow(parentRow);
     }
 
     // Compute the new row number of the node.
     let row = -1;
-    if (aNewIndex == 0 || this._isPlainContainer(aParentNode)) {
+    let cc = aParentNode.childCount;
+    if (aNewIndex == 0 || this._isPlainContainer(aParentNode) || cc == 0) {
       // We don't need to worry about sub hierarchies of the parent node
       // if it's a plain container, or if the new node is its first child.
       if (aParentNode == this._rootNode)
         row = aNewIndex;
       else
         row = parentRow + aNewIndex + 1;
     }
     else {
       // Here, we try to find the next visible element in the child list so we
       // can set the new visible index to be right before that.  Note that we
       // have to search down instead of up, because some siblings could have
       // children themselves that would be in the way.
-      let cc = aParentNode.childCount;
       let separatorsAreHidden = PlacesUtils.nodeIsSeparator(aNode) &&
                                 this.isSorted();
       for (let i = aNewIndex + 1; i < cc; i++) {
         let node = aParentNode.getChild(i);
         if (!separatorsAreHidden || PlacesUtils.nodeIsSeparator(node)) {
           // The children have not been shifted so the next item will have what
           // should be our index.
           row = this._getRowForNode(node, false, parentRow, i);
@@ -659,18 +629,20 @@ PlacesTreeView.prototype = {
                                             aNewIndex - 1);
         row = prevIndex + this._countVisibleRowsForNodeAtRow(prevIndex);
       }
     }
 
     this._rows.splice(row, 0, aNode);
     this._tree.rowCountChanged(row, 1);
 
-    if (PlacesUtils.nodeIsContainer(aNode) && PlacesUtils.asContainer(aNode).containerOpen)
+    if (PlacesUtils.nodeIsContainer(aNode) &&
+        PlacesUtils.asContainer(aNode).containerOpen) {
       this.invalidateContainer(aNode);
+    }
   },
 
   /**
    * THIS FUNCTION DOES NOT HANDLE cases where a collapsed node is being
    * removed but the node it is collapsed with is not being removed (this then
    * just swap out the removee with its collapsing partner). The only time
    * when we really remove things is when deleting URIs, which will apply to
    * all collapsees. This function is called sometimes when resorting items.
@@ -809,64 +781,132 @@ PlacesTreeView.prototype = {
     if (aColumnType != this.COLUMN_TYPE_LASTMODIFIED) {
       let lastModifiedColumn =
         this._findColumnByType(this.COLUMN_TYPE_LASTMODIFIED);
       if (lastModifiedColumn && !lastModifiedColumn.hidden)
         this._tree.invalidateCell(row, lastModifiedColumn);
     }
   },
 
+  _populateLivemarkContainer: function PTV__populateLivemarkContainer(aNode) {
+    PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
+      (function (aStatus, aLivemark) {
+        let placesNode = aNode;
+        // Need to check containerOpen since getLivemark is async.
+        if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen)
+          return;
+
+        let children = aLivemark.getNodesForContainer(placesNode);
+        for (let i = 0; i < children.length; i++) {
+          let child = children[i];
+          this.nodeInserted(placesNode, child, i);
+        }
+      }).bind(this));
+  },
+
   nodeTitleChanged: function PTV_nodeTitleChanged(aNode, aNewTitle) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
   },
 
   nodeURIChanged: function PTV_nodeURIChanged(aNode, aNewURI) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_URI);
   },
 
   nodeIconChanged: function PTV_nodeIconChanged(aNode) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
   },
 
   nodeHistoryDetailsChanged:
   function PTV_nodeHistoryDetailsChanged(aNode, aUpdatedVisitDate,
                                          aUpdatedVisitCount) {
+    if (aNode.parent && aNode.parent._feedURI) {
+      // Find the node in the parent.
+      let parentRow = this._flatList ? 0 : this._getRowForNode(aNode.parent);
+      for (let i = parentRow; i < this._rows.length; i++) {
+        let child = this.nodeForTreeIndex(i);
+        if (child.uri == aNode.uri) {
+          delete child._cellProperties;
+          this._invalidateCellValue(child, this.COLUMN_TYPE_TITLE);
+          break;
+        }
+      }
+      return;
+    }
+
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_DATE);
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_VISITCOUNT);
   },
 
   nodeTagsChanged: function PTV_nodeTagsChanged(aNode) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_TAGS);
   },
 
   nodeKeywordChanged: function PTV_nodeKeywordChanged(aNode, aNewKeyword) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_KEYWORD);
   },
 
   nodeAnnotationChanged: function PTV_nodeAnnotationChanged(aNode, aAnno) {
     if (aAnno == PlacesUIUtils.DESCRIPTION_ANNO) {
       this._invalidateCellValue(aNode, this.COLUMN_TYPE_DESCRIPTION);
-    } else if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
-      // The livemark attribute is set as a cell property on the title cell.
-      this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
+    }
+    else if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
+      PlacesUtils.livemarks.getLivemark(
+        { id: aNode.itemId },
+        (function (aStatus, aLivemark) {
+          if (Components.isSuccessCode(aStatus)) {
+            aNode._feedURI = aLivemark.feedURI;
+            if (aNode._cellProperties) {
+              aNode._cellProperties.push(this._getAtomFor("livemark"));
+            }
+            // The livemark attribute is set as a cell property on the title cell.
+            this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
+          }
+        }).bind(this)
+      );
     }
   },
 
   nodeDateAddedChanged: function PTV_nodeDateAddedChanged(aNode, aNewValue) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_DATEADDED);
   },
 
   nodeLastModifiedChanged:
   function PTV_nodeLastModifiedChanged(aNode, aNewValue) {
     this._invalidateCellValue(aNode, this.COLUMN_TYPE_LASTMODIFIED);
   },
 
   containerStateChanged:
   function PTV_containerStateChanged(aNode, aOldState, aNewState) {
     this.invalidateContainer(aNode);
+
+    if (PlacesUtils.nodeIsFolder(aNode) ||
+        (this._flatList && aNode == this._rootNode)) {
+      let queryOptions = PlacesUtils.asQuery(this._rootNode).queryOptions;
+      if (queryOptions.excludeItems) {
+        return;
+      }
+
+      PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
+        (function (aStatus, aLivemark) {
+          if (Components.isSuccessCode(aStatus)) {
+            let shouldInvalidate = !aNode._feedURI;
+            aNode._feedURI = aLivemark.feedURI;
+            if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
+              aLivemark.registerForUpdates(aNode, this);
+              aLivemark.reload();
+              if (shouldInvalidate)
+                this.invalidateContainer(aNode);
+            }
+            else {
+              aLivemark.unregisterForUpdates(aNode);
+            }
+          }
+        }).bind(this)
+      );
+    }
   },
 
   invalidateContainer: function PTV_invalidateContainer(aContainer) {
     NS_ASSERT(this._result, "Need to have a result to update");
     if (!this._tree)
       return;
 
     let startReplacement, replaceCount;
@@ -950,16 +990,23 @@ PlacesTreeView.prototype = {
 
         // If we don't have a parent, we made it all the way to the root
         // and didn't find a match, so we can open our item.
         if (!parent && !item.containerOpen)
           item.containerOpen = true;
       }
     }
 
+    if (aContainer._feedURI) {
+      let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
+      if (!queryOptions.excludeItems) {
+        this._populateLivemarkContainer(aContainer);
+      }
+    }
+
     this._tree.endUpdateBatch();
 
     // Restore selection.
     this._restoreSelection(nodesToReselect, aContainer);
     this.selection.selectEventsSuppressed = false;
   },
 
   _columns: [],
@@ -1104,33 +1151,50 @@ PlacesTreeView.prototype = {
             properties.push(this._getAtomFor("tagContainer"));
           else if (PlacesUtils.nodeIsDay(node))
             properties.push(this._getAtomFor("dayContainer"));
           else if (PlacesUtils.nodeIsHost(node))
             properties.push(this._getAtomFor("hostContainer"));
         }
         else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
                  nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT) {
-          if (PlacesUtils.nodeIsLivemarkContainer(node))
+          if (node._feedURI) {
             properties.push(this._getAtomFor("livemark"));
+          }
+          else {
+            PlacesUtils.livemarks.getLivemark(
+              { id: node.itemId },
+              (function (aStatus, aLivemark) {
+                if (Components.isSuccessCode(aStatus)) {
+                  node._feedURI = aLivemark.feedURI;
+                  node._cellProperties.push(this._getAtomFor("livemark"));
+                  // The livemark attribute is set as a cell property on the title cell.
+                  this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
+                }
+              }).bind(this)
+            );
+          }
         }
 
         if (itemId != -1) {
           let queryName = PlacesUIUtils.getLeftPaneQueryNameFromId(itemId);
           if (queryName)
             properties.push(this._getAtomFor("OrganizerQuery_" + queryName));
         }
       }
       else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
         properties.push(this._getAtomFor("separator"));
       else if (PlacesUtils.nodeIsURI(node)) {
         properties.push(this._getAtomFor(PlacesUIUtils.guessUrlSchemeForUI(node.uri)));
-        if (itemId != -1) {
-          if (PlacesUtils.nodeIsLivemarkContainer(node.parent))
-            properties.push(this._getAtomFor("livemarkItem"));
+
+        if (node.parent._feedURI) {
+          properties.push(this._getAtomFor("livemarkItem"));
+          if (node.accessCount) {
+            properties.push(this._getAtomFor("visited"));
+          }
         }
       }
 
       node._cellProperties = properties;
     }
     for (let i = 0; i < node._cellProperties.length; i++)
       aProperties.AppendElement(node._cellProperties[i]);
   },
@@ -1149,17 +1213,17 @@ PlacesTreeView.prototype = {
       if (this._flatList)
         return true;
 
       // treat non-expandable childless queries as non-containers
       if (PlacesUtils.nodeIsQuery(node)) {
         let parent = node.parent;
         if ((PlacesUtils.nodeIsQuery(parent) ||
              PlacesUtils.nodeIsFolder(parent)) &&
-            !node.hasChildren)
+            !PlacesUtils.asQuery(node).hasChildren)
           return PlacesUtils.asQuery(parent).queryOptions.expandQueries;
       }
       return true;
     }
     return false;
   },
 
   isContainerOpen: function PTV_isContainerOpen(aRow) {
@@ -1169,18 +1233,24 @@ PlacesTreeView.prototype = {
     // All containers are listed in the rows array.
     return this._rows[aRow].containerOpen;
   },
 
   isContainerEmpty: function PTV_isContainerEmpty(aRow) {
     if (this._flatList)
       return true;
 
+    let node = this._rows[aRow];
+    if (node._feedURI) {
+      let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
+      return queryOptions.excludeItems;
+    }
+
     // All containers are listed in the rows array.
-    return !this._rows[aRow].hasChildren;
+    return !node.hasChildren;
   },
 
   isSeparator: function PTV_isSeparator(aRow) {
     // All separators are listed in the rows array.
     let node = this._rows[aRow];
     return node && PlacesUtils.nodeIsSeparator(node);
   },
 
@@ -1413,25 +1483,28 @@ PlacesTreeView.prototype = {
       throw Cr.NS_ERROR_UNEXPECTED;
 
     let node = this._rows[aRow];
     if (this._flatList && this._openContainerCallback) {
       this._openContainerCallback(node);
       return;
     }
 
-    let resource = this._getResourceForNode(node);
-    if (resource) {
-      const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
-      const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true");
+    // Persist containers open status, but never persist livemarks.
+    if (!node._feedURI) {
+      let resource = this._getResourceForNode(node);
+      if (resource) {
+        const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
+        const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true");
 
-      if (node.containerOpen)
-        PlacesUIUtils.localStore.Unassert(resource, openLiteral, trueLiteral);
-      else
-        PlacesUIUtils.localStore.Assert(resource, openLiteral, trueLiteral, true);
+        if (node.containerOpen)
+          PlacesUIUtils.localStore.Unassert(resource, openLiteral, trueLiteral);
+        else
+          PlacesUIUtils.localStore.Assert(resource, openLiteral, trueLiteral, true);
+      }
     }
 
     node.containerOpen = !node.containerOpen;
   },
 
   cycleHeader: function PTV_cycleHeader(aColumn) {
     if (!this._result)
       throw Cr.NS_ERROR_UNEXPECTED;
@@ -1564,20 +1637,18 @@ PlacesTreeView.prototype = {
     // Only bookmark-nodes are editable, and those are never built lazily
     let node = this._rows[aRow];
     if (!node || node.itemId == -1)
       return false;
 
     // The following items are never editable:
     // * Read-only items.
     // * places-roots
-    // * livemark items
     // * separators
     if (PlacesUtils.nodeIsReadOnly(node) ||
-        PlacesUtils.nodeIsLivemarkItem(node) ||
         PlacesUtils.nodeIsSeparator(node))
       return false;
 
     if (PlacesUtils.nodeIsFolder(node)) {
       let itemId = PlacesUtils.getConcreteItemId(node);
       if (PlacesUtils.isRootItem(itemId))
         return false;
     }
--- a/browser/components/places/tests/browser/browser_457473_no_copy_guid.js
+++ b/browser/components/places/tests/browser/browser_457473_no_copy_guid.js
@@ -36,17 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 function test() {
   // sanity check
   ok(PlacesUtils, "checking PlacesUtils, running in chrome context?");
   ok(PlacesUIUtils, "checking PlacesUIUtils, running in chrome context?");
 
   /*
-  - create, a test folder, add bookmark, separator, livemark to it
+  - create, a test folder, add bookmark, separator to it
   - fetch guids for all
   - copy the folder
   - test that guids are all different
   - undo copy
   - redo copy
   - test that guids for the copy stay the same
   */
 
@@ -61,20 +61,16 @@ function test() {
   testRootNode.containerOpen = true;
   is(testRootNode.childCount, 0, "confirm test root node is a container, and is empty");
 
   // create folder A, fill it w/ each item type
   var folderAId = PlacesUtils.bookmarks.createFolder(testRootId, "A", -1);
   PlacesUtils.bookmarks.insertBookmark(folderAId, PlacesUtils._uri("http://foo"),
                                        -1, "test bookmark");
   PlacesUtils.bookmarks.insertSeparator(folderAId, -1);
-  PlacesUtils.livemarks.createLivemarkFolderOnly(folderAId, "test livemark",
-                                                 PlacesUtils._uri("http://test"),
-                                                 PlacesUtils._uri("http://test"), -1);
-
   var folderANode = testRootNode.getChild(0);
   var folderAGUIDs = getGUIDs(folderANode);
 
   // test the test function
   ok(checkGUIDs(folderANode, folderAGUIDs, true), "confirm guid test works");
 
   // serialize the folder
   var serializedNode = PlacesUtils.wrapNode(folderANode, PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER);
@@ -120,18 +116,17 @@ function test() {
 }
 
 function getGUIDs(aNode) {
   PlacesUtils.asContainer(aNode);
   aNode.containerOpen = true;
   var GUIDs = {
     folder: PlacesUtils.bookmarks.getItemGUID(aNode.itemId),
     bookmark: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(0).itemId),
-    separator: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(1).itemId),
-    livemark: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(2).itemId)
+    separator: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(1).itemId)
   };
   aNode.containerOpen = false;
   return GUIDs;
 }
 
 function checkGUIDs(aFolderNode, aGUIDs, aShouldMatch) {
 
   function check(aNode, aGUID, aEquals) {
@@ -139,14 +134,13 @@ function checkGUIDs(aFolderNode, aGUIDs,
     return aEquals ? (nodeGUID == aGUID) : (nodeGUID != aGUID);
   }
 
   PlacesUtils.asContainer(aFolderNode);
   aFolderNode.containerOpen = true;
 
   var allMatch = check(aFolderNode, aGUIDs.folder, aShouldMatch) &&
                  check(aFolderNode.getChild(0), aGUIDs.bookmark, aShouldMatch) &&
-                 check(aFolderNode.getChild(1), aGUIDs.separator, aShouldMatch) &&
-                 check(aFolderNode.getChild(2), aGUIDs.livemark, aShouldMatch);
+                 check(aFolderNode.getChild(1), aGUIDs.separator, aShouldMatch)
 
   aFolderNode.containerOpen = false;
   return allMatch;
 }
--- a/browser/components/places/tests/browser/browser_library_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_library_views_liveupdate.js
@@ -90,21 +90,16 @@ function startTest() {
   bs.setItemTitle(id, "bmf_edited");
   addedBookmarks.push(id);
   id = bs.insertBookmark(id,
                          PlacesUtils._uri("http://bmf1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "bmf1");
   addedBookmarks.push(id);
   bs.moveItem(id, bs.bookmarksMenuFolder, 0);
-  id = PlacesUtils.livemarks.createLivemarkFolderOnly(
-    bs.bookmarksMenuFolder, "bml",
-    PlacesUtils._uri("http://bml.siteuri.mozilla.org/"),
-    PlacesUtils._uri("http://bml.feeduri.mozilla.org/"), bs.DEFAULT_INDEX);
-  addedBookmarks.push(id);
 
   // TOOLBAR
   ok(true, "*** Acting on toolbar bookmarks");
   bs.insertBookmark(bs.toolbarFolder,
                     PlacesUtils._uri("http://tb1.mozilla.org/"),
                     bs.DEFAULT_INDEX,
                     "tb1");
   bs.setItemTitle(id, "tb1_edited");
@@ -123,20 +118,16 @@ function startTest() {
   bs.setItemTitle(id, "tbf_edited");
   addedBookmarks.push(id);
   id = bs.insertBookmark(id,
                          PlacesUtils._uri("http://tbf1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "bmf1");
   addedBookmarks.push(id);
   bs.moveItem(id, bs.toolbarFolder, 0);
-  id = PlacesUtils.livemarks.createLivemarkFolderOnly(
-    bs.toolbarFolder, "tbl", PlacesUtils._uri("http://tbl.siteuri.mozilla.org/"),
-    PlacesUtils._uri("http://tbl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX);
-  addedBookmarks.push(id);
 
   // UNSORTED
   ok(true, "*** Acting on unsorted bookmarks");
   id = bs.insertBookmark(bs.unfiledBookmarksFolder,
                          PlacesUtils._uri("http://ub1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "ub1");
   bs.setItemTitle(id, "ub1_edited");
@@ -155,21 +146,16 @@ function startTest() {
   bs.setItemTitle(id, "ubf_edited");
   addedBookmarks.push(id);
   id = bs.insertBookmark(id,
                          PlacesUtils._uri("http://ubf1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "ubf1");
   addedBookmarks.push(id);
   bs.moveItem(id, bs.unfiledBookmarksFolder, 0);
-  id = PlacesUtils.livemarks.createLivemarkFolderOnly(
-    bs.unfiledBookmarksFolder, "bubl",
-    PlacesUtils._uri("http://bubl.siteuri.mozilla.org/"),
-    PlacesUtils._uri("http://bubl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX);
-  addedBookmarks.push(id);
 
   // Remove all added bookmarks.
   addedBookmarks.forEach(function (aItem) {
     // If we remove an item after its containing folder has been removed,
     // this will throw, but we can ignore that.
     try {
       bs.removeItem(aItem);
     } catch (ex) {}
@@ -196,37 +182,17 @@ function finishTest() {
  */
 var bookmarksObserver = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsINavBookmarkObserver
   , Ci.nsIAnnotationObserver
   ]),
 
   // nsIAnnotationObserver
-  onItemAnnotationSet: function(aItemId, aAnnotationName) {
-    if (aAnnotationName == PlacesUtils.LMANNO_FEEDURI) {
-      // Check that item is recognized as a livemark.
-      let validator = function(aTreeRowIndex) {
-        let tree = gLibrary.PlacesOrganizer._places;
-        let livemarkAtom = Cc["@mozilla.org/atom-service;1"].
-                           getService(Ci.nsIAtomService).
-                           getAtom("livemark");
-        let properties = Cc["@mozilla.org/supports-array;1"].
-                         createInstance(Ci.nsISupportsArray);
-        tree.view.getCellProperties(aTreeRowIndex,
-                                    tree.columns.getColumnAt(0),
-                                    properties);
-        return properties.GetIndexOf(livemarkAtom) != -1;
-      };
-
-      var [node, index, valid] = getNodeForTreeItem(aItemId, gLibrary.PlacesOrganizer._places, validator);
-      isnot(node, null, "Found new Places node in left pane at " + index);
-      ok(valid, "Node is recognized as a livemark");
-    }
-  },
+  onItemAnnotationSet: function() {},
   onItemAnnotationRemoved: function() {},
   onPageAnnotationSet: function() {},
   onPageAnnotationRemoved: function() {},
 
   // nsINavBookmarkObserver
   onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex, aItemType,
                                         aURI) {
     var node = null;
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -113,21 +113,16 @@ function startTest() {
   addedBookmarks.push(id);
   id = bs.insertBookmark(id,
                          PlacesUtils._uri("http://bmf1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "bmf1");
   bs.setItemTitle(id, "bmf1_edited");
   addedBookmarks.push(id);
   bs.moveItem(id, bs.bookmarksMenuFolder, 0);
-  id = PlacesUtils.livemarks.createLivemarkFolderOnly(
-    bs.bookmarksMenuFolder, "bml",
-    PlacesUtils._uri("http://bml.siteuri.mozilla.org/"),
-    PlacesUtils._uri("http://bml.feeduri.mozilla.org/"), bs.DEFAULT_INDEX);
-  addedBookmarks.push(id);
 
   // TOOLBAR
   info("*** Acting on toolbar bookmarks");
   id = bs.insertBookmark(bs.toolbarFolder,
                          PlacesUtils._uri("http://tb1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "tb1");
   bs.setItemTitle(id, "tb1_edited");
@@ -149,20 +144,16 @@ function startTest() {
   addedBookmarks.push(id);
   id = bs.insertBookmark(id,
                          PlacesUtils._uri("http://tbf1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "tbf1");
   bs.setItemTitle(id, "tbf1_edited");
   addedBookmarks.push(id);
   bs.moveItem(id, bs.toolbarFolder, 0);
-  id = PlacesUtils.livemarks.createLivemarkFolderOnly(
-    bs.toolbarFolder, "tbl", PlacesUtils._uri("http://tbl.siteuri.mozilla.org/"),
-    PlacesUtils._uri("http://tbl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX);
-  addedBookmarks.push(id);
 
   // UNSORTED
   info("*** Acting on unsorted bookmarks");
   id = bs.insertBookmark(bs.unfiledBookmarksFolder,
                          PlacesUtils._uri("http://ub1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "ub1");
   bs.setItemTitle(id, "ub1_edited");
@@ -182,21 +173,16 @@ function startTest() {
   addedBookmarks.push(id);
   id = bs.insertBookmark(id,
                          PlacesUtils._uri("http://ubf1.mozilla.org/"),
                          bs.DEFAULT_INDEX,
                          "bubf1");
   bs.setItemTitle(id, "bubf1_edited");
   addedBookmarks.push(id);
   bs.moveItem(id, bs.unfiledBookmarksFolder, 0);
-  id = PlacesUtils.livemarks.createLivemarkFolderOnly(
-    bs.unfiledBookmarksFolder, "bubl",
-    PlacesUtils._uri("http://bubl.siteuri.mozilla.org/"),
-    PlacesUtils._uri("http://bubl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX);
-  addedBookmarks.push(id);
 
   // Remove all added bookmarks.
   addedBookmarks.forEach(function (aItem) {
     // If we remove an item after its containing folder has been removed,
     // this will throw, but we can ignore that.
     try {
       bs.removeItem(aItem);
     } catch (ex) {}
@@ -228,48 +214,17 @@ function finishTest() {
  */
 var bookmarksObserver = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsINavBookmarkObserver
   , Ci.nsIAnnotationObserver
   ]),
 
   // nsIAnnotationObserver
-  onItemAnnotationSet: function(aItemId, aAnnotationName) {
-    if (aAnnotationName == PlacesUtils.LMANNO_FEEDURI) {
-      var views = getViewsForFolder(PlacesUtils.bookmarks.getFolderIdForItem(aItemId));
-      ok(views.length > 0, "Found affected views (" + views.length + "): " + views);
-
-      // Check that item is recognized as a livemark.
-      let validator = function(aElementOrTreeIndex) {
-        if (typeof(aElementOrTreeIndex) == "number") {
-          var sidebar = document.getElementById("sidebar");
-          var tree = sidebar.contentDocument.getElementById("bookmarks-view");
-          let livemarkAtom = Cc["@mozilla.org/atom-service;1"].
-                             getService(Ci.nsIAtomService).
-                             getAtom("livemark");
-          let properties = Cc["@mozilla.org/supports-array;1"].
-                           createInstance(Ci.nsISupportsArray);
-          tree.view.getCellProperties(aElementOrTreeIndex,
-                                      tree.columns.getColumnAt(0),
-                                      properties);
-          return properties.GetIndexOf(livemarkAtom) != -1;
-        }
-        else {
-          return aElementOrTreeIndex.hasAttribute("livemark");
-        }
-      };
-
-      for (var i = 0; i < views.length; i++) {
-        var [node, index, valid] = searchItemInView(aItemId, views[i], validator);
-        isnot(node, null, "Found new Places node in " + views[i] + " at " + index);
-        ok(valid, "Node is recognized as a livemark");
-      }
-    }
-  },
+  onItemAnnotationSet: function() {},
   onItemAnnotationRemoved: function() {},
   onPageAnnotationSet: function() {},
   onPageAnnotationRemoved: function() {},
 
   // nsINavBookmarkObserver
   onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex,
                                         aItemType, aURI) {
     var views = getViewsForFolder(aFolderId);
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -97,15 +97,15 @@ let (XULAppInfo = {
 
 
 const FILENAME_BOOKMARKS_HTML = "bookmarks.html";
 let (backup_date = new Date().toLocaleFormat("%Y-%m-%d")) {
   const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json";
 }
 
 // Smart bookmarks constants.
-const SMART_BOOKMARKS_VERSION = 2;
+const SMART_BOOKMARKS_VERSION = 3;
 const SMART_BOOKMARKS_ON_TOOLBAR = 1;
 const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.
 
 // Default bookmarks constants.
 const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1;
 const DEFAULT_BOOKMARKS_ON_MENU = 1;
--- a/browser/components/places/tests/unit/test_384370.js
+++ b/browser/components/places/tests/unit/test_384370.js
@@ -31,29 +31,25 @@
  * 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 ***** */
 
-// The following components need to be initialized to perform tests without
-// asserting in debug builds (Bug 448804).
-Cc["@mozilla.org/browser/livemark-service;2"].getService(Ci.nsILivemarkService);
-Cc["@mozilla.org/feed-processor;1"].createInstance(Ci.nsIFeedProcessor);
-
 const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
 const DESCRIPTION_ANNO = "bookmarkProperties/description";
 const POST_DATA_ANNO = "bookmarkProperties/POSTData";
 
 do_check_eq(typeof PlacesUtils, "object");
 
 // main
 function run_test() {
+  do_test_pending();
   /*
     HTML+FEATURES SUMMARY:
     - import legacy bookmarks
     - export as json, import, test (tests integrity of html > json)
     - export as html, import, test (tests integrity of json > html)
 
     BACKUP/RESTORE SUMMARY:
     - create a bookmark in each root
@@ -87,31 +83,35 @@ function run_test() {
   // 2. run the test-suite
   // Note: we do not empty the db before this import to catch bugs like 380999
   try {
     importer.importHTMLFromFile(bookmarksFileOld, true);
   } catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
   populate();
   validate();
 
-  // Test exporting a Places canonical json file.
-  // 1. export to bookmarks.exported.json
-  // 2. empty bookmarks db
-  // 3. import bookmarks.exported.json
-  // 4. run the test-suite
-  try {
-    PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
-  } catch(ex) { do_throw("couldn't export to file: " + ex); }
-  LOG("exported json"); 
-  try {
-    PlacesUtils.restoreBookmarksFromJSONFile(jsonFile);
-  } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
-  LOG("imported json"); 
-  validate();
-  LOG("validated import"); 
+  waitForAsyncUpdates(function () {
+    // Test exporting a Places canonical json file.
+    // 1. export to bookmarks.exported.json
+    // 2. empty bookmarks db
+    // 3. import bookmarks.exported.json
+    // 4. run the test-suite
+    try {
+      PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
+    } catch(ex) { do_throw("couldn't export to file: " + ex); }
+    LOG("exported json");
+    try {
+      PlacesUtils.restoreBookmarksFromJSONFile(jsonFile);
+    } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
+    LOG("imported json");
+    validate();
+    LOG("validated import");
+
+    waitForAsyncUpdates(do_test_finished);
+  });
 }
 
 var tagData = [
   { uri: uri("http://slint.us"), tags: ["indie", "kentucky", "music"] },
   { uri: uri("http://en.wikipedia.org/wiki/Diplodocus"), tags: ["dinosaur", "dj", "rad word"] }
 ];
 
 var bookmarkData = [
@@ -238,24 +238,27 @@ function testToolbarFolder() {
 
   // child count (add 2 for pre-existing items)
   do_check_eq(toolbar.childCount, bookmarkData.length + 2);
   
   // livemark
   var livemark = toolbar.getChild(1);
   // title
   do_check_eq("Latest Headlines", livemark.title);
-  // livemark check
-  do_check_true(PlacesUtils.livemarks.isLivemark(livemark.itemId));
-  // site url
-  do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
-              PlacesUtils.livemarks.getSiteURI(livemark.itemId).spec);
-  // feed url
-  do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
-              PlacesUtils.livemarks.getFeedURI(livemark.itemId).spec);
+
+  PlacesUtils.livemarks.getLivemark(
+    { id: livemark.itemId },
+    function (aStatus, aLivemark) {
+      do_check_true(Components.isSuccessCode(aStatus));
+      do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
+                  aLivemark.siteURI.spec);
+      do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
+                  aLivemark.feedURI.spec);
+    }
+  );
 
   // test added bookmark data
   var child = toolbar.getChild(2);
   do_check_eq(child.uri, bookmarkData[0].uri.spec);
   do_check_eq(child.title, bookmarkData[0].title);
   child = toolbar.getChild(3);
   do_check_eq(child.uri, bookmarkData[1].uri.spec);
   do_check_eq(child.title, bookmarkData[1].title);
--- a/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js
+++ b/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js
@@ -44,78 +44,80 @@
 // Get Services
 var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
          getService(Ci.nsINavHistoryService);
 var dbConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
 var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
          getService(Ci.nsINavBookmarksService);
 var as = Cc["@mozilla.org/browser/annotation-service;1"].
          getService(Ci.nsIAnnotationService);
-var lms = Cc["@mozilla.org/browser/livemark-service;2"].
-          getService(Ci.nsILivemarkService);
 var icos = Cc["@mozilla.org/browser/favicon-service;1"].
            getService(Ci.nsIFaviconService);
 var ps = Cc["@mozilla.org/preferences-service;1"].
          getService(Ci.nsIPrefBranch);
 var ies = Cc["@mozilla.org/browser/places/import-export-service;1"].
           getService(Ci.nsIPlacesImportExportService);
 
 const DESCRIPTION_ANNO = "bookmarkProperties/description";
 const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
 const POST_DATA_ANNO = "bookmarkProperties/POSTData";
 
 const TEST_FAVICON_PAGE_URL = "http://en-US.www.mozilla.com/en-US/firefox/central/";
 const TEST_FAVICON_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
 
-// main
 function run_test() {
+  do_test_pending();
+
   // avoid creating the places smart folder during tests
   ps.setIntPref("browser.places.smartBookmarksVersion", -1);
 
   // import bookmarks from corrupt file
   var corruptBookmarksFile = do_get_file("bookmarks.corrupt.html");
   try {
     ies.importHTMLFromFile(corruptBookmarksFile, true);
   } catch(ex) { do_throw("couldn't import corrupt bookmarks file: " + ex); }
 
   // Check that every bookmark is correct
   // Corrupt bookmarks should not have been imported
   database_check();
-
-  // Create corruption in database
-  var corruptItemId = bs.insertBookmark(bs.toolbarFolder,
-                                        uri("http://test.mozilla.org"),
-                                        bs.DEFAULT_INDEX, "We love belugas");
-  var stmt = dbConn.createStatement("UPDATE moz_bookmarks SET fk = NULL WHERE id = :itemId");
-  stmt.params.itemId = corruptItemId;
-  stmt.execute();
-  stmt.finalize();
+  waitForAsyncUpdates(function() {
+    // Create corruption in database
+    var corruptItemId = bs.insertBookmark(bs.toolbarFolder,
+                                          uri("http://test.mozilla.org"),
+                                          bs.DEFAULT_INDEX, "We love belugas");
+    var stmt = dbConn.createStatement("UPDATE moz_bookmarks SET fk = NULL WHERE id = :itemId");
+    stmt.params.itemId = corruptItemId;
+    stmt.execute();
+    stmt.finalize();
 
-  // Export bookmarks
-  var bookmarksFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
-  bookmarksFile.append("bookmarks.exported.html");
-  if (bookmarksFile.exists())
-    bookmarksFile.remove(false);
-  bookmarksFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
-  if (!bookmarksFile.exists())
-    do_throw("couldn't create file: bookmarks.exported.html");
-  try {
-    ies.exportHTMLToFile(bookmarksFile);
-  } catch(ex) { do_throw("couldn't export to bookmarks.exported.html: " + ex); }
+    // Export bookmarks
+    var bookmarksFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
+    bookmarksFile.append("bookmarks.exported.html");
+    if (bookmarksFile.exists())
+      bookmarksFile.remove(false);
+    bookmarksFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
+    if (!bookmarksFile.exists())
+      do_throw("couldn't create file: bookmarks.exported.html");
+    try {
+      ies.exportHTMLToFile(bookmarksFile);
+    } catch(ex) { do_throw("couldn't export to bookmarks.exported.html: " + ex); }
 
-  // Clear all bookmarks
-  remove_all_bookmarks();
+    // Clear all bookmarks
+    remove_all_bookmarks();
 
-  // Import bookmarks
-  try {
-    ies.importHTMLFromFile(bookmarksFile, true);
-  } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
+    // Import bookmarks
+    try {
+      ies.importHTMLFromFile(bookmarksFile, true);
+    } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
 
-  // Check that every bookmark is correct
-  database_check();
+    // Check that every bookmark is correct
+    database_check();
+
+    waitForAsyncUpdates(do_test_finished);
+  });
 }
 
 /*
  * Check for imported bookmarks correctness
  */
 function database_check() {
   // BOOKMARKS MENU
   var query = hs.getNewQuery();
@@ -187,24 +189,26 @@ function database_check() {
   var toolbar = result.root;
   toolbar.containerOpen = true;
   do_check_eq(toolbar.childCount, 3);
   
   // livemark
   var livemark = toolbar.getChild(1);
   // title
   do_check_eq("Latest Headlines", livemark.title);
-  // livemark check
-  do_check_true(lms.isLivemark(livemark.itemId));
-  // site url
-  do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
-              lms.getSiteURI(livemark.itemId).spec);
-  // feed url
-  do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
-              lms.getFeedURI(livemark.itemId).spec);
+  PlacesUtils.livemarks.getLivemark(
+    { id: livemark.itemId },
+    function (aStatus, aLivemark) {
+      do_check_true(Components.isSuccessCode(aStatus));
+      do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
+                  aLivemark.siteURI.spec);
+      do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
+                  aLivemark.feedURI.spec);
+    }
+  );
 
   // cleanup
   toolbar.containerOpen = false;
 
   // UNFILED BOOKMARKS
   query.setFolders([bs.unfiledBookmarksFolder], 1);
   result = hs.executeQuery(query, hs.getNewQueryOptions());
   var unfiledBookmarks = result.root;
--- a/browser/components/places/tests/unit/test_bookmarks_html.js
+++ b/browser/components/places/tests/unit/test_bookmarks_html.js
@@ -78,17 +78,16 @@ let test_bookmarks = {
     },
   ],
   toolbar: [
     { title: "Getting Started",
       url: "http://en-us.www.mozilla.com/en-US/firefox/central/",
       icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
     },
     { title: "Latest Headlines",
-      description: "Livemark test comment",
       url: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
       feedUrl: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
     }
   ],
   unfiled: [
     { title: "Example.tld",
       url: "http://example.tld/",
     },
@@ -100,16 +99,20 @@ let gBookmarksFileOld;
 // Places bookmarks.html file pointer.
 let gBookmarksFileNew;
 
 let importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
                getService(Ci.nsIPlacesImportExportService);
 
 function run_test()
 {
+  run_next_test();
+}
+
+add_test(function setup() {
   // Avoid creating smart bookmarks during the test.
   Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1);
 
   // File pointer to legacy bookmarks file.
   gBookmarksFileOld = do_get_file("bookmarks.preplaces.html");
 
   // File pointer to a new Places-exported bookmarks file.
   gBookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
@@ -126,41 +129,49 @@ function run_test()
   // Test importing a pre-Places canonical bookmarks file.
   // 1. import bookmarks.preplaces.html
   // 2. run the test-suite
   // Note: we do not empty the db before this import to catch bugs like 380999
   try {
     importer.importHTMLFromFile(gBookmarksFileOld, true);
   } catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
 
-  testImportedBookmarks();
+  waitForAsyncUpdates(function () {
+    testImportedBookmarks();
 
-  // Prepare for next tests.
-  try {
-    importer.exportHTMLToFile(gBookmarksFileNew);
-  } catch(ex) { do_throw("couldn't export to file: " + ex); }
+    // Prepare for next tests.
+    try {
+      importer.exportHTMLToFile(gBookmarksFileNew);
+    } catch(ex) { do_throw("couldn't export to file: " + ex); }
 
-  remove_all_bookmarks();
-  run_next_test();
-}
+    waitForAsyncUpdates(function () {
+      remove_all_bookmarks();
+      run_next_test();
+    });
+  });
+});
 
 add_test(function test_import_new()
 {
   // Test importing a Places bookmarks.html file.
   // 1. import bookmarks.exported.html
   // 2. run the test-suite
 
   try {
     importer.importHTMLFromFile(gBookmarksFileNew, true);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
 
-  testImportedBookmarks();
+  waitForAsyncUpdates(function () {
+    testImportedBookmarks();
 
-  remove_all_bookmarks();
-  run_next_test();
+    waitForAsyncUpdates(function () {
+      remove_all_bookmarks();
+      run_next_test();
+    });
+  });
 });
 
 add_test(function test_emptytitle_export()
 {
   // Test exporting and importing with an empty-titled bookmark.
   // 1. import bookmarks
   // 1. create an empty-titled bookmark.
   // 2. export to bookmarks.exported.html
@@ -184,28 +195,32 @@ add_test(function test_emptytitle_export
   } catch(ex) { do_throw("couldn't export to file: " + ex); }
 
   remove_all_bookmarks();
 
   try {
     importer.importHTMLFromFile(gBookmarksFileNew, true);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
 
-  testImportedBookmarks();
+  waitForAsyncUpdates(function () {
+    testImportedBookmarks();
 
-  // Cleanup.
-  test_bookmarks.unfiled.pop();
-  PlacesUtils.bookmarks.removeItem(id);
+    // Cleanup.
+    test_bookmarks.unfiled.pop();
+    PlacesUtils.bookmarks.removeItem(id);
 
-  try {
-    importer.exportHTMLToFile(gBookmarksFileNew);
-  } catch(ex) { do_throw("couldn't export to file: " + ex); }
+    try {
+      importer.exportHTMLToFile(gBookmarksFileNew);
+    } catch(ex) { do_throw("couldn't export to file: " + ex); }
 
-  remove_all_bookmarks();
-  run_next_test();
+    waitForAsyncUpdates(function () {
+      remove_all_bookmarks();
+      run_next_test();
+    });
+  });
 });
 
 add_test(function test_import_preplaces_to_folder()
 {
   // Test importing a pre-Places canonical bookmarks file to a specific folder.
   // 1. create a new folder
   // 2. import bookmarks.preplaces.html to that folder
   // 3. run the test-suite
@@ -213,21 +228,25 @@ add_test(function test_import_preplaces_
   let testFolder = PlacesUtils.bookmarks.createFolder(
     PlacesUtils.bookmarksMenuFolderId, "test-import",
     PlacesUtils.bookmarks.DEFAULT_INDEX
   );
   try {
     importer.importHTMLFromFileToFolder(gBookmarksFileOld, testFolder, false);
   } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
 
-  // Import-to-folder creates subfolders for toolbar and unfiled.
-  testImportedBookmarksToFolder(testFolder);
+  waitForAsyncUpdates(function () {
+    // Import-to-folder creates subfolders for toolbar and unfiled.
+    testImportedBookmarksToFolder(testFolder);
 
-  remove_all_bookmarks();
-  run_next_test();
+    waitForAsyncUpdates(function () {
+      remove_all_bookmarks();
+      run_next_test();
+    });
+  });
 });
 
 add_test(function test_import_to_folder()
 {
   // Test importing a Places canonical bookmarks file to a specific folder.
   // 1. create a new folder
   // 2. import bookmarks.exported.html to that folder
   // 3. run the test-suite
@@ -235,21 +254,25 @@ add_test(function test_import_to_folder(
   let testFolder = PlacesUtils.bookmarks.createFolder(
     PlacesUtils.bookmarksMenuFolderId, "test-import",
     PlacesUtils.bookmarks.DEFAULT_INDEX
   );
   try {
     importer.importHTMLFromFileToFolder(gBookmarksFileNew, testFolder, false);
   } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
 
-  // Import-to-folder creates subfolders for toolbar and unfiled.
-  testImportedBookmarksToFolder(testFolder);
+  waitForAsyncUpdates(function () {
+    // Import-to-folder creates subfolders for toolbar and unfiled.
+    testImportedBookmarksToFolder(testFolder);
 
-  remove_all_bookmarks();
-  run_next_test();
+    waitForAsyncUpdates(function () {
+      remove_all_bookmarks();
+      run_next_test();
+    });
+  });
 });
 
 add_test(function test_import_ontop()
 {
   // Test importing the exported bookmarks.html file *on top of* the existing
   // bookmarks.
   // 1. empty bookmarks db
   // 2. import the exported bookmarks file
@@ -262,20 +285,24 @@ add_test(function test_import_ontop()
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
   try {
     importer.exportHTMLToFile(gBookmarksFileNew);
   } catch(ex) { do_throw("couldn't export to file: " + ex); }
   try {
     importer.importHTMLFromFile(gBookmarksFileNew, true);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
 
-  testImportedBookmarks();
+  waitForAsyncUpdates(function () {
+    testImportedBookmarks();
 
-  remove_all_bookmarks();
-  run_next_test();
+    waitForAsyncUpdates(function () {
+      remove_all_bookmarks();
+      run_next_test();
+    });
+  });
 });
 
 function testImportedBookmarks()
 {
   for (let group in test_bookmarks) {
     let root;
     switch (group) {
       case "menu":
@@ -345,18 +372,24 @@ function checkItem(aExpected, aNode)
           do_check_eq(PlacesUtils.bookmarks.getItemDateAdded(id),
                       aExpected.dateAdded);
         break;
       case "lastModified":
           do_check_eq(PlacesUtils.bookmarks.getItemLastModified(id),
                       aExpected.lastModified);
         break;
       case "url":
-        if (!PlacesUtils.livemarks.isLivemark(id))
-          do_check_eq(aNode.uri, aExpected.url);
+        PlacesUtils.livemarks.getLivemark(
+          { id: id },
+          function (aStatus, aLivemark) {
+            if (!Components.isSuccessCode(aStatus)) {
+              do_check_eq(aNode.uri, aExpected.url);
+            }
+          }
+        );
         break;
       case "icon":
         let faviconURI = PlacesUtils.favicons.getFaviconForPage(
           NetUtil.newURI(aExpected.url)
         );
         let dataURL = PlacesUtils.favicons.getFaviconDataAsDataURL(faviconURI);
         // Avoid do_check_eq for console spam.
         do_check_true(dataURL == aExpected.icon);
@@ -373,21 +406,24 @@ function checkItem(aExpected, aNode)
                                .getItemAnnotation(id, PlacesUtils.POST_DATA_ANNO),
                     aExpected.postData);
         break;
       case "charset":
         do_check_eq(PlacesUtils.history.getCharsetForURI(NetUtil.newURI(aNode.uri)),
                     aExpected.charset);
         break;
       case "feedUrl":
-        do_check_true(PlacesUtils.livemarks.isLivemark(id));
-        do_check_eq(PlacesUtils.livemarks.getSiteURI(id).spec,
-                    aExpected.url);
-        do_check_eq(PlacesUtils.livemarks.getFeedURI(id).spec,
-                    aExpected.feedUrl);
+        PlacesUtils.livemarks.getLivemark(
+          { id: id },
+          function (aStatus, aLivemark) {
+            do_check_true(Components.isSuccessCode(aStatus));
+            do_check_eq(aLivemark.siteURI.spec, aExpected.url);
+            do_check_eq(aLivemark.feedURI.spec, Expected.feedUrl);
+          }
+        );
         break;
       case "children":
         let folder = aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
         do_check_eq(folder.hasChildren, aExpected.children.length > 0);
         folder.containerOpen = true;
         do_check_eq(folder.childCount, aExpected.children.length);
 
         aExpected.children.forEach(function (item, index) checkItem(item, folder.getChild(index)));
--- a/browser/components/places/tests/unit/test_placesTxn.js
+++ b/browser/components/places/tests/unit/test_placesTxn.js
@@ -34,17 +34,16 @@
  * 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 ***** */
 
 var bmsvc = PlacesUtils.bookmarks;
-var lmsvc = PlacesUtils.livemarks;
 var ptSvc = PlacesUIUtils.ptm;
 var tagssvc = PlacesUtils.tagging;
 var annosvc = PlacesUtils.annotations;
 
 // create and add bookmarks observer
 var observer = {
   onBeginUpdateBatch: function() {
     this._beginUpdateBatch = true;
@@ -414,94 +413,16 @@ function run_test() {
   do_check_eq(observer._itemChangedId, bkmk1Id);
   do_check_eq(observer._itemChangedProperty, "keyword");
   do_check_eq(observer._itemChangedValue, "kw1"); 
   txn11.undoTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
   do_check_eq(observer._itemChangedProperty, "keyword");
   do_check_eq(observer._itemChangedValue, ""); 
 
-  // Testing create livemark
-  var txn12 = ptSvc.createLivemark(uri("http://feeduri.com"),
-                                   uri("http://siteuri.com"),
-                                   "Livemark1", root);
-  txn12.doTransaction();
-  var lvmkId = observer._itemAddedId;
-  do_check_true(lmsvc.isLivemark(lvmkId));
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/");
-  txn12.undoTransaction();
-  do_check_false(lmsvc.isLivemark(lvmkId));
-  txn12.redoTransaction();
-  lvmkId = observer._itemAddedId;
-  do_check_true(lmsvc.isLivemark(lvmkId));
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/");
-
-  // editLivemarkSiteURI
-  var txn13 = ptSvc.editLivemarkSiteURI(lvmkId, uri("http://new-siteuri.com/"));
-  txn13.doTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/siteURI");
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://new-siteuri.com/");
-  txn13.undoTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/siteURI");
-  do_check_eq(observer._itemChangedValue, "");
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/");
-  txn13.redoTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/siteURI");
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://new-siteuri.com/");
-  txn13.undoTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/siteURI");
-  do_check_eq(observer._itemChangedValue, "");
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/");
-
-  // editLivemarkFeedURI
-  var txn14 = ptSvc.editLivemarkFeedURI(lvmkId, uri("http://new-feeduri.com/"));
-  txn14.doTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/feedURI");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://new-feeduri.com/");
-  txn14.undoTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/feedURI");
-  do_check_eq(observer._itemChangedValue, "");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/");
-  txn14.redoTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/feedURI");
-  do_check_eq(observer._itemChangedValue, "");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://new-feeduri.com/");
-  txn14.undoTransaction();
-  do_check_eq(observer._itemChangedId, lvmkId);
-  do_check_eq(observer._itemChangedProperty, "livemark/feedURI");
-  do_check_eq(observer._itemChangedValue, "");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/");
-
-  // Testing remove livemark
-  // Set an annotation and check that we don't lose it on undo
-  annosvc.setItemAnnotation(lvmkId, "livemark/testAnno", "testAnno",
-                            0, annosvc.EXPIRE_NEVER);
-  var txn15 = ptSvc.removeItem(lvmkId);
-  txn15.doTransaction();
-  do_check_false(lmsvc.isLivemark(lvmkId));
-  do_check_eq(observer._itemRemovedId, lvmkId);
-  txn15.undoTransaction();
-  lvmkId = observer._itemAddedId;
-  do_check_true(lmsvc.isLivemark(lvmkId));
-  do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/");
-  do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/");
-  do_check_eq(annosvc.getItemAnnotation(lvmkId, "livemark/testAnno"), "testAnno");
-  txn15.redoTransaction();
-  do_check_false(lmsvc.isLivemark(lvmkId));
-  do_check_eq(observer._itemRemovedId, lvmkId);
-
   // Test LoadInSidebar transaction.
   var txn16 = ptSvc.setLoadInSidebar(bkmk1Id, true);
   txn16.doTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
   do_check_eq(observer._itemChangedProperty, PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
   do_check_eq(observer._itemChanged_isAnnotationProperty, true);
   txn16.undoTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
--- a/browser/components/places/tests/unit/test_txnGUIDs.js
+++ b/browser/components/places/tests/unit/test_txnGUIDs.js
@@ -36,52 +36,70 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * This test will ensure any transactions service that is going to create
  * a new item, won't replace the GUID when undoing and redoing the action.
  */
-var bmsvc = PlacesUtils.bookmarks;
-var txnsvc = PlacesUIUtils.ptm;
 
 function test_GUID_persistance(aTxn) {
   aTxn.doTransaction();
-  var itemId = bmsvc.getIdForItemAt(bmsvc.unfiledBookmarksFolder, 0);
-  var GUID = bmsvc.getItemGUID(itemId);
-  aTxn.undoTransaction();
-  aTxn.redoTransaction();
-  do_check_eq(GUID, bmsvc.getItemGUID(itemId));
-  aTxn.undoTransaction();
+  waitForAsyncUpdates(function () {
+    let itemId = PlacesUtils.bookmarks
+                            .getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+    let GUID = PlacesUtils.bookmarks.getItemGUID(itemId);
+    aTxn.undoTransaction();
+    aTxn.redoTransaction();
+    waitForAsyncUpdates(function() {
+      let itemId = PlacesUtils.bookmarks
+                              .getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+      do_check_eq(GUID, PlacesUtils.bookmarks.getItemGUID(itemId));
+      aTxn.undoTransaction();
+      waitForAsyncUpdates(run_next_test);
+    });
+  });
 }
 
 function run_test() {
-  // Create folder.
-  var createFolderTxn = txnsvc.createFolder("Test folder",
-                                            bmsvc.unfiledBookmarksFolder,
-                                            bmsvc.DEFAULT_INDEX);
-  test_GUID_persistance(createFolderTxn);
+  run_next_test();
+}
 
-  // Create bookmark.
-  var createBookmarkTxn = txnsvc.createItem(uri("http://www.example.com"),
-                                            bmsvc.unfiledBookmarksFolder,
-                                            bmsvc.DEFAULT_INDEX,
-                                            "Test bookmark");
-  test_GUID_persistance(createBookmarkTxn);
+add_test(function create_folder() {
+  let createFolderTxn = new PlacesCreateFolderTransaction(
+    "Test folder", PlacesUtils.unfiledBookmarksFolderId,
+    PlacesUtils.bookmarks.DEFAULT_INDEX
+  );
+  test_GUID_persistance(createFolderTxn);
+});
 
-  // Create separator.
-  var createSeparatorTxn = txnsvc.createSeparator(bmsvc.unfiledBookmarksFolder,
-                                                  bmsvc.DEFAULT_INDEX);
-  test_GUID_persistance(createFolderTxn);
+add_test(function create_bookmark() {
+  let createBookmarkTxn = new PlacesCreateBookmarkTransaction(
+    NetUtil.newURI("http://www.example.com"), PlacesUtils.unfiledBookmarksFolderId,
+    PlacesUtils.bookmarks.DEFAULT_INDEX, "Test bookmark"
+  );
+  test_GUID_persistance(createBookmarkTxn);
+});
+  
+add_test(function create_separator() {
+  let createSeparatorTxn = new PlacesCreateSeparatorTransaction(
+    PlacesUtils.unfiledBookmarksFolderId, PlacesUtils.bookmarks.DEFAULT_INDEX
+  );
+  test_GUID_persistance(createSeparatorTxn);
+});
 
-  // Create livemark.
-  var createLivemarkTxn = txnsvc.createLivemark(uri("http://feeduri.com"),
-                                               uri("http://siteuri.com"),
-                                               "Test livemark",
-                                               bmsvc.unfiledBookmarksFolder,
-                                               bmsvc.DEFAULT_INDEX);
+add_test(function tag_uri() {
+  let tagURITxn = new PlacesTagURITransaction(
+    NetUtil.newURI("http://www.example.com"), ["foo"]
+  );
+  test_GUID_persistance(tagURITxn);
+});
+
+add_test(function create_livemark() {
+  let createLivemarkTxn = new PlacesCreateLivemarkTransaction(
+    NetUtil.newURI("http://feeduri.com"), NetUtil.newURI("http://siteuri.com"),
+    "Test livemark", PlacesUtils.unfiledBookmarksFolderId,
+    PlacesUtils.bookmarks.DEFAULT_INDEX
+  );
   test_GUID_persistance(createLivemarkTxn);
+});
 
-  // Tag URI.
-  var tagURITxn = txnsvc.tagURI(uri("http://www.example.com"), ["foo"]);
-  test_GUID_persistance(tagURITxn);
-}
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -184,28 +184,16 @@ PrivateBrowsingService.prototype = {
           let plainURL = win.gBrowser.currentURI.spec;
           if (plainURL.indexOf("view-source:") == 0) {
             plainURL = plainURL.substr(12);
             this._viewSrcURLs.push(plainURL);
           }
         }
         win.close();
       }
-        
-      var windowsEnum = Services.wm.getEnumerator("navigator:browser");
-      while (windowsEnum.hasMoreElements()) {
-        var window = windowsEnum.getNext();
-        window.getInterface(Ci.nsIWebNavigation)
-              .QueryInterface(Ci.nsIDocShellTreeItem)
-              .treeOwner
-              .QueryInterface(Ci.nsIInterfaceRequestor)
-              .getInterface(Ci.nsIXULWindow)
-              .docShell.QueryInterface(Ci.nsILoadContext)
-              .usePrivateBrowsing = this._inPrivateBrowsing;
-      }
 
       if (!this._quitting && this._saveSession) {
         let browserWindow = this._getBrowserWindow();
 
 	// if there are open browser windows, load a dummy session to get a distinct 
         // separation between private and non-private sessions
 	if (browserWindow) {
           // set an empty session to transition from/to pb mode, see bug 476463
@@ -224,16 +212,28 @@ PrivateBrowsingService.prototype = {
           browser.removeTab(browser.tabContainer.firstChild);
           browserWindow.getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShellTreeItem)
                        .treeOwner
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIXULWindow)
                        .docShell.contentViewer.resetCloseWindow();
         }
+
+        var windowsEnum = Services.wm.getEnumerator("navigator:browser");
+        while (windowsEnum.hasMoreElements()) {
+          var window = windowsEnum.getNext();
+          window.getInterface(Ci.nsIWebNavigation)
+                .QueryInterface(Ci.nsIDocShellTreeItem)
+                .treeOwner
+                .QueryInterface(Ci.nsIInterfaceRequestor)
+                .getInterface(Ci.nsIXULWindow)
+                .docShell.QueryInterface(Ci.nsILoadContext)
+                .usePrivateBrowsing = this._inPrivateBrowsing;
+        }
       }
     }
     else
       this._saveSession = false;
   },
 
   _onAfterPrivateBrowsingModeChange: function PBS__onAfterPrivateBrowsingModeChange() {
     // nothing to do here if we're enabling at startup or the current session is being
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload.js
@@ -55,36 +55,36 @@ function test() {
       dialogWin.document.documentElement.getButton("accept").click();
     else if (rejectDialog-- > 0)
       dialogWin.document.documentElement.getButton("cancel").click();
   }
 
   Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
 
   waitForExplicitFinish();
-  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
+  let browser1 = gBrowser.addTab().linkedBrowser;
   browser1.addEventListener("load", function() {
     browser1.removeEventListener("load", arguments.callee, true);
 
-    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
+    let browser2 = gBrowser.addTab().linkedBrowser;
     browser2.addEventListener("load", function() {
       browser2.removeEventListener("load", arguments.callee, true);
 
       rejectDialog = 1;
       pb.privateBrowsingEnabled = true;
 
       ok(!pb.privateBrowsingEnabled, "Private browsing mode should not have been activated");
       is(confirmCalls, 1, "Only one confirm box should be shown");
       is(gBrowser.tabs.length, 3,
          "No tabs should be closed because private browsing mode transition was canceled");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
+      is(gBrowser.tabContainer.firstChild.linkedBrowser.currentURI.spec, "about:blank",
          "The first tab should be a blank tab");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
+      is(gBrowser.tabContainer.firstChild.nextSibling.linkedBrowser.currentURI.spec, TEST_PAGE_1,
          "The middle tab should be the same one we opened");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+      is(gBrowser.tabContainer.lastChild.linkedBrowser.currentURI.spec, TEST_PAGE_2,
          "The last tab should be the same one we opened");
       is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
 
       confirmCalls = 0;
       acceptDialog = 2;
       pb.privateBrowsingEnabled = true;
 
       ok(pb.privateBrowsingEnabled, "Private browsing mode should have been activated");
@@ -108,53 +108,59 @@ function test() {
             confirmCalls = 0;
             rejectDialog = 1;
             pb.privateBrowsingEnabled = false;
 
             ok(pb.privateBrowsingEnabled, "Private browsing mode should not have been deactivated");
             is(confirmCalls, 1, "Only one confirm box should be shown");
             is(gBrowser.tabs.length, 2,
                "No tabs should be closed because private browsing mode transition was canceled");
-            is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, TEST_PAGE_1,
+            is(gBrowser.tabContainer.firstChild.linkedBrowser.currentURI.spec, TEST_PAGE_1,
                "The first tab should be the same one we opened");
-            is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+            is(gBrowser.tabContainer.lastChild.linkedBrowser.currentURI.spec, TEST_PAGE_2,
                "The last tab should be the same one we opened");
             is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
 
+            // Ensure that all restored tabs are loaded without waiting for the
+            // user to bring them to the foreground, by resetting the related
+            // preference (see the "firefox.js" defaults file for details).
+            Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
             confirmCalls = 0;
             acceptDialog = 2;
             pb.privateBrowsingEnabled = false;
 
             ok(!pb.privateBrowsingEnabled, "Private browsing mode should have been deactivated");
             is(confirmCalls, 2, "Only two confirm boxes should be shown");
             is(gBrowser.tabs.length, 3,
                "Incorrect number of tabs after transition into private browsing");
 
             let loads = 0;
             function waitForLoad(event) {
               gBrowser.removeEventListener("load", arguments.callee, true);
 
               if (++loads != 3)
                 return;
 
-              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
+              is(gBrowser.tabContainer.firstChild.linkedBrowser.currentURI.spec, "about:blank",
                  "The first tab should be a blank tab");
-              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
+              is(gBrowser.tabContainer.firstChild.nextSibling.linkedBrowser.currentURI.spec, TEST_PAGE_1,
                  "The middle tab should be the same one we opened");
-              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+              is(gBrowser.tabContainer.lastChild.linkedBrowser.currentURI.spec, TEST_PAGE_2,
                  "The last tab should be the same one we opened");
               is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
               is(acceptDialog, 0, "Two prompts should have been raised");
 
               acceptDialog = 2;
               gBrowser.removeTab(gBrowser.tabContainer.lastChild);
               gBrowser.removeTab(gBrowser.tabContainer.lastChild);
               gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
 
               Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
+              Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
               finish();
             }
             for (let i = 0; i < gBrowser.browsers.length; ++i)
               gBrowser.browsers[i].addEventListener("load", waitForLoad, true);
           }, true);
           gBrowser.selectedBrowser.loadURI(TEST_PAGE_2);
         }, true);
         gBrowser.selectedBrowser.loadURI(TEST_PAGE_1);
--- a/browser/components/sessionstore/test/browser_580512.js
+++ b/browser/components/sessionstore/test/browser_580512.js
@@ -35,17 +35,17 @@ function checkSecondWin(win) {
   document.documentElement.setAttribute("windowtype", "navigator:browser");
   finish();
 }
 
 function openWinWithCb(cb, argURIs, expectedURIs) {
   if (!expectedURIs)
     expectedURIs = argURIs;
 
-  var win = openDialog("chrome://browser/content/", "_blank",
+  var win = openDialog(getBrowserURL(), "_blank",
                        "chrome,all,dialog=no", argURIs.join("|"));
 
   win.addEventListener("load", function () {
     win.removeEventListener("load", arguments.callee, false);
     info("the window loaded");
 
     var expectedLoads = expectedURIs.length;
 
--- a/browser/components/sessionstore/test/browser_586068-cascaded_restore.js
+++ b/browser/components/sessionstore/test/browser_586068-cascaded_restore.js
@@ -85,16 +85,18 @@ function runNextTest() {
   else {
     ss.setBrowserState(stateBackup);
     executeSoon(finish);
   }
 }
 
 
 function test_cascade() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
       dump("\n\nload: " + aBrowser.currentURI.spec + "\n" + JSON.stringify(countTabs()) + "\n\n");
       if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
@@ -215,16 +217,18 @@ function test_select() {
   }
 
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setBrowserState(JSON.stringify(state));
 }
 
 
 function test_multiWindowState() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
       // We only care about load events when the tab still has
       // __SS_restoreState == TAB_STATE_RESTORING on it.
       // Since our listener is attached before the sessionstore one, this works out.
       if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
@@ -292,16 +296,18 @@ function test_multiWindowState() {
   Services.ww.registerNotification(windowObserver);
 
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setBrowserState(JSON.stringify(state));
 }
 
 
 function test_setWindowStateNoOverwrite() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
       // We only care about load events when the tab still has
       // __SS_restoreState == TAB_STATE_RESTORING on it.
       // Since our listener is attached before the sessionstore one, this works out.
       if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
@@ -361,16 +367,18 @@ function test_setWindowStateNoOverwrite(
   }
 
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setWindowState(window, JSON.stringify(state1), true);
 }
 
 
 function test_setWindowStateOverwrite() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
       // We only care about load events when the tab still has
       // __SS_restoreState == TAB_STATE_RESTORING on it.
       // Since our listener is attached before the sessionstore one, this works out.
       if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
@@ -430,16 +438,18 @@ function test_setWindowStateOverwrite() 
   }
 
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setWindowState(window, JSON.stringify(state1), true);
 }
 
 
 function test_setBrowserStateInterrupted() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
       // We only care about load events when the tab still has
       // __SS_restoreState == TAB_STATE_RESTORING on it.
       // Since our listener is attached before the sessionstore one, this works out.
       if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
@@ -622,16 +632,18 @@ function test_reload() {
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setBrowserState(JSON.stringify(state));
 }
 
 
 // This doesn't actually test anything, just does a cascaded restore with default
 // settings. This really just sets up to test that reloads work.
 function test_reloadCascadeSetup() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
       if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
           aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
         test_cascadeReloadSetup_progressCallback();
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -32,16 +32,24 @@
  * 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 ***** */
 
 let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
 
+// Some tests here assume that all restored tabs are loaded without waiting for
+// the user to bring them to the foreground. We ensure this by resetting the
+// related preference (see the "firefox.js" defaults file for details).
+Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+registerCleanupFunction(function () {
+  Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
+});
+
 // This assumes that tests will at least have some state/entries
 function waitForBrowserState(aState, aSetStateCallback) {
   let windows = [window];
   let tabsRestored = 0;
   let expectedTabsRestored = 0;
   let expectedWindows = aState.windows.length;
   let windowsOpen = 1;
   let listening = false;
--- a/browser/components/tabview/test/head.js
+++ b/browser/components/tabview/test/head.js
@@ -1,11 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+// Some tests here assume that all restored tabs are loaded without waiting for
+// the user to bring them to the foreground. We ensure this by resetting the
+// related preference (see the "firefox.js" defaults file for details).
+Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
+registerCleanupFunction(function () {
+  Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
+});
+
+// ----------
 function createEmptyGroupItem(contentWindow, width, height, padding, animate) {
   let pageBounds = contentWindow.Items.getPageBounds();
   pageBounds.inset(padding, padding);
 
   let box = new contentWindow.Rect(pageBounds);
   box.width = width;
   box.height = height;
 
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -37,27 +37,34 @@
 # ***** END LICENSE BLOCK *****
 
 MOZ_APP_BASENAME=Firefox
 MOZ_APP_VENDOR=Mozilla
 MOZ_UPDATER=1
 MOZ_PHOENIX=1
 
 if test "$OS_ARCH" = "WINNT"; then
+  MOZ_VERIFY_MAR_SIGNATURE=1
   if ! test "$HAVE_64BIT_OS"; then
     MOZ_MAINTENANCE_SERVICE=1
   fi
 fi
 
 MOZ_CHROME_FILE_FORMAT=omni
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_SYNC=1
 MOZ_APP_VERSION=$FIREFOX_VERSION
 MOZ_EXTENSIONS_DEFAULT=" gnomevfs"
 # MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
 # Changing either of these values requires a clobber to ensure correct results,
 # because branding dependencies are broken.
 MOZ_BRANDING_DIRECTORY=browser/branding/nightly
 MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
 MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+# This should usually be the same as the value MAR_CHANNEL_ID.
+# If more than one ID is needed, then you should use a comma separated list
+# of values.
+ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
+# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
+MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
 MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
--- a/browser/fuel/src/fuelApplication.js
+++ b/browser/fuel/src/fuelApplication.js
@@ -50,17 +50,18 @@ var Utilities = {
     let bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
                     getService(Ci.nsINavBookmarksService);
     this.__defineGetter__("bookmarks", function() bookmarks);
     return this.bookmarks;
   },
 
   get livemarks() {
     let livemarks = Cc["@mozilla.org/browser/livemark-service;2"].
-                    getService(Ci.nsILivemarkService);
+                    getService[Ci.mozIAsyncLivemarks].
+                    QueryInterface(Ci.nsILivemarkService);
     this.__defineGetter__("livemarks", function() livemarks);
     return this.livemarks;
   },
 
   get annotations() {
     let annotations = Cc["@mozilla.org/browser/annotation-service;1"].
                       getService(Ci.nsIAnnotationService);
     this.__defineGetter__("annotations", function() annotations);
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -92,16 +92,17 @@
 ; [Base Browser Files]
 #ifndef XP_UNIX
 @BINPATH@/@MOZ_APP_NAME@.exe
 #else
 @BINPATH@/@MOZ_APP_NAME@-bin
 @BINPATH@/@MOZ_APP_NAME@
 #endif
 @BINPATH@/application.ini
+@BINPATH@/update-settings.ini
 @BINPATH@/platform.ini
 #ifndef XP_OS2
 @BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
 #else
 @BINPATH@/mozsqlt3@DLL_SUFFIX@
 #endif
 @BINPATH@/blocklist.xml
 #ifdef XP_UNIX
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -164,21 +164,21 @@ libs:: $(addsuffix .xml,$(SEARCH_PLUGINS
 	$(NSINSTALL) -D $(FINAL_TARGET)/searchplugins
 	for SEARCH_PLUGIN in $^; do\
 	  SEARCH_PLUGIN_BASE=`basename $$SEARCH_PLUGIN`;\
 	  $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
 	    $$SEARCH_PLUGIN > $(FINAL_TARGET)/searchplugins/$$SEARCH_PLUGIN_BASE; \
 	done
 
 install:: $(addsuffix .xml,$(SEARCH_PLUGINS))
-	$(NSINSTALL) -D $(DESTDIR)$mozappdir/searchplugins
+	$(NSINSTALL) -D $(DESTDIR)$(mozappdir)/searchplugins
 	for i in $^; do \
 	  SEARCH_PLUGIN_BASE=`basename $$SEARCH_PLUGIN`;\
 	  $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
-	    $$SEARCH_PLUGIN > $(DESTDIR)$mozappdir/searchplugins/$$SEARCH_PLUGIN_BASE; \
+	    $$SEARCH_PLUGIN > $(DESTDIR)$(mozappdir)/searchplugins/$$SEARCH_PLUGIN_BASE; \
 	done
 
 
 libs-%:
 	$(NSINSTALL) -D $(DIST)/install
 	@$(MAKE) -C ../../toolkit/locales libs-$* BOTH_MANIFESTS=1
 	@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$* BOTH_MANIFESTS=1
 	@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$* BOTH_MANIFESTS=1
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -208,16 +208,21 @@ menuitem.bookmark-item {
 }
 
 .bookmark-item[container][livemark] { 
   list-style-image: url("chrome://browser/skin/feeds/feedIcon16.png");
 }
 
 .bookmark-item[container][livemark] .bookmark-item {
   list-style-image: url("chrome://browser/skin/places/livemark-item.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+.bookmark-item[container][livemark] .bookmark-item[visited] {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 .bookmark-item[container][query] {
   list-style-image: url("chrome://browser/skin/places/query.png");
 }
 
 .bookmark-item[query][tagContainer] {
   list-style-image: url("chrome://browser/skin/places/tag.png");
index 1ed34429cca0204a19332ed5d9ef421f98049629..8ef1ba4a5cd268f4549fa2b511d6d47f8b46333e
GIT binary patch
literal 3861
zc$@(h59;uVP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^000U@X+uL$Nkc;*
zaB^>EX>4Tx0C?J+Q+HUC_ZB|i_hk=OLfG)Jmu!ImA|tE_$Pihg5Rw34gb)%y#f69p
zRumNxoJdu~g4GI0orvO~D7a@qiilc^Ra`jkAKa(4eR}Wh?fcjJyyu+f{LXpL4}cL8
zCXwc%Y5+M>g*-agACFH+#L2yY0u@N$1RxOR%fe>`#Q*^C19^CUbg)1C0k3ZW0swH;
zE+i7i;s1lWP$pLZAdvvzA`<5d0gzGv$SzdK6adH=0I*ZDWC{S3003-xd_p1ssto|_
z^hrJi0NAOM+!p}Yq8zCR0F40vnJ7mj0zkU}U{!%qECRs70HCZuA}$2Lt^t5qwlYTo
zfV~9(c8*w(4?ti5fSE!p%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqG
zxRuZvck=My;vwR~Y_URN7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=4R(?
z@ASo@{%i1WB0eGU-~POe0t5gMPS5Y!U*+Z218~Oyuywy{sapWrRsd+<`CT*H37}dE
z(0cicc{uz)9-g64$UGe!3JVMEC1RnyFyo6p|1;rl;ER6t{6HT5+j{T-ahgDxt-zy$
z{c&M#cCJ#6=gR~_F>d$gBmT#QfBlXr(c(0*Tr3re@mPttP$EsodAU-NL?OwQ;u7h9
zGVvdl{RxwI4FIf$Pry#L2er#=z<%xl0*ek<(slqqe)BDi8VivC5N9+pdG`PSlfU_o
zKq~<N&6lL(006w`7+k277fi+o002awfhw>;2Moa!tiTSO!5zH77Xo1hL_iEAz&sE_
z2IPPo3ZWR5K^auQI@koYumc*P5t`u;w81er4d>tzT!HIw7Y1M$p28Tsh6w~g$Osc*
zAv%Z=Vvg7%&IlKojszlMNHmgwq#)^t6j36@$a16tsX}UzT}UJHEpik&ja)$bklV;0
zGK&0)yhkyVfwEBp)B<%txu_o+ipHRG(R4HqU4WLNYtb6C9zB4zqNmYI=yh}eeTt4_
zfYC7yW{lZkT#ScBV2M~7CdU?I<ybXVk2PZ*ST}YR8^E4n?+7FUi+~gC2wsE`!fb+&
zkVjZdSVO2K>?5=ix(HVZgM=}{CnA%mPqZa^68Xe<Vmh&qSVpWS?jar_o+Vx<4ijIK
zNF)x)lH^VbAtjJ9NefA9NZUv)q*J6m(hzB!OeX7)ZOPu`2(o~zAeWK1kPnbglKaWS
z<hK+$#faie38ExYq?8g$HDy2L1f`!cLYbhdQO&8I)Cj7GI-goeZJ>5gFH?u96Et<2
zCC!@_L(8Nsqt(!wX=iEoXfNq>x(VHb9z~bXm(pwK2kGbOgY<U{4TcSa$4Fu*8EYAP
z8K)Sx884YkrUlcNnaETy*D@QKXP6I|Z&g?-_9}c8k;)R4I+a$HewF8{R8@0TKh=4v
z3skFB5362QeWpfLvryxy3Dg#=)u|m-yQwy=&Qf<$k5JE1U!%TX{et>q4YG!XMxcgB
zqf}$J#u<$v7REAV@mNCEa#jQDENhreVq3EL>`ZnA`x|yIdrVV9bE;;nW|3x{=5fsd
z4#u(I@HyF>O3oq94bFQl11&!-vDRv>X03j$H`;pIzS?5#a_tuF>)P*iaGgM%ES>c_
zZ94aL3A#4AQM!e?+jY<CKGS3CdFcuD%JmNE-O)$&ZS<q{7wYfU@6jJOFf<4@kQr<-
zIAie4kYng;m}$7t@Py&05zA=0k;G`D(Mh8xxF+t0XX7<^7d~dJZyaK*G~Q+0Ydm3M
zX)@cS#H7XKzA4R=Yno=d(X`Wa%*@Cv+^pEF$?T3f)tqadVZPbC+x(4%rA3^@N{cp&
z$Clcbe9HxvO_ukpm{vYkc~<pS*Q`m_T<a|BZPr(8P#ag944XQe%eJVko2|rln{D3|
z;uMc5(kb;*ZrU;I{Ok(sn(PMcIrd@pCH8Ih&mGJh5*^k%bUS=<bal*jY;e5mq~SEf
zsl=(n=~rhPXQ6YQ^EDTyOOVSFmv)yIQ*Eb;r*5Bm%a!FC?z+;o)Agg9yPMpt*=^L_
z%ss_@tNTqZn;Xep!#(do^zips;&II5ou`|p!t;>lFJ5+DSzi0S9#6BJCZ5(XZOGfi
zTj0IRdtf>~J!SgN=>tB-J_4V5pNGDtz9Qc}z9W9tewls;{GR(e`pf-~_`l(K@)q$<
z1z-We0p$U`ff|9c18V~x1epY-2Q>wa1-k|>3_cY?3<(WcA99m#z!&lx`C~KOXDpi0
z70L*m6<QnmFw7=Q9@Y_#hR+D!5Pol_`Aq4|wg`yeM{J0=A88qx7x{e@DJn9mF6vRV
zQ*?23_bk?|<XQV?y^isZsf@Wh+iJFQc4w?=Y*K7v?3=iNxT?5;c!&5!@s|>G6C?@k
ziR8rC#65}Qa{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1<g_shTvOnd6AVN?t
z7*FM=ZcQB%@`Rg(Pes0>jiOPpx423?lIEROmG(H@JAFg?XogQlb;dIZPf{y+kr|S?
zBlAsGMAqJ{&)IR=Ejg5&l$@hd4QZCNE7vf$D7Q~$D=U)?<ay?8${Ul1%J<|W`E&Ez
z6>Nn}(WA6du22pZOfRS_cv~1-c(_QtNLti0-)8>m`6CO07JR*suu!<Lv)H(JS@GZ^
zzeT$iBa2fPcP=qqQo3Y#Y4Fm0%V^88mi<uTSW;E;YI)r9j#7itrKLkFf>$(^sg%jf
zZm#rNxnmV!m1I@#YM0epR(~oNm0zrItf;Q|utvD%;#W>z)qM4NZQ9!2O1H}G>qzUQ
z>u#*~S--DJy=p<#(1!30tsC);<r`mZO5Sv#dTRBK&9u$R%>y-IHSJr>wyfLop*ExT
zdYyk=%U1oZtGB+{Cfe4&-FJKQ4uc&PJKpb<?7X!rcvow^MSb;d((Z!Yj~Zedy1(Xr
z-MB}0PsN^(d!>5^_C@dOYIJXG+^@gCvI%WcHjN%gI&kHifN$EH?V5MBa9S!3!a?Q1
zC*P)gd*e{(q0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2k
zV|B+hk5`_cohUu=`Q(C=<ELb&o}ErVJ=B@pdG}2GnQL89UA<>R&z?UQbnZ;IU-!xL
z-sg{9@Vs#JBKKn3CAUkhJ+3`ResKNaNUvLO>t*-L?N>ambo5Q@JJIjcfBI^`)pOVQ
z*DhV3dA;w(>>IakCfyvkCA#(acJ}QTcM9%I++BK)c(44v+WqPW`VZ=VwEnSWz-{38
zV8CF{!&wjS4he^z{*?dIhvCvk%tzHDMk9@nogW_?4H~`jWX_Y}r?RIL&&qyQ|9R_k
ztLNYS;`>X_Sp3-V3;B!Bzpi<y^K$R2sjoW6BgY@S&UroYru?nW+kNl2@4DZ|y&st<
z{6PLt^U?Za$EVOw_de%*{`@cZg!B7=IVBMQ000SaNLh0L01FcU01FcV0GgZ_00007
zbV*G`2iyS;5H}ZlWv=u9000JJOGiWi{{a60|De66lK=n&Q%OWYR7gvel}l_JRTzbh
zvH&3#kQEyeRAqtGq=0DRAVJ#=VgZXv?2%xJ$c80rB*ca)Z2C@U^R|=NZXEKe6Ud`!
zn~>%OeWYz1Cw82fvB&W|Jf0bI`2QOxlcFrbNJsb1_4)2SbMNmN-|h`x1%lO;2)<c^
zXq_M7nzE`7wbkA|d)P}1vp(;7>3?eP;)(vb>HEqV`5aE95zehfxFjdyKe}a+7s0oh
zm=%+~eeU(?`->R)<L<G<US<S~_KF%OdJd&T7$sLP%MfxM{m|GUB|>0^S)L>|J%?mk
zf?FybOYCK4FF^PmzY}VNZOO1K6PB_J%XUz7NYq+~#ADprmISBY4`z9ip@~^IZV9Gk
zV@FY6V2%=dnJEXT_B(xkSmrjY^eo)SDU>4b!k+#T#dsJ6%Ys#OgbHO@W*W?JP4Fax
zu^BPxR$4*Vt(Z`3W&uw(QX*905X)jOGvxp^ekb6EsgqfgV6FZP`|h_Cq#mW-Q*eep
zML}MHVHL}=VHzp80WZM7*c5EXg{qlY_-hT5_m>cePM|Y9hRE0qwq;dt`(iIMUVtt?
z3@rs+*I~+!pqsQ%UO{pGN4OnzaC;kJq*uhaZd$_YbT%9Wh>T9sak<Fr7SeJ~_|&|C
zdk-GsX5SEcXh%{z*)m@gUS_-i?G4cKTQHI{aD#PldOt*A_6KOYSr|*La9e9(_nsB^
zdBcLHCBe*ofY9*o;%wtd3GJa#diogd{JDxOg;@OiDSizOA{ZSP_sp}G8LtLzG$2m_
zcGWb@2Nz&Rzkqv<7VY?i#v~L*zk_?V7RKTg<n#i0H^B_EJW2o1gg9GS)iAgGn6`HY
zEj<GW4BQrDx2fX!eqnV@@a$#A+kut_<kSQuG@+_lWOKXFR{G#JpM){|J=F9DoGb66
z*#DXE<Z=|C#oK}4;J7F@{!Py5P)N&<p5sb;h>CF@DXM|izySK`soBF`X1oB`8lYwq
zP^CB(7rkgYKSnmApb-8BPIEo7yBf^M*Kn`bl4pZLCcw=84)Bv21sh2zht9|tx=1@2
z4Zn@w!S(J41u_t&s&DOyQkb0ZGUElfT#rm<0~u)(rSA9Ow0!_YP9s0x0r$d5WH%o|
zoB9cE3k7&SDZKWj`hx(xpw0nk^0xkAQFtk37xOD?xZKu<^`wlcxfQeoqIeQd2`@9=
zi|ArK<V+kpbYAjK0<x5(z79#+M&{W)NQy$^Nhs^or=5|NIGEXg5p{+}piy-*vni?A
zqMhLW76p1t3#ODjjj4FDkwz+$7hYz(SMk-eP?x%Cp><OHKU(+3<#n+*dzsmP6$b}n
zSc@l-r@!cN#9n6h0tDZvMDwdn_Qf-BeyJy&7OmZUT4=w&_glGt=?u{PS`)Kkk`o_Q
z@tL;K)*naW{D~3l-siZYlAngR^u^EdQJ-Y;u$P#F&++;5)Sh_RS5@`OvBX}%_<a8Y
X?5nX&f{nAe00000NkvXXu0mjfkCJEf
--- a/browser/themes/gnomestripe/places/places.css
+++ b/browser/themes/gnomestripe/places/places.css
@@ -23,16 +23,21 @@ treechildren::-moz-tree-image(title) {
   margin: 0px 2px;
   width: 16px;
   height: 16px;
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
 treechildren::-moz-tree-image(title, livemarkItem) {
   list-style-image: url("chrome://browser/skin/places/livemark-item.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+treechildren::-moz-tree-image(title, livemarkItem, visited) {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 treechildren::-moz-tree-image(title, separator) {
   list-style-image: none;
   width: 0;
   height: 0;
 }
 
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -253,17 +253,22 @@ toolbarbutton.bookmark-item > menupopup 
   list-style-image: url("chrome://global/skin/tree/folder.png");
 }
 
 .bookmark-item[query][hostContainer][open] {
   list-style-image: url("chrome://global/skin/tree/folder.png");
 }
 
 .bookmark-item[livemark] .menuitem-iconic {
-  list-style-image: url("chrome://browser/skin/livemark-item.png");
+  list-style-image: url("chrome://browser/skin/places/livemark-item.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+.bookmark-item[livemark] .menuitem-iconic[visited] {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 .bookmark-item menuitem[openInTabs],
 .bookmark-item menuitem[siteURI] {
   list-style-image: none;
 }
 
 #wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box {
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -24,17 +24,16 @@ browser.jar:
   skin/classic/browser/hud-style-twisties.png
   skin/classic/browser/identity.png
   skin/classic/browser/Info.png
   skin/classic/browser/KUI-background.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/page-livemarks.png
-  skin/classic/browser/livemark-item.png
   skin/classic/browser/pageInfo.css
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/Privacy-48.png
   skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar-dropmarker.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Search.png
   skin/classic/browser/section_collapsed.png
@@ -85,16 +84,17 @@ browser.jar:
   skin/classic/browser/places/twisty-open.gif               (places/twisty-open.gif)
   skin/classic/browser/places/twisty-closed.gif             (places/twisty-closed.gif)
   skin/classic/browser/places/tag.png                       (places/tag.png)
   skin/classic/browser/places/downloads.png                 (places/downloads.png)
   skin/classic/browser/places/expander-closed-active.png    (places/expander-closed-active.png)
   skin/classic/browser/places/expander-closed.png           (places/expander-closed.png)
   skin/classic/browser/places/expander-open-active.png      (places/expander-open-active.png)
   skin/classic/browser/places/expander-open.png             (places/expander-open.png)
+  skin/classic/browser/places/livemark-item.png             (places/livemark-item.png)
   skin/classic/browser/preferences/alwaysAsk.png            (preferences/alwaysAsk.png)
   skin/classic/browser/preferences/application.png          (preferences/application.png)
   skin/classic/browser/preferences/Options.png              (preferences/Options.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/preferences/Options-sync.png         (preferences/Options-sync.png)
 #endif
   skin/classic/browser/preferences/saveFile.png             (preferences/saveFile.png)
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
deleted file mode 100644
index 32af074ad846aad169f5953d8dad64e10feb2350..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8ef1ba4a5cd268f4549fa2b511d6d47f8b46333e
GIT binary patch
literal 3861
zc$@(h59;uVP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^000U@X+uL$Nkc;*
zaB^>EX>4Tx0C?J+Q+HUC_ZB|i_hk=OLfG)Jmu!ImA|tE_$Pihg5Rw34gb)%y#f69p
zRumNxoJdu~g4GI0orvO~D7a@qiilc^Ra`jkAKa(4eR}Wh?fcjJyyu+f{LXpL4}cL8
zCXwc%Y5+M>g*-agACFH+#L2yY0u@N$1RxOR%fe>`#Q*^C19^CUbg)1C0k3ZW0swH;
zE+i7i;s1lWP$pLZAdvvzA`<5d0gzGv$SzdK6adH=0I*ZDWC{S3003-xd_p1ssto|_
z^hrJi0NAOM+!p}Yq8zCR0F40vnJ7mj0zkU}U{!%qECRs70HCZuA}$2Lt^t5qwlYTo
zfV~9(c8*w(4?ti5fSE!p%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqG
zxRuZvck=My;vwR~Y_URN7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=4R(?
z@ASo@{%i1WB0eGU-~POe0t5gMPS5Y!U*+Z218~Oyuywy{sapWrRsd+<`CT*H37}dE
z(0cicc{uz)9-g64$UGe!3JVMEC1RnyFyo6p|1;rl;ER6t{6HT5+j{T-ahgDxt-zy$
z{c&M#cCJ#6=gR~_F>d$gBmT#QfBlXr(c(0*Tr3re@mPttP$EsodAU-NL?OwQ;u7h9
zGVvdl{RxwI4FIf$Pry#L2er#=z<%xl0*ek<(slqqe)BDi8VivC5N9+pdG`PSlfU_o
zKq~<N&6lL(006w`7+k277fi+o002awfhw>;2Moa!tiTSO!5zH77Xo1hL_iEAz&sE_
z2IPPo3ZWR5K^auQI@koYumc*P5t`u;w81er4d>tzT!HIw7Y1M$p28Tsh6w~g$Osc*
zAv%Z=Vvg7%&IlKojszlMNHmgwq#)^t6j36@$a16tsX}UzT}UJHEpik&ja)$bklV;0
zGK&0)yhkyVfwEBp)B<%txu_o+ipHRG(R4HqU4WLNYtb6C9zB4zqNmYI=yh}eeTt4_
zfYC7yW{lZkT#ScBV2M~7CdU?I<ybXVk2PZ*ST}YR8^E4n?+7FUi+~gC2wsE`!fb+&
zkVjZdSVO2K>?5=ix(HVZgM=}{CnA%mPqZa^68Xe<Vmh&qSVpWS?jar_o+Vx<4ijIK
zNF)x)lH^VbAtjJ9NefA9NZUv)q*J6m(hzB!OeX7)ZOPu`2(o~zAeWK1kPnbglKaWS
z<hK+$#faie38ExYq?8g$HDy2L1f`!cLYbhdQO&8I)Cj7GI-goeZJ>5gFH?u96Et<2
zCC!@_L(8Nsqt(!wX=iEoXfNq>x(VHb9z~bXm(pwK2kGbOgY<U{4TcSa$4Fu*8EYAP
z8K)Sx884YkrUlcNnaETy*D@QKXP6I|Z&g?-_9}c8k;)R4I+a$HewF8{R8@0TKh=4v
z3skFB5362QeWpfLvryxy3Dg#=)u|m-yQwy=&Qf<$k5JE1U!%TX{et>q4YG!XMxcgB
zqf}$J#u<$v7REAV@mNCEa#jQDENhreVq3EL>`ZnA`x|yIdrVV9bE;;nW|3x{=5fsd
z4#u(I@HyF>O3oq94bFQl11&!-vDRv>X03j$H`;pIzS?5#a_tuF>)P*iaGgM%ES>c_
zZ94aL3A#4AQM!e?+jY<CKGS3CdFcuD%JmNE-O)$&ZS<q{7wYfU@6jJOFf<4@kQr<-
zIAie4kYng;m}$7t@Py&05zA=0k;G`D(Mh8xxF+t0XX7<^7d~dJZyaK*G~Q+0Ydm3M
zX)@cS#H7XKzA4R=Yno=d(X`Wa%*@Cv+^pEF$?T3f)tqadVZPbC+x(4%rA3^@N{cp&
z$Clcbe9HxvO_ukpm{vYkc~<pS*Q`m_T<a|BZPr(8P#ag944XQe%eJVko2|rln{D3|
z;uMc5(kb;*ZrU;I{Ok(sn(PMcIrd@pCH8Ih&mGJh5*^k%bUS=<bal*jY;e5mq~SEf
zsl=(n=~rhPXQ6YQ^EDTyOOVSFmv)yIQ*Eb;r*5Bm%a!FC?z+;o)Agg9yPMpt*=^L_
z%ss_@tNTqZn;Xep!#(do^zips;&II5ou`|p!t;>lFJ5+DSzi0S9#6BJCZ5(XZOGfi
zTj0IRdtf>~J!SgN=>tB-J_4V5pNGDtz9Qc}z9W9tewls;{GR(e`pf-~_`l(K@)q$<
z1z-We0p$U`ff|9c18V~x1epY-2Q>wa1-k|>3_cY?3<(WcA99m#z!&lx`C~KOXDpi0
z70L*m6<QnmFw7=Q9@Y_#hR+D!5Pol_`Aq4|wg`yeM{J0=A88qx7x{e@DJn9mF6vRV
zQ*?23_bk?|<XQV?y^isZsf@Wh+iJFQc4w?=Y*K7v?3=iNxT?5;c!&5!@s|>G6C?@k
ziR8rC#65}Qa{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1<g_shTvOnd6AVN?t
z7*FM=ZcQB%@`Rg(Pes0>jiOPpx423?lIEROmG(H@JAFg?XogQlb;dIZPf{y+kr|S?
zBlAsGMAqJ{&)IR=Ejg5&l$@hd4QZCNE7vf$D7Q~$D=U)?<ay?8${Ul1%J<|W`E&Ez
z6>Nn}(WA6du22pZOfRS_cv~1-c(_QtNLti0-)8>m`6CO07JR*suu!<Lv)H(JS@GZ^
zzeT$iBa2fPcP=qqQo3Y#Y4Fm0%V^88mi<uTSW;E;YI)r9j#7itrKLkFf>$(^sg%jf
zZm#rNxnmV!m1I@#YM0epR(~oNm0zrItf;Q|utvD%;#W>z)qM4NZQ9!2O1H}G>qzUQ
z>u#*~S--DJy=p<#(1!30tsC);<r`mZO5Sv#dTRBK&9u$R%>y-IHSJr>wyfLop*ExT
zdYyk=%U1oZtGB+{Cfe4&-FJKQ4uc&PJKpb<?7X!rcvow^MSb;d((Z!Yj~Zedy1(Xr
z-MB}0PsN^(d!>5^_C@dOYIJXG+^@gCvI%WcHjN%gI&kHifN$EH?V5MBa9S!3!a?Q1
zC*P)gd*e{(q0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2k
zV|B+hk5`_cohUu=`Q(C=<ELb&o}ErVJ=B@pdG}2GnQL89UA<>R&z?UQbnZ;IU-!xL
z-sg{9@Vs#JBKKn3CAUkhJ+3`ResKNaNUvLO>t*-L?N>ambo5Q@JJIjcfBI^`)pOVQ
z*DhV3dA;w(>>IakCfyvkCA#(acJ}QTcM9%I++BK)c(44v+WqPW`VZ=VwEnSWz-{38
zV8CF{!&wjS4he^z{*?dIhvCvk%tzHDMk9@nogW_?4H~`jWX_Y}r?RIL&&qyQ|9R_k
ztLNYS;`>X_Sp3-V3;B!Bzpi<y^K$R2sjoW6BgY@S&UroYru?nW+kNl2@4DZ|y&st<
z{6PLt^U?Za$EVOw_de%*{`@cZg!B7=IVBMQ000SaNLh0L01FcU01FcV0GgZ_00007
zbV*G`2iyS;5H}ZlWv=u9000JJOGiWi{{a60|De66lK=n&Q%OWYR7gvel}l_JRTzbh
zvH&3#kQEyeRAqtGq=0DRAVJ#=VgZXv?2%xJ$c80rB*ca)Z2C@U^R|=NZXEKe6Ud`!
zn~>%OeWYz1Cw82fvB&W|Jf0bI`2QOxlcFrbNJsb1_4)2SbMNmN-|h`x1%lO;2)<c^
zXq_M7nzE`7wbkA|d)P}1vp(;7>3?eP;)(vb>HEqV`5aE95zehfxFjdyKe}a+7s0oh
zm=%+~eeU(?`->R)<L<G<US<S~_KF%OdJd&T7$sLP%MfxM{m|GUB|>0^S)L>|J%?mk
zf?FybOYCK4FF^PmzY}VNZOO1K6PB_J%XUz7NYq+~#ADprmISBY4`z9ip@~^IZV9Gk
zV@FY6V2%=dnJEXT_B(xkSmrjY^eo)SDU>4b!k+#T#dsJ6%Ys#OgbHO@W*W?JP4Fax
zu^BPxR$4*Vt(Z`3W&uw(QX*905X)jOGvxp^ekb6EsgqfgV6FZP`|h_Cq#mW-Q*eep
zML}MHVHL}=VHzp80WZM7*c5EXg{qlY_-hT5_m>cePM|Y9hRE0qwq;dt`(iIMUVtt?
z3@rs+*I~+!pqsQ%UO{pGN4OnzaC;kJq*uhaZd$_YbT%9Wh>T9sak<Fr7SeJ~_|&|C
zdk-GsX5SEcXh%{z*)m@gUS_-i?G4cKTQHI{aD#PldOt*A_6KOYSr|*La9e9(_nsB^
zdBcLHCBe*ofY9*o;%wtd3GJa#diogd{JDxOg;@OiDSizOA{ZSP_sp}G8LtLzG$2m_
zcGWb@2Nz&Rzkqv<7VY?i#v~L*zk_?V7RKTg<n#i0H^B_EJW2o1gg9GS)iAgGn6`HY
zEj<GW4BQrDx2fX!eqnV@@a$#A+kut_<kSQuG@+_lWOKXFR{G#JpM){|J=F9DoGb66
z*#DXE<Z=|C#oK}4;J7F@{!Py5P)N&<p5sb;h>CF@DXM|izySK`soBF`X1oB`8lYwq
zP^CB(7rkgYKSnmApb-8BPIEo7yBf^M*Kn`bl4pZLCcw=84)Bv21sh2zht9|tx=1@2
z4Zn@w!S(J41u_t&s&DOyQkb0ZGUElfT#rm<0~u)(rSA9Ow0!_YP9s0x0r$d5WH%o|
zoB9cE3k7&SDZKWj`hx(xpw0nk^0xkAQFtk37xOD?xZKu<^`wlcxfQeoqIeQd2`@9=
zi|ArK<V+kpbYAjK0<x5(z79#+M&{W)NQy$^Nhs^or=5|NIGEXg5p{+}piy-*vni?A
zqMhLW76p1t3#ODjjj4FDkwz+$7hYz(SMk-eP?x%Cp><OHKU(+3<#n+*dzsmP6$b}n
zSc@l-r@!cN#9n6h0tDZvMDwdn_Qf-BeyJy&7OmZUT4=w&_glGt=?u{PS`)Kkk`o_Q
z@tL;K)*naW{D~3l-siZYlAngR^u^EdQJ-Y;u$P#F&++;5)Sh_RS5@`OvBX}%_<a8Y
X?5nX&f{nAe00000NkvXXu0mjfkCJEf
--- a/browser/themes/pinstripe/places/places.css
+++ b/browser/themes/pinstripe/places/places.css
@@ -92,17 +92,22 @@ treechildren::-moz-tree-image(title) {
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
   -moz-padding-end: 2px;
   margin: 0px 2px;
   width: 16px;
   height: 16px;
 }
 
 treechildren::-moz-tree-image(title, livemarkItem) {
-  list-style-image: url("chrome://browser/skin/livemark-item.png");
+  list-style-image: url("chrome://browser/skin/places/livemark-item.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+treechildren::-moz-tree-image(title, livemarkItem, visited) {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 treechildren::-moz-tree-image(title, container),
 treechildren::-moz-tree-image(title, open) {
   list-style-image: url("chrome://global/skin/tree/folder.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -604,18 +604,22 @@ menuitem.bookmark-item {
 }
 
 .bookmark-item[container][livemark] { 
   list-style-image: url("chrome://browser/skin/livemark-folder.png");
   -moz-image-region: auto;
 }
 
 .bookmark-item[container][livemark] .bookmark-item {
-  list-style-image: url("chrome://browser/skin/livemark-item.png");
-  -moz-image-region: auto;
+  list-style-image: url("chrome://browser/skin/places/livemark-item.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+.bookmark-item[container][livemark] .bookmark-item[visited] {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 .bookmark-item[container][query] {
   list-style-image: url("chrome://browser/skin/places/query.png");
   -moz-image-region: auto;
 }
 
 .bookmark-item[query][tagContainer] {
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -22,17 +22,16 @@ browser.jar:
         skin/classic/browser/Info.png                                (Info.png)
         skin/classic/browser/identity.png                            (identity.png)
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/KUI-close.png
         skin/classic/browser/pageInfo.css
         skin/classic/browser/pageInfo.png                            (pageInfo.png)
         skin/classic/browser/page-livemarks.png                      (feeds/feedIcon16.png)
-        skin/classic/browser/livemark-item.png                       (livemark-item.png)
         skin/classic/browser/livemark-folder.png                     (livemark-folder.png)
         skin/classic/browser/Privacy-16.png
         skin/classic/browser/Privacy-48.png
         skin/classic/browser/reload-stop-go.png
         skin/classic/browser/Secure24.png                            (Secure24.png)
         skin/classic/browser/Toolbar.png                             (Toolbar.png)
         skin/classic/browser/Toolbar-inverted.png
         skin/classic/browser/toolbarbutton-dropdown-arrow.png
@@ -75,16 +74,17 @@ browser.jar:
         skin/classic/browser/places/libraryToolbar.png               (places/libraryToolbar.png)
         skin/classic/browser/places/starred48.png                    (places/starred48.png)
         skin/classic/browser/places/unstarred48.png                  (places/unstarred48.png)
         skin/classic/browser/places/tag.png                          (places/tag.png)
         skin/classic/browser/places/history.png                      (places/history.png)
         skin/classic/browser/places/allBookmarks.png                 (places/allBookmarks.png)
         skin/classic/browser/places/unsortedBookmarks.png            (places/unsortedBookmarks.png)
         skin/classic/browser/places/downloads.png                    (places/downloads.png)
+        skin/classic/browser/places/livemark-item.png                (places/livemark-item.png)
         skin/classic/browser/preferences/alwaysAsk.png               (preferences/alwaysAsk.png)
         skin/classic/browser/preferences/application.png             (preferences/application.png)
         skin/classic/browser/preferences/mail.png                    (preferences/mail.png)
         skin/classic/browser/preferences/Options.png                 (preferences/Options.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/preferences/Options-sync.png            (preferences/Options-sync.png)
 #endif
         skin/classic/browser/preferences/saveFile.png                (preferences/saveFile.png)
@@ -191,17 +191,16 @@ browser.jar:
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/KUI-close.png
         skin/classic/aero/browser/pageInfo.css
         skin/classic/aero/browser/pageInfo.png                       (pageInfo-aero.png)
         skin/classic/aero/browser/page-livemarks.png                 (feeds/feedIcon16-aero.png)
-        skin/classic/aero/browser/livemark-item.png                  (livemark-item-aero.png)
         skin/classic/aero/browser/livemark-folder.png                (livemark-folder-aero.png)
         skin/classic/aero/browser/Privacy-16.png                     (Privacy-16-aero.png)
         skin/classic/aero/browser/Privacy-48.png                     (Privacy-48-aero.png)
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
@@ -244,16 +243,17 @@ browser.jar:
         skin/classic/aero/browser/places/libraryToolbar.png          (places/libraryToolbar-aero.png)
         skin/classic/aero/browser/places/starred48.png               (places/starred48-aero.png)
         skin/classic/aero/browser/places/unstarred48.png             (places/unstarred48.png)
         skin/classic/aero/browser/places/tag.png                     (places/tag-aero.png)
         skin/classic/aero/browser/places/history.png                 (places/history-aero.png)
         skin/classic/aero/browser/places/allBookmarks.png            (places/allBookmarks-aero.png)
         skin/classic/aero/browser/places/unsortedBookmarks.png       (places/unsortedBookmarks-aero.png)
         skin/classic/aero/browser/places/downloads.png               (places/downloads.png)
+        skin/classic/aero/browser/places/livemark-item.png           (places/livemark-item.png)
         skin/classic/aero/browser/preferences/alwaysAsk.png          (preferences/alwaysAsk-aero.png)
         skin/classic/aero/browser/preferences/application.png        (preferences/application-aero.png)
         skin/classic/aero/browser/preferences/mail.png               (preferences/mail-aero.png)
         skin/classic/aero/browser/preferences/Options.png            (preferences/Options-aero.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/preferences/Options-sync.png       (preferences/Options-sync.png)
 #endif
         skin/classic/aero/browser/preferences/saveFile.png           (preferences/saveFile-aero.png)
deleted file mode 100644
index 1fa03b78bc21c957fcd50614653988c524230707..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 83139be73329171d44e5baea573c43c482c77ec6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8ef1ba4a5cd268f4549fa2b511d6d47f8b46333e
GIT binary patch
literal 3861
zc$@(h59;uVP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^000U@X+uL$Nkc;*
zaB^>EX>4Tx0C?J+Q+HUC_ZB|i_hk=OLfG)Jmu!ImA|tE_$Pihg5Rw34gb)%y#f69p
zRumNxoJdu~g4GI0orvO~D7a@qiilc^Ra`jkAKa(4eR}Wh?fcjJyyu+f{LXpL4}cL8
zCXwc%Y5+M>g*-agACFH+#L2yY0u@N$1RxOR%fe>`#Q*^C19^CUbg)1C0k3ZW0swH;
zE+i7i;s1lWP$pLZAdvvzA`<5d0gzGv$SzdK6adH=0I*ZDWC{S3003-xd_p1ssto|_
z^hrJi0NAOM+!p}Yq8zCR0F40vnJ7mj0zkU}U{!%qECRs70HCZuA}$2Lt^t5qwlYTo
zfV~9(c8*w(4?ti5fSE!p%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqG
zxRuZvck=My;vwR~Y_URN7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=4R(?
z@ASo@{%i1WB0eGU-~POe0t5gMPS5Y!U*+Z218~Oyuywy{sapWrRsd+<`CT*H37}dE
z(0cicc{uz)9-g64$UGe!3JVMEC1RnyFyo6p|1;rl;ER6t{6HT5+j{T-ahgDxt-zy$
z{c&M#cCJ#6=gR~_F>d$gBmT#QfBlXr(c(0*Tr3re@mPttP$EsodAU-NL?OwQ;u7h9
zGVvdl{RxwI4FIf$Pry#L2er#=z<%xl0*ek<(slqqe)BDi8VivC5N9+pdG`PSlfU_o
zKq~<N&6lL(006w`7+k277fi+o002awfhw>;2Moa!tiTSO!5zH77Xo1hL_iEAz&sE_
z2IPPo3ZWR5K^auQI@koYumc*P5t`u;w81er4d>tzT!HIw7Y1M$p28Tsh6w~g$Osc*
zAv%Z=Vvg7%&IlKojszlMNHmgwq#)^t6j36@$a16tsX}UzT}UJHEpik&ja)$bklV;0
zGK&0)yhkyVfwEBp)B<%txu_o+ipHRG(R4HqU4WLNYtb6C9zB4zqNmYI=yh}eeTt4_
zfYC7yW{lZkT#ScBV2M~7CdU?I<ybXVk2PZ*ST}YR8^E4n?+7FUi+~gC2wsE`!fb+&
zkVjZdSVO2K>?5=ix(HVZgM=}{CnA%mPqZa^68Xe<Vmh&qSVpWS?jar_o+Vx<4ijIK
zNF)x)lH^VbAtjJ9NefA9NZUv)q*J6m(hzB!OeX7)ZOPu`2(o~zAeWK1kPnbglKaWS
z<hK+$#faie38ExYq?8g$HDy2L1f`!cLYbhdQO&8I)Cj7GI-goeZJ>5gFH?u96Et<2
zCC!@_L(8Nsqt(!wX=iEoXfNq>x(VHb9z~bXm(pwK2kGbOgY<U{4TcSa$4Fu*8EYAP
z8K)Sx884YkrUlcNnaETy*D@QKXP6I|Z&g?-_9}c8k;)R4I+a$HewF8{R8@0TKh=4v
z3skFB5362QeWpfLvryxy3Dg#=)u|m-yQwy=&Qf<$k5JE1U!%TX{et>q4YG!XMxcgB
zqf}$J#u<$v7REAV@mNCEa#jQDENhreVq3EL>`ZnA`x|yIdrVV9bE;;nW|3x{=5fsd
z4#u(I@HyF>O3oq94bFQl11&!-vDRv>X03j$H`;pIzS?5#a_tuF>)P*iaGgM%ES>c_
zZ94aL3A#4AQM!e?+jY<CKGS3CdFcuD%JmNE-O)$&ZS<q{7wYfU@6jJOFf<4@kQr<-
zIAie4kYng;m}$7t@Py&05zA=0k;G`D(Mh8xxF+t0XX7<^7d~dJZyaK*G~Q+0Ydm3M
zX)@cS#H7XKzA4R=Yno=d(X`Wa%*@Cv+^pEF$?T3f)tqadVZPbC+x(4%rA3^@N{cp&
z$Clcbe9HxvO_ukpm{vYkc~<pS*Q`m_T<a|BZPr(8P#ag944XQe%eJVko2|rln{D3|
z;uMc5(kb;*ZrU;I{Ok(sn(PMcIrd@pCH8Ih&mGJh5*^k%bUS=<bal*jY;e5mq~SEf
zsl=(n=~rhPXQ6YQ^EDTyOOVSFmv)yIQ*Eb;r*5Bm%a!FC?z+;o)Agg9yPMpt*=^L_
z%ss_@tNTqZn;Xep!#(do^zips;&II5ou`|p!t;>lFJ5+DSzi0S9#6BJCZ5(XZOGfi
zTj0IRdtf>~J!SgN=>tB-J_4V5pNGDtz9Qc}z9W9tewls;{GR(e`pf-~_`l(K@)q$<
z1z-We0p$U`ff|9c18V~x1epY-2Q>wa1-k|>3_cY?3<(WcA99m#z!&lx`C~KOXDpi0
z70L*m6<QnmFw7=Q9@Y_#hR+D!5Pol_`Aq4|wg`yeM{J0=A88qx7x{e@DJn9mF6vRV
zQ*?23_bk?|<XQV?y^isZsf@Wh+iJFQc4w?=Y*K7v?3=iNxT?5;c!&5!@s|>G6C?@k
ziR8rC#65}Qa{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1<g_shTvOnd6AVN?t
z7*FM=ZcQB%@`Rg(Pes0>jiOPpx423?lIEROmG(H@JAFg?XogQlb;dIZPf{y+kr|S?
zBlAsGMAqJ{&)IR=Ejg5&l$@hd4QZCNE7vf$D7Q~$D=U)?<ay?8${Ul1%J<|W`E&Ez
z6>Nn}(WA6du22pZOfRS_cv~1-c(_QtNLti0-)8>m`6CO07JR*suu!<Lv)H(JS@GZ^
zzeT$iBa2fPcP=qqQo3Y#Y4Fm0%V^88mi<uTSW;E;YI)r9j#7itrKLkFf>$(^sg%jf
zZm#rNxnmV!m1I@#YM0epR(~oNm0zrItf;Q|utvD%;#W>z)qM4NZQ9!2O1H}G>qzUQ
z>u#*~S--DJy=p<#(1!30tsC);<r`mZO5Sv#dTRBK&9u$R%>y-IHSJr>wyfLop*ExT
zdYyk=%U1oZtGB+{Cfe4&-FJKQ4uc&PJKpb<?7X!rcvow^MSb;d((Z!Yj~Zedy1(Xr
z-MB}0PsN^(d!>5^_C@dOYIJXG+^@gCvI%WcHjN%gI&kHifN$EH?V5MBa9S!3!a?Q1
zC*P)gd*e{(q0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2k
zV|B+hk5`_cohUu=`Q(C=<ELb&o}ErVJ=B@pdG}2GnQL89UA<>R&z?UQbnZ;IU-!xL
z-sg{9@Vs#JBKKn3CAUkhJ+3`ResKNaNUvLO>t*-L?N>ambo5Q@JJIjcfBI^`)pOVQ
z*DhV3dA;w(>>IakCfyvkCA#(acJ}QTcM9%I++BK)c(44v+WqPW`VZ=VwEnSWz-{38
zV8CF{!&wjS4he^z{*?dIhvCvk%tzHDMk9@nogW_?4H~`jWX_Y}r?RIL&&qyQ|9R_k
ztLNYS;`>X_Sp3-V3;B!Bzpi<y^K$R2sjoW6BgY@S&UroYru?nW+kNl2@4DZ|y&st<
z{6PLt^U?Za$EVOw_de%*{`@cZg!B7=IVBMQ000SaNLh0L01FcU01FcV0GgZ_00007
zbV*G`2iyS;5H}ZlWv=u9000JJOGiWi{{a60|De66lK=n&Q%OWYR7gvel}l_JRTzbh
zvH&3#kQEyeRAqtGq=0DRAVJ#=VgZXv?2%xJ$c80rB*ca)Z2C@U^R|=NZXEKe6Ud`!
zn~>%OeWYz1Cw82fvB&W|Jf0bI`2QOxlcFrbNJsb1_4)2SbMNmN-|h`x1%lO;2)<c^
zXq_M7nzE`7wbkA|d)P}1vp(;7>3?eP;)(vb>HEqV`5aE95zehfxFjdyKe}a+7s0oh
zm=%+~eeU(?`->R)<L<G<US<S~_KF%OdJd&T7$sLP%MfxM{m|GUB|>0^S)L>|J%?mk
zf?FybOYCK4FF^PmzY}VNZOO1K6PB_J%XUz7NYq+~#ADprmISBY4`z9ip@~^IZV9Gk
zV@FY6V2%=dnJEXT_B(xkSmrjY^eo)SDU>4b!k+#T#dsJ6%Ys#OgbHO@W*W?JP4Fax
zu^BPxR$4*Vt(Z`3W&uw(QX*905X)jOGvxp^ekb6EsgqfgV6FZP`|h_Cq#mW-Q*eep
zML}MHVHL}=VHzp80WZM7*c5EXg{qlY_-hT5_m>cePM|Y9hRE0qwq;dt`(iIMUVtt?
z3@rs+*I~+!pqsQ%UO{pGN4OnzaC;kJq*uhaZd$_YbT%9Wh>T9sak<Fr7SeJ~_|&|C
zdk-GsX5SEcXh%{z*)m@gUS_-i?G4cKTQHI{aD#PldOt*A_6KOYSr|*La9e9(_nsB^
zdBcLHCBe*ofY9*o;%wtd3GJa#diogd{JDxOg;@OiDSizOA{ZSP_sp}G8LtLzG$2m_
zcGWb@2Nz&Rzkqv<7VY?i#v~L*zk_?V7RKTg<n#i0H^B_EJW2o1gg9GS)iAgGn6`HY
zEj<GW4BQrDx2fX!eqnV@@a$#A+kut_<kSQuG@+_lWOKXFR{G#JpM){|J=F9DoGb66
z*#DXE<Z=|C#oK}4;J7F@{!Py5P)N&<p5sb;h>CF@DXM|izySK`soBF`X1oB`8lYwq
zP^CB(7rkgYKSnmApb-8BPIEo7yBf^M*Kn`bl4pZLCcw=84)Bv21sh2zht9|tx=1@2
z4Zn@w!S(J41u_t&s&DOyQkb0ZGUElfT#rm<0~u)(rSA9Ow0!_YP9s0x0r$d5WH%o|
zoB9cE3k7&SDZKWj`hx(xpw0nk^0xkAQFtk37xOD?xZKu<^`wlcxfQeoqIeQd2`@9=
zi|ArK<V+kpbYAjK0<x5(z79#+M&{W)NQy$^Nhs^or=5|NIGEXg5p{+}piy-*vni?A
zqMhLW76p1t3#ODjjj4FDkwz+$7hYz(SMk-eP?x%Cp><OHKU(+3<#n+*dzsmP6$b}n
zSc@l-r@!cN#9n6h0tDZvMDwdn_Qf-BeyJy&7OmZUT4=w&_glGt=?u{PS`)Kkk`o_Q
z@tL;K)*naW{D~3l-siZYlAngR^u^EdQJ-Y;u$P#F&++;5)Sh_RS5@`OvBX}%_<a8Y
X?5nX&f{nAe00000NkvXXu0mjfkCJEf
--- a/browser/themes/winstripe/places/places.css
+++ b/browser/themes/winstripe/places/places.css
@@ -25,17 +25,22 @@ treechildren::-moz-tree-image(title) {
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
   padding-right: 2px;
   margin: 0px 2px;
   width: 16px;
   height: 16px;
 }
 
 treechildren::-moz-tree-image(title, livemarkItem) {
-  list-style-image: url("chrome://browser/skin/livemark-item.png");
+  list-style-image: url("chrome://browser/skin/places/livemark-item.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+treechildren::-moz-tree-image(title, livemarkItem, visited) {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 treechildren::-moz-tree-image(title, separator) {
   list-style-image: none;
   width: 0;
   height: 0;
 }
 
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -63,16 +63,20 @@ TEST_DIRS += mobile/sutagent/android \
           mobile/sutagent/android/fencp \
           mobile/robocop \
           $(NULL)
 endif
 
 ifdef MOZ_APP_BASENAME
 DIST_FILES = application.ini
 
+ifneq (android,$(MOZ_WIDGET_TOOLKIT))
+DIST_FILES += update-settings.ini
+endif
+
 ifdef LIBXUL_SDK
 GRE_MILESTONE = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build Milestone)
 APP_INI_DEPS = $(LIBXUL_DIST)/bin/platform.ini
 else
 GRE_MILESTONE = $(shell tail -n 1 $(topsrcdir)/config/milestone.txt 2>/dev/null || tail -1 $(topsrcdir)/config/milestone.txt)
 APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
 endif
 
@@ -94,16 +98,18 @@ SOURCE_REPO := $(shell cd $(topsrcdir)/$
 ifdef SOURCE_REPO
 DEFINES += -DMOZ_SOURCE_REPO="$(SOURCE_REPO)"
 endif
 
 DEFINES += \
   -DMOZ_APP_BASENAME="$(MOZ_APP_BASENAME)" \
   -DMOZ_APP_VENDOR="$(MOZ_APP_VENDOR)" \
   -DMOZ_APP_ID="$(MOZ_APP_ID)" \
+  -DMAR_CHANNEL_ID="$(MAR_CHANNEL_ID)" \
+  -DACCEPTED_MAR_CHANNEL_IDS="$(ACCEPTED_MAR_CHANNEL_IDS)" \
   $(NULL)
 
 ifdef MOZ_APP_PROFILE
 DEFINES += -DMOZ_APP_PROFILE="$(MOZ_APP_PROFILE)"
 endif
 
 ifdef MOZILLA_OFFICIAL
 DEFINES += -DMOZILLA_OFFICIAL
@@ -148,16 +154,22 @@ GARBAGE_DIRS += $(_LEAKTEST_DIR)
 		$(topsrcdir)/build/pgo/blueprint/fancytype-screen.css \
 		$(NULL)
 
 leaktest.py: leaktest.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@
 	chmod +x $@
 GARBAGE += leaktest.py
 
+ifneq (android,$(MOZ_WIDGET_TOOLKIT))
+update-settings.ini: update-settings.ini.in $(APP_INI_DEPS)
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
+GARBAGE += update-settings.ini
+endif
+
 ifdef MOZ_APP_BASENAME
 application.ini: application.ini.in $(APP_INI_DEPS)
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
 GARBAGE += application.ini
 
 ifdef MOZ_APP_STATIC_INI
 application.ini.h: appini_header.py application.ini 
 	$(PYTHON) $^ > $@
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -1,15 +1,15 @@
 #!/usr/bin/python
 
 # The directories end up in the debug info, so the easy way of getting
 # a reproducible build is to run it in a know absolute directory.
 # We use a directory in /builds/slave because the mozilla infrastructure
 # cleans it up automatically.
-base_dir = "/builds/slave/moz-toolschain"
+base_dir = "/builds/slave/moz-toolchain"
 
 source_dir = base_dir + "/src"
 build_dir  = base_dir + "/build"
 aux_inst_dir = build_dir + '/aux_inst'
 old_make = aux_inst_dir + '/bin/make'
 
 ##############################################
 
@@ -53,16 +53,20 @@ def build_package(package_source_dir, pa
            ["%s/configure" % package_source_dir] + configure_args)
     run_in(package_build_dir, [make, "-j8"])
     run_in(package_build_dir, [make, "install"])
 
 def build_aux_tools(base_dir):
     make_build_dir = base_dir + '/make_build'
     build_package(make_source_dir, make_build_dir,
                   ["--prefix=%s" % aux_inst_dir], "make")
+
+    run_in(unifdef_source_dir, ["make"])
+    run_in(unifdef_source_dir, ["make", "prefix=%s" % aux_inst_dir, "install"])
+
     tar_build_dir = base_dir + '/tar_build'
     build_package(tar_source_dir, tar_build_dir,
                   ["--prefix=%s" % aux_inst_dir])
 
 def with_env(env, f):
     old_env = os.environ.copy()
     os.environ.update(env)
     f()
@@ -79,22 +83,27 @@ def build_glibc_aux(stage_dir, inst_dir)
     build_package(glibc_source_dir, glibc_build_dir,
                   ["--disable-profile",
                    "--enable-add-ons=nptl",
                    "--without-selinux",
                    "--enable-kernel=%s" % linux_version,
                    "--libdir=%s/lib64" % inst_dir,
                    "--prefix=%s" % inst_dir])
 
-def build_linux_headers(inst_dir):
+def build_linux_headers_aux(inst_dir):
     run_in(linux_source_dir, [old_make, "headers_check"])
     run_in(linux_source_dir, [old_make, "INSTALL_HDR_PATH=dest",
                                "headers_install"])
     shutil.move(linux_source_dir + "/dest", inst_dir)
 
+def build_linux_headers(inst_dir):
+    def f():
+        build_linux_headers_aux(inst_dir)
+    with_env({"PATH" : aux_inst_dir + "/bin:%s" % os.environ["PATH"]}, f)
+
 def build_one_stage(env, stage_dir, is_stage_one):
     def f():
         build_one_stage_aux(stage_dir, is_stage_one)
     with_env(env, f)
 
 def build_one_stage_aux(stage_dir, is_stage_one):
     os.mkdir(stage_dir)
 
@@ -162,65 +171,71 @@ binutils_version = "2.21.1"
 glibc_version = "2.5.1"
 linux_version = "2.6.18"
 tar_version = "1.26"
 make_version = "3.81"
 gcc_version = "4.5.2"
 mpfr_version = "2.4.2"
 gmp_version = "5.0.1"
 mpc_version = "0.8.1"
+unifdef_version = "2.6"
 
 binutils_source_uri = "http://ftp.gnu.org/gnu/binutils/binutils-%sa.tar.bz2" % \
     binutils_version
 glibc_source_uri = "http://ftp.gnu.org/gnu/glibc/glibc-%s.tar.bz2" % \
     glibc_version
 linux_source_uri = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-%s.tar.bz2" % \
     linux_version
 tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \
     tar_version
 make_source_uri = "http://ftp.gnu.org/gnu/make/make-%s.tar.bz2" % \
     make_version
+unifdef_source_uri = "http://dotat.at/prog/unifdef/unifdef-%s.tar.gz" % \
+    unifdef_version
 gcc_source_uri = "http://ftp.gnu.org/gnu/gcc/gcc-%s/gcc-%s.tar.bz2" % \
     (gcc_version, gcc_version)
 mpfr_source_uri = "http://www.mpfr.org/mpfr-%s/mpfr-%s.tar.bz2" % \
     (mpfr_version, mpfr_version)
 gmp_source_uri = "http://ftp.gnu.org/gnu/gmp/gmp-%s.tar.bz2" % gmp_version
 mpc_source_uri = "http://www.multiprecision.org/mpc/download/mpc-%s.tar.gz" % \
     mpc_version
 
 binutils_source_tar = download_uri(binutils_source_uri)
 glibc_source_tar = download_uri(glibc_source_uri)
 linux_source_tar = download_uri(linux_source_uri)
 tar_source_tar = download_uri(tar_source_uri)
 make_source_tar = download_uri(make_source_uri)
+unifdef_source_tar = download_uri(unifdef_source_uri)
 mpc_source_tar = download_uri(mpc_source_uri)
 mpfr_source_tar = download_uri(mpfr_source_uri)
 gmp_source_tar = download_uri(gmp_source_uri)
 gcc_source_tar = download_uri(gcc_source_uri)
 
 binutils_source_dir  = build_source_dir('binutils-', binutils_version)
 glibc_source_dir  = build_source_dir('glibc-', glibc_version)
 linux_source_dir  = build_source_dir('linux-', linux_version)
 tar_source_dir  = build_source_dir('tar-', tar_version)
 make_source_dir  = build_source_dir('make-', make_version)
+unifdef_source_dir  = build_source_dir('unifdef-', unifdef_version)
 mpc_source_dir  = build_source_dir('mpc-', mpc_version)
 mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
 gmp_source_dir  = build_source_dir('gmp-', gmp_version)
 gcc_source_dir  = build_source_dir('gcc-', gcc_version)
 
 if not os.path.exists(source_dir):
     os.makedirs(source_dir)
     extract(binutils_source_tar, source_dir)
     patch('binutils-deterministic.patch', 1, binutils_source_dir)
     extract(glibc_source_tar, source_dir)
     extract(linux_source_tar, source_dir)
     patch('glibc-deterministic.patch', 1, glibc_source_dir)
     run_in(glibc_source_dir, ["autoconf"])
     extract(tar_source_tar, source_dir)
     extract(make_source_tar, source_dir)
+    extract(unifdef_source_tar, source_dir)
     extract(mpc_source_tar, source_dir)
     extract(mpfr_source_tar, source_dir)
     extract(gmp_source_tar, source_dir)
     extract(gcc_source_tar, source_dir)
     patch('plugin_finish_decl.diff', 0, gcc_source_dir)
     patch('pr49911.diff', 1, gcc_source_dir)
     patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
 
new file mode 100644
--- /dev/null
+++ b/build/update-settings.ini.in
@@ -0,0 +1,44 @@
+#if 0
+; ***** 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 MAR channel config.
+;
+; The Initial Developer of the Original Code is
+; Mozilla Foundation.
+; Portions created by the Initial Developer are Copyright (C) 2011
+; the Initial Developer. All Rights Reserved.
+;
+; Contributor(s):
+;   Brian R. Bondy <netzen@gmail.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 *****
+#endif
+; If you modify this file updates may fail.
+; Do not modify this file.
+
+#filter substitution
+[Settings]
+ACCEPTED_MAR_CHANNEL_IDS=@ACCEPTED_MAR_CHANNEL_IDS@
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -48,16 +48,18 @@ FIREFOX_VERSION	= @FIREFOX_VERSION@
 
 MOZ_BUILD_APP = @MOZ_BUILD_APP@
 MOZ_APP_NAME	= @MOZ_APP_NAME@
 MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@
 MOZ_APP_BASENAME = @MOZ_APP_BASENAME@
 MOZ_APP_VENDOR = @MOZ_APP_VENDOR@
 MOZ_APP_PROFILE = @MOZ_APP_PROFILE@
 MOZ_APP_ID = @MOZ_APP_ID@
+MAR_CHANNEL_ID = @MAR_CHANNEL_ID@
+ACCEPTED_MAR_CHANNEL_IDS = @ACCEPTED_MAR_CHANNEL_IDS@
 MOZ_PROFILE_MIGRATOR = @MOZ_PROFILE_MIGRATOR@
 MOZ_EXTENSION_MANAGER = @MOZ_EXTENSION_MANAGER@
 MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@
 MOZ_APP_VERSION = @MOZ_APP_VERSION@
 MOZ_UA_BUILDID = @MOZ_UA_BUILDID@
 MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@
 MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@
 
@@ -135,16 +137,17 @@ MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLO
 ENABLE_TESTS	= @ENABLE_TESTS@
 IBMBIDI = @IBMBIDI@
 MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
 ACCESSIBILITY = @ACCESSIBILITY@
 MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@
 XPCOM_USE_LEA = @XPCOM_USE_LEA@
 MOZ_INSTALLER	= @MOZ_INSTALLER@
 MOZ_MAINTENANCE_SERVICE	= @MOZ_MAINTENANCE_SERVICE@
+MOZ_VERIFY_MAR_SIGNATURE	= @MOZ_VERIFY_MAR_SIGNATURE@
 MOZ_UPDATER	= @MOZ_UPDATER@
 MOZ_UPDATE_CHANNEL	= @MOZ_UPDATE_CHANNEL@
 MOZ_UPDATE_PACKAGING	= @MOZ_UPDATE_PACKAGING@
 MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
 NS_ENABLE_TSF = @NS_ENABLE_TSF@
 MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
 MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
 MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
--- a/config/config.mk
+++ b/config/config.mk
@@ -787,18 +787,20 @@ EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
 EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
 EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
+ifneq ($(OS_ARCH),Darwin)
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
+endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
 
 # PGO builds with GCC build objects with instrumentation in a first pass,
 # then objects optimized, without instrumentation, in a second pass. If
 # we overwrite the ojects from the first pass with those from the second,
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -126,20 +126,22 @@ define _INSTALL_TESTS
 $(DIR_INSTALL) $(wildcard $(srcdir)/$(dir)/*) $(testxpcobjdir)/$(relativesrcdir)/$(dir)
 
 endef # do not remove the blank line!
 
 SOLO_FILE ?= $(error Specify a test filename in SOLO_FILE when using check-interactive or check-one)
 
 libs::
 	$(foreach dir,$(XPCSHELL_TESTS),$(_INSTALL_TESTS))
+ifndef NO_XPCSHELL_MANIFEST_CHECK
 	$(PYTHON) $(MOZILLA_DIR)/build/xpccheck.py \
 	  $(topsrcdir) \
 	  $(topsrcdir)/testing/xpcshell/xpcshell.ini \
 	  $(addprefix $(MOZILLA_DIR)/$(relativesrcdir)/,$(XPCSHELL_TESTS))
+endif
 
 testxpcsrcdir = $(topsrcdir)/testing/xpcshell
 
 # Execute all tests in the $(XPCSHELL_TESTS) directories.
 # See also testsuite-targets.mk 'xpcshell-tests' target for global execution.
 xpcshell-tests:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
--- a/configure.in
+++ b/configure.in
@@ -959,18 +959,18 @@ EOF
             AC_MSG_ERROR([windres version $WINDRES_VERSION or higher is required to build.])
         fi
 
         MOZ_WINSDK_MAXVER=0x06010000
     fi # !GNU_CC
 
     AC_DEFINE_UNQUOTED(WINVER,0x$WINVER)
     AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x$WINVER)
-    # Require OS features provided by IE 5.0
-    AC_DEFINE_UNQUOTED(_WIN32_IE,0x0500)
+    # Require OS features provided by IE 6.0 SP2 (XP SP2)
+    AC_DEFINE_UNQUOTED(_WIN32_IE,0x0603)
 
     # If the maximum version supported by this SDK is lower than the target
     # version, error out
     AC_MSG_CHECKING([for Windows SDK being recent enough])
     if $PERL -e "exit(0x$MOZ_WINSDK_TARGETVER > $MOZ_WINSDK_MAXVER)"; then
         AC_MSG_RESULT("yes")
     else
         AC_MSG_RESULT("no")
@@ -6477,16 +6477,33 @@ if test -n "$MOZ_MAINTENANCE_SERVICE"; t
   if test "$OS_ARCH" = "WINNT"; then
     AC_DEFINE(MOZ_MAINTENANCE_SERVICE)
   else
     AC_MSG_ERROR([Can only build with --enable-maintenance-service with a Windows target])
   fi
 fi
 
 dnl ========================================================
+dnl Verify MAR signatures
+dnl ========================================================
+
+MOZ_ARG_ENABLE_BOOL(verify-mar,
+[  --enable-verify-mar     Enable verifying MAR signatures],
+    MOZ_VERIFY_MAR_SIGNATURE=1,
+    MOZ_VERIFY_MAR_SIGNATURE= )
+
+if test -n "$MOZ_VERIFY_MAR_SIGNATURE"; then
+  if test "$OS_ARCH" = "WINNT"; then
+    AC_DEFINE(MOZ_VERIFY_MAR_SIGNATURE)
+  else
+    AC_MSG_ERROR([Can only build with --enable-verify-mar with a Windows target])
+  fi
+fi
+
+dnl ========================================================
 dnl Updater
 dnl ========================================================
 
 MOZ_ARG_DISABLE_BOOL(updater,
 [  --disable-updater       Disable building of updater],
     MOZ_UPDATER=,
     MOZ_UPDATER=1 )
 
@@ -8260,30 +8277,23 @@ if test "$MOZ_TREE_CAIRO"; then
     fi
     AC_SUBST(MOZ_ENABLE_CAIRO_FT)
     AC_SUBST(MOZ_ENABLE_DWRITE_FONT)
     AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
     AC_SUBST(MOZ_ENABLE_D3D9_LAYER)
     AC_SUBST(MOZ_ENABLE_D3D10_LAYER)
     AC_SUBST(CAIRO_FT_CFLAGS)
 
-    if test "$MOZ_DEBUG"; then
-      SANITY_CHECKING_FEATURE="#define CAIRO_DO_SANITY_CHECKING 1"
-    else
-      SANITY_CHECKING_FEATURE="#undef CAIRO_DO_SANITY_CHECKING"
-    fi
-
     AC_SUBST(PS_SURFACE_FEATURE)
     AC_SUBST(PDF_SURFACE_FEATURE)
     AC_SUBST(SVG_SURFACE_FEATURE)
     AC_SUBST(XLIB_SURFACE_FEATURE)
     AC_SUBST(XLIB_XRENDER_SURFACE_FEATURE)
     AC_SUBST(QUARTZ_SURFACE_FEATURE)
     AC_SUBST(QUARTZ_IMAGE_SURFACE_FEATURE)
-    AC_SUBST(XCB_SURFACE_FEATURE)
     AC_SUBST(WIN32_SURFACE_FEATURE)
     AC_SUBST(OS2_SURFACE_FEATURE)
     AC_SUBST(DIRECTFB_SURFACE_FEATURE)
     AC_SUBST(FT_FONT_FEATURE)
     AC_SUBST(FC_FONT_FEATURE)
     AC_SUBST(WIN32_FONT_FEATURE)
     AC_SUBST(WIN32_DWRITE_FONT_FEATURE)
     AC_SUBST(WIN32_D2D_SURFACE_FEATURE)
@@ -8584,16 +8594,17 @@ AC_SUBST(IBMBIDI)
 AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
 AC_SUBST(MOZ_SPELLCHECK)
 AC_SUBST(MOZ_JAVA_COMPOSITOR)
 AC_SUBST(MOZ_ONLY_TOUCH_EVENTS)
 AC_SUBST(MOZ_USER_DIR)
 AC_SUBST(MOZ_CRASHREPORTER)
 AC_SUBST(MOZ_MAINTENANCE_SERVICE)
+AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE)
 AC_SUBST(MOZ_UPDATER)
 AC_SUBST(MOZ_ANGLE)
 AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX)
 AC_SUBST(MOZ_D3DX9_VERSION)
 AC_SUBST(MOZ_D3DX9_CAB)
 AC_SUBST(MOZ_D3DCOMPILER_CAB)
 AC_SUBST(MOZ_D3DX9_DLL)
@@ -8671,16 +8682,18 @@ if test -z "$MOZ_APP_NAME"; then
 fi
 
 AC_SUBST(MOZ_APP_NAME)
 AC_SUBST(MOZ_APP_DISPLAYNAME)
 AC_SUBST(MOZ_APP_BASENAME)
 AC_SUBST(MOZ_APP_VENDOR)
 AC_SUBST(MOZ_APP_PROFILE)
 AC_SUBST(MOZ_APP_ID)
+AC_SUBST(MAR_CHANNEL_ID)
+AC_SUBST(ACCEPTED_MAR_CHANNEL_IDS)
 AC_SUBST(MOZ_PROFILE_MIGRATOR)
 AC_SUBST(MOZ_EXTENSION_MANAGER)
 AC_DEFINE_UNQUOTED(MOZ_APP_UA_NAME, "$MOZ_APP_UA_NAME")
 AC_SUBST(MOZ_APP_UA_NAME)
 AC_DEFINE_UNQUOTED(MOZ_APP_UA_VERSION, "$MOZ_APP_VERSION")
 AC_SUBST(MOZ_APP_VERSION)
 AC_DEFINE_UNQUOTED(MOZ_UA_FIREFOX_VERSION, "$FIREFOX_VERSION")
 AC_DEFINE_UNQUOTED(FIREFOX_VERSION,$FIREFOX_VERSION)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -126,17 +126,16 @@ class nsIWordBreaker;
 class nsIJSRuntimeService;
 class nsEventListenerManager;
 class nsIScriptContext;
 class nsIRunnable;
 class nsIInterfaceRequestor;
 template<class E> class nsCOMArray;
 template<class K, class V> class nsRefPtrHashtable;
 struct JSRuntime;
-class nsIUGenCategory;
 class nsIWidget;
 class nsIDragSession;
 class nsIPresShell;
 class nsIXPConnectJSObjectHolder;
 #ifdef MOZ_XTF
 class nsIXTFService;
 #endif
 #ifdef IBMBIDI
@@ -620,21 +619,16 @@ public:
     return sLineBreaker;
   }
 
   static nsIWordBreaker* WordBreaker()
   {
     return sWordBreaker;
   }
 
-  static nsIUGenCategory* GetGenCat()
-  {
-    return sGenCat;
-  }
-
   /**
    * Regster aObserver as a shutdown observer. A strong reference is held
    * to aObserver until UnregisterShutdownObserver is called.
    */
   static void RegisterShutdownObserver(nsIObserver* aObserver);
   static void UnregisterShutdownObserver(nsIObserver* aObserver);
 
   /**
@@ -2012,17 +2006,16 @@ private:
   static nsIStringBundleService* sStringBundleService;
   static nsIStringBundle* sStringBundles[PropertiesFile_COUNT];
 
   static nsIContentPolicy* sContentPolicyService;
   static bool sTriedToGetContentPolicy;
 
   static nsILineBreaker* sLineBreaker;
   static nsIWordBreaker* sWordBreaker;
-  static nsIUGenCategory* sGenCat;
 
   static nsIScriptRuntime* sScriptRuntimes[NS_STID_ARRAY_UBOUND];
   static PRInt32 sScriptRootCount[NS_STID_ARRAY_UBOUND];
   static PRUint32 sJSGCThingRootCount;
 
 #ifdef IBMBIDI
   static nsIBidiKeyboard* sBidiKeyboard;
 #endif
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -686,16 +686,17 @@ DragDataProducer::Produce(nsDOMDataTrans
     if (*aSelection) {
       rv = nsCopySupport::GetTransferableForSelection(*aSelection, doc,
                                                       getter_AddRefs(transferable));
     }
     else {
       rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
                                                  getter_AddRefs(transferable));
     }
+    NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsISupportsString> data;
     PRUint32 dataSize;
     rv = transferable->GetTransferData(kHTMLMime, getter_AddRefs(data), &dataSize);
     if (NS_SUCCEEDED(rv)) {
       data->GetData(mHtmlString);
     }
     rv = transferable->GetTransferData(kHTMLContext, getter_AddRefs(data), &dataSize);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -117,16 +117,17 @@
 #ifdef MOZ_XTF
 #include "nsIXTFService.h"
 static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
 #endif
 #include "nsIMIMEService.h"
 #include "nsLWBrkCIID.h"
 #include "nsILineBreaker.h"
 #include "nsIWordBreaker.h"
+#include "nsUnicodeProperties.h"
 #include "jsdbgapi.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsBindingManager.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsXBLBinding.h"
 #include "nsXBLPrototypeBinding.h"
@@ -149,17 +150,16 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIPermissionManager.h"
 #include "nsIContentPrefService.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIRunnable.h"
 #include "nsDOMJSUtils.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValue.h"
 #include "nsReferencedElement.h"
-#include "nsIUGenCategory.h"
 #include "nsIDragService.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsCPrefetchService.h"
 #include "nsIChromeRegistry.h"
 #include "nsEventDispatcher.h"
@@ -255,17 +255,16 @@ nsDataHashtable<nsISupportsHashKey, Even
 nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nsnull;
 nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nsnull;
 nsIStringBundleService *nsContentUtils::sStringBundleService;
 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
 nsIContentPolicy *nsContentUtils::sContentPolicyService;
 bool nsContentUtils::sTriedToGetContentPolicy = false;
 nsILineBreaker *nsContentUtils::sLineBreaker;
 nsIWordBreaker *nsContentUtils::sWordBreaker;
-nsIUGenCategory *nsContentUtils::sGenCat;
 nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
 PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
 PRUint32 nsContentUtils::sJSGCThingRootCount;
 #ifdef IBMBIDI
 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
 #endif
 PRUint32 nsContentUtils::sScriptBlockerCount = 0;
 #ifdef DEBUG
@@ -384,19 +383,16 @@ nsContentUtils::Init()
   }
 
   rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker);
   NS_ENSURE_SUCCESS(rv, rv);
   
   rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = CallGetService(NS_UNICHARCATEGORY_CONTRACTID, &sGenCat);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   if (!InitializeEventTable())
     return NS_ERROR_FAILURE;
 
   if (!sEventListenerManagersHash.ops) {
     static PLDHashTableOps hash_table_ops =
     {
       PL_DHashAllocTable,
       PL_DHashFreeTable,
@@ -972,17 +968,17 @@ nsContentUtils::IsPunctuationMarkAt(cons
     }
   }
   return false;
 }
 
 // static
 bool nsContentUtils::IsAlphanumeric(PRUint32 aChar)
 {
-  nsIUGenCategory::nsUGenCategory cat = sGenCat->Get(aChar);
+  nsIUGenCategory::nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar);
 
   return (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kNumber);
 }
  
 // static
 bool nsContentUtils::IsAlphanumericAt(const nsTextFragment* aFrag, PRUint32 aOffset)
 {
   PRUnichar h = aFrag->CharAt(aOffset);
@@ -1133,17 +1129,16 @@ nsContentUtils::Shutdown()
   sXPConnect = nsnull;
   sThreadJSContextStack = nsnull;
   NS_IF_RELEASE(sSecurityManager);
   NS_IF_RELEASE(sNameSpaceManager);
   NS_IF_RELEASE(sParserService);
   NS_IF_RELEASE(sIOService);
   NS_IF_RELEASE(sLineBreaker);
   NS_IF_RELEASE(sWordBreaker);
-  NS_IF_RELEASE(sGenCat);
 #ifdef MOZ_XTF
   NS_IF_RELEASE(sXTFService);
 #endif
   NS_IF_RELEASE(sImgLoader);
   NS_IF_RELEASE(sImgCache);
 #ifdef IBMBIDI
   NS_IF_RELEASE(sBidiKeyboard);
 #endif
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -39,17 +39,16 @@
  */
 
 #include "nsDOMTokenList.h"
 
 #include "nsAttrValue.h"
 #include "nsContentUtils.h"
 #include "nsDOMError.h"
 #include "nsGenericElement.h"
-#include "nsHashSets.h"
 
 
 nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
   : mElement(aElement),
     mAttrAtom(aAttrAtom)
 {
   // We don't add a reference to our element. If it goes away,
   // we'll be told to drop our reference
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -45,17 +45,16 @@
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #include "nsIDocument.h"
 #include "nsWeakReference.h"
 #include "nsWeakPtr.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
-#include "nsHashSets.h"
 #include "nsIDOMXMLDocument.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsStubDocumentObserver.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIContent.h"
 #include "nsEventListenerManager.h"
--- a/content/base/src/nsEventSource.cpp
+++ b/content/base/src/nsEventSource.cpp
@@ -898,23 +898,16 @@ nsEventSource::SetupHttpChannel()
 
   nsCOMPtr<nsIURI> codebase;
   nsresult rv = GetBaseURI(getter_AddRefs(codebase));
   if (NS_SUCCEEDED(rv)) {
     rv = mHttpChannel->SetReferrer(codebase);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
-  mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
-  if (notificationCallbacks != this) {
-    mNotificationCallbacks = notificationCallbacks;
-    mHttpChannel->SetNotificationCallbacks(this);
-  }
-
   return NS_OK;
 }
 
 nsresult
 nsEventSource::InitChannelAndRequestEventSource()
 {
   if (mReadyState == nsIEventSource::CLOSED) {
     return NS_ERROR_ABORT;
@@ -947,16 +940,23 @@ nsEventSource::InitChannelAndRequestEven
   NS_ENSURE_SUCCESS(rv, rv);
 
   mHttpChannel = do_QueryInterface(channel);
   NS_ENSURE_TRUE(mHttpChannel, NS_ERROR_NO_INTERFACE);
 
   rv = SetupHttpChannel();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
+  mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
+  if (notificationCallbacks != this) {
+    mNotificationCallbacks = notificationCallbacks;
+    mHttpChannel->SetNotificationCallbacks(this);
+  }
+
   nsCOMPtr<nsIStreamListener> listener =
     new nsCORSListenerProxy(this, mPrincipal, mHttpChannel,
                             mWithCredentials, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Start reading from the channel
   rv = mHttpChannel->AsyncOpen(listener, nsnull);
   if (NS_SUCCEEDED(rv)) {
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -481,18 +481,23 @@ include $(topsrcdir)/config/rules.mk
 		test_plugin_freezing.html \
 		test_bug638112.html \
 		bug638112-response.txt \
 		bug638112.sjs \
 		test_bug656283.html \
 		test_blobbuilder.html \
 		fileutils.js \
 		test_bug338583.html \
+		test_EventSource_redirects.html \
 		eventsource.resource \
 		eventsource.resource^headers^ \
+		eventsource_redirect.resource \
+		eventsource_redirect.resource^headers^ \
+		eventsource_redirect_to.resource \
+		eventsource_redirect_to.resource^headers^ \
 		badContentType.eventsource \
 		badContentType.eventsource^headers^ \
 		badEventFieldName.eventsource \
 		badEventFieldName.eventsource^headers^ \
 		badHTTPResponseCode.eventsource \
 		badHTTPResponseCode.eventsource^headers^ \
 		badMessageEvent.eventsource \
 		badMessageEvent.eventsource^headers^ \
new file mode 100644
--- /dev/null
+++ b/content/base/test/eventsource_redirect.resource
@@ -0,0 +1,2 @@
+redirected
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/eventsource_redirect.resource^headers^
@@ -0,0 +1,3 @@
+HTTP 301 Moved Permanently
+Location: eventsource_redirect_to.resource
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/eventsource_redirect_to.resource
@@ -0,0 +1,3 @@
+retry:500
+data: 1
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/eventsource_redirect_to.resource^headers^
@@ -0,0 +1,3 @@
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_EventSource_redirects.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=716841
+-->
+<head>
+  <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+  <title>Test for Bug 338583</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+</head>
+<body bgColor=white>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=716841">Mozilla Bug 716841</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+  function doTest(test_id) {
+    oldPrefVal = SpecialPowers.getBoolPref("dom.server-events.enabled");
+    SpecialPowers.setBoolPref("dom.server-events.enabled", true);
+
+    ok(true, "here we go");
+
+    source = new EventSource("eventsource_redirect.resource");
+    ok(source.url == "http://mochi.test:8888/tests/content/base/test/eventsource_redirect.resource", "Test failed.");
+    ok(source.readyState == 0 || source.readyState == 1, "Test failed.");
+
+    source.onopen = function (event) {
+      ok(true, "opened");
+    };
+
+    source.onmessage = function (event) {
+      ok(true, "event received");
+      source.close();
+      SimpleTest.finish();
+    };
+
+    source.onerror = function (event) {
+      ok(false, "received onError: " + event);
+      source.close();
+      SimpleTest.finish();
+    };
+
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  addLoadEvent(doTest);
+
+</script>
+</pre>
+
+</body>
+</html>
+
--- a/content/canvas/src/CustomQS_Canvas2D.h
+++ b/content/canvas/src/CustomQS_Canvas2D.h
@@ -267,17 +267,17 @@ nsIDOMCanvasRenderingContext2D_CreateIma
 
         uint32_t data_width, data_height;
         if (!GetImageDataDimensions(cx, dataObject, &data_width, &data_height))
             return false;
 
         return CreateImageData(cx, data_width, data_height, NULL, 0, 0, vp);
     }
 
-    jsdouble width, height;
+    double width, height;
     if (!JS_ValueToNumber(cx, argv[0], &width) ||
         !JS_ValueToNumber(cx, argv[1], &height))
         return false;
 
     if (!NS_finite(width) || !NS_finite(height))
         return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
     if (!width || !height)
@@ -306,17 +306,17 @@ nsIDOMCanvasRenderingContext2D_GetImageD
     if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, tvr.jsval_addr(), nsnull))
         return JS_FALSE;
 
     if (argc < 4)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
-    jsdouble xd, yd, width, height;
+    double xd, yd, width, height;
     if (!JS_ValueToNumber(cx, argv[0], &xd) ||
         !JS_ValueToNumber(cx, argv[1], &yd) ||
         !JS_ValueToNumber(cx, argv[2], &width) ||
         !JS_ValueToNumber(cx, argv[3], &height))
         return false;
 
     if (!NS_finite(xd) || !NS_finite(yd) ||
         !NS_finite(width) || !NS_finite(height))
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -484,25 +484,19 @@ WebGLContext::SetDimensions(PRInt32 widt
         }
         LogMessage("Using software rendering via OSMesa (THIS WILL BE SLOW)");
     }
 
 #ifdef XP_WIN
     // if we want EGL, try it now
     if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
         gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
-        if (gl) {
-            if (InitAndValidateGL()) {
-                if (useANGLE) {
-                    gl->SetFlushGuaranteesResolve(true);
-                }
-            } else {
-                LogMessage("Error during ANGLE OpenGL ES initialization");
-                return NS_ERROR_FAILURE;
-            }
+        if (gl && !InitAndValidateGL()) {
+            LogMessage("Error during ANGLE OpenGL ES initialization");
+            return NS_ERROR_FAILURE;
         }
     }
 #endif
 
     // try the default provider, whatever that is
     if (!gl && useOpenGL) {
         gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
         if (gl && !InitAndValidateGL()) {
--- a/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
+++ b/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
@@ -24,130 +24,150 @@ description("This test verifies the func
 
 debug("");
 
 var wtu = WebGLTestUtils;
 var canvas = document.getElementById("canvas");
 var gl = create3DContext(canvas);
 var ext = null;
 
+var getExtension = function(){
+    ext = gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
+    if(ext) return;
+
+    ext = gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic");
+    if(ext) return;
+
+    ext = gl.getExtension("EXT_texture_filter_anisotropic");
+    if(ext) return;
+}
+
+var listsExtension = function(){
+    var supported = gl.getSupportedExtensions();
+    if(supported.indexOf("MOZ_EXT_texture_filter_anisotropic") >= 0) return true;
+    if(supported.indexOf("WEBKIT_EXT_texture_filter_anisotropic") >= 0) return true;
+    if(supported.indexOf("EXT_texture_filter_anisotropic") >= 0) return true;
+
+    return false;
+}
+
 if (!gl) {
     testFailed("WebGL context does not exist");
 } else {
     testPassed("WebGL context exists");
 
     // Run tests with extension disabled
     runHintTestDisabled();
 
     // Query the extension and store globally so shouldBe can access it
-    ext = gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
+    getExtension();
+
     if (!ext) {
         testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
 
         runSupportedTest(false);
     } else {
         testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
 
         runSupportedTest(true);
         runHintTestEnabled();
     }
 }
 
 function runSupportedTest(extensionEnabled) {
-    var supported = gl.getSupportedExtensions();
-    if (supported.indexOf("MOZ_EXT_texture_filter_anisotropic") >= 0) {
+    if (listsExtension()) {
         if (extensionEnabled) {
             testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
         } else {
             testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
         }
     } else {
         if (extensionEnabled) {
             testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
         } else {
-            testPassed("EXt_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
+            testPassed("EXT_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
         }
     }
 }
 
 function runHintTestDisabled() {
-    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension disabled");
+    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
     
-    var MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
-    gl.getParameter(MAX_TEXTURE_MAX_ANISOTROPY);
-    glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
+    var MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+    gl.getParameter(MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY_EXT should not be queryable if extension is disabled");
     
-    debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
-    var TEXTURE_MAX_ANISOTROPY = 0x84FE;
+    debug("Testing TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+    var TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
     var texture = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, texture);
    
-    gl.getTexParameter(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY);
-    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
+    gl.getTexParameter(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be queryable if extension is disabled");
 
-    gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
-    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
+    gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT, 1);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be settable if extension is disabled");
     
-    gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
-    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
+    gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT, 1);
+    glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be settable if extension is disabled");
 
     gl.deleteTexture(texture);
 }
 
 function runHintTestEnabled() {
-    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension enabled");
+    debug("Testing MAX_TEXTURE_MAX_ANISOTROPY_EXT with extension enabled");
 
-    shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY", "0x84FF");
+    shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT", "0x84FF");
 
-    var max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY);
-    glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
+    var max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+    glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY_EXT query should succeed if extension is enabled");
 
     if(max_anisotropy >= 2){
-        testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0");
+        testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY_EXT is 2.0");
     }
     else{
-        testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0, returned values was: " + max_anisotropy);
+        testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY_EXT is 2.0, returned values was: " + max_anisotropy);
     }
     
     // TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
 
-    debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
-    shouldBe("ext.TEXTURE_MAX_ANISOTROPY", "0x84FE");
+    debug("Testing TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+    shouldBe("ext.TEXTURE_MAX_ANISOTROPY_EXT", "0x84FE");
 
     var texture = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, texture);
    
-    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
-    glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
+    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+    glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY_EXT query should succeed if extension is enabled");
 
     if(queried_value == 1){
-        testPassed("Initial value of TEXTURE_MAX_ANISOTROPY is 1.0");
+        testPassed("Initial value of TEXTURE_MAX_ANISOTROPY_EXT is 1.0");
     }
     else{
-        testFailed("Initial value of TEXTURE_MAX_ANISOTROPY should be 1.0, returned value was: " + queried_value);
+        testFailed("Initial value of TEXTURE_MAX_ANISOTROPY_EXT should be 1.0, returned value was: " + queried_value);
     }
 
-    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
-    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
+    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 0);
+    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to < 1 should be an invalid value");
     
-    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
-    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
+    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 0);
+    glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY_EXT set to < 1 should be an invalid value");
     
-    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
-    glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
+    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
+    glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to >= 2 should should succeed");
     
-    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
-    glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
+    gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
+    glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY_EXT set to >= 2 should should succeed");
 
-    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
+    var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
     if(queried_value == max_anisotropy){
-        testPassed("Set value of TEXTURE_MAX_ANISOTROPY matches expecation");
+        testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT matches expecation");
     }
     else{
-        testFailed("Set value of TEXTURE_MAX_ANISOTROPY should be: " + max_anisotropy + " , returned value was: " + queried_value);
+        testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT should be: " + max_anisotropy + " , returned value was: " + queried_value);
     }
 
     gl.deleteTexture(texture);
 }
 
 debug("");
 successfullyParsed = true;
 </script>
--- a/content/events/test/test_bug574663.html
+++ b/content/events/test/test_bug574663.html
@@ -99,30 +99,30 @@ function runTest() {
     nextTest();
   }, win);
 }
 
 function initPrefs()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
-                  getService(Components.interfaces.nsIPrefBranch2);
+                  getService(Components.interfaces.nsIPrefBranch);
   prefSvc.setBoolPref("general.smoothScroll", false);
   // Disables the app level scroll acceleration
   prefSvc.setIntPref("mousewheel.acceleration.start", -1);
   prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
   // Enable zooming for ctrl-scrolling
   prefSvc.setIntPref("mousewheel.withcontrolkey.action", 3);
 }
 
 function clearPrefs()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
-                  getService(Components.interfaces.nsIPrefBranch2);
+                  getService(Components.interfaces.nsIPrefBranch);
 
   prefSvc.clearUserPref("general.smoothScroll");
   prefSvc.clearUserPref("mousewheel.acceleration.start");
   prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
   prefSvc.clearUserPref("mousewheel.withcontrolkey.action");
 }
 
 window.onload = function () {
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -955,19 +955,16 @@ nsGenericHTMLElement::InsertAdjacentHTML
       static_cast<nsINode*>(this)->InsertBefore(fragment, GetFirstChild(), &rv);
       break;
     case eBeforeEnd:
       static_cast<nsINode*>(this)->AppendChild(fragment, &rv);
       break;
     case eAfterEnd:
       destination->InsertBefore(fragment, GetNextSibling(), &rv);
       break;
-    default:
-      NS_NOTREACHED("Bad position.");
-      break;
   }
   return rv;
 }
 
 nsresult
 nsGenericHTMLElement::ScrollIntoView(bool aTop, PRUint8 optional_argc)
 {
   nsIDocument *document = GetCurrentDoc();
--- a/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/content/html/content/src/nsHTMLOptionElement.cpp
@@ -188,51 +188,35 @@ nsHTMLOptionElement::SetSelected(bool aV
 }
 
 NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, selected)
 // GetText returns a whitespace compressed .textContent value.
 NS_IMPL_STRING_ATTR_WITH_FALLBACK(nsHTMLOptionElement, Label, label, GetText)
 NS_IMPL_STRING_ATTR_WITH_FALLBACK(nsHTMLOptionElement, Value, value, GetText)
 NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, Disabled, disabled)
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsHTMLOptionElement::GetIndex(PRInt32* aIndex)
 {
-  NS_ENSURE_ARG_POINTER(aIndex);
-
-  *aIndex = -1; // -1 indicates the index was not found
-
-  // Get our containing select content object.
-  nsHTMLSelectElement* selectElement = GetSelect();
-
-  if (selectElement) {
-    // Get the options from the select object.
-    nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
-    selectElement->GetOptions(getter_AddRefs(options));
+  // When the element is not in a list of options, the index is 0.
+  *aIndex = 0;
 
-    if (options) {
-      // Walk the options to find out where we are in the list (ick, O(n))
-      PRUint32 length = 0;
-      options->GetLength(&length);
-
-      nsCOMPtr<nsIDOMNode> thisOption;
-
-      for (PRUint32 i = 0; i < length; i++) {
-        options->Item(i, getter_AddRefs(thisOption));
-
-        if (thisOption.get() == static_cast<nsIDOMNode *>(this)) {
-          *aIndex = i;
-
-          break;
-        }
-      }
-    }
+  // Only select elements can contain a list of options.
+  nsHTMLSelectElement* selectElement = GetSelect();
+  if (!selectElement) {
+    return NS_OK;
   }
 
-  return NS_OK;
+  nsHTMLOptionCollection* options = selectElement->GetOptions();
+  if (!options) {
+    return NS_OK;
+  }
+
+  // aIndex will not be set if GetOptionsIndex fails.
+  return options->GetOptionIndex(this, 0, true, aIndex);
 }
 
 bool
 nsHTMLOptionElement::Selected() const
 {
   // If we haven't been explictly selected or deselected, use our default value
   if (!mSelectedChanged) {
     return DefaultSelected();
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -1987,16 +1987,18 @@ nsHTMLOptionCollection::DropReference()
 }
 
 nsresult
 nsHTMLOptionCollection::GetOptionIndex(mozilla::dom::Element* aOption,
                                        PRInt32 aStartIndex,
                                        bool aForward,
                                        PRInt32* aIndex)
 {
+  // NOTE: aIndex shouldn't be set if the returned value isn't NS_OK.
+
   PRInt32 index;
 
   // Make the common case fast
   if (aStartIndex == 0 && aForward) {
     index = mElements.IndexOf(aOption);
     if (index == -1) {
       return NS_ERROR_FAILURE;
     }
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -138,17 +138,19 @@ public:
   }
 
   /**
    * Drop the reference to the select.  Called during select destruction.
    */
   void DropReference();
 
   /**
-   * Finds the index of a given option element
+   * Finds the index of a given option element.
+   * If the option isn't part of the collection, return NS_ERROR_FAILURE
+   * without setting aIndex.
    *
    * @param aOption the option to get the index of
    * @param aStartIndex the index to start looking at
    * @param aForward TRUE to look forward, FALSE to look backward
    * @return the option index
    */
   nsresult GetOptionIndex(mozilla::dom::Element* aOption,
                           PRInt32 aStartIndex, bool aForward,
@@ -195,18 +197,18 @@ public:
   }
 
   bool ContainsOption(PRInt32 aIndex, const nsAString& aValue)
   {
     return mValues.Contains(aValue) || mIndices.Contains(aIndex);
   }
 
 private:
-  nsCheapStringSet mValues;
-  nsCheapInt32Set mIndices;
+  nsCheapSet<nsStringHashKey> mValues;
+  nsCheapSet<nsUint32HashKey> mIndices;
 };
 
 class NS_STACK_CLASS nsSafeOptionListMutation
 {
 public:
   /**
    * @param aSelect The select element which option list is being mutated.
    *                Can be null.
--- a/content/html/content/test/forms/Makefile.in
+++ b/content/html/content/test/forms/Makefile.in
@@ -59,13 +59,14 @@ include $(topsrcdir)/config/rules.mk
 		test_label_control_attribute.html \
 		test_output_element.html \
 		test_button_attributes_reflection.html \
 		test_textarea_attributes_reflection.html \
 		test_validation.html \
 		test_maxlength_attribute.html \
 		test_datalist_element.html \
 		test_form_attributes_reflection.html \
+		test_option_index_attribute.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/forms/test_option_index_attribute.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+See those bugs:
+https://bugzilla.mozilla.org/show_bug.cgi?id=720385
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for option.index</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720385">Mozilla Bug 720385</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <datalist>
+    <option></option>
+    <option></option>
+  </datalist>
+  <select>
+    <option></option>
+    <foo>
+      <option></option>
+      <optgroup>
+        <option></option>
+      </optgroup>
+      <option></option>
+    </foo>
+    <option></option>
+  </select>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 720385 **/
+
+var initialIndexes = [ 0, 0, 0, 1, 2, 3, 4 ];
+var options = document.getElementsByTagName('option');
+
+is(options.length, initialIndexes.length,
+   "Must have " + initialIndexes.length +" options");
+
+for (var i=0; i<options.length; ++i) {
+  is(options[i].index, initialIndexes[i], "test");
+}
+
+var o = document.createElement('option');
+is(o.index, 0, "option outside of a document have index=0");
+
+document.body.appendChild(o);
+is(o.index, 0, "option outside of a select have index=0");
+
+var datalist = document.getElementsByTagName('datalist')[0];
+
+datalist.appendChild(o);
+is(o.index, 0, "option outside of a select have index=0");
+
+datalist.removeChild(o);
+is(o.index, 0, "option outside of a select have index=0");
+
+var select = document.getElementsByTagName('select')[0];
+
+select.appendChild(o);
+is(o.index, 5, "option inside a select have an index");
+
+select.removeChild(select.options[0]);
+is(o.index, 4, "option inside a select have an index");
+
+select.insertBefore(o, select.options[0]);
+is(o.index, 0, "option inside a select have an index");
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/content/test/test_bug353415-2.html
+++ b/content/html/content/test/test_bug353415-2.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <html>
 <head>
   <title>Test</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 </head>
 <body>
-<iframe name="submit_frame" onLoad="doCheck();"></iframe>
+<iframe name="submit_frame"></iframe>
 <form method="get" id="form1" target="submit_frame" action="../../../../../blah">
 <table>
 <tr><td>
 <input type="text" name="field1" value="teststring"><br>
 <input type="radio" name="field2" value="0" checked> 0
 <input type="radio" name="field3" value="1"> 1<br>
 <input type="checkbox" name="field4" value="1" checked> 1
 <input type="checkbox" name="field5" value="2"> 2
@@ -47,18 +47,19 @@
 <label name="field11-2"></label>
 <input name="field12-2">
 <input type="button" name="field13-2" value="button">
 <input type="hidden" name="field14-2" value="14">
 </tr>
 </table>
 </form>
 <script>
-	document.forms[0].submit();
+  SimpleTest.waitForExplicitFinish();
 
-	SimpleTest.waitForExplicitFinish();
-        function doCheck(){
-		is(frames['submit_frame'].location.href, "http://mochi.test:8888/blah?field1-2=teststring&field2-2=0&field4-2=1&field6-2=3&field7-2=2&field8-2=8&field9-2=9&field12-2=&field1=teststring&field2=0&field4=1&field6=3&field7=2&field8=8&field9=9&field12=&field14=14&field14-2=14", "Submit string was correct.");
-                SimpleTest.finish();
-	}
+  frames['submit_frame'].onload = function() {
+    is(frames['submit_frame'].location.href, "http://mochi.test:8888/blah?field1-2=teststring&field2-2=0&field4-2=1&field6-2=3&field7-2=2&field8-2=8&field9-2=9&field12-2=&field1=teststring&field2=0&field4=1&field6=3&field7=2&field8=8&field9=9&field12=&field14=14&field14-2=14", "Submit string was correct.");
+    SimpleTest.finish();
+  }
+
+  document.forms[0].submit();
 </script>
 </body>
 </html>
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -89,17 +89,18 @@ nsSMILAnimationFunction::nsSMILAnimation
     mBeginTime(LL_MININT),
     mAnimationElement(nsnull),
     mErrorFlags(0),
     mIsActive(false),
     mIsFrozen(false),
     mLastValue(false),
     mHasChanged(true),
     mValueNeedsReparsingEverySample(false),
-    mPrevSampleWasSingleValueAnimation(false)
+    mPrevSampleWasSingleValueAnimation(false),
+    mWasSkippedInPrevSample(false)
 {
 }
 
 void
 nsSMILAnimationFunction::SetAnimationElement(
     nsISMILAnimationElement* aAnimationElement)
 {
   mAnimationElement = aAnimationElement;
@@ -228,16 +229,17 @@ nsSMILAnimationFunction::Inactivate(bool
 }
 
 void
 nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
                                        nsSMILValue& aResult)
 {
   mHasChanged = false;
   mPrevSampleWasSingleValueAnimation = false;
+  mWasSkippedInPrevSample = false;
 
   // Skip animations that are inactive or in error
   if (!IsActiveOrFrozen() || mErrorFlags != 0)
     return;
 
   // Get the animation values
   nsSMILValueArray values;
   nsresult rv = GetValues(aSMILAttr, values);
--- a/content/smil/nsSMILAnimationFunction.h
+++ b/content/smil/nsSMILAnimationFunction.h
@@ -242,16 +242,34 @@ public:
    *
    * @param aNewTarget A nsSMILTargetIdentifier representing the animation
    *                   target of this function for this sample.
    * @return  true if |aNewTarget| is different from the old cached value;
    *          otherwise, false.
    */
   bool UpdateCachedTarget(const nsSMILTargetIdentifier& aNewTarget);
 
+  /**
+   * Returns true if this function was skipped in the previous sample (because
+   * there was a higher-priority non-additive animation). If a skipped animation
+   * function is later used, then the animation sandwich must be recomposited.
+   */
+  bool WasSkippedInPrevSample() const {
+    return mWasSkippedInPrevSample;
+  }
+
+  /**
+   * Mark this animation function as having been skipped. By marking the
+   * function as skipped, if it is used in a subsequent sample we'll know to
+   * recomposite the sandwich.
+   */
+  void SetWasSkipped() {
+    mWasSkippedInPrevSample = true;
+  }
+
   // Comparator utility class, used for sorting nsSMILAnimationFunctions
   class Comparator {
     public:
       bool Equals(const nsSMILAnimationFunction* aElem1,
                     const nsSMILAnimationFunction* aElem2) const {
         return (aElem1->CompareTo(aElem2) == 0);
       }
       bool LessThan(const nsSMILAnimationFunction* aElem1,
@@ -461,17 +479,18 @@ protected:
   nsSMILValue                   mFrozenValue;
 
   // Allows us to check whether an animation function has changed target from
   // sample to sample (because if neither target nor animated value have
   // changed, we don't have to do anything).
   nsSMILWeakTargetIdentifier    mLastTarget;
 
   // Boolean flags
-  bool                          mIsActive:1;
-  bool                          mIsFrozen:1;
-  bool                          mLastValue:1;
-  bool                          mHasChanged:1;
-  bool                          mValueNeedsReparsingEverySample:1;
-  bool                          mPrevSampleWasSingleValueAnimation:1;
+  bool mIsActive:1;
+  bool mIsFrozen:1;
+  bool mLastValue:1;
+  bool mHasChanged:1;
+  bool mValueNeedsReparsingEverySample:1;
+  bool mPrevSampleWasSingleValueAnimation:1;
+  bool mWasSkippedInPrevSample:1;
 };
 
 #endif // NS_SMILANIMATIONFUNCTION_H_
--- a/content/smil/nsSMILCompositor.cpp
+++ b/content/smil/nsSMILCompositor.cpp
@@ -168,26 +168,41 @@ nsSMILCompositor::CreateSMILAttr()
 }
 
 PRUint32
 nsSMILCompositor::GetFirstFuncToAffectSandwich()
 {
   PRUint32 i;
   for (i = mAnimationFunctions.Length(); i > 0; --i) {
     nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i-1];
-    if (curAnimFunc->UpdateCachedTarget(mKey) ||
-        (!mForceCompositing && curAnimFunc->HasChanged())) {
-      mForceCompositing = true;
-    }
+    // In the following, the lack of short-circuit behavior of |= means that we
+    // will ALWAYS run UpdateCachedTarget (even if mForceCompositing is true)
+    // but only call HasChanged and WasSkippedInPrevSample if necessary.  This
+    // is important since we need UpdateCachedTarget to run in order to detect
+    // changes to the target in subsequent samples.
+    mForceCompositing |=
+      curAnimFunc->UpdateCachedTarget(mKey) ||
+      curAnimFunc->HasChanged() ||
+      curAnimFunc->WasSkippedInPrevSample();
 
     if (curAnimFunc->WillReplace()) {
       --i;
       break;
     }
   }
+  // Mark remaining animation functions as having been skipped so if we later
+  // use them we'll know to force compositing.
+  // Note that we only really need to do this if something has changed
+  // (otherwise we would have set the flag on a previous sample) and if
+  // something has changed mForceCompositing will be true.
+  if (mForceCompositing) {
+    for (PRUint32 j = i; j > 0; --j) {
+      mAnimationFunctions[j-1]->SetWasSkipped();
+    }
+  }
   return i;
 }
 
 void
 nsSMILCompositor::UpdateCachedBaseValue(const nsSMILValue& aBaseValue)
 {
   if (!mCachedBaseValue) {
     // We don't have last sample's base value cached. Assume it's changed.
--- a/content/smil/nsSMILCompositor.h
+++ b/content/smil/nsSMILCompositor.h
@@ -126,14 +126,14 @@ public:
 
   // Member data for detecting when we need to force-recompose
   // ---------------------------------------------------------
   // Flag for tracking whether we need to compose. Initialized to false, but
   // gets flipped to true if we detect that something has changed.
   bool mForceCompositing;
 
   // Cached base value, so we can detect & force-recompose when it changes
-  // from one sample to the next.  (nsSMILAnimationController copies this
+  // from one sample to the next. (nsSMILAnimationController copies this
   // forward from the previous sample's compositor.)
   nsAutoPtr<nsSMILValue> mCachedBaseValue;
 };
 
 #endif // NS_SMILCOMPOSITOR_H_
--- a/content/smil/nsSMILParserUtils.cpp
+++ b/content/smil/nsSMILParserUtils.cpp
@@ -610,21 +610,16 @@ nsSMILParserUtils::ParseValuesGeneric(co
 
   while (tokenizer.hasMoreTokens()) {
     nsresult rv = aParser.Parse(tokenizer.nextToken());
     if (NS_FAILED(rv)) {
       return NS_ERROR_FAILURE;
     }
   }
 
-  // Disallow ;-terminated values lists.
-  if (tokenizer.lastTokenEndedWithSeparator()) {
-    return NS_ERROR_FAILURE;
-  }
-
   return NS_OK;
 }
 
 nsresult
 nsSMILParserUtils::ParseRepeatCount(const nsAString& aSpec,
                                     nsSMILRepeatCount& aResult)
 {
   nsresult rv = NS_OK;
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -50,16 +50,17 @@
 #include "nsThreadUtils.h"
 #include "nsIPresShell.h"
 #include "prdtoa.h"
 #include "plstr.h"
 #include "prtime.h"
 #include "nsString.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Util.h"
+#include "nsCharSeparatedTokenizer.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 // Helper class: InstanceTimeComparator
 
 // Upon inserting an instance time into one of our instance time lists we assign
 // it a serial number. This allows us to sort the instance times in such a way
@@ -1266,38 +1267,37 @@ nsSMILTimedElement::Unlink()
 // Implementation helpers
 
 nsresult
 nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
                                       Element* aContextNode,
                                       bool aIsBegin,
                                       RemovalTestFunction aRemove)
 {
-  PRInt32 start;
-  PRInt32 end = -1;
-  PRInt32 length;
-  nsresult rv = NS_OK;
   TimeValueSpecList& timeSpecsList = aIsBegin ? mBeginSpecs : mEndSpecs;
   InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
 
   ClearSpecs(timeSpecsList, instances, aRemove);
 
   AutoIntervalUpdateBatcher updateBatcher(*this);
 
-  do {
-    start = end + 1;
-    end = aSpec.FindChar(';', start);
-    length = (end == -1) ? -1 : end - start;
+  nsCharSeparatedTokenizer tokenizer(aSpec, ';');
+  if (!tokenizer.hasMoreTokens()) { // Empty list
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = NS_OK;
+  while (tokenizer.hasMoreTokens() && NS_SUCCEEDED(rv)) {
     nsAutoPtr<nsSMILTimeValueSpec>
       spec(new nsSMILTimeValueSpec(*this, aIsBegin));
-    rv = spec->SetSpec(Substring(aSpec, start, length), aContextNode);
+    rv = spec->SetSpec(tokenizer.nextToken(), aContextNode);
     if (NS_SUCCEEDED(rv)) {
       timeSpecsList.AppendElement(spec.forget());
     }
-  } while (end != -1 && NS_SUCCEEDED(rv));
+  }
 
   if (NS_FAILED(rv)) {
     ClearSpecs(timeSpecsList, instances, aRemove);
   }
 
   return rv;
 }
 
@@ -2195,21 +2195,18 @@ nsSMILTimedElement::GetNextMilestone(nsS
         return true;
       }
 
       return false;
     }
 
   case STATE_POSTACTIVE:
     return false;
-
-  default:
-    NS_ABORT_IF_FALSE(false, "Invalid element state");
-    return false;
   }
+  MOZ_NOT_REACHED("Invalid element state");
 }
 
 void
 nsSMILTimedElement::NotifyNewInterval()
 {
   NS_ABORT_IF_FALSE(mCurrentInterval,
       "Attempting to notify dependents of a new interval but the interval "
       "is not set");
@@ -2270,21 +2267,18 @@ nsSMILTimedElement::GetEffectiveBeginIns
     return mCurrentInterval->Begin();
 
   case STATE_WAITING:
   case STATE_POSTACTIVE:
     {
       const nsSMILInterval* prevInterval = GetPreviousInterval();
       return prevInterval ? prevInterval->Begin() : nsnull;
     }
-
-  default:
-    NS_NOTREACHED("Invalid element state");
-    return nsnull;
   }
+  MOZ_NOT_REACHED("Invalid element state");
 }
 
 const nsSMILInterval*
 nsSMILTimedElement::GetPreviousInterval() const
 {
   return mOldIntervals.IsEmpty()
     ? nsnull
     : mOldIntervals[mOldIntervals.Length()-1].get();
--- a/content/smil/test/Makefile.in
+++ b/content/smil/test/Makefile.in
@@ -86,16 +86,17 @@ include $(topsrcdir)/config/rules.mk
 	  test_smilSync.xhtml \
 	  test_smilSyncbaseTarget.xhtml \
 	  test_smilSyncTransform.xhtml \
 	  test_smilTextZoom.xhtml \
 	  test_smilTimeEvents.xhtml \
 	  test_smilTiming.xhtml \
 	  test_smilTimingZeroIntervals.xhtml \
 	  test_smilUpdatedInterval.xhtml \
+	  test_smilValues.xhtml \
 	  test_smilXHR.xhtml \
 	  $(NULL)
 
 # Tests disabled due to intermittent orange
 # test_smilCSSInherit.xhtml disabled until bug 501183 is fixed
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/smil/test/smilAnimateMotionValueLists.js
+++ b/content/smil/test/smilAnimateMotionValueLists.js
@@ -35,26 +35,27 @@
  * 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 ***** */
 
 /* Lists of valid & invalid values for the various <animateMotion> attributes */
 const gValidValues = [
   "10 10",
+  "10 10;",  // Trailing semicolons are allowed
+  "10 10;  ",
   "   10   10em  ",
   "1 2  ; 3,4",
   "1,2;3,4",
   "0 0",
   "0,0",
 ];
 
 const gInvalidValues = [
   ";10 10",
-  "10 10;",  // We treat semicolon-terminated value-lists as failure cases
   "10 10;;",
   "1 2 3",
   "1 2 3 4",
   "1,2;3,4 ,",
   ",", " , ",
   ";", " ; ",
   "a", " a; ", ";a;",
   "", " ",
@@ -123,8 +124,35 @@ const gInvalidPath = [
 
 // paths that at least start with a valid "M" segment are valid - the spec says
 // to parse everything up to the first invalid token
 const gValidPathWithErrors = [
  "M20 20em",
  "m0 0 L30,,30",
  "M10 10 L50 50 abc",
 ];
+
+const gValidKeyPoints = [
+  "0; 0.5; 1",
+  "0;.5;1",
+  "0; 0; 1",
+  "0; 1; 1",
+  "0; 0; 1;", // Trailing semicolons are allowed
+  "0; 0; 1; ",
+  "0; 0.000; 1",
+  "0; 0.000001; 1",
+];
+
+const gInvalidKeyPoints = [
+  "0; 1",
+  "0; 1;",
+  "0",
+  "1",
+  "a",
+  "",
+  "  ",
+  "0; -0.1; 1",
+  "0; 1.1; 1",
+  "0; 0.1; 1.1",
+  "-0.1; 0.1; 1",
+  "0; a; 1",
+  "0;;1",
+];
--- a/content/smil/test/test_smilAnimateMotionInvalidValues.xhtml
+++ b/content/smil/test/test_smilAnimateMotionInvalidValues.xhtml
@@ -59,16 +59,23 @@ function testAttr(aAttrName, aAttrValueA
       // and just test the rotation matrix components
       anim.setAttribute("values", "0 0; 50 50");
       componentsToCheck = CTMUtil.CTM_COMPONENTS_ROTATE;
     } else {
       // Apply a supplementary rotation to make sure that we don't apply it if
       // our value is rejected.
       anim.setAttribute("rotate", Math.PI/4);
       componentsToCheck = CTMUtil.CTM_COMPONENTS_ALL;
+      if (aAttrName == "keyPoints") {
+        // Add three times so we can test a greater range of values for
+        // keyPoints
+        anim.setAttribute("values", "0 0; 25 25; 50 50");
+        anim.setAttribute("keyTimes", "0; 0.5; 1");
+        anim.setAttribute("calcMode", "discrete");
+      }
     }
 
     var curCTM = gRect.getCTM();
     if (aIsValid) {
       var errMsg = "CTM should have changed when applying animateMotion " +
         "with '" + aAttrName + "' set to valid value '" + curVal + "'";
       CTMUtil.assertCTMNotEqual(curCTM, gUnAnimatedCTM, componentsToCheck,
                                 errMsg, aIsTodo);
@@ -153,16 +160,19 @@ function main()
 
   testAttr("by", gValidToBy, true, false);
   testAttr("by", gInvalidToBy, false, false);
 
   testAttr("path", gValidPath, true, false);
   testAttr("path", gInvalidPath, false, false);
   testAttr("path", gValidPathWithErrors, true, false);
 
+  testAttr("keyPoints", gValidKeyPoints, true, false);
+  testAttr("keyPoints", gInvalidKeyPoints, false, false);
+
   testMpathElem(gValidPath, true, false);
   testMpathElem(gInvalidPath, false, false);
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
 ]]>
--- a/content/smil/test/test_smilTiming.xhtml
+++ b/content/smil/test/test_smilTiming.xhtml
@@ -13,101 +13,278 @@
 </svg>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 <![CDATA[
 /** Test for SMIL timing **/
 
 /* Global Variables */
-const svgns="http://www.w3.org/2000/svg";
-var svg = document.getElementById("svg");
-var circle = document.getElementById('circle');
+const svgns = "http://www.w3.org/2000/svg";
+var gSvg    = document.getElementById("svg");
+var gCircle = document.getElementById('circle');
 
 SimpleTest.waitForExplicitFinish();
 
-function createAnim() {
+function main() {
+  ok(gSvg.animationsPaused(), "should be paused by <svg> load handler");
+  is(gSvg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
+
+  var testCases = Array();
+
+  const secPerMin = 60;
+  const secPerHour = secPerMin * 60;
+
+  // In the following tests that compare start times, getStartTime will round
+  // the start time to three decimal places since we expect our implementation
+  // to be millisecond accurate.
+
+  // Offset syntax
+  // -- Basic tests, sign and whitespace
+  testCases.push(StartTimeTest('3s', 3));
+  testCases.push(StartTimeTest('0s', 0));
+  testCases.push(StartTimeTest('+2s', 2));
+  testCases.push(StartTimeTest('-1s\t\r', -1));
+  testCases.push(StartTimeTest('- 1s', -1));
+  testCases.push(StartTimeTest('  -1s', -1));
+  testCases.push(StartTimeTest(' - 1s', -1));
+  testCases.push(StartTimeTest(' \t\n\r-1s', -1));
+  testCases.push(StartTimeTest('+\n5s', 5));
+  testCases.push(StartTimeTest('-\n5s', -5));
+  testCases.push(StartTimeTest('\t 5s', 5));
+  // -- These tests are from SMILANIM 3.6.7
+  testCases.push(StartTimeTest('02:30:03', 2*secPerHour + 30*secPerMin + 3));
+  testCases.push(StartTimeTest('50:00:10.25', 50*secPerHour + 10.25));
+  testCases.push(StartTimeTest('02:33', 2*secPerMin + 33));
+  testCases.push(StartTimeTest('00:10.5', 10.5));
+  testCases.push(StartTimeTest('3.2h', 3.2*secPerHour));
+  testCases.push(StartTimeTest('45min', 45*secPerMin));
+  testCases.push(StartTimeTest('30s', 30));
+  testCases.push(StartTimeTest('5ms', 0.005));
+  testCases.push(StartTimeTest('12.467', 12.467));
+  testCases.push(StartTimeTest('00.5s', 0.5));
+  testCases.push(StartTimeTest('00:00.005', 0.005));
+  // -- Additional tests
+  testCases.push(StartTimeTest('61:59:59', 61*secPerHour + 59*secPerMin + 59));
+  testCases.push(StartTimeTest('02:59.999999999999999999999', 3*secPerMin));
+  testCases.push(StartTimeTest('1234:23:45',
+                               1234*secPerHour + 23*secPerMin + 45));
+  testCases.push(StartTimeTest('61min', 61*secPerMin));
+  testCases.push(StartTimeTest('0:30:03', 30*secPerMin + 3));
+  // -- Fractional precision
+  testCases.push(StartTimeTest('25.4567', 25.457));
+  testCases.push(StartTimeTest('0.123456789', 0.123));
+  testCases.push(StartTimeTest('0.00000000000000000000001', 0));
+  testCases.push(StartTimeTest('-0.00000000000000000000001', 0));
+  testCases.push(StartTimeTest('0.0009', 0.001));
+  testCases.push(StartTimeTest('0.99999999999999999999999999999999999999', 1));
+  testCases.push(StartTimeTest('23.4567ms', 0.023));
+  testCases.push(StartTimeTest('23.7ms', 0.024));
+  // -- Test errors
+  testCases.push(StartTimeTest(' + +3s', 'none'));
+  testCases.push(StartTimeTest(' +-3s', 'none'));
+  testCases.push(StartTimeTest('1:12:12:12', 'none'));
+  testCases.push(StartTimeTest('4:50:60', 'none'));
+  testCases.push(StartTimeTest('4:60:0', 'none'));
+  testCases.push(StartTimeTest('4:60', 'none'));
+  testCases.push(StartTimeTest('4:-1:00', 'none'));
+  testCases.push(StartTimeTest('4 5m', 'none'));
+  testCases.push(StartTimeTest('4 5ms', 'none'));
+  testCases.push(StartTimeTest('02:3:03', 'none'));
+  testCases.push(StartTimeTest('45.7 s', 'none'));
+  testCases.push(StartTimeTest(' 3 h ', 'none'));
+  testCases.push(StartTimeTest('2:33 ', 'none'));
+  testCases.push(StartTimeTest('02:33 2', 'none'));
+  testCases.push(StartTimeTest('\u000B 02:33', 'none'));
+  testCases.push(StartTimeTest('h', 'none'));
+  testCases.push(StartTimeTest('23.s', 'none'));
+  testCases.push(StartTimeTest('23.', 'none'));
+  testCases.push(StartTimeTest('23.54.2s', 'none'));
+  testCases.push(StartTimeTest('23sec', 'none'));
+  testCases.push(StartTimeTest('five', 'none'));
+  testCases.push(StartTimeTest('', 'none'));
+  testCases.push(StartTimeTest('02:33s', 'none'));
+  testCases.push(StartTimeTest('02:33 s', 'none'));
+  testCases.push(StartTimeTest('2.54e6', 'none'));
+  testCases.push(StartTimeTest('02.5:33', 'none'));
+  testCases.push(StartTimeTest('2:-45:33', 'none'));
+  testCases.push(StartTimeTest('2:4.5:33', 'none'));
+  testCases.push(StartTimeTest('45m', 'none'));
+  testCases.push(StartTimeTest(':20:30', 'none'));
+  testCases.push(StartTimeTest('1.5:30', 'none'));
+  testCases.push(StartTimeTest('15:-30', 'none'));
+  testCases.push(StartTimeTest('::30', 'none'));
+  testCases.push(StartTimeTest('15:30s', 'none'));
+  testCases.push(StartTimeTest('2:1.:30', 'none'));
+  testCases.push(StartTimeTest('2:.1:30', 'none'));
+  testCases.push(StartTimeTest('2.0:15:30', 'none'));
+  testCases.push(StartTimeTest('2.:15:30', 'none'));
+  testCases.push(StartTimeTest('.2:15:30', 'none'));
+  testCases.push(StartTimeTest('70:15', 'none'));
+  testCases.push(StartTimeTest('media', 'none'));
+  testCases.push(StartTimeTest('5mi', 'none'));
+  testCases.push(StartTimeTest('5hours', 'none'));
+  testCases.push(StartTimeTest('h05:30', 'none'));
+  testCases.push(StartTimeTest('05:40\x9A', 'none'));
+  testCases.push(StartTimeTest('05:40\u30D5', 'none'));
+  testCases.push(StartTimeTest('05:40β', 'none'));
+
+  // List syntax
+  testCases.push(StartTimeTest('3', 3));
+  testCases.push(StartTimeTest('3;', 3));
+  testCases.push(StartTimeTest('3; ', 3));
+  testCases.push(StartTimeTest('3 ; ', 3));
+  testCases.push(StartTimeTest('3;;', 'none'));
+  testCases.push(StartTimeTest('3;; ', 'none'));
+  testCases.push(StartTimeTest(';3', 'none'));
+  testCases.push(StartTimeTest(' ;3', 'none'));
+  testCases.push(StartTimeTest('3;4', 3));
+  testCases.push(StartTimeTest(' 3 ; 4 ', 3));
+
+  // List syntax on end times
+  testCases.push({
+    'attr' : { 'begin': '0s',
+               'end': '1s; 2s' },
+    'times': [ [ 0, 0 ],
+               [ 1, -100 ] ]
+  });
+  testCases.push({
+    'attr' : { 'begin': '0s',
+               'end': '1s; 2s; ' },
+    'times': [ [ 0, 0 ],
+               [ 1, -100 ] ]
+  });
+  testCases.push({
+    'attr' : { 'begin': '0s',
+               'end': '3s; 2s' },
+    'times': [ [ 0, 0 ],
+               [ 1, 10 ],
+               [ 2, -100 ] ]
+  });
+
+  // Simple case
+  testCases.push({
+    'attr' : { 'begin': '3s' },
+    'times': [ [ 0, -100 ],
+               [ 4, 10 ] ]
+  });
+
+  // Multiple begins
+  testCases.push({
+    'attr' : { 'begin': '2s; 6s',
+               'dur': '2s' },
+    'times': [ [ 0, -100 ],
+               [ 3, 50 ],
+               [ 4, -100 ],
+               [ 7, 50 ],
+               [ 8, -100 ] ]
+  });
+
+  // Negative begins
+  testCases.push({
+    'attr' : { 'begin': '-3s; 1s ; 4s',
+               'dur': '2s ',
+               'fill': 'freeze' },
+    'times': [ [ 0, -100 ],
+               [ 0.5, -100 ],
+               [ 1, 0 ],
+               [ 2, 50 ],
+               [ 3, 100 ],
+               [ 5, 50 ] ]
+  });
+
+  // Sorting
+  testCases.push({
+    'attr' : { 'begin': '-3s; 110s; 1s; 4s; -5s; -10s',
+               'end': '111s; -5s; -15s; 6s; -5s; 1.2s',
+               'dur': '2s ',
+               'fill': 'freeze' },
+    'times': [ [ 0, -100 ],
+               [ 1, 0 ],
+               [ 2, 10 ],
+               [ 4, 0 ],
+               [ 5, 50 ],
+               [ 109, 100 ],
+               [ 110, 0 ],
+               [ 112, 50 ] ]
+  });
+
+  for (var i = 0; i < testCases.length; i++) {
+    gSvg.setCurrentTime(0);
+    var test = testCases[i];
+
+    // Generate string version of params for output messages
+    var params = "";
+    for (var name in test.attr) {
+      params += name + '="' + test.attr[name] + '" ';
+    }
+    params = params.trim();
+
+    // Create animation elements
+    var anim = createAnim(test.attr);
+
+    // Run samples
+    if ('times' in test) {
+      for (var j = 0; j < test.times.length; j++) {
+        var curSample = test.times[j];
+        checkSample(curSample[0], curSample[1], params);
+      }
+    }
+
+    // Check start time
+    if ('startTime' in test) {
+      is(getStartTime(anim), test.startTime,
+         "Got unexpected start time for " + params);
+    }
+
+    anim.parentNode.removeChild(anim);
+  }
+
+  SimpleTest.finish();
+}
+
+function createAnim(attr) {
   var anim = document.createElementNS(svgns,'animate');
   anim.setAttribute('attributeName','cx');
   anim.setAttribute('from','0');
   anim.setAttribute('to','100');
   anim.setAttribute('dur','10s');
   anim.setAttribute('begin','indefinite');
-  return circle.appendChild(anim);
-}
-
-function removeAnim(anim) {
-  anim.parentNode.removeChild(anim);
+  for (name in attr) {
+    anim.setAttribute(name, attr[name]);
+  }
+  return gCircle.appendChild(anim);
 }
 
-function main() {
-  ok(svg.animationsPaused(), "should be paused by <svg> load handler");
-  is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
-
-  var tests =
-    [ testOffsetStartup,
-      testMultipleBegins,
-      testNegativeBegins,
-      testSorting
-    ];
-  for (var i = 0; i < tests.length; i++) {
-    var anim = createAnim();
-    svg.setCurrentTime(0);
-    tests[i](anim);
-    removeAnim(anim);
-  }
-  SimpleTest.finish();
-}
-
-function checkSample(time, expectedValue) {
-  svg.setCurrentTime(time);
-  is(circle.cx.animVal.value, expectedValue);
+function checkSample(time, expectedValue, params) {
+  gSvg.setCurrentTime(time);
+  var msg = "Unexpected sample value for " + params +
+    " at t=" + time + ": ";
+  is(gCircle.cx.animVal.value, expectedValue);
 }
 
-function testOffsetStartup(anim) {
-  anim.setAttribute('begin', '3s');
-  checkSample(0,-100);
-  checkSample(4,10);
-}
-
-function testMultipleBegins(anim) {
-  anim.setAttribute('begin', '2s; 6s');
-  anim.setAttribute('dur', ' 2s');
-  checkSample(0,-100);
-  checkSample(3,50);
-  checkSample(4,-100);
-  checkSample(7,50);
-  checkSample(8,-100);
+function getStartTime(anim) {
+  var startTime;
+  try {
+    startTime = anim.getStartTime();
+    // We round start times to 3 decimal places to make comparisons simpler
+    startTime = parseFloat(startTime.toFixed(3));
+  } catch(e) {
+    if (e.code == DOMException.INVALID_STATE_ERR) {
+      startTime = 'none';
+    } else {
+      ok(false, "Unexpected exception: " + e);
+    }
+  }
+  return startTime;
 }
 
-function testNegativeBegins(anim) {
-  anim.setAttribute('begin', '-3s; 1s ; 4s');
-  anim.setAttribute('dur', '2s ');
-  anim.setAttribute('fill', 'freeze');
-  checkSample(0,-100);
-  checkSample(0.5,-100);
-  checkSample(1,0);
-  checkSample(2,50);
-  checkSample(3,100);
-  checkSample(5,50);
-}
-
-function testSorting(anim) {
-  anim.setAttribute('begin', '-3s; 110s; 1s; 4s; -5s; -10s');
-  anim.setAttribute('end', '111s; -5s; -15s; 6s; -5s; 1.2s');
-  anim.setAttribute('dur', '2s ');
-  anim.setAttribute('fill', 'freeze');
-  checkSample(0,-100);
-  checkSample(1,0);
-  checkSample(2,10);
-  checkSample(4,0);
-  checkSample(5,50);
-  checkSample(109,100);
-  checkSample(110,0);
-  checkSample(112,50);
+function StartTimeTest(beginSpec, expectedStartTime) {
+  return { 'attr'     : { 'begin': beginSpec },
+           'startTime': expectedStartTime };
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/smil/test/test_smilValues.xhtml
@@ -0,0 +1,170 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test for SMIL values</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank"
+  href="https://bugzilla.mozilla.org/show_bug.cgi?id=557885">Mozilla Bug
+  474742</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
+  <circle cx="-100" cy="20" r="15" fill="blue" id="circle"/>
+</svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+/** Test for SMIL values **/
+
+var gSvg = document.getElementById("svg");
+SimpleTest.waitForExplicitFinish();
+
+function main()
+{
+  gSvg.pauseAnimations();
+
+  var testCases = Array();
+
+  // Single value
+  testCases.push({
+    'attr' : { 'values': 'a' },
+    'times': [ [ 0, 'a' ] ]
+  });
+
+  // The parsing below is based on the following discussion:
+  //
+  //   http://lists.w3.org/Archives/Public/www-svg/2011Nov/0136.html
+  //
+  // In summary:
+  // * Values lists are semi-colon delimited and semi-colon terminated.
+  // * However, if there are extra non-whitespace characters after the final
+  //   semi-colon then there's an implied semi-colon at the end.
+  //
+  // This differs to what is specified in SVG 1.1 but is consistent with the
+  // majority of browsers and with existing content (particularly that generated
+  // by Ikivo Animator).
+
+  // Trailing semi-colon
+  testCases.push({
+    'attr' : { 'values': 'a;' },
+    'times': [ [ 0, 'a' ], [ 10, 'a' ] ]
+  });
+
+  // Trailing semi-colon + whitespace
+  testCases.push({
+    'attr' : { 'values': 'a; ' },
+    'times': [ [ 0, 'a' ], [ 10, 'a' ] ]
+  });
+
+  // Whitespace + trailing semi-colon
+  testCases.push({
+    'attr' : { 'values': 'a ;' },
+    'times': [ [ 0, 'a' ], [ 10, 'a' ] ]
+  });
+
+  // Empty at end
+  testCases.push({
+    'attr' : { 'values': 'a;;' },
+    'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, '' ] ]
+  });
+
+  // Empty at end + whitespace
+  testCases.push({
+    'attr' : { 'values': 'a;; ' },
+    'times': [ [ 0, 'a' ], [ 4, 'a' ], [ 5, '' ], [ 10, '' ] ]
+  });
+
+  // Empty in middle
+  testCases.push({
+    'attr' : { 'values': 'a;;b' },
+    'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, 'b' ] ]
+  });
+
+  // Empty in middle + trailing semi-colon
+  testCases.push({
+    'attr' : { 'values': 'a;;b;' },
+    'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, 'b' ] ]
+  });
+
+  // Whitespace in middle
+  testCases.push({
+    'attr' : { 'values': 'a; ;b' },
+    'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, 'b' ] ]
+  });
+
+  // Empty at start
+  testCases.push({
+    'attr' : { 'values': ';a' },
+    'times': [ [ 0, '' ], [ 5, 'a' ], [ 10, 'a' ] ]
+  });
+
+  // Whitespace at start
+  testCases.push({
+    'attr' : { 'values': ' ;a' },
+    'times': [ [ 0, '' ], [ 5, 'a' ], [ 10, 'a' ] ]
+  });
+
+  // Embedded whitespace
+  testCases.push({
+    'attr' : { 'values': ' a b ; c d ' },
+    'times': [ [ 0, 'a b' ], [ 5, 'c d' ], [ 10, 'c d' ] ]
+  });
+
+  // Whitespace only
+  testCases.push({
+    'attr' : { 'values': '  ' },
+    'times': [ [ 0, '' ], [ 10, '' ] ]
+  });
+
+  for (var i = 0; i < testCases.length; i++) {
+    gSvg.setCurrentTime(0);
+    var test = testCases[i];
+
+    // Create animation elements
+    var anim = createAnim(test.attr);
+
+    // Run samples
+    for (var j = 0; j < test.times.length; j++) {
+      var curSample = test.times[j];
+      gSvg.setCurrentTime(curSample[0]);
+      checkSample(anim, curSample[1], curSample[0], i);
+    }
+
+    anim.parentNode.removeChild(anim);
+  }
+
+  SimpleTest.finish();
+}
+
+function createAnim(attr)
+{
+  const svgns = "http://www.w3.org/2000/svg";
+  var anim = document.createElementNS(svgns, 'animate');
+  anim.setAttribute('attributeName','class');
+  anim.setAttribute('dur','10s');
+  anim.setAttribute('begin','0s');
+  anim.setAttribute('fill','freeze');
+  for (name in attr) {
+    anim.setAttribute(name, attr[name]);
+  }
+  return document.getElementById('circle').appendChild(anim);
+}
+
+function checkSample(anim, expectedValue, sampleTime, caseNum)
+{
+  var msg = "Test case " + caseNum +
+    " (values: '" + anim.getAttribute('values') + "')," +
+    "t=" + sampleTime +
+    ": Unexpected sample value:";
+  is(anim.targetElement.className.animVal, expectedValue, msg);
+}
+
+window.addEventListener("load", main, false);
+]]>
+</script>
+</pre>
+</body>
+</html>
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -442,17 +442,17 @@ SVGMotionSMILAnimationFunction::SetKeyPo
   mHasChanged = true;
 
   return NS_OK;
 }
 
 void
 SVGMotionSMILAnimationFunction::UnsetKeyPoints()
 {
-  mKeyTimes.Clear();
+  mKeyPoints.Clear();
   SetKeyPointsErrorFlag(false);
   mHasChanged = true;
 }
 
 nsresult
 SVGMotionSMILAnimationFunction::SetRotate(const nsAString& aRotate,
                                           nsAttrValue& aResult)
 {
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -159,25 +159,25 @@ DestroyMatchList(nsISupports* aKey, nsTe
         aMatch = next;
     }
 
     return PL_DHASH_REMOVE;
 }
 
 nsXULTemplateBuilder::~nsXULTemplateBuilder(void)
 {
+    Uninit(true);
+
     if (--gRefCnt == 0) {
         NS_IF_RELEASE(gRDFService);
         NS_IF_RELEASE(gRDFContainerUtils);
         NS_IF_RELEASE(gSystemPrincipal);
         NS_IF_RELEASE(gScriptSecurityManager);
         NS_IF_RELEASE(gObserverService);
     }
-
-    Uninit(true);
 }
 
 
 nsresult
 nsXULTemplateBuilder::InitGlobals()
 {
     nsresult rv;
 
--- a/docshell/base/nsILoadContext.idl
+++ b/docshell/base/nsILoadContext.idl
@@ -83,9 +83,20 @@ interface nsILoadContext : nsISupports
    * on any URIs that might be around.
    */
   readonly attribute boolean isContent;
 
   /*
    * Attribute that determines if private browsing should be used.
    */
   attribute boolean usePrivateBrowsing;
+
+%{C++
+  /**
+   * De-XPCOMed getter to make call-sites cleaner.
+   */
+  bool UsePrivateBrowsing() {
+    bool usingPB;
+    GetUsePrivateBrowsing(&usingPB);
+    return usingPB;
+  }
+%}
 };
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMRequest.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DOMRequest.h"
+
+#include "mozilla/Util.h"
+#include "nsDOMClassInfo.h"
+#include "DOMError.h"
+#include "nsEventDispatcher.h"
+#include "nsIPrivateDOMEvent.h"
+#include "nsDOMEvent.h"
+
+using mozilla::dom::DOMRequest;
+using mozilla::dom::DOMRequestService;
+
+DOMRequest::DOMRequest(nsIDOMWindow* aWindow)
+  : mDone(false)
+  , mResult(JSVAL_VOID)
+  , mRooted(false)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
+  mOwner = window->IsInnerWindow() ? window.get() :
+                                     window->GetCurrentInnerWindow();
+
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
+  mScriptContext = sgo->GetContext();
+}
+
+DOMCI_DATA(DOMRequest, DOMRequest)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
+                                                  nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
+                                                nsDOMEventTargetHelper)
+  tmp->mResult = JSVAL_VOID;
+  tmp->UnrootResultVal();
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest,
+                                               nsDOMEventTargetHelper)
+  // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
+  // nsDOMEventTargetHelper does it for us.
+  if (JSVAL_IS_GCTHING(tmp->mResult)) {
+    void *gcThing = JSVAL_TO_GCTHING(tmp->mResult);
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResult")
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMRequest)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMDOMRequest)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMRequest)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(DOMRequest, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(DOMRequest, nsDOMEventTargetHelper)
+
+NS_IMPL_EVENT_HANDLER(DOMRequest, success);
+NS_IMPL_EVENT_HANDLER(DOMRequest, error);
+
+NS_IMETHODIMP
+DOMRequest::GetReadyState(nsAString& aReadyState)
+{
+  mDone ? aReadyState.AssignLiteral("done") :
+          aReadyState.AssignLiteral("pending");
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMRequest::GetResult(jsval* aResult)
+{
+  NS_ASSERTION(mDone || mResult == JSVAL_VOID,
+               "Result should be undefined when pending");
+  *aResult = mResult;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMRequest::GetError(nsIDOMDOMError** aError)
+{
+  NS_ASSERTION(mDone || !mError,
+               "Error should be null when pending");
+
+  NS_IF_ADDREF(*aError = mError);
+
+  return NS_OK;
+}
+
+void
+DOMRequest::FireSuccess(jsval aResult)
+{
+  NS_ABORT_IF_FALSE(!mDone, "Already fired success/error");
+
+  mDone = true;
+  RootResultVal();
+  mResult = aResult;
+
+  FireEvent(NS_LITERAL_STRING("success"));
+}
+
+void
+DOMRequest::FireError(const nsAString& aError)
+{
+  NS_ABORT_IF_FALSE(!mDone, "Already fired success/error");
+
+  mDone = true;
+  mError = DOMError::CreateWithName(aError);
+
+  FireEvent(NS_LITERAL_STRING("error"));
+}
+
+void
+DOMRequest::FireEvent(const nsAString& aType)
+{
+  if (NS_FAILED(CheckInnerWindowCorrectness())) {
+    return;
+  }
+
+  nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
+  nsresult rv = event->InitEvent(aType, false, false);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  rv = event->SetTrusted(PR_TRUE);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  bool dummy;
+  DispatchEvent(event, &dummy);
+}
+
+NS_IMPL_ISUPPORTS1(DOMRequestService, nsIDOMRequestService)
+
+NS_IMETHODIMP
+DOMRequestService::CreateRequest(nsIDOMWindow* aWindow,
+                                 nsIDOMDOMRequest** aRequest)
+{
+  NS_ADDREF(*aRequest = new DOMRequest(aWindow));
+  
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMRequestService::FireSuccess(nsIDOMDOMRequest* aRequest,
+                               const jsval& aResult)
+{
+  static_cast<DOMRequest*>(aRequest)->FireSuccess(aResult);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMRequestService::FireError(nsIDOMDOMRequest* aRequest,
+                             const nsAString& aError)
+{
+  static_cast<DOMRequest*>(aRequest)->FireError(aError);
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMRequest.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_domrequest_h__
+#define mozilla_dom_domrequest_h__
+
+#include "nsIDOMDOMRequest.h"
+#include "nsIDOMDOMError.h"
+#include "nsDOMEventTargetHelper.h"
+#include "nsContentUtils.h"
+
+#include "nsCOMPtr.h"
+
+namespace mozilla {
+namespace dom {
+
+class DOMRequest : public nsDOMEventTargetHelper,
+                   public nsIDOMDOMRequest
+{
+  bool mDone;
+  jsval mResult;
+  nsCOMPtr<nsIDOMDOMError> mError;
+  bool mRooted;
+
+  NS_DECL_EVENT_HANDLER(success)
+  NS_DECL_EVENT_HANDLER(error)
+
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMDOMREQUEST
+  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
+
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMRequest,
+                                                         nsDOMEventTargetHelper)
+
+  void FireSuccess(jsval aResult);
+  void FireError(const nsAString& aError);
+
+  DOMRequest(nsIDOMWindow* aWindow);
+
+  virtual ~DOMRequest()
+  {
+    UnrootResultVal();
+  }
+
+private:
+  void FireEvent(const nsAString& aType);
+
+  void RootResultVal()
+  {
+    if (!mRooted) {
+      NS_HOLD_JS_OBJECTS(this, DOMRequest);
+      mRooted = true;
+    }
+  }
+
+  void UnrootResultVal()
+  {
+    if (mRooted) {
+      NS_DROP_JS_OBJECTS(this, DOMRequest);
+      mRooted = false;
+    }
+  }
+};
+
+class DOMRequestService : public nsIDOMRequestService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMREQUESTSERVICE
+
+  // Returns an owning reference! No one should call this but the factory.
+  static DOMRequestService* FactoryCreate()
+  {
+    DOMRequestService* res = new DOMRequestService;
+    NS_ADDREF(res);
+    return res;
+  }
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#define DOMREQUEST_SERVICE_CONTRACTID "@mozilla.org/dom/dom-request-service;1"
+
+#endif // mozilla_dom_domrequest_h__
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -42,16 +42,20 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= dom
 LIBRARY_NAME	= jsdombase_s
 LIBXUL_LIBRARY	= 1
 FORCE_STATIC_LIB = 1
 
+DIRS = \
+  test \
+  $(NULL)
+
 EXTRA_PP_COMPONENTS = \
 		ConsoleAPI.js \
 		ConsoleAPI.manifest \
 		$(NULL)
 
 EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
 		$(NULL)
 
@@ -62,16 +66,17 @@ EXTRA_COMPONENTS = \
 		$(NULL)
 
 EXTRA_JS_MODULES += Webapps.jsm \
 		$(NULL)
 endif
 
 XPIDLSRCS = \
   nsIDOMDOMError.idl \
+  nsIDOMDOMRequest.idl \
   nsIEntropyCollector.idl \
   nsIScriptChannel.idl \
   $(NULL)
 
 EXPORTS = \
   nsDOMCID.h \
   nsDOMClassInfoClasses.h \
   nsDOMClassInfoID.h \
@@ -100,16 +105,17 @@ EXPORTS = \
   nsContentPermissionHelper.h \
   nsStructuredCloneContainer.h \
   nsDOMMemoryReporter.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom
 EXPORTS_mozilla/dom = \
   DOMError.h \
+  DOMRequest.h \
   StructuredCloneTags.h \
   $(NULL)
 
 CPPSRCS =			\
 	nsBarProps.cpp          \
 	nsDOMException.cpp 	\
 	nsDOMWindowUtils.cpp 	\
 	nsJSEnvironment.cpp	\
@@ -130,16 +136,17 @@ CPPSRCS =			\
 	nsDOMScriptObjectFactory.cpp \
 	nsQueryContentEventResult.cpp \
 	nsContentPermissionHelper.cpp \
 	nsStructuredCloneContainer.cpp \
 	nsDOMNavigationTiming.cpp \
 	nsPerformance.cpp	\
 	nsDOMMemoryReporter.cpp \
 	DOMError.cpp \
+	DOMRequest.cpp \
 	Navigator.cpp \
 	$(NULL)
 
 include $(topsrcdir)/dom/dom-config.mk
 
 ifdef MOZ_JSDEBUGGER
 DEFINES += -DMOZ_JSDEBUGGER
 endif
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -532,16 +532,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "CallEvent.h"
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothAdapter.h"
 #endif
 
 #include "DOMError.h"
+#include "DOMRequest.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
@@ -1635,16 +1636,19 @@ static nsDOMClassInfoData sClassInfoData
 
 #ifdef MOZ_B2G_BT
   NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
+                           EVENTTARGET_SCRIPTABLE_FLAGS)
 };
 
 // Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
@@ -4382,16 +4386,21 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(DOMRequest, nsIDOMDOMRequest)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+  DOM_CLASSINFO_MAP_END
+
 #ifdef NS_DEBUG
   {
     PRUint32 i = ArrayLength(sClassInfoData);
 
     if (i != eDOMClassInfoIDCount) {
       NS_ERROR("The number of items in sClassInfoData doesn't match the "
                "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
 
@@ -4458,17 +4467,17 @@ nsDOMClassInfo::GetArrayIndexFromId(JSCo
 
   jsint i;
   if (JSID_IS_INT(id)) {
       i = JSID_TO_INT(id);
   } else {
       JSAutoRequest ar(cx);
 
       jsval idval;
-      jsdouble array_index;
+      double array_index;
       if (!::JS_IdToValue(cx, id, &idval) ||
           !::JS_ValueToNumber(cx, idval, &array_index) ||
           !::JS_DoubleIsInt32(array_index, &i)) {
         return -1;
       }
   }
 
   if (aIsNumber) {
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -541,8 +541,9 @@ DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 #endif
 
 #ifdef MOZ_B2G_BT
 DOMCI_CLASS(BluetoothAdapter)
 #endif
 
 DOMCI_CLASS(DOMError)
+DOMCI_CLASS(DOMRequest)
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2338,18 +2338,27 @@ nsFocusManager::DetermineElementToMoveFo
 {
   *aNextContent = nsnull;
 
   nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
   if (!docShell)
     return NS_OK;
 
   nsCOMPtr<nsIContent> startContent = aStartContent;
-  if (!startContent && aType != MOVEFOCUS_CARET)
-    startContent = aWindow->GetFocusedNode();
+  if (!startContent && aType != MOVEFOCUS_CARET) {
+    if (aType == MOVEFOCUS_FORWARDDOC || aType == MOVEFOCUS_BACKWARDDOC) {
+      // When moving between documents, make sure to get the right
+      // starting content in a descendant.
+      nsCOMPtr<nsPIDOMWindow> focusedWindow;
+      startContent = GetFocusedDescendant(aWindow, true, getter_AddRefs(focusedWindow));
+    }
+    else {
+      startContent = aWindow->GetFocusedNode();
+    }
+  }
 
   nsCOMPtr<nsIDocument> doc;
   if (startContent)
     doc = startContent->GetCurrentDoc();
   else
     doc = do_QueryInterface(aWindow->GetExtantDocument());
   if (!doc)
     return NS_OK;
@@ -2357,21 +2366,21 @@ nsFocusManager::DetermineElementToMoveFo
   LookAndFeel::GetInt(LookAndFeel::eIntID_TabFocusModel,
                       &nsIContent::sTabFocusModel);
 
   if (aType == MOVEFOCUS_ROOT) {
     NS_IF_ADDREF(*aNextContent = GetRootForFocus(aWindow, doc, false, false));
     return NS_OK;
   }
   if (aType == MOVEFOCUS_FORWARDDOC) {
-    NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(true));
+    NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(startContent, true));
     return NS_OK;
   }
   if (aType == MOVEFOCUS_BACKWARDDOC) {
-    NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(false));
+    NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(startContent, false));
     return NS_OK;
   }
   
   nsIContent* rootContent = doc->GetRootElement();
   NS_ENSURE_TRUE(rootContent, NS_OK);
 
   nsIPresShell *presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, NS_OK);
@@ -3131,76 +3140,202 @@ nsFocusManager::GetPreviousDocShell(nsID
 
   if (prevItem)
     GetLastDocShell(prevItem, aResult);
   else
     NS_ADDREF(*aResult = parentItem);
 }
 
 nsIContent*
-nsFocusManager::GetNextTabbableDocument(bool aForward)
+nsFocusManager::GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward)
 {
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (!pm)
+    return nsnull;
+
+  // Iterate through the array backwards if aForward is false.
+  nsTArray<nsIFrame *> popups = pm->GetVisiblePopups();
+  PRInt32 i = aForward ? 0 : popups.Length() - 1;
+  PRInt32 end = aForward ? popups.Length() : -1;
+
+  for (; i != end; aForward ? i++ : i--) {
+    nsIFrame* popupFrame = popups[i];
+    if (aCurrentPopup) {
+      // If the current popup is set, then we need to skip over this popup and
+      // wait until the currently focused popup is found. Once found, the
+      // current popup will be cleared so that the next popup is used.
+      if (aCurrentPopup == popupFrame)
+        aCurrentPopup = nsnull;
+      continue;
+    }
+
+    // Skip over non-panels
+    if (popupFrame->GetContent()->Tag() != nsGkAtoms::panel ||
+        (aDocument && popupFrame->GetContent()->GetCurrentDoc() != aDocument)) {
+      continue;
+    }
+
+    // Find the first focusable content within the popup. If there isn't any
+    // focusable content in the popup, skip to the next popup.
+    nsIPresShell* presShell = popupFrame->PresContext()->GetPresShell();
+    if (presShell) {
+      nsCOMPtr<nsIContent> nextFocus;
+      nsIContent* popup = popupFrame->GetContent();
+      nsresult rv = GetNextTabbableContent(presShell, popup,
+                                           nsnull, popup,
+                                           true, 1, false,
+                                           getter_AddRefs(nextFocus));
+      if (NS_SUCCEEDED(rv) && nextFocus) {
+        return nextFocus.get();
+      }
+    }
+  }
+
+  return nsnull;
+}
+
+nsIContent*
+nsFocusManager::GetNextTabbableDocument(nsIContent* aStartContent, bool aForward)
+{
+  // If currentPopup is set, then the starting content is in a panel.
+  nsIFrame* currentPopup = nsnull;
+  nsCOMPtr<nsIDocument> doc;
   nsCOMPtr<nsIDocShellTreeItem> startItem;
-  if (mFocusedWindow) {
+
+  if (aStartContent) {
+    doc = aStartContent->GetCurrentDoc();
+    if (doc) {
+      startItem = do_QueryInterface(doc->GetWindow()->GetDocShell());
+    }
+
+    // Check if the starting content is inside a panel. Document navigation
+    // must start from this panel instead of the document root.
+    nsIContent* content = aStartContent;
+    while (content) {
+      if (content->NodeInfo()->Equals(nsGkAtoms::panel, kNameSpaceID_XUL)) {
+        currentPopup = content->GetPrimaryFrame();
+        break;
+      }
+      content = content->GetParent();
+    }
+  }
+  else if (mFocusedWindow) {
     startItem = do_QueryInterface(mFocusedWindow->GetDocShell());
+    doc = do_QueryInterface(mFocusedWindow->GetExtantDocument());
   }
   else {
     nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(mActiveWindow);
     startItem = do_QueryInterface(webnav);
+
+    if (mActiveWindow) {
+      doc = do_QueryInterface(mActiveWindow->GetExtantDocument());
+    }
   }
+
   if (!startItem)
     return nsnull;
 
   // perform a depth first search (preorder) of the docshell tree
   // looking for an HTML Frame or a chrome document
-  nsIContent* content = nsnull;
+  nsIContent* content = aStartContent;
   nsCOMPtr<nsIDocShellTreeItem> curItem = startItem;
   nsCOMPtr<nsIDocShellTreeItem> nextItem;
   do {
-    if (aForward) {
-      GetNextDocShell(curItem, getter_AddRefs(nextItem));
-      if (!nextItem) {
-        // wrap around to the beginning, which is the top of the tree
-        startItem->GetRootTreeItem(getter_AddRefs(nextItem));
+    // If moving forward, check for a panel in the starting document. If one
+    // exists with focusable content, return that content instead of the next
+    // document. If currentPopup is set, then, another panel may exist. If no
+    // such panel exists, then continue on to check the next document.
+    // When moving backwards, and the starting content is in a panel, then
+    // check for additional panels in the starting document. If the starting
+    // content is not in a panel, move back to the previous document and check
+    // for panels there.
+
+    bool checkPopups = false;
+    nsCOMPtr<nsPIDOMWindow> nextFrame = nsnull;
+
+    if (doc && (aForward || currentPopup)) {
+      nsIContent* popupContent = GetNextTabbablePanel(doc, currentPopup, aForward);
+      if (popupContent)
+        return popupContent;
+
+      if (!aForward && currentPopup) {
+        // The starting content was in a popup, yet no other popups were
+        // found. Move onto the starting content's document.
+        nextFrame = doc->GetWindow();
       }
     }
-    else {
-      GetPreviousDocShell(curItem, getter_AddRefs(nextItem));
-      if (!nextItem) {
-        // wrap around to the end, which is the last item in the tree
-        nsCOMPtr<nsIDocShellTreeItem> rootItem;
-        startItem->GetRootTreeItem(getter_AddRefs(rootItem));
-        GetLastDocShell(rootItem, getter_AddRefs(nextItem));
+
+    // Look for the next or previous document.
+    if (!nextFrame) {
+      if (aForward) {
+        GetNextDocShell(curItem, getter_AddRefs(nextItem));
+        if (!nextItem) {
+          // wrap around to the beginning, which is the top of the tree
+          startItem->GetRootTreeItem(getter_AddRefs(nextItem));
+        }
       }
+      else {
+        GetPreviousDocShell(curItem, getter_AddRefs(nextItem));
+        if (!nextItem) {
+          // wrap around to the end, which is the last item in the tree
+          nsCOMPtr<nsIDocShellTreeItem> rootItem;
+          startItem->GetRootTreeItem(getter_AddRefs(rootItem));
+          GetLastDocShell(rootItem, getter_AddRefs(nextItem));
+        }
+
+        // When going back to the previous document, check for any focusable
+        // popups in that previous document first.
+        checkPopups = true;
+      }
+
+      curItem = nextItem;
+      nextFrame = do_GetInterface(nextItem);
     }
 
-    curItem = nextItem;
-    nsCOMPtr<nsPIDOMWindow> nextFrame = do_GetInterface(nextItem);
     if (!nextFrame)
       return nsnull;
 
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(nextFrame->GetExtantDocument());
-    if (doc && !doc->EventHandlingSuppressed()) {
-      content = GetRootForFocus(nextFrame, doc, true, true);
-      if (content && !GetRootForFocus(nextFrame, doc, false, false)) {
-        // if the found content is in a chrome shell or a frameset, navigate
-        // forward one tabbable item so that the first item is focused. Note
-        // that we always go forward and not back here.
-        nsCOMPtr<nsIContent> nextFocus;
-        Element* rootElement = doc->GetRootElement();
-        nsIPresShell* presShell = doc->GetShell();
-        if (presShell) {
-          nsresult rv = GetNextTabbableContent(presShell, rootElement,
-                                               nsnull, rootElement,
-                                               true, 1, false,
-                                               getter_AddRefs(nextFocus));
-          return NS_SUCCEEDED(rv) ? nextFocus.get() : nsnull;
-        }
+    // Clear currentPopup for the next iteration
+    currentPopup = nsnull;
+
+    // If event handling is suppressed, move on to the next document. Set
+    // content to null so that the popup check will be skipped on the next
+    // loop iteration.
+    doc = do_QueryInterface(nextFrame->GetExtantDocument());
+    if (!doc || doc->EventHandlingSuppressed()) {
+      content = nsnull;
+      continue;
+    }
+
+    if (checkPopups) {
+      // When iterating backwards, check the panels of the previous document
+      // first. If a panel exists that has focusable content, focus that.
+      // Otherwise, continue on to focus the document.
+      nsIContent* popupContent = GetNextTabbablePanel(doc, nsnull, false);
+      if (popupContent)
+        return popupContent;
+    }
+
+    content = GetRootForFocus(nextFrame, doc, true, true);
+    if (content && !GetRootForFocus(nextFrame, doc, false, false)) {
+      // if the found content is in a chrome shell or a frameset, navigate
+      // forward one tabbable item so that the first item is focused. Note
+      // that we always go forward and not back here.
+      nsCOMPtr<nsIContent> nextFocus;
+      Element* rootElement = doc->GetRootElement();
+      nsIPresShell* presShell = doc->GetShell();
+      if (presShell) {
+        nsresult rv = GetNextTabbableContent(presShell, rootElement,
+                                             nsnull, rootElement,
+                                             true, 1, false,
+                                             getter_AddRefs(nextFocus));
+        return NS_SUCCEEDED(rv) ? nextFocus.get() : nsnull;
       }
     }
+
   } while (!content);
 
   return content;
 }
 
 void
 nsFocusManager::GetFocusInSelection(nsPIDOMWindow* aWindow,
                                     nsIContent* aStartSelection,
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -454,26 +454,41 @@ protected:
 
   /**
    * Get the previous docshell child of aItem and return it in aResult.
    */
   void GetPreviousDocShell(nsIDocShellTreeItem* aItem,
                            nsIDocShellTreeItem** aResult);
 
   /**
-   * Get the tabbable next document from the currently focused frame if
-   * aForward is true, or the previously tabbable document if aForward is
-   * false. If this document is a chrome or frameset document, returns
-   * the first focusable element within this document, otherwise, returns
-   * the root node of the document.
+   * Determine the first panel with focusable content in document tab order
+   * from the given document. aForward indicates the direction to scan. If
+   * aCurrentPopup is set to a panel, the next or previous popup after
+   * aCurrentPopup after it is used. If aCurrentPopup is null, then the first
+   * or last popup is used. If a panel has no focusable content, it is skipped.
+   * Null is returned if no panel is open or no open panel contains a focusable
+   * element.
+   */
+  nsIContent* GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward);
+
+  /**
+   * Get the tabbable next document from aStartContent or, if null, the
+   * currently focused frame if aForward is true, or the previously tabbable
+   * document if aForward is false. If this document is a chrome or frameset
+   * document, returns the first focusable element within this document,
+   * otherwise, returns the root node of the document.
+   *
+   *
+   * Panels with focusable content are also placed in the cycling order, just
+   * after the document containing that panel.
    *
    * This method would be used for document navigation, which is typically
    * invoked by pressing F6.
    */
-  nsIContent* GetNextTabbableDocument(bool aForward);
+  nsIContent* GetNextTabbableDocument(nsIContent* aStartContent, bool aForward);
 
   /**
    * Retreives a focusable element within the current selection of aWindow.
    * Currently, this only detects links.
    *  
    * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
    * which is used, for example, to focus links as the caret is moved over
    * them.
new file mode 100644
--- /dev/null
+++ b/dom/base/nsIDOMDOMRequest.idl
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEventTarget.idl"
+
+interface nsIDOMDOMError;
+interface nsIDOMWindow;
+
+[scriptable, builtinclass, uuid(a3ad2846-ffb2-48d7-a786-2254cb82560d)]
+interface nsIDOMDOMRequest : nsIDOMEventTarget
+{
+  readonly attribute DOMString readyState; // "pending" or "done"
+
+  readonly attribute jsval result;
+  readonly attribute nsIDOMDOMError error;
+
+           attribute nsIDOMEventListener onsuccess;
+           attribute nsIDOMEventListener onerror;
+};
+
+[scriptable, builtinclass, uuid(eebcdf29-f8fa-4c36-bbc7-2146b1cbaf7b)]
+interface nsIDOMRequestService : nsISupports
+{
+  nsIDOMDOMRequest createRequest(in nsIDOMWindow window);
+
+  void fireSuccess(in nsIDOMDOMRequest request, in jsval result);
+  void fireError(in nsIDOMDOMRequest request, in DOMString error);
+};
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -3270,18 +3270,19 @@ nsJSContext::CycleCollectNow(nsICycleCol
   for (PRInt32 i = 0; i < aExtraForgetSkippableCalls; ++i) {
     nsCycleCollector_forgetSkippable();
   }
 
   // nsCycleCollector_forgetSkippable may mark some gray js to black.
   if (!sCleanupSinceLastGC && aExtraForgetSkippableCalls >= 0) {
     nsCycleCollector_forgetSkippable();
   }
-  PRUint32 collected = nsCycleCollector_collect(aListener);
-  sCCollectedWaitingForGC += collected;
+  nsCycleCollectorResults ccResults;
+  nsCycleCollector_collect(&ccResults, aListener);
+  sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed;
 
   // If we collected a substantial amount of cycles, poke the GC since more objects
   // might be unreachable now.
   if (sCCollectedWaitingForGC > 250) {
     PokeGC(js::gcreason::CC_WAITING);
   }
 
   PRTime now = PR_Now();
@@ -3298,26 +3299,33 @@ nsJSContext::CycleCollectNow(nsICycleCol
   if (sPostGCEventsToConsole) {
     PRTime delta = 0;
     if (sFirstCollectionTime) {
       delta = now - sFirstCollectionTime;
     } else {
       sFirstCollectionTime = now;
     }
 
+    nsString gcmsg;
+    if (ccResults.mForcedGC) {
+      gcmsg.AssignLiteral(", forced a GC");
+    }
+
     NS_NAMED_MULTILINE_LITERAL_STRING(kFmt,
-      NS_LL("CC(T+%.1f) collected: %lu (%lu waiting for GC), suspected: %lu, duration: %llu ms.\n")
+      NS_LL("CC(T+%.1f) duration: %llums, suspected: %lu, visited: %lu RCed and %lu GCed, collected: %lu RCed and %lu GCed (%lu waiting for GC)%s\n")
       NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, removed: %lu"));
     nsString msg;
     PRUint32 cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1;
     sMinForgetSkippableTime = (sMinForgetSkippableTime == PR_UINT32_MAX)
       ? 0 : sMinForgetSkippableTime;
     msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC,
-                                        collected, sCCollectedWaitingForGC, suspected,
-                                        (now - start) / PR_USEC_PER_MSEC,
+                                        (now - start) / PR_USEC_PER_MSEC, suspected,
+                                        ccResults.mVisitedRefCounted, ccResults.mVisitedGCed,
+                                        ccResults.mFreedRefCounted, ccResults.mFreedGCed,
+                                        sCCollectedWaitingForGC, gcmsg.get(),
                                         sForgetSkippableBeforeCC,
                                         sMinForgetSkippableTime / PR_USEC_PER_MSEC,
                                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
                                         (sTotalForgetSkippableTime / cleanups) /
                                           PR_USEC_PER_MSEC,
                                         sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
                                         sRemovedPurples));
     nsCOMPtr<nsIConsoleService> cs =
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -40,16 +40,17 @@
 #include "nsScreen.h"
 #include "nsIDocShell.h"
 #include "nsPresContext.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsLayoutUtils.h"
+#include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
 /* static */ bool nsScreen::sInitialized = false;
 /* static */ bool nsScreen::sAllowScreenEnabledProperty = false;
 /* static */ bool nsScreen::sAllowScreenBrightnessProperty = false;
 
@@ -257,71 +258,83 @@ nsScreen::GetAvailRect(nsRect& aRect)
   aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
   aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);
 
   return NS_OK;
 }
 
 namespace {
 
-bool
-IsChromeType(nsIDocShell *aDocShell)
-{
+bool IsWhiteListed(nsIDocShell *aDocShell) {
   nsCOMPtr<nsIDocShellTreeItem> ds = do_QueryInterface(aDocShell);
   if (!ds) {
     return false;
   }
 
   PRInt32 itemType;
   ds->GetItemType(&itemType);
-  return itemType == nsIDocShellTreeItem::typeChrome;
+  if (itemType == nsIDocShellTreeItem::typeChrome) {
+    return true;
+  }
+
+  nsCOMPtr<nsIDocument> doc = do_GetInterface(aDocShell);
+  nsIPrincipal *principal = doc->NodePrincipal();
+
+  nsCOMPtr<nsIURI> principalURI;
+  principal->GetURI(getter_AddRefs(principalURI));
+  if (nsContentUtils::URIIsChromeOrInPref(principalURI,
+                                          "dom.mozScreenWhitelist")) {
+    return true;
+  }
+
+  return false;
 }
 
 } // anonymous namespace
 
 nsresult
 nsScreen::GetMozEnabled(bool *aEnabled)
 {
-  if (!sAllowScreenEnabledProperty || !IsChromeType(mDocShell)) {
+  if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
     *aEnabled = true;
     return NS_OK;
   }
 
   *aEnabled = hal::GetScreenEnabled();
   return NS_OK;
 }
 
 nsresult
 nsScreen::SetMozEnabled(bool aEnabled)
 {
-  if (!sAllowScreenEnabledProperty || !IsChromeType(mDocShell)) {
+  if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
     return NS_OK;
   }
 
   // TODO bug 707589: When the screen's state changes, all visible windows
   // should fire a visibility change event.
   hal::SetScreenEnabled(aEnabled);
   return NS_OK;
 }
 
 nsresult
 nsScreen::GetMozBrightness(double *aBrightness)
 {
-  if (!sAllowScreenBrightnessProperty || !IsChromeType(mDocShell)) {
+  if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
     *aBrightness = 1;
     return NS_OK;
   }
 
   *aBrightness = hal::GetScreenBrightness();
   return NS_OK;
 }
 
 nsresult
 nsScreen::SetMozBrightness(double aBrightness)
 {
-  if (!sAllowScreenBrightnessProperty || !IsChromeType(mDocShell)) {
+  if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
     return NS_OK;
   }
 
   NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
   hal::SetScreenBrightness(aBrightness);
   return NS_OK;
 }
new file mode 100644
--- /dev/null
+++ b/dom/base/test/Makefile.in
@@ -0,0 +1,53 @@
+# ***** 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 Indexed Database Test Code.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Shawn Wilsher <me@shawnwilsher.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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = dom/base/test
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+TEST_FILES = \
+  test_domrequest.html \
+  $(NULL)
+
+libs:: $(TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_domrequest.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for XMLHttpRequest</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+"use strict";
+
+var reqserv = SpecialPowers.getDOMRequestService();
+ok("createRequest" in reqserv, "appears to be a service");
+
+// create a request
+var req = reqserv.createRequest(window);
+ok("result" in req, "request has result");
+ok("error" in req, "request has error");
+ok("onsuccess" in req, "request has onsuccess");
+ok("onerror" in req, "request has onerror");
+ok("readyState" in req, "request has readyState");
+
+is(req.readyState, "pending", "readyState is pending");
+is(req.result, undefined, "result is undefined");
+is(req.onsuccess, null, "onsuccess is null");
+is(req.onerror, null, "onerror is null");
+
+// fire success
+var ev = null;
+req.onsuccess = function(e) {
+  ev = e;
+}
+reqserv.fireSuccess(req, "my result");
+ok(ev, "got success event");
+is(ev.type, "success", "correct type during success");
+is(ev.target, req, "correct target during success");
+is(req.readyState, "done", "correct readyState after success");
+is(req.error, null, "correct error after success");
+is(req.result, "my result", "correct result after success");
+
+// fire error
+req = reqserv.createRequest(window);
+ev = null;
+req.onerror = function(e) {
+  ev = e;
+}
+reqserv.fireError(req, "OhMyError");
+ok(ev, "got success event");
+is(ev.type, "error", "correct type during error");
+is(ev.target, req, "correct target during error");
+is(req.readyState, "done", "correct readyState after error");
+is(req.error.name, "OhMyError", "correct error after error");
+is(req.result, undefined, "correct result after error");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/battery/nsIDOMBatteryManager.idl
+++ b/dom/battery/nsIDOMBatteryManager.idl
@@ -33,17 +33,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
 
-[scriptable, function, uuid(41e88f87-42cb-4db1-8724-f5456a16c410)]
+[scriptable, uuid(41e88f87-42cb-4db1-8724-f5456a16c410)]
 interface nsIDOMMozBatteryManager : nsIDOMEventTarget
 {
   readonly attribute double     level;
   readonly attribute boolean    charging;
   readonly attribute double     dischargingTime;
   readonly attribute double     chargingTime;
 
   attribute nsIDOMEventListener onlevelchange;
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -1445,10 +1445,10 @@ CountHelper::DoDatabaseWork(mozIStorageC
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               jsval* aVal)
 {
-  return JS_NewNumberValue(aCx, static_cast<jsdouble>(mCount), aVal);
+  return JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal);
 }
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -895,30 +895,30 @@ SwapBytes(PRUint32 u)
          ((u & 0x0000ff00U) << 8) |                                           
          ((u & 0x00ff0000U) >> 8) |                                           
          ((u & 0xff000000U) >> 24);
 #else
   return u;
 #endif
 }
 
-static inline jsdouble
+static inline double
 SwapBytes(PRUint64 u)
 {
 #ifdef IS_BIG_ENDIAN
   return ((u & 0x00000000000000ffLLU) << 56) |
          ((u & 0x000000000000ff00LLU) << 40) |
          ((u & 0x0000000000ff0000LLU) << 24) |
          ((u & 0x00000000ff000000LLU) << 8) |
          ((u & 0x000000ff00000000LLU) >> 8) |
          ((u & 0x0000ff0000000000LLU) >> 24) |
          ((u & 0x00ff000000000000LLU) >> 40) |
          ((u & 0xff00000000000000LLU) >> 56);
 #else
-  return jsdouble(u);
+  return double(u);
 #endif
 }
 
 static inline bool
 StructuredCloneReadString(JSStructuredCloneReader* aReader,
                           nsCString& aString)
 {
   PRUint32 length;
@@ -2014,17 +2014,17 @@ AddHelper::DoDatabaseWork(mozIStorageCon
 
     if (keyUnset && !keyPath.IsEmpty()) {
       // Special case where someone put an object into an autoIncrement'ing
       // objectStore with no key in its keyPath set. We needed to figure out
       // which row id we would get above before we could set that properly.
 
       // This is a duplicate of the js engine's byte munging here
       union {
-        jsdouble d;
+        double d;
         PRUint64 u;
       } pun;
     
       pun.d = SwapBytes(static_cast<PRUint64>(autoIncrementNum));
 
       JSAutoStructuredCloneBuffer& buffer = mCloneWriteInfo.mCloneBuffer;
       PRUint64 offsetToKeyProp = mCloneWriteInfo.mOffsetToKeyProp;
 
@@ -2846,10 +2846,10 @@ CountHelper::DoDatabaseWork(mozIStorageC
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               jsval* aVal)
 {
-  return JS_NewNumberValue(aCx, static_cast<jsdouble>(mCount), aVal);
+  return JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal);
 }
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -243,17 +243,17 @@ Key::DecodeJSVal(const unsigned char*& a
   else if (*aPos - aTypeOffset == eString) {
     nsString key;
     DecodeString(aPos, aEnd, key);
     if (!xpc::StringToJsval(aCx, key, aVal)) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
   else if (*aPos - aTypeOffset == eDate) {
-    jsdouble msec = static_cast<jsdouble>(DecodeNumber(aPos, aEnd));
+    double msec = static_cast<double>(DecodeNumber(aPos, aEnd));
     JSObject* date = JS_NewDateObjectMsec(aCx, msec);
     if (!date) {
       NS_WARNING("Failed to make date!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     *aVal = OBJECT_TO_JSVAL(date);
   }
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -166,18 +166,18 @@ interface nsIWebGLExtensionLoseContext :
 {
   void loseContext();
   void restoreContext();
 };
 
 [scriptable, uuid(73bfb64d-94bd-4a7a-9eab-6b6d32e57aa0)]
 interface nsIWebGLExtensionTextureFilterAnisotropic : nsIWebGLExtension
 {
-  const WebGLenum TEXTURE_MAX_ANISOTROPY = 0x84FE;
-  const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
+  const WebGLenum TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+  const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
 };
 
 [scriptable, builtinclass, uuid(f000afac-11b3-4c06-a35f-8db411f1cf54)]
 interface nsIDOMWebGLRenderingContext : nsISupports
 {
   //
   //  CONSTANTS
   //
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -46,17 +46,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[builtinclass, scriptable, uuid(b4afb8f4-d9ab-44d9-9d0c-f765c47d57c2)]
+[builtinclass, scriptable, uuid(fc30df1b-9b5a-42f6-965b-cbcc67ac3c4c)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -554,52 +554,34 @@ interface nsIDOMCSS2Properties : nsISupp
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozMarginEnd;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozMarginStart;
                                         // raises(DOMException) on setting
 
-           attribute DOMString        MozOpacity;
-                                        // raises(DOMException) on setting
-
            attribute DOMString        MozOrient;
                                         // raises(DOMException) on setting
 
-           attribute DOMString        MozOutline;
-                                        // raises(DOMException) on setting
-
-           attribute DOMString        MozOutlineColor;
-                                        // raises(DOMException) on setting
-
            attribute DOMString        MozOutlineRadius;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozOutlineRadiusTopleft;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozOutlineRadiusTopright;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozOutlineRadiusBottomleft;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozOutlineRadiusBottomright;
                                         // raises(DOMException) on setting
 
-           attribute DOMString        MozOutlineStyle;
-                                        // raises(DOMException) on setting
-
-           attribute DOMString        MozOutlineWidth;
-                                        // raises(DOMException) on setting
-
-           attribute DOMString        MozOutlineOffset;
-                                        // raises(DOMException) on setting
-
            attribute DOMString        MozPaddingEnd;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozPaddingStart;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozUserFocus;
                                         // raises(DOMException) on setting
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -452,17 +452,17 @@ JSValToNPVariant(NPP npp, JSContext *cx,
       VOID_TO_NPVARIANT(*variant);
     } else if (JSVAL_IS_NULL(val)) {
       NULL_TO_NPVARIANT(*variant);
     } else if (JSVAL_IS_BOOLEAN(val)) {
       BOOLEAN_TO_NPVARIANT(JSVAL_TO_BOOLEAN(val), *variant);
     } else if (JSVAL_IS_INT(val)) {
       INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant);
     } else if (JSVAL_IS_DOUBLE(val)) {
-      jsdouble d = JSVAL_TO_DOUBLE(val);
+      double d = JSVAL_TO_DOUBLE(val);
       jsint i;
       if (JS_DoubleIsInt32(d, &i)) {
         INT32_TO_NPVARIANT(i, *variant);
       } else {
         DOUBLE_TO_NPVARIANT(d, *variant);
       }
     } else if (JSVAL_IS_STRING(val)) {
       JSString *jsstr = JSVAL_TO_STRING(val);
--- a/dom/sms/interfaces/nsIDOMSmsManager.idl
+++ b/dom/sms/interfaces/nsIDOMSmsManager.idl
@@ -35,17 +35,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
 interface nsIDOMMozSmsRequest;
 interface nsIDOMMozSmsFilter;
 
-[scriptable, function, uuid(c9916dce-2947-41bb-95c2-818f792a020c)]
+[scriptable, uuid(c9916dce-2947-41bb-95c2-818f792a020c)]
 interface nsIDOMMozSmsManager : nsIDOMEventTarget
 {
   unsigned short      getNumberOfMessagesForText(in DOMString text);
 
   // The first parameter can be either a DOMString (only one number) or an array
   // of DOMStrings.
   // The method returns a SmsRequest object if one number has been passed.
   // An array of SmsRequest objects otherwise.
--- a/dom/sms/interfaces/nsIDOMSmsRequest.idl
+++ b/dom/sms/interfaces/nsIDOMSmsRequest.idl
@@ -33,17 +33,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
 
-[scriptable, function, uuid(1b24469d-cfb7-4667-aaf0-c1d17289ae7c)]
+[scriptable, uuid(1b24469d-cfb7-4667-aaf0-c1d17289ae7c)]
 interface nsIDOMMozSmsRequest : nsIDOMEventTarget
 {
   // Returns whether "processing" or "done".
   readonly attribute DOMString           readyState;
   // Can be null.
   readonly attribute DOMString           error;
   // Can be bool, nsIDOMSmsMessage, nsIDOMSmsIterator or null.
   readonly attribute jsval               result;
--- a/dom/sms/interfaces/nsISmsDatabaseService.idl
+++ b/dom/sms/interfaces/nsISmsDatabaseService.idl
@@ -40,17 +40,17 @@
 #define SMS_DATABASE_SERVICE_CID \
 { 0x2454c2a1, 0xefdd, 0x4d96,    \
 { 0x83, 0xbd, 0x51, 0xa2, 0x9a, 0x21, 0xf5, 0xab } }
 #define SMS_DATABASE_SERVICE_CONTRACTID "@mozilla.org/sms/smsdatabaseservice;1"
 %}
 
 interface nsIDOMMozSmsFilter;
 
-[scriptable, function, uuid(86b3b538-359d-40b0-acdf-8dfd698ff117)]
+[scriptable, uuid(86b3b538-359d-40b0-acdf-8dfd698ff117)]
 interface nsISmsDatabaseService : nsISupports
 {
   // Takes some information required to save the message and returns its id.
   long saveReceivedMessage(in DOMString aSender, in DOMString aBody, in unsigned long long aDate);
   // Takes some information required to save the message and returns its id.
   long saveSentMessage(in DOMString aReceiver, in DOMString aBody, in unsigned long long aDate);
 
   [binaryname(GetMessageMoz)] void getMessage(in long messageId, in long requestId, [optional] in unsigned long long processId);
--- a/dom/sms/src/SmsMessage.cpp
+++ b/dom/sms/src/SmsMessage.cpp
@@ -103,17 +103,17 @@ SmsMessage::Create(PRInt32 aId,
     if (!JS_ObjectIsDate(aCx, &obj)) {
       return NS_ERROR_INVALID_ARG;
     }
     data.timestamp() = js_DateGetMsecSinceEpoch(aCx, &obj);
   } else {
     if (!aTimestamp.isNumber()) {
       return NS_ERROR_INVALID_ARG;
     }
-    jsdouble number = aTimestamp.toNumber();
+    double number = aTimestamp.toNumber();
     if (static_cast<PRUint64>(number) != number) {
       return NS_ERROR_INVALID_ARG;
     }
     data.timestamp() = static_cast<PRUint64>(number);
   }
 
   nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(data);
   message.swap(*aMessage);
--- a/dom/system/b2g/AudioManager.cpp
+++ b/dom/system/b2g/AudioManager.cpp
@@ -71,16 +71,20 @@ AudioManager::GetMasterVolume(float* aMa
 }
 
 NS_IMETHODIMP
 AudioManager::SetMasterVolume(float aMasterVolume)
 {
   if (AudioSystem::setMasterVolume(aMasterVolume)) {
     return NS_ERROR_FAILURE;
   }
+  // For now, just set the voice volume at the same level
+  if (AudioSystem::setVoiceVolume(aMasterVolume)) {
+    return NS_ERROR_FAILURE;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AudioManager::GetMasterMuted(bool* aMasterMuted)
 {
   if (AudioSystem::getMasterMute(aMasterMuted)) {
     return NS_ERROR_FAILURE;
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -36,36 +36,43 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Telephony.h"
 
 #include "nsIDocument.h"
 #include "nsIURI.h"
+#include "nsIURL.h"
 #include "nsPIDOMWindow.h"
 
 #include "jsapi.h"
 #include "mozilla/Preferences.h"
+#include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsIInterfaceRequestorUtils.h"
+#include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "SystemWorkerManager.h"
 
 #include "CallEvent.h"
 #include "TelephonyCall.h"
 
 USING_TELEPHONY_NAMESPACE
 using mozilla::Preferences;
 
 #define DOM_TELEPHONY_APP_PHONE_URL_PREF "dom.telephony.app.phone.url"
 
 namespace {
 
+typedef nsAutoTArray<Telephony*, 2> TelephonyList;
+
+TelephonyList* gTelephonyList;
+
 template <class T>
 inline nsresult
 nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
                   const nsTArray<nsRefPtr<T> >& aSourceArray,
                   JSObject** aResultArray)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aGlobal, "Null global!");
@@ -105,25 +112,46 @@ nsTArrayToJSArray(JSContext* aCx, JSObje
   }
 
   *aResultArray = arrayObj;
   return NS_OK;
 }
 
 } // anonymous namespace
 
+Telephony::Telephony()
+: mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false)
+{
+  if (!gTelephonyList) {
+    gTelephonyList = new TelephonyList();
+  }
+
+  gTelephonyList->AppendElement(this);
+}
+
 Telephony::~Telephony()
 {
   if (mRIL && mRILTelephonyCallback) {
     mRIL->UnregisterCallback(mRILTelephonyCallback);
   }
 
   if (mRooted) {
     NS_DROP_JS_OBJECTS(this, Telephony);
   }
+
+  NS_ASSERTION(gTelephonyList, "This should never be null!");
+  NS_ASSERTION(gTelephonyList->Contains(this), "Should be in the list!");
+
+  if (gTelephonyList->Length() == 1) {
+    delete gTelephonyList;
+    gTelephonyList = nsnull;
+  }
+  else {
+    gTelephonyList->RemoveElement(this);
+  }
 }
 
 // static
 already_AddRefed<Telephony>
 Telephony::Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL)
 {
   NS_ASSERTION(aOwner, "Null owner!");
   NS_ASSERTION(aRIL, "Null RIL!");
@@ -145,46 +173,71 @@ Telephony::Create(nsPIDOMWindow* aOwner,
   NS_ENSURE_SUCCESS(rv, nsnull);
 
   rv = aRIL->RegisterCallback(telephony->mRILTelephonyCallback);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
   return telephony.forget();
 }
 
+already_AddRefed<TelephonyCall>
+Telephony::CreateNewDialingCall(const nsAString& aNumber)
+{
+  nsRefPtr<TelephonyCall> call =
+    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!");
+
+  return call.forget();
+}
+
 void
-Telephony::SwitchActiveCall(TelephonyCall* aCall)
+Telephony::NoteDialedCallFromOtherInstance(const nsAString& aNumber)
 {
-  if (mActiveCall) {
-    // Put the call on hold?
-    NS_NOTYETIMPLEMENTED("Implement me!");
-  }
-  mActiveCall = aCall;
+  // We don't need to hang on to this call object, it is held alive by mCalls.
+  nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aNumber);
+}
+
+nsresult
+Telephony::NotifyCallsChanged(TelephonyCall* aCall)
+{
+  nsRefPtr<CallEvent> event = CallEvent::Create(aCall);
+  NS_ASSERTION(event, "This should never fail!");
+
+  nsresult rv =
+    event->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("callschanged"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Telephony,
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(incoming)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(callschanged)
   for (PRUint32 index = 0; index < tmp->mCalls.Length(); index++) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCalls[i]");
     cb.NoteXPCOMChild(tmp->mCalls[index]->ToISupports());
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Telephony,
                                                nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mCallsArray, "mCallsArray")
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Telephony,
                                                 nsDOMEventTargetHelper)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(incoming)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(callschanged)
   tmp->mCalls.Clear();
   tmp->mActiveCall = nsnull;
   tmp->mCallsArray = nsnull;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Telephony)
   NS_INTERFACE_MAP_ENTRY(nsIDOMTelephony)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Telephony)
@@ -211,21 +264,26 @@ Telephony::Dial(const nsAString& aNumber
       NS_WARNING("Only permitted to dial one call at a time!");
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   nsresult rv = mRIL->Dial(aNumber);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<TelephonyCall> call =
-    TelephonyCall::Create(this, aNumber, nsIRadioInterfaceLayer::CALL_STATE_DIALING);
-  NS_ASSERTION(call, "This should never fail!");
+  nsRefPtr<TelephonyCall> call = CreateNewDialingCall(aNumber);
 
-  NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
+  // Notify other telephony objects that we just dialed.
+  for (PRUint32 index = 0; index < gTelephonyList->Length(); index++) {
+    Telephony*& telephony = gTelephonyList->ElementAt(index);
+    if (telephony != this) {
+      nsRefPtr<Telephony> kungFuDeathGrip = telephony;
+      telephony->NoteDialedCallFromOtherInstance(aNumber);
+    }
+  }
 
   call.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::GetMuted(bool* aMuted)
 {
@@ -275,42 +333,16 @@ Telephony::GetActive(jsval* aActive)
                                mScriptContext->GetNativeGlobal(),
                                mActiveCall->ToISupports(), aActive);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Telephony::SetActive(const jsval& aActive)
-{
-  if (aActive.isObject()) {
-    nsIXPConnect* xpc = nsContentUtils::XPConnect();
-    NS_ASSERTION(xpc, "This should never be null!");
-
-    nsISupports* native =
-      xpc->GetNativeOfWrapper(mScriptContext->GetNativeContext(),
-                              &aActive.toObject());
-
-    nsCOMPtr<nsIDOMTelephonyCall> call = do_QueryInterface(native);
-    if (call) {
-      // See if this call has the same telephony object. Otherwise we can't use
-      // it.
-      TelephonyCall* concreteCall = static_cast<TelephonyCall*>(call.get());
-      if (this == concreteCall->mTelephony) {
-        SwitchActiveCall(concreteCall);
-        return NS_OK;
-      }
-    }
-  }
-
-  return NS_ERROR_INVALID_ARG;
-}
-
-NS_IMETHODIMP
 Telephony::GetCalls(jsval* aCalls)
 {
   JSObject* calls = mCallsArray;
   if (!calls) {
     nsresult rv =
       nsTArrayToJSArray(mScriptContext->GetNativeContext(),
                         mScriptContext->GetNativeGlobal(), mCalls, &calls);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -349,41 +381,35 @@ NS_IMETHODIMP
 Telephony::StopTone()
 {
   nsresult rv = mRIL->StopTone();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-Telephony::SendTones(const nsAString& aTones, PRUint32 aToneDuration,
-                     PRUint32 aIntervalDuration)
-{
-  NS_NOTYETIMPLEMENTED("Implement me!");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
 NS_IMPL_EVENT_HANDLER(Telephony, incoming)
+NS_IMPL_EVENT_HANDLER(Telephony, callschanged)
 
 NS_IMETHODIMP
 Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
                             const nsAString& aNumber)
 {
   NS_ASSERTION(aCallIndex != kOutgoingPlaceholderCallIndex,
                "This should never happen!");
 
   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() == nsIRadioInterfaceLayer::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;
@@ -402,17 +428,17 @@ Telephony::CallStateChanged(PRUint32 aCa
   }
 
   if (modifiedCall) {
     // Change state.
     modifiedCall->ChangeState(aCallState);
 
     // See if this should replace our current active call.
     if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
-      SwitchActiveCall(modifiedCall);
+      mActiveCall = modifiedCall;
     }
 
     return NS_OK;
   }
 
   // Didn't know anything about this call before now, must be incoming.
   NS_ASSERTION(aCallState == nsIRadioInterfaceLayer::CALL_STATE_INCOMING,
                "Serious logic problem here!");
@@ -481,32 +507,58 @@ NS_NewTelephony(nsPIDOMWindow* aWindow, 
   // Need the document in order to make security decisions.
   nsCOMPtr<nsIDocument> document =
     do_QueryInterface(innerWindow->GetExtantDocument());
   NS_ENSURE_TRUE(document, NS_NOINTERFACE);
 
   // Do security checks. We assume that chrome is always allowed and we also
   // allow a single page specified by preferences.
   if (!nsContentUtils::IsSystemPrincipal(document->NodePrincipal())) {
-    nsCOMPtr<nsIURI> documentURI;
+    nsCOMPtr<nsIURI> originalURI;
     nsresult rv =
-      document->NodePrincipal()->GetURI(getter_AddRefs(documentURI));
+      document->NodePrincipal()->GetURI(getter_AddRefs(originalURI));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIURI> documentURI;
+    rv = originalURI->Clone(getter_AddRefs(documentURI));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCString documentURL;
-    rv = documentURI->GetSpec(documentURL);
-    NS_ENSURE_SUCCESS(rv, rv);
+    // Strip the query string (if there is one) before comparing.
+    nsCOMPtr<nsIURL> documentURL = do_QueryInterface(documentURI);
+    if (documentURL) {
+      rv = documentURL->SetQuery(EmptyCString());
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    bool allowed = false;
 
     // The pref may not exist but in that case we deny access just as we do if
     // the url doesn't match.
-    nsCString phoneAppURL;
-    if (NS_FAILED(Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF,
-                                          &phoneAppURL)) ||
-        !phoneAppURL.Equals(documentURL,
-                            nsCaseInsensitiveCStringComparator())) {
+    nsCString whitelist;
+    if (NS_SUCCEEDED(Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF,
+                                             &whitelist))) {
+      nsCOMPtr<nsIIOService> ios = do_GetIOService();
+      NS_ENSURE_TRUE(ios, NS_ERROR_FAILURE);
+
+      nsCCharSeparatedTokenizer tokenizer(whitelist, ',');
+      while (tokenizer.hasMoreTokens()) {
+        nsCOMPtr<nsIURI> uri;
+        if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), tokenizer.nextToken(),
+                                   nsnull, nsnull, ios))) {
+          rv = documentURI->EqualsExceptRef(uri, &allowed);
+          NS_ENSURE_SUCCESS(rv, rv);
+
+          if (allowed) {
+            break;
+          }
+        }
+      }
+    }
+
+    if (!allowed) {
       *aTelephony = nsnull;
       return NS_OK;
     }
   }
 
   // Security checks passed, make a telephony object.
   nsIInterfaceRequestor* ireq = SystemWorkerManager::GetInterfaceRequestor();
   NS_ENSURE_TRUE(ireq, NS_ERROR_UNEXPECTED);
--- a/dom/telephony/Telephony.h
+++ b/dom/telephony/Telephony.h
@@ -53,16 +53,17 @@ BEGIN_TELEPHONY_NAMESPACE
 
 class Telephony : public nsDOMEventTargetHelper,
                   public nsIDOMTelephony
 {
   nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
   nsCOMPtr<nsIRILTelephonyCallback> mRILTelephonyCallback;
 
   NS_DECL_EVENT_HANDLER(incoming)
+  NS_DECL_EVENT_HANDLER(callschanged)
 
   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;
 
@@ -94,24 +95,26 @@ public:
   }
 
   void
   AddCall(TelephonyCall* aCall)
   {
     NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!");
     mCalls.AppendElement(aCall);
     mCallsArray = nsnull;
+    NotifyCallsChanged(aCall);
   }
 
   void
   RemoveCall(TelephonyCall* aCall)
   {
     NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!");
     mCalls.RemoveElement(aCall);
     mCallsArray = nsnull;
+    NotifyCallsChanged(aCall);
   }
 
   nsIRadioInterfaceLayer*
   RIL() const
   {
     return mRIL;
   }
 
@@ -123,24 +126,27 @@ public:
 
   nsIScriptContext*
   ScriptContext() const
   {
     return mScriptContext;
   }
 
 private:
-  Telephony()
-  : mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false)
-  { }
-
+  Telephony();
   ~Telephony();
 
+  already_AddRefed<TelephonyCall>
+  CreateNewDialingCall(const nsAString& aNumber);
+
   void
-  SwitchActiveCall(TelephonyCall* aCall);
+  NoteDialedCallFromOtherInstance(const nsAString& aNumber);
+
+  nsresult
+  NotifyCallsChanged(TelephonyCall* aCall);
 
   class RILTelephonyCallback : public nsIRILTelephonyCallback
   {
     Telephony* mTelephony;
 
   public:
     NS_DECL_ISUPPORTS
     NS_FORWARD_NSIRILTELEPHONYCALLBACK(mTelephony->)
--- a/dom/telephony/nsIDOMTelephony.idl
+++ b/dom/telephony/nsIDOMTelephony.idl
@@ -38,31 +38,29 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
 interface nsIDOMTelephonyCall;
 
-[scriptable, builtinclass, uuid(047be0d8-a9cd-49aa-8948-2f60ff3a7a18)]
+[scriptable, builtinclass, uuid(0de46b73-be83-4970-ad15-45f92cb0902a)]
 interface nsIDOMTelephony : nsIDOMEventTarget
 {
   nsIDOMTelephonyCall dial(in DOMString number);
 
   attribute boolean muted;
   attribute boolean speakerEnabled;
 
   // The call that is "active", i.e. receives microphone input and tones
   // generated via startTone.
-  attribute jsval active;
+  readonly attribute jsval active;
 
   // Array of all calls that are currently connected.
   readonly attribute jsval calls;
 
   void startTone(in DOMString tone);
   void stopTone();
-  void sendTones(in DOMString tones,
-                 [optional] in unsigned long toneDuration,
-                 [optional] in unsigned long intervalDuration);
 
   attribute nsIDOMEventListener onincoming;
+  attribute nsIDOMEventListener oncallschanged;
 };
--- a/dom/tests/browser/browser_ConsoleStorageAPITests.js
+++ b/dom/tests/browser/browser_ConsoleStorageAPITests.js
@@ -19,17 +19,16 @@ var ConsoleObserver = {
     apiCallCount = 0;
   },
 
   observe: function CO_observe(aSubject, aTopic, aData)
   {
     if (aTopic == "console-storage-cache-event") {
       apiCallCount ++;
       if (apiCallCount == 4) {
-        // remove the observer so we don't trigger this test again
         Services.obs.removeObserver(this, "console-storage-cache-event");
 
         try {
         let tab = gBrowser.selectedTab;
         let browser = gBrowser.selectedBrowser;
         let win = XPCNativeWrapper.unwrap(browser.contentWindow);
         let windowID = getWindowId(win);
         let messages = ConsoleAPIStorage.getEvents(windowID);
@@ -37,22 +36,23 @@ var ConsoleObserver = {
 
         ConsoleAPIStorage.clearEvents();
         messages = ConsoleAPIStorage.getEvents(windowID);
         is(messages.length, 0, "Cleared Storage");
 
         // make sure a closed window's events are in fact removed from the
         // storage cache
         win.console.log("adding a new event");
-
-        // close the window - the storage cache should now be empty
+        // Close the window.
         gBrowser.removeTab(tab, {animate: false});
-
+        // Ensure actual window destruction is not delayed (too long).
         window.QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
+        // Ensure "inner-window-destroyed" event is processed,
+        // so the storage cache is cleared.
         executeSoon(function () {
           // use the old windowID again to see if we have any stray cached messages
           messages = ConsoleAPIStorage.getEvents(windowID);
           is(messages.length, 0, "tab close is clearing the cache");
           finish();
         });
         } catch (ex) {
           dump(ex + "\n\n\n");
@@ -66,16 +66,22 @@ var ConsoleObserver = {
 function tearDown()
 {
   while (gBrowser.tabs.length > 1)
     gBrowser.removeCurrentTab();
 }
 
 function test()
 {
+  // Don't cache removed tabs, so "clear console cache on tab close" triggers.
+  Services.prefs.setIntPref("browser.tabs.max_tabs_undo", 0);
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref("browser.tabs.max_tabs_undo");
+  });
+
   registerCleanupFunction(tearDown);
 
   ConsoleObserver.init();
 
   waitForExplicitFinish();
 
   var tab = gBrowser.addTab(TEST_URI);
   gBrowser.selectedTab = tab;
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -150,12 +150,13 @@ include $(topsrcdir)/config/rules.mk
 		test_window_bar.html \
 		file_window_bar.html \
 		test_resize_move_windows.html \
 		test_devicemotion_multiple_listeners.html \
 		devicemotion_outer.html \
 		devicemotion_inner.html \
 		test_bug698061.html \
 		test_bug707749.html \
+		test_bug691707.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug691707.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=691707
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 691707</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=691707">Mozilla Bug 691707</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 691707 **/
+
+var nodeList = document.body.childNodes;
+var properties = [i for (i in nodeList)];
+for (var j = 1; j < nodeList.length; ++j)
+    ok(properties.indexOf("" + j) >= 0, "Enumerating hit all numeric properties");
+ok(properties.indexOf("item") >= 0, "Enumerating hit 'item' from the prototype");
+ok(properties.indexOf("length") >= 0, "Enumerating hit 'length' from the prototype");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/tests/mochitest/chrome/Makefile.in
+++ b/dom/tests/mochitest/chrome/Makefile.in
@@ -69,16 +69,18 @@ include $(topsrcdir)/config/rules.mk
 		DOMWindowCreated_content.html \
 		test_sandbox_image.xul \
 		test_cyclecollector.xul \
 		test_resize_move_windows.xul \
 		test_popup_blocker_chrome.xul \
 		test_moving_xhr.xul \
 		test_nodesFromRect.html \
 		489127.html \
+		test_focus_docnav.xul \
+		window_focus_docnav.xul \
 		$(NULL)
 
 ifeq (WINNT,$(OS_ARCH))
 _TEST_FILES += \
 		test_sizemode_attribute.xul \
 		sizemode_attribute.xul \
 		$(NULL)
 endif
--- a/dom/tests/mochitest/chrome/focus_frameset.html
+++ b/dom/tests/mochitest/chrome/focus_frameset.html
@@ -1,14 +1,15 @@
 <html id="outer">
 
 <script type="application/javascript"
         src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 <script>
-SimpleTest.waitForFocus(function () opener.framesetWindowLoaded(window));
+if (opener)
+  SimpleTest.waitForFocus(function () opener.framesetWindowLoaded(window));
 </script>
 
 <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;">
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/test_focus_docnav.xul
@@ -0,0 +1,28 @@
+<?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"?>
+
+<window onload="runTest();"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+  window.open("window_focus_docnav.xul", "_blank", "chrome,width=600,height=550");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/window_focus_docnav.xul
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window onload="start()"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/javascript"
+        src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="textbox"/>
+
+<panel id="panel2" onpopupshown="runTests(this, 2);" onpopuphidden="document.getElementById('panel').hidePopup()">
+  <textbox id="p2textbox" value="Popup2"/>
+</panel>
+<panel id="panel" onpopupshown="runTests(this, 1);"
+                  onpopuphidden="done()">
+  <textbox id="p1textbox" value="Popup1"/>
+</panel>
+
+<browser id="browser" type="content" src="focus_frameset.html" width="500" height="400"/>
+
+<script type="application/javascript">
+<![CDATA[
+
+var fm = Components.classes["@mozilla.org/focus-manager;1"].
+           getService(Components.interfaces.nsIFocusManager);
+
+function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
+function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
+
+function done()
+{
+  var opener = window.opener;
+  window.close();
+  opener.wrappedJSObject.SimpleTest.finish();
+}
+
+function previous(expectedWindow, expectedElement, desc)
+{
+  synthesizeKey("VK_F6", { shiftKey: true });
+  is(fm.focusedWindow, expectedWindow, desc);
+  is(fm.focusedElement, expectedElement, desc + " element");
+}
+
+function next(expectedWindow, expectedElement, desc)
+{
+  synthesizeKey("VK_F6", { });
+  is(fm.focusedWindow, expectedWindow, desc);
+  is(fm.focusedElement, expectedElement, desc + " element" + "::" + (fm.focusedElement ? fm.focusedElement.parentNode.id : "<none>"));
+}
+
+// This test runs through three cases. Document navigation forward and
+// backward using the F6 key when no popups are open, with one popup open and
+// with two popups open.
+function runTests(panel, popupCount)
+{
+  if (!popupCount || popupCount > 2)
+    popupCount = 0;
+
+  fm.clearFocus(window);
+
+  var childwin = document.getElementById("browser").contentWindow;
+
+  if (popupCount) {
+    if (popupCount == 2) {
+      next(window, document.getElementById("p2textbox").inputField, "First into popup 2 with " + popupCount);
+    }
+
+    next(window, document.getElementById("p1textbox").inputField, "First into popup 1 with " + popupCount);
+  }
+
+  next(childwin.frames[0], childwin.frames[0].document.documentElement, "First with " + popupCount);
+  next(childwin.frames[1], childwin.frames[1].document.documentElement, "Second with " + popupCount);
+  previous(childwin.frames[0], childwin.frames[0].document.documentElement, "Second back with " + popupCount);
+
+  if (popupCount) {
+    previous(window, document.getElementById("p1textbox").inputField, "First back from popup 1 with " + popupCount);
+
+    if (popupCount == 2) {
+      previous(window, document.getElementById("p2textbox").inputField, "First back from popup 2 with " + popupCount);
+    }
+  }
+
+  previous(window, document.getElementById("textbox").inputField, "First back with " + popupCount);
+
+  if (panel == document.getElementById("panel"))
+    document.getElementById("panel2").openPopup(null, "after_start", 100, 20);
+  else if (panel == document.getElementById("panel2"))
+    panel.hidePopup();
+  else
+    document.getElementById("panel").openPopup(null, "after_start");
+}
+
+function start()
+{
+  window.opener.wrappedJSObject.SimpleTest.waitForExplicitFinish();
+  window.opener.wrappedJSObject.SimpleTest.waitForFocus(
+    function() { runTests(null, 0); },
+    document.getElementById("browser").contentWindow);
+}
+
+]]></script>
+
+</window>
--- a/dom/workers/Events.cpp
+++ b/dom/workers/Events.cpp
@@ -845,17 +845,17 @@ public:
   InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
   {
     return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
                         sProperties, sFunctions, NULL, NULL);
   }
 
   static JSObject*
   Create(JSContext* aCx, JSObject* aParent, JSString* aType,
-         bool aLengthComputable, jsdouble aLoaded, jsdouble aTotal)
+         bool aLengthComputable, double aLoaded, double aTotal)
   {
     JSString* type = JS_InternJSString(aCx, aType);
     if (!type) {
       return NULL;
     }
 
     JSObject* obj = JS_NewObject(aCx, &sClass, NULL, aParent);
     if (!obj) {
@@ -902,18 +902,18 @@ private:
                          JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
                          classPtr->name);
     return NULL;
   }
 
   static void
   InitProgressEventCommon(JSObject* aObj, Event* aEvent, JSString* aType,
                           JSBool aBubbles, JSBool aCancelable,
-                          JSBool aLengthComputable, jsdouble aLoaded,
-                          jsdouble aTotal, bool aIsTrusted)
+                          JSBool aLengthComputable, double aLoaded,
+                          double aTotal, bool aIsTrusted)
   {
     Event::InitEventCommon(aObj, aEvent, aType, aBubbles, aCancelable,
                            aIsTrusted);
     JS_SetReservedSlot(aObj, SLOT_lengthComputable,
                        aLengthComputable ? JSVAL_TRUE : JSVAL_FALSE);
     JS_SetReservedSlot(aObj, SLOT_loaded, DOUBLE_TO_JSVAL(aLoaded));
     JS_SetReservedSlot(aObj, SLOT_total, DOUBLE_TO_JSVAL(aTotal));
   }
@@ -962,17 +962,17 @@ private:
 
     ProgressEvent* event = GetInstancePrivate(aCx, obj, sFunctions[0].name);
     if (!event) {
       return false;
     }
 
     JSString* type;
     JSBool bubbles, cancelable, lengthComputable;
-    jsdouble loaded, total;
+    double loaded, total;
     if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "Sbbbdd", &type,
                              &bubbles, &cancelable, &lengthComputable, &loaded,
                              &total)) {
       return false;
     }
 
     InitProgressEventCommon(obj, event, type, bubbles, cancelable,
                             lengthComputable, loaded, total, false);
@@ -1060,17 +1060,17 @@ CreateErrorEvent(JSContext* aCx, JSStrin
 {
   JSObject* global = JS_GetGlobalForScopeChain(aCx);
   return ErrorEvent::Create(aCx, global, aMessage, aFilename, aLineNumber,
                             aMainRuntime);
 }
 
 JSObject*
 CreateProgressEvent(JSContext* aCx, JSString* aType, bool aLengthComputable,
-                    jsdouble aLoaded, jsdouble aTotal)
+                    double aLoaded, double aTotal)
 {
   JSObject* global = JS_GetGlobalForScopeChain(aCx);
   return ProgressEvent::Create(aCx, global, aType, aLengthComputable, aLoaded,
                                aTotal);
 }
 
 bool
 IsSupportedEventClass(JSObject* aEvent)
--- a/dom/workers/Events.h
+++ b/dom/workers/Events.h
@@ -64,17 +64,17 @@ CreateMessageEvent(JSContext* aCx, JSAut
                    bool aMainRuntime);
 
 JSObject*
 CreateErrorEvent(JSContext* aCx, JSString* aMessage, JSString* aFilename,
                  uint32 aLineNumber, bool aMainRuntime);
 
 JSObject*
 CreateProgressEvent(JSContext* aCx, JSString* aType, bool aLengthComputable,
-                    jsdouble aLoaded, jsdouble aTotal);
+                    double aLoaded, double aTotal);
 
 bool
 IsSupportedEventClass(JSObject* aEvent);
 
 void
 SetEventTarget(JSObject* aEvent, JSObject* aTarget);
 
 bool
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -135,17 +135,17 @@ private:
       return false;
     }
 
     PRUint64 size;
     if (NS_FAILED(blob->GetSize(&size))) {
       ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
     }
 
-    if (!JS_NewNumberValue(aCx, jsdouble(size), aVp)) {
+    if (!JS_NewNumberValue(aCx, double(size), aVp)) {
       return false;
     }
 
     return true;
   }
 
   static JSBool
   GetType(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
@@ -178,17 +178,17 @@ private:
       return false;
     }
 
     nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
     if (!blob) {
       return false;
     }
 
-    jsdouble start = 0, end = 0;
+    double start = 0, end = 0;
     JSString* jsContentType = JS_GetEmptyString(JS_GetRuntime(aCx));
     if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start,
                              &end, &jsContentType)) {
       return false;
     }
 
     nsDependentJSString contentType;
     if (!contentType.init(aCx, jsContentType)) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3528,17 +3528,17 @@ WorkerPrivate::SetTimeout(JSContext* aCx
   else {
     JS_ReportError(aCx, "Useless %s call (missing quotes around argument?)",
                    aIsInterval ? "setInterval" : "setTimeout");
     return false;
   }
 
   // See if any of the optional arguments were passed.
   if (aArgc > 1) {
-    jsdouble intervalMS = 0;
+    double intervalMS = 0;
     if (!JS_ValueToNumber(aCx, argv[1], &intervalMS)) {
       return false;
     }
     newInfo->mInterval = TimeDuration::FromMilliseconds(intervalMS);
 
     if (aArgc > 2 && JSVAL_IS_OBJECT(newInfo->mTimeoutVal)) {
       nsTArray<jsval> extraArgVals(aArgc - 2);
       for (uintN index = 2; index < aArgc; index++) {
--- a/editor/libeditor/base/tests/test_dragdrop.html
+++ b/editor/libeditor/base/tests/test_dragdrop.html
@@ -112,16 +112,22 @@ function doTest()
 
   // -------- Test dragging regular text of text/plain to <textarea>
 
 // XXXndeakin Can't test textareas due to some event handling issue
 //  selection.selectAllChildren(text);
 //  synthesizeDrop(text, textarea, [[{type: "text/plain", data: "Somewhat Longer Text"}]], "copy");
 //  is(textarea.value, "Somewhat Longer Text", "Drag text/plain onto textarea");
 
+  // -------- Test dragging special text type of text/plain to contenteditable
+
+  selection.selectAllChildren(text);
+  synthesizeDrop(text, input, [[{type: "text/x-moz-text-internal", data: "Some Special Text"}]], "copy");
+  is(input.value, "Some Plain Text", "Drag text/x-moz-text-internal onto input");
+
   // -------- Test dragging regular text of text/plain to contenteditable
 
   selection.selectAllChildren(text);
   synthesizeDrop(text, contenteditable, [[{type: "text/plain", data: "Sample Text"}]], "copy");
   is(contenteditable.childNodes.length, 3, "Drag text/plain onto contenteditable child nodes");
   is(contenteditable.textContent, "This is some editable text.Sample Text",
                                   "Drag text/plain onto contenteditable text");
 
--- a/editor/libeditor/text/nsPlaintextDataTransfer.cpp
+++ b/editor/libeditor/text/nsPlaintextDataTransfer.cpp
@@ -164,22 +164,26 @@ nsresult nsPlaintextEditor::InsertFromDa
                                                    nsIDOMDocument *aSourceDoc,
                                                    nsIDOMNode *aDestinationNode,
                                                    PRInt32 aDestOffset,
                                                    bool aDoDeleteSelection)
 {
   nsCOMPtr<nsIVariant> data;
   aDataTransfer->MozGetDataAt(NS_LITERAL_STRING("text/plain"), aIndex,
                               getter_AddRefs(data));
-  nsAutoString insertText;
-  data->GetAsAString(insertText);
-  nsContentUtils::PlatformToDOMLineBreaks(insertText);
+  if (data) {
+    nsAutoString insertText;
+    data->GetAsAString(insertText);
+    nsContentUtils::PlatformToDOMLineBreaks(insertText);
 
-  nsAutoEditBatch beginBatching(this);
-  return InsertTextAt(insertText, aDestinationNode, aDestOffset, aDoDeleteSelection);
+    nsAutoEditBatch beginBatching(this);
+    return InsertTextAt(insertText, aDestinationNode, aDestOffset, aDoDeleteSelection);
+  }
+
+  return NS_OK;
 }
 
 nsresult nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
 {
   ForceCompositionEnd();
 
   nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDropEvent));
   NS_ENSURE_TRUE(dragEvent, NS_ERROR_FAILURE);
--- a/extensions/spellcheck/src/mozEnglishWordUtils.cpp
+++ b/extensions/spellcheck/src/mozEnglishWordUtils.cpp
@@ -36,38 +36,37 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozEnglishWordUtils.h"
 #include "nsICharsetAlias.h"
 #include "nsReadableUtils.h"
 #include "nsIServiceManager.h"
 #include "nsUnicharUtils.h"
 #include "nsUnicharUtilCIID.h"
+#include "nsUnicodeProperties.h"
 #include "nsCRT.h"
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozEnglishWordUtils)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozEnglishWordUtils)
 
 NS_INTERFACE_MAP_BEGIN(mozEnglishWordUtils)
   NS_INTERFACE_MAP_ENTRY(mozISpellI18NUtil)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellI18NUtil)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozEnglishWordUtils)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_2(mozEnglishWordUtils,
-                           mCategories,
+NS_IMPL_CYCLE_COLLECTION_1(mozEnglishWordUtils,
                            mURLDetector)
 
 mozEnglishWordUtils::mozEnglishWordUtils()
 {
   mLanguage.AssignLiteral("en");
 
   nsresult rv;
   mURLDetector = do_CreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &rv);
-  mCategories = do_GetService(NS_UNICHARCATEGORY_CONTRACTID);
 }
 
 mozEnglishWordUtils::~mozEnglishWordUtils()
 {
 }
 
 /* attribute wstring language; */
 NS_IMETHODIMP mozEnglishWordUtils::GetLanguage(PRUnichar * *aLanguage)
@@ -163,17 +162,17 @@ NS_IMETHODIMP mozEnglishWordUtils::GetRo
     }
   return NS_OK;
 }
 
 // This needs vast improvement
 bool mozEnglishWordUtils::ucIsAlpha(PRUnichar aChar)
 {
   // XXX we have to fix callers to handle the full Unicode range
-  return nsIUGenCategory::kLetter == mCategories->Get(PRUint32(aChar));
+  return nsIUGenCategory::kLetter == mozilla::unicode::GetGenCategory(aChar);
 }
 
 /* void FindNextWord (in wstring word, in PRUint32 length, in PRUint32 offset, out PRUint32 begin, out PRUint32 end); */
 NS_IMETHODIMP mozEnglishWordUtils::FindNextWord(const PRUnichar *word, PRUint32 length, PRUint32 offset, PRInt32 *begin, PRInt32 *end)
 {
   const PRUnichar *p = word + offset;
   const PRUnichar *endbuf = word + length;
   const PRUnichar *startWord=p;
--- a/extensions/spellcheck/src/mozEnglishWordUtils.h
+++ b/extensions/spellcheck/src/mozEnglishWordUtils.h
@@ -38,17 +38,16 @@
 #ifndef mozEnglishWordUtils_h__
 #define mozEnglishWordUtils_h__
 
 #include "nsCOMPtr.h"
 #include "mozISpellI18NUtil.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsString.h"
-#include "nsIUGenCategory.h"
 
 #include "mozITXTToHTMLConv.h" 
 #include "nsCycleCollectionParticipant.h"
 
 class mozEnglishWordUtils : public mozISpellI18NUtil
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -63,13 +62,12 @@ public:
   };  
 
 protected:
   mozEnglishWordUtils::myspCapitalization captype(const nsString &word);
   bool ucIsAlpha(PRUnichar aChar);
 
   nsString mLanguage;
   nsString mCharset;
-  nsCOMPtr<nsIUGenCategory>   mCategories;
   nsCOMPtr<mozITXTToHTMLConv> mURLDetector; // used to detect urls so the spell checker can skip them.
 };
 
 #endif
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -43,16 +43,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMRange.h"
 #include "nsIEditor.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMHTMLBRElement.h"
 #include "nsUnicharUtilCIID.h"
+#include "nsUnicodeProperties.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIContent.h"
 #include "nsTextFragment.h"
 #include "mozilla/dom/Element.h"
 #include "nsIFrame.h"
 #include "nsRange.h"
 #include "nsContentUtils.h"
 
@@ -82,20 +83,16 @@ inline bool IsConditionalPunctuation(PRU
 
 // mozInlineSpellWordUtil::Init
 
 nsresult
 mozInlineSpellWordUtil::Init(nsWeakPtr aWeakEditor)
 {
   nsresult rv;
 
-  mCategories = do_GetService(NS_UNICHARCATEGORY_CONTRACTID, &rv);
-  if (NS_FAILED(rv))
-    return rv;
-  
   // getting the editor can fail commonly because the editor was detached, so
   // don't assert
   nsCOMPtr<nsIEditor> editor = do_QueryReferent(aWeakEditor, &rv);
   if (NS_FAILED(rv))
     return rv;
 
   nsCOMPtr<nsIDOMDocument> domDoc;
   rv = editor->GetDocument(getter_AddRefs(domDoc));
@@ -801,17 +798,17 @@ WordSplitState::ClassifyCharacter(PRInt3
   NS_ASSERTION(aIndex >= 0 && aIndex <= PRInt32(mDOMWordText.Length()),
                "Index out of range");
   if (aIndex == PRInt32(mDOMWordText.Length()))
     return CHAR_CLASS_SEPARATOR;
 
   // this will classify the character, we want to treat "ignorable" characters
   // such as soft hyphens as word characters.
   nsIUGenCategory::nsUGenCategory
-    charCategory = mWordUtil->GetCategories()->Get(PRUint32(mDOMWordText[aIndex]));
+    charCategory = mozilla::unicode::GetGenCategory(mDOMWordText[aIndex]);
   if (charCategory == nsIUGenCategory::kLetter ||
       IsIgnorableCharacter(mDOMWordText[aIndex]))
     return CHAR_CLASS_WORD;
 
   // If conditional punctuation is surrounded immediately on both sides by word
   // characters it also counts as a word character.
   if (IsConditionalPunctuation(mDOMWordText[aIndex])) {
     if (!aRecurse) {
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.h
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.h
@@ -35,17 +35,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsCOMPtr.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 #include "nsString.h"
 #include "nsTArray.h"
-#include "nsIUGenCategory.h"
 
 //#define DEBUG_SPELLCHECK
 
 class nsRange;
 class nsINode;
 
 /**
  *    This class extracts text from the DOM and builds it into a single string.
@@ -112,24 +111,22 @@ public:
 
   // Call to normalize some punctuation. This function takes an autostring
   // so we can access characters directly.
   static void NormalizeWord(nsSubstring& aWord);
 
   nsIDOMDocument* GetDOMDocument() const { return mDOMDocument; }
   nsIDocument* GetDocument() const { return mDocument; }
   nsINode* GetRootNode() { return mRootNode; }
-  nsIUGenCategory* GetCategories() { return mCategories; }
   
 private:
 
   // cached stuff for the editor, set by Init
   nsCOMPtr<nsIDOMDocument> mDOMDocument;
   nsCOMPtr<nsIDocument>         mDocument;
-  nsCOMPtr<nsIUGenCategory>     mCategories;
 
   // range to check, see SetPosition and SetEnd
   nsINode*    mRootNode;
   NodeOffset  mSoftBegin;
   NodeOffset  mSoftEnd;
 
   // DOM text covering the soft range, with newlines added at block boundaries
   nsString mSoftText;
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -658,25 +658,36 @@ DrawTargetCG::Fill(const Path *aPath, co
 
   CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
   UnboundnessFixer fixer;
   CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
   CGContextSetAlpha(cg, aDrawOptions.mAlpha);
 
   CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
 
+  CGContextBeginPath(cg);
+  // XXX: we could put fill mode into the path fill rule if we wanted
+  const PathCG *cgPath = static_cast<const PathCG*>(aPath);
+
   if (isGradient(aPattern)) {
-    // XXX: we should be able to avoid the extra SaveState that PushClip does
-    PushClip(aPath);
+    // setup a clip to draw the gradient through
+    if (CGPathIsEmpty(cgPath->GetPath())) {
+      // Adding an empty path will cause us not to clip
+      // so clip everything explicitly
+      CGContextClipToRect(mCg, CGRectZero);
+    } else {
+      CGContextAddPath(cg, cgPath->GetPath());
+      if (cgPath->GetFillRule() == FILL_EVEN_ODD)
+        CGContextEOClip(mCg);
+      else
+        CGContextClip(mCg);
+    }
+
     DrawGradient(cg, aPattern);
-    PopClip();
   } else {
-    CGContextBeginPath(cg);
-    // XXX: we could put fill mode into the path fill rule if we wanted
-    const PathCG *cgPath = static_cast<const PathCG*>(aPath);
     CGContextAddPath(cg, cgPath->GetPath());
 
     SetFillFromPattern(cg, mColorSpace, aPattern);
 
     if (cgPath->GetFillRule() == FILL_EVEN_ODD)
       CGContextEOFillPath(cg);
     else
       CGContextFillPath(cg);
--- a/gfx/2d/PathCG.cpp
+++ b/gfx/2d/PathCG.cpp
@@ -155,26 +155,26 @@ PathCG::TransformedCopyToBuilder(const M
         case kCGPathElementAddLineToPoint:
           {
             CGPoint pt = element->points[0];
             CGPathAddLineToPoint(info->path, &info->transform, pt.x, pt.y);
             break;
           }
         case kCGPathElementAddQuadCurveToPoint:
           {
-            CGPoint pt  = element->points[0];
-            CGPoint cpt = element->points[1];
+            CGPoint cpt = element->points[0];
+            CGPoint pt  = element->points[1];
             CGPathAddQuadCurveToPoint(info->path, &info->transform, cpt.x, cpt.y, pt.x, pt.y);
             break;
           }
         case kCGPathElementAddCurveToPoint:
           {
-            CGPoint pt   = element->points[0];
-            CGPoint cpt1 = element->points[1];
-            CGPoint cpt2 = element->points[2];
+            CGPoint cpt1 = element->points[0];
+            CGPoint cpt2 = element->points[1];
+            CGPoint pt   = element->points[2];
             CGPathAddCurveToPoint(info->path, &info->transform, cpt1.x, cpt1.y, cpt2.x, cpt2.y, pt.x, pt.y);
             break;
           }
         case kCGPathElementCloseSubpath:
           {
             CGPathCloseSubpath(info->path);
             break;
           }
--- a/gfx/angle/README.mozilla
+++ b/gfx/angle/README.mozilla
@@ -5,16 +5,18 @@ 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
+  angle-enforce-readpixels-spec.patch - see bug 724476.
+  angle-impl-read-bgra.patch - see bug 724476.
 
 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-enforce-readpixels-spec.patch
@@ -0,0 +1,34 @@
+From: Jeff Gilbert <jgilbert@mozilla.com>
+Bug 724476 - ANGLE Bug 293 - Enforce readPixels format/type semantics
+
+diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp
+--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
++++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
+@@ -98,27 +98,16 @@ bool validReadFormatType(GLenum format, 
+         switch (type)
+         {
+           case GL_UNSIGNED_BYTE:
+             break;
+           default:
+             return false;
+         }
+         break;
+-      case GL_BGRA_EXT:
+-        switch (type)
+-        {
+-          case GL_UNSIGNED_BYTE:
+-          case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+-          case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+-            break;
+-          default:
+-            return false;
+-        }
+-        break;
+       case gl::IMPLEMENTATION_COLOR_READ_FORMAT:
+         switch (type)
+         {
+           case gl::IMPLEMENTATION_COLOR_READ_TYPE:
+             break;
+           default:
+             return false;
+         }
new file mode 100644
--- /dev/null
+++ b/gfx/angle/angle-impl-read-bgra.patch
@@ -0,0 +1,71 @@
+From: Jeff Gilbert <jgilbert@mozilla.com>
+Bug 724476 - ANGLE Bug 294 - Use BGRA/UBYTE as exposed fast format/type for readPixels
+
+diff --git a/gfx/angle/src/libGLESv2/Context.cpp b/gfx/angle/src/libGLESv2/Context.cpp
+--- a/gfx/angle/src/libGLESv2/Context.cpp
++++ b/gfx/angle/src/libGLESv2/Context.cpp
+@@ -2520,16 +2520,17 @@ void Context::readPixels(GLint x, GLint 
+     {
+         if (desc.Format == D3DFMT_A8R8G8B8 &&
+             format == GL_BGRA_EXT &&
+             type == GL_UNSIGNED_BYTE)
+         {
+             // Fast path for EXT_read_format_bgra, given
+             // an RGBA source buffer.  Note that buffers with no
+             // alpha go through the slow path below.
++            // Note that this is also the combo exposed by IMPLEMENTATION_COLOR_READ_TYPE/FORMAT
+             memcpy(dest + j * outputPitch,
+                    source + j * inputPitch,
+                    (rect.right - rect.left) * 4);
+             continue;
+         }
+ 
+         for (int i = 0; i < rect.right - rect.left; i++)
+         {
+@@ -2666,20 +2667,20 @@ void Context::readPixels(GLint x, GLint 
+                         ((unsigned short)(     a + 0.5f) << 15) |
+                         ((unsigned short)(31 * r + 0.5f) << 10) |
+                         ((unsigned short)(31 * g + 0.5f) << 5) |
+                         ((unsigned short)(31 * b + 0.5f) << 0);
+                     break;
+                   default: UNREACHABLE();
+                 }
+                 break;
+-              case GL_RGB:   // IMPLEMENTATION_COLOR_READ_FORMAT
++              case GL_RGB:
+                 switch (type)
+                 {
+-                  case GL_UNSIGNED_SHORT_5_6_5:   // IMPLEMENTATION_COLOR_READ_TYPE
++                  case GL_UNSIGNED_SHORT_5_6_5:
+                     dest16[i + j * outputPitch / sizeof(unsigned short)] = 
+                         ((unsigned short)(31 * b + 0.5f) << 0) |
+                         ((unsigned short)(63 * g + 0.5f) << 5) |
+                         ((unsigned short)(31 * r + 0.5f) << 11);
+                     break;
+                   default: UNREACHABLE();
+                 }
+                 break;
+diff --git a/gfx/angle/src/libGLESv2/Context.h b/gfx/angle/src/libGLESv2/Context.h
+--- a/gfx/angle/src/libGLESv2/Context.h
++++ b/gfx/angle/src/libGLESv2/Context.h
+@@ -69,18 +69,18 @@ enum
+     MAX_VARYING_VECTORS_SM3 = 10,
+     MAX_TEXTURE_IMAGE_UNITS = 16,
+     MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF = 4,   // For devices supporting vertex texture fetch
+     MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF,    
+     MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3,    // Reserve space for dx_Coord, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers.
+     MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3,
+     MAX_DRAW_BUFFERS = 1,
+ 
+-    IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB,
+-    IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5
++    IMPLEMENTATION_COLOR_READ_FORMAT = GL_BGRA_EXT,
++    IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_BYTE
+ };
+ 
+ enum QueryType
+ {
+     QUERY_ANY_SAMPLES_PASSED,
+     QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE,
+ 
+     QUERY_TYPE_COUNT
--- a/gfx/angle/src/libGLESv2/Context.cpp
+++ b/gfx/angle/src/libGLESv2/Context.cpp
@@ -2520,16 +2520,17 @@ void Context::readPixels(GLint x, GLint 
     {
         if (desc.Format == D3DFMT_A8R8G8B8 &&
             format == GL_BGRA_EXT &&
             type == GL_UNSIGNED_BYTE)
         {
             // Fast path for EXT_read_format_bgra, given
             // an RGBA source buffer.  Note that buffers with no
             // alpha go through the slow path below.
+            // Note that this is also the combo exposed by IMPLEMENTATION_COLOR_READ_TYPE/FORMAT
             memcpy(dest + j * outputPitch,
                    source + j * inputPitch,
                    (rect.right - rect.left) * 4);
             continue;
         }
 
         for (int i = 0; i < rect.right - rect.left; i++)
         {
@@ -2666,20 +2667,20 @@ void Context::readPixels(GLint x, GLint 
                         ((unsigned short)(     a + 0.5f) << 15) |
                         ((unsigned short)(31 * r + 0.5f) << 10) |
                         ((unsigned short)(31 * g + 0.5f) << 5) |
                         ((unsigned short)(31 * b + 0.5f) << 0);
                     break;
                   default: UNREACHABLE();
                 }
                 break;
-              case GL_RGB:   // IMPLEMENTATION_COLOR_READ_FORMAT
+              case GL_RGB:
                 switch (type)
                 {
-                  case GL_UNSIGNED_SHORT_5_6_5:   // IMPLEMENTATION_COLOR_READ_TYPE
+                  case GL_UNSIGNED_SHORT_5_6_5:
                     dest16[i + j * outputPitch / sizeof(unsigned short)] = 
                         ((unsigned short)(31 * b + 0.5f) << 0) |
                         ((unsigned short)(63 * g + 0.5f) << 5) |
                         ((unsigned short)(31 * r + 0.5f) << 11);
                     break;
                   default: UNREACHABLE();
                 }
                 break;
--- a/gfx/angle/src/libGLESv2/Context.h
+++ b/gfx/angle/src/libGLESv2/Context.h
@@ -69,18 +69,18 @@ enum
     MAX_VARYING_VECTORS_SM3 = 10,
     MAX_TEXTURE_IMAGE_UNITS = 16,
     MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF = 4,   // For devices supporting vertex texture fetch
     MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF,    
     MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3,    // Reserve space for dx_Coord, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers.
     MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3,
     MAX_DRAW_BUFFERS = 1,
 
-    IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB,
-    IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5
+    IMPLEMENTATION_COLOR_READ_FORMAT = GL_BGRA_EXT,
+    IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_BYTE
 };
 
 enum QueryType
 {
     QUERY_ANY_SAMPLES_PASSED,
     QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE,
 
     QUERY_TYPE_COUNT
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
+++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
@@ -98,27 +98,16 @@ bool validReadFormatType(GLenum format, 
         switch (type)
         {
           case GL_UNSIGNED_BYTE:
             break;
           default:
             return false;
         }
         break;
-      case GL_BGRA_EXT:
-        switch (type)
-        {
-          case GL_UNSIGNED_BYTE:
-          case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
-          case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
-            break;
-          default:
-            return false;
-        }
-        break;
       case gl::IMPLEMENTATION_COLOR_READ_FORMAT:
         switch (type)
         {
           case gl::IMPLEMENTATION_COLOR_READ_TYPE:
             break;
           default:
             return false;
         }
--- a/gfx/cairo/cairo/src/cairo-features.h.in
+++ b/gfx/cairo/cairo/src/cairo-features.h.in
@@ -64,18 +64,16 @@
 @XLIB_SURFACE_FEATURE@
 
 @XLIB_XRENDER_SURFACE_FEATURE@