Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Mon, 07 Nov 2011 12:14:52 -0800
changeset 105302 e784f2911b5bd7956f52be6a93f010a032cf364e
parent 105301 89fff0ee52d5e237060a44b133a68e723dab8ae4 (current diff)
parent 79888 8200dc82b5edba7ff37f424df9895759d244e7bc (diff)
child 105303 a44853532140fdc0b52f1fd34bbc0f34f2a992e3
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherderautoland@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/tests/mochitest/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();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetValueAsString(nsAString& aValue)
 {
-#ifdef MOZ_SMIL
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
-#endif
   if (HasOwner()) {
     InternalItem().GetValueAsString(aValue);
     return NS_OK;
   }
   SVGLength(mValue, mUnit).GetValueAsString(aValue);
   return NS_OK;
 }
 
@@ -270,21 +256,19 @@ DOMSVGLength::NewValueSpecifiedUnits(PRU
   }
 
   if (!SVGLength::IsValidUnitType(aUnit)) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
   if (HasOwner()) {
     InternalItem().SetValueAndUnit(aValue, PRUint8(aUnit));
     Element()->DidChangeLengthList(mAttrEnum, true);
-#ifdef MOZ_SMIL
     if (mList->mAList->IsAnimating()) {
       Element()->AnimationNeedsResample();
     }
-#endif
     return NS_OK;
   }
   mUnit = PRUint8(aUnit);
   mValue = aValue;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -90,21 +90,19 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
 NS_INTERFACE_MAP_END
 
 
 nsIDOMSVGLength*
 DOMSVGLengthList::GetItemWithoutAddRef(PRUint32 aIndex)
 {
-#ifdef MOZ_SMIL
   if (IsAnimValList()) {
     Element()->FlushAnimations();
   }
-#endif
   if (aIndex < Length()) {
     EnsureItemAt(aIndex);
     return mItems[aIndex];
   }
   return nsnull;
 }
 
 void
@@ -153,21 +151,19 @@ DOMSVGLengthList::InternalList()
 }
 
 // ----------------------------------------------------------------------------
 // nsIDOMSVGLengthList implementation:
 
 NS_IMETHODIMP
 DOMSVGLengthList::GetNumberOfItems(PRUint32 *aNumberOfItems)
 {
-#ifdef MOZ_SMIL
   if (IsAnimValList()) {
     Element()->FlushAnimations();
   }
-#endif
   *aNumberOfItems = Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLengthList::Clear()
 {
   if (IsAnimValList()) {
@@ -178,21 +174,19 @@ DOMSVGLengthList::Clear()
     // Notify any existing DOM items of removal *before* truncating the lists
     // so that they can find their SVGLength internal counterparts and copy
     // their values. This also notifies the animVal list:
     mAList->InternalBaseValListWillChangeTo(SVGLengthList());
 
     mItems.Clear();
     InternalList().Clear();
     Element()->DidChangeLengthList(AttrEnum(), true);
-#ifdef MOZ_SMIL
     if (mAList->IsAnimating()) {
       Element()->AnimationNeedsResample();
     }
-#endif
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLengthList::Initialize(nsIDOMSVGLength *newItem,
                              nsIDOMSVGLength **_retval)
 {
@@ -271,21 +265,19 @@ DOMSVGLengthList::InsertItemBefore(nsIDO
   // This MUST come after the insertion into InternalList(), or else under the
   // insertion into InternalList() the values read from domItem would be bad
   // data from InternalList() itself!:
   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
 
   UpdateListIndicesFromIndex(mItems, index + 1);
 
   Element()->DidChangeLengthList(AttrEnum(), true);
-#ifdef MOZ_SMIL
   if (mAList->IsAnimating()) {
     Element()->AnimationNeedsResample();
   }
-#endif
   *_retval = domItem.forget().get();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
                               PRUint32 index,
                               nsIDOMSVGLength **_retval)
@@ -315,21 +307,19 @@ DOMSVGLengthList::ReplaceItem(nsIDOMSVGL
   InternalList()[index] = domItem->ToSVGLength();
   mItems[index] = domItem;
 
   // This MUST come after the ToSVGPoint() call, otherwise that call
   // would end up reading bad data from InternalList()!
   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
 
   Element()->DidChangeLengthList(AttrEnum(), true);
-#ifdef MOZ_SMIL
   if (mAList->IsAnimating()) {
     Element()->AnimationNeedsResample();
   }
-#endif
   NS_ADDREF(*_retval = domItem.get());
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMSVGLengthList::RemoveItem(PRUint32 index,
                              nsIDOMSVGLength **_retval)
 {
@@ -356,21 +346,19 @@ DOMSVGLengthList::RemoveItem(PRUint32 in
   NS_ADDREF(*_retval = mItems[index]);
 
   InternalList().RemoveItem(index);