Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Mon, 07 Nov 2011 12:14:52 -0800
changeset 105711 e784f2911b5bd7956f52be6a93f010a032cf364e
parent 105710 89fff0ee52d5e237060a44b133a68e723dab8ae4 (current diff)
parent 79888 8200dc82b5edba7ff37f424df9895759d244e7bc (diff)
child 105712 a44853532140fdc0b52f1fd34bbc0f34f2a992e3
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone10.0a1
Merge from mozilla-central.
accessible/tests/mochitest/Makefile.in
accessible/tests/mochitest/actions/Makefile.in
accessible/tests/mochitest/events/Makefile.in
accessible/tests/mochitest/states/Makefile.in
accessible/tests/mochitest/tree/Makefile.in
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/components/feeds/test/Makefile.in
browser/components/feeds/test/chrome/Makefile.in
browser/components/nsBrowserGlue.js
browser/components/sessionstore/test/browser/Makefile.in
browser/components/tabview/test/Makefile.in
browser/devtools/highlighter/test/Makefile.in
browser/devtools/highlighter/test/browser_inspector_editor.js
browser/devtools/highlighter/test/browser_inspector_initialization.js
browser/devtools/highlighter/test/browser_inspector_tab_switch.js
browser/devtools/jar.mn
browser/devtools/styleinspector/CssHtmlTree.jsm
browser/devtools/styleinspector/CssLogic.jsm
browser/devtools/styleinspector/StyleInspector.jsm
browser/devtools/styleinspector/csshtmltree.xhtml
browser/devtools/styleinspector/cssruleview.xhtml
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/test/browser/Makefile.in
browser/devtools/webconsole/test/browser/test-console-extras.html
browser/locales/en-US/chrome/browser/browser.properties
browser/locales/en-US/chrome/browser/devtools/inspector.properties
browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
browser/themes/gnomestripe/browser/browser.css
browser/themes/gnomestripe/browser/devtools/search.png
browser/themes/pinstripe/browser/browser.css
browser/themes/pinstripe/browser/devtools/search.png
browser/themes/winstripe/browser/browser.css
browser/themes/winstripe/browser/devtools/search.png
config/autoconf.mk.in
configure.in
content/base/public/nsIContent.h
content/base/public/nsIDocument.h
content/base/public/nsINode.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsGenericDOMDataNode.cpp
content/base/src/nsGenericDOMDataNode.h
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/base/src/nsGkAtomList.h
content/base/src/nsStyledElement.cpp
content/base/src/nsTreeSanitizer.cpp
content/base/test/Makefile.in
content/events/public/nsEventNameList.h
content/events/public/nsIPrivateDOMEvent.h
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventListenerManager.cpp
content/events/test/Makefile.in
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/test/file_fullscreen-api.html
content/smil/nsSMILAnimationController.cpp
content/svg/content/src/DOMSVGLength.cpp
content/svg/content/src/DOMSVGNumber.cpp
content/svg/content/src/DOMSVGPathSegList.cpp
content/svg/content/src/DOMSVGPoint.cpp
content/svg/content/src/DOMSVGPointList.cpp
content/svg/content/src/DOMSVGTransform.cpp
content/svg/content/src/Makefile.in
content/svg/content/src/SVGAnimatedLengthList.cpp
content/svg/content/src/SVGAnimatedLengthList.h
content/svg/content/src/SVGAnimatedNumberList.cpp
content/svg/content/src/SVGAnimatedNumberList.h
content/svg/content/src/SVGAnimatedPathSegList.cpp
content/svg/content/src/SVGAnimatedPathSegList.h
content/svg/content/src/SVGAnimatedPointList.cpp
content/svg/content/src/SVGAnimatedPointList.h
content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
content/svg/content/src/SVGAnimatedTransformList.cpp
content/svg/content/src/SVGAnimatedTransformList.h
content/svg/content/src/nsSVGAngle.cpp
content/svg/content/src/nsSVGAngle.h
content/svg/content/src/nsSVGBoolean.cpp
content/svg/content/src/nsSVGBoolean.h
content/svg/content/src/nsSVGClass.cpp
content/svg/content/src/nsSVGClass.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGEnum.cpp
content/svg/content/src/nsSVGEnum.h
content/svg/content/src/nsSVGInteger.cpp
content/svg/content/src/nsSVGInteger.h
content/svg/content/src/nsSVGIntegerPair.cpp
content/svg/content/src/nsSVGIntegerPair.h
content/svg/content/src/nsSVGLength2.cpp
content/svg/content/src/nsSVGLength2.h
content/svg/content/src/nsSVGNumber2.cpp
content/svg/content/src/nsSVGNumber2.h
content/svg/content/src/nsSVGNumberPair.cpp
content/svg/content/src/nsSVGNumberPair.h
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/src/nsSVGSVGElement.h
content/svg/content/src/nsSVGString.cpp
content/svg/content/src/nsSVGString.h
content/svg/content/src/nsSVGViewBox.cpp
content/svg/content/src/nsSVGViewBox.h
content/xml/document/test/Makefile.in
docshell/base/nsDocShell.cpp
dom/Makefile.in
dom/base/ConsoleAPI.js
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsJSEnvironment.cpp
dom/plugins/base/nsPluginStreamListenerPeer.cpp
dom/src/storage/nsDOMStorage.cpp
dom/src/storage/nsDOMStorage.h
dom/tests/browser/browser_ConsoleAPITests.js
dom/tests/browser/test-console-api.html
dom/tests/mochitest/general/test_consoleAPI.html
dom/workers/Events.cpp
dom/workers/Exceptions.cpp
dom/workers/ScriptLoader.cpp
dom/workers/WorkerPrivate.cpp
editor/libeditor/text/tests/Makefile.in
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
image/decoders/nsICODecoder.cpp
image/decoders/nsPNGDecoder.h
image/src/SVGDocumentWrapper.cpp
image/test/mochitest/Makefile.in
intl/uconv/src/nsTextToSubURI.cpp
js/src/Makefile.in
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsclass.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jsxml.cpp
js/src/tests/js1_8_5/extensions/jstests.list
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/base/tests/Makefile.in
layout/generic/nsBlockFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsHTMLReflowState.h
layout/generic/nsLineBox.cpp
layout/generic/nsLineBox.h
layout/generic/nsPlaceholderFrame.cpp
layout/generic/nsPlaceholderFrame.h
layout/inspector/src/inDOMUtils.cpp
layout/style/nsDOMCSSAttrDeclaration.cpp
layout/style/nsDOMCSSAttrDeclaration.h
layout/style/nsHTMLCSSStyleSheet.cpp
layout/style/test/Makefile.in
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
layout/xul/base/test/Makefile.in
mobile/chrome/content/BookmarkPopup.js
mobile/chrome/tests/Makefile.in
mobile/installer/package-manifest.in
mobile/themes/core/honeycomb/browser.css
mobile/themes/core/honeycomb/defines.inc
modules/libpref/public/Preferences.h
modules/libpref/src/Preferences.cpp
modules/libpref/src/init/all.js
parser/html/nsHtml5TreeBuilderCppSupplement.h
services/sync/tests/unit/test_syncscheduler.js
startupcache/test/TestStartupCache.cpp
testing/mochitest/runtests.py
testing/testsuite-targets.mk
toolkit/components/downloads/nsDownloadManager.cpp
toolkit/components/places/tests/cpp/places_test_harness.h
toolkit/components/places/tests/cpp/test_IHistory.cpp
toolkit/components/startup/nsTryToClose.js
toolkit/components/startup/nsTryToClose.manifest
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/crashreporter/test/Makefile.in
toolkit/mozapps/extensions/AddonRepository.jsm
widget/public/nsGUIEvent.h
widget/src/android/GfxInfo.cpp
widget/src/windows/WinTaskbar.cpp
widget/src/windows/nsAppShell.cpp
xpcom/build/nsXPComInit.cpp
xpcom/idl-parser/xpidl.py
xpcom/idl-parser/xpidllex.py
xpcom/idl-parser/xpidlyacc.py
xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp
xpcom/reflect/xptinfo/src/xptiprivate.h
xpcom/tests/TestHarness.h
xpcom/threads/nsThread.cpp
xpcom/threads/nsThread.h
xpcom/threads/nsThreadManager.cpp
--- a/Makefile.in
+++ b/Makefile.in
@@ -208,16 +208,18 @@ ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
 # No point in clobbering if PGO has been explicitly disabled.
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 maybe_clobber_profiledbuild: clean
 else
 maybe_clobber_profiledbuild:
 endif
 else
 maybe_clobber_profiledbuild:
+	$(RM) $(DIST)/bin/*.pgc
+	find $(DIST)/$(MOZ_APP_NAME) -name "*.pgc" -exec mv {} $(DIST)/bin \;
 endif
 
 .PHONY: maybe_clobber_profiledbuild
 
 # Look for R_386_PC32 relocations in shared libs, these
 # break x86_64 builds and SELinux users.
 ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)
 scheck::
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1003,16 +1003,19 @@ pref("services.sync.prefs.sync.xpinstall
 pref("devtools.errorconsole.enabled", false);
 
 // Enable the Inspector
 pref("devtools.inspector.enabled", true);
 
 // Enable the style inspector
 pref("devtools.styleinspector.enabled", true);
 
+// Enable the rules view
+pref("devtools.ruleview.enabled", true);
+
 // Enable the Scratchpad tool.
 pref("devtools.scratchpad.enabled", true);
 
 // Enable tools for Chrome development.
 pref("devtools.chrome.enabled", false);
 
 // Disable the GCLI enhanced command line.
 pref("devtools.gcli.enable", false);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8185,17 +8185,17 @@ let DownloadMonitorPanel = {
       return;
     }
 
     // Find the download with the longest remaining time
     let numPaused = 0;
     let maxTime = -Infinity;
     let dls = gDownloadMgr.activeDownloads;
     while (dls.hasMoreElements()) {
-      let dl = dls.getNext().QueryInterface(Ci.nsIDownload);
+      let dl = dls.getNext();
       if (dl.state == gDownloadMgr.DOWNLOAD_DOWNLOADING) {
         // Figure out if this download takes longer
         if (dl.speed > 0 && dl.size > 0)
           maxTime = Math.max(maxTime, (dl.size - dl.amountTransferred) / dl.speed);
         else
           maxTime = -1;
       }
       else if (dl.state == gDownloadMgr.DOWNLOAD_PAUSED)
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -962,17 +962,17 @@
                   flex="1" contenttooltip="aHTMLTooltip"
                   tabcontainer="tabbrowser-tabs"
                   contentcontextmenu="contentAreaContextMenu"
                   autocompletepopup="PopupAutoComplete"
                   onclick="return contentAreaClick(event, false);"/>
       <statuspanel id="statusbar-display" inactive="true"/>
     </vbox>
     <splitter id="devtools-side-splitter" hidden="true"/>
-    <vbox id="devtools-sidebar-box" hidden="true" flex="1"
+    <vbox id="devtools-sidebar-box" hidden="true"
           style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
       <toolbar id="devtools-sidebar-toolbar" nowindowdrag="true"/>
       <deck id="devtools-sidebar-deck" flex="1"/>
     </vbox>
     <vbox id="browser-border-end" hidden="true" layer="true"/>
   </hbox>
 
   <hbox id="full-screen-warning-container" hidden="true" fadeout="true">
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1103,40 +1103,43 @@
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <parameter name="aLoadInBackground"/>
         <parameter name="aAllowThirdPartyFixup"/>
         <body>
           <![CDATA[
             var aFromExternal;
             var aRelatedToCurrent;
+            var aIsUTF8;
             if (arguments.length == 2 &&
                 typeof arguments[1] == "object" &&
                 !(arguments[1] instanceof Ci.nsIURI)) {
               let params = arguments[1];
               aReferrerURI          = params.referrerURI;
               aCharset              = params.charset;
               aPostData             = params.postData;
               aLoadInBackground     = params.inBackground;
               aAllowThirdPartyFixup = params.allowThirdPartyFixup;
               aFromExternal         = params.fromExternal;
               aRelatedToCurrent     = params.relatedToCurrent;
+              aIsUTF8               = params.isUTF8;
             }
 
             var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
                          Services.prefs.getBoolPref("browser.tabs.loadInBackground");
             var owner = bgLoad ? null : this.selectedTab;
             var tab = this.addTab(aURI, {
                                   referrerURI: aReferrerURI,
                                   charset: aCharset,
                                   postData: aPostData,
                                   ownerTab: owner,
                                   allowThirdPartyFixup: aAllowThirdPartyFixup,
                                   fromExternal: aFromExternal,
-                                  relatedToCurrent: aRelatedToCurrent});
+                                  relatedToCurrent: aRelatedToCurrent,
+                                  isUTF8: aIsUTF8});
             if (!bgLoad)
               this.selectedTab = tab;
 
             return tab;
          ]]>
         </body>
       </method>
 
@@ -1199,28 +1202,30 @@
         <parameter name="aPostData"/>
         <parameter name="aOwner"/>
         <parameter name="aAllowThirdPartyFixup"/>
         <body>
           <![CDATA[
             var aFromExternal;
             var aRelatedToCurrent;
             var aSkipAnimation;
+            var aIsUTF8;
             if (arguments.length == 2 &&
                 typeof arguments[1] == "object" &&
                 !(arguments[1] instanceof Ci.nsIURI)) {
               let params = arguments[1];
               aReferrerURI          = params.referrerURI;
               aCharset              = params.charset;
               aPostData             = params.postData;
               aOwner                = params.ownerTab;
               aAllowThirdPartyFixup = params.allowThirdPartyFixup;
               aFromExternal         = params.fromExternal;
               aRelatedToCurrent     = params.relatedToCurrent;
               aSkipAnimation        = params.skipAnimation;
+              aIsUTF8               = params.isUTF8;
             }
 
             this._browsers = null; // invalidate cache
 
             // if we're adding tabs, we're past interrupt mode, ditch the owner
             if (this.mCurrentTab.owner)
               this.mCurrentTab.owner = null;
 
@@ -1358,16 +1363,18 @@
               // the document successfully loads
               b.userTypedValue = aURI;
 
               let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
               if (aAllowThirdPartyFixup)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
               if (aFromExternal)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
+              if (aIsUTF8)
+                flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
               try {
                 b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
               } catch (ex) {
                 Cu.reportError(ex);
               }
             }
 
             // We start our browsers out as inactive, and then maintain
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -201,16 +201,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_selectTabAtIndex.js \
                  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_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 \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_urlbarEnter.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_VALUE = "example.com/\xF7?\xF7";
+const START_VALUE = "example.com/%C3%B7?%C3%B7";
+
+function test() {
+  waitForExplicitFinish();
+  runNextTest();
+}
+
+function locationBarEnter(aEvent, aClosure) {
+  executeSoon(function() {
+    gURLBar.focus();
+    EventUtils.synthesizeKey("VK_RETURN", aEvent);
+    addPageShowListener(aClosure);
+  });
+}
+
+function runNextTest() {
+  let test = gTests.shift();
+  if (!test) {
+    finish();
+    return;
+  }
+  
+  info("Running test: " + test.desc);
+  let tab = gBrowser.selectedTab = gBrowser.addTab(START_VALUE);
+  addPageShowListener(function() {
+    locationBarEnter(test.event, function() {
+      test.check(tab);
+
+      // Clean up
+      while (gBrowser.tabs.length > 1)
+        gBrowser.removeTab(gBrowser.selectedTab)
+      runNextTest();
+    });
+  });
+}
+
+let gTests = [
+  { desc: "Simple return keypress",
+    event: {},
+    check: checkCurrent
+  },
+
+  { desc: "Alt+Return keypress",
+    event: { altKey: true },
+    check: checkNewTab,
+  },
+]
+
+function checkCurrent(aTab) {
+  is(gURLBar.value, TEST_VALUE, "Urlbar should preserve the value on return keypress");
+  is(gBrowser.selectedTab, aTab, "New URL was loaded in the current tab");
+}
+
+function checkNewTab(aTab) {
+  is(gURLBar.value, TEST_VALUE, "Urlbar should preserve the value on return keypress");
+  isnot(gBrowser.selectedTab, aTab, "New URL was loaded in a new tab");
+}
+
+function addPageShowListener(aFunc) {
+  gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
+    aFunc();
+  });
+}
+
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -321,16 +321,20 @@
           function loadCurrent() {
             let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
             // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
             // inheriting the currently loaded document's principal, unless this
             // URL is marked as safe to inherit (e.g. came from a bookmark
             // keyword).
             if (!mayInheritPrincipal)
               flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+            // If the value wasn't typed, we know that we decoded the value as
+            // UTF-8 (see losslessDecodeURI)
+            if (!this.valueIsTyped)
+              flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
             gBrowser.loadURIWithFlags(url, flags, null, null, postData);
           }
 
           // Focus the content area before triggering loads, since if the load
           // occurs in a new tab, we want focus to be restored to the content
           // area when the current tab is re-selected.
           gBrowser.selectedBrowser.focus();
 
@@ -356,16 +360,18 @@
 
             if (where == "current") {
               loadCurrent();
             } else {
               this.handleRevert();
               let params = { allowThirdPartyFixup: true, postData: postData };
               if (altEnter)
                 params.inBackground = false;
+              if (!this.valueIsTyped)
+                params.isUTF8 = true;
               openUILinkIn(url, where, params);
             }
           } else {
             loadCurrent();
           }
         ]]></body>
       </method>
 
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -194,16 +194,18 @@ function openLinkIn(url, where, params) 
   var aFromChrome           = params.fromChrome;
   var aAllowThirdPartyFixup = params.allowThirdPartyFixup;
   var aPostData             = params.postData;
   var aCharset              = params.charset;
   var aReferrerURI          = params.referrerURI;
   var aRelatedToCurrent     = params.relatedToCurrent;
   var aInBackground         = params.inBackground;
   var aDisallowInheritPrincipal = params.disallowInheritPrincipal;
+  // Currently, this parameter works only for where=="tab" or "current"
+  var aIsUTF8               = params.isUTF8;
 
   if (where == "save") {
     saveURL(url, null, null, true, null, aReferrerURI);
     return;
   }
   const Cc = Components.classes;
   const Ci = Components.interfaces;
 
@@ -267,30 +269,33 @@ function openLinkIn(url, where, params) 
 
   switch (where) {
   case "current":
     let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
     if (aAllowThirdPartyFixup)
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
     if (aDisallowInheritPrincipal)
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+    if (aIsUTF8)
+      flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
     w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData);
     break;
   case "tabshifted":
     loadInBackground = !loadInBackground;
     // fall through
   case "tab":
     let browser = w.gBrowser;
     browser.loadOneTab(url, {
                        referrerURI: aReferrerURI,
                        charset: aCharset,
                        postData: aPostData,
                        inBackground: loadInBackground,
                        allowThirdPartyFixup: aAllowThirdPartyFixup,
-                       relatedToCurrent: aRelatedToCurrent});
+                       relatedToCurrent: aRelatedToCurrent,
+                       isUTF8: aIsUTF8});
     break;
   }
 
   // If this window is active, focus the target window. Otherwise, focus the
   // content but don't raise the window, since the URI we just loaded may have
   // resulted in a new frontmost window (e.g. "javascript:window.open('');").
   var fm = Components.classes["@mozilla.org/focus-manager;1"].
              getService(Components.interfaces.nsIFocusManager);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -756,16 +756,17 @@ BrowserGlue.prototype = {
     catch (e) {
     }
   },
 
 #ifdef MOZ_TELEMETRY_REPORTING
   _showTelemetryNotification: function BG__showTelemetryNotification() {
     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;
 
     var telemetryPrompted = null;
     try {
       telemetryPrompted = Services.prefs.getIntPref(PREF_TELEMETRY_PROMPTED);
@@ -798,24 +799,27 @@ BrowserGlue.prototype = {
                       callback:  function(aNotificationBar, aButton) {
                         Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
                       }
                     },
                     {
                       label:     browserBundle.GetStringFromName("telemetryNoButtonLabel"),
                       accessKey: browserBundle.GetStringFromName("telemetryNoButtonAccessKey"),
                       popup:     null,
-                      callback:  function(aNotificationBar, aButton) {}
+                      callback:  function(aNotificationBar, aButton) {
+                        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 = 6; // arbitrary number, just so bar sticks around for a bit
 
     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
--- a/browser/devtools/highlighter/TreePanel.jsm
+++ b/browser/devtools/highlighter/TreePanel.jsm
@@ -453,16 +453,19 @@ TreePanel.prototype = {
     // position the editor
     editor.style.left = editorLeft + "px";
     editor.style.top = editorTop + "px";
 
     // set and select the text
     editorInput.value = aAttrVal;
     editorInput.select();
 
+    // remove tree key navigation events
+    this.treeIFrame.removeEventListener("keypress", this.IUI, false);
+
     // listen for editor specific events
     this.bindEditorEvent(editor, "click", function(aEvent) {
       aEvent.stopPropagation();
     });
     this.bindEditorEvent(editor, "dblclick", function(aEvent) {
       aEvent.stopPropagation();
     });
     this.bindEditorEvent(editor, "keypress",
@@ -510,18 +513,22 @@ TreePanel.prototype = {
    * Handle keypress events in the editor.
    * @param aEvent
    *        The keyboard event.
    */
   handleEditorKeypress: function TP_handleEditorKeypress(aEvent)
   {
     if (aEvent.which == this.window.KeyEvent.DOM_VK_RETURN) {
       this.saveEditor();
+      aEvent.preventDefault();
+      aEvent.stopPropagation();
     } else if (aEvent.keyCode == this.window.KeyEvent.DOM_VK_ESCAPE) {
       this.closeEditor();
+      aEvent.preventDefault();
+      aEvent.stopPropagation();
     }
   },
 
   /**
    * Close the editor and cleanup.
    */
   closeEditor: function TP_closeEditor()
   {
@@ -541,16 +548,19 @@ TreePanel.prototype = {
     this.unbindEditorEvent(editor, "keypress");
 
     // clean up after the editor
     editorInput.value = "";
     editorInput.blur();
     this.editingContext = null;
     this.editingEvents = {};
 
+    // re-add navigation listener
+    this.treeIFrame.addEventListener("keypress", this.IUI, false);
+
     // event notification
     Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
                                   null);
   },
 
   /**
    * Commit the edits made in the editor, then close it.
    */
@@ -562,16 +572,17 @@ TreePanel.prototype = {
     // set the new attribute value on the original target DOM element
     this.editingContext.repObj.setAttribute(this.editingContext.attrName,
                                               editorInput.value);
 
     // update the HTML tree attribute value
     this.editingContext.attrObj.innerHTML = editorInput.value;
 
     this.IUI.isDirty = true;
+    this.IUI.nodeChanged(this.registrationObject);
 
     // event notification
     Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
                                   null);
 
     this.closeEditor();
   },
 
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -45,16 +45,17 @@ const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 var EXPORTED_SYMBOLS = ["InspectorUI"];
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/TreePanel.jsm");
+Cu.import("resource:///modules/devtools/CssRuleView.jsm");
 
 const INSPECTOR_INVISIBLE_ELEMENTS = {
   "head": true,
   "base": true,
   "basefont": true,
   "isindex": true,
   "link": true,
   "meta": true,
@@ -73,19 +74,25 @@ const INSPECTOR_NOTIFICATIONS = {
 
   // Fires once the Inspector completes the initialization and opens up on
   // screen.
   OPENED: "inspector-opened",
 
   // Fires once the Inspector is closed.
   CLOSED: "inspector-closed",
 
+  // Fires when the Inspector is reopened after tab-switch.
+  STATE_RESTORED: "inspector-state-restored",
+
   // Fires when the Tree Panel is opened and initialized.
   TREEPANELREADY: "inspector-treepanel-ready",
 
+  // Fires when the CSS Rule View is opened and initialized.
+  RULEVIEWREADY: "inspector-ruleview-ready",
+
   // Event notifications for the attribute-value editor
   EDITOR_OPENED: "inspector-editor-opened",
   EDITOR_CLOSED: "inspector-editor-closed",
   EDITOR_SAVED: "inspector-editor-saved",
 };
 
 ///////////////////////////////////////////////////////////////////////////
 //// Highlighter
@@ -735,16 +742,17 @@ function InspectorUI(aWindow)
 }
 
 InspectorUI.prototype = {
   browser: null,
   tools: null,
   toolEvents: null,
   inspecting: false,
   treePanelEnabled: true,
+  ruleViewEnabled: true,
   isDirty: false,
   store: null,
 
   /**
    * Toggle the inspector interface elements on or off.
    *
    * @param aEvent
    *        The event that requested the UI change. Toolbar button or menu.
@@ -886,16 +894,21 @@ InspectorUI.prototype = {
       this.chromeDoc.getElementById("inspector-inspect-toolbutton");
 
     this.initTools();
 
     if (this.treePanelEnabled) {
       this.treePanel = new TreePanel(this.chromeWin, this);
     }
 
+    if (Services.prefs.getBoolPref("devtools.ruleview.enabled") &&
+        !this.toolRegistered("ruleview")) {
+      this.registerRuleView();
+    }
+
     if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") &&
         !this.toolRegistered("styleinspector")) {
       this.stylePanel = new StyleInspector(this.chromeWin, this);
     }
 
     this.toolbar.hidden = false;
     this.inspectMenuitem.setAttribute("checked", true);
 
@@ -906,16 +919,41 @@ InspectorUI.prototype = {
 
     this.progressListener = new InspectorProgressListener(this);
 
     // initialize the highlighter
     this.initializeHighlighter();
   },
 
   /**
+   * Register the Rule View in the Sidebar.
+   */
+  registerRuleView: function IUI_registerRuleView()
+  {
+    let isOpen = this.isRuleViewOpen.bind(this);
+
+    this.ruleViewObject = {
+      id: "ruleview",
+      label: this.strings.GetStringFromName("ruleView.label"),
+      tooltiptext: this.strings.GetStringFromName("ruleView.tooltiptext"),
+      accesskey: this.strings.GetStringFromName("ruleView.accesskey"),
+      context: this,
+      get isOpen() isOpen(),
+      show: this.openRuleView,
+      hide: this.closeRuleView,
+      onSelect: this.selectInRuleView,
+      panel: null,
+      unregister: this.destroyRuleView,
+      sidebar: true,
+    };
+
+    this.registerTool(this.ruleViewObject);
+  },
+
+  /**
    * Register and initialize any included tools.
    */
   initTools: function IUI_initTools()
   {
     // Extras go here.
   },
 
   /**
@@ -1115,16 +1153,29 @@ InspectorUI.prototype = {
       }
     }
 
     this.breadcrumbs.update();
 
     this.toolsSelect(aScroll);
   },
 
+  /**
+   * Called when the highlighted node is changed by a tool.
+   *
+   * @param object aUpdater
+   *        The tool that triggered the update (if any), that tool's
+   *        onChanged will not be called.
+   */
+  nodeChanged: function IUI_nodeChanged(aUpdater)
+  {
+    this.highlighter.highlight();
+    this.toolsOnChanged(aUpdater);
+  },
+
   /////////////////////////////////////////////////////////////////////////
   //// Event Handling
 
   highlighterReady: function IUI_highlighterReady()
   {
     // Setup the InspectorStore or restore state
     this.initializeStore();
 
@@ -1267,16 +1318,104 @@ InspectorUI.prototype = {
             event.stopPropagation();
             break;
         }
         break;
     }
   },
 
   /////////////////////////////////////////////////////////////////////////
+  //// CssRuleView methods
+
+  /**
+   * Is the cssRuleView open?
+   */
+  isRuleViewOpen: function IUI_isRuleViewOpen()
+  {
+    return this.isSidebarOpen && this.ruleButton.hasAttribute("checked") &&
+      (this.sidebarDeck.selectedPanel == this.getToolIframe(this.ruleViewObject));
+  },
+
+  /**
+   * Convenience getter to retrieve the Rule Button.
+   */
+  get ruleButton()
+  {
+    return this.chromeDoc.getElementById(
+      this.getToolbarButtonId(this.ruleViewObject.id));
+  },
+
+  /**
+   * Open the CssRuleView.
+   */
+  openRuleView: function IUI_openRuleView()
+  {
+    let iframe = this.getToolIframe(this.ruleViewObject);
+    let boundLoadListener = function() {
+      iframe.removeEventListener("load", boundLoadListener, true);
+      let doc = iframe.contentDocument;
+      this.ruleView = new CssRuleView(doc);
+      this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
+      this.ruleView.element.addEventListener("CssRuleViewChanged",
+                                             this.boundRuleViewChanged);
+
+      doc.documentElement.appendChild(this.ruleView.element);
+      this.ruleView.highlight(this.selection);
+      Services.obs.notifyObservers(null,
+        INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, null);
+    }.bind(this);
+
+    iframe.addEventListener("load", boundLoadListener, true);
+
+    iframe.setAttribute("src", "chrome://browser/content/devtools/cssruleview.xul");
+  },
+
+  /**
+   * Stub to Close the CSS Rule View. Does nothing currently because the
+   * Rule View lives in the sidebar.
+   */
+  closeRuleView: function IUI_closeRuleView()
+  {
+    // do nothing for now
+  },
+
+  /**
+   * Update the selected node in the Css Rule View.
+   * @param {nsIDOMnode} the selected node.
+   */
+  selectInRuleView: function IUI_selectInRuleView(aNode)
+  {
+    if (this.ruleView)
+      this.ruleView.highlight(aNode);
+  },
+
+  ruleViewChanged: function IUI_ruleViewChanged()
+  {
+    this.isDirty = true;
+    this.nodeChanged(this.ruleViewObject);
+  },
+
+  /**
+   * Destroy the rule view.
+   */
+  destroyRuleView: function IUI_destroyRuleView()
+  {
+    let iframe = this.getToolIframe(this.ruleViewObject);
+    iframe.parentNode.removeChild(iframe);
+
+    if (this.ruleView) {
+      this.ruleView.element.removeEventListener("CssRuleViewChanged",
+                                                this.boundRuleViewChanged);
+      delete boundRuleViewChanged;
+      this.ruleView.clear();
+      delete this.ruleView;
+    }
+  },
+
+  /////////////////////////////////////////////////////////////////////////
   //// Utility Methods
 
   /**
    * inspect the given node, highlighting it on the page and selecting the
    * correct row in the tree panel
    *
    * @param aNode
    *        the element in the document to inspect
@@ -1547,20 +1686,16 @@ InspectorUI.prototype = {
     // create tool iframe
     let iframe = this.chromeDoc.createElement("iframe");
     iframe.id = "devtools-sidebar-iframe-" + aRegObj.id;
     iframe.setAttribute("flex", "1");
     this.sidebarDeck.appendChild(iframe);
 
     // wire up button to show the iframe
     this.bindToolEvent(btn, "click", function showIframe() {
-      let visible = this.sidebarDeck.selectedPanel == iframe;
-      if (!visible) {
-        sidebarDeck.selectedPanel = iframe;
-      }
       this.toolShow(aRegObj);
     }.bind(this));
   },
 
   /**
    * Return the registered object's iframe.
    * @param aRegObj see registerTool function.
    * @return iframe or null
@@ -1571,20 +1706,28 @@ InspectorUI.prototype = {
   },
 
   /**
    * Show the specified tool.
    * @param aTool Object (see comment for IUI_registerTool)
    */
   toolShow: function IUI_toolShow(aTool)
   {
-    aTool.show.call(aTool.context, this.selection);
-
     let btn = this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id));
     btn.setAttribute("checked", "true");
+    if (aTool.sidebar) {
+      this.sidebarDeck.selectedPanel = this.getToolIframe(aTool);
+      this.sidebarTools.forEach(function(other) {
+        if (other != aTool)
+          this.chromeDoc.getElementById(
+            this.getToolbarButtonId(other.id)).removeAttribute("checked");
+      }.bind(this));
+    }
+
+    aTool.show.call(aTool.context, this.selection);
   },
 
   /**
    * Hide the specified tool.
    * @param aTool Object (see comment for IUI_registerTool)
    */
   toolHide: function IUI_toolHide(aTool)
   {
@@ -1684,26 +1827,34 @@ InspectorUI.prototype = {
    * Restore tools previously save using saveToolState().
    *
    * @param aWinID The ID of the window to which the associated tools are to be
    *               restored.
    */
   restoreToolState: function IUI_restoreToolState(aWinID)
   {
     let openTools = this.store.getValue(aWinID, "openTools");
+    let activeSidebarTool;
     if (openTools) {
       this.toolsDo(function IUI_toolsOnShow(aTool) {
         if (aTool.id in openTools) {
           if (aTool.sidebar && !this.isSidebarOpen) {
             this.showSidebar();
+            activeSidebarTool = aTool;
           }
           this.toolShow(aTool);
         }
       }.bind(this));
+      this.sidebarTools.forEach(function(tool) {
+        if (tool != activeSidebarTool)
+          this.chromeDoc.getElementById(
+            this.getToolbarButtonId(tool.id)).removeAttribute("checked");
+      }.bind(this));
     }
+    Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.STATE_RESTORED, null);
   },
 
   /**
    * For each tool in the tools collection select the current node that is
    * selected in the highlighter
    * @param aScroll boolean
    *        Do you want to scroll the treepanel?
    */
@@ -1718,24 +1869,40 @@ InspectorUI.prototype = {
   },
 
   /**
    * Dim or undim each tool in the tools collection
    * @param aState true = dim, false = undim
    */
   toolsDim: function IUI_toolsDim(aState)
   {
-    this.toolsDo(function IUI_toolsOnSelect(aTool) {
+    this.toolsDo(function IUI_toolsDim(aTool) {
       if (aTool.isOpen && "dim" in aTool) {
         aTool.dim.call(aTool.context, aState);
       }
     });
   },
 
   /**
+   * Notify registered tools of changes to the highlighted element.
+   *
+   * @param object aUpdater
+   *        The tool that triggered the update (if any), that tool's
+   *        onChanged will not be called.
+   */
+  toolsOnChanged: function IUI_toolsChanged(aUpdater)
+  {
+    this.toolsDo(function IUI_toolsOnChanged(aTool) {
+      if (aTool.isOpen && ("onChanged" in aTool) && aTool != aUpdater) {
+        aTool.onChanged.call(aTool.context);
+      }
+    });
+  },
+
+  /**
    * Loop through all registered tools and pass each into the provided function
    * @param aFunction The function to which each tool is to be passed
    */
   toolsDo: function IUI_toolsDo(aFunction)
   {
     for each (let tool in this.tools) {
       aFunction(tool);
     }
@@ -1932,18 +2099,23 @@ InspectorProgressListener.prototype = {
   function IPL_onStateChange(aProgress, aRequest, aFlag, aStatus)
   {
     // Remove myself if the Inspector is no longer open.
     if (!this.IUI.isInspectorOpen) {
       this.destroy();
       return;
     }
 
-    // Skip non-start states.
-    if (!(aFlag & Ci.nsIWebProgressListener.STATE_START)) {
+    let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
+    let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
+    let isNetwork = aFlag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
+    let isRequest = aFlag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
+
+    // Skip non-interesting states.
+    if (!isStart || !isDocument || !isRequest || !isNetwork) {
       return;
     }
 
     // If the request is about to happen in a new window, we are not concerned
     // about the request.
     if (aProgress.DOMWindow != this.IUI.win) {
       return;
     }
--- a/browser/devtools/highlighter/test/Makefile.in
+++ b/browser/devtools/highlighter/test/Makefile.in
@@ -60,15 +60,17 @@ include $(topsrcdir)/config/rules.mk
 		browser_inspector_editor.js \
 		browser_inspector_bug_566084_location_changed.js \
 		browser_inspector_infobar.js \
 		browser_inspector_bug_690361.js \
 		browser_inspector_bug_672902_keyboard_shortcuts.js \
 		browser_inspector_keybindings.js \
 		browser_inspector_breadcrumbs.html \
 		browser_inspector_breadcrumbs.js \
+		browser_inspector_bug_699308_iframe_navigation.js \
+        browser_inspector_changes.js \
 		$(NULL)
 
 # Disabled due to constant failures
 # 		browser_inspector_treePanel_click.js \
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/highlighter/test/browser_inspector_bug_699308_iframe_navigation.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let iframe;
+let iframeLoads = 0;
+let checksAfterLoads = false;
+
+function startTest() {
+  ok(window.InspectorUI, "InspectorUI variable exists");
+  Services.obs.addObserver(runInspectorTests,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
+  InspectorUI.toggleInspectorUI();
+}
+
+function runInspectorTests() {
+  Services.obs.removeObserver(runInspectorTests,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
+
+  iframe = content.document.querySelector("iframe");
+  ok(iframe, "found the iframe element");
+
+  ok(InspectorUI.inspecting, "Inspector is highlighting");
+  ok(InspectorUI.isInspectorOpen, "Inspector is open");
+
+  Services.obs.addObserver(finishTest,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
+
+  iframe.addEventListener("load", onIframeLoad, false);
+
+  executeSoon(function() {
+    iframe.contentWindow.location = "javascript:location.reload()";
+  });
+}
+
+function onIframeLoad() {
+  if (++iframeLoads != 2) {
+    executeSoon(function() {
+      iframe.contentWindow.location = "javascript:location.reload()";
+    });
+    return;
+  }
+
+  iframe.removeEventListener("load", onIframeLoad, false);
+
+  ok(InspectorUI.inspecting, "Inspector is highlighting after iframe nav");
+  ok(InspectorUI.isInspectorOpen, "Inspector Panel is open after iframe nav");
+
+  checksAfterLoads = true;
+
+  InspectorUI.closeInspectorUI();
+}
+
+function finishTest() {
+  Services.obs.removeObserver(finishTest,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
+
+  is(iframeLoads, 2, "iframe loads");
+  ok(checksAfterLoads, "the Inspector tests got the chance to run after iframe reloads");
+  ok(!InspectorUI.isInspectorOpen, "Inspector Panel is not open");
+
+  iframe = null;
+  gBrowser.removeCurrentTab();
+  executeSoon(finish);
+}
+
+function test() {
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
+    waitForFocus(startTest, content);
+  }, true);
+
+  content.location = "data:text/html,<p>bug 699308 - test iframe navigation" +
+    "<iframe src='data:text/html,hello world'></iframe>";
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/highlighter/test/browser_inspector_changes.js
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Inspect Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Camp <dcamp@mozilla.com>
+ *   Rob Campbell <rcampbell@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 ***** */
+let doc;
+let testDiv;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<div id="testdiv">Test div!</div>';
+  doc.title = "Inspector Change Test";
+  startInspectorTests();
+}
+
+
+function getInspectorProp(aName)
+{
+  for each (let view in InspectorUI.stylePanel.cssHtmlTree.propertyViews) {
+    if (view.name == aName) {
+      return view;
+    }
+  }
+  return null;
+}
+
+function startInspectorTests()
+{
+  ok(InspectorUI, "InspectorUI variable exists");
+  Services.obs.addObserver(runInspectorTests,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
+  InspectorUI.toggleInspectorUI();
+}
+
+function runInspectorTests()
+{
+  Services.obs.removeObserver(runInspectorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
+  testDiv = doc.getElementById("testdiv");
+
+  testDiv.style.fontSize = "10px";
+
+  InspectorUI.inspectNode(testDiv);
+  InspectorUI.stopInspecting();
+
+  // Start up the style inspector panel...
+  Services.obs.addObserver(stylePanelTests, "StyleInspector-populated", false);
+
+  executeSoon(function() {
+    InspectorUI.showSidebar();
+    document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
+  });
+}
+
+function stylePanelTests()
+{
+  Services.obs.removeObserver(stylePanelTests, "StyleInspector-populated");
+
+  ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
+  ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
+
+  let propView = getInspectorProp("font-size");
+  is(propView.value, "10px", "Style inspector should be showing the correct font size.");
+
+  Services.obs.addObserver(stylePanelAfterChange, "StyleInspector-populated", false);
+
+  testDiv.style.fontSize = "15px";
+  InspectorUI.nodeChanged();
+}
+
+function stylePanelAfterChange()
+{
+  Services.obs.removeObserver(stylePanelAfterChange, "StyleInspector-populated");
+
+  let propView = getInspectorProp("font-size");
+  is(propView.value, "15px", "Style inspector should be showing the new font size.");
+
+  stylePanelNotActive();
+}
+
+function stylePanelNotActive()
+{
+  // Tests changes made while the style panel is not active.
+  InspectorUI.ruleButton.click();
+  executeSoon(function() {
+    testDiv.style.fontSize = "20px";
+    Services.obs.addObserver(stylePanelAfterSwitch, "StyleInspector-populated", false);
+    document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
+  });
+}
+
+function stylePanelAfterSwitch()
+{
+  Services.obs.removeObserver(stylePanelAfterSwitch, "StyleInspector-populated");
+
+  let propView = getInspectorProp("font-size");
+  is(propView.value, "20px", "Style inspector should be showing the newest font size.");
+
+  Services.obs.addObserver(finishTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
+  executeSoon(function() {
+    InspectorUI.closeInspectorUI(true);
+  });
+}
+
+function finishTest()
+{
+  Services.obs.removeObserver(finishTest,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function() {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,basic tests for inspector";
+}
+
--- a/browser/devtools/highlighter/test/browser_inspector_editor.js
+++ b/browser/devtools/highlighter/test/browser_inspector_editor.js
@@ -29,36 +29,45 @@ function setupEditorTests()
   Services.obs.addObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
   InspectorUI.toggleInspectorUI();
 }
 
 function setupHTMLPanel()
 {
   Services.obs.removeObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
   Services.obs.addObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
-  InspectorUI.treePanel.open();
+  InspectorUI.toolShow(InspectorUI.treePanel.registrationObject);
 }
 
 function runEditorTests()
 {
   Services.obs.removeObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
   InspectorUI.stopInspecting();
+  InspectorUI.inspectNode(doc.body, true);
 
   // setup generator for async test steps
   editorTestSteps = doEditorTestSteps();
 
   // add step listeners
   Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
   Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
   Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
 
   // start the tests
   doNextStep();
 }
 
+function highlighterTrap()
+{
+  // bug 696107
+  Services.obs.removeObserver(highlighterTrap, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
+  ok(false, "Highlighter moved. Shouldn't be here!");
+  finishUp();
+}
+
 function doEditorTestSteps()
 {
   let treePanel = InspectorUI.treePanel;
   let editor = treePanel.treeBrowserDocument.getElementById("attribute-editor");
   let editorInput = treePanel.treeBrowserDocument.getElementById("attribute-editor-input");
 
   // Step 1: grab and test the attribute-value nodes in the HTML panel, then open editor
   let attrValNode_id = treePanel.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='id']")[0];
@@ -73,16 +82,19 @@ function doEditorTestSteps()
     EventUtils.synthesizeMouse(attrValNode_id, 2, 2, {clickCount: 2}, attrValNode_id.ownerDocument.defaultView);
   });
 
   yield; // End of Step 1
 
 
   // Step 2: validate editing session, enter new attribute value into editor, and save input
   ok(InspectorUI.treePanel.editingContext, "Step 2: editor session started");
+  let selection = InspectorUI.selection;
+
+  ok(selection, "Selection is: " + selection);
 
   let editorVisible = editor.classList.contains("editing");
   ok(editorVisible, "editor popup visible");
 
   // check if the editor popup is "near" the correct position
   let editorDims = editor.getBoundingClientRect();
   let attrValNodeDims = attrValNode_id.getBoundingClientRect();
   let editorPositionOK = (editorDims.left >= (attrValNodeDims.left - editorDims.width - 5)) &&
@@ -98,25 +110,32 @@ function doEditorTestSteps()
 
   is(treePanel.editingContext.repObj, div, "editor session has correct reference to div");
   is(treePanel.editingContext.attrObj, attrValNode_id, "editor session has correct reference to `id` attribute-value node in HTML panel");
   is(treePanel.editingContext.attrName, "id", "editor session knows correct attribute-name");
 
   editorInput.value = "Hello World";
   editorInput.focus();
 
-  // hit <enter> to save the inputted value
+  Services.obs.addObserver(highlighterTrap,
+      InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
+
+  // hit <enter> to save the textbox value
   executeSoon(function() {
+    // Extra key to test that keyboard handlers have been removed. bug 696107.
+    EventUtils.synthesizeKey("VK_LEFT", {}, attrValNode_id.ownerDocument.defaultView);
     EventUtils.synthesizeKey("VK_RETURN", {}, attrValNode_id.ownerDocument.defaultView);
   });
 
   // two `yield` statements, to trap both the "SAVED" and "CLOSED" events that will be triggered
   yield;
   yield; // End of Step 2
 
+  // remove this from previous step
+  Services.obs.removeObserver(highlighterTrap, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
 
   // Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value
   ok(!treePanel.editingContext, "Step 3: editor session ended");
   editorVisible = editor.classList.contains("editing");
   ok(!editorVisible, "editor popup hidden");
   attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
   ok(!attrValNodeHighlighted, "`id` attribute-value node is no longer editor-highlighted");
   is(div.getAttribute("id"), "Hello World", "`id` attribute-value successfully updated");
@@ -205,26 +224,24 @@ function doEditorTestSteps()
   // Step 8: validate that the editor was closed and that the editing was not saved
   ok(!treePanel.editingContext, "Step 8: editor session ended");
   editorVisible = editor.classList.contains("editing");
   ok(!editorVisible, "editor popup hidden");
   is(div.getAttribute("id"), "Hello World", "`id` attribute-value *not* updated");
   is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated");
 
   // End of Step 8
+  executeSoon(finishUp);
+}
 
+function finishUp() {
   // end of all steps, so clean up
   Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
   Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
   Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
-
-  executeSoon(finishUp);
-}
-
-function finishUp() {
   doc = div = null;
   InspectorUI.closeInspectorUI();
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
--- a/browser/devtools/highlighter/test/browser_inspector_initialization.js
+++ b/browser/devtools/highlighter/test/browser_inspector_initialization.js
@@ -90,32 +90,44 @@ function treePanelTests()
     InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
   Services.obs.addObserver(stylePanelTests,
     "StyleInspector-opened", false);
 
   ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
 
   executeSoon(function() {
     InspectorUI.showSidebar();
+    document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
   });
 }
 
 function stylePanelTests()
 {
   Services.obs.removeObserver(stylePanelTests, "StyleInspector-opened");
-  Services.obs.addObserver(runContextMenuTest,
-    InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
 
   ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
   ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
 
+  InspectorUI.ruleButton.click();
+  executeSoon(function() {
+    ruleViewTests();
+  });
+}
+
+function ruleViewTests()
+{
+  Services.obs.addObserver(runContextMenuTest,
+      InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
+
+  ok(InspectorUI.isRuleViewOpen(), "Rule View is open");
+  ok(InspectorUI.ruleView, "InspectorUI has a cssRuleView");
+
   executeSoon(function() {
     InspectorUI.closeInspectorUI();
   });
-
 }
 
 function runContextMenuTest()
 {
   Services.obs.removeObserver(runContextMenuTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
   Services.obs.addObserver(inspectNodesFromContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
   salutation = doc.getElementById("salutation");
   ok(salutation, "hello, context menu test!");
@@ -188,16 +200,20 @@ function finishInspectorTests()
 {
   Services.obs.removeObserver(finishInspectorTests,
     InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
 
   ok(!InspectorUI.highlighter, "Highlighter is gone");
   ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
   ok(!InspectorUI.inspecting, "Inspector is not inspecting");
   ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is closed");
+  ok(!InspectorUI.stylePanel, "Inspector Style Panel is gone");
+  ok(!InspectorUI.ruleView, "Inspector Rule View is gone");
+  is(InspectorUI.sidebarToolbar.children.length, 0, "No items in the Sidebar toolbar");
+  is(InspectorUI.sidebarDeck.children.length, 0, "No items in the Sidebar deck");
   ok(!InspectorUI.toolbar, "toolbar is hidden");
 
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
--- a/browser/devtools/highlighter/test/browser_inspector_tab_switch.js
+++ b/browser/devtools/highlighter/test/browser_inspector_tab_switch.js
@@ -57,16 +57,17 @@ function inspectorTabOpen1()
 function inspectorUIOpen1()
 {
   Services.obs.removeObserver(inspectorUIOpen1,
     InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
 
   // Make sure the inspector is open.
   ok(InspectorUI.inspecting, "Inspector is highlighting");
   ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
+  ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
   ok(!InspectorUI.store.isEmpty(), "InspectorUI.store is not empty");
   is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
 
   // Highlight a node.
   div = content.document.getElementsByTagName("div")[0];
   InspectorUI.inspectNode(div);
   is(InspectorUI.selection, div, "selection matches the div element");
 
@@ -83,16 +84,17 @@ function inspectorUIOpen1()
   content.location = "data:text/html,<p>tab 2: the inspector should close now";
 }
 
 function inspectorTabOpen2()
 {
   // Make sure the inspector is closed.
   ok(!InspectorUI.inspecting, "Inspector is not highlighting");
   ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
+  ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
   is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
 
   // Activate the inspector again.
   executeSoon(function() {
     Services.obs.addObserver(inspectorUIOpen2,
       InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
     InspectorUI.openInspectorUI();
   });
@@ -142,30 +144,51 @@ function inspectorOpenTreePanelTab1()
   Services.obs.removeObserver(inspectorOpenTreePanelTab1,
     InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
 
   ok(InspectorUI.inspecting, "Inspector is highlighting");
   ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
   is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
   is(InspectorUI.selection, div, "selection matches the div element");
 
+  Services.obs.addObserver(inspectorSidebarStyleView1, "StyleInspector-opened", false);
+
+  executeSoon(function() {
+    InspectorUI.showSidebar();
+    InspectorUI.toolShow(InspectorUI.stylePanel.registrationObject);
+  });
+}
+
+function inspectorSidebarStyleView1()
+{
+  Services.obs.removeObserver(inspectorSidebarStyleView1, "StyleInspector-opened");
+  ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
+  ok(InspectorUI.stylePanel, "Inspector Has a Style Panel Instance");
+  InspectorUI.sidebarTools.forEach(function(aTool) {
+    let btn = document.getElementById(InspectorUI.getToolbarButtonId(aTool.id));
+    is(btn.hasAttribute("checked"),
+      (aTool == InspectorUI.stylePanel.registrationObject),
+      "Button " + btn.id + " has correct checked attribute");
+  });
+
   // Switch back to tab 2.
   Services.obs.addObserver(inspectorFocusTab2,
     InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
   gBrowser.selectedTab = tab2;
 }
 
 function inspectorFocusTab2()
 {
   Services.obs.removeObserver(inspectorFocusTab2,
     InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
 
   // Make sure the inspector is still open.
   ok(!InspectorUI.inspecting, "Inspector is not highlighting");
   ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
+  ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
   is(InspectorUI.store.length, 2, "Inspector.store.length is 2");
   isnot(InspectorUI.selection, div, "selection does not match the div element");
 
   // Switch back to tab 1.
   Services.obs.addObserver(inspectorSecondFocusTab1,
     InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
   gBrowser.selectedTab = tab1;
 }
@@ -175,30 +198,41 @@ function inspectorSecondFocusTab1()
   Services.obs.removeObserver(inspectorSecondFocusTab1,
     InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
 
   ok(InspectorUI.inspecting, "Inspector is highlighting");
   ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
   is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
   is(InspectorUI.selection, div, "selection matches the div element");
 
+  ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
+  ok(InspectorUI.stylePanel, "Inspector Has a Style Panel Instance");
+  InspectorUI.sidebarTools.forEach(function(aTool) {
+    let btn = document.getElementById(InspectorUI.getToolbarButtonId(aTool.id));
+    is(btn.hasAttribute("checked"),
+      (aTool == InspectorUI.stylePanel.registrationObject),
+      "Button " + btn.id + " has correct checked attribute");
+  });
+
   // Switch back to tab 2.
   Services.obs.addObserver(inspectorSecondFocusTab2,
     InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
   gBrowser.selectedTab = tab2;
 }
 
 function inspectorSecondFocusTab2()
 {
   Services.obs.removeObserver(inspectorSecondFocusTab2,
     InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
 
   // Make sure the inspector is still open.
   ok(!InspectorUI.inspecting, "Inspector is not highlighting");
   ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
+  ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
+
   is(InspectorUI.store.length, 2, "Inspector.store.length is 2");
   isnot(InspectorUI.selection, div, "selection does not match the div element");
 
   // Remove tab 1.
   tab1window = gBrowser.getBrowserForTab(tab1).contentWindow;
   tab1window.addEventListener("pagehide", inspectorTabUnload1, false);
   gBrowser.removeTab(tab1);
 }
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -1,11 +1,11 @@
 browser.jar:
 *   content/browser/inspector.html                (highlighter/inspector.html)
     content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
 *   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
 *   content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
-    content/browser/csshtmltree.xhtml             (styleinspector/csshtmltree.xhtml)
-    content/browser/devtools/cssruleview.xhtml    (styleinspector/cssruleview.xhtml)
+    content/browser/devtools/csshtmltree.xul      (styleinspector/csshtmltree.xul)
+    content/browser/devtools/cssruleview.xul      (styleinspector/cssruleview.xul)
     content/browser/devtools/styleinspector.css   (styleinspector/styleinspector.css)
     content/browser/orion.js                      (sourceeditor/orion/orion.js)
     content/browser/orion.css                     (sourceeditor/orion/orion.css)
     content/browser/orion-mozilla.css             (sourceeditor/orion/mozilla.css)
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -793,16 +793,18 @@ var Scratchpad = {
   /**
    * The popupshowing event handler for the Edit menu. This method updates the
    * enabled/disabled state of the Undo and Redo commands, based on the editor
    * state such that the menu items render correctly for the user when the menu
    * shows.
    */
   onEditPopupShowing: function SP_onEditPopupShowing()
   {
+    goUpdateGlobalEditMenuItems();
+
     let undo = document.getElementById("sp-cmd-undo");
     undo.setAttribute("disabled", !this.editor.canUndo());
 
     let redo = document.getElementById("sp-cmd-redo");
     redo.setAttribute("disabled", !this.editor.canRedo());
   },
 
   /**
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -285,17 +285,18 @@
                 label="&browserContext.label;"
                 accesskey="&browserContext.accesskey;"
                 type="radio"/>
     </menupopup>
   </menu>
 </menubar>
 
 <popupset id="scratchpad-popups">
-  <menupopup id="scratchpad-text-popup">
+  <menupopup id="scratchpad-text-popup"
+             onpopupshowing="goUpdateGlobalEditMenuItems()">
     <menuitem id="menu_cut"/>
     <menuitem id="menu_copy"/>
     <menuitem id="menu_paste"/>
     <menuitem id="menu_delete"/>
     <menuseparator/>
     <menuitem id="menu_selectAll"/>
     <menuseparator/>
     <menuitem id="sp-text-run"
--- a/browser/devtools/scratchpad/test/Makefile.in
+++ b/browser/devtools/scratchpad/test/Makefile.in
@@ -51,11 +51,12 @@ include $(topsrcdir)/config/rules.mk
 		browser_scratchpad_inspect.js \
 		browser_scratchpad_files.js \
 		browser_scratchpad_ui.js \
 		browser_scratchpad_bug_646070_chrome_context_pref.js \
 		browser_scratchpad_bug_660560_tab.js \
 		browser_scratchpad_open.js \
 		browser_scratchpad_restore.js \
 		browser_scratchpad_bug_679467_falsy.js \
+		browser_scratchpad_bug_699130_edit_ui_updates.js \
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_699130_edit_ui_updates.js
@@ -0,0 +1,193 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource:///modules/source-editor.jsm");
+
+// Reference to the Scratchpad chrome window object.
+let gScratchpadWindow;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+
+    gScratchpadWindow = Scratchpad.openScratchpad();
+    gScratchpadWindow.addEventListener("load", function onScratchpadLoad() {
+      gScratchpadWindow.removeEventListener("load", onScratchpadLoad, false);
+      waitForFocus(runTests, gScratchpadWindow);
+    }, false);
+  }, true);
+
+  content.location = "data:text/html,test Edit menu updates Scratchpad - bug 699130";
+}
+
+function runTests()
+{
+  let sp = gScratchpadWindow.Scratchpad;
+  let doc = gScratchpadWindow.document;
+  let winUtils = gScratchpadWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+                 getInterface(Ci.nsIDOMWindowUtils);
+  let OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+
+  info("will test the Edit menu");
+
+  let pass = 0;
+
+  sp.setText("bug 699130: hello world! (edit menu)");
+
+  let editMenu = doc.getElementById("sp-edit-menu");
+  ok(editMenu, "the Edit menu");
+  let menubar = editMenu.parentNode;
+  ok(menubar, "menubar found");
+
+  let editMenuIndex = -1;
+  for (let i = 0; i < menubar.children.length; i++) {
+    if (menubar.children[i] === editMenu) {
+      editMenuIndex = i;
+      break;
+    }
+  }
+  isnot(editMenuIndex, -1, "Edit menu index is correct");
+
+  let menuPopup = editMenu.menupopup;
+  ok(menuPopup, "the Edit menupopup");
+  let cutItem = doc.getElementById("sp-menu-cut");
+  ok(cutItem, "the Cut menuitem");
+  let pasteItem = doc.getElementById("sp-menu-paste");
+  ok(pasteItem, "the Paste menuitem");
+
+  let anchor = doc.documentElement;
+  let isContextMenu = false;
+
+  let openMenu = function(aX, aY, aCallback) {
+    if (!editMenu || OS != "Darwin") {
+      menuPopup.addEventListener("popupshown", function onPopupShown() {
+        menuPopup.removeEventListener("popupshown", onPopupShown, false);
+        executeSoon(aCallback);
+      }, false);
+    }
+
+    executeSoon(function() {
+      if (editMenu) {
+        if (OS == "Darwin") {
+          winUtils.forceUpdateNativeMenuAt(editMenuIndex);
+          executeSoon(aCallback);
+        } else {
+          editMenu.open = true;
+        }
+      } else {
+        menuPopup.openPopup(anchor, "overlap", aX, aY, isContextMenu, false);
+      }
+    });
+  };
+
+  let closeMenu = function(aCallback) {
+    if (!editMenu || OS != "Darwin") {
+      menuPopup.addEventListener("popuphidden", function onPopupHidden() {
+        menuPopup.removeEventListener("popuphidden", onPopupHidden, false);
+        executeSoon(aCallback);
+      }, false);
+    }
+
+    executeSoon(function() {
+      if (editMenu) {
+        if (OS == "Darwin") {
+          winUtils.forceUpdateNativeMenuAt(editMenuIndex);
+          executeSoon(aCallback);
+        } else {
+          editMenu.open = false;
+        }
+      } else {
+        menuPopup.hidePopup();
+      }
+    });
+  };
+
+  let firstShow = function() {
+    ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled");
+    closeMenu(firstHide);
+  };
+
+  let firstHide = function() {
+    sp.selectRange(0, 10);
+    openMenu(11, 11, showAfterSelect);
+  };
+
+  let showAfterSelect = function() {
+    ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled after select");
+    closeMenu(hideAfterSelect);
+  };
+
+  let hideAfterSelect = function() {
+    sp.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onCut);
+    EventUtils.synthesizeKey("x", {accelKey: true}, gScratchpadWindow);
+  };
+
+  let onCut = function() {
+    sp.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onCut);
+    openMenu(12, 12, showAfterCut);
+  };
+
+  let showAfterCut = function() {
+    ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after cut");
+    ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after cut");
+    closeMenu(hideAfterCut);
+  };
+
+  let hideAfterCut = function() {
+    sp.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste);
+    EventUtils.synthesizeKey("v", {accelKey: true}, gScratchpadWindow);
+  };
+
+  let onPaste = function() {
+    sp.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste);
+    openMenu(13, 13, showAfterPaste);
+  };
+
+  let showAfterPaste = function() {
+    ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after paste");
+    ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after paste");
+    closeMenu(hideAfterPaste);
+  };
+
+  let hideAfterPaste = function() {
+    if (pass == 0) {
+      pass++;
+      testContextMenu();
+    } else {
+      finishTest();
+    }
+  };
+
+  let testContextMenu = function() {
+    info("will test the context menu");
+
+    editMenu = null;
+    isContextMenu = true;
+
+    menuPopup = doc.getElementById("scratchpad-text-popup");
+    ok(menuPopup, "the context menupopup");
+    cutItem = doc.getElementById("menu_cut");
+    ok(cutItem, "the Cut menuitem");
+    pasteItem = doc.getElementById("menu_paste");
+    ok(pasteItem, "the Paste menuitem");
+
+    sp.setText("bug 699130: hello world! (context menu)");
+    openMenu(10, 10, firstShow);
+  };
+
+  let finishTest = function() {
+    gScratchpadWindow.close();
+    gScratchpadWindow = null;
+    gBrowser.removeCurrentTab();
+    finish();
+  };
+
+  openMenu(10, 10, firstShow);
+}
--- a/browser/devtools/sourceeditor/orion/README
+++ b/browser/devtools/sourceeditor/orion/README
@@ -17,16 +17,19 @@ Orion version: git clone from 2011-10-26
     https://github.com/mihaisucan/orion.client/tree/bug-362286
       see https://bugs.eclipse.org/bugs/show_bug.cgi?id=362286
   + patch for Eclipse Bug 362107 - Ctrl-Up/Down failure on Linux:
     https://github.com/mihaisucan/orion.client/tree/bug-362107
       see https://bugs.eclipse.org/bugs/show_bug.cgi?id=362107
   + patch for Eclipse Bug 362428 - _getXToOffset() throws:
     https://github.com/mihaisucan/orion.client/tree/bug-362428
       see https://bugs.eclipse.org/bugs/show_bug.cgi?id=362428
+  + patch for Eclipse Bug 362835 - Pasted HTML shows twice:
+    https://github.com/mihaisucan/orion.client/tree/bug-362835
+      see https://bugs.eclipse.org/bugs/show_bug.cgi?id=362835
 
 # License
 
 The following files are licensed according to the contents in the LICENSE
 file:
   orion.js
   orion.css
 
--- a/browser/devtools/sourceeditor/orion/orion.js
+++ b/browser/devtools/sourceeditor/orion/orion.js
@@ -1947,17 +1947,17 @@ if (typeof window !== "undefined" && typ
  * All rights reserved. This program and the accompanying materials are made 
  * available under the terms of the Eclipse Public License v1.0 
  * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
  * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
  * 
  * Contributors: 
  *		Felipe Heidrich (IBM Corporation) - initial API and implementation
  *		Silenio Quarti (IBM Corporation) - initial API and implementation
- *		Mihai Sucan (Mozilla Foundation) - fix for Bug#334583 Bug#348471 Bug#349485 Bug#350595 Bug#360726 Bug#361180 Bug#358623 Bug#362286 Bug#362107 Bug#362428
+ *		Mihai Sucan (Mozilla Foundation) - fix for Bug#334583 Bug#348471 Bug#349485 Bug#350595 Bug#360726 Bug#361180 Bug#358623 Bug#362286 Bug#362107 Bug#362428 Bug#362835
  ******************************************************************************/
 
 /*global window document navigator setTimeout clearTimeout XMLHttpRequest define */
 
 /**
  * @namespace The global container for Orion APIs.
  */ 
 var orion = orion || {};
@@ -5668,17 +5668,20 @@ orion.textview.TextView = (function() {
 					return clipboadText.join("");
 				};
 				
 				/* Try execCommand first. Works on firefox with clipboard permission. */
 				var result = false;
 				this._ignorePaste = true;
 				try {
 					result = document.execCommand("paste", false, null);
-				} catch (ex) {}
+				} catch (ex) {
+					// Firefox can throw even when execCommand() works, see bug 362835
+					result = clipboardDiv.childNodes.length > 1 || clipboardDiv.firstChild && clipboardDiv.firstChild.childNodes.length > 0;
+				}
 				this._ignorePaste = false;
 				if (!result) {
 					/*
 					* Try native paste in DOM, works for firefox during the paste event.
 					*/
 					if (event) {
 						setTimeout(function() {
 							self.focus();
--- a/browser/devtools/sourceeditor/test/browser_bug684862_paste_html.js
+++ b/browser/devtools/sourceeditor/test/browser_bug684862_paste_html.js
@@ -68,26 +68,29 @@ function editorLoaded()
   is(editor.getCaretOffset(), 0, "caret location");
 
   let onPaste = function() {
     editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste);
 
     let text = editor.getText();
     ok(text, "editor has content after paste");
 
-    isnot(text.indexOf("foobarBug684862"), -1, "editor content is correct");
+    let pos = text.indexOf("foobarBug684862");
+    isnot(pos, -1, "editor content is correct");
+    // Test for bug 699541 - Pasted HTML shows twice in Orion.
+    is(text.lastIndexOf("foobarBug684862"), pos, "editor content is correct (no duplicate)");
 
     executeSoon(function() {
       editor.setCaretOffset(4);
       EventUtils.synthesizeKey("a", {}, testWin);
       EventUtils.synthesizeKey("VK_RIGHT", {}, testWin);
 
       text = editor.getText();
 
-      isnot(text.indexOf("foobarBug684862"), -1,
+      is(text.indexOf("foobarBug684862"), pos + 1,
             "editor content is correct after navigation");
       is(editor.getCaretOffset(), 6, "caret location");
 
       executeSoon(testEnd);
     });
   };
 
   editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste);
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -64,28 +64,31 @@ function CssHtmlTree(aStyleInspector)
   this.styleWin = aStyleInspector.iframe;
   this.styleInspector = aStyleInspector;
   this.cssLogic = aStyleInspector.cssLogic;
   this.doc = aStyleInspector.document;
   this.win = aStyleInspector.window;
   this.getRTLAttr = this.win.getComputedStyle(this.win.gBrowser).direction;
   this.propertyViews = [];
 
-  // The document in which we display the results (csshtmltree.xhtml).
+  // The document in which we display the results (csshtmltree.xul).
   this.styleDocument = this.styleWin.contentWindow.document;
 
   // Nodes used in templating
   this.root = this.styleDocument.getElementById("root");
   this.path = this.styleDocument.getElementById("path");
   this.templateRoot = this.styleDocument.getElementById("templateRoot");
   this.templatePath = this.styleDocument.getElementById("templatePath");
   this.propertyContainer = this.styleDocument.getElementById("propertyContainer");
   this.templateProperty = this.styleDocument.getElementById("templateProperty");
   this.panel = aStyleInspector.panel;
 
+  // No results text.
+  this.noResults = this.styleDocument.getElementById("noResults");
+
   // The element that we're inspecting, and the document that it comes from.
   this.viewedElement = null;
   this.createStyleViews();
 }
 
 /**
  * Memoized lookup of a l10n string from a string bundle.
  * @param {string} aName The key to lookup.
@@ -128,112 +131,142 @@ CssHtmlTree.processTemplate = function C
     aDestination.appendChild(duplicated.firstChild);
   }
 };
 
 XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
         .createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
 
 CssHtmlTree.prototype = {
+  // Cache the list of properties that have matched and unmatched properties.
+  _matchedProperties: null,
+  _unmatchedProperties: null,
+
   htmlComplete: false,
 
   // Used for cancelling timeouts in the style filter.
-  filterChangedTimeout: null,
+  _filterChangedTimeout: null,
 
   // The search filter
   searchField: null,
-  
+
   // Reference to the "Only user Styles" checkbox.
   onlyUserStylesCheckbox: null,
 
   // Holds the ID of the panelRefresh timeout.
   _panelRefreshTimeout: null,
 
+  // Toggle for zebra striping
+  _darkStripe: true,
+
+  // Number of visible properties
+  numVisibleProperties: 0,
+
   get showOnlyUserStyles()
   {
     return this.onlyUserStylesCheckbox.checked;
   },
 
   /**
    * Update the highlighted element. The CssHtmlTree panel will show the style
    * information for the given element.
    * @param {nsIDOMElement} aElement The highlighted node to get styles for.
    */
   highlight: function CssHtmlTree_highlight(aElement)
   {
-    if (this.viewedElement == aElement) {
-      return;
-    }
-
     this.viewedElement = aElement;
+    this._unmatchedProperties = null;
+    this._matchedProperties = null;
 
     CssHtmlTree.processTemplate(this.templatePath, this.path, this);
 
     if (this.htmlComplete) {
       this.refreshPanel();
     } else {
+      if (this._panelRefreshTimeout) {
+        this.win.clearTimeout(this._panelRefreshTimeout);
+      }
+
       CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
 
       // We use a setTimeout loop to display the properties in batches of 15 at a
       // time. This results in a perceptibly more responsive UI.
       let i = 0;
       let batchSize = 15;
       let max = CssHtmlTree.propertyNames.length - 1;
       function displayProperties() {
         if (this.viewedElement == aElement && this.styleInspector.isOpen()) {
           // Display the next 15 properties
           for (let step = i + batchSize; i < step && i <= max; i++) {
             let name = CssHtmlTree.propertyNames[i];
             let propView = new PropertyView(this, name);
             CssHtmlTree.processTemplate(this.templateProperty,
               this.propertyContainer, propView, true);
-            propView.refreshMatchedSelectors();
-            propView.refreshUnmatchedSelectors();
+            if (propView.visible) {
+              this.numVisibleProperties++;
+            }
+            propView.refreshAllSelectors();
             this.propertyViews.push(propView);
           }
           if (i < max) {
             // There are still some properties to display. We loop here to display
             // the next batch of 15.
-            this.win.setTimeout(displayProperties.bind(this), 50);
+            this._panelRefreshTimeout =
+              this.win.setTimeout(displayProperties.bind(this), 15);
           } else {
             this.htmlComplete = true;
+            this._panelRefreshTimeout = null;
+            this.noResults.hidden = this.numVisibleProperties > 0;
             Services.obs.notifyObservers(null, "StyleInspector-populated", null);
           }
         }
       }
-      this.win.setTimeout(displayProperties.bind(this), 50);
+      this._panelRefreshTimeout =
+        this.win.setTimeout(displayProperties.bind(this), 15);
     }
   },
 
   /**
    * Refresh the panel content.
    */
   refreshPanel: function CssHtmlTree_refreshPanel()
   {
-    this.win.clearTimeout(this._panelRefreshTimeout);
+    if (this._panelRefreshTimeout) {
+      this.win.clearTimeout(this._panelRefreshTimeout);
+    }
+
+    this.noResults.hidden = true;
+
+    // Reset visible property count
+    this.numVisibleProperties = 0;
+
+    // Reset zebra striping.
+    this._darkStripe = true;
 
     // We use a setTimeout loop to display the properties in batches of 15 at a
     // time. This results in a perceptibly more responsive UI.
     let i = 0;
     let batchSize = 15;
     let max = this.propertyViews.length - 1;
     function refreshView() {
       // Refresh the next 15 property views
       for (let step = i + batchSize; i < step && i <= max; i++) {
         this.propertyViews[i].refresh();
       }
       if (i < max) {
         // There are still some property views to refresh. We loop here to
         // display the next batch of 15.
-        this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 0);
+        this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
       } else {
+        this._panelRefreshTimeout = null;
+        this.noResults.hidden = this.numVisibleProperties > 0;
         Services.obs.notifyObservers(null, "StyleInspector-populated", null);
       }
     }
-    this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 0);
+    this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
   },
 
   /**
    * Called when the user clicks on a parent element in the "current element"
    * path.
    *
    * @param {Event} aEvent the DOM Event object.
    */
@@ -249,37 +282,38 @@ CssHtmlTree.prototype = {
    * Called when the user enters a search term.
    *
    * @param {Event} aEvent the DOM Event object.
    */
   filterChanged: function CssHtmlTree_filterChanged(aEvent)
   {
     let win = this.styleWin.contentWindow;
 
-    if (this.filterChangedTimeout) {
-      win.clearTimeout(this.filterChangedTimeout);
-      this.filterChangeTimeout = null;
+    if (this._filterChangedTimeout) {
+      win.clearTimeout(this._filterChangedTimeout);
     }
 
-    this.filterChangedTimeout = win.setTimeout(function() {
+    this._filterChangedTimeout = win.setTimeout(function() {
       this.refreshPanel();
+      this._filterChangeTimeout = null;
     }.bind(this), FILTER_CHANGED_TIMEOUT);
   },
 
   /**
    * The change event handler for the onlyUserStyles checkbox. When
    * onlyUserStyles.checked is true we do not display properties that have no
    * matched selectors, and we do not display UA styles. If .checked is false we
    * do display even properties with no matched selectors, and we include the UA
    * styles.
    *
    * @param {Event} aEvent the DOM Event object.
    */
   onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
   {
+    this._matchedProperties = null;
     this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
                                  CssLogic.FILTER.ALL :
                                  CssLogic.FILTER.UA;
     this.refreshPanel();
   },
 
   /**
    * Provide access to the path to get from document.body to the selected
@@ -300,50 +334,104 @@ CssHtmlTree.prototype = {
   {
     if (CssHtmlTree.propertyNames) {
       return;
     }
 
     CssHtmlTree.propertyNames = [];
 
     // Here we build and cache a list of css properties supported by the browser
-    // We could use any element but let's use the main document's body
-    let styles = this.styleWin.contentWindow.getComputedStyle(this.styleDocument.body);
+    // We could use any element but let's use the main document's root element
+    let styles = this.styleWin.contentWindow.getComputedStyle(this.styleDocument.documentElement);
     let mozProps = [];
     for (let i = 0, numStyles = styles.length; i < numStyles; i++) {
       let prop = styles.item(i);
       if (prop.charAt(0) == "-") {
         mozProps.push(prop);
       } else {
         CssHtmlTree.propertyNames.push(prop);
       }
     }
 
     CssHtmlTree.propertyNames.sort();
     CssHtmlTree.propertyNames.push.apply(CssHtmlTree.propertyNames,
       mozProps.sort());
   },
 
   /**
+   * Get a list of properties that have matched selectors.
+   *
+   * @return {object} the object maps property names (keys) to booleans (values)
+   * that tell if the given property has matched selectors or not.
+   */
+  get matchedProperties()
+  {
+    if (!this._matchedProperties) {
+      this._matchedProperties =
+        this.cssLogic.hasMatchedSelectors(CssHtmlTree.propertyNames);
+    }
+    return this._matchedProperties;
+  },
+
+  /**
+   * Check if a property has unmatched selectors. Result is cached.
+   *
+   * @param {string} aProperty the name of the property you want to check.
+   * @return {boolean} true if the property has unmatched selectors, false
+   * otherwise.
+   */
+  hasUnmatchedSelectors: function CssHtmlTree_hasUnmatchedSelectors(aProperty)
+  {
+    // Initially check all of the properties that return false for
+    // hasMatchedSelectors(). This speeds-up the UI.
+    if (!this._unmatchedProperties) {
+      let properties = [];
+      CssHtmlTree.propertyNames.forEach(function(aName) {
+        if (!this.matchedProperties[aName]) {
+          properties.push(aName);
+        }
+      }, this);
+
+      if (properties.indexOf(aProperty) == -1) {
+        properties.push(aProperty);
+      }
+
+      this._unmatchedProperties = this.cssLogic.hasUnmatchedSelectors(properties);
+    }
+
+    // Lazy-get the result for properties we do not have cached.
+    if (!(aProperty in this._unmatchedProperties)) {
+      let result = this.cssLogic.hasUnmatchedSelectors([aProperty]);
+      this._unmatchedProperties[aProperty] = result[aProperty];
+    }
+
+    return this._unmatchedProperties[aProperty];
+  },
+
+  /**
    * Destructor for CssHtmlTree.
    */
   destroy: function CssHtmlTree_destroy()
   {
     delete this.viewedElement;
 
+    // Remove event listeners
+    this.onlyUserStylesCheckbox.removeEventListener("command",
+      this.onlyUserStylesChanged);
+    this.searchField.removeEventListener("command", this.filterChanged);
+
     // Nodes used in templating
     delete this.root;
     delete this.path;
-    delete this.templateRoot;
     delete this.templatePath;
     delete this.propertyContainer;
     delete this.templateProperty;
     delete this.panel;
 
-    // The document in which we display the results (csshtmltree.xhtml).
+    // The document in which we display the results (csshtmltree.xul).
     delete this.styleDocument;
 
     // The element that we're inspecting, and the document that it comes from.
     delete this.propertyViews;
     delete this.styleWin;
     delete this.cssLogic;
     delete this.doc;
     delete this.win;
@@ -363,55 +451,51 @@ function PropertyView(aTree, aName)
 {
   this.tree = aTree;
   this.name = aName;
   this.getRTLAttr = aTree.getRTLAttr;
 
   this.link = "https://developer.mozilla.org/en/CSS/" + aName;
 
   this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors");
-  this.templateUnmatchedSelectors = aTree.styleDocument.getElementById("templateUnmatchedSelectors");
 }
 
 PropertyView.prototype = {
   // The parent element which contains the open attribute
   element: null,
 
+  // Property header node
+  propertyHeader: null,
+
   // Destination for property values
   valueNode: null,
 
   // Are matched rules expanded?
   matchedExpanded: false,
 
   // Are unmatched rules expanded?
   unmatchedExpanded: false,
 
+  // Unmatched selector table
+  unmatchedSelectorTable: null,
+
   // Matched selector container
   matchedSelectorsContainer: null,
 
-  // Unmatched selector container
-  unmatchedSelectorsContainer: null,
-
   // Matched selector expando
   matchedExpander: null,
 
   // Unmatched selector expando
   unmatchedExpander: null,
 
-  // Container for X matched selectors
-  matchedSelectorsTitleNode: null,
-
-  // Container for X unmatched selectors
-  unmatchedSelectorsTitleNode: null,
+  // Unmatched selector container
+  unmatchedSelectorsContainer: null,
 
-  // Matched selectors table
-  matchedSelectorTable: null,
-
-  // Unmatched selectors table
-  unmatchedSelectorTable: null,
+  // Unmatched title block
+  unmatchedTitleBlock: null,
 
   // Cache for matched selector views
   _matchedSelectorViews: null,
 
   // Cache for unmatched selector views
   _unmatchedSelectorViews: null,
 
   // The previously selected element used for the selector view caches
@@ -436,25 +520,25 @@ PropertyView.prototype = {
     return this.tree.cssLogic.getPropertyInfo(this.name);
   },
 
   /**
    * Does the property have any matched selectors?
    */
   get hasMatchedSelectors()
   {
-    return this.propertyInfo.hasMatchedSelectors();
+    return this.name in this.tree.matchedProperties;
   },
 
   /**
    * Does the property have any unmatched selectors?
    */
   get hasUnmatchedSelectors()
   {
-    return this.propertyInfo.hasUnmatchedSelectors();
+    return this.name in this.tree.hasUnmatchedSelectors;
   },
 
   /**
    * Should this property be visible?
    */
   get visible()
   {
     if (this.tree.showOnlyUserStyles && !this.hasMatchedSelectors) {
@@ -467,20 +551,28 @@ PropertyView.prototype = {
       return false;
     }
 
     return true;
   },
 
   /**
    * Returns the className that should be assigned to the propertyView.
+   *
+   * @return string
    */
   get className()
   {
-    return this.visible ? "property-view" : "property-view-hidden";
+    if (this.visible) {
+      this.tree._darkStripe = !this.tree._darkStripe;
+      let darkValue = this.tree._darkStripe ?
+                      "property-view darkrow" : "property-view";
+      return darkValue;
+    }
+    return "property-view-hidden";
   },
 
   /**
    * Refresh the panel's CSS property value.
    */
   refresh: function PropertyView_refresh()
   {
     this.element.className = this.className;
@@ -489,67 +581,96 @@ PropertyView.prototype = {
       this._matchedSelectorViews = null;
       this._unmatchedSelectorViews = null;
       this.prevViewedElement = this.tree.viewedElement;
     }
 
     if (!this.tree.viewedElement || !this.visible) {
       this.valueNode.innerHTML = "";
       this.matchedSelectorsContainer.hidden = true;
-      this.unmatchedSelectorsContainer.hidden = true;
-      this.matchedSelectorTable.innerHTML = "";
-      this.unmatchedSelectorTable.innerHTML = "";
+      this.matchedSelectorsContainer.innerHTML = "";
       this.matchedExpander.removeAttribute("open");
-      this.unmatchedExpander.removeAttribute("open");
       return;
     }
 
+    this.tree.numVisibleProperties++;
     this.valueNode.innerHTML = this.propertyInfo.value;
-    
-    this.refreshMatchedSelectors();
-    this.refreshUnmatchedSelectors();
+    this.refreshAllSelectors();
   },
 
   /**
    * Refresh the panel matched rules.
    */
   refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
   {
     let hasMatchedSelectors = this.hasMatchedSelectors;
     this.matchedSelectorsContainer.hidden = !hasMatchedSelectors;
 
+    if (hasMatchedSelectors) {
+      this.propertyHeader.classList.add("expandable");
+    } else {
+      this.propertyHeader.classList.remove("expandable");
+    }
+
     if (this.matchedExpanded && hasMatchedSelectors) {
       CssHtmlTree.processTemplate(this.templateMatchedSelectors,
-        this.matchedSelectorTable, this);
+        this.matchedSelectorsContainer, this);
       this.matchedExpander.setAttribute("open", "");
     } else {
-      this.matchedSelectorTable.innerHTML = "";
+      this.matchedSelectorsContainer.innerHTML = "";
       this.matchedExpander.removeAttribute("open");
     }
   },
 
   /**
    * Refresh the panel unmatched rules.
    */
   refreshUnmatchedSelectors: function PropertyView_refreshUnmatchedSelectors()
   {
-    let hasUnmatchedSelectors = this.hasUnmatchedSelectors;
-    this.unmatchedSelectorsContainer.hidden = !hasUnmatchedSelectors;
+    let hasMatchedSelectors = this.hasMatchedSelectors;
+
+    this.unmatchedSelectorTable.hidden = !this.unmatchedExpanded;
 
-    if (this.unmatchedExpanded && hasUnmatchedSelectors) {
+    if (hasMatchedSelectors) {
+      this.unmatchedSelectorsContainer.hidden = !this.matchedExpanded ||
+        !this.hasUnmatchedSelectors;
+      this.unmatchedTitleBlock.hidden = false;
+    } else {
+      this.unmatchedSelectorsContainer.hidden = !this.unmatchedExpanded;
+      this.unmatchedTitleBlock.hidden = true;
+    }
+
+    if (this.unmatchedExpanded && this.hasUnmatchedSelectors) {
       CssHtmlTree.processTemplate(this.templateUnmatchedSelectors,
-          this.unmatchedSelectorTable, this);
-      this.unmatchedExpander.setAttribute("open", "");
+        this.unmatchedSelectorTable, this);
+      if (!hasMatchedSelectors) {
+        this.matchedExpander.setAttribute("open", "");
+        this.unmatchedSelectorTable.classList.add("only-unmatched");
+      } else {
+        this.unmatchedExpander.setAttribute("open", "");
+        this.unmatchedSelectorTable.classList.remove("only-unmatched");
+      }
     } else {
-      this.unmatchedSelectorTable.innerHTML = "";
+      if (!hasMatchedSelectors) {
+        this.matchedExpander.removeAttribute("open");
+      }
       this.unmatchedExpander.removeAttribute("open");
+      this.unmatchedSelectorTable.innerHTML = "";
     }
   },
 
   /**
+   * Refresh the panel matched and unmatched rules
+   */
+  refreshAllSelectors: function PropertyView_refreshAllSelectors()
+  {
+    this.refreshMatchedSelectors();
+  },
+
+  /**
    * Provide access to the matched SelectorViews that we are currently
    * displaying.
    */
   get matchedSelectorViews()
   {
     if (!this._matchedSelectorViews) {
       this._matchedSelectorViews = [];
       this.propertyInfo.matchedSelectors.forEach(
@@ -575,33 +696,48 @@ PropertyView.prototype = {
         }, this);
     }
 
     return this._unmatchedSelectorViews;
   },
 
   /**
    * The action when a user expands matched selectors.
+   *
+   * @param {Event} aEvent Used to determine the class name of the targets click
+   * event. If the class name is "helplink" then the event is allowed to bubble
+   * to the mdn link icon.
    */
-  matchedSelectorsClick: function PropertyView_matchedSelectorsClick(aEvent)
+  propertyHeaderClick: function PropertyView_propertyHeaderClick(aEvent)
   {
-    this.matchedExpanded = !this.matchedExpanded;
-    this.refreshMatchedSelectors();
-    aEvent.preventDefault();
+    if (aEvent.target.className != "helplink") {
+      this.matchedExpanded = !this.matchedExpanded;
+      this.refreshAllSelectors();
+      aEvent.preventDefault();
+    }
   },
 
   /**
    * The action when a user expands unmatched selectors.
    */
   unmatchedSelectorsClick: function PropertyView_unmatchedSelectorsClick(aEvent)
   {
     this.unmatchedExpanded = !this.unmatchedExpanded;
     this.refreshUnmatchedSelectors();
     aEvent.preventDefault();
   },
+
+  /**
+   * The action when a user clicks on the MDN help link for a property.
+   */
+  mdnLinkClick: function PropertyView_mdnLinkClick(aEvent)
+  {
+    this.tree.win.openUILinkIn(this.link, "tab");
+    aEvent.preventDefault();
+  },
 };
 
 /**
  * A container to view us easy access to display data from a CssRule
  * @param CssHtmlTree aTree, the owning CssHtmlTree
  * @param aSelectorInfo
  */
 function SelectorView(aTree, aSelectorInfo)
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -146,31 +146,33 @@ CssLogic.prototype = {
   // Used for tracking unique CssSheet/CssRule/CssSelector objects, in a run of
   // processMatchedSelectors().
   _passId: 0,
 
   // Used for tracking matched CssSelector objects, such that we can skip them
   // in processUnmatchedSelectors().
   _matchId: 0,
 
+  _matchedRules: null,
   _matchedSelectors: null,
   _unmatchedSelectors: null,
 
   domUtils: Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils),
 
   /**
    * Reset various properties
    */
   reset: function CssLogic_reset()
   {
     this._propertyInfos = {};
     this._ruleCount = 0;
     this._sheetIndex = 0;
     this._sheets = {};
     this._sheetsCached = false;
+    this._matchedRules = null;
     this._matchedSelectors = null;
     this._unmatchedSelectors = null;
   },
 
   /**
    * Focus on a new element - remove the style caches.
    *
    * @param {nsIDOMElement} aViewedElement the element the user has highlighted
@@ -195,16 +197,17 @@ CssLogic.prototype = {
 
       // Hunt down top level stylesheets, and cache them.
       this._cacheSheets();
     } else {
       // Clear cached data in the CssPropertyInfo objects.
       this._propertyInfos = {};
     }
 
+    this._matchedRules = null;
     this._matchedSelectors = null;
     this._unmatchedSelectors = null;
     let win = this.viewedDocument.defaultView;
     this._computedStyle = win.getComputedStyle(this.viewedElement, "");
   },
 
   /**
    * Get the source filter.
@@ -237,16 +240,17 @@ CssLogic.prototype = {
     this._ruleCount = ruleCount;
 
     // Full update is needed because the this.processMatchedSelectors() method
     // skips UA stylesheets if the filter does not allow such sheets.
     let needFullUpdate = (oldValue == CssLogic.FILTER.UA ||
         aValue == CssLogic.FILTER.UA);
 
     if (needFullUpdate) {
+      this._matchedRules = null;
       this._matchedSelectors = null;
       this._unmatchedSelectors = null;
       this._propertyInfos = {};
     } else {
       // Update the CssPropertyInfo objects.
       for each (let propertyInfo in this._propertyInfos) {
         propertyInfo.needRefilter = true;
       }
@@ -284,17 +288,17 @@ CssLogic.prototype = {
   _cacheSheets: function CssLogic_cacheSheets()
   {
     this._passId++;
     this.reset();
 
     // styleSheets isn't an array, but forEach can work on it anyway
     Array.prototype.forEach.call(this.viewedDocument.styleSheets,
         this._cacheSheet, this);
-    
+
     this._sheetsCached = true;
   },
 
   /**
    * Cache a stylesheet if it falls within the requirements: if it's enabled,
    * and if the @media is allowed. This method also walks through the stylesheet
    * cssRules to find @imported rules, to cache the stylesheets of those rules
    * as well.
@@ -304,29 +308,29 @@ CssLogic.prototype = {
    */
   _cacheSheet: function CssLogic_cacheSheet(aDomSheet)
   {
     if (aDomSheet.disabled) {
       return;
     }
 
     // Only work with stylesheets that have their media allowed.
-    if (!CssLogic.sheetMediaAllowed(aDomSheet)) {
+    if (!this.mediaMatches(aDomSheet)) {
       return;
     }
 
     // Cache the sheet.
-    let cssSheet = this.getSheet(aDomSheet, false, this._sheetIndex++);
+    let cssSheet = this.getSheet(aDomSheet, this._sheetIndex++);
     if (cssSheet._passId != this._passId) {
       cssSheet._passId = this._passId;
 
       // Find import rules.
       Array.prototype.forEach.call(aDomSheet.cssRules, function(aDomRule) {
         if (aDomRule.type == Ci.nsIDOMCSSRule.IMPORT_RULE && aDomRule.styleSheet &&
-            CssLogic.sheetMediaAllowed(aDomRule)) {
+            this.mediaMatches(aDomRule)) {
           this._cacheSheet(aDomRule.styleSheet);
         }
       }, this);
     }
   },
 
   /**
    * Retrieve the list of stylesheets in the document.
@@ -350,53 +354,53 @@ CssLogic.prototype = {
   },
 
   /**
    * Retrieve a CssSheet object for a given a CSSStyleSheet object. If the
    * stylesheet is already cached, you get the existing CssSheet object,
    * otherwise the new CSSStyleSheet object is cached.
    *
    * @param {CSSStyleSheet} aDomSheet the CSSStyleSheet object you want.
-   * @param {boolean} aSystemSheet tells if the stylesheet is a browser-provided
-   * sheet or not.
    * @param {number} aIndex the index, within the document, of the stylesheet.
    *
    * @return {CssSheet} the CssSheet object for the given CSSStyleSheet object.
    */
-  getSheet: function CL_getSheet(aDomSheet, aSystemSheet, aIndex)
+  getSheet: function CL_getSheet(aDomSheet, aIndex)
   {
-    let cacheId = aSystemSheet ? "1" : "0";
+    let cacheId = "";
 
     if (aDomSheet.href) {
-      cacheId += aDomSheet.href;
+      cacheId = aDomSheet.href;
     } else if (aDomSheet.ownerNode && aDomSheet.ownerNode.ownerDocument) {
-      cacheId += aDomSheet.ownerNode.ownerDocument.location;
+      cacheId = aDomSheet.ownerNode.ownerDocument.location;
     }
 
     let sheet = null;
     let sheetFound = false;
 
     if (cacheId in this._sheets) {
       for (let i = 0, numSheets = this._sheets[cacheId].length; i < numSheets; i++) {
         sheet = this._sheets[cacheId][i];
-        if (sheet.domSheet == aDomSheet) {
-          sheet.index = aIndex;
+        if (sheet.domSheet === aDomSheet) {
+          if (aIndex != -1) {
+            sheet.index = aIndex;
+          }
           sheetFound = true;
           break;
         }
       }
     }
 
     if (!sheetFound) {
       if (!(cacheId in this._sheets)) {
         this._sheets[cacheId] = [];
       }
 
-      sheet = new CssSheet(this, aDomSheet, aSystemSheet, aIndex);
-      if (sheet.sheetAllowed && !aSystemSheet) {
+      sheet = new CssSheet(this, aDomSheet, aIndex);
+      if (sheet.sheetAllowed && !sheet.systemSheet) {
         this._ruleCount += sheet.ruleCount;
       }
 
       this._sheets[cacheId].push(sheet);
     }
 
     return sheet;
   },
@@ -481,219 +485,314 @@ CssLogic.prototype = {
         this._matchedSelectors.forEach(function(aValue) {
           aCallback.call(aScope, aValue[0], aValue[1]);
           aValue[0]._cssRule._passId = this._passId;
         }, this);
       }
       return;
     }
 
+    if (!this._matchedRules) {
+      this._buildMatchedRules();
+    }
+
     this._matchedSelectors = [];
     this._unmatchedSelectors = null;
     this._passId++;
-    this._matchId++;
 
-    let element = this.viewedElement;
-    let filter = this.sourceFilter;
-    let sheetIndex = 0;
-    let domRules = null;
-    do {
-      try {
-        domRules = this.domUtils.getCSSStyleRules(element);
-      } catch (ex) {
-        Services.console.
-            logStringMessage("CssLogic_processMatchedSelectors error: " + ex);
-        continue;
-      }
+    for (let i = 0; i < this._matchedRules.length; i++) {
+      let rule = this._matchedRules[i][0];
+      let status = this._matchedRules[i][1];
 
-      let status = (this.viewedElement == element) ?
-          CssLogic.STATUS.MATCHED : CssLogic.STATUS.PARENT_MATCH;
-
-      for (let i = 0, numRules = domRules.Count(); i < numRules; i++) {
-        let domRule = domRules.GetElementAt(i);
-        if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
-          continue;
+      rule.selectors.forEach(function (aSelector) {
+        if (aSelector._matchId !== this._matchId &&
+            (aSelector.elementStyle ||
+             this._selectorMatchesElement(aSelector))) {
+          aSelector._matchId = this._matchId;
+          this._matchedSelectors.push([ aSelector, status ]);
+          if (aCallback) {
+            aCallback.call(aScope, aSelector, status);
+          }
         }
-
-        let domSheet = domRule.parentStyleSheet;
-        let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
-        if (filter !== CssLogic.FILTER.UA && systemSheet) {
-          continue;
-        }
-
-        let sheet = this.getSheet(domSheet, systemSheet, sheetIndex);
-        let rule = sheet.getRule(domRule);
+      }, this);
 
-        rule.selectors.forEach(function (aSelector) {
-          if (aSelector._matchId !== this._matchId &&
-              element.mozMatchesSelector(aSelector)) {
-            aSelector._matchId = this._matchId;
-            this._matchedSelectors.push([ aSelector, status ]);
-            if (aCallback) {
-              aCallback.call(aScope, aSelector, status);
-            }
-          }
-        }, this);
-
-        if (sheet._passId !== this._passId) {
-          sheetIndex++;
-          sheet._passId = this._passId;
-        }
+      rule._passId = this._passId;
+    }
+  },
 
-        if (rule._passId !== this._passId) {
-          rule._passId = this._passId;
-        }
-      }
-
-      // Add element.style information.
-      if (element.style.length > 0) {
-        let rule = new CssRule(null, { style: element.style }, element);
-        let selector = rule.selectors[0];
-        selector._matchId = this._matchId;
-
-        this._matchedSelectors.push([ selector, status ]);
-        if (aCallback) {
-          aCallback.call(aScope, selector, status);
-        }
-        rule._passId = this._passId;
+  /**
+   * Check if the given selector matches the highlighted element or any of its
+   * parents.
+   *
+   * @private
+   * @param {string} aSelector the selector string you want to check.
+   * @return {boolean} true if the given selector matches the highlighted
+   * element or any of its parents, otherwise false is returned.
+   */
+  _selectorMatchesElement: function CL__selectorMatchesElement(aSelector)
+  {
+    let element = this.viewedElement;
+    do {
+      if (element.mozMatchesSelector(aSelector)) {
+        return true;
       }
     } while ((element = element.parentNode) &&
-        element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
+             element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
+
+    return false;
   },
 
   /**
    * Process the CssSelector object that do not match the highlighted elements,
    * nor its parents. Your callback function is invoked for every such
    * CssSelector object. You receive one argument: the CssSelector object.
    *
    * The list of unmatched selectors is cached.
    *
    * @param {function} aCallback the function you want to execute for each of
    * the unmatched selectors.
    * @param {object} aScope the scope you want for the callback function. aScope
    * will be the this object when aCallback executes.
    */
   processUnmatchedSelectors: function CL_processUnmatchedSelectors(aCallback, aScope)
   {
-    if (!this._matchedSelectors) {
-      this.processMatchedSelectors();
-    }
     if (this._unmatchedSelectors) {
       if (aCallback) {
         this._unmatchedSelectors.forEach(aCallback, aScope);
       }
       return;
     }
 
+    if (!this._matchedSelectors) {
+      this.processMatchedSelectors();
+    }
+
     this._unmatchedSelectors = [];
 
     this.forEachSheet(function (aSheet) {
       // We do not show unmatched selectors from system stylesheets
-      if (aSheet.systemSheet) {
+      if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
         return;
       }
 
       aSheet.forEachRule(function (aRule) {
         aRule.selectors.forEach(function (aSelector) {
-          if (aSelector._matchId != this._matchId) {
+          if (aSelector._matchId !== this._matchId) {
             this._unmatchedSelectors.push(aSelector);
             if (aCallback) {
               aCallback.call(aScope, aSelector);
             }
           }
         }, this);
       }, this);
     }, this);
   },
 
   /**
    * Check if the highlighted element or it's parents have matched selectors.
    *
-   * @param {function} [aCallback] Simple callback method. If aCallback is
-   * provided then the domRules for each element in the loop are passed to
-   * the callback function. When the element has .style properties, the callback
-   * receives {style: element.style}. If the callback returns true then the
-   * element has matched rules, otherwise not.
-   * @return {Boolean} true if the current element or it's parents have
-   * matching CssSelector objects, false otherwise
+   * @param {array} aProperties The list of properties you want to check if they
+   * have matched selectors or not.
+   * @return {object} An object that tells for each property if it has matched
+   * selectors or not. Object keys are property names and values are booleans.
    */
-  hasMatchedSelectors: function CL_hasMatchedSelectors(aCallback)
+  hasMatchedSelectors: function CL_hasMatchedSelectors(aProperties)
+  {
+    if (!this._matchedRules) {
+      this._buildMatchedRules();
+    }
+
+    let result = {};
+
+    this._matchedRules.some(function(aValue) {
+      let rule = aValue[0];
+      aProperties = aProperties.filter(function(aProperty) {
+        if (rule.getPropertyValue(aProperty)) {
+          // We just need to find if a rule has this property while it matches
+          // the viewedElement (or its parents).
+          result[aProperty] = true;
+          return false;
+        }
+        return true; // Keep the property for the next rule.
+      });
+      return aProperties.length == 0;
+    }, this);
+
+    return result;
+  },
+
+  /**
+   * Build the array of matched rules for the currently highlighted element.
+   * The array will hold rules that match the viewedElement and its parents.
+   *
+   * @private
+   */
+  _buildMatchedRules: function CL__buildMatchedRules()
   {
     let domRules;
     let element = this.viewedElement;
-    let matched = false;
+    let filter = this.sourceFilter;
+    let sheetIndex = 0;
+
+    this._matchId++;
+    this._passId++;
+    this._matchedRules = [];
 
     do {
+      let status = this.viewedElement === element ?
+                   CssLogic.STATUS.MATCHED : CssLogic.STATUS.PARENT_MATCH;
+
       try {
         domRules = this.domUtils.getCSSStyleRules(element);
       } catch (ex) {
         Services.console.
-            logStringMessage("CssLogic_hasMatchedSelectors error: " + ex);
+          logStringMessage("CL__buildMatchedRules error: " + ex);
         continue;
       }
 
-      // Check if the are DOM rules that we can consider as matched rules
-      // (depending on the callback).
-      if (domRules.Count() && (!aCallback || aCallback(domRules))) {
-        matched = true;
+      for (let i = 0, n = domRules.Count(); i < n; i++) {
+        let domRule = domRules.GetElementAt(i);
+        if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
+          continue;
+        }
+
+        let sheet = this.getSheet(domRule.parentStyleSheet, -1);
+        if (sheet._passId !== this._passId) {
+          sheet.index = sheetIndex++;
+          sheet._passId = this._passId;
+        }
+
+        if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) {
+          continue;
+        }
+
+        let rule = sheet.getRule(domRule);
+        if (rule._passId === this._passId) {
+          continue;
+        }
+
+        rule._matchId = this._matchId;
+        rule._passId = this._passId;
+        this._matchedRules.push([rule, status]);
       }
 
-      // Check if the element has any element.style properties that we can
-      // consider as "matched" (depending on the callback).
-      if (element.style.length > 0 &&
-          (!aCallback || aCallback({style: element.style}))) {
-        matched = true;
-      }
 
-      if (matched) {
-        break;
+      // Add element.style information.
+      if (element.style.length > 0) {
+        let rule = new CssRule(null, { style: element.style }, element);
+        rule._matchId = this._matchId;
+        rule._passId = this._passId;
+        this._matchedRules.push([rule, status]);
       }
     } while ((element = element.parentNode) &&
-        element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
-
-    return matched;
+              element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
   },
 
   /**
    * Check if the highlighted element or it's parents have unmatched selectors.
    *
-   * @param {String} aProperty The CSS property to check against
-   * @return {Boolean} true if the current element or it's parents have
-   * unmatched CssSelector objects, false otherwise
+   * Please note that this method is far slower than hasMatchedSelectors()
+   * because it needs to do a lot more checks in the DOM.
+   *
+   * @param {array} aProperties The list of properties you want to check if they
+   * have unmatched selectors or not.
+   * @return {object} An object that tells for each property if it has unmatched
+   * selectors or not. Object keys are property names and values are booleans.
    */
-  hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperty)
+  hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperties)
   {
-    return this.forSomeSheets(function (aSheet) {
-      // We do not show unmatched selectors from system stylesheets
-      if (aSheet.systemSheet) {
+    if (!this._matchedRules) {
+      this._buildMatchedRules();
+    }
+
+    let result = {};
+
+    this.forSomeSheets(function (aSheet) {
+      if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
         return false;
       }
 
       return aSheet.forSomeRules(function (aRule) {
-        if (aRule.getPropertyValue(aProperty)) {
-          let element = this.viewedElement;
-          let selectorText = aRule._domRule.selectorText;
-          let matches = false;
+        let unmatched = aRule._matchId !== this._matchId ||
+                        this._ruleHasUnmatchedSelector(aRule);
+        if (!unmatched) {
+          return false;
+        }
 
-          do {
-            if (element.mozMatchesSelector(selectorText)) {
-              matches = true;
-              break;
-            }
-          } while ((element = element.parentNode) &&
-                   element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
-
-          if (!matches) {
-            // Now we know that there are rules but none match.
+        aProperties = aProperties.filter(function(aProperty) {
+          if (!aRule.getPropertyValue(aProperty)) {
+            // Keep this property for the next rule. We need to find a rule
+            // which has the property.
             return true;
           }
-        }
+
+          result[aProperty] = true;
+
+          // We found a rule that has the current property while it does not
+          // match the current element. We can remove this property from the
+          // array.
+          return false;
+        });
+
+        return aProperties.length == 0;
       }, this);
     }, this);
+
+    aProperties.forEach(function(aProperty) { result[aProperty] = false; });
+
+    return result;
   },
+
+  /**
+   * Check if a CssRule has an unmatched selector for the highlighted element or
+   * its parents.
+   *
+   * @private
+   * @param {CssRule} aRule The rule you want to check if it has an unmatched
+   * selector.
+   * @return {boolean} True if the rule has an unmatched selector, false
+   * otherwise.
+   */
+  _ruleHasUnmatchedSelector: function CL__ruleHasUnmatchedSelector(aRule)
+  {
+    if (!aRule._cssSheet && aRule.sourceElement) {
+      // CssRule wraps element.style, which never has unmatched selectors.
+      return false;
+    }
+
+    let element = this.viewedElement;
+    let selectors = aRule.selectors;
+
+    do {
+      selectors = selectors.filter(function(aSelector) {
+        return !element.mozMatchesSelector(aSelector);
+      });
+
+      if (selectors.length == 0) {
+        break;
+      }
+    } while ((element = element.parentNode) &&
+             element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
+
+    return selectors.length > 0;
+  },
+
+  /**
+   * Tells if the given DOM CSS object matches the current view media.
+   *
+   * @param {object} aDomObject The DOM CSS object to check.
+   * @return {boolean} True if the DOM CSS object matches the current view
+   * media, or false otherwise.
+   */
+  mediaMatches: function CL_mediaMatches(aDomObject)
+  {
+    let mediaText = aDomObject.media.mediaText;
+    return !mediaText || this.viewedDocument.defaultView.
+                         matchMedia(mediaText).matches;
+   },
 };
 
 /**
  * If the element has an id, return '#id'. Otherwise return 'tagname[n]' where
  * n is the index of this element in its siblings.
  * <p>A technically more 'correct' output from the no-id case might be:
  * 'tagname:nth-of-type(n)' however this is unlikely to be more understood
  * and it is longer.
@@ -785,92 +884,65 @@ CssLogic.isSystemStyleSheet = function C
   if (url.substr(0, 7) === "chrome:") return true;
   if (url === "XPCSafeJSObjectWrapper.cpp") return true;
   if (url.substr(0, 6) === "about:") return true;
 
   return false;
 };
 
 /**
- * Check if the given DOM CSS object holds an allowed media. Currently we only
- * allow media screen or all.
- *
- * @param {CSSStyleSheet|CSSImportRule|CSSMediaRule} aDomObject the
- * DOM object you want checked.
- * @return {boolean} true if the media description is allowed, or false
- * otherwise.
- */
-CssLogic.sheetMediaAllowed = function CssLogic_sheetMediaAllowed(aDomObject)
-{
-  let result = false;
-  let media = aDomObject.media;
-
-  if (media.length > 0) {
-    let mediaItem = null;
-    for (let m = 0, mediaLen = media.length; m < mediaLen; m++) {
-      mediaItem = media.item(m).toLowerCase();
-      if (mediaItem === CssLogic.MEDIA.SCREEN ||
-          mediaItem === CssLogic.MEDIA.ALL) {
-        result = true;
-        break;
-      }
-    }
-  } else {
-    result = true;
-  }
-
-  return result;
-};
-
-/**
  * Return a shortened version of a style sheet's source.
  *
  * @param {CSSStyleSheet} aSheet the DOM object for the style sheet.
  */
 CssLogic.shortSource = function CssLogic_shortSource(aSheet)
 {
-    // Use a string like "inline" if there is no source href
-    if (!aSheet || !aSheet.href) {
-      return CssLogic.l10n("rule.sourceInline");
-    }
+  // Use a string like "inline" if there is no source href
+  if (!aSheet || !aSheet.href) {
+    return CssLogic.l10n("rule.sourceInline");
+  }
 
-    // We try, in turn, the filename, filePath, query string, whole thing
-    let url = Services.io.newURI(aSheet.href, null, null);
+  // We try, in turn, the filename, filePath, query string, whole thing
+  let url = {};
+  try {
+    url = Services.io.newURI(aSheet.href, null, null);
     url = url.QueryInterface(Ci.nsIURL);
-    if (url.fileName) {
-      return url.fileName;
-    }
+  } catch (ex) {
+    // Some UA-provided stylesheets are not valid URLs.
+  }
+
+  if (url.fileName) {
+    return url.fileName;
+  }
 
-    if (url.filePath) {
-      return url.filePath;
-    }
+  if (url.filePath) {
+    return url.filePath;
+  }
 
-    if (url.query) {
-      return url.query;
-    }
+  if (url.query) {
+    return url.query;
+  }
 
-    return this.domSheet.href;
+  return aSheet.href;
 }
 
 /**
  * A safe way to access cached bits of information about a stylesheet.
  *
  * @constructor
  * @param {CssLogic} aCssLogic pointer to the CssLogic instance working with
  * this CssSheet object.
  * @param {CSSStyleSheet} aDomSheet reference to a DOM CSSStyleSheet object.
- * @param {boolean} aSystemSheet tells if the stylesheet is system-provided.
  * @param {number} aIndex tells the index/position of the stylesheet within the
  * main document.
  */
-function CssSheet(aCssLogic, aDomSheet, aSystemSheet, aIndex)
+function CssSheet(aCssLogic, aDomSheet, aIndex)
 {
   this._cssLogic = aCssLogic;
   this.domSheet = aDomSheet;
-  this.systemSheet = aSystemSheet;
   this.index = this.systemSheet ? -100 * aIndex : aIndex;
 
   // Cache of the sheets href. Cached by the getter.
   this._href = null;
   // Short version of href for use in select boxes etc. Cached by getter.
   this._shortSource = null;
 
   // null for uncached.
@@ -879,16 +951,54 @@ function CssSheet(aCssLogic, aDomSheet, 
   // Cached CssRules from the given stylesheet.
   this._rules = {};
 
   this._ruleCount = -1;
 }
 
 CssSheet.prototype = {
   _passId: null,
+  _systemSheet: null,
+  _mediaMatches: null,
+
+  /**
+   * Tells if the stylesheet is provided by the browser or not.
+   *
+   * @return {boolean} true if this is a browser-provided stylesheet, or false
+   * otherwise.
+   */
+  get systemSheet()
+  {
+    if (this._systemSheet === null) {
+      this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet);
+    }
+    return this._systemSheet;
+  },
+
+  /**
+   * Tells if the stylesheet is disabled or not.
+   * @return {boolean} true if this stylesheet is disabled, or false otherwise.
+   */
+  get disabled()
+  {
+    return this.domSheet.disabled;
+  },
+
+  /**
+   * Tells if the stylesheet matches the current browser view media.
+   * @return {boolean} true if this stylesheet matches the current browser view
+   * media, or false otherwise.
+   */
+  get mediaMatches()
+  {
+    if (this._mediaMatches === null) {
+      this._mediaMatches = this._cssLogic.mediaMatches(this.domSheet);
+    }
+    return this._mediaMatches;
+  },
 
   /**
    * Get a source for a stylesheet, taking into account embedded stylesheets
    * for which we need to use document.defaultView.location.href rather than
    * sheet.href
    *
    * @return {string} the address of the stylesheet.
    */
@@ -971,17 +1081,17 @@ CssSheet.prototype = {
     let cacheId = aDomRule.type + aDomRule.selectorText;
 
     let rule = null;
     let ruleFound = false;
 
     if (cacheId in this._rules) {
       for (let i = 0, rulesLen = this._rules[cacheId].length; i < rulesLen; i++) {
         rule = this._rules[cacheId][i];
-        if (rule._domRule == aDomRule) {
+        if (rule._domRule === aDomRule) {
           ruleFound = true;
           break;
         }
       }
     }
 
     if (!ruleFound) {
       if (!(cacheId in this._rules)) {
@@ -1013,17 +1123,17 @@ CssSheet.prototype = {
     let ruleCount = 0;
     let domRules = this.domSheet.cssRules;
 
     function _iterator(aDomRule) {
       if (aDomRule.type == Ci.nsIDOMCSSRule.STYLE_RULE) {
         aCallback.call(aScope, this.getRule(aDomRule));
         ruleCount++;
       } else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
-          aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
+          aDomRule.cssRules && this._cssLogic.mediaMatches(aDomRule)) {
         Array.prototype.forEach.call(aDomRule.cssRules, _iterator, this);
       }
     }
 
     Array.prototype.forEach.call(domRules, _iterator, this);
 
     this._ruleCount = ruleCount;
   },
@@ -1046,17 +1156,17 @@ CssSheet.prototype = {
    */
   forSomeRules: function CssSheet_forSomeRules(aCallback, aScope)
   {
     let domRules = this.domSheet.cssRules;
     function _iterator(aDomRule) {
       if (aDomRule.type == Ci.nsIDOMCSSRule.STYLE_RULE) {
         return aCallback.call(aScope, this.getRule(aDomRule));
       } else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
-          aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
+          aDomRule.cssRules && this._cssLogic.mediaMatches(aDomRule)) {
         return Array.prototype.some.call(aDomRule.cssRules, _iterator, this);
       }
     }
     return Array.prototype.some.call(domRules, _iterator, this);
   },
 
   toString: function CssSheet_toString()
   {
@@ -1404,18 +1514,16 @@ function CssPropertyInfo(aCssLogic, aPro
   this._matchedRuleCount = 0;
 
   // An array holding CssSelectorInfo objects for each of the matched selectors
   // that are inside a CSS rule. Only rules that hold the this.property are
   // counted. This includes rules that come from filtered stylesheets (those
   // that have sheetAllowed = false).
   this._matchedSelectors = null;
   this._unmatchedSelectors = null;
-  this._hasMatchedSelectors = null;
-  this._hasUnmatchedSelectors = null;
 }
 
 CssPropertyInfo.prototype = {
   /**
    * Retrieve the computed style value for the current property, for the
    * highlighted element.
    *
    * @return {string} the computed style value for the current property, for the
@@ -1504,70 +1612,16 @@ CssPropertyInfo.prototype = {
     } else if (this.needRefilter) {
       this._refilterSelectors();
     }
 
     return this._unmatchedSelectors;
   },
 
   /**
-   * Check if the property has any matched selectors.
-   * 
-   * @return {Boolean} true if the current element or it's parents have
-   * matching CssSelector objects, false otherwise
-   */
-  hasMatchedSelectors: function CssPropertyInfo_hasMatchedSelectors()
-  {
-    if (this._hasMatchedSelectors === null) {
-      this._hasMatchedSelectors = this._cssLogic.hasMatchedSelectors(function(aDomRules) {
-        if (!aDomRules.Count) {
-          // For element.style.
-          return !!aDomRules.style.getPropertyValue(this.property);
-        }
-
-        for (let i = 0; i < aDomRules.Count(); i++) {
-          let domRule = aDomRules.GetElementAt(i);
-
-          if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
-            continue;
-          }
-
-          let domSheet = domRule.parentStyleSheet;
-          let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
-          let filter = this._cssLogic.sourceFilter;
-          if (filter !== CssLogic.FILTER.UA && systemSheet) {
-            continue;
-          }
-
-          if (domRule.style.getPropertyValue(this.property)) {
-            return true;
-          }
-        }
-        return false;
-      }.bind(this));
-    }
-
-    return this._hasMatchedSelectors;
-  },
-
-  /**
-   * Check if the property has any matched selectors.
-   *
-   * @return {Boolean} true if the current element or it's parents have
-   * unmatched CssSelector objects, false otherwise
-   */
-  hasUnmatchedSelectors: function CssPropertyInfo_hasUnmatchedSelectors()
-  {
-    if (this._hasUnmatchedSelectors === null) {
-      this._hasUnmatchedSelectors = this._cssLogic.hasUnmatchedSelectors(this.property);
-    }
-    return this._hasUnmatchedSelectors;
-  },
-
-  /**
    * Find the selectors that match the highlighted element and its parents.
    * Uses CssLogic.processMatchedSelectors() to find the matched selectors,
    * passing in a reference to CssPropertyInfo._processMatchedSelector() to
    * create CssSelectorInfo objects, which we then sort
    * @private
    */
   _findMatchedSelectors: function CssPropertyInfo_findMatchedSelectors()
   {
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -113,56 +113,106 @@ ElementStyle.prototype = {
 
   // Empty, unconnected element of the same type as this node, used
   // to figure out how shorthand properties will be parsed.
   dummyElement: null,
 
   domUtils: Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils),
 
   /**
+   * Called by the Rule object when it has been changed through the
+   * setProperty* methods.
+   */
+  _changed: function ElementStyle_changed()
+  {
+    if (this.onChanged) {
+      this.onChanged();
+    }
+  },
+
+  /**
    * Refresh the list of rules to be displayed for the active element.
    * Upon completion, this.rules[] will hold a list of Rule objects.
    */
   _populate: function ElementStyle_populate()
   {
     this.rules = [];
 
+    let element = this.element;
+    do {
+      this._addElementRules(element);
+    } while ((element = element.parentNode) &&
+             element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
+
+    // Mark overridden computed styles.
+    this.markOverridden();
+  },
+
+  _addElementRules: function ElementStyle_addElementRules(aElement)
+  {
+    let inherited = aElement !== this.element ? aElement : null;
+
     // Include the element's style first.
-    this.rules.push(new Rule(this, {
-      style: this.element.style,
-      selectorText: CssLogic.l10n("rule.sourceElement")
-    }));
+    this._maybeAddRule({
+      style: aElement.style,
+      selectorText: CssLogic.l10n("rule.sourceElement"),
+      inherited: inherited
+    });
 
     // Get the styles that apply to the element.
-    try {
-      var domRules = this.domUtils.getCSSStyleRules(this.element);
-    } catch (ex) {
-      Services.console.logStringMessage("ElementStyle_populate error: " + ex);
-      return;
-    }
+    var domRules = this.domUtils.getCSSStyleRules(aElement);
 
     // getCSStyleRules returns ordered from least-specific to
     // most-specific.
     for (let i = domRules.Count() - 1; i >= 0; i--) {
       let domRule = domRules.GetElementAt(i);
 
       // XXX: Optionally provide access to system sheets.
       let systemSheet = CssLogic.isSystemStyleSheet(domRule.parentStyleSheet);
       if (systemSheet) {
         continue;
       }
 
-      // XXX: non-style rules.
-      if (domRule.type === Ci.nsIDOMCSSRule.STYLE_RULE) {
-        this.rules.push(new Rule(this, { domRule: domRule }));
+      if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
+        continue;
       }
+
+      this._maybeAddRule({
+        domRule: domRule,
+        inherited: inherited
+      });
+    }
+  },
+
+  /**
+   * Add a rule if it's one we care about.  Filters out duplicates and
+   * inherited styles with no inherited properties.
+   *
+   * @param {object} aOptions
+   *        Options for creating the Rule, see the Rule constructor.
+   *
+   * @return true if we added the rule.
+   */
+  _maybeAddRule: function ElementStyle_maybeAddRule(aOptions)
+  {
+    // If we've already included this domRule (for example, when a
+    // common selector is inherited), ignore it.
+    if (aOptions.domRule &&
+        this.rules.some(function(rule) rule.domRule === aOptions.domRule)) {
+      return false;
     }
 
-    // Mark overridden computed styles.
-    this.markOverridden();
+    let rule = new Rule(this, aOptions);
+
+    // Ignore inherited rules with no properties.
+    if (aOptions.inherited && rule.textProps.length == 0) {
+      return false;
+    }
+
+    this.rules.push(rule);
   },
 
   /**
    * Mark the properties listed in this.rules with an overridden flag
    * if an earlier property overrides it.
    */
   markOverridden: function ElementStyle_markOverridden()
   {
@@ -173,17 +223,17 @@ ElementStyle.prototype = {
       textProps = textProps.concat(rule.textProps.slice(0).reverse());
     }
 
     // Gather all the computed properties applied by those text
     // properties.
     let computedProps = [];
     for each (let textProp in textProps) {
       computedProps = computedProps.concat(textProp.computed);
-    };
+    }
 
     // Walk over the computed properties.  As we see a property name
     // for the first time, mark that property's name as taken by this
     // property.
     //
     // If we come across a property whose name is already taken, check
     // its priority against the property that was found first:
     //
@@ -209,17 +259,17 @@ ElementStyle.prototype = {
         earlier.overridden = true;
         overridden = false;
       } else {
         overridden = !!earlier;
       }
 
       computedProp._overriddenDirty = (!!computedProp.overridden != overridden);
       computedProp.overridden = overridden;
-      if (!computedProp.overridden) {
+      if (!computedProp.overridden && computedProp.textProp.enabled) {
         taken[computedProp.name] = computedProp;
       }
     }
 
     // For each TextProperty, mark it overridden if all of its
     // computed properties are marked overridden.  Update the text
     // property's associated editor, if any.  This will clear the
     // _overriddenDirty state on all computed properties.
@@ -268,40 +318,53 @@ ElementStyle.prototype = {
  *        The ElementStyle to which this rule belongs.
  * @param {object} aOptions
  *        The information used to construct this rule.  Properties include:
  *          domRule: the nsIDOMCSSStyleRule to view, if any.
  *          style: the nsIDOMCSSStyleDeclaration to view.  If omitted,
  *            the domRule's style will be used.
  *          selectorText: selector text to display.  If omitted, the domRule's
  *            selectorText will be used.
+ *          inherited: An element this rule was inherited from.  If omitted,
+ *            the rule applies directly to the current element.
  * @constructor
  */
 function Rule(aElementStyle, aOptions)
 {
   this.elementStyle = aElementStyle;
   this.domRule = aOptions.domRule || null;
   this.style = aOptions.style || this.domRule.style;
   this.selectorText = aOptions.selectorText || this.domRule.selectorText;
-
+  this.inherited = aOptions.inherited || null;
   this._getTextProperties();
 }
 
 Rule.prototype = {
   get title()
   {
     if (this._title) {
       return this._title;
     }
     let sheet = this.domRule ? this.domRule.parentStyleSheet : null;
     this._title = CssLogic.shortSource(sheet);
     if (this.domRule) {
       let line = this.elementStyle.domUtils.getRuleLine(this.domRule);
       this._title += ":" + line;
     }
+
+    if (this.inherited) {
+      let eltText = this.inherited.tagName.toLowerCase();
+      if (this.inherited.id) {
+        eltText += "#" + this.inherited.id;
+      }
+      let args = [eltText, this._title];
+      this._title = CssLogic._strings.formatStringFromName("rule.inheritedSource",
+                                                           args, args.length);
+    }
+
     return this._title;
   },
 
   /**
    * Create a new TextProperty to include in the rule.
    *
    * @param {string} aName
    *        The text property name (such as "background" or "border-top").
@@ -331,16 +394,17 @@ Rule.prototype = {
 
       this.style.setProperty(prop.name, prop.value, prop.priority);
       // Refresh the property's value from the style, to reflect
       // any changes made during parsing.
       prop.value = this.style.getPropertyValue(prop.name);
       prop.priority = this.style.getPropertyPriority(prop.name);
       prop.updateComputed();
     }
+    this.elementStyle._changed();
 
     this.elementStyle.markOverridden();
   },
 
   /**
    * Renames a property.
    *
    * @param {TextProperty} aProperty
@@ -411,17 +475,23 @@ Rule.prototype = {
   {
     this.textProps = [];
     let lines = this.style.cssText.match(CSS_LINE_RE);
     for each (let line in lines) {
       let matches = CSS_PROP_RE.exec(line);
       if(!matches || !matches[2])
         continue;
 
-      let prop = new TextProperty(this, matches[1], matches[2], matches[3] || "");
+      let name = matches[1];
+      if (this.inherited &&
+          !this.elementStyle.domUtils.isInheritedProperty(name)) {
+        continue;
+      }
+
+      let prop = new TextProperty(this, name, matches[2], matches[3] || "");
       this.textProps.push(prop);
     }
   },
 }
 
 /**
  * A single property in a rule's cssText.
  *
@@ -473,16 +543,17 @@ TextProperty.prototype = {
     let dummyStyle = dummyElement.style;
     dummyStyle.cssText = "";
     dummyStyle.setProperty(this.name, this.value, this.priority);
 
     this.computed = [];
     for (let i = 0, n = dummyStyle.length; i < n; i++) {
       let prop = dummyStyle.item(i);
       this.computed.push({
+        textProp: this,
         name: prop,
         value: dummyStyle.getPropertyValue(prop),
         priority: dummyStyle.getPropertyPriority(prop),
       });
     }
   },
 
   setValue: function TextProperty_setValue(aValue, aPriority)
@@ -563,33 +634,52 @@ CssRuleView.prototype = {
 
     this.clear();
 
     this._viewedElement = aElement;
     if (!this._viewedElement) {
       return;
     }
 
+    if (this._elementStyle) {
+      delete this._elementStyle.onChanged;
+    }
+
     this._elementStyle = new ElementStyle(aElement);
+    this._elementStyle.onChanged = function() {
+      this._changed();
+    }.bind(this);
+
     this._createEditors();
   },
 
   /**
    * Clear the rule view.
    */
   clear: function CssRuleView_clear()
   {
     while (this.element.hasChildNodes()) {
       this.element.removeChild(this.element.lastChild);
     }
     this._viewedElement = null;
     this._elementStyle = null;
   },
 
   /**
+   * Called when the user has made changes to the ElementStyle.
+   * Emits an event that clients can listen to.
+   */
+  _changed: function CssRuleView_changed()
+  {
+    var evt = this.doc.createEvent("Events");
+    evt.initEvent("CssRuleViewChanged", true, false);
+    this.element.dispatchEvent(evt);
+  },
+
+  /**
    * Creates editor UI for each of the rules in _elementStyle.
    */
   _createEditors: function CssRuleView_createEditors()
   {
     for each (let rule in this._elementStyle.rules) {
       // Don't hold a reference to this editor beyond the one held
       // by the node.
       let editor = new RuleEditor(this.doc, rule);
@@ -939,20 +1029,22 @@ TextPropertyEditor.prototype = {
    * value editor.
    *
    * @param {string} aValue
    *        The value from the text editor.
    * @return an object with 'value' and 'priority' properties.
    */
   _parseValue: function TextPropertyEditor_parseValue(aValue)
   {
-    let [value, priority] = aValue.split("!", 2);
+    let pieces = aValue.split("!", 2);
+    let value = pieces[0];
+    let priority = pieces.length > 1 ? pieces[1] : "";
     return {
-      value: value.trim(),
-      priority: (priority ? priority.trim() : "")
+      value: pieces[0].trim(),
+      priority: (pieces.length > 1 ? pieces[1].trim() : "")
     };
   },
 
   /**
    * Called when a value editor closes.  If the user pressed escape,
    * revert to the value this property had before editing.
    *
    * @param {string} aValue
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -82,16 +82,17 @@ StyleInspector.prototype = {
       this.registrationObject = {
         id: "styleinspector",
         label: this.l10n("style.highlighter.button.label1"),
         tooltiptext: this.l10n("style.highlighter.button.tooltip"),
         accesskey: this.l10n("style.highlighter.accesskey1"),
         context: this,
         get isOpen() isOpen(),
         onSelect: this.selectNode,
+        onChanged: this.updateNode,
         show: this.open,
         hide: this.close,
         dim: this.dimTool,
         panel: null,
         unregister: this.destroy,
         sidebar: true,
       };
 
@@ -107,17 +108,17 @@ StyleInspector.prototype = {
    */
   createSidebarContent: function SI_createSidebarContent(aPreserveOnHide)
   {
     this.preserveOnHide = !!aPreserveOnHide;
 
     let boundIframeOnLoad = function loadedInitializeIframe() {
       if (this.iframe &&
           this.iframe.getAttribute("src") ==
-          "chrome://browser/content/csshtmltree.xhtml") {
+          "chrome://browser/content/devtools/csshtmltree.xul") {
         let selectedNode = this.selectedNode || null;
         this.cssHtmlTree = new CssHtmlTree(this);
         this.cssLogic.highlight(selectedNode);
         this.cssHtmlTree.highlight(selectedNode);
         this.iframe.removeEventListener("load", boundIframeOnLoad, true);
         this.iframeReady = true;
         Services.obs.notifyObservers(null, "StyleInspector-opened", null);
       }
@@ -147,47 +148,31 @@ StyleInspector.prototype = {
     panel.setAttribute("noautofocus", "true");
     panel.setAttribute("noautohide", "true");
     panel.setAttribute("titlebar", "normal");
     panel.setAttribute("close", "true");
     panel.setAttribute("label", this.l10n("panelTitle"));
     panel.setAttribute("width", 350);
     panel.setAttribute("height", this.window.screen.height / 2);
 
-    let vbox = this.document.createElement("vbox");
-    vbox.setAttribute("flex", "1");
-    panel.appendChild(vbox);
-
     let iframe = this.document.createElement("iframe");
     let boundIframeOnLoad = function loadedInitializeIframe()
     {
       this.iframe.removeEventListener("load", boundIframeOnLoad, true);
       this.iframeReady = true;
       if (aCallback)
         aCallback(this);
     }.bind(this);
 
-    iframe.setAttribute("flex", "1");
+    iframe.flex = 1;
     iframe.setAttribute("tooltip", "aHTMLTooltip");
     iframe.addEventListener("load", boundIframeOnLoad, true);
-    iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
-
-    vbox.appendChild(iframe);
-
-    let hbox = this.document.createElement("hbox");
-    hbox.setAttribute("class", "resizerbox");
-    vbox.appendChild(hbox);
+    iframe.setAttribute("src", "chrome://browser/content/devtools/csshtmltree.xul");
 
-    let spacer = this.document.createElement("spacer");
-    spacer.setAttribute("flex", "1");
-    hbox.appendChild(spacer);
-
-    let resizer = this.document.createElement("resizer");
-    resizer.setAttribute("dir", "bottomend");
-    hbox.appendChild(resizer);
+    panel.appendChild(iframe);
     popupSet.appendChild(panel);
 
     this._boundPopupShown = this.popupShown.bind(this);
     this._boundPopupHidden = this.popupHidden.bind(this);
     panel.addEventListener("popupshown", this._boundPopupShown, false);
     panel.addEventListener("popuphidden", this._boundPopupHidden, false);
 
     this.panel = panel;
@@ -259,16 +244,27 @@ StyleInspector.prototype = {
     this.selectedNode = aNode;
     if (this.isOpen() && !this.dimmed) {
       this.cssLogic.highlight(aNode);
       this.cssHtmlTree.highlight(aNode);
     }
   },
 
   /**
+   * Update the display for the currently-selected node.
+   */
+  updateNode: function SI_updateNode()
+  {
+    if (this.isOpen() && !this.dimmed) {
+      this.cssLogic.highlight(this.selectedNode);
+      this.cssHtmlTree.refreshPanel();
+    }
+  },
+
+  /**
    * Dim or undim a panel by setting or removing a dimmed attribute.
    * @param aState
    *        true = dim, false = undim
    */
   dimTool: function SI_dimTool(aState)
   {
     this.dimmed = aState;
   },
@@ -277,17 +273,17 @@ StyleInspector.prototype = {
    * Open the panel.
    * @param {DOMNode} aSelection the (optional) DOM node to select.
    */
   open: function SI_open(aSelection)
   {
     this.selectNode(aSelection);
     if (this.openDocked) {
       if (!this.iframeReady) {
-        this.iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
+        this.iframe.setAttribute("src", "chrome://browser/content/devtools/csshtmltree.xul");
       }
     } else {
       this.panel.openPopup(this.window.gBrowser.selectedBrowser, "end_before", 0, 0,
         false, false);
     }
   },
 
   /**
rename from browser/devtools/styleinspector/csshtmltree.xhtml
rename to browser/devtools/styleinspector/csshtmltree.xul
--- a/browser/devtools/styleinspector/csshtmltree.xhtml
+++ b/browser/devtools/styleinspector/csshtmltree.xul
@@ -1,25 +1,9 @@
-<!DOCTYPE html [
-  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-  %htmlDTD;
-  <!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
-  %inspectorDTD;
-  <!ELEMENT loop ANY>
-  <!ATTLIST li foreach CDATA #IMPLIED>
-  <!ATTLIST div foreach CDATA #IMPLIED>
-  <!ATTLIST loop foreach CDATA #IMPLIED>
-  <!ATTLIST a target CDATA #IMPLIED>
-  <!ATTLIST a __pathElement CDATA #IMPLIED>
-  <!ATTLIST div _id CDATA #IMPLIED>
-  <!ATTLIST div save CDATA #IMPLIED>
-  <!ATTLIST table save CDATA #IMPLIED>
-  <!ATTLIST loop if CDATA #IMPLIED>
-  <!ATTLIST tr if CDATA #IMPLIED>
-]>
+<?xml version="1.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/
    -
@@ -30,122 +14,140 @@
    -
    - The Original Code is the Mozilla Inspector Module.
    -
    - The Initial Developer of the Original Code is The Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2011
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
-   -   Joe Walker (jwalker@mozilla.com) (original author)
+   -   Joe Walker <jwalker@mozilla.com> (original author)
    -   Mihai Șucan <mihai.sucan@gmail.com>
    -   Michael Ratcliffe <mratcliffe@mozilla.com>
+   -   Dão Gottwald <dao@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 LGPL or the GPL. 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 ***** -->
-<html xmlns="http://www.w3.org/1999/xhtml"
-  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-<head>
-  <meta http-equiv="Content-Type"
-    content="application/xhtml+xml; charset=UTF-8" />
-  <link rel="stylesheet" type="text/css"
-    href="chrome://browser/skin/devtools/csshtmltree.css" />
-</head>
-<body role="application">
+
+<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/csshtmltree.css" type="text/css"?>
+
+<!DOCTYPE window [
+  <!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
+  %inspectorDTD;
+  <!ELEMENT loop ANY>
+  <!ATTLIST li foreach CDATA #IMPLIED>
+  <!ATTLIST div foreach CDATA #IMPLIED>
+  <!ATTLIST loop foreach CDATA #IMPLIED>
+  <!ATTLIST a target CDATA #IMPLIED>
+  <!ATTLIST a __pathElement CDATA #IMPLIED>
+  <!ATTLIST div _id CDATA #IMPLIED>
+  <!ATTLIST div save CDATA #IMPLIED>
+  <!ATTLIST table save CDATA #IMPLIED>
+  <!ATTLIST loop if CDATA #IMPLIED>
+  <!ATTLIST tr if CDATA #IMPLIED>
+]>
+
+<xul:window xmlns="http://www.w3.org/1999/xhtml"
+            xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <!-- The output from #templateRoot (below) is inserted here. -->
-<div id="root">
-</div>
+<div id="root"></div>
 
 <!-- The output from #templatePath (below) is inserted here. -->
 <div id="path">
 </div>
 
+<!-- When no properties are found the following block is displayed. -->
+<div id="noResults" hidden="">
+  &noPropertiesFound;
+</div>
+
 <!-- The output from #templateProperty (below) is appended here. -->
 <div id="propertyContainer">
 </div>
 
+<xul:hbox id="footer">
+  <xul:label class="legendKey bestmatch">&bestMatch;</xul:label>
+  <xul:label class="legendKey matched">&matched;</xul:label>
+  <xul:label class="legendKey parentmatch">&parentMatch;</xul:label>
+  <xul:spacer flex="1"/>
+  <xul:resizer dir="bottomright"/>
+</xul:hbox>
 <!--
 To visually debug the templates without running firefox, alter the display:none
 -->
 <div style="display:none;">
   <!--
   templateRoot sits at the top of the window and contains the "include default
   styles" checkbox. For data it needs an instance of CssHtmlTree.
   -->
   <div id="templateRoot">
-    <div class="filters">
-      <label class="userStylesLabel" dir="${getRTLAttr}">
+    <xul:hbox class="headerControls" flex="1">
+      <label class="userStylesLabel">
+        <input class="onlyuserstyles" save="${onlyUserStylesCheckbox}"
+               type="checkbox" onchange="${onlyUserStylesChanged}" checked=""/>
         &userStylesLabel;
-        <input class="userStyles" save="${onlyUserStylesCheckbox}" type="checkbox"
-               onchange="${onlyUserStylesChanged}" checked=""/>
       </label>
-      <input save="${searchField}" class="searchfield" type="text"
-             oninput="${filterChanged}"/>
-    </div>
+      <xul:textbox class="searchfield" type="search" save="${searchField}"
+                   placeholder="&userStylesSearch;"
+                   oncommand="${filterChanged}"/>
+    </xul:hbox>
   </div>
 
   <!--
   templatePath sits just below the top of the window showing what we're looking
   at. For data it needs an instance of CssHtmlTree.
   -->
   <div id="templatePath">
-    <p class="path">
-      <label dir="${getRTLAttr}">&lookingAtLabel;</label>
-      <ol>
-        <li foreach="item in ${pathElements}" dir="${getRTLAttr}">
-          <a href="#" onclick="${pathClick}" __pathElement="${item.element}">
-            ${__element.pathElement = item.element; item.display}
-          </a>
-        </li>
-      </ol>
-    </p>
+    <span class="selectedElementLabel">
+      &selectedElementLabel;
+    </span>
+    <!-- following broken in RTL mode, see bug 699900 -->
+    <ol>
+      <li foreach="item in ${pathElements}">
+        <a href="#" onclick="${pathClick}" __pathElement="${item.element}">
+          ${__element.pathElement = item.element; item.display}
+        </a>
+      </li>
+    </ol>
   </div>
 
   <!--
   TemplateProperty lists the properties themselves. Each needs data like this:
   {
     property: ... // PropertyView from CssHtmlTree.jsm
   }
   -->
   <div id="templateProperty">
-    <div class="${className}" save="${element}" dir="${getRTLAttr}">
-      <div class="property-header">
-        <div class="property-name" dir="${getRTLAttr}">
-          <a class="link" target="_blank" title="&helpLinkTitle;"
-              href="${link}">${name}</a>
+    <div class="${className}" save="${element}">
+      <xul:hbox class="property-header" save="${propertyHeader}"
+                onclick="${propertyHeaderClick}">
+        <div save="${matchedExpander}" class="match expander"/>
+        <div class="property-name">${name}</div>
+        <div class="helplink-container">
+          <a href="${link}" class="helplink" title="&helpLinkTitle;" onclick="${mdnLinkClick}">
+            &helpLinkTitle;
+          </a>
         </div>
         <div save="${valueNode}" class="property-value" dir="ltr">${value}</div>
-      </div>
+      </xul:hbox>
 
-      <div save="${matchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
-        <div onclick="${matchedSelectorsClick}" class="rule-matched">
-          <div save="${matchedExpander}" class="expander"></div>
-          <div save="${matchedSelectorsTitleNode}">&matchedSelectors;</div>
-        </div>
-        <table save="${matchedSelectorTable}" dir="${getRTLAttr}"></table>
-      </div>
-
-      <div save="${unmatchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
-        <div onclick="${unmatchedSelectorsClick}" class="rule-unmatched">
-          <div save="${unmatchedExpander}" class="expander"></div>
-          <div save="${unmatchedSelectorsTitleNode}">&unmatchedSelectors;</div>
-        </div>
-        <table save="${unmatchedSelectorTable}" dir="${getRTLAttr}"></table>
+      <div save="${matchedSelectorsContainer}" class="rulelink">
       </div>
     </div>
   </div>
 
   <!--
   A templateMatchedSelectors sits inside each templateProperties showing the
   list of selectors that affect that property. Each needs data like this:
   {
@@ -158,43 +160,17 @@ To visually debug the templates without 
     <table>
       <loop foreach="selector in ${matchedSelectorViews}">
         <tr>
           <td dir="ltr" class="rule-text ${selector.statusClass}">
             ${selector.humanReadableText(__element)}
           </td>
           <td class="rule-link">
             <a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
-                title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
-          </td>
-        </tr>
-      </loop>
-    </table>
-  </div>
-
-  <!--
-  A templateUnmatchedSelectors sits inside each templateProperties showing the
-  list of selectors that fail to affect that property. Each needs data like this:
-  {
-    unmatchedSelectorViews: ..., // from cssHtmlTree.propertyViews[name].unmatchedSelectorViews
-  }
-  This is a template so the parent does not need to be a table, except that
-  using a div as the parent causes the DOM to muck with the tr elements
-  -->
-  <div id="templateUnmatchedSelectors">
-    <table>
-      <loop foreach="selector in ${unmatchedSelectorViews}">
-        <tr>
-          <td dir="ltr" class="rule-text unmatched">
-            ${selector.humanReadableText(__element)}
-          </td>
-          <td class="rule-link">
-            <a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
-                title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
+               title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
           </td>
         </tr>
       </loop>
     </table>
   </div>
 </div>
 
-</body>
-</html>
+</xul:window>
rename from browser/devtools/styleinspector/cssruleview.xhtml
rename to browser/devtools/styleinspector/cssruleview.xul
--- a/browser/devtools/styleinspector/cssruleview.xhtml
+++ b/browser/devtools/styleinspector/cssruleview.xul
@@ -1,14 +1,9 @@
-<!DOCTYPE html [
-  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-  %htmlDTD;
-  <!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/styleinspector.dtd">
-  %inspectorDTD;
-]>
+<?xml version="1.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/
    -
@@ -34,20 +29,16 @@
    - 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 LGPL or the GPL. 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 ***** -->
-<html xmlns="http://www.w3.org/1999/xhtml"
-  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-<head>
-  <meta http-equiv="Content-Type"
-    content="application/xhtml+xml; charset=UTF-8" />
-  <link rel="stylesheet" type="text/css"
-    href="chrome://browser/content/devtools/styleinspector.css" />
-  <link rel="stylesheet" type="text/css"
-    href="chrome://browser/skin/devtools/csshtmltree.css" />
-</head>
-<body role="application" id="ruleview-body"></body>
-</html>
+<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/styleinspector.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/csshtmltree.css" type="text/css"?>
+<!DOCTYPE window [
+  <!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
+  %inspectorDTD;
+]>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
--- a/browser/devtools/styleinspector/test/browser/Makefile.in
+++ b/browser/devtools/styleinspector/test/browser/Makefile.in
@@ -46,18 +46,20 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
   browser_styleinspector.js \
   browser_styleinspector_webconsole.js \
   browser_bug683672.js \
   browser_styleinspector_bug_672746_default_styles.js \
   browser_styleinspector_bug_672744_search_filter.js \
+  browser_styleinspector_bug_689759_no_results_placeholder.js \
   browser_bug_692400_element_style.js \
   browser_ruleview_editor.js \
+  browser_ruleview_inherit.js \
   browser_ruleview_manipulation.js \
   browser_ruleview_override.js \
   browser_ruleview_ui.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_styleinspector_webconsole.htm \
--- a/browser/devtools/styleinspector/test/browser/browser_bug683672.js
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.js
@@ -33,17 +33,17 @@ function tabLoaded()
 
 function runTests()
 {
   Services.obs.removeObserver(runTests, "StyleInspector-opened", false);
 
   ok(stylePanel.isOpen(), "style inspector is open");
 
   testMatchedSelectors();
-  testUnmatchedSelectors();
+  //testUnmatchedSelectors();
 
   info("finishing up");
   Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
   stylePanel.close();
 }
 
 function testMatchedSelectors()
 {
@@ -60,17 +60,17 @@ function testMatchedSelectors()
       "style inspector node matches the selected node");
 
   let propertyView = new PropertyView(htmlTree, "color");
   let numMatchedSelectors = propertyView.propertyInfo.matchedSelectors.length;
 
   is(numMatchedSelectors, 6,
       "CssLogic returns the correct number of matched selectors for div");
 
-  is(propertyView.propertyInfo.hasMatchedSelectors(), true,
+  is(propertyView.hasMatchedSelectors, true,
       "hasMatchedSelectors returns true");
 }
 
 function testUnmatchedSelectors()
 {
   info("checking selector counts, unmatched rules and titles");
   let body = content.document.body;
   ok(body, "captain, we have a body");
@@ -84,17 +84,17 @@ function testUnmatchedSelectors()
       "style inspector node matches the selected node");
 
   let propertyView = new PropertyView(htmlTree, "color");
   let numUnmatchedSelectors = propertyView.propertyInfo.unmatchedSelectors.length;
 
   is(numUnmatchedSelectors, 13,
       "CssLogic returns the correct number of unmatched selectors for body");
 
-  is(propertyView.propertyInfo.hasUnmatchedSelectors(), true,
+  is(propertyView.hasUnmatchedSelectors, true,
       "hasUnmatchedSelectors returns true");
 }
 
 function finishUp()
 {
   Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
   ok(!stylePanel.isOpen(), "style inspector is closed");
   doc = stylePanel = null;
--- a/browser/devtools/styleinspector/test/browser/browser_bug_692400_element_style.js
+++ b/browser/devtools/styleinspector/test/browser/browser_bug_692400_element_style.js
@@ -39,17 +39,17 @@ function SI_checkText()
 
   ok(propertyView, "found PropertyView for color");
 
   is(propertyView.hasMatchedSelectors, true, "hasMatchedSelectors is true");
 
   propertyView.matchedExpanded = true;
   propertyView.refreshMatchedSelectors();
 
-  let td = propertyView.matchedSelectorTable.querySelector("td.rule-text");
+  let td = propertyView.matchedSelectorsContainer.querySelector("td.rule-text");
   ok(td, "found the first table row");
 
   let selector = propertyView.matchedSelectorViews[0];
   ok(selector, "found the first matched selector view");
 
   try {
     is(td.textContent.trim(), selector.humanReadableText(td).trim(),
       "selector text is correct");
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_inherit.js
@@ -0,0 +1,101 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/devtools/CssRuleView.jsm");
+
+let doc;
+
+function simpleInherit()
+{
+  let style = '' +
+    '#test2 {' +
+    '  background-color: green;' +
+    '  color: purple;' +
+    '}';
+
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("test1"));
+
+  is(elementStyle.rules.length, 2, "Should have 2 rules.");
+
+  let elementRule = elementStyle.rules[0];
+  ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
+
+  let inheritRule = elementStyle.rules[1];
+  is(inheritRule.selectorText, "#test2", "Inherited rule should be the one that includes inheritable properties.");
+  ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
+  is(inheritRule.textProps.length, 1, "Should only display one inherited style");
+  let inheritProp = inheritRule.textProps[0];
+  is(inheritProp.name, "color", "color should have been inherited.");
+
+  styleNode.parentNode.removeChild(styleNode);
+
+  emptyInherit();
+}
+
+function emptyInherit()
+{
+  // No inheritable styles, this rule shouldn't show up.
+  let style = '' +
+    '#test2 {' +
+    '  background-color: green;' +
+    '}';
+
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("test1"));
+
+  is(elementStyle.rules.length, 1, "Should have 1 rule.");
+
+  let elementRule = elementStyle.rules[0];
+  ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
+
+  styleNode.parentNode.removeChild(styleNode);
+
+  elementStyleInherit();
+}
+
+function elementStyleInherit()
+{
+  doc.body.innerHTML = '<div id="test2" style="color: red"><div id="test1">Styled Node</div></div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("test1"));
+
+  is(elementStyle.rules.length, 2, "Should have 2 rules.");
+
+  let elementRule = elementStyle.rules[0];
+  ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
+
+  let inheritRule = elementStyle.rules[1];
+  ok(!inheritRule.domRule, "Inherited rule should be an element style, not a rule.");
+  ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
+  is(inheritRule.textProps.length, 1, "Should only display one inherited style");
+  let inheritProp = inheritRule.textProps[0];
+  is(inheritProp.name, "color", "color should have been inherited.");
+
+  finishTest();
+}
+
+function finishTest()
+{
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    waitForFocus(simpleInherit, content);
+  }, true);
+
+  content.location = "data:text/html,basic style inspector tests";
+}
--- a/browser/devtools/styleinspector/test/browser/browser_ruleview_override.js
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_override.js
@@ -105,16 +105,43 @@ function importantOverride()
 
   styleNode.parentNode.removeChild(styleNode);
 
   let elementRule = elementStyle.rules[0];
   let elementProp = elementRule.createProperty("background-color", "purple", "important");
   ok(classProp.overridden, "New important prop should override class property.");
   ok(!elementProp.overridden, "New important prop should not be overriden.");
 
+  disableOverride();
+}
+
+function disableOverride()
+{
+  let style = '' +
+    '#testid {' +
+    '  background-color: blue;' +
+    '}' +
+    '.testclass {' +
+    '  background-color: green;' +
+    '}';
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("testid"));
+
+  let idRule = elementStyle.rules[1];
+  let idProp = idRule.textProps[0];
+  idProp.setEnabled(false);
+
+  let classRule = elementStyle.rules[2];
+  let classProp = classRule.textProps[0];
+  ok(!classProp.overridden, "Class prop should not be overridden after id prop was disabled.");
+
+  styleNode.parentNode.removeChild(styleNode);
+
   finishTest();
 }
 
 function finishTest()
 {
   doc = null;
   gBrowser.removeCurrentTab();
   finish();
--- a/browser/devtools/styleinspector/test/browser/browser_ruleview_ui.js
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_ui.js
@@ -27,54 +27,67 @@ function waitForEditorBlur(aEditor, aCal
   input.addEventListener("blur", function onBlur() {
     input.removeEventListener("blur", onBlur, false);
     executeSoon(function() {
       aCallback();
     });
   }, false);
 }
 
+var gRuleViewChanged = false;
+function ruleViewChanged()
+{
+  gRuleViewChanged = true;
+}
+
+function expectChange()
+{
+  ok(gRuleViewChanged, "Rule view should have fired a change event.");
+  gRuleViewChanged = false;
+}
+
 function startTest()
 {
   let style = '' +
     '#testid {' +
     '  background-color: blue;' +
     '} ' +
     '.testclass {' +
     '  background-color: green;' +
     '}';
 
   let styleNode = addStyle(doc, style);
   doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
   let testElement = doc.getElementById("testid");
 
-  ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
+  ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xul",
                           "cssruleviewtest",
                           "width=200,height=350");
   ruleDialog.addEventListener("load", function onLoad(evt) {
     ruleDialog.removeEventListener("load", onLoad);
     let doc = ruleDialog.document;
-    let body = doc.getElementById("ruleview-body");
     ruleView = new CssRuleView(doc);
-    body.appendChild(ruleView.element);
+    doc.documentElement.appendChild(ruleView.element);
+    ruleView.element.addEventListener("CssRuleViewChanged", ruleViewChanged, false);
     ruleView.highlight(testElement);
     waitForFocus(testCancelNew, ruleDialog);
   }, true);
 }
 
 function testCancelNew()
 {
   // Start at the beginning: start to add a rule to the element's style
   // declaration, but leave it empty.
 
   let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
   waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
     is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
     let input = aEditor.input;
     waitForEditorBlur(aEditor, function () {
+      ok(!gRuleViewChanged, "Shouldn't get a change event after a cancel.");
       is(elementRuleEditor.rule.textProps.length,  0, "Should have canceled creating a new text property.");
       ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties.");
       testCreateNew();
     });
     aEditor.input.blur();
   });
 
   EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
@@ -87,23 +100,25 @@ function testCreateNew()
   // Create a new property.
   let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
   waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
     is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
     let input = aEditor.input;
     input.value = "background-color";
 
     waitForEditorFocus(elementRuleEditor.element, function onNewValue(aEditor) {
+      expectChange();
       is(elementRuleEditor.rule.textProps.length,  1, "Should have created a new text property.");
       is(elementRuleEditor.propertyList.children.length, 1, "Should have created a property editor.");
       let textProp = elementRuleEditor.rule.textProps[0];
       is(aEditor, textProp.editor.valueSpan.inplaceEditor, "Should be editing the value span now.");
 
       aEditor.input.value = "purple";
       waitForEditorBlur(aEditor, function() {
+        expectChange();
         is(textProp.value, "purple", "Text prop should have been changed.");
         testEditProperty();
       });
 
       aEditor.input.blur();
     });
     EventUtils.sendKey("return", input);
   });
@@ -116,20 +131,22 @@ function testCreateNew()
 function testEditProperty()
 {
   let idRuleEditor = ruleView.element.children[1]._ruleEditor;
   let propEditor = idRuleEditor.rule.textProps[0].editor;
   waitForEditorFocus(propEditor.element, function onNewElement(aEditor) {
     is(propEditor.nameSpan.inplaceEditor, aEditor, "Next focused editor should be the name editor.");
     let input = aEditor.input;
     waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
+      expectChange();
       input = aEditor.input;
       is(propEditor.valueSpan.inplaceEditor, aEditor, "Focus should have moved to the value.");
 
       waitForEditorBlur(aEditor, function() {
+        expectChange();
         is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
            "border-color should have been set.");
         testDisableProperty();
       });
 
       for each (let ch in "red;") {
         EventUtils.sendChar(ch, input);
       }
@@ -146,24 +163,30 @@ function testEditProperty()
 
 function testDisableProperty()
 {
   let idRuleEditor = ruleView.element.children[1]._ruleEditor;
   let propEditor = idRuleEditor.rule.textProps[0].editor;
 
   propEditor.enable.click();
   is(idRuleEditor.rule.style.getPropertyValue("border-color"), "", "Border-color should have been unset.");
+  expectChange();
+
   propEditor.enable.click();
   is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
      "Border-color should have been reset.");
+  expectChange();
+
   finishTest();
 }
 
 function finishTest()
 {
+  ruleView.element.removeEventListener("CssRuleViewChanged", ruleViewChanged, false);
+  ruleView.clear();
   ruleDialog.close();
   ruleDialog = ruleView = null;
   doc = null;
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
--- a/browser/devtools/styleinspector/test/browser/browser_styleinspector.js
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector.js
@@ -59,17 +59,17 @@ function runStyleInspectorTests()
   stylePanel.close();
 }
 
 function SI_CheckProperty()
 {
   let cssLogic = stylePanel.cssLogic;
   let propertyInfo = cssLogic.getPropertyInfo("color");
   ok(propertyInfo.matchedRuleCount > 0, "color property has matching rules");
-  ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
+  //ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
 }
 
 function finishUp()
 {
   Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
   ok(!stylePanel.isOpen(), "style inspector is closed");
   doc = stylePanel = null;
   gBrowser.removeCurrentTab();
--- a/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_672744_search_filter.js
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_672744_search_filter.js
@@ -47,29 +47,29 @@ function SI_inspectNode()
      "cssLogic node matches the cssHtmlTree node");
 }
 
 function SI_toggleDefaultStyles()
 {
   Services.obs.removeObserver(SI_toggleDefaultStyles, "StyleInspector-populated", false);
 
   info("clearing \"only user styles\" checkbox");
+
   let iframe = stylePanel.iframe;
-  let checkbox = iframe.contentDocument.querySelector(".userStyles");
+  let checkbox = iframe.contentDocument.querySelector(".onlyuserstyles");
   Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
   EventUtils.synthesizeMouse(checkbox, 5, 5, {}, iframe.contentWindow);
 }
 
 function SI_AddFilterText()
 {
   Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated", false);
 
   let iframe = stylePanel.iframe;
   let searchbar = iframe.contentDocument.querySelector(".searchfield");
-
   Services.obs.addObserver(SI_checkFilter, "StyleInspector-populated", false);
   info("setting filter text to \"color\"");
   searchbar.focus();
   EventUtils.synthesizeKey("c", {}, iframe.contentWindow);
   EventUtils.synthesizeKey("o", {}, iframe.contentWindow);
   EventUtils.synthesizeKey("l", {}, iframe.contentWindow);
   EventUtils.synthesizeKey("o", {}, iframe.contentWindow);
   EventUtils.synthesizeKey("r", {}, iframe.contentWindow);
--- a/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_672746_default_styles.js
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_672746_default_styles.js
@@ -57,17 +57,17 @@ function SI_check()
 
   SI_toggleDefaultStyles();
 }
 
 function SI_toggleDefaultStyles()
 {
   // Click on the checkbox.
   let iframe = stylePanel.iframe;
-  let checkbox = iframe.contentDocument.querySelector(".userStyles");
+  let checkbox = iframe.contentDocument.querySelector(".onlyuserstyles");
   Services.obs.addObserver(SI_checkDefaultStyles, "StyleInspector-populated", false);
   EventUtils.synthesizeMouse(checkbox, 5, 5, {}, iframe.contentWindow);
 }
 
 function SI_checkDefaultStyles()
 {
   Services.obs.removeObserver(SI_checkDefaultStyles, "StyleInspector-populated", false);
   // Check that the default styles are now applied.
@@ -81,17 +81,17 @@ function SI_checkDefaultStyles()
 }
 
 function propertyVisible(aName)
 {
   info("Checking property visibility for " + aName);
   let propertyViews = stylePanel.cssHtmlTree.propertyViews;
   for each (let propView in propertyViews) {
     if (propView.name == aName) {
-      return propView.className == "property-view";
+      return propView.visible;
     }
   }
 }
 
 function finishUp()
 {
   Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
   ok(!stylePanel.isOpen(), "style inspector is closed");
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_689759_no_results_placeholder.js
@@ -0,0 +1,118 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the no results placeholder works properly.
+
+let doc;
+let stylePanel;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<style type="text/css"> ' +
+    '.matches {color: #F00;}</style>' +
+    '<span id="matches" class="matches">Some styled text</span>';
+  doc.title = "Tests that the no results placeholder works properly";
+  ok(window.StyleInspector, "StyleInspector exists");
+  stylePanel = new StyleInspector(window);
+  Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+  stylePanel.createPanel(false, function() {
+    stylePanel.open(doc.body);
+  });
+}
+
+function runStyleInspectorTests()
+{
+  Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
+
+  let span = doc.querySelector("#matches");
+  ok(span, "captain, we have the matches span");
+
+  let htmlTree = stylePanel.cssHtmlTree;
+  stylePanel.selectNode(span);
+
+  is(span, htmlTree.viewedElement,
+    "style inspector node matches the selected node");
+  is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
+     "cssLogic node matches the cssHtmlTree node");
+}
+
+function SI_AddFilterText()
+{
+  Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated", false);
+
+  let iframe = stylePanel.iframe;
+  let searchbar = stylePanel.cssHtmlTree.searchField;
+  let searchTerm = "xxxxx";
+
+  Services.obs.addObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
+  info("setting filter text to \"" + searchTerm + "\"");
+  searchbar.focus();
+  for each (let c in searchTerm) {
+    EventUtils.synthesizeKey(c, {}, iframe.contentWindow);
+  }
+}
+
+function SI_checkPlaceholderVisible()
+{
+  Services.obs.removeObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
+  info("SI_checkPlaceholderVisible called");
+  let placeholder = stylePanel.cssHtmlTree.noResults;
+  let iframe = stylePanel.iframe;
+  let display = iframe.contentWindow.getComputedStyle(placeholder).display;
+
+  is(display, "block", "placeholder is visible");
+
+  SI_ClearFilterText();
+}
+
+function SI_ClearFilterText()
+{
+  let iframe = stylePanel.iframe;
+  let searchbar = stylePanel.cssHtmlTree.searchField;
+
+  Services.obs.addObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
+  info("clearing filter text");
+  searchbar.focus();
+  searchbar.value = "";
+  EventUtils.synthesizeKey("c", {}, iframe.contentWindow);
+}
+
+function SI_checkPlaceholderHidden()
+{
+  Services.obs.removeObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
+  let placeholder = stylePanel.cssHtmlTree.noResults;
+  let iframe = stylePanel.iframe;
+  let display = iframe.contentWindow.getComputedStyle(placeholder).display;
+
+  is(display, "none", "placeholder is hidden");
+
+  Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+  stylePanel.close();
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,no results placeholder test";
+}
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -193,17 +193,19 @@ const LEVELS = {
   error: SEVERITY_ERROR,
   warn: SEVERITY_WARNING,
   info: SEVERITY_INFO,
   log: SEVERITY_LOG,
   trace: SEVERITY_LOG,
   dir: SEVERITY_LOG,
   group: SEVERITY_LOG,
   groupCollapsed: SEVERITY_LOG,
-  groupEnd: SEVERITY_LOG
+  groupEnd: SEVERITY_LOG,
+  time: SEVERITY_LOG,
+  timeEnd: SEVERITY_LOG
 };
 
 // The lowest HTTP response code (inclusive) that is considered an error.
 const MIN_HTTP_ERROR_CODE = 400;
 // The highest HTTP response code (exclusive) that is considered an error.
 const MAX_HTTP_ERROR_CODE = 600;
 
 // HTTP status codes.
@@ -2089,16 +2091,40 @@ HUD_SERVICE.prototype =
         break;
 
       case "groupEnd":
         if (hud.groupDepth > 0) {
           hud.groupDepth--;
         }
         return;
 
+      case "time":
+        if (!args) {
+          return;
+        }
+        if (args.error) {
+          Cu.reportError(this.getStr(args.error));
+          return;
+        }
+        body = this.getFormatStr("timerStarted", [args.name]);
+        clipboardText = body;
+        sourceURL = aMessage.filename;
+        sourceLine = aMessage.lineNumber;
+        break;
+
+      case "timeEnd":
+        if (!args) {
+          return;
+        }
+        body = this.getFormatStr("timeEnd", [args.name, args.duration]);
+        clipboardText = body;
+        sourceURL = aMessage.filename;
+        sourceLine = aMessage.lineNumber;
+        break;
+
       default:
         Cu.reportError("Unknown Console API log level: " + level);
         return;
     }
 
     let node = ConsoleUtils.createMessageNode(hud.outputNode.ownerDocument,
                                               CATEGORY_WEBDEV,
                                               LEVELS[level],
@@ -4617,26 +4643,25 @@ function JSTermHelper(aJSTerm)
       noautofocus: "true",
       noautohide: "true",
       close: "true",
       width: 350,
       height: (win.screen.height / 2)
     });
 
     let iframe = createAndAppendElement(panel, "iframe", {
-      src: "chrome://browser/content/devtools/cssruleview.xhtml",
+      src: "chrome://browser/content/devtools/cssruleview.xul",
       flex: "1",
     });
 
     panel.addEventListener("load", function onLoad() {
       panel.removeEventListener("load", onLoad, true);
       let doc = iframe.contentDocument;
       let view = new CssRuleView(doc);
-      let body = doc.getElementById("ruleview-body");
-      body.appendChild(view.element);
+      doc.documentElement.appendChild(view.element);
       view.highlight(aNode);
     }, true);
 
     let parent = doc.getElementById("mainPopupSet");
     parent.appendChild(panel);
 
     panel.addEventListener("popuphidden", function onHide() {
       panel.removeEventListener("popuphidden", onHide);
--- a/browser/devtools/webconsole/test/browser/Makefile.in
+++ b/browser/devtools/webconsole/test/browser/Makefile.in
@@ -144,16 +144,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_webconsole_bug_653531_highlighter_console_helper.js \
 	browser_webconsole_bug_659907_console_dir.js \
 	browser_webconsole_bug_678816.js \
 	browser_webconsole_bug_664131_console_group.js \
 	browser_gcli_inspect.js \
 	browser_gcli_integrate.js \
 	browser_gcli_require.js \
 	browser_gcli_web.js \
+	browser_webconsole_bug_658368_time_methods.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
 	test-console.html \
 	test-network.html \
 	test-network-request.html \
 	test-mutation.html \
@@ -215,15 +216,16 @@ include $(topsrcdir)/config/rules.mk
 	test-bug-632347-iterators-generators.html \
 	test-bug-585956-console-trace.html \
 	test-bug-644419-log-limits.html \
 	test-bug-632275-getters.html \
 	test-bug-646025-console-file-location.html \
 	test-bug-678816-content.js \
 	test-file-location.js \
 	browser_gcli_inspect.html \
+	test-bug-658368-time-methods.html \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_PAGES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_658368_time_methods.js
@@ -0,0 +1,87 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the Console API implements the time() and timeEnd() methods.
+
+function test() {
+  addTab("http://example.com/browser/browser/devtools/webconsole/" +
+         "test/browser/test-bug-658368-time-methods.html");
+  openConsole();
+  browser.addEventListener("load", onLoad, true);
+}
+
+function onLoad(aEvent) {
+  browser.removeEventListener(aEvent.type, onLoad, true);
+
+  let hudId = HUDService.getHudIdByWindow(content);
+  let hud = HUDService.hudReferences[hudId];
+  outputNode = hud.outputNode;
+
+  executeSoon(function() {
+    findLogEntry("aTimer: timer started");
+    findLogEntry("ms");
+
+    // The next test makes sure that timers with the same name but in separate
+    // tabs, do not contain the same value.
+    addTab("data:text/html,<script type='text/javascript'>" +
+           "console.timeEnd('bTimer');</script>");
+    openConsole();
+    browser.addEventListener("load", testTimerIndependenceInTabs, true);
+  });
+}
+
+function testTimerIndependenceInTabs(aEvent) {
+  browser.removeEventListener(aEvent.type, testTimerIndependenceInTabs, true);
+
+  let hudId = HUDService.getHudIdByWindow(content);
+  let hud = HUDService.hudReferences[hudId];
+  outputNode = hud.outputNode;
+
+  executeSoon(function() {
+    testLogEntry(outputNode, "bTimer: timer started", "bTimer was not started",
+                 false, true);
+
+    // The next test makes sure that timers with the same name but in separate
+    // pages, do not contain the same value.
+    browser.addEventListener("load", testTimerIndependenceInSameTab, true);
+    content.location = "data:text/html,<script type='text/javascript'>" +
+           "console.time('bTimer');</script>";
+  });
+}
+
+function testTimerIndependenceInSameTab(aEvent) {
+  browser.removeEventListener(aEvent.type, testTimerIndependenceInSameTab, true);
+
+  let hudId = HUDService.getHudIdByWindow(content);
+  let hud = HUDService.hudReferences[hudId];
+  outputNode = hud.outputNode;
+
+  executeSoon(function() {
+    findLogEntry("bTimer: timer started");
+    hud.jsterm.clearOutput();
+
+    // Now the following console.timeEnd() call shouldn't display anything,
+    // if the timers in different pages are not related.
+    browser.addEventListener("load", testTimerIndependenceInSameTabAgain, true);
+    content.location = "data:text/html,<script type='text/javascript'>" +
+           "console.timeEnd('bTimer');</script>";
+  });
+}
+
+function testTimerIndependenceInSameTabAgain(aEvent) {
+  browser.removeEventListener(aEvent.type, testTimerIndependenceInSameTabAgain, true);
+
+  let hudId = HUDService.getHudIdByWindow(content);
+  let hud = HUDService.hudReferences[hudId];
+  outputNode = hud.outputNode;
+
+  executeSoon(function() {
+    testLogEntry(outputNode, "bTimer: timer started", "bTimer was not started",
+                 false, true);
+
+    finishTest();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser/test-bug-658368-time-methods.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<!-- Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ -->
+  <head>
+    <title>Test for bug 658368: Expand console object with time and timeEnd
+      methods</title>
+  </head>
+  <body>
+    <h1>Test for bug 658368: Expand console object with time and timeEnd
+      methods</h1>
+
+    <script type="text/javascript">
+      function foo() {
+        console.timeEnd("aTimer");
+      }
+      console.time("aTimer");
+      foo();
+      console.time("bTimer");
+    </script>
+  </body>
+</html>
+
--- a/browser/devtools/webconsole/test/browser/test-console-extras.html
+++ b/browser/devtools/webconsole/test/browser/test-console-extras.html
@@ -1,16 +1,14 @@
 <!DOCTYPE HTML>
 <html dir="ltr" xml:lang="en-US" lang="en-US"><head>
     <title>Console extended API test</title>
     <script type="text/javascript">
       function test() {
         console.log("start");
-        console.time();
-        console.timeEnd()
         console.exception()
         console.assert()
         console.clear()
         console.dirxml()
         console.profile()
         console.profileEnd()
         console.count()
         console.table()
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -273,18 +273,16 @@
 @BINPATH@/components/nsSetDefaultBrowser.manifest
 @BINPATH@/components/nsSetDefaultBrowser.js
 @BINPATH@/components/BrowserPlaces.manifest
 @BINPATH@/components/nsPrivateBrowsingService.manifest
 @BINPATH@/components/nsPrivateBrowsingService.js
 @BINPATH@/components/toolkitsearch.manifest
 @BINPATH@/components/nsSearchService.js
 @BINPATH@/components/nsSearchSuggestions.js
-@BINPATH@/components/nsTryToClose.manifest
-@BINPATH@/components/nsTryToClose.js
 @BINPATH@/components/passwordmgr.manifest
 @BINPATH@/components/nsLoginInfo.js
 @BINPATH@/components/nsLoginManager.js
 @BINPATH@/components/nsLoginManagerPrompter.js
 @BINPATH@/components/storage-Legacy.js
 @BINPATH@/components/storage-mozStorage.js
 @BINPATH@/components/crypto-SDR.js
 @BINPATH@/components/jsconsole-clhandler.manifest
@@ -476,19 +474,17 @@
 @BINPATH@/res/entityTables/*
 #ifdef XP_MACOSX
 @BINPATH@/res/MainMenu.nib/
 #endif
 
 ; svg
 @BINPATH@/res/svg.css
 @BINPATH@/components/dom_svg.xpt
-#ifdef MOZ_SMIL
 @BINPATH@/components/dom_smil.xpt
-#endif
 
 ; [Personal Security Manager]
 ;
 @BINPATH@/@DLL_PREFIX@nssckbi@DLL_SUFFIX@
 @BINPATH@/components/pipboot.xpt
 @BINPATH@/components/pipnss.xpt
 @BINPATH@/components/pippki.xpt
 @BINPATH@/@DLL_PREFIX@nss3@DLL_SUFFIX@
--- a/browser/locales/en-US/chrome/browser/devtools/inspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/inspector.properties
@@ -18,8 +18,13 @@ htmlPanel.label=HTML
 # LOCALIZATION NOTE (htmlPanel.tooltiptext): The text that appears when a user
 # hovers over the HTML panel's toolbar button.
 htmlPanel.tooltiptext=HTML panel
 
 # LOCALIZATION NOTE (htmlPanel.accesskey): The key bound to the HTML panel's
 # toolbar button.
 htmlPanel.accesskey=H
 
+# LOCALIZATION NOTE (ruleView.*): Button label, accesskey and tooltip text
+# associated with the Highlighter's CSS Rule View in the Style Sidebar.
+ruleView.label=Rules
+ruleView.accesskey=R
+ruleView.tooltiptext=View and Edit CSS
\ No newline at end of file
--- a/browser/locales/en-US/chrome/browser/devtools/styleinspector.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/styleinspector.dtd
@@ -1,25 +1,39 @@
 <!-- LOCALIZATION NOTE (userStylesLabel): This is the label for the checkbox
   -  that specifies whether the styles that are not from the user's stylesheet
   -  should be displayed or not. -->
 <!ENTITY userStylesLabel    "Only user styles">
 
-<!-- LOCALIZATION NOTE (lookingAtLabel): This is the label for the path of
+<!-- LOCALIZATION NOTE (userStylesSearch): This is the placeholder that goes in
+  -  the search box when no search term has been entered. -->
+<!ENTITY userStylesSearch      "Search">
+
+<!-- LOCALIZATION NOTE (selectedElementLabel): This is the label for the path of
   -  the highlighted element in the web page. This path is based on the document
   -  tree. -->
-<!ENTITY lookingAtLabel        "Looking at:">
+<!ENTITY selectedElementLabel  "Selected element:">
 
 <!-- LOCALIZATION NOTE (helpLinkTitle): For each style property
   -  the user can hover it and get a help link button which allows one to
   -  quickly jump to the documentation from the Mozilla Developer Network site.
   -  This is the link title shown in the hover tooltip. -->
 <!ENTITY helpLinkTitle         "Read the documentation for this property">
 
-<!-- LOCALIZATION NOTE (matchedSelectors): For each style property the
-  -  panel shows whether there are any selectors that match the currently
-  -  selected element. -->
-<!ENTITY matchedSelectors      "Matched selectors">
+<!-- LOCALIZATION NOTE (noPropertiesFound): In the case where there are no CSS
+  -  properties to display e.g. due to search criteria this message is
+  -  displayed. -->
+<!ENTITY noPropertiesFound     "No CSS properties found.">
 
 <!-- LOCALIZATION NOTE (unmatchedSelectors): For each style property
   -  the panel shows whether there are any selectors that do not match the
   -  currently selected element. -->
 <!ENTITY unmatchedSelectors    "Unmatched selectors">
+
+<!-- LOCALIZATION NOTE (bestMatch, matched, parentMatch & unmatched): For each
+  -  style property the panel shows the rules which hold that specific property.
+  -  For every rule, the rule status is also displayed: a rule can be the best
+  -  match, a match, a parent match, or a rule did not match the element the
+  -  user has highlighted. -->
+<!ENTITY bestMatch             "Best Match">
+<!ENTITY matched               "Matched">
+<!ENTITY parentMatch           "Parent Match">
+<!ENTITY unmatched             "Unmatched">
--- a/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
@@ -14,23 +14,30 @@ rule.status.UNMATCHED=Unmatched
 
 # LOCALIZATION NOTE (rule.sourceElement, rule.sourceInline): For each
 # style property the panel shows the rules which hold that specific property.
 # For every rule, the rule source is also displayed: a rule can come from a
 # file, from the same page (inline), or from the element itself (element).
 rule.sourceInline=inline
 rule.sourceElement=element
 
+# LOCALIZATION NOTE (rule.inheritedSource): Shown for CSS rules
+# that were inherited from a parent node.  Will be passed a node
+# identifier and a source location.
+# e.g "Inherited from body#bodyID (styles.css:20)"
+rule.inheritedSource=Inherited from %S (%S)
+
 # LOCALIZATION NOTE (group): Style properties are displayed in categories and
 # these are the category names.
 group.Text_Fonts_and_Color=Text, Fonts & Color
 group.Background=Background
 group.Dimensions=Dimensions
 group.Positioning_and_Page_Flow=Positioning and Page Flow
 group.Borders=Borders
 group.Lists=Lists
 group.Effects_and_Other=Effects and Other
 
 # LOCALIZATION NOTE (style.highlighter.button): These strings are used inside
 # sidebar of the Highlighter for the style inspector button
 style.highlighter.button.label1=Properties
 style.highlighter.accesskey1=P
 style.highlighter.button.tooltip=Inspect element styles
+
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -167,8 +167,20 @@ Autocomplete.label=Autocomplete popup
 # they are said to be anonymous. See stacktrace.outputMessage.
 stacktrace.anonymousFunction=<anonymous>
 
 # LOCALIZATION NOTE (stacktrace.outputMessage):
 # This string is used in the Web Console output to identify a web developer call
 # to console.trace(). The stack trace of JavaScript function calls is displayed.
 # In this minimal message we only show the last call.
 stacktrace.outputMessage=Stack trace from %S, function %S, line %S.
+
+# LOCALIZATION NOTE (timerStarted):
+# This string is used to display the result of the console.time() call.
+# %S=name of timer
+timerStarted=%S: timer started
+
+# LOCALIZATION NOTE (timeEnd):
+# This string is used to display the result of the console.timeEnd() call.
+# %1$S=name of timer, %2$S=number of milliseconds
+timeEnd=%1$S: %2$Sms
+
+maxTimersExceeded=The maximum allowed number of timers in this page was exceeded.
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1899,16 +1899,26 @@ panel[dimmed="true"] {
 #addon-bar {
   box-shadow: 0 1px 0 rgba(0,0,0,.15) inset;
   padding: 0;
   min-height: 20px;
 }
 
 #status-bar {
   min-height: 0;
+  -moz-appearance: none;
+  background-color: transparent;
+  border: none;
+}
+
+#addon-bar[customizing] > #status-bar {
+  opacity: .5;
+  background-image: -moz-repeating-linear-gradient(-45deg,
+                                                   rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
+                                                   rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
 }
 
 #status-bar > statusbarpanel {
   border-width: 0;
   -moz-appearance: none;
 }
 
 #addonbar-closebutton {
index 95e7217927854ed98dd7e55123709ad8baf126f9..447d73938398ff2c09efafc33d14c82252229668
GIT binary patch
literal 882
zc$@)p1C9KNP)<h;3K|Lk000e1NJLTq001xm000OG0ssI2FiGnW00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq-
z3_1diBBnb400Qz!L_t(I%Y~EQPZL=b$G_*^mH~AmOkxE!kyxU*OlPK>mB>B-55BnD
zU2%17YU`_i1Fj)i)&zWq|A1dAxEgIjl+6b4X^lZBZ59Q#YBV(@v|Tmn)NwfbFatKm
z;C(yip8Gl9dwx*wmHx;NC%*|B_|h2}yS})XCL#he0MOQzAPOEj)7o0EX@M_trl+4h
zdi1iY%Kz%sTL460W|wyOuquzYeV5H<?@#@us%k_1-p?XN$8L;XyY}|Y8wR%?`*wYO
zT@VQ=q$DAPq9{Li{dDjC>$`WK%+2NM>vshLJ3q^rnR(XNH~Zkh3#)8@fAYxW<Z`i4
zDip0^(JB_LLZK9o>jHpn+d?3jOkVEkonKh2M2uaZxOBN^Wo5a_?{^#rK-Z}sOO{nx
zpK{qYO%q@u%4Q3{_s(>8|C!0GRdQx$pI^LqXK?Ug@jna9V6?RzsI65XyZ|BugQ}(l
ze69h&{_sIcB$LS-6E}Z3b2^nu|Fg7IQ?2+nrSK*_q=i;imL10dsLJn)L?Qs(HZp_3
z*=(Wrx9MP$nn>um+`IAdOg>){f<OcY2toirJgyH8J_NbXD3Q<sPa%<~iX6w;aGX>s
zt?QbQQcCHjVlcqW4B&k1T*<N+0N5(qVN(YnM8#(T2J-n*F88jXVVA1bc;#g8Qya_x
zIyxHb>Z%1n2s#w3bLY<oup2F<ELql3-H1icy3fL<F~6`lKJiDj;(Kq~l`YV9<LQ$n
zDP`nz<YNwI2w(%dYpW9pqrLs0d)426B9mDg8cO}UTJSc)%ZWt77#R4QfD0FN*W;s2
zDWN0H=VRwS8AH<unMUaGd}`w6Ek*H{%VpOei=OTNwMR&48ljKTM76t>cwF!3X#9lJ
z(h|6O^+Y<oHawhKUCq<x0JgUu92rTeYE4Uvx1K&`1e==TvFJ978aDN?sn0!LxP2#C
zk>l&5&COfp{(WC{ooepvY}|&UX`Za9si#}cXjI#?XUCTLKX2?ZMa}?8lK=n!07*qo
IM6N<$f=Y9k=>Px#
--- a/browser/themes/gnomestripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/browser/devtools/csshtmltree.css
@@ -17,181 +17,251 @@
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Joe Walker <jwalker@mozilla.com> (original author)
  *   Mihai Șucan <mihai.sucan@gmail.com>
  *   Michael Ratcliffe <mratcliffe@mozilla.com>
+ *   Dão Gottwald <dao@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 ***** */
 
-body {
-  font-family: sans-serif;
-  font-size: 11px;
-  background: #EEE;
+:root {
+  -moz-appearance: none;
+  background: -moz-Field;
+  color: -moz-FieldText;
 }
-.path,
-.filters {
+
+#root {
+  display: -moz-box;
+}
+
+#path {
   font-size: 11px;
   word-spacing: -1px;
+  margin-bottom: 0;
+  color: -moz-dialogtext;
+  background-color: -moz-dialog;
+  padding: 4px 5px 0;
 }
-.path ol {
+#path ol {
   list-style: none outside none;
   margin: 0;
   padding: 0;
 }
-.path li {
+#path li {
   border-radius: 3px;
   padding: 2px 3px;
-  text-shadow: #FFF 0 1px 0;
-  font-weight: bold;
   font-size: 11px;
-  background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
   display: inline-block;
 }
-.path li:after {
+#path li:after {
   content: " > ";
 }
-.path li:last-child {
-  background: -moz-linear-gradient(top, #FFC, #DD8);
+#path li:last-child {
+  font-weight: bold;
+  color: #0091ff;
 }
-.path li:last-child:after {
-  color: red;
+#path li:last-child:after {
   content: "";
 }
 
 .property-header {
-  padding: 2px 5px;
-  background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
-  color: #666;
+  padding: 4px;
+  -moz-padding-start: 0;
+  -moz-padding-end: 5px;
 }
 
-.property-name,
-.rule-matched,
 .rule-unmatched {
   cursor: pointer;
+  padding: 2px;
+  -moz-padding-start: 4px;
+  -moz-padding-end: 0;
+  white-space: nowrap;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
-.link {
-  color: #55A;
-}
+.link,
 .link:visited {
-  color: #55A;
+  color: #0091ff;
 }
-a.link {
-  text-decoration: none;
-  cursor: pointer;
-}
-a.link:visited {
+.link,
+.helplink,
+.link:visited,
+.helplink:visited {
   text-decoration: none;
 }
 
-.rule-matched,
-.rule-unmatched {
-  padding: 2px 0;
-  white-space: nowrap;
+.helplink-container {
+  position: relative;
+  top: 2px;
+}
+
+.helplink {
+  display: block;
+  height: 14px;
+  width: 0;
+  overflow: hidden;
+  -moz-padding-start: 14px;
+  background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
+  -moz-margin-end: 2px;
+}
+
+.property-header:not(:hover) > .helplink-container {
+  visibility: hidden;
+}
+
+.unmatchedSelectorTable {
+  -moz-margin-start: 15px;
 }
 
 .rulelink {
-  color: #55A;
+  color: -moz-dialogtext;
+  -moz-margin-start: 12px;
 }
 
 .expander {
-  width: 8px;
-  height: 8px;
-  float: left;
-  -moz-margin-start: 15px;
+  -moz-appearance: treetwisty;
+  -moz-margin-start: 10px;
   -moz-margin-end: 5px;
-  margin-top: 3px;
-  background: url("chrome://browser/skin/devtools/arrows.png");
-  background-position: 24px 0;
+}
+
+.expander[open] {
+  -moz-appearance: treetwistyopen;
 }
 
-.searchfield {
-  background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
-  border-radius: 5px;
-  -moz-padding-start: 20px;
-  width: 135px;
-  float: right;
+.expandable {
+  cursor: pointer;
 }
 
-.expander[dir="rtl"] {
-  background-position: 16px 0;
+.match {
+  visibility: hidden;
 }
-.expander[open] {
-  background-position: 8px 0;
+
+.expandable > .match {
+  visibility: visible;
+}
+
+.only-unmatched {
+  -moz-margin-start: 0;
 }
 
 .property-name {
-  display: inline-block;
   font-size: 12px;
-  font-weight: bold;
-  color: #000;
+  color: -moz-FieldText;
+  width: 220px;
 }
 .property-value {
-  display: inline-block;
   font-size: 10px;
+  color: grey;
 }
 
 .property-view-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
-  -moz-padding-start: 10px;
-}
-
-.resizerbox {
-  background-color: window;
+  -moz-padding-start: 15px;
 }
 
 .bestmatch {
   color: black;
 }
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 .unmatched {
   color: brown;
 }
 
-.userStyles {
+#propertyContainer {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-flex: 1;
+  overflow-y: auto;
+}
+
+.selectedElementLabel {
+  font-weight: bold;
+}
+
+.darkrow {
+  background-color: rgba(0,0,0,.022);
+}
+
+#noResults {
+  font-size: 18px;
+  margin-top: 5px;
+  text-align: center;
+}
+
+.headerControls {
+  color: -moz-dialogtext;
+  background-color: -moz-dialog;
+  padding-top: 5px;
+}
+
+.onlyuserstyles,
+.userStylesLabel {
+  cursor: pointer;
+}
+
+.userStylesLabel {
+  display: -moz-box;
+  white-space: nowrap;
+}
+
+.onlyuserstyles {
   position: relative;
   top: 3px;
+  font-family: sans-serif;
+  font-size: 11px;
+}
+
+.searchfield {
+  display: -moz-box;
+  -moz-box-flex: 1;
+  margin-left: 10px;
 }
 
-.userStyles,
-.userStylesLabel {
-  cursor: pointer;
+.styleinspector-legend {
+  -moz-margin-start: 12px;
+}
+
+#footer {
+  border-top: 1px solid -moz-dialog;
+}
+
+.legendKey {
+  margin: 0 5px;
 }
 
 /**
  * CSS Rule View
  */
 
 .ruleview {
   background-color: #FFF;
@@ -224,17 +294,17 @@ a.link:visited {
   width: 8px;
   height: 8px;
   background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
   cursor: pointer;
   -moz-margin-start: 2px;
   -moz-margin-end: 5px;
 }
 
-.ruleview-expander[dir="rtl"] {
+.ruleview-expander:-moz-locale-dir(rtl) {
   background-position: 16px 0;
 }
 
 .ruleview-expander.styleinspector-open {
   background-position: 8px 0;
 }
 
 .ruleview-newproperty {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dbe064863d65ac3123a7a60070114dd465852de2
GIT binary patch
literal 661
zc$@*10&4w<P)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipn-
z2m%$DyLk=(00I?BL_t(2&sCB?Zxc}v#DDkh-PyVG`C^*@2}yxvJ^(@nAt)nCl!gMO
zrA+~m(o!O%NEB%)k%&Zr_zXc%P*5X80V3cS;`rY=j_<v<6iH07(ljHDW@mRiZaj@R
zo#LVY_0?Lx*B_8&BLLz!A}uFeySn6YX1uAe^FI0b=0!^>pCAm;Ism{L!(?)VbC%l=
z9$%(<cL1OO-aWf_e`kBMRg5CyQVFd!)*3(v!hk4_DMk@H+nX)+b}Gk?jkWTJ*N=K}
zsf_O{e5JThEmMwX2m*~0VKf@^<M&^zwG4*??mT>%dSAYMm(h5F)*;GQ)E6&NEClSf
zI~<NDRLU{6*@WG8ht9zOV{+n|5S3+Pl=4xYhgOPWAwWdv4@Ts<q1(>@xN@-yfKrMq
z8>5Z2_(6am7-#vpw-10I094W#fZcWn5D>vShgQCih#(^1pm*W`P@PSvrV0Jwh;DC)
z6NeK4546?_>l~g^oO=`y&lK424*1pX9B(0l6CnsRx)enm^!hl!^VK=wpH3I+9L`w)
zoOL*BC?zSXvAmIra~Nx|#!i6~>Pz#~7w4y(a~2UtV|gQ0qz!X(<;jA{bFBG~d~(F$
z_=sUPnsO%3xwW#sK-w^8D)%}0^!9nnScB)C<n=r_$)$at=F0j!wPt@>x#JUFA2e6D
vlDS%yLZ~q|$CwFWsF|x(Xs&K0ry_uVAQ%nSnI7d%00000NkvXXu0mjf<!Km0
deleted file mode 100644
index df7212d78c8f86e7abe5073d85bf419786993550..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/gnomestripe/browser/jar.mn
+++ b/browser/themes/gnomestripe/browser/jar.mn
@@ -74,22 +74,22 @@ browser.jar:
   skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
   skin/classic/browser/tabbrowser/alltabs.png          (tabbrowser/alltabs.png)
   skin/classic/browser/tabbrowser/connecting.png      (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/loading.png         (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/tab.png             (tabbrowser/tab.png)
   skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
-  skin/classic/browser/tabview/search.png             (tabview/search.png)  
+  skin/classic/browser/tabview/search.png             (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png            (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css            (tabview/tabview.css)
   skin/classic/browser/devtools/arrows.png            (devtools/arrows.png)
-  skin/classic/browser/devtools/search.png            (devtools/search.png)
+  skin/classic/browser/devtools/goto-mdn.png          (devtools/goto-mdn.png)
   skin/classic/browser/devtools/csshtmltree.css       (devtools/csshtmltree.css)
   skin/classic/browser/devtools/gcli.css              (devtools/gcli.css)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png  (devtools/breadcrumbs/ltr-middle-selected-pressed.png)
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -2464,16 +2464,23 @@ panel[dimmed="true"] {
   -moz-appearance: statusbar;
 }
 
 #status-bar {
   -moz-appearance: none;
   padding-right: 0;
 }
 
+#addon-bar[customizing] > #status-bar {
+  opacity: .5;
+  background-image: -moz-repeating-linear-gradient(-45deg,
+                                                   rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
+                                                   rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
+}
+
 #status-bar > statusbarpanel {
   border-width: 0;
   -moz-appearance: none;
 }
 
 #addonbar-closebutton {
   padding: 0;
   margin: 0 4px;
index 95e7217927854ed98dd7e55123709ad8baf126f9..447d73938398ff2c09efafc33d14c82252229668
GIT binary patch
literal 882
zc$@)p1C9KNP)<h;3K|Lk000e1NJLTq001xm000OG0ssI2FiGnW00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq-
z3_1diBBnb400Qz!L_t(I%Y~EQPZL=b$G_*^mH~AmOkxE!kyxU*OlPK>mB>B-55BnD
zU2%17YU`_i1Fj)i)&zWq|A1dAxEgIjl+6b4X^lZBZ59Q#YBV(@v|Tmn)NwfbFatKm
z;C(yip8Gl9dwx*wmHx;NC%*|B_|h2}yS})XCL#he0MOQzAPOEj)7o0EX@M_trl+4h
zdi1iY%Kz%sTL460W|wyOuquzYeV5H<?@#@us%k_1-p?XN$8L;XyY}|Y8wR%?`*wYO
zT@VQ=q$DAPq9{Li{dDjC>$`WK%+2NM>vshLJ3q^rnR(XNH~Zkh3#)8@fAYxW<Z`i4
zDip0^(JB_LLZK9o>jHpn+d?3jOkVEkonKh2M2uaZxOBN^Wo5a_?{^#rK-Z}sOO{nx
zpK{qYO%q@u%4Q3{_s(>8|C!0GRdQx$pI^LqXK?Ug@jna9V6?RzsI65XyZ|BugQ}(l
ze69h&{_sIcB$LS-6E}Z3b2^nu|Fg7IQ?2+nrSK*_q=i;imL10dsLJn)L?Qs(HZp_3
z*=(Wrx9MP$nn>um+`IAdOg>){f<OcY2toirJgyH8J_NbXD3Q<sPa%<~iX6w;aGX>s
zt?QbQQcCHjVlcqW4B&k1T*<N+0N5(qVN(YnM8#(T2J-n*F88jXVVA1bc;#g8Qya_x
zIyxHb>Z%1n2s#w3bLY<oup2F<ELql3-H1icy3fL<F~6`lKJiDj;(Kq~l`YV9<LQ$n
zDP`nz<YNwI2w(%dYpW9pqrLs0d)426B9mDg8cO}UTJSc)%ZWt77#R4QfD0FN*W;s2
zDWN0H=VRwS8AH<unMUaGd}`w6Ek*H{%VpOei=OTNwMR&48ljKTM76t>cwF!3X#9lJ
z(h|6O^+Y<oHawhKUCq<x0JgUu92rTeYE4Uvx1K&`1e==TvFJ978aDN?sn0!LxP2#C
zk>l&5&COfp{(WC{ooepvY}|&UX`Za9si#}cXjI#?XUCTLKX2?ZMa}?8lK=n!07*qo
IM6N<$f=Y9k=>Px#
--- a/browser/themes/pinstripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/browser/devtools/csshtmltree.css
@@ -17,181 +17,253 @@
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Joe Walker <jwalker@mozilla.com> (original author)
  *   Mihai Șucan <mihai.sucan@gmail.com>
  *   Michael Ratcliffe <mratcliffe@mozilla.com>
+ *   Dão Gottwald <dao@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 ***** */
 
-body {
-  font-family: sans-serif;
-  font-size: 11px;
-  background: #EEE;
+:root {
+  -moz-appearance: none;
+  background: -moz-Field;
+  color: -moz-FieldText;
 }
-.path,
-.filters {
+
+#root {
+  display: -moz-box;
+}
+
+#path {
   font-size: 11px;
   word-spacing: -1px;
+  margin-bottom: 0;
+  color: -moz-dialogtext;
+  background-color: -moz-dialog;
+  padding: 4px 5px 0;
 }
-.path ol {
+#path ol {
   list-style: none outside none;
   margin: 0;
   padding: 0;
 }
-.path li {
+#path li {
   border-radius: 3px;
   padding: 2px 3px;
-  text-shadow: #FFF 0 1px 0;
-  font-weight: bold;
   font-size: 11px;
-  background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
   display: inline-block;
 }
-.path li:after {
+#path li:after {
   content: " > ";
 }
-.path li:last-child {
-  background: -moz-linear-gradient(top, #FFC, #DD8);
+#path li:last-child {
+  font-weight: bold;
+  color: #0091ff;
 }
-.path li:last-child:after {
-  color: red;
+#path li:last-child:after {
   content: "";
 }
 
 .property-header {
-  padding: 2px 5px;
-  background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
-  color: #666;
+  padding: 4px;
+  -moz-padding-start: 0;
+  -moz-padding-end: 5px;
 }
 
-.property-name,
-.rule-matched,
 .rule-unmatched {
   cursor: pointer;
+  padding: 2px;
+  -moz-padding-start: 4px;
+  -moz-padding-end: 0;
+  white-space: nowrap;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
-.link {
-  color: #55A;
-}
+.link,
 .link:visited {
-  color: #55A;
+  color: #0091ff;
 }
-a.link {
-  text-decoration: none;
-  cursor: pointer;
-}
-a.link:visited {
+.link,
+.helplink,
+.link:visited,
+.helplink:visited {
   text-decoration: none;
 }
 
-.rule-matched,
-.rule-unmatched {
-  padding: 2px 0;
-  white-space: nowrap;
+.helplink-container {
+  position: relative;
+  top: 2px;
+}
+
+.helplink {
+  display: block;
+  height: 14px;
+  width: 0;
+  overflow: hidden;
+  -moz-padding-start: 14px;
+  background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
+  -moz-margin-end: 2px;
+}
+
+.property-header:not(:hover) > .helplink-container {
+  visibility: hidden;
+}
+
+.unmatchedSelectorTable {
+  -moz-margin-start: 15px;
 }
 
 .rulelink {
-  color: #55A;
+  color: -moz-dialogtext;
+  -moz-margin-start: 12px;
 }
 
 .expander {
-  width: 8px;
-  height: 8px;
-  float: left;
-  -moz-margin-start: 15px;
+  -moz-appearance: treetwisty;
+  width: 12px;
+  height: 12px;
+  -moz-margin-start: 5px;
   -moz-margin-end: 5px;
-  margin-top: 3px;
-  background: url("chrome://browser/skin/devtools/arrows.png");
-  background-position: 24px 0;
+}
+
+.expander[open] {
+  -moz-appearance: treetwistyopen;
 }
 
-.searchfield {
-  background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
-  border-radius: 5px;
-  -moz-padding-start: 20px;
-  width: 135px;
-  float: right;
+.expandable {
+  cursor: pointer;
 }
 
-.expander[dir="rtl"] {
-  background-position: 16px 0;
+.match {
+  visibility: hidden;
 }
-.expander[open] {
-  background-position: 8px 0;
+
+.expandable > .match {
+  visibility: visible;
+}
+
+.only-unmatched {
+  -moz-margin-start: 0;
 }
 
 .property-name {
-  display: inline-block;
   font-size: 12px;
-  font-weight: bold;
-  color: #000;
+  color: -moz-FieldText;
+  width: 220px;
 }
 .property-value {
-  display: inline-block;
   font-size: 10px;
+  color: grey;
 }
 
 .property-view-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
-  -moz-padding-start: 10px;
-}
-
-.resizerbox {
-  background-color: window;
+  -moz-padding-start: 15px;
 }
 
 .bestmatch {
   color: black;
 }
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 .unmatched {
   color: brown;
 }
 
-.userStyles {
+#propertyContainer {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-flex: 1;
+  overflow-y: auto;
+}
+
+.selectedElementLabel {
+  font-weight: bold;
+}
+
+.darkrow {
+  background-color: rgba(0,0,0,.022);
+}
+
+#noResults {
+  font-size: 18px;
+  margin-top: 5px;
+  text-align: center;
+}
+
+.headerControls {
+  color: -moz-dialogtext;
+  background-color: -moz-dialog;
+  padding-top: 5px;
+}
+
+.onlyuserstyles,
+.userStylesLabel {
+  cursor: pointer;
+}
+
+.userStylesLabel {
+  display: -moz-box;
+  white-space: nowrap;
+}
+
+.onlyuserstyles {
   position: relative;
   top: 3px;
+  font-family: sans-serif;
+  font-size: 11px;
+}
+
+.searchfield {
+  display: -moz-box;
+  -moz-box-flex: 1;
+  margin-left: 10px;
 }
 
-.userStyles,
-.userStylesLabel {
-  cursor: pointer;
+.styleinspector-legend {
+  -moz-margin-start: 12px;
+}
+
+#footer {
+  border-top: 1px solid -moz-dialog;
+}
+
+.legendKey {
+  margin: 0 5px;
 }
 
 /**
  * CSS Rule View
  */
 
 .ruleview {
   background-color: #FFF;
@@ -224,17 +296,17 @@ a.link:visited {
   width: 8px;
   height: 8px;
   background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
   cursor: pointer;
   -moz-margin-start: 2px;
   -moz-margin-end: 5px;
 }
 
-.ruleview-expander[dir="rtl"] {
+.ruleview-expander:-moz-locale-dir(rtl) {
   background-position: 16px 0;
 }
 
 .ruleview-expander.styleinspector-open {
   background-position: 8px 0;
 }
 
 .ruleview-newproperty {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dbe064863d65ac3123a7a60070114dd465852de2
GIT binary patch
literal 661
zc$@*10&4w<P)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipn-
z2m%$DyLk=(00I?BL_t(2&sCB?Zxc}v#DDkh-PyVG`C^*@2}yxvJ^(@nAt)nCl!gMO
zrA+~m(o!O%NEB%)k%&Zr_zXc%P*5X80V3cS;`rY=j_<v<6iH07(ljHDW@mRiZaj@R
zo#LVY_0?Lx*B_8&BLLz!A}uFeySn6YX1uAe^FI0b=0!^>pCAm;Ism{L!(?)VbC%l=
z9$%(<cL1OO-aWf_e`kBMRg5CyQVFd!)*3(v!hk4_DMk@H+nX)+b}Gk?jkWTJ*N=K}
zsf_O{e5JThEmMwX2m*~0VKf@^<M&^zwG4*??mT>%dSAYMm(h5F)*;GQ)E6&NEClSf
zI~<NDRLU{6*@WG8ht9zOV{+n|5S3+Pl=4xYhgOPWAwWdv4@Ts<q1(>@xN@-yfKrMq
z8>5Z2_(6am7-#vpw-10I094W#fZcWn5D>vShgQCih#(^1pm*W`P@PSvrV0Jwh;DC)
z6NeK4546?_>l~g^oO=`y&lK424*1pX9B(0l6CnsRx)enm^!hl!^VK=wpH3I+9L`w)
zoOL*BC?zSXvAmIra~Nx|#!i6~>Pz#~7w4y(a~2UtV|gQ0qz!X(<;jA{bFBG~d~(F$
z_=sUPnsO%3xwW#sK-w^8D)%}0^!9nnScB)C<n=r_$)$at=F0j!wPt@>x#JUFA2e6D
vlDS%yLZ~q|$CwFWsF|x(Xs&K0ry_uVAQ%nSnI7d%00000NkvXXu0mjf<!Km0
deleted file mode 100644
index df7212d78c8f86e7abe5073d85bf419786993550..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -118,17 +118,17 @@ browser.jar:
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabview/close.png                    (tabview/close.png)
   skin/classic/browser/tabview/edit-light.png               (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png                   (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png           (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png                  (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css                  (tabview/tabview.css)
   skin/classic/browser/devtools/arrows.png                  (devtools/arrows.png)
-  skin/classic/browser/devtools/search.png                  (devtools/search.png)
+  skin/classic/browser/devtools/goto-mdn.png                (devtools/goto-mdn.png)
   skin/classic/browser/devtools/csshtmltree.css             (devtools/csshtmltree.css)
   skin/classic/browser/devtools/gcli.css                    (devtools/gcli.css)
   skin/classic/browser/devtools/toolbarbutton-close.png     (devtools/toolbarbutton-close.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -2563,16 +2563,23 @@ panel[dimmed="true"] {
 
 #status-bar {
   -moz-appearance: none;
   background-color: transparent;
   border: none;
   min-height: 0;
 }
 
+#addon-bar[customizing] > #status-bar {
+  opacity: .5;
+  background-image: -moz-repeating-linear-gradient(-45deg,
+                                                   rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
+                                                   rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
+}
+
 #status-bar > statusbarpanel {
   border-width: 0;
   -moz-appearance: none;
 }
 
 #addonbar-closebutton {
   border: none;
   padding: 0 5px;
index 95e7217927854ed98dd7e55123709ad8baf126f9..447d73938398ff2c09efafc33d14c82252229668
GIT binary patch
literal 882
zc$@)p1C9KNP)<h;3K|Lk000e1NJLTq001xm000OG0ssI2FiGnW00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq-
z3_1diBBnb400Qz!L_t(I%Y~EQPZL=b$G_*^mH~AmOkxE!kyxU*OlPK>mB>B-55BnD
zU2%17YU`_i1Fj)i)&zWq|A1dAxEgIjl+6b4X^lZBZ59Q#YBV(@v|Tmn)NwfbFatKm
z;C(yip8Gl9dwx*wmHx;NC%*|B_|h2}yS})XCL#he0MOQzAPOEj)7o0EX@M_trl+4h
zdi1iY%Kz%sTL460W|wyOuquzYeV5H<?@#@us%k_1-p?XN$8L;XyY}|Y8wR%?`*wYO
zT@VQ=q$DAPq9{Li{dDjC>$`WK%+2NM>vshLJ3q^rnR(XNH~Zkh3#)8@fAYxW<Z`i4
zDip0^(JB_LLZK9o>jHpn+d?3jOkVEkonKh2M2uaZxOBN^Wo5a_?{^#rK-Z}sOO{nx
zpK{qYO%q@u%4Q3{_s(>8|C!0GRdQx$pI^LqXK?Ug@jna9V6?RzsI65XyZ|BugQ}(l
ze69h&{_sIcB$LS-6E}Z3b2^nu|Fg7IQ?2+nrSK*_q=i;imL10dsLJn)L?Qs(HZp_3
z*=(Wrx9MP$nn>um+`IAdOg>){f<OcY2toirJgyH8J_NbXD3Q<sPa%<~iX6w;aGX>s
zt?QbQQcCHjVlcqW4B&k1T*<N+0N5(qVN(YnM8#(T2J-n*F88jXVVA1bc;#g8Qya_x
zIyxHb>Z%1n2s#w3bLY<oup2F<ELql3-H1icy3fL<F~6`lKJiDj;(Kq~l`YV9<LQ$n
zDP`nz<YNwI2w(%dYpW9pqrLs0d)426B9mDg8cO}UTJSc)%ZWt77#R4QfD0FN*W;s2
zDWN0H=VRwS8AH<unMUaGd}`w6Ek*H{%VpOei=OTNwMR&48ljKTM76t>cwF!3X#9lJ
z(h|6O^+Y<oHawhKUCq<x0JgUu92rTeYE4Uvx1K&`1e==TvFJ978aDN?sn0!LxP2#C
zk>l&5&COfp{(WC{ooepvY}|&UX`Za9si#}cXjI#?XUCTLKX2?ZMa}?8lK=n!07*qo
IM6N<$f=Y9k=>Px#
--- a/browser/themes/winstripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/browser/devtools/csshtmltree.css
@@ -17,181 +17,253 @@
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Joe Walker <jwalker@mozilla.com> (original author)
  *   Mihai Șucan <mihai.sucan@gmail.com>
  *   Michael Ratcliffe <mratcliffe@mozilla.com>
+ *   Dão Gottwald <dao@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 ***** */
 
-body {
-  font-family: sans-serif;
-  font-size: 11px;
-  background: #EEE;
+:root {
+  -moz-appearance: none;
+  background: -moz-Field;
+  color: -moz-FieldText;
 }
-.path,
-.filters {
+
+#root {
+  display: -moz-box;
+}
+
+#path {
   font-size: 11px;
   word-spacing: -1px;
+  margin-bottom: 0;
+  color: -moz-dialogtext;
+  background-color: -moz-dialog;
+  padding: 4px 5px 0;
 }
-.path ol {
+#path ol {
   list-style: none outside none;
   margin: 0;
   padding: 0;
 }
-.path li {
+#path li {
   border-radius: 3px;
   padding: 2px 3px;
-  text-shadow: #FFF 0 1px 0;
-  font-weight: bold;
   font-size: 11px;
-  background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
   display: inline-block;
 }
-.path li:after {
+#path li:after {
   content: " > ";
 }
-.path li:last-child {
-  background: -moz-linear-gradient(top, #FFC, #DD8);
+#path li:last-child {
+  font-weight: bold;
+  color: #0091ff;
 }
-.path li:last-child:after {
-  color: red;
+#path li:last-child:after {
   content: "";
 }
 
 .property-header {
-  padding: 2px 5px;
-  background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
-  color: #666;
+  padding: 4px;
+  -moz-padding-start: 0;
+  -moz-padding-end: 5px;
 }
 
-.property-name,
-.rule-matched,
 .rule-unmatched {
   cursor: pointer;
+  padding: 2px;
+  -moz-padding-start: 4px;
+  -moz-padding-end: 0;
+  white-space: nowrap;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
-.link {
-  color: #55A;
-}
+.link,
 .link:visited {
-  color: #55A;
+  color: #0091ff;
 }
-a.link {
-  text-decoration: none;
-  cursor: pointer;
-}
-a.link:visited {
+.link,
+.helplink,
+.link:visited,
+.helplink:visited {
   text-decoration: none;
 }
 
-.rule-matched,
-.rule-unmatched {
-  padding: 2px 0;
-  white-space: nowrap;
+.helplink-container {
+  position: relative;
+  top: 2px;
+}
+
+.helplink {
+  display: block;
+  height: 14px;
+  width: 0;
+  overflow: hidden;
+  -moz-padding-start: 14px;
+  background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
+  -moz-margin-end: 2px;
+}
+
+.property-header:not(:hover) > .helplink-container {
+  visibility: hidden;
+}
+
+.unmatchedSelectorTable {
+  -moz-margin-start: 15px;
 }
 
 .rulelink {
-  color: #55A;
+  color: -moz-dialogtext;
+  -moz-margin-start: 12px;
 }
 
 .expander {
-  width: 8px;
-  height: 8px;
-  float: left;
-  -moz-margin-start: 15px;
+  width: 9px;
+  height: 9px;
+  -moz-margin-start: 5px;
   -moz-margin-end: 5px;
-  margin-top: 3px;
-  background: url("chrome://browser/skin/devtools/arrows.png");
-  background-position: 24px 0;
+  background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
+}
+
+.expander[open] {
+  background-image: url("chrome://global/skin/tree/twisty-open.png");
 }
 
-.searchfield {
-  background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
-  border-radius: 5px;
-  -moz-padding-start: 20px;
-  width: 135px;
-  float: right;
+.expandable {
+  cursor: pointer;
 }
 
-.expander[dir="rtl"] {
-  background-position: 16px 0;
+.match {
+  visibility: hidden;
 }
-.expander[open] {
-  background-position: 8px 0;
+
+.expandable > .match {
+  visibility: visible;
+}
+
+.only-unmatched {
+  -moz-margin-start: 0;
 }
 
 .property-name {
-  display: inline-block;
   font-size: 12px;
-  font-weight: bold;
-  color: #000;
+  color: -moz-FieldText;
+  width: 220px;
 }
 .property-value {
-  display: inline-block;
   font-size: 10px;
+  color: grey;
 }
 
 .property-view-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
-  -moz-padding-start: 10px;
-}
-
-.resizerbox {
-  background-color: window;
+  -moz-padding-start: 15px;
 }
 
 .bestmatch {
   color: black;
 }
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 .unmatched {
   color: brown;
 }
 
-.userStyles {
+#propertyContainer {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-flex: 1;
+  overflow-y: auto;
+}
+
+.selectedElementLabel {
+  font-weight: bold;
+}
+
+.darkrow {
+  background-color: rgba(0,0,0,.022);
+}
+
+#noResults {
+  font-size: 18px;
+  margin-top: 5px;
+  text-align: center;
+}
+
+.headerControls {
+  color: -moz-dialogtext;
+  background-color: -moz-dialog;
+  padding-top: 5px;
+}
+
+.onlyuserstyles,
+.userStylesLabel {
+  cursor: pointer;
+}
+
+.userStylesLabel {
+  display: -moz-box;
+  white-space: nowrap;
+}
+
+.onlyuserstyles {
   position: relative;
   top: 3px;
+  font-family: sans-serif;
+  font-size: 11px;
+}
+
+.searchfield {
+  display: -moz-box;
+  -moz-box-flex: 1;
+  margin-left: 10px;
 }
 
-.userStyles,
-.userStylesLabel {
-  cursor: pointer;
+.styleinspector-legend {
+  -moz-margin-start: 12px;
+}
+
+#footer {
+  border-top: 1px solid -moz-dialog;
+}
+
+.legendKey {
+  margin: 0 5px;
 }
 
 /**
  * CSS Rule View
  */
 
 .ruleview {
   background-color: #FFF;
@@ -224,17 +296,17 @@ a.link:visited {
   width: 8px;
   height: 8px;
   background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
   cursor: pointer;
   -moz-margin-start: 2px;
   -moz-margin-end: 5px;
 }
 
-.ruleview-expander[dir="rtl"] {
+.ruleview-expander:-moz-locale-dir(rtl) {
   background-position: 16px 0;
 }
 
 .ruleview-expander.styleinspector-open {
   background-position: 8px 0;
 }
 
 .ruleview-newproperty {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dbe064863d65ac3123a7a60070114dd465852de2
GIT binary patch
literal 661
zc$@*10&4w<P)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipn-
z2m%$DyLk=(00I?BL_t(2&sCB?Zxc}v#DDkh-PyVG`C^*@2}yxvJ^(@nAt)nCl!gMO
zrA+~m(o!O%NEB%)k%&Zr_zXc%P*5X80V3cS;`rY=j_<v<6iH07(ljHDW@mRiZaj@R
zo#LVY_0?Lx*B_8&BLLz!A}uFeySn6YX1uAe^FI0b=0!^>pCAm;Ism{L!(?)VbC%l=
z9$%(<cL1OO-aWf_e`kBMRg5CyQVFd!)*3(v!hk4_DMk@H+nX)+b}Gk?jkWTJ*N=K}
zsf_O{e5JThEmMwX2m*~0VKf@^<M&^zwG4*??mT>%dSAYMm(h5F)*;GQ)E6&NEClSf
zI~<NDRLU{6*@WG8ht9zOV{+n|5S3+Pl=4xYhgOPWAwWdv4@Ts<q1(>@xN@-yfKrMq
z8>5Z2_(6am7-#vpw-10I094W#fZcWn5D>vShgQCih#(^1pm*W`P@PSvrV0Jwh;DC)
z6NeK4546?_>l~g^oO=`y&lK424*1pX9B(0l6CnsRx)enm^!hl!^VK=wpH3I+9L`w)
zoOL*BC?zSXvAmIra~Nx|#!i6~>Pz#~7w4y(a~2UtV|gQ0qz!X(<;jA{bFBG~d~(F$
z_=sUPnsO%3xwW#sK-w^8D)%}0^!9nnScB)C<n=r_$)$at=F0j!wPt@>x#JUFA2e6D
vlDS%yLZ~q|$CwFWsF|x(Xs&K0ry_uVAQ%nSnI7d%00000NkvXXu0mjf<!Km0
deleted file mode 100644
index df7212d78c8f86e7abe5073d85bf419786993550..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -102,17 +102,17 @@ browser.jar:
         skin/classic/browser/tabview/edit-light.png                 (tabview/edit-light.png)
         skin/classic/browser/tabview/grain.png                      (tabview/grain.png)
         skin/classic/browser/tabview/search.png                     (tabview/search.png)
         skin/classic/browser/tabview/stack-expander.png             (tabview/stack-expander.png)
         skin/classic/browser/tabview/tabview.png                    (tabview/tabview.png)
         skin/classic/browser/tabview/tabview-inverted.png           (tabview/tabview-inverted.png)
         skin/classic/browser/tabview/tabview.css                    (tabview/tabview.css)
         skin/classic/browser/devtools/arrows.png                    (devtools/arrows.png)
-        skin/classic/browser/devtools/search.png                    (devtools/search.png)
+        skin/classic/browser/devtools/goto-mdn.png                  (devtools/goto-mdn.png)
         skin/classic/browser/devtools/csshtmltree.css               (devtools/csshtmltree.css)
         skin/classic/browser/devtools/gcli.css                      (devtools/gcli.css)
         skin/classic/browser/devtools/toolbarbutton-close.png       (devtools/toolbarbutton-close.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
@@ -254,17 +254,17 @@ browser.jar:
         skin/classic/aero/browser/tabview/edit-light.png             (tabview/edit-light.png)
         skin/classic/aero/browser/tabview/grain.png                  (tabview/grain.png)
         skin/classic/aero/browser/tabview/search.png                 (tabview/search.png)
         skin/classic/aero/browser/tabview/stack-expander.png         (tabview/stack-expander.png)
         skin/classic/aero/browser/tabview/tabview.png                (tabview/tabview.png)
         skin/classic/aero/browser/tabview/tabview-inverted.png       (tabview/tabview-inverted.png)
         skin/classic/aero/browser/tabview/tabview.css                (tabview/tabview.css)
         skin/classic/aero/browser/devtools/arrows.png                (devtools/arrows.png)
-        skin/classic/aero/browser/devtools/search.png                (devtools/search.png)
+        skin/classic/aero/browser/devtools/goto-mdn.png              (devtools/goto-mdn.png)
         skin/classic/aero/browser/devtools/csshtmltree.css           (devtools/csshtmltree.css)
         skin/classic/aero/browser/devtools/gcli.css                  (devtools/gcli.css)
         skin/classic/aero/browser/devtools/toolbarbutton-close.png   (devtools/toolbarbutton-close.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
--- a/build/pymake/pymake/process.py
+++ b/build/pymake/pymake/process.py
@@ -210,19 +210,23 @@ class PythonJob(Job):
             if self.method not in m.__dict__:
                 print >>sys.stderr, "No method named '%s' in module %s" % (method, module)
                 return -127
             m.__dict__[self.method](self.argv)
         except PythonException, e:
             print >>sys.stderr, e
             return e.exitcode
         except:
-            print >>sys.stderr, sys.exc_info()[1]
-            print >>sys.stderr, traceback.print_exc()
-            return -127
+            e = sys.exc_info()[1]
+            if isinstance(e, SystemExit) and (e.code == 0 or e.code == '0'):
+                pass # sys.exit(0) is not a failure
+            else:
+                print >>sys.stderr, e
+                print >>sys.stderr, traceback.print_exc()
+                return -127
         finally:
             os.environ = oldenv
         return 0
 
 def job_runner(job):
     """
     Run a job. Called in a Process pool.
     """
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/native-command-sys-exit.mk
@@ -0,0 +1,8 @@
+#T gmake skip
+
+CMD = %pycmd asplode
+PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir
+
+all:
+	$(CMD) 0
+	@echo TEST-PASS
--- a/build/pymake/tests/pycmd.py
+++ b/build/pymake/tests/pycmd.py
@@ -1,9 +1,13 @@
-import os
+import os, sys
 
 def writetofile(args):
   with open(args[0], 'w') as f:
     f.write(' '.join(args[1:]))
 
 def writeenvtofile(args):
   with open(args[0], 'w') as f:
     f.write(os.environ[args[1]])
+
+def asplode(args):
+  sys.exit(args[0])
+  return 0
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -248,17 +248,16 @@ MOZ_NATIVE_PNG	= @SYSTEM_PNG@
 MOZ_TREE_CAIRO = @MOZ_TREE_CAIRO@
 MOZ_TREE_PIXMAN = @MOZ_TREE_PIXMAN@
 
 MOZ_UPDATE_XTERM = @MOZ_UPDATE_XTERM@
 MOZ_PERMISSIONS = @MOZ_PERMISSIONS@
 MOZ_XTF = @MOZ_XTF@
 MOZ_SVG_DLISTS = @MOZ_SVG_DLISTS@
 MOZ_CAIRO_CFLAGS = @MOZ_CAIRO_CFLAGS@
-MOZ_SMIL = @MOZ_SMIL@
 
 MOZ_PREF_EXTENSIONS = @MOZ_PREF_EXTENSIONS@
 
 MOZ_CAIRO_LIBS = @MOZ_CAIRO_LIBS@
 
 MOZ_ENABLE_GNOMEUI = @MOZ_ENABLE_GNOMEUI@
 MOZ_GNOMEUI_CFLAGS = @MOZ_GNOMEUI_CFLAGS@
 MOZ_GNOMEUI_LIBS = @MOZ_GNOMEUI_LIBS@
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -800,21 +800,21 @@ endif
 
 # In the second pass, we need to merge the pgc files into the pgd file.
 # The compiler would do this for us automatically if they were in the right
 # place, but they're in dist/bin.
 ifneq (,$(SHARED_LIBRARY)$(PROGRAM))
 export::
 ifdef PROGRAM
 	$(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \
-	  $(PROGRAM:$(BIN_SUFFIX)=) $(DIST)/$(MOZ_APP_NAME)
+	  $(PROGRAM:$(BIN_SUFFIX)=) $(DIST)/bin
 endif
 ifdef SHARED_LIBRARY
 	$(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \
-	  $(SHARED_LIBRARY_NAME) $(DIST)/$(MOZ_APP_NAME)
+	  $(SHARED_LIBRARY_NAME) $(DIST)/bin
 endif
 endif # SHARED_LIBRARY || PROGRAM
 endif # WINNT_
 endif # MOZ_PROFILE_USE
 ifdef MOZ_PROFILE_GENERATE
 # Clean up profiling data during PROFILE_GENERATE phase
 export::
 ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_)
@@ -1464,30 +1464,30 @@ XPIDL_DEPS = \
   $(topsrcdir)/xpcom/idl-parser/xpidl.py \
   $(NULL)
 
 $(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(XPIDL_GEN_DIR)/.done
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) \
 	  -I$(topsrcdir)/other-licenses/ply \
 	  -I$(topsrcdir)/xpcom/idl-parser \
-	  $(topsrcdir)/xpcom/idl-parser/header.py --cachedir=$(topsrcdir)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
+	  $(topsrcdir)/xpcom/idl-parser/header.py --cachedir=$(DEPTH)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
 	@if test -n "$(findstring $*.h, $(EXPORTS))"; \
 	  then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi
 
 ifndef NO_GEN_XPT
 # generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link
 # into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components.
 $(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_DEPS) $(XPIDL_GEN_DIR)/.done
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) \
 	  -I$(topsrcdir)/other-licenses/ply \
 	  -I$(topsrcdir)/xpcom/idl-parser \
 	  -I$(topsrcdir)/xpcom/typelib/xpt/tools \
-	  $(topsrcdir)/xpcom/idl-parser/typelib.py --cachedir=$(topsrcdir)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
+	  $(topsrcdir)/xpcom/idl-parser/typelib.py --cachedir=$(DEPTH)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
 
 # no need to link together if XPIDLSRCS contains only XPIDL_MODULE
 ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
 $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS)
 	$(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
 endif # XPIDL_MODULE.xpt != XPIDLSRCS
 
 libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
--- a/configure.in
+++ b/configure.in
@@ -6185,28 +6185,16 @@ fi
 dnl ========================================================
 dnl SVG Display Lists
 dnl ========================================================
 if test -n "$MOZ_SVG_DLISTS"; then
   AC_DEFINE(MOZ_SVG_DLISTS)
 fi
 
 dnl ========================================================
-dnl SMIL
-dnl ========================================================
-MOZ_SMIL=1
-MOZ_ARG_DISABLE_BOOL(smil,
-[  --disable-smil          Disable SMIL animation support],
-    MOZ_SMIL=,
-    MOZ_SMIL=1 )
-if test -n "$MOZ_SMIL"; then
-  AC_DEFINE(MOZ_SMIL)
-fi
-
-dnl ========================================================
 dnl Build Freetype in the tree
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(tree-freetype,
 [  --enable-tree-freetype  Enable Tree FreeType],
     MOZ_TREE_FREETYPE=1,
     MOZ_TREE_FREETYPE= )
 if test -n "$MOZ_TREE_FREETYPE"; then
    if test -n "$_WIN32_MSVC"; then
@@ -8288,17 +8276,16 @@ AC_SUBST(FILTER)
 AC_SUBST(BIN_FLAGS)
 AC_SUBST(MOZ_WIDGET_TOOLKIT)
 AC_SUBST(MOZ_UPDATE_XTERM)
 AC_SUBST(MOZ_PLATFORM_MAEMO)
 AC_SUBST(MOZ_AUTH_EXTENSION)
 AC_SUBST(MOZ_PERMISSIONS)
 AC_SUBST(MOZ_XTF)
 AC_SUBST(MOZ_PREF_EXTENSIONS)
-AC_SUBST(MOZ_SMIL)
 AC_SUBST(MOZ_JS_LIBS)
 AC_SUBST(MOZ_PSM)
 AC_SUBST(MOZ_DEBUG)
 AC_SUBST(MOZ_DEBUG_SYMBOLS)
 AC_SUBST(MOZ_DEBUG_ENABLE_DEFS)
 AC_SUBST(MOZ_DEBUG_DISABLE_DEFS)
 AC_SUBST(MOZ_DEBUG_FLAGS)
 AC_SUBST(MOZ_DEBUG_LDFLAGS)
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/693212.xhtml
@@ -0,0 +1,16 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+  function boom() { 
+    select = document.createElementNS("http://www.w3.org/1999/xhtml", "select");
+    text = document.body.childNodes[0];
+    select.setAttribute("onDOMSubtreeModified", "text.parentNode.removeChild(text);");
+    select.appendChild(text);
+  }
+</script>
+</head>
+
+<body onload="boom()">
+
+</body>
+</html>
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -91,9 +91,10 @@ load 637214-1.svg
 load 637214-2.svg
 load 642022-1.html
 load 646184.html
 load 658845-1.svg
 load 667336-1.html
 load 679459.html
 load 679689-1.html
 load 682463.html
+load 693212.xhtml
 load 698974-1.html
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -52,20 +52,18 @@ class nsIContent;
 class nsEventListenerManager;
 class nsIURI;
 class nsRuleWalker;
 class nsAttrValue;
 class nsAttrName;
 class nsTextFragment;
 class nsIDocShell;
 class nsIFrame;
-#ifdef MOZ_SMIL
 class nsISMILAttr;
 class nsIDOMCSSStyleDeclaration;
-#endif // MOZ_SMIL
 
 namespace mozilla {
 namespace css {
 class StyleRule;
 }
 }
 
 enum nsLinkState {
@@ -886,17 +884,16 @@ public:
    */
   nsIFrame* GetPrimaryFrame() const { return mPrimaryFrame; }
   void SetPrimaryFrame(nsIFrame* aFrame) {
     NS_PRECONDITION(!aFrame || !mPrimaryFrame || aFrame == mPrimaryFrame,
                     "Losing track of existing primary frame");
     mPrimaryFrame = aFrame;
   }
 
-#ifdef MOZ_SMIL
   /*
    * Returns a new nsISMILAttr that allows the caller to animate the given
    * attribute on this element.
    *
    * The CALLER OWNS the result and is responsible for deleting it.
    */
   virtual nsISMILAttr* GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName) = 0;
 
@@ -919,17 +916,16 @@ public:
 
   /**
    * Set the SMIL override style rule for this node.  If aNotify is true, this
    * method will notify the document's pres context, so that the style changes
    * will be noticed.
    */
   virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
                                             bool aNotify) = 0;
-#endif // MOZ_SMIL
 
   nsresult LookupNamespaceURI(const nsAString& aNamespacePrefix,
                               nsAString& aNamespaceURI) const;
 
   /**
    * If this content has independent selection, e.g., if this is input field
    * or textarea, this return TRUE.  Otherwise, false.
    */
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -56,19 +56,17 @@
 #include "nsHashKeys.h"
 #include "nsNodeInfoManager.h"
 #include "nsIStreamListener.h"
 #include "nsIVariant.h"
 #include "nsIObserver.h"
 #include "nsGkAtoms.h"
 #include "nsAutoPtr.h"
 #include "nsPIDOMWindow.h"
-#ifdef MOZ_SMIL
 #include "nsSMILAnimationController.h"
-#endif // MOZ_SMIL
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIAnimationFrameListener.h"
 #include "nsEventStates.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIBFCacheEntry.h"
 #include "nsDOMMemoryReporter.h"
 
@@ -740,20 +738,20 @@ public:
    * Returns the element which either requested DOM full-screen mode, or
    * contains the element which requested DOM full-screen mode if the
    * requestee is in a subdocument. Note this element must be *in*
    * this document.
    */
   virtual Element* GetFullScreenElement() = 0;
 
   /**
-   * Requests that the document make aElement the full-screen element,
-   * and move into full-screen mode.
+   * Asynchronously requests that the document make aElement the full-screen
+   * element, and move into full-screen mode.
    */
-  virtual void RequestFullScreen(Element* aElement) = 0;
+  virtual void AsyncRequestFullScreen(Element* aElement) = 0;
 
   /**
    * Requests that the document, and all documents in its hierarchy exit
    * from DOM full-screen mode.
    */
   virtual void CancelFullScreen() = 0;
 
   /**
@@ -1321,27 +1319,25 @@ public:
   bool IsActive() const { return mDocumentContainer && !mRemovedFromDocShell; }
 
   void RegisterFreezableElement(nsIContent* aContent);
   bool UnregisterFreezableElement(nsIContent* aContent);
   typedef void (* FreezableElementEnumerator)(nsIContent*, void*);
   void EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
                                   void* aData);
 
-#ifdef MOZ_SMIL
   // Indicates whether mAnimationController has been (lazily) initialized.
   // If this returns true, we're promising that GetAnimationController()
   // will have a non-null return value.
   bool HasAnimationController()  { return !!mAnimationController; }
 
   // Getter for this document's SMIL Animation Controller. Performs lazy
   // initialization, if this document supports animation and if
   // mAnimationController isn't yet initialized.
   virtual nsSMILAnimationController* GetAnimationController() = 0;
-#endif // MOZ_SMIL
 
   // Makes the images on this document capable of having their animation
   // active or suspended. An Image will animate as long as at least one of its
   // owning Documents needs it to animate; otherwise it can suspend.
   virtual void SetImagesNeedAnimating(bool aAnimating) = 0;
 
   /**
    * Prevents user initiated events from being dispatched to the document and
@@ -1644,20 +1640,18 @@ protected:
   mozilla::css::Loader* mCSSLoader; // [STRONG]
 
   // The set of all object, embed, applet, video and audio elements for
   // which this is the owner document. (They might not be in the document.)
   // These are non-owning pointers, the elements are responsible for removing
   // themselves when they go away.
   nsAutoPtr<nsTHashtable<nsPtrHashKey<nsIContent> > > mFreezableElements;
 
-#ifdef MOZ_SMIL
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
   nsRefPtr<nsSMILAnimationController> mAnimationController;
-#endif // MOZ_SMIL
 
   // Table of element properties for this document.
   nsPropertyTable mPropertyTable;
   nsTArray<nsAutoPtr<nsPropertyTable> > mExtraPropertyTables;
 
   // Compatibility mode
   nsCompatibility mCompatMode;
 
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -279,19 +279,17 @@ private:
   // Its value is always between 0 and 300, inclusive.
   static PRUint32 sMutationCount;
 };
 
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define DOM_USER_DATA_HANDLER 2
-#ifdef MOZ_SMIL
 #define SMIL_MAPPED_ATTR_ANIMVAL 3
-#endif // MOZ_SMIL
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
 { 0x20d16be2, 0x3c58, 0x4099, \
   { 0xbf, 0xa6, 0xd0, 0xe7, 0x6b, 0xb1, 0x3d, 0xc5 } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -180,21 +180,19 @@
 #endif // MOZ_MEDIA
 
 #include "mozAutoDocUpdate.h"
 #include "nsGlobalWindow.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsEventStateManager.h"
 
-#ifdef MOZ_SMIL
 #include "nsSMILAnimationController.h"
 #include "imgIContainer.h"
 #include "nsSVGUtils.h"
-#endif // MOZ_SMIL
 
 #include "nsRefreshDriver.h"
 
 // FOR CSP (autogenerated by xpidl)
 #include "nsIContentSecurityPolicy.h"
 #include "nsCSPService.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsHTMLCSSStyleSheet.h"
@@ -1586,21 +1584,19 @@ nsDocument::~nsDocument()
 
   // Clear mObservers to keep it in sync with the mutationobserver list
   mObservers.Clear();
 
   if (mStyleSheetSetList) {
     mStyleSheetSetList->Disconnect();
   }
 
-#ifdef MOZ_SMIL
   if (mAnimationController) {
     mAnimationController->Disconnect();
   }
-#endif // MOZ_SMIL
 
   mParentDocument = nsnull;
 
   // Kill the subdocument map, doing this will release its strong
   // references, if any.
   if (mSubDocuments) {
     PL_DHashTableDestroy(mSubDocuments);
 
@@ -1873,22 +1869,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPreloadingImages)
 
   for (PRUint32 i = 0; i < tmp->mAnimationFrameListeners.Length(); ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAnimationFrameListeners[i]");
     cb.NoteXPCOMChild(tmp->mAnimationFrameListeners[i]);
   }
 
-#ifdef MOZ_SMIL
   // Traverse animation components
   if (tmp->mAnimationController) {
     tmp->mAnimationController->Traverse(&cb);
   }
-#endif // MOZ_SMIL
 
   if (tmp->mSubDocuments && tmp->mSubDocuments->ops) {
     PL_DHashTableEnumerate(tmp->mSubDocuments, SubDocTraverser, &cb);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
@@ -1950,21 +1944,19 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   tmp->mRadioGroups.Clear();
   
   // nsDocument has a pretty complex destructor, so we're going to
   // assume that *most* cycles you actually want to break somewhere
   // else, and not unlink an awful lot here.
 
   tmp->mIdentifierMap.Clear();
 
-#ifdef MOZ_SMIL
   if (tmp->mAnimationController) {
     tmp->mAnimationController->Unlink();
   }
-#endif // MOZ_SMIL
   
   tmp->mInUnlinkOrDeletion = false;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 nsresult
 nsDocument::Init()
 {
@@ -3763,23 +3755,21 @@ nsDocument::SetScriptGlobalObject(nsIScr
 #ifdef DEBUG
   {
     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobalObject));
 
     NS_ASSERTION(!win || win->IsInnerWindow(),
                  "Script global object must be an inner window!");
   }
 #endif
-#ifdef MOZ_SMIL
   NS_ABORT_IF_FALSE(aScriptGlobalObject || !mAnimationController ||
                     mAnimationController->IsPausedByType(
                         nsSMILTimeContainer::PAUSE_PAGEHIDE |
                         nsSMILTimeContainer::PAUSE_BEGIN),
                     "Clearing window pointer while animations are unpaused");
-#endif // MOZ_SMIL
 
   if (mScriptGlobalObject && !aScriptGlobalObject) {
     // We're detaching from the window.  We need to grab a pointer to
     // our layout history state now.
     mLayoutHistoryState = GetLayoutHistoryState();
 
     if (mPresShell && !EventHandlingSuppressed()) {
       RevokeAnimationFrameNotifications();
@@ -5530,17 +5520,16 @@ nsDocument::RequestExternalResource(nsIU
 }
 
 void
 nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
 {
   mExternalResourceMap.EnumerateResources(aCallback, aData);
 }
 
-#ifdef MOZ_SMIL
 nsSMILAnimationController*
 nsDocument::GetAnimationController()
 {
   // We create the animation controller lazily because most documents won't want
   // one and only SVG documents and the like will call this
   if (mAnimationController)
     return mAnimationController;
   // Refuse to create an Animation Controller if SMIL is disabled, and also
@@ -5565,17 +5554,16 @@ nsDocument::GetAnimationController()
   // controller. (Skip this check for SVG-as-an-image documents, though,
   // because they don't get OnPageShow / OnPageHide calls).
   if (!mIsShowing && !mIsBeingUsedAsImage) {
     mAnimationController->OnPageHide();
   }
 
   return mAnimationController;
 }
-#endif // MOZ_SMIL
 
 struct DirTable {
   const char* mName;
   PRUint8     mValue;
 };
 
 static const DirTable dirAttributes[] = {
   {"ltr", IBMBIDI_TEXTDIRECTION_LTR},
@@ -7274,21 +7262,19 @@ nsDocument::OnPageShow(bool aPersisted,
 
   // See nsIDocument
   if (!aDispatchStartTarget) {
     // Set mIsShowing before firing events, in case those event handlers
     // move us around.
     mIsShowing = true;
   }
  
-#ifdef MOZ_SMIL
   if (mAnimationController) {
     mAnimationController->OnPageShow();
   }
-#endif
 
   if (aPersisted) {
     SetImagesNeedAnimating(true);
   }
 
   UpdateVisibilityState();
 
   nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
@@ -7344,21 +7330,19 @@ nsDocument::OnPageHide(bool aPersisted,
 
   // See nsIDocument
   if (!aDispatchStartTarget) {
     // Set mIsShowing before firing events, in case those event handlers
     // move us around.
     mIsShowing = false;
   }
 
-#ifdef MOZ_SMIL
   if (mAnimationController) {
     mAnimationController->OnPageHide();
   }
-#endif
   
   if (aPersisted) {
     SetImagesNeedAnimating(false);
   }
 
   // Now send out a PageHide event.
   nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
   if (!target) {
@@ -8552,28 +8536,63 @@ GetRootDocument(nsIDocument* aDoc)
     return nsnull;
   nsIDocument* doc = aDoc;
   while (doc->GetParentDocument()) {
     doc = doc->GetParentDocument();
   }
   return doc;
 }
 
-void
-nsDocument::RequestFullScreen(Element* aElement)
-{
-  if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) {
-    if (aElement) {
-      nsRefPtr<nsPLDOMEvent> e =
-        new nsPLDOMEvent(aElement,
-                         NS_LITERAL_STRING("mozfullscreenerror"),
-                         true,
-                         false);
-      e->PostDOMEvent();
-    }
+class nsCallRequestFullScreen : public nsRunnable
+{
+public:
+  nsCallRequestFullScreen(Element* aElement)
+    : mElement(aElement),
+      mDoc(aElement->OwnerDoc()),
+      mWasCallerChrome(nsContentUtils::IsCallerChrome())
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    nsDocument* doc = static_cast<nsDocument*>(mDoc.get());
+    doc->RequestFullScreen(mElement, mWasCallerChrome);
+    return NS_OK;
+  }
+
+  nsRefPtr<Element> mElement;
+  nsCOMPtr<nsIDocument> mDoc;
+  bool mWasCallerChrome;
+};
+
+void
+nsDocument::AsyncRequestFullScreen(Element* aElement)
+{
+  if (!aElement) {
+    return;
+  }
+  // Request full-screen asynchronously.
+  nsCOMPtr<nsIRunnable> event(new nsCallRequestFullScreen(aElement));
+  NS_DispatchToCurrentThread(event);
+}
+
+void
+nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
+{
+  if (!aElement ||
+      !aElement->IsInDoc() ||
+      aElement->OwnerDoc() != this ||
+      !IsFullScreenEnabled(aWasCallerChrome) ||
+      !GetWindow()) {
+    nsRefPtr<nsPLDOMEvent> e =
+      new nsPLDOMEvent(this,
+                       NS_LITERAL_STRING("mozfullscreenerror"),
+                       true,
+                       false);
+    e->PostDOMEvent();
     return;
   }
 
   // Turn off full-screen state in all documents which were previously
   // full-screen but which shouldn't be after this request is granted.
   // Note commonAncestor will be null when in a separate browser window
   // to the requesting document.
   nsIDocument* commonAncestor = nsnull;
@@ -8658,49 +8677,53 @@ nsDocument::GetMozFullScreen(bool *aFull
   *aFullScreen = IsFullScreenDoc();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
 {
   NS_ENSURE_ARG_POINTER(aFullScreen);
-  *aFullScreen = false;
-
-  if (nsContentUtils::IsCallerChrome() &&
-      nsContentUtils::IsFullScreenApiEnabled()) {
+  *aFullScreen = IsFullScreenEnabled(nsContentUtils::IsCallerChrome());
+  return NS_OK;
+}
+
+bool
+nsDocument::IsFullScreenEnabled(bool aCallerIsChrome)
+{
+  if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome) {
     // Chrome code can always use the full-screen API, provided it's not
-    // explicitly disabled.
-    *aFullScreen = true;
-    return NS_OK;
+    // explicitly disabled. Note IsCallerChrome() returns true when running
+    // in an nsRunnable, so don't use GetMozFullScreenEnabled() from an
+    // nsRunnable!
+    return true;
   }
 
   if (!nsContentUtils::IsFullScreenApiEnabled() ||
       nsContentUtils::HasPluginWithUncontrolledEventDispatch(this) ||
       !IsVisible()) {
-    return NS_OK;
+    return false;
   }
 
   // Ensure that all ancestor <iframe> elements have the mozallowfullscreen
   // boolean attribute set.
   nsINode* node = static_cast<nsINode*>(this);
   do {
     nsIContent* content = static_cast<nsIContent*>(node);
     if (content->IsHTML(nsGkAtoms::iframe) &&
         !content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) {
       // The node requesting fullscreen, or one of its crossdoc ancestors,
       // is an iframe which doesn't have the "mozalllowfullscreen" attribute.
       // This request is not authorized by the parent document.
-      return NS_OK;
+      return false;
     }
     node = nsContentUtils::GetCrossDocParentNode(node);
   } while (node);
 
-  *aFullScreen = true;
-  return NS_OK;
+  return true;
 }
 
 PRInt64
 nsDocument::SizeOf() const
 {
   PRInt64 size = MemoryReporter::GetBasicSize<nsDocument, nsIDocument>(this);
   size += mAttrStyleSheet ? mAttrStyleSheet->DOMSizeOf() : 0;
   return size;
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -860,21 +860,19 @@ public:
     RequestExternalResource(nsIURI* aURI,
                             nsINode* aRequestingNode,
                             ExternalResourceLoad** aPendingLoad);
   virtual NS_HIDDEN_(void)
     EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData);
 
   nsTArray<nsCString> mFileDataUris;
 
-#ifdef MOZ_SMIL
   // Returns our (lazily-initialized) animation controller.
   // If HasAnimationController is true, this is guaranteed to return non-null.
   nsSMILAnimationController* GetAnimationController();
-#endif // MOZ_SMIL
 
   void SetImagesNeedAnimating(bool aAnimating);
 
   virtual void SuppressEventHandling(PRUint32 aIncrease);
 
   virtual void UnsuppressEventHandlingAndFireEvents(bool aFireEvents);
   
   void DecreaseEventSuppression() {
@@ -947,33 +945,46 @@ public:
   virtual nsresult GetStateObject(nsIVariant** aResult);
 
   virtual nsDOMNavigationTiming* GetNavigationTiming() const;
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming);
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
 
   virtual Element* GetFullScreenElement();
-  virtual void RequestFullScreen(Element* aElement);
+  virtual void AsyncRequestFullScreen(Element* aElement);
   virtual void CancelFullScreen();
   virtual bool IsFullScreenDoc();
 
+  // This is called asynchronously by nsIDocument::AsyncRequestFullScreen()
+  // to move document into full-screen mode if allowed. aWasCallerChrome
+  // should be true when nsIDocument::AsyncRequestFullScreen() was called
+  // by chrome code.
+  void RequestFullScreen(Element* aElement, bool aWasCallerChrome);
+
   // Returns true if making this change results in a change in the full-screen
   // state of this document.
   bool SetFullScreenState(Element* aElement, bool aIsFullScreen);
  
   // This method may fire a DOM event; if it does so it will happen
   // synchronously.
   void UpdateVisibilityState();
   // Posts an event to call UpdateVisibilityState
   virtual void PostVisibilityUpdateEvent();
 
 protected:
   friend class nsNodeUtils;
 
+  // Returns true if a request for DOM full-screen is currently enabled in
+  // this document. This returns true if there are no windowed plugins in this
+  // doc tree, and if the document is visible, and if the api is not
+  // disabled by pref. aIsCallerChrome must contain the return value of
+  // nsContentUtils::IsCallerChrome() from the context we're checking.
+  bool IsFullScreenEnabled(bool aIsCallerChrome);
+
   /**
    * Check that aId is not empty and log a message to the console
    * service if it is.
    * @returns true if aId looks correct, false otherwise.
    */
   inline bool CheckGetElementByIdArg(const nsAString& aId)
   {
     if (aId.IsEmpty()) {
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -923,17 +923,16 @@ nsGenericDOMDataNode::DoGetClasses() con
 }
 
 NS_IMETHODIMP
 nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
 {
   return NS_OK;
 }
 
-#ifdef MOZ_SMIL
 nsIDOMCSSStyleDeclaration*
 nsGenericDOMDataNode::GetSMILOverrideStyle()
 {
   return nsnull;
 }
 
 css::StyleRule*
 nsGenericDOMDataNode::GetSMILOverrideStyleRule()
@@ -943,17 +942,16 @@ nsGenericDOMDataNode::GetSMILOverrideSty
 
 nsresult
 nsGenericDOMDataNode::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
                                                bool aNotify)
 {
   NS_NOTREACHED("How come we're setting SMILOverrideStyle on a non-element?");
   return NS_ERROR_UNEXPECTED;
 }
-#endif // MOZ_SMIL
 
 css::StyleRule*
 nsGenericDOMDataNode::GetInlineStyleRule()
 {
   return nsnull;
 }
 
 NS_IMETHODIMP
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -47,19 +47,17 @@
 
 #include "nsTextFragment.h"
 #include "nsDOMError.h"
 #include "nsEventListenerManager.h"
 #include "nsGenericElement.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMMemoryReporter.h"
 
-#ifdef MOZ_SMIL
 #include "nsISMILAttr.h"
-#endif // MOZ_SMIL
 
 // This bit is set to indicate that if the text node changes to
 // non-whitespace, we may need to create a frame for it. This bit must
 // not be set on nodes that already have a frame.
 #define NS_CREATE_FRAME_IF_NON_WHITESPACE (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET)
 
 // This bit is set to indicate that if the text node changes to
 // whitespace, we may need to reframe it (or its ancestors).
@@ -223,26 +221,24 @@ public:
   }
   virtual nsresult AppendText(const PRUnichar* aBuffer, PRUint32 aLength,
                               bool aNotify);
   virtual bool TextIsOnlyWhitespace();
   virtual void AppendTextTo(nsAString& aResult);
   virtual void DestroyContent();
   virtual void SaveSubtreeState();
 
-#ifdef MOZ_SMIL
   virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/)
   {
     return nsnull;
   }
   virtual nsIDOMCSSStyleDeclaration* GetSMILOverrideStyle();
   virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule();
   virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
                                             bool aNotify);
-#endif // MOZ_SMIL
 
 #ifdef DEBUG
   virtual void List(FILE* out, PRInt32 aIndent) const;
   virtual void DumpContent(FILE* out, PRInt32 aIndent, bool aDumpAll) const;
 #endif
 
   virtual nsIContent *GetBindingParent() const;
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2288,20 +2288,18 @@ nsGenericElement::nsDOMSlots::~nsDOMSlot
 }
 
 void
 nsGenericElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL)
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
   cb.NoteXPCOMChild(mStyle.get());
 
-#ifdef MOZ_SMIL
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle");
   cb.NoteXPCOMChild(mSMILOverrideStyle.get());
-#endif // MOZ_SMIL
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
   cb.NoteXPCOMChild(mAttributeMap.get());
 
   if (aIsXUL) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers");
     cb.NoteXPCOMChild(mControllers);
   }
@@ -2309,19 +2307,17 @@ nsGenericElement::nsDOMSlots::Traverse(n
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
 }
 
 void
 nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
 {
   mStyle = nsnull;
-#ifdef MOZ_SMIL
   mSMILOverrideStyle = nsnull;
-#endif // MOZ_SMIL
   if (mAttributeMap) {
     mAttributeMap->DropReference();
     mAttributeMap = nsnull;
   }
   if (aIsXUL)
     NS_IF_RELEASE(mControllers);
   mChildrenList = nsnull;
 }
@@ -2451,23 +2447,21 @@ nsGenericElement::InternalIsSupported(ns
              PL_strcasecmp(f, "SVGZoomEvents") == 0 ||
              nsSVGFeatures::HaveFeature(aObject, aFeature)) {
     if (aVersion.IsEmpty() ||
         PL_strcmp(v, "1.0") == 0 ||
         PL_strcmp(v, "1.1") == 0) {
       *aReturn = true;
     }
   }
-#ifdef MOZ_SMIL
   else if (NS_SMILEnabled() && PL_strcasecmp(f, "TimeControl") == 0) {
     if (aVersion.IsEmpty() || PL_strcmp(v, "1.0") == 0) {
       *aReturn = true;
     }
   }
-#endif /* MOZ_SMIL */
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::IsSupported(const nsAString& aFeature,
                               const nsAString& aVersion,
                               bool* aReturn)
@@ -3350,17 +3344,16 @@ nsGenericElement::DoGetClasses() const
 }
 
 NS_IMETHODIMP
 nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
 {
   return NS_OK;
 }
 
-#ifdef MOZ_SMIL
 nsIDOMCSSStyleDeclaration*
 nsGenericElement::GetSMILOverrideStyle()
 {
   nsGenericElement::nsDOMSlots *slots = DOMSlots();
 
   if (!slots->mSMILOverrideStyle) {
     slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, true);
   }
@@ -3393,17 +3386,16 @@ nsGenericElement::SetSMILOverrideStyleRu
       if (shell) {
         shell->RestyleForAnimation(this, eRestyle_Self);
       }
     }
   }
 
   return NS_OK;
 }
-#endif // MOZ_SMIL
 
 css::StyleRule*
 nsGenericElement::GetInlineStyleRule()
 {
   return nsnull;
 }
 
 NS_IMETHODIMP
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -62,19 +62,17 @@
 #include "nsIDOMXPathNSResolver.h"
 #include "nsPresContext.h"
 #include "nsIDOMDOMStringMap.h"
 #include "nsContentList.h"
 #include "nsDOMClassInfoID.h" // DOMCI_DATA
 #include "nsIDOMTouchEvent.h"
 #include "nsIInlineEventHandlers.h"
 
-#ifdef MOZ_SMIL
 #include "nsISMILAttr.h"
-#endif // MOZ_SMIL
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMNamedNodeMap;
 class nsICSSDeclaration;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
@@ -344,26 +342,24 @@ public:
   virtual bool IsLink(nsIURI** aURI) const;
 
   virtual PRUint32 GetScriptTypeID() const;
   NS_IMETHOD SetScriptTypeID(PRUint32 aLang);
 
   virtual void DestroyContent();
   virtual void SaveSubtreeState();
 
-#ifdef MOZ_SMIL
   virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/)
   {
     return nsnull;
   }
   virtual nsIDOMCSSStyleDeclaration* GetSMILOverrideStyle();
   virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule();
   virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
                                             bool aNotify);
-#endif // MOZ_SMIL
 
 #ifdef DEBUG
   virtual void List(FILE* out, PRInt32 aIndent) const
   {
     List(out, aIndent, EmptyCString());
   }
   virtual void DumpContent(FILE* out, PRInt32 aIndent, bool aDumpAll) const;
   void List(FILE* out, PRInt32 aIndent, const nsCString& aPrefix) const;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1363,17 +1363,16 @@ GK_ATOM(xChannelSelector, "xChannelSelec
 GK_ATOM(xor_, "xor")
 GK_ATOM(y, "y")
 GK_ATOM(y1, "y1")
 GK_ATOM(y2, "y2")
 GK_ATOM(yChannelSelector, "yChannelSelector")
 GK_ATOM(z, "z")
 GK_ATOM(zoomAndPan, "zoomAndPan")
 
-#ifdef MOZ_SMIL
 GK_ATOM(accumulate, "accumulate")
 GK_ATOM(additive, "additive")
 GK_ATOM(attributeName, "attributeName")
 GK_ATOM(attributeType, "attributeType")
 GK_ATOM(auto_reverse, "auto-reverse")
 GK_ATOM(begin, "begin")
 GK_ATOM(by, "by")
 GK_ATOM(calcMode, "calcMode")
@@ -1390,17 +1389,16 @@ GK_ATOM(onendEvent, "onendEvent")
 GK_ATOM(onrepeat, "onrepeat")
 GK_ATOM(onrepeatEvent, "onrepeatEvent")
 GK_ATOM(repeatCount, "repeatCount")
 GK_ATOM(repeatDur, "repeatDur")
 GK_ATOM(repeatEvent, "repeatEvent")
 GK_ATOM(restart, "restart")
 GK_ATOM(to, "to")
 GK_ATOM(XML, "XML")
-#endif
 
 // internal MathML attributes: different from columnalign_, columnlines_,
 // fontstyle_, rowalign_ and rowlines_
 GK_ATOM(_moz_math_columnalign_, "_moz-math-columnalign")
 GK_ATOM(_moz_math_columnline_, "_moz-math-columnline")
 GK_ATOM(_moz_math_fontstyle_, "_moz-math-font-style")
 GK_ATOM(_moz_math_rowalign_, "_moz-math-rowalign")
 GK_ATOM(_moz_math_rowline_, "_moz-math-rowline")
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -266,21 +266,17 @@ nsStyledElementNotElementCSSInlineStyle:
   }
     
   nsGenericElement::nsDOMSlots *slots = DOMSlots();
 
   if (!slots->mStyle) {
     // Just in case...
     ReparseStyleAttribute(true);
 
-    slots->mStyle = new nsDOMCSSAttributeDeclaration(this
-#ifdef MOZ_SMIL
-                                                     , false
-#endif // MOZ_SMIL
-                                                     );
+    slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
     SetMayHaveStyle();
   }
 
   *retval = NS_OK;
   return slots->mStyle;
 }
 
 nsresult
--- a/content/base/src/nsTreeSanitizer.cpp
+++ b/content/base/src/nsTreeSanitizer.cpp
@@ -318,17 +318,16 @@ nsIAtom** const kURLAttributesHTML[] = {
   &nsGkAtoms::src,
   &nsGkAtoms::longdesc,
   &nsGkAtoms::cite,
   &nsGkAtoms::background,
   nsnull
 };
 
 nsIAtom** const kElementsSVG[] = {
-#ifdef MOZ_SVG
   &nsGkAtoms::a, // a
   &nsGkAtoms::altGlyph, // altGlyph
   &nsGkAtoms::altGlyphDef, // altGlyphDef
   &nsGkAtoms::altGlyphItem, // altGlyphItem
   &nsGkAtoms::animate, // animate
   &nsGkAtoms::animateColor, // animateColor
   &nsGkAtoms::animateMotion, // animateMotion
   &nsGkAtoms::animateTransform, // animateTransform
@@ -402,49 +401,39 @@ nsIAtom** const kElementsSVG[] = {
   &nsGkAtoms::text, // text
   &nsGkAtoms::textPath, // textPath
   &nsGkAtoms::title, // title
   &nsGkAtoms::tref, // tref
   &nsGkAtoms::tspan, // tspan
   &nsGkAtoms::use, // use
   &nsGkAtoms::view, // view
   &nsGkAtoms::vkern, // vkern
-#endif
   nsnull
 };
 
 nsIAtom** const kAttributesSVG[] = {
-#ifdef MOZ_SVG
   // accent-height
-#ifdef MOZ_SMIL
   &nsGkAtoms::accumulate, // accumulate
   &nsGkAtoms::additive, // additive
-#endif
   &nsGkAtoms::alignment_baseline, // alignment-baseline
   // alphabetic
   &nsGkAtoms::amplitude, // amplitude
   // arabic-form
   // ascent
-#ifdef MOZ_SMIL
   &nsGkAtoms::attributeName, // attributeName
   &nsGkAtoms::attributeType, // attributeType
-#endif
   &nsGkAtoms::azimuth, // azimuth
   &nsGkAtoms::baseFrequency, // baseFrequency
   &nsGkAtoms::baseline_shift, // baseline-shift
   // baseProfile
   // bbox
-#ifdef MOZ_SMIL
   &nsGkAtoms::begin, // begin
-#endif
   &nsGkAtoms::bias, // bias
-#ifdef MOZ_SMIL
   &nsGkAtoms::by, // by
   &nsGkAtoms::calcMode, // calcMode
-#endif
   // cap-height
   &nsGkAtoms::_class, // class
   &nsGkAtoms::clip_path, // clip-path
   &nsGkAtoms::clip_rule, // clip-rule
   &nsGkAtoms::clipPathUnits, // clipPathUnits
   &nsGkAtoms::color, // color
   &nsGkAtoms::colorInterpolation, // color-interpolation
   &nsGkAtoms::colorInterpolationFilters, // color-interpolation-filters
@@ -455,27 +444,23 @@ nsIAtom** const kAttributesSVG[] = {
   &nsGkAtoms::cy, // cy
   &nsGkAtoms::d, // d
   // descent
   &nsGkAtoms::diffuseConstant, // diffuseConstant
   &nsGkAtoms::direction, // direction
   &nsGkAtoms::display, // display
   &nsGkAtoms::divisor, // divisor
   &nsGkAtoms::dominant_baseline, // dominant-baseline
-#ifdef MOZ_SMIL
   &nsGkAtoms::dur, // dur
-#endif
   &nsGkAtoms::dx, // dx
   &nsGkAtoms::dy, // dy
   &nsGkAtoms::edgeMode, // edgeMode
   &nsGkAtoms::elevation, // elevation
   // enable-background
-#ifdef MOZ_SMIL
   &nsGkAtoms::end, // end
-#endif
   &nsGkAtoms::fill, // fill
   &nsGkAtoms::fill_opacity, // fill-opacity
   &nsGkAtoms::fill_rule, // fill-rule
   &nsGkAtoms::filter, // filter
   &nsGkAtoms::filterRes, // filterRes
   &nsGkAtoms::filterUnits, // filterUnits
   &nsGkAtoms::flood_color, // flood-color
   &nsGkAtoms::flood_opacity, // flood-opacity
@@ -513,21 +498,19 @@ nsIAtom** const kAttributesSVG[] = {
   // k
   &nsGkAtoms::k1, // k1
   &nsGkAtoms::k2, // k2
   &nsGkAtoms::k3, // k3
   &nsGkAtoms::k4, // k4
   &nsGkAtoms::kerning, // kerning
   &nsGkAtoms::kernelMatrix, // kernelMatrix
   &nsGkAtoms::kernelUnitLength, // kernelUnitLength
-#ifdef MOZ_SMIL
   &nsGkAtoms::keyPoints, // keyPoints
   &nsGkAtoms::keySplines, // keySplines
   &nsGkAtoms::keyTimes, // keyTimes
-#endif
   &nsGkAtoms::lang, // lang
   // lengthAdjust
   &nsGkAtoms::letter_spacing, // letter-spacing
   &nsGkAtoms::lighting_color, // lighting-color
   &nsGkAtoms::limitingConeAngle, // limitingConeAngle
   // local
   &nsGkAtoms::marker, // marker
   &nsGkAtoms::marker_end, // marker-end
@@ -570,25 +553,21 @@ nsIAtom** const kAttributesSVG[] = {
   &nsGkAtoms::pointsAtZ, // pointsAtZ
   &nsGkAtoms::preserveAlpha, // preserveAlpha
   &nsGkAtoms::preserveAspectRatio, // preserveAspectRatio
   &nsGkAtoms::primitiveUnits, // primitiveUnits
   &nsGkAtoms::r, // r
   &nsGkAtoms::radius, // radius
   &nsGkAtoms::refX, // refX
   &nsGkAtoms::refY, // refY
-#ifdef MOZ_SMIL
   &nsGkAtoms::repeatCount, // repeatCount
   &nsGkAtoms::repeatDur, // repeatDur
-#endif
   &nsGkAtoms::requiredExtensions, // requiredExtensions
   &nsGkAtoms::requiredFeatures, // requiredFeatures
-#ifdef MOZ_SMIL
   &nsGkAtoms::restart, // restart
-#endif
   &nsGkAtoms::result, // result
   &nsGkAtoms::rotate, // rotate
   &nsGkAtoms::rx, // rx
   &nsGkAtoms::ry, // ry
   &nsGkAtoms::scale, // scale
   &nsGkAtoms::seed, // seed
   &nsGkAtoms::shape_rendering, // shape-rendering
   &nsGkAtoms::slope, // slope
@@ -620,19 +599,17 @@ nsIAtom** const kAttributesSVG[] = {
   &nsGkAtoms::target, // target
   &nsGkAtoms::targetX, // targetX
   &nsGkAtoms::targetY, // targetY
   &nsGkAtoms::text_anchor, // text-anchor
   &nsGkAtoms::text_decoration, // text-decoration
   // textLength
   &nsGkAtoms::text_rendering, // text-rendering
   &nsGkAtoms::title, // title
-#ifdef MOZ_SMIL
   &nsGkAtoms::to, // to
-#endif
   &nsGkAtoms::transform, // transform
   &nsGkAtoms::type, // type
   // u1
   // u2
   // underline-position
   // underline-thickness
   // unicode
   &nsGkAtoms::unicode_bidi, // unicode-bidi
@@ -659,17 +636,16 @@ nsIAtom** const kAttributesSVG[] = {
   &nsGkAtoms::x2, // x2
   &nsGkAtoms::xChannelSelector, // xChannelSelector
   &nsGkAtoms::y, // y
   &nsGkAtoms::y1, // y1
   &nsGkAtoms::y2, // y2
   &nsGkAtoms::yChannelSelector, // yChannelSelector
   &nsGkAtoms::z, // z
   &nsGkAtoms::zoomAndPan, // zoomAndPan
-#endif
   nsnull
 };
 
 nsIAtom** const kURLAttributesSVG[] = {
   nsnull
 };
 
 nsIAtom** const kElementsMathML[] = {
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -643,17 +643,16 @@ NON_IDL_EVENT(SVGZoom,
               NS_SVG_ZOOM,
               EventNameType_None,
               NS_SVGZOOM_EVENT)
 // This is a bit hackish, but SVG's event names are weird.
 NON_IDL_EVENT(zoom,
               NS_SVG_ZOOM,
               EventNameType_SVGSVG,
               NS_EVENT_NULL)
-#ifdef MOZ_SMIL
 NON_IDL_EVENT(begin,
               NS_SMIL_BEGIN,
               EventNameType_SMIL,
               NS_EVENT_NULL)
 NON_IDL_EVENT(beginEvent,
               NS_SMIL_BEGIN,
               EventNameType_None,
               NS_SMIL_TIME_EVENT)
@@ -668,17 +667,16 @@ NON_IDL_EVENT(endEvent,
 NON_IDL_EVENT(repeat,
               NS_SMIL_REPEAT,
               EventNameType_SMIL,
               NS_EVENT_NULL)
 NON_IDL_EVENT(repeatEvent,
               NS_SMIL_REPEAT,
               EventNameType_None,
               NS_SMIL_TIME_EVENT)
-#endif // MOZ_SMIL
 
 NON_IDL_EVENT(MozAudioAvailable,
               NS_MOZAUDIOAVAILABLE,
               EventNameType_None,
               NS_EVENT_NULL)
 NON_IDL_EVENT(MozAfterPaint,
               NS_AFTERPAINT,
               EventNameType_None,
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -100,20 +100,18 @@ NS_NewDOMTextEvent(nsIDOMEvent** aResult
 nsresult
 NS_NewDOMBeforeUnloadEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMPageTransitionEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMSVGEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
 NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsGUIEvent* aEvent);
-#ifdef MOZ_SMIL
 nsresult
 NS_NewDOMTimeEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
-#endif // MOZ_SMIL
 nsresult
 NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsInputEvent* aEvent);
 nsresult
 NS_NewDOMCommandEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsCommandEvent* aEvent);
 nsresult
 NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
 NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -80,19 +80,17 @@ static const char* const sEventNames[] =
   "DOMSubtreeModified", "DOMNodeInserted", "DOMNodeRemoved", 
   "DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument",
   "DOMAttrModified", "DOMCharacterDataModified",
   "DOMActivate", "DOMFocusIn", "DOMFocusOut",
   "pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll",
   "offline", "online", "copy", "cut", "paste", "open", "message", "show",
   "SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
   "SVGZoom",
-#ifdef MOZ_SMIL
   "beginEvent", "endEvent", "repeatEvent",
-#endif // MOZ_SMIL
 #ifdef MOZ_MEDIA
   "loadstart", "progress", "suspend", "emptied", "stalled", "play", "pause",
   "loadedmetadata", "loadeddata", "waiting", "playing", "canplay",
   "canplaythrough", "seeking", "seeked", "timeupdate", "ended", "ratechange",
   "durationchange", "volumechange", "MozAudioAvailable",
 #endif // MOZ_MEDIA
   "MozAfterPaint",
   "MozBeforePaint",
@@ -799,25 +797,23 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
     }
     case NS_SVGZOOM_EVENT:
     {
       newEvent = new nsGUIEvent(false, msg, nsnull);
       NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
       newEvent->eventStructType = NS_SVGZOOM_EVENT;
       break;
     }
-#ifdef MOZ_SMIL
     case NS_SMIL_TIME_EVENT:
     {
       newEvent = new nsUIEvent(false, msg, 0);
       NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
       newEvent->eventStructType = NS_SMIL_TIME_EVENT;
       break;
     }
-#endif // MOZ_SMIL
     case NS_SIMPLE_GESTURE_EVENT:
     {
       nsSimpleGestureEvent* oldSimpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
       nsSimpleGestureEvent* simpleGestureEvent = 
         new nsSimpleGestureEvent(false, msg, nsnull, 0, 0.0);
       NS_ENSURE_TRUE(simpleGestureEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
       simpleGestureEvent->direction = oldSimpleGestureEvent->direction;
@@ -1290,24 +1286,22 @@ const char* nsDOMEvent::GetEventName(PRU
   case NS_SVG_ERROR:
     return sEventNames[eDOMEvents_SVGError];
   case NS_SVG_RESIZE:
     return sEventNames[eDOMEvents_SVGResize];
   case NS_SVG_SCROLL:
     return sEventNames[eDOMEvents_SVGScroll];
   case NS_SVG_ZOOM:
     return sEventNames[eDOMEvents_SVGZoom];
-#ifdef MOZ_SMIL
   case NS_SMIL_BEGIN:
     return sEventNames[eDOMEvents_beginEvent];
   case NS_SMIL_END:
     return sEventNames[eDOMEvents_endEvent];
   case NS_SMIL_REPEAT:
     return sEventNames[eDOMEvents_repeatEvent];
-#endif // MOZ_SMIL
 #ifdef MOZ_MEDIA
   case NS_LOADSTART:
     return sEventNames[eDOMEvents_loadstart];
   case NS_PROGRESS:
     return sEventNames[eDOMEvents_progress];
   case NS_SUSPEND:
     return sEventNames[eDOMEvents_suspend];
   case NS_EMPTIED:
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -144,21 +144,19 @@ public:
     eDOMEvents_show,
     eDOMEvents_SVGLoad,
     eDOMEvents_SVGUnload,
     eDOMEvents_SVGAbort,
     eDOMEvents_SVGError,
     eDOMEvents_SVGResize,
     eDOMEvents_SVGScroll,
     eDOMEvents_SVGZoom,
-#ifdef MOZ_SMIL
     eDOMEvents_beginEvent,
     eDOMEvents_endEvent,
     eDOMEvents_repeatEvent,
-#endif // MOZ_SMIL
 #ifdef MOZ_MEDIA
     eDOMEvents_loadstart,
     eDOMEvents_progress,
     eDOMEvents_suspend,
     eDOMEvents_emptied,
     eDOMEvents_stalled,
     eDOMEvents_play,
     eDOMEvents_pause,
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -787,20 +787,18 @@ nsEventDispatcher::CreateEvent(nsPresCon
       return NS_NewDOMTextEvent(aDOMEvent, aPresContext,
                                 static_cast<nsTextEvent*>(aEvent));
     case NS_SVG_EVENT:
       return NS_NewDOMSVGEvent(aDOMEvent, aPresContext,
                                aEvent);
     case NS_SVGZOOM_EVENT:
       return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext,
                                    static_cast<nsGUIEvent*>(aEvent));
-#ifdef MOZ_SMIL
     case NS_SMIL_TIME_EVENT:
       return NS_NewDOMTimeEvent(aDOMEvent, aPresContext, aEvent);
-#endif // MOZ_SMIL
 
     case NS_COMMAND_EVENT:
       return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
                                    static_cast<nsCommandEvent*>(aEvent));
     case NS_SIMPLE_GESTURE_EVENT:
       return NS_NewDOMSimpleGestureEvent(aDOMEvent, aPresContext,
                                          static_cast<nsSimpleGestureEvent*>(aEvent));
     case NS_MOZTOUCH_EVENT:
@@ -854,21 +852,19 @@ nsEventDispatcher::CreateEvent(nsPresCon
       aEventType.LowerCaseEqualsLiteral("htmlevents"))
     return NS_NewDOMEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("svgevent") ||
       aEventType.LowerCaseEqualsLiteral("svgevents"))
     return NS_NewDOMSVGEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") ||
       aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
     return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext, nsnull);
-#ifdef MOZ_SMIL
   if (aEventType.LowerCaseEqualsLiteral("timeevent") ||
       aEventType.LowerCaseEqualsLiteral("timeevents"))
     return NS_NewDOMTimeEvent(aDOMEvent, aPresContext, nsnull);
-#endif // MOZ_SMIL
   if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
       aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
     return NS_NewDOMXULCommandEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
       aEventType.LowerCaseEqualsLiteral("commandevents"))
     return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, nsnull);
   if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
       aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -619,24 +619,22 @@ nsEventListenerManager::CompileEventHand
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGError)
         attrName = nsGkAtoms::onerror;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGResize)
         attrName = nsGkAtoms::onresize;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGScroll)
         attrName = nsGkAtoms::onscroll;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGZoom)
         attrName = nsGkAtoms::onzoom;
-#ifdef MOZ_SMIL
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onbeginEvent)
         attrName = nsGkAtoms::onbegin;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onrepeatEvent)
         attrName = nsGkAtoms::onrepeat;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onendEvent)
         attrName = nsGkAtoms::onend;
-#endif // MOZ_SMIL
 
       content->GetAttr(kNameSpaceID_None, attrName, handlerBody);
       body = &handlerBody;
     }
 
     PRUint32 lineNo = 0;
     nsCAutoString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
     nsCOMPtr<nsIDocument> doc;
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3399,49 +3399,28 @@ nsGenericHTMLElement::Focus()
 
 nsresult nsGenericHTMLElement::MozRequestFullScreen()
 {
   // Only grant full-screen requests if this is called from inside a trusted
   // event handler (i.e. inside an event handler for a user initiated event).
   // This stops the full-screen from being abused similar to the popups of old,
   // and it also makes it harder for bad guys' script to go full-screen and
   // spoof the browser chrome/window and phish logins etc.
-  nsIDocument* doc = OwnerDoc();
-  if (!nsContentUtils::IsRequestFullScreenAllowed() ||
-      !IsInDoc()) {
+  if (!nsContentUtils::IsRequestFullScreenAllowed()) {
     nsRefPtr<nsPLDOMEvent> e =
-      new nsPLDOMEvent(this,
+      new nsPLDOMEvent(OwnerDoc(),
                        NS_LITERAL_STRING("mozfullscreenerror"),
                        true,
                        false);
     e->PostDOMEvent();
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(doc));
-  NS_ENSURE_STATE(domDocument);
-  bool fullScreenEnabled;
-  domDocument->GetMozFullScreenEnabled(&fullScreenEnabled);
-  if (!fullScreenEnabled) {
-    nsRefPtr<nsPLDOMEvent> e =
-      new nsPLDOMEvent(this,
-                       NS_LITERAL_STRING("mozfullscreenerror"),
-                       true,
-                       false);
-    e->PostDOMEvent();
-    return NS_OK;
-  }
-
-  doc->RequestFullScreen(this);
-#ifdef DEBUG
-  bool fullscreen;
-  domDocument->GetMozFullScreen(&fullscreen);
-  NS_ASSERTION(fullscreen, "Document should report fullscreen");
-  NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");
-#endif
+  OwnerDoc()->AsyncRequestFullScreen(this);
+
   return NS_OK;
 }
 
 nsresult nsGenericHTMLElement::Click()
 {
   if (HasFlag(NODE_HANDLING_CLICK))
     return NS_OK;
 
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -278,16 +278,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug677658.html \
 		test_bug677463.html \
 		test_bug682886.html \
 		file_fullscreen-api.html \
 		file_fullscreen-api-keys.html \
 		test_fullscreen-api.html \
 		file_fullscreen-plugins.html \
 		file_fullscreen-denied.html \
+		file_fullscreen-denied-inner.html \
 		file_fullscreen-hidden.html \
 		file_fullscreen-navigation.html \
 		test_li_attributes_reflection.html \
 		test_ol_attributes_reflection.html \
 		test_bug651956.html \
 		test_bug694503.html \
 		$(NULL)
 
--- a/content/html/content/test/file_fullscreen-api-keys.html
+++ b/content/html/content/test/file_fullscreen-api-keys.html
@@ -89,25 +89,29 @@ function testScriptInitiatedKeyEvents() 
   ok(document.mozFullScreen,
      "Should remain in full-screen mode for script initiated key events for " + gKeyName);
 }
 
 function testNextKey() {
   if (!document.mozFullScreen) {
     document.body.mozRequestFullScreen();
   }
-  ok(document.mozFullScreen, "Must be in full-screen mode");
+  // mozRequestFullScreen() is async...
+  setTimeout(
+    function() {
+      ok(document.mozFullScreen, "Must be in full-screen mode");
 
-  gKeyName = keyList[gKeyTestIndex].code;
-  gKeyCode = KeyEvent["DOM_" + gKeyName];
-  gKeySuppressed = keyList[gKeyTestIndex].suppressed;
-  gKeyTestIndex++;
+      gKeyName = keyList[gKeyTestIndex].code;
+      gKeyCode = KeyEvent["DOM_" + gKeyName];
+      gKeySuppressed = keyList[gKeyTestIndex].suppressed;
+      gKeyTestIndex++;
 
-  testScriptInitiatedKeyEvents();
-  testTrustedKeyEvents();
+      testScriptInitiatedKeyEvents();
+      testTrustedKeyEvents();
+    }, 0);
 }
 
 window.addEventListener("keydown", keyHandler, true);
 window.addEventListener("keyup", keyHandler, true);
 window.addEventListener("keypress", keyHandler, true);
 setTimeout(testNextKey, 0);
 
 </script>
--- a/content/html/content/test/file_fullscreen-api.html
+++ b/content/html/content/test/file_fullscreen-api.html
@@ -93,48 +93,61 @@ function fullScreenChange(event) {
     case 2: {
       ok(document.mozFullScreen, "Should be back in full-screen mode (second time)");
       is(event.target, iframe,
          "Event target should be full-screen element container");
       is(document.mozFullScreenElement, iframe,
         "Full-screen element should be iframe element.");
       var fse = fullScreenElement();
       fse.mozRequestFullScreen();
-      ok(document.mozFullScreen, "Should still be full-screen mode after re-requesting.");
-      is(document.mozFullScreenElement, fse, "Full-screen element should have switched to requestee.");
-      var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
-      _innerFrame.contentDocument.body.appendChild(fse);
-      ok(!document.mozFullScreen, "Should exit full-screen after transplanting FSE");
-      is(document.mozFullScreenElement, null, "Full-screen element transplanted, should be null.");
-      is(iframe.contentDocument.mozFullScreenElement, null, "Full-screen element in outer frame should be null.");
-      is(_innerFrame.contentDocument.mozFullScreenElement, null, "Full-screen element in inner frame should be null.");
-      ok(!iframe.contentDocument.mozFullScreen, "Outer frame should not acquire full-screen status.");
-      ok(!_innerFrame.contentDocument.mozFullScreen, "Inner frame should not acquire full-screen status.");
       
-      document.body.appendChild(fse);
+      setTimeout(
+        function() {
+          ok(document.mozFullScreen, "Should still be full-screen mode after re-requesting.");
+          is(document.mozFullScreenElement, fse, "Full-screen element should have switched to requestee.");
+          var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
+          _innerFrame.contentDocument.body.appendChild(fse);
+          ok(!document.mozFullScreen, "Should exit full-screen after transplanting FSE");
+          is(document.mozFullScreenElement, null, "Full-screen element transplanted, should be null.");
+          is(iframe.contentDocument.mozFullScreenElement, null, "Full-screen element in outer frame should be null.");
+          is(_innerFrame.contentDocument.mozFullScreenElement, null, "Full-screen element in inner frame should be null.");
+          ok(!iframe.contentDocument.mozFullScreen, "Outer frame should not acquire full-screen status.");
+          ok(!_innerFrame.contentDocument.mozFullScreen, "Inner frame should not acquire full-screen status.");
+          
+          document.body.appendChild(fse);
+        }, 0);
+      
       break;
     }
     case 3: {
       ok(!document.mozFullScreen, "Should be back in non-full-screen mode (second time)");
       is(event.target, document,
          "Event target should be full-screen element container");
       is(document.mozFullScreenElement, null, "Full-screen element should be null.");
       document.body.removeChild(iframe);
       iframe = null;
+      
+      // Do a request out of document. It should be denied.
+      // Continue test in the following mozfullscreenerror handler.
       outOfDocElement = document.createElement("div");
-      outOfDocElement.mozRequestFullScreen();
-      ok(!document.mozFullScreen, "Requests for full-screen from not-in-doc elements should fail.");
+      var f =
+      function(e) {
+        document.removeEventListener("mozfullscreenerror", f, false);
+        ok(!document.mozFullScreen, "Requests for full-screen from not-in-doc elements should fail.");
 
-      container = document.createElement("div");
-      inDocElement = document.createElement("div");
-      container.appendChild(inDocElement);
-      fullScreenElement().appendChild(container);
-      
-      inDocElement.mozRequestFullScreen();
-      ok(document.mozFullScreen, "Should grant request to return to full-screen mode (third time)");
+        container = document.createElement("div");
+        inDocElement = document.createElement("div");
+        container.appendChild(inDocElement);
+        fullScreenElement().appendChild(container);
+        
+        inDocElement.mozRequestFullScreen();
+      };
+      document.addEventListener("mozfullscreenerror", f, false);
+      outOfDocElement.mozRequestFullScreen();
+
       break;
     }
     case 4: {
       ok(document.mozFullScreen, "Should still be in full-screen mode (third time)");
       is(event.target, inDocElement, "Event target should be inDocElement");
       is(document.mozFullScreenElement, inDocElement,
         "FSE should be inDocElement.");       
       
@@ -152,21 +165,21 @@ function fullScreenChange(event) {
         "Should not have a full-screen element again.");
       break;
     }
     case 5: {
       ok(!document.mozFullScreen, "Should be back in non-full-screen mode (third time)");
       setRequireTrustedContext(true);
       fullscreendenied = false;
       fullScreenElement().mozRequestFullScreen();
-      ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
 
       setTimeout(
         function() {
           ok(fullscreendenied, "Request for fullscreen should have been denied because calling context isn't trusted");
+          ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
           button = document.createElement("button");
           button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
           fullScreenElement().appendChild(button);
           sendMouseClick(button);
         }, 0);
       break;
     }
     case 6: {
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_fullscreen-denied-inner.html
@@ -0,0 +1,22 @@
+<html>
+  <body onload='foo();'>
+  <script>
+    function foo() {
+      document.addEventListener('mozfullscreenerror',
+        function() {
+          parent.ok(true, "Request from an iframe without mozallowfullscreen should be denied");
+          parent.finish();
+        },
+        false);
+      document.addEventListener('mozfullscreenchange',
+        function() {
+          parent.ok(false, "Request from an iframe without mozallowfullscreen should be denied, but was granted!");
+          parent.finish();
+        },
+        false);
+      parent.is(document.mozFullScreenEnabled, false, "Full-screen should not be enabled, coz mozallowfullscreen isn't present.");
+      document.body.mozRequestFullScreen();    
+    }
+  </script>
+  </body>
+</html>
--- a/content/html/content/test/file_fullscreen-denied.html
+++ b/content/html/content/test/file_fullscreen-denied.html
@@ -24,24 +24,16 @@ Test DOM full-screen API.
 function ok(condition, msg) {
   opener.ok(condition, msg);
 }
 
 function is(a, b, msg) {
   opener.is(a, b, msg);
 }
 
-/*
-<html>
-  <body onload='document.body.mozRequestFullScreen();'>
-  </body>
-</html>
-*/
-var requestFullScreenContents = "data:text/html;charset=utf-8,<html>%0D%0A  <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A  <%2Fbody>%0D%0A<%2Fhtml>";
-
 var fullscreendenied = false;
 
 document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
 
 var gotFullScreenChange = false;
 
 function run() {
   document.addEventListener("mozfullscreenchange",
@@ -49,18 +41,18 @@ function run() {
       ok(false, "Should never receive a mozfullscreenchange event in the main window.");
       gotFullScreenChange = true;
     },
     false);
 
   // Request full-screen from a non trusted context (this script isn't a user
   // generated event!).
   SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
+  fullscreendenied = false;
   document.body.mozRequestFullScreen();
-  fullscreendenied = false;
   setTimeout(
     function() {
       ok(!document.mozFullScreen, "Should not grant request in non-truested context");
       ok(fullscreendenied, "Request in non-trusted event handler should be denied");
       // Test requesting full-screen mode in a long-running user-generated event handler.
       // The request in the key handler should not be granted.
       window.addEventListener("keypress", keyHandler, false);
       synthesizeKey("VK_A", {});
@@ -82,28 +74,27 @@ function keyHandler(event) {
     function() {
       ok(fullscreendenied, "Request in long running event handler should be denied");
       ok(!document.mozFullScreen, "Should not grant request in long-running event handler.");
       
       // Disable the requirement for trusted contexts only, so the tests are easier
       // to write.
       SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);  
       
-      // Create an iframe without a mozallowfullscreen sttribute, whose contents requests
+      // Create an iframe without a mozallowfullscreen attribute, whose contents requests
       // full-screen. The request should be denied, and we should not receive a fullscreenchange
       // event in this document.
       var iframe = document.createElement("iframe");
-      iframe.src = requestFullScreenContents;
+      iframe.src = "file_fullscreen-denied-inner.html";
       document.body.appendChild(iframe);
-     
-      setTimeout(
-        function() {
-          ok(!gotFullScreenChange, "Should not ever grant a fullscreen request in this doc.");
-          opener.nextTest();
-        }, 0);
     }, 0);
 }
 
+function finish() {
+  ok(!gotFullScreenChange, "Should not ever grant a fullscreen request in this doc.");
+  opener.nextTest();
+}
+
 </script>
 </pre>
 <div id="full-screen-element"></div>
 </body>
 </html>
--- a/content/html/content/test/file_fullscreen-plugins.html
+++ b/content/html/content/test/file_fullscreen-plugins.html
@@ -69,25 +69,36 @@ function scheduleTest() {
 function startTest() {
   ok(!document.mozFullScreen, "Should not be in full-screen mode initially");
   document.body.mozRequestFullScreen();
 
   if (isMacOs) {
     // Running on MacOS, all plugins are effectively windowless, request for full-screen should be granted.
     // Continue test in the (mac-specific) "mozfullscreenchange" handler.
     return;
+  } else {
+    // Non-MacOS, request should be denied, carry on the test after receiving error event.
+    document.addEventListener("mozfullscreenerror", nonMacTest, false);
   }
+}
 
+function nonMacTest() {
+  document.removeEventListener("mozfullscreenerror", nonMacTest, false);
   ok(!document.mozFullScreen, "Request for full-screen from a document containing windowed plugin should be denied.");
 
   // Remove plugin in this document. Should still be a windowed plugin in sub-document.
   windowedPlugin = document.getElementById("windowed-plugin");
   windowedPlugin.parentNode.removeChild(windowedPlugin);
 
+  document.addEventListener("mozfullscreenerror", nonMacTest2, false);
   document.body.mozRequestFullScreen();
+}
+
+function nonMacTest2() {
+  document.removeEventListener("mozfullscreenerror", nonMacTest2, false);
   ok(!document.mozFullScreen, "Request for full-screen from a document with subdocument containing windowed plugin should be denied.");
   // Remove subdoc which contains windowed plugin, request full-screen, request should be granted.
   // Continue test in "mozfullscreenchange" handler.
   var f = document.getElementById("subdoc-plugin");
   f.parentNode.removeChild(f);
   document.body.mozRequestFullScreen();
 }
 
--- a/content/smil/Makefile.in
+++ b/content/smil/Makefile.in
@@ -41,76 +41,67 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 LIBRARY_NAME	= gkconsmil_s
 LIBXUL_LIBRARY	= 1
 
+EXPORTS	= \
+	nsISMILAnimationElement.h \
+	nsISMILAttr.h \
+	nsISMILType.h \
+	nsSMILAnimationController.h \
+	nsSMILCompositorTable.h \
+	nsSMILCSSProperty.h \
+	nsSMILKeySpline.h \
+	nsSMILMappedAttribute.h \
+	nsSMILMilestone.h \
+	nsSMILTimeContainer.h \
+	nsSMILTypes.h \
+	$(NULL)
 
-# nsSMILKeySpline is used by CSS transitions -- need to build it regardless
-# of whether SMIL is enabled.
-CPPSRCS		= nsSMILKeySpline.cpp
-EXPORTS		= nsSMILKeySpline.h
-
-ifdef MOZ_SMIL
-CPPSRCS		+= \
+CPPSRCS	= \
 	nsDOMTimeEvent.cpp \
 	nsSMILAnimationController.cpp \
 	nsSMILAnimationFunction.cpp \
 	nsSMILCompositor.cpp \
 	nsSMILCSSProperty.cpp \
 	nsSMILCSSValueType.cpp \
 	nsSMILFloatType.cpp \
 	nsSMILInstanceTime.cpp \
 	nsSMILInterval.cpp \
+	nsSMILKeySpline.cpp \
 	nsSMILMappedAttribute.cpp \
 	nsSMILNullType.cpp \
 	nsSMILParserUtils.cpp \
 	nsSMILRepeatCount.cpp \
 	nsSMILSetAnimationFunction.cpp \
 	nsSMILTimeContainer.cpp \
 	nsSMILTimedElement.cpp \
 	nsSMILTimeValue.cpp \
 	nsSMILTimeValueSpec.cpp \
 	nsSMILValue.cpp \
 	SMILBoolType.cpp \
 	SMILEnumType.cpp \
 	SMILIntegerType.cpp \
 	SMILStringType.cpp \
-		$(NULL)
-endif
+	$(NULL)
 
 include $(topsrcdir)/config/config.mk
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
-ifdef MOZ_SMIL
 ifdef ENABLE_TESTS
 TOOL_DIRS		+= test
 endif # ENABLE_TESTS
 
-EXPORTS		+= \
-	  nsISMILAnimationElement.h \
-	  nsISMILAttr.h \
-	  nsISMILType.h \
-	  nsSMILAnimationController.h \
-	  nsSMILCompositorTable.h \
-	  nsSMILCSSProperty.h \
-	  nsSMILKeySpline.h \
-	  nsSMILMappedAttribute.h \
-	  nsSMILMilestone.h \
-	  nsSMILTimeContainer.h \
-	  nsSMILTypes.h \
-	  $(NULL)
-
 INCLUDES += 	\
 		-I$(srcdir)/../base/src \
 		-I$(srcdir)/../../layout/style \
 		-I$(srcdir)/../events/src \
 		$(NULL)
-endif # MOZ_SMIL
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/smil/nsSMILAnimationController.cpp
+++ b/content/smil/nsSMILAnimationController.cpp
@@ -203,16 +203,17 @@ nsSMILAnimationController::RegisterAnima
   if (mDeferredStartSampling) {
     mDeferredStartSampling = false;
     if (mChildContainerTable.Count()) {
       // mAnimationElementTable was empty, but now we've added its 1st element
       NS_ABORT_IF_FALSE(mAnimationElementTable.Count() == 1,
                         "we shouldn't have deferred sampling if we already had "
                         "animations registered");
       StartSampling(GetRefreshDriver());
+      Sample(); // Run the first sample manually
     } // else, don't sample until a time container is registered (via AddChild)
   }
 }
 
 void
 nsSMILAnimationController::UnregisterAnimationElement(
                                   nsISMILAnimationElement* aAnimationElement)
 {
@@ -812,18 +813,18 @@ nsSMILAnimationController::GetTargetIden
 
 nsresult
 nsSMILAnimationController::AddChild(nsSMILTimeContainer& aChild)
 {
   TimeContainerPtrKey* key = mChildContainerTable.PutEntry(&aChild);
   NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
 
   if (!mPauseState && mChildContainerTable.Count() == 1) {
+    MaybeStartSampling(GetRefreshDriver());
     Sample(); // Run the first sample manually
-    MaybeStartSampling(GetRefreshDriver());
   }
 
   return NS_OK;
 }
 
 void
 nsSMILAnimationController::RemoveChild(nsSMILTimeContainer& aChild)
 {
--- a/content/smil/test/Makefile.in
+++ b/content/smil/test/Makefile.in
@@ -64,16 +64,17 @@ include $(topsrcdir)/config/rules.mk
 	  test_smilContainerBinding.xhtml \
 	  test_smilCrossContainer.xhtml \
 	  test_smilCSSFontStretchRelative.xhtml \
 	  test_smilCSSFromBy.xhtml \
 	  test_smilCSSFromTo.xhtml \
 	  test_smilCSSInherit.xhtml \
 	  test_smilCSSInvalidValues.xhtml \
 	  test_smilCSSPaced.xhtml \
+	  test_smilDynamicDelayedBeginElement.xhtml \
 	  test_smilMappedAttrFromTo.xhtml \
 	  test_smilMappedAttrFromBy.xhtml \
 	  test_smilMappedAttrPaced.xhtml \
 	  test_smilReset.xhtml \
 	  test_smilRestart.xhtml \
 	  test_smilExtDoc.xhtml \
 	  test_smilFillMode.xhtml \
 	  test_smilGetStartTime.xhtml \
new file mode 100644
--- /dev/null
+++ b/content/smil/test/test_smilDynamicDelayedBeginElement.xhtml
@@ -0,0 +1,96 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=699143
+-->
+<head>
+  <title>Test for Bug 699143</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="smilTestUtils.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=699143">Mozilla Bug 699143</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <svg xmlns="http://www.w3.org/2000/svg">
+    <rect id="r" height="500px" width="500px" fill="blue"/>
+  </svg>
+</div>
+<pre id="test">
+<script type="text/javascript">
+<![CDATA[
+
+/** Test for Bug 699143 **/
+SimpleTest.waitForExplicitFinish();
+
+// Values for 'width' attr on the <rect> above
+const INITIAL_VAL = "500px"
+const FROM_VAL = "20px";
+const TO_VAL   = "80px";
+
+// Helper function
+function createAnim() {
+  var a = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
+  a.setAttribute('attributeName', 'width');
+  a.setAttribute('from', FROM_VAL);
+  a.setAttribute('to',   TO_VAL);
+  a.setAttribute('begin', 'indefinite');
+  a.setAttribute('dur', '3s');
+  a.setAttribute('fill', 'freeze');
+  return a;
+}
+
+// Main Functions
+function main() {
+  if (!SMILUtil.isSMILEnabled()) {
+    ok(false, "SMIL dosn't seem to be enabled");
+    SimpleTest.finish();
+    return;
+  }
+
+  // In unpatched Firefox builds, we'll only trigger Bug 699143 if we insert
+  // an animation and call beginElement() **after** the document start-time.
+  // Hence, we use executeSoon here to allow some time to pass.
+  SimpleTest.executeSoon(runTest);
+}
+
+function runTest() {
+  var svg = SMILUtil.getSVGRoot();
+
+  is(svg.getCurrentTime(), 0,
+     "even though we've allowed time to pass, we shouldn't have bothered " +
+     "updating the current time, since there aren't any animation elements");
+
+  // Insert an animation elem (should affect currentTime but not targeted attr)
+  var r = document.getElementById("r");
+  var a = createAnim();
+  r.appendChild(a);
+  isnot(svg.getCurrentTime(), 0,
+       "insertion of first animation element should have triggered a " +
+       "synchronous sample and updated our current time");
+  is(r.width.animVal.valueAsString, INITIAL_VAL,
+     "inserted animation shouldn't have affected its targeted attribute, " +
+     "since it doesn't have any intervals yet");
+
+  // Trigger the animation & be sure it takes effect
+  a.beginElement();
+  is(r.width.animVal.valueAsString, FROM_VAL,
+     "beginElement() should activate our animation & set its 'from' val");
+
+  // Rewind to time=0 & check target attr, to be sure beginElement()-generated
+  // interval starts later than that.
+  svg.setCurrentTime(0);
+  is(r.width.animVal.valueAsString, INITIAL_VAL,
+     "after rewinding to 0, our beginElement()-generated interval " +
+     "shouldn't be active yet");
+
+  SimpleTest.finish();
+}
+
+window.addEventListener("load", main, false);
+
+]]>
+</script>
+</pre>
+</body>
+</html>
--- a/content/svg/content/src/DOMSVGLength.cpp
+++ b/content/svg/content/src/DOMSVGLength.cpp
@@ -106,33 +106,29 @@ DOMSVGLength::DOMSVGLength()
   , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
   , mValue(0.0f)
 {
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetUnitType(PRUint16* aUnit)
 {
-#ifdef MOZ_SMIL
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
-#endif
   *aUnit = HasOwner() ? InternalItem().GetUnit() : mUnit;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetValue(float* aValue)
 {
-#ifdef MOZ_SMIL
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
-#endif
   if (HasOwner()) {
     *aValue = InternalItem().GetValueInUserUnits(Element(), Axis());
     if (NS_finite(*aValue)) {
       return NS_OK;
     }
   } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
              mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
     *aValue = mValue;
@@ -157,41 +153,37 @@ DOMSVGLength::SetValue(float aUserUnitVa
   // Although the value passed in is in user units, this method does not turn
   // this length into a user unit length. Instead it converts the user unit
   // value to this length's current unit and sets that, leaving this length's
   // unit as it is.
 
   if (HasOwner()) {
     if (InternalItem().SetFromUserUnitValue(aUserUnitValue, Element(), Axis())) {
       Element()->DidChangeLengthList(mAttrEnum, true);
-#ifdef MOZ_SMIL
       if (mList->mAList->IsAnimating()) {
         Element()->AnimationNeedsResample();
       }
-#endif
       return NS_OK;
     }
   } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
              mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
     mValue = aUserUnitValue;
     return NS_OK;
   }
   // else [SVGWG issue] Can't convert user unit value to this length's unit
   // ReportToConsole
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetValueInSpecifiedUnits(float* aValue)
 {
-#ifdef MOZ_SMIL
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
-#endif
   *aValue = HasOwner() ? InternalItem().GetValueInCurrentUnits() : mValue;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
 {
   if (mIsAnimValItem) {
@@ -200,21 +192,19 @@ DOMSVGLength::SetValueInSpecifiedUnits(f
 
   if (!NS_finite(aValue)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   if (HasOwner()) {
     InternalItem().SetValueInCurrentUnits(aValue);
     Element()->DidChangeLengthList(mAttrEnum, true);
-#ifdef MOZ_SMIL
     if (mList->mAList->IsAnimating()) {
       Element()->AnimationNeedsResample();
     }
-#endif
     return NS_OK;
   }
   mValue = aValue;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::SetValueAsString(const nsAString& aValue)
@@ -225,36 +215,32 @@ DOMSVGLength::SetValueAsString(const nsA
 
   SVGLength value;
   if (!value.SetValueFromString(aValue)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
   if (HasOwner()) {
     InternalItem() = value;
     Element()->DidChangeLengthList(mAttrEnum, true);
-#ifdef MOZ_SMIL
     if (mList->mAList->IsAnimating()) {
       Element()->AnimationNeedsResample();
     }
-#endif
     return NS_OK;
   }
   mValue = value.GetValueInCurrentUnits();
   mUnit = value.GetUnit();