Merge fx-team to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 08 Jun 2014 21:31:29 -0400
changeset 207725 84277c73fd7861829bfdb6d0ee5e5e25bae9bc35
parent 207719 8bd92dc9ef59a915bb805ecf9fe244b8f3fc6e66 (current diff)
parent 207724 98c8ea754cb4cd654a1c089f6d6e75d7b7e0d361 (diff)
child 207782 5f46ba7c1a82d68cf0d939c1ea842c91234e9508
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone32.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 fx-team to m-c. a=merge
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -260,16 +260,19 @@ const NOTIFICATIONS = {
 };
 
 /**
  * Attach notification constants to the object prototype so tests etc can
  * use them without needing to import anything
  */
 DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS;
 
+/**
+ * target is dynamic because the selectedTab changes
+ */
 Object.defineProperty(DeveloperToolbar.prototype, "target", {
   get: function() {
     return TargetFactory.forTab(this._chromeWindow.getBrowser().selectedTab);
   },
   enumerable: true
 });
 
 /**
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -485,16 +485,20 @@ StyleEditorUI.prototype = {
           }
 
           editor.onShow();
 
           this.emit("editor-selected", editor);
 
           // Is there any CSS coverage markup to include?
           csscoverage.getUsage(this._target).then(usage => {
+            if (usage == null) {
+              return;
+            }
+
             let href = editor.styleSheet.href || editor.styleSheet.nodeHref;
             usage.createEditorReport(href).then(data => {
               editor.removeAllUnusedRegions();
 
               if (data.reports.length > 0) {
                 // So there is some coverage markup, but can we apply it?
                 let text = editor.sourceEditor.getText() + "\r";
                 // If the CSS text contains a '}' with some non-whitespace
--- a/browser/devtools/styleeditor/StyleSheetEditor.jsm
+++ b/browser/devtools/styleeditor/StyleSheetEditor.jsm
@@ -221,17 +221,17 @@ StyleSheetEditor.prototype = {
   },
 
   /**
    * Start fetching the full text source for this editor's sheet.
    */
   fetchSource: function(callback) {
     return this.styleSheet.getText().then((longStr) => {
       longStr.string().then((source) => {
-        this._state.text = prettifyCSS(source);
+        this._state.text = CssLogic.prettifyCSS(source);
         this.sourceLoaded = true;
 
         if (callback) {
           callback(source);
         }
         return source;
       });
     }, e => {
@@ -635,83 +635,16 @@ StyleSheetEditor.prototype = {
       this.sourceEditor.destroy();
     }
     this.cssSheet.off("property-change", this._onPropertyChange);
     this.cssSheet.off("media-rules-changed", this._onMediaRulesChanged);
     this.styleSheet.off("error", this._onError);
   }
 }
 
-
-const TAB_CHARS = "\t";
-
-const CURRENT_OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-const LINE_SEPARATOR = CURRENT_OS === "WINNT" ? "\r\n" : "\n";
-
-/**
- * Prettify minified CSS text.
- * This prettifies CSS code where there is no indentation in usual places while
- * keeping original indentation as-is elsewhere.
- *
- * @param string text
- *        The CSS source to prettify.
- * @return string
- *         Prettified CSS source
- */
-function prettifyCSS(text)
-{
-  // remove initial and terminating HTML comments and surrounding whitespace
-  text = text.replace(/(?:^\s*<!--[\r\n]*)|(?:\s*-->\s*$)/g, "");
-
-  let parts = [];    // indented parts
-  let partStart = 0; // start offset of currently parsed part
-  let indent = "";
-  let indentLevel = 0;
-
-  for (let i = 0; i < text.length; i++) {
-    let c = text[i];
-    let shouldIndent = false;
-
-    switch (c) {
-      case "}":
-        if (i - partStart > 1) {
-          // there's more than just } on the line, add line
-          parts.push(indent + text.substring(partStart, i));
-          partStart = i;
-        }
-        indent = TAB_CHARS.repeat(--indentLevel);
-        /* fallthrough */
-      case ";":
-      case "{":
-        shouldIndent = true;
-        break;
-    }
-
-    if (shouldIndent) {
-      let la = text[i+1]; // one-character lookahead
-      if (!/\n/.test(la) || /^\s+$/.test(text.substring(i+1, text.length))) {
-        // following character should be a new line, but isn't,
-        // or it's whitespace at the end of the file
-        parts.push(indent + text.substring(partStart, i + 1));
-        if (c == "}") {
-          parts.push(""); // for extra line separator
-        }
-        partStart = i + 1;
-      } else {
-        return text; // assume it is not minified, early exit
-      }
-    }
-
-    if (c == "{") {
-      indent = TAB_CHARS.repeat(++indentLevel);
-    }
-  }
-  return parts.join(LINE_SEPARATOR);
-}
-
 /**
  * Find a path on disk for a file given it's hosted uri, the uri of the
  * original resource that generated it (e.g. Sass file), and the location of the
  * local file for that source.
  *
  * @param {nsIURI} uri
  *        The uri of the resource
  * @param {nsIURI} origUri
--- a/browser/locales/en-US/chrome/browser/devtools/gcli.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gcli.properties
@@ -75,29 +75,16 @@ fileErrIsNotFile='%1$S' is not a file
 # filename
 fileErrIsNotDirectory='%1$S' is not a directory
 
 # LOCALIZATION NOTE: Error message given when a file argument does not match
 # the specified regular expression %1$S is a filename %2$S is a regular
 # expression
 fileErrDoesntMatch='%1$S' does not match '%2$S'
 
-# LOCALIZATION NOTE: When a command has a parameter that has a number of
-# pre-defined options the user interface presents these in a drop-down menu,
-# where the first 'option' is an indicator that a selection should be made.
-# This string describes that first option.
-fieldSelectionSelect=Select a %S…
-
-# LOCALIZATION NOTE (fieldArrayAdd, fieldArrayDel): When a command has a
-# parameter that can be repeated multiple times (e.g. like the 'cat a.txt
-# b.txt' command) the user interface presents buttons to add and remove
-# arguments. This string is used to add arguments.
-fieldArrayAdd=Add
-fieldArrayDel=Delete
-
 # LOCALIZATION NOTE: When the menu has displayed all the matches that it
 # should (i.e. about 10 items) then we display this to alert the user that
 # more matches are available.
 fieldMenuMore=More matches, keep typing
 
 # LOCALIZATION NOTE: The command line provides completion for JavaScript
 # commands, however there are times when the scope of what we're completing
 # against can't be used. This error message is displayed when this happens.
@@ -176,25 +163,25 @@ helpListNone=No commands starting with '
 # LOCALIZATION NOTE (helpManRequired, helpManOptional, helpManDefault): When
 # the 'help x' command wants to show the manual for the 'x' command, it needs
 # to be able to describe the parameters as either required or optional, or if
 # they have a default value.
 helpManRequired=required
 helpManOptional=optional
 helpManDefault=optional, default=%S
 
+# LOCALIZATION NOTE (helpIntro): This forms part of the output from the 'help'
+# command. 'GCLI' is a project name and should be left untranslated.
+helpIntro=GCLI is an experiment to create a highly usable command line for web developers.
+
 # LOCALIZATION NOTE: Text shown as part of the output of the 'help' command
 # when the command in question has sub-commands, before a list of the matching
 # sub-commands.
 subCommands=Sub-Commands
 
-# LOCALIZATION NOTE: Text shown as part of the output of the 'help' command
-# when the command in question should have sub-commands but in fact has none.
-subCommandsNone=None
-
 # LOCALIZATION NOTE (contextDesc, contextManual, contextPrefixDesc): These
 # strings are used to describe the 'context' command and its 'prefix'
 # parameter. See localization comment for 'connect' for an explanation about
 # 'prefix'.
 contextDesc=Concentrate on a group of commands
 contextManual=Setup a default prefix to future commands. For example 'context git' would allow you to type 'commit' rather than 'git commit'.
 contextPrefixDesc=The command prefix
 
@@ -221,35 +208,29 @@ connectMethodDesc=The method of connecti
 connectUrlDesc=The URL to connect to
 connectDupReply=Connection called %S already exists.
 
 # LOCALIZATION NOTE: The output of the 'connect' command, telling the user
 # what it has done. Parameters: %S is the prefix command. See localization
 # comment for 'connect' for an explanation about 'prefix'.
 connectReply=Added %S commands.
 
-# LOCALIZATION NOTE (disconnectDesc2, disconnectManual2, disconnectPrefixDesc,
-# disconnectForceDesc): These strings describe the 'disconnect' command and
+# LOCALIZATION NOTE (disconnectDesc2, disconnectManual2,
+# disconnectPrefixDesc): These strings describe the 'disconnect' command and
 # all its available parameters. See localization comment for 'connect' for an
 # explanation about 'prefix'.
 disconnectDesc2=Disconnect from server
 disconnectManual2=Disconnect from a server currently connected for remote commands execution
 disconnectPrefixDesc=Parent prefix for imported commands
-disconnectForceDesc=Ignore outstanding requests
 
 # LOCALIZATION NOTE: This is the output of the 'disconnect' command,
 # explaining the user what has been done. Parameters: %S is the number of
 # commands removed.
 disconnectReply=Removed %S commands.
 
-# LOCALIZATION NOTE: This error message is displayed when the user attempts to
-# disconnect before all requests have completed. Parameters: %S is a list of
-# incomplete requests.
-disconnectOutstanding=Outstanding requests (%S)
-
 # LOCALIZATION NOTE (globalDesc, globalWindowDesc, globalOutput): These
 # strings describe the 'global' command and its parameters
 globalDesc=Change the JS global
 globalWindowDesc=The new window/global
 globalOutput=JS global is now %S
 
 # LOCALIZATION NOTE: These strings describe the 'clear' command
 clearDesc=Clear the output area
@@ -284,23 +265,16 @@ prefShowSettingValue=%1$S: %2$S
 # describe the 'pref set' command and all its parameters.
 prefSetDesc=Alter a setting
 prefSetManual=Alter preferences defined by the environment
 prefSetSettingDesc=Setting to alter
 prefSetSettingManual=The name of the setting to alter.
 prefSetValueDesc=New value for setting
 prefSetValueManual=The new value for the specified setting
 
-# LOCALIZATION NOTE (prefSetCheckHeading, prefSetCheckBody, prefSetCheckGo):
-# These strings are displayed to the user the first time they try to alter a
-# setting.
-prefSetCheckHeading=This might void your warranty!
-prefSetCheckBody=Changing these advanced settings can be harmful to the stability, security, and performance of this application. You should only continue if you are sure of what you are doing.
-prefSetCheckGo=I'll be careful, I promise!
-
 # LOCALIZATION NOTE (prefResetDesc, prefResetManual, prefResetSettingDesc,
 # prefResetSettingManual): These strings describe the 'pref reset' command and
 # all its parameters.
 prefResetDesc=Reset a setting
 prefResetManual=Reset the value of a setting to the system defaults
 prefResetSettingDesc=Setting to reset
 prefResetSettingManual=The name of the setting to reset to the system default value
 
@@ -333,13 +307,8 @@ introTextGo=Got it!
 # LOCALIZATION NOTE: This is a short description of the 'hideIntro' setting.
 hideIntroDesc=Show the initial welcome message
 
 # LOCALIZATION NOTE: This is a description of the 'eagerHelper' setting. It's
 # displayed when the user asks for help on the settings. eagerHelper allows
 # users to select between showing no tooltips, permanent tooltips, and only
 # important tooltips.
 eagerHelperDesc=How eager are the tooltips
-
-# LOCALIZATION NOTE: This text is displayed at the top of the output for the
-# help command, just before the list of commands. This text is wrapped inside
-# a link to a localized MDN article.
-introBody=For more information see MDN.
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -574,25 +574,28 @@ resizeModeManual2=Responsive websites re
 # name, which is why it should be as short as possible.
 cmdDesc=Manipulate the commands
 
 # LOCALIZATION NOTE (cmdRefreshDesc) A very short description of the 'cmd refresh'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 cmdRefreshDesc=Re-read mozcmd directory
 
-# LOCALIZATION NOTE (cmdStatus2) When the we load new commands from mozcmd
+# LOCALIZATION NOTE (cmdStatus3) When the we load new commands from mozcmd
 # directory, we report where we loaded from using %1$S.
-cmdStatus2=Read commands from '%1$S'
+cmdStatus3=Loaded commands from '%1$S'
 
-# LOCALIZATION NOTE (cmdSetdirDesc) 
+# LOCALIZATION NOTE (cmdSetdirDesc)  A very short description of the 'cmd setdir'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
 cmdSetdirDesc=Setup a mozcmd directory
 
-# LOCALIZATION NOTE (cmdSetdirManual) 
-cmdSetdirManual=A 'mozcmd' directory is an easy way to create new custom commands for the Firefox command line. For more information see the <a href="https://developer.mozilla.org/en-US/docs/Tools/GCLI/Customization">MDN documentation</a>.
+# LOCALIZATION NOTE (cmdSetdirManual2) A fuller description of the 'cmd setdir'
+# command, displayed when the user asks for help on what it does.
+cmdSetdirManual2=A 'mozcmd' directory is an easy way to create new custom commands. For more information see the <a href="https://developer.mozilla.org/docs/Tools/GCLI/Customization">MDN documentation</a>.
 
 # LOCALIZATION NOTE (cmdSetdirDirectoryDesc) The description of the directory
 # parameter to the 'cmd setdir' command.
 cmdSetdirDirectoryDesc=Directory containing .mozcmd files
 
 # LOCALIZATION NOTE (addonDesc) A very short description of the 'addon'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
@@ -1383,9 +1386,8 @@ listenNoInitOutput=DebuggerServer not in
 # LOCALIZATION NOTE (mediaDesc, mediaEmulateDesc, mediaEmulateManual,
 # mediaEmulateType, mediaResetDesc, mediaResetManual) These strings describe
 # the 'media' commands and all available parameters.
 mediaDesc=CSS media type emulation
 mediaEmulateDesc=Emulate a specified CSS media type
 mediaEmulateManual=View the document as if rendered on a device supporting the given media type, with the relevant CSS rules applied.
 mediaEmulateType=The media type to emulate
 mediaResetDesc=Stop emulating a CSS media type
-mediaResetManual=Stop emulating a CSS media type
--- a/toolkit/devtools/gcli/commands/cmd.js
+++ b/toolkit/devtools/gcli/commands/cmd.js
@@ -141,16 +141,17 @@ exports.items = [
       let dirName = prefBranch.getComplexValue(PREF_DIR,
                                               Ci.nsISupportsString).data.trim();
       return gcli.lookupFormat("cmdStatus2", [ dirName ]);
     }
   },
   {
     name: "cmd setdir",
     description: gcli.lookup("cmdSetdirDesc"),
+    manual: gcli.lookup("cmdSetdirManual2"),
     params: [
       {
         name: "directory",
         description: gcli.lookup("cmdSetdirDirectoryDesc"),
         type: {
           name: "file",
           filetype: "directory",
           existing: "yes"
@@ -163,12 +164,12 @@ exports.items = [
       return true; // !prefBranch.prefHasUserValue(PREF_DIR);
     },
     exec: function(args, context) {
       supportsString.data = args.directory;
       prefBranch.setComplexValue(PREF_DIR, Ci.nsISupportsString, supportsString);
 
       gcli.load();
 
-      return gcli.lookupFormat("cmdStatus2", [ args.directory ]);
+      return gcli.lookupFormat("cmdStatus3", [ args.directory ]);
     }
   }
 ];
--- a/toolkit/devtools/gcli/commands/csscoverage.js
+++ b/toolkit/devtools/gcli/commands/csscoverage.js
@@ -27,65 +27,81 @@ exports.items = [
     description: l10n.lookup("csscoverageDesc"),
   },
   {
     name: "csscoverage start",
     hidden: true,
     description: l10n.lookup("csscoverageStartDesc"),
     exec: function*(args, context) {
       let usage = yield csscoverage.getUsage(context.environment.target);
+      if (usage == null) {
+        throw new Error(l10n.lookup("csscoverageNoRemoteError"));
+      }
       yield usage.start(context.environment.chromeWindow,
                         context.environment.target);
     }
   },
   {
     name: "csscoverage stop",
     hidden: true,
     description: l10n.lookup("csscoverageStopDesc"),
     exec: function*(args, context) {
       let target = context.environment.target;
       let usage = yield csscoverage.getUsage(target);
+      if (usage == null) {
+        throw new Error(l10n.lookup("csscoverageNoRemoteError"));
+      }
       yield usage.stop();
       yield gDevTools.showToolbox(target, "styleeditor");
     }
   },
   {
     name: "csscoverage oneshot",
     hidden: true,
     description: l10n.lookup("csscoverageOneShotDesc"),
     exec: function*(args, context) {
       let target = context.environment.target;
       let usage = yield csscoverage.getUsage(target);
+      if (usage == null) {
+        throw new Error(l10n.lookup("csscoverageNoRemoteError"));
+      }
       yield usage.oneshot();
       yield gDevTools.showToolbox(target, "styleeditor");
     }
   },
   {
     name: "csscoverage toggle",
     hidden: true,
     description: l10n.lookup("csscoverageToggleDesc"),
     exec: function*(args, context) {
       let target = context.environment.target;
       let usage = yield csscoverage.getUsage(target);
+      if (usage == null) {
+        throw new Error(l10n.lookup("csscoverageNoRemoteError"));
+      }
 
       let running = yield usage.toggle();
       if (running) {
         return l10n.lookup("csscoverageRunningReply");
       }
 
       yield usage.stop();
       yield gDevTools.showToolbox(target, "styleeditor");
     }
   },
   {
     name: "csscoverage report",
     hidden: true,
     description: l10n.lookup("csscoverageReportDesc"),
     exec: function*(args, context) {
       let usage = yield csscoverage.getUsage(context.environment.target);
+      if (usage == null) {
+        throw new Error(l10n.lookup("csscoverageNoRemoteError"));
+      }
+
       return {
         isTypedData: true,
         type: "csscoveragePageReport",
         data: yield usage.createPageReport()
       };
     }
   },
   {
--- a/toolkit/devtools/gcli/commands/media.js
+++ b/toolkit/devtools/gcli/commands/media.js
@@ -32,16 +32,15 @@ exports.items = [
       let markupDocumentViewer = context.environment.chromeWindow
                                         .gBrowser.markupDocumentViewer;
       markupDocumentViewer.emulateMedium(args.type);
     }
   },
   {
     name: "media reset",
     description: gcli.lookup("mediaResetDesc"),
-    manual: gcli.lookup("mediaEmulateManual"),
     exec: function(args, context) {
       let markupDocumentViewer = context.environment.chromeWindow
                                         .gBrowser.markupDocumentViewer;
       markupDocumentViewer.stopEmulatingMedium();
     }
   }
 ];
--- a/toolkit/devtools/gcli/source/lib/gcli/commands/help.js
+++ b/toolkit/devtools/gcli/source/lib/gcli/commands/help.js
@@ -330,23 +330,17 @@ exports.items = [
     item: 'converter',
     from: 'commandsData',
     to: 'view',
     exec: function(commandsData, context) {
       return {
         html:
           '<div>\n' +
           '  <div if="${includeIntro}">\n' +
-          '    <p>GCLI is an experiment to create a highly usable command line for web developers.</p>\n' +
-          '    <p>\n' +
-          '      Useful links:\n' +
-          '      <a href=\'https://github.com/joewalker/gcli\'>Source</a> (Apache-2.0),\n' +
-          '      <a href=\'https://github.com/joewalker/gcli/blob/master/docs/index.md\'>Documentation</a> (for users/embedders),\n' +
-          '      <a href=\'https://wiki.mozilla.org/DevTools/Features/GCLI\'>Mozilla feature page</a> (for GCLI in the web console).\n' +
-          '    </p>\n' +
+          '    <p>${l10n.helpIntro}</p>\n' +
           '  </div>\n' +
           '\n' +
           '  <p>${heading}</p>\n' +
           '\n' +
           '  <table>\n' +
           '    <tr foreach="command in ${matchingCommands}">\n' +
           '      <td class="gcli-help-name">${command.name}</td>\n' +
           '      <td class="gcli-help-arrow">-</td>\n' +
@@ -369,23 +363,19 @@ exports.items = [
   {
     // Convert a list of commands into a formatted list
     item: 'converter',
     from: 'commandsData',
     to: 'stringView',
     exec: function(commandsData, context) {
       return {
         html:
-          '<pre><span if="${includeIntro}">## Welcome to GCLI\n' +
-          '\n' +
-          'GCLI is an experiment to create a highly usable JavaScript command line for developers.\n' +
+          '<pre><span if="${includeIntro}">## ${l10n.helpIntro1}\n' +
           '\n' +
-          'Useful links:\n' +
-          '- Source (Apache-2.0): https://github.com/joewalker/gcli\n' +
-          '- Documentation: https://github.com/joewalker/gcli/blob/master/docs/index.md</span>\n' +
+          '${l10n.helpIntro}\n' +
           '\n' +
           '# ${heading}\n' +
           '\n' +
           '<loop foreach="command in ${matchingCommands}">${command.name} &#x2192; ${command.description}\n' +
           '</loop></pre>',
         options: { allowEval: true, stack: 'commandsData->stringView' },
         data: getHelpListData(commandsData, context)
       };
--- a/toolkit/devtools/server/actors/csscoverage.js
+++ b/toolkit/devtools/server/actors/csscoverage.js
@@ -16,19 +16,16 @@ const protocol = require("devtools/serve
 const { method, custom, RetVal, Arg } = protocol;
 
 loader.lazyGetter(this, "gDevTools", () => {
   return require("resource:///modules/devtools/gDevTools.jsm").gDevTools;
 });
 loader.lazyGetter(this, "DOMUtils", () => {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils)
 });
-loader.lazyGetter(this, "prettifyCSS", () => {
-  return require("resource:///modules/devtools/StyleSheetEditor.jsm").prettifyCSS;
-});
 
 const CSSRule = Ci.nsIDOMCSSRule;
 
 const MAX_UNUSED_RULES = 10000;
 
 /**
  * Allow: let foo = l10n.lookup("csscoverageFoo");
  */
@@ -362,17 +359,17 @@ let UsageReportActor = protocol.ActorCla
 
     // Helper function to create a JSONable data structure representing a rule
     const ruleToRuleReport = function(rule, ruleData) {
       return {
         url: rule.url,
         shortUrl: rule.url.split("/").slice(-1),
         start: { line: rule.line, column: rule.column },
         selectorText: ruleData.selectorText,
-        formattedCssText: prettifyCSS(ruleData.cssText)
+        formattedCssText: CssLogic.prettifyCSS(ruleData.cssText)
       };
     }
 
     // A count of each type of rule for the bar chart
     let summary = { used: 0, unused: 0, preload: 0 };
 
     // Create the set of the unused rules
     let unusedMap = new Map();
@@ -752,19 +749,21 @@ exports.unregister = function(handle) {
   handle.removeGlobalActor(UsageReportActor, "usageReportActor");
   handle.removeTabActor(UsageReportActor, "usageReportActor");
 };
 
 const knownFronts = new WeakMap();
 
 /**
  * Create a UsageReportFront only when needed (returns a promise)
+ * For notes on target.makeRemote(), see
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1016330#c7
  */
 const getUsage = exports.getUsage = function(target) {
   return target.makeRemote().then(() => {
     let front = knownFronts.get(target.client)
-    if (front == null) {
+    if (front == null && target.form.usageReportActor != null) {
       front = new UsageReportFront(target.client, target.form);
       knownFronts.set(target.client, front);
     }
     return front;
   });
 };
--- a/toolkit/devtools/styleinspector/css-logic.js
+++ b/toolkit/devtools/styleinspector/css-logic.js
@@ -923,16 +923,80 @@ CssLogic.findCssSelector = function CssL
     index = positionInNodeList(ele, ele.parentNode.children) + 1;
     selector = CssLogic_findCssSelector(ele.parentNode) + ' > ' +
             tagName + ':nth-child(' + index + ')';
   }
 
   return selector;
 };
 
+const TAB_CHARS = "\t";
+
+/**
+ * Prettify minified CSS text.
+ * This prettifies CSS code where there is no indentation in usual places while
+ * keeping original indentation as-is elsewhere.
+ * @param string text The CSS source to prettify.
+ * @return string Prettified CSS source
+ */
+CssLogic.prettifyCSS = function(text) {
+  if (CssLogic.LINE_SEPARATOR == null) {
+    let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+    CssLogic.LINE_SEPARATOR = (os === "WINNT" ? "\r\n" : "\n");
+  }
+
+  // remove initial and terminating HTML comments and surrounding whitespace
+  text = text.replace(/(?:^\s*<!--[\r\n]*)|(?:\s*-->\s*$)/g, "");
+
+  let parts = [];    // indented parts
+  let partStart = 0; // start offset of currently parsed part
+  let indent = "";
+  let indentLevel = 0;
+
+  for (let i = 0; i < text.length; i++) {
+    let c = text[i];
+    let shouldIndent = false;
+
+    switch (c) {
+      case "}":
+        if (i - partStart > 1) {
+          // there's more than just } on the line, add line
+          parts.push(indent + text.substring(partStart, i));
+          partStart = i;
+        }
+        indent = TAB_CHARS.repeat(--indentLevel);
+        /* fallthrough */
+      case ";":
+      case "{":
+        shouldIndent = true;
+        break;
+    }
+
+    if (shouldIndent) {
+      let la = text[i+1]; // one-character lookahead
+      if (!/\n/.test(la) || /^\s+$/.test(text.substring(i+1, text.length))) {
+        // following character should be a new line, but isn't,
+        // or it's whitespace at the end of the file
+        parts.push(indent + text.substring(partStart, i + 1));
+        if (c == "}") {
+          parts.push(""); // for extra line separator
+        }
+        partStart = i + 1;
+      } else {
+        return text; // assume it is not minified, early exit
+      }
+    }
+
+    if (c == "{") {
+      indent = TAB_CHARS.repeat(++indentLevel);
+    }
+  }
+  return parts.join(CssLogic.LINE_SEPARATOR);
+};
+
 /**
  * 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 {number} aIndex tells the index/position of the stylesheet within the
--- a/toolkit/locales/en-US/chrome/global/devtools/csscoverage.properties
+++ b/toolkit/locales/en-US/chrome/global/devtools/csscoverage.properties
@@ -21,8 +21,9 @@ csscoverageRunningReply=Running CSS cove
 csscoverageDoneReply=CSS Coverage analysis completed
 
 # LOCALIZATION NOTE (csscoverageRunningError, csscoverageNotRunningError,
 # csscoverageNotRunError): Error message that describe things that can go wrong
 # with the css coverage system
 csscoverageRunningError=CSS coverage analysis already running
 csscoverageNotRunningError=CSS coverage analysis not running
 csscoverageNotRunError=CSS coverage analysis has not been run
+csscoverageNoRemoteError=Target does not support CSS Coverage