Bug 1498185 - Implement the type and action columns in the new about:performance, r=felipe.
☠☠ backed out by 2e10a4e70394 ☠ ☠
authorFlorian Quèze <florian@queze.net>
Wed, 17 Oct 2018 22:24:14 +0200
changeset 497572 37647eaadbc29b3f744b225825414bca6bad5b1c
parent 497543 3a58f94c3f5ad656c0c96abf87d0522c3066690e
child 497573 4c0be70aed863561a6c9d7ee84bf63b9acfb51eb
push id9996
push userarchaeopteryx@coole-files.de
push dateThu, 18 Oct 2018 18:37:15 +0000
treeherdermozilla-beta@8efe26839243 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe
bugs1498185
milestone64.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
Bug 1498185 - Implement the type and action columns in the new about:performance, r=felipe.
toolkit/components/aboutperformance/content/aboutPerformance.js
toolkit/components/aboutperformance/content/aboutPerformance.xhtml
toolkit/themes/shared/icons/shortcut.svg
toolkit/themes/shared/jar.inc.mn
--- a/toolkit/components/aboutperformance/content/aboutPerformance.js
+++ b/toolkit/components/aboutperformance/content/aboutPerformance.js
@@ -609,35 +609,40 @@ var State = {
         if (id in this._buffer[index].tabs) {
           oldest = this._buffer[index].tabs[id];
           break;
         }
       }
       let prev = previous[id];
       let host = tab.host;
 
+      let type = "tab";
       let name = `${host} (${id})`;
       let image = "chrome://mozapps/skin/places/defaultFavicon.svg";
       let found = tabFinder.get(parseInt(id));
       if (found) {
         if (found.tabbrowser) {
           name = found.tab.getAttribute("label");
           image = found.tab.getAttribute("image");
         } else {
           name = "Preloaded: " + found.tab.linkedBrowser.contentTitle;
+          type = "other";
         }
       } else if (id == 1) {
         name = BRAND_NAME;
         image = "chrome://branding/content/icon32.png";
+        type = "browser";
       } else if (/^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/.test(host)) {
         let addon = WebExtensionPolicy.getByHostname(host);
         name = `${addon.name} (${addon.id})`;
         image = "chrome://mozapps/skin/extensions/extensionGeneric-16.svg";
+        type = "addon";
       } else if (id == 0 && !tab.isWorker) {
         name = "Ghost windows";
+        type = "other";
       }
 
       // Create a map of all the child items from the previous time we read the
       // counters, indexed by counterId so that we can quickly find the previous
       // value for any subitem.
       let prevChildren = new Map();
       if (prev) {
         for (let child of prev.children) {
@@ -686,17 +691,17 @@ var State = {
           dispatches - prev.dispatchCount - (prev.dispatchesFromFormerChildren || 0);
       }
       if (oldest) {
         dispatchesSinceStartOfBuffer =
           dispatches - oldest.dispatchCount - (oldest.dispatchesFromFormerChildren || 0);
         durationSinceStartOfBuffer =
           duration - oldest.duration - (oldest.durationFromFormerChildren || 0);
       }
-      return ({id, name, image,
+      return ({id, name, image, type,
                totalDispatches: dispatches, totalDuration: duration,
                durationSincePrevious, dispatchesSincePrevious,
                durationSinceStartOfBuffer, dispatchesSinceStartOfBuffer,
                children});
     });
   },
 };
 
@@ -995,36 +1000,57 @@ var View = {
       tbody.firstChild.remove();
     tbody.appendChild(this._fragment);
     this._fragment = document.createDocumentFragment();
   },
   insertAfterRow(row) {
     row.parentNode.insertBefore(this._fragment, row.nextSibling);
     this._fragment = document.createDocumentFragment();
   },
-  appendRow(name, value, tooltip, classes, image = "") {
+  appendRow(name, value, tooltip, type, image = "") {
     let row = document.createElement("tr");
 
     let elt = document.createElement("td");
     elt.textContent = name;
     if (image)
       elt.style.backgroundImage = `url('${image}')`;
-    if (classes)
-      elt.classList.add(...classes);
-    if (!classes || !classes.includes("indent"))
+
+    if (["subframe", "tracker", "worker"].includes(type))
+      elt.classList.add("indent");
+    else
       elt.classList.add("root");
+    if (["tracker", "worker"].includes(type))
+      elt.classList.add(type);
+    row.appendChild(elt);
+
+    elt = document.createElement("td");
+    elt.textContent = type;
     row.appendChild(elt);
 
     elt = document.createElement("td");
     elt.textContent = value;
     row.appendChild(elt);
 
     if (tooltip)
       row.title = tooltip;
 
+    elt = document.createElement("td");
+    if (type == "tab") {
+      let img = document.createElement("img");
+      img.className = "action-icon close-icon";
+      img.title = "Close tab";
+      elt.appendChild(img);
+    } else if (type == "addon") {
+      let img = document.createElement("img");
+      img.className = "action-icon addon-icon";
+      img.title = "Show in add-on manager";
+      elt.appendChild(img);
+    }
+    row.appendChild(elt);
+
     this._fragment.appendChild(row);
     return row;
   },
 };
 
 var Control = {
   _openItems: new Set(),
   init() {
@@ -1044,16 +1070,39 @@ var Control = {
         } else {
           this._openItems.delete(id);
           while (row.nextSibling.firstChild.classList.contains("indent"))
             row.nextSibling.remove();
         }
         return;
       }
 
+      // Handle closing a tab.
+      if (target.classList.contains("close-icon")) {
+        let row = target.parentNode.parentNode;
+        let id = parseInt(row.windowId);
+        let found = tabFinder.get(id);
+        if (!found || !found.tabbrowser)
+          return;
+        let {tabbrowser, tab} = found;
+        tabbrowser.removeTab(tab);
+        while (row.nextSibling.firstChild.classList.contains("indent"))
+          row.nextSibling.remove();
+        row.remove();
+        return;
+      }
+
+      if (target.classList.contains("addon-icon")) {
+        let row = target.parentNode.parentNode;
+        let id = row.windowId;
+        let parentWin = window.docShell.rootTreeItem.domWindow;
+        parentWin.BrowserOpenAddonsMgr("addons://detail/" + encodeURIComponent(id));
+        return;
+      }
+
       // Handle selection changes
       let row = target.parentNode;
       if (this.selectedRow) {
         this.selectedRow.removeAttribute("selected");
       }
       if (row.windowId) {
         row.setAttribute("selected", "true");
         this.selectedRow = row;
@@ -1105,24 +1154,24 @@ var Control = {
       if (this.selectedRow) {
         selectedId = this.selectedRow.windowId;
         this.selectedRow = null;
       }
       let openItems = this._openItems;
       this._openItems = new Set();
 
       let counters = this._sortCounters(State.getCounters());
-      for (let {id, name, image, totalDispatches, dispatchesSincePrevious,
+      for (let {id, name, image, type, totalDispatches, dispatchesSincePrevious,
                 totalDuration, durationSincePrevious, children} of counters) {
         let row =
           View.appendRow(name,
                          this._formatEnergyImpact(dispatchesSincePrevious, durationSincePrevious),
                          this._formatTooltip(totalDispatches, totalDuration,
                                              dispatchesSincePrevious, durationSincePrevious),
-                         null, image);
+                         type, image);
         row.windowId = id;
         if (id == selectedId) {
           row.setAttribute("selected", "true");
           this.selectedRow = row;
         }
 
         if (!children.length)
           continue;
@@ -1150,28 +1199,28 @@ var Control = {
     // Inform watchers
     Services.obs.notifyObservers(null, UPDATE_COMPLETE_TOPIC, mode);
   },
   _showChildren(row) {
     let children = row._children;
     children.sort((a, b) => b.dispatchesSincePrevious - a.dispatchesSincePrevious);
     for (let row of children) {
       let host = row.host.replace(/^blob:https?:\/\//, "");
-      let classes = ["indent"];
+      let type = "subframe";
       if (State.isTracker(host))
-        classes.push("tracking");
+        type = "tracker";
       if (row.isWorker)
-        classes.push("worker");
+        type = "worker";
       View.appendRow(row.host,
                      this._formatEnergyImpact(row.dispatchesSincePrevious,
                                               row.durationSincePrevious),
                      this._formatTooltip(row.dispatchCount, row.duration,
                                          row.dispatchesSincePrevious,
                                          row.durationSincePrevious),
-                     classes);
+                     type);
     }
   },
   _computeEnergyImpact(dispatches, duration) {
     // 'Dispatches' doesn't make sense to users, and it's difficult to present
     // two numbers in a meaningful way, so we need to somehow aggregate the
     // dispatches and duration values we have.
     // The current formula to aggregate the numbers assumes that the cost of
     // a dispatch is equivalent to 1ms of CPU time.
--- a/toolkit/components/aboutperformance/content/aboutPerformance.xhtml
+++ b/toolkit/components/aboutperformance/content/aboutPerformance.xhtml
@@ -130,17 +130,61 @@
         height: 2em;
       }
       #dispatch-thead, #dispatch-tbody tr {
         display: table;
         table-layout: fixed;
         width: 100%;
       }
       #dispatch-table td:nth-child(2) {
-        width: 10em;
+        width: 8em;
+      }
+      #dispatch-table td:nth-child(3) {
+        width: 12em;
+      }
+      #dispatch-table td:nth-child(4) {
+        width: 20px;
+      }
+
+      /* Show action icons on selected or hovered rows */
+      tr:-moz-any([selected], :hover) > td > .action-icon {
+        padding: 1px 10px;
+        -moz-context-properties: fill, fill-opacity;
+        fill-opacity: 0;
+        background-repeat: no-repeat;
+        background-position: center;
+        fill: currentColor;
+      }
+      .addon-icon {
+        background-image: url(chrome://global/skin/icons/shortcut.svg);
+        background-size: 16px;
+      }
+      .close-icon {
+        background-image: url(chrome://global/skin/icons/close.svg);
+        background-size: 24px;
+      }
+      .action-icon {
+        position: relative;
+      }
+      /* action icon background */
+      .action-icon::before {
+        background-color: currentColor;
+        opacity: 0;
+        height: 200%;
+        position: absolute;
+        top: -50%;
+        left: -3px;
+        padding-left: 13px;
+        padding-right: 13px;
+      }
+      .action-icon:hover::before {
+        opacity: 0.1;
+      }
+      .action-icon:hover:active::before {
+        opacity: 0.2;
       }
 
       #dispatch-table > tbody {
         border-top: 1px solid var(--in-content-border-color);
       }
       #dispatch-table > thead > tr > td {
         border: none;
         background-color: var(--in-content-box-background-hover);
@@ -152,21 +196,21 @@
         border-image: linear-gradient(transparent 0%, transparent 20%, #c1c1c1 20%, #c1c1c1 80%, transparent 80%, transparent 100%) 1 1;
         border-bottom: 1px solid var(--in-content-border-color);
       }
       #dispatch-tbody > tr > td {
         padding: 5px 10px;
         min-height: 2em;
         color: var(--in-content-text-color);
         max-width: 70vw;
-        text-overflow: ellipsis;
         overflow: hidden;
         white-space: nowrap;
       }
       #dispatch-tbody > tr > td:first-child {
+        text-overflow: ellipsis;
         padding-inline-start: 32px;
         background-repeat: no-repeat;
         background-size: 16px 16px;
       }
       #dispatch-tbody > tr > td.root{
         background-position: 36px;
         padding-inline-start: 62px;
       }
@@ -183,17 +227,17 @@
       }
       .twisty.open {
         background-image: url("chrome://global/skin/icons/twisty-expanded.svg");
       }
       #dispatch-tbody > tr > td.indent {
         padding-inline-start: 88px;
         background-position: 62px;
       }
-      #dispatch-tbody > tr > td.tracking {
+      #dispatch-tbody > tr > td.tracker {
         background-image: url(chrome://browser/skin/controlcenter/trackers.svg);
         -moz-context-properties: fill;
         fill: rgb(224, 41, 29);
       }
       #dispatch-tbody > tr > td.worker {
         background-image: url(chrome://devtools/skin/images/debugging-workers.svg);
         -moz-context-properties: fill;
         fill: #808080;
@@ -234,16 +278,18 @@
       <div id="webpages" class="measuring">
       </div>
     </div>
     <div>
       <table id="dispatch-table">
         <thead id="dispatch-thead">
           <tr>
             <td>Name</td>
+            <td>Type</td>
             <td>Energy Impact</td>
+            <td></td><!-- actions -->
           </tr>
         </thead>
         <tbody id="dispatch-tbody"></tbody>
       </table>
     </div>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/icons/shortcut.svg
@@ -0,0 +1,4 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="context-fill" d="M11 2H5a1 1 0 0 0 0 2h3.59L6.05 6.54a7 7 0 0 0-2 5V13a1 1 0 0 0 2 0v-1.51A5 5 0 0 1 7.46 8L10 5.41V9a1 1 0 0 0 2 0V3a1 1 0 0 0-1-1z"/></svg>
--- a/toolkit/themes/shared/jar.inc.mn
+++ b/toolkit/themes/shared/jar.inc.mn
@@ -35,16 +35,17 @@ toolkit.jar:
   skin/classic/global/icons/error.svg                      (../../shared/icons/error.svg)
   skin/classic/global/icons/find-previous-arrow.svg        (../../shared/icons/find-previous-arrow.svg)
   skin/classic/global/icons/find-next-arrow.svg            (../../shared/icons/find-next-arrow.svg)
   skin/classic/global/icons/help.svg                       (../../shared/icons/help.svg)
   skin/classic/global/icons/info.svg                       (../../shared/incontent-icons/info.svg)
   skin/classic/global/icons/loading.png                    (../../shared/icons/loading.png)
   skin/classic/global/icons/loading@2x.png                 (../../shared/icons/loading@2x.png)
   skin/classic/global/icons/resizer.svg                    (../../shared/icons/resizer.svg)
+  skin/classic/global/icons/shortcut.svg                   (../../shared/icons/shortcut.svg)
   skin/classic/global/icons/spinner-arrow-down.svg         (../../shared/icons/spinner-arrow-down.svg)
   skin/classic/global/icons/spinner-arrow-up.svg           (../../shared/icons/spinner-arrow-up.svg)
   skin/classic/global/icons/twisty-collapsed.svg           (../../shared/icons/twisty-collapsed.svg)
   skin/classic/global/icons/twisty-collapsed-rtl.svg       (../../shared/icons/twisty-collapsed-rtl.svg)
   skin/classic/global/icons/twisty-expanded.svg            (../../shared/icons/twisty-expanded.svg)
   skin/classic/global/icons/arrow-dropdown-12.svg          (../../shared/icons/arrow-dropdown-12.svg)
   skin/classic/global/icons/arrow-dropdown-16.svg          (../../shared/icons/arrow-dropdown-16.svg)
   skin/classic/global/icons/warning.svg                    (../../shared/icons/warning.svg)