Bug 1272774 - show favicons on about:debugging via favicons service; draft
authorgasolin <gasolin@gmail.com>
Fri, 03 Jun 2016 15:34:53 +0800
changeset 383836 bd5ff509bb675ad9b4af94a95b5b20e6fe681b96
parent 383490 adb1d2a92e0daeaef0b03867a5ed36335ae4080d
child 524558 3a1e9c04c18e097d1f322020757783d99cd8093d
push id22110
push userbmo:gasolin@mozilla.com
push dateTue, 05 Jul 2016 06:33:12 +0000
bugs1272774
milestone50.0a1
Bug 1272774 - show favicons on about:debugging via favicons service; MozReview-Commit-ID: 4uKuABaynVr
devtools/client/aboutdebugging/components/tabs/panel.js
devtools/server/actors/webbrowser.js
--- a/devtools/client/aboutdebugging/components/tabs/panel.js
+++ b/devtools/client/aboutdebugging/components/tabs/panel.js
@@ -34,36 +34,36 @@ module.exports = createClass({
 
   componentWillUnmount() {
     let { client } = this.props;
     client.removeListener("tabListChanged", this.update);
   },
 
   update() {
     this.props.client.mainRoot.listTabs().then(({ tabs }) => {
+      let TabIconPromises = [];
       // Filter out closed tabs (represented as `null`).
       tabs = tabs.filter(tab => !!tab);
+
       tabs.forEach(tab => {
-        // FIXME Also try to fetch low-res favicon. But we should use actor
-        // support for this to get the high-res one (bug 1061654).
-        let url = new URL(tab.url);
-        if (url.protocol.startsWith("http")) {
-          let prePath = url.origin;
-          let idx = url.pathname.lastIndexOf("/");
-          if (idx === -1) {
-            prePath += url.pathname;
-          } else {
-            prePath += url.pathname.substr(0, idx);
-          }
-          tab.icon = prePath + "/favicon.ico";
-        } else {
-          tab.icon = "chrome://devtools/skin/images/tabs-icon.svg";
+        let packet = {
+          to: tab.actor,
+          type: "getFavicon"
+        };
+
+        let tabIconPromise = this.props.client.request(packet);
+        TabIconPromises.push(tabIconPromise);
+      });
+
+      Promise.all(TabIconPromises).then(responses => {
+        for (let i = 0; i < responses.length; i++) {
+          tabs[i].icon = responses[i].icon;
         }
+        this.setState({ tabs });
       });
-      this.setState({ tabs });
     });
   },
 
   render() {
     let { client, id } = this.props;
     let { tabs } = this.state;
 
     return dom.div({
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -1,16 +1,15 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
-
 var { Ci, Cu } = require("chrome");
 var Services = require("Services");
 var { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 var promise = require("promise");
 var {
   ActorPool, createExtraActors, appendExtraActors, GeneratedLocation
 } = require("devtools/server/actors/common");
 var { DebuggerServer } = require("devtools/server/main");
@@ -23,17 +22,19 @@ loader.lazyRequireGetter(this, "RootActo
 loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/script", true);
 loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/script", true);
 loader.lazyRequireGetter(this, "BrowserAddonActor", "devtools/server/actors/addon", true);
 loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker", true);
 loader.lazyRequireGetter(this, "ServiceWorkerRegistrationActorList", "devtools/server/actors/worker", true);
 loader.lazyRequireGetter(this, "ProcessActorList", "devtools/server/actors/process", true);
 loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
 loader.lazyImporter(this, "ExtensionContent", "resource://gre/modules/ExtensionContent.jsm");
-
+XPCOMUtils.defineLazyServiceGetter(this, "favicons",
+                                   "@mozilla.org/browser/favicon-service;1",
+                                   "mozIAsyncFavicons");
 // Assumptions on events module:
 // events needs to be dispatched synchronously,
 // by calling the listeners in the order or registration.
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 
 loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
 
 function getWindowID(window) {
@@ -1218,16 +1219,50 @@ TabActor.prototype = {
 
     // We watch for all child docshells under the current document,
     this._progressListener.watch(this.docShell);
 
     // And list all already existing ones.
     this._updateChildDocShells();
   },
 
+
+  // FIXME Also try to fetch low-res favicon. But we should use actor
+  // support for this to get the high-res one (bug 1061654).
+  onGetFavicon() {
+    let url = new URL(this.url);
+    if (url.protocol.startsWith("http")) {
+      if (!(url instanceof Ci.nsIURI)) {
+         url = Services.io.newURI(url, null, null);
+      }
+
+      return new Promise(resolve => {
+        favicons.getFaviconURLForPage(url, uri => {
+          if (uri) {
+            uri = favicons.getFaviconLinkForIcon(uri);
+            resolve(uri.spec);
+          } else {
+            resolve(favicons.defaultFavicon.spec);
+          }
+        });
+      }).then(iconUri => {
+        return {
+          "from": this.actorID,
+          "icon": iconUri
+        };
+      });
+    } else {
+      return {
+        "from": this.actorID,
+        "icon": favicons.defaultFavicon.spec
+      };
+    }
+  },
+
+
   onSwitchToFrame(request) {
     let windowId = request.windowId;
     let win;
 
     try {
       win = Services.wm.getOuterWindowWithId(windowId);
     } catch (e) {
       // ignore
@@ -2119,17 +2154,18 @@ TabActor.prototype.requestTypes = {
   "detach": TabActor.prototype.onDetach,
   "focus": TabActor.prototype.onFocus,
   "reload": TabActor.prototype.onReload,
   "navigateTo": TabActor.prototype.onNavigateTo,
   "reconfigure": TabActor.prototype.onReconfigure,
   "switchToFrame": TabActor.prototype.onSwitchToFrame,
   "listFrames": TabActor.prototype.onListFrames,
   "listWorkers": TabActor.prototype.onListWorkers,
-  "resolveLocation": TabActor.prototype.onResolveLocation
+  "resolveLocation": TabActor.prototype.onResolveLocation,
+  "getFavicon": TabActor.prototype.onGetFavicon
 };
 
 exports.TabActor = TabActor;
 
 /**
  * Creates a tab actor for handling requests to a single in-process
  * <xul:browser> tab, or <html:iframe>.
  * Most of the implementation comes from TabActor.