Bug 1207107 - Design update for aboutCertError;r=dao, a=sylvestre
authorBrian Grinstead <bgrinstead@mozilla.com>
Thu, 29 Oct 2015 15:37:41 -0700
changeset 305358 bacfca882a0c0efa60130824e374dd0964a93a78
parent 305357 e8d4a3fe4645ea50c2fa5618541c1ae8bd52086a
child 305359 00fe0e2bbdbbaccea3e87549d76464d28cd677f1
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao, sylvestre
bugs1207107
milestone44.0a2
Bug 1207107 - Design update for aboutCertError;r=dao, a=sylvestre
browser/base/content/aboutcerterror/aboutCertError.xhtml
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_aboutCertError.js
browser/base/content/test/general/browser_bug431826.js
browser/base/content/test/general/browser_bug633691.js
browser/themes/shared/aboutCertError.css
browser/themes/shared/incontent-icons/cert-error.svg
browser/themes/shared/jar.inc.mn
--- a/browser/base/content/aboutcerterror/aboutCertError.xhtml
+++ b/browser/base/content/aboutcerterror/aboutCertError.xhtml
@@ -13,17 +13,17 @@
   %certerrorDTD;
 ]>
 
 <!-- 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/. -->
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
-    <title>&certerror.pagetitle;</title>
+    <title>&certerror.pagetitle1;</title>
     <link rel="stylesheet" href="chrome://browser/skin/aboutCertError.css" type="text/css" media="all" />
     <link rel="stylesheet" href="chrome://browser/content/certerror/aboutCertError.css" type="text/css" media="all" />
     <!-- This page currently uses the same favicon as neterror.xhtml.
          If the location of the favicon is changed for both pages, the
          FAVICON_ERRORPAGE_URL symbol in toolkit/components/places/src/nsFaviconService.h
          should be updated. If this page starts using a different favicon
          than neterror.xhtml nsFaviconService->SetAndLoadFaviconForPage
          should be updated to ignore this one as well. -->
@@ -46,56 +46,61 @@
         // s is optional, if no match just return nothing
         if (!matches || matches.length < 2)
           return "";
 
         // parenthetical match is the second entry
         return decodeURIComponent(matches[1]);
       }
 
+      function goBack(buttonEl)
+      {
+        if (history.length > 1) {
+          history.back();
+        } else {
+          location.href = "about:home";
+        }
+        buttonEl.disabled = true;
+      }
+
+      function toggleVisibility(id)
+      {
+        var node = document.getElementById(id);
+        node.style.visibility = node.style.visibility == "" ? "hidden" : "";
+      }
+
       function getDescription()
       {
         var url = document.documentURI;
         var desc = url.search(/d\=/);
 
         // desc == -1 if not found; if so, return an empty string
         // instead of what would turn out to be portions of the URI
         if (desc == -1)
           return "";
 
         return decodeURIComponent(url.slice(desc + 2));
       }
 
       function initPage()
       {
-        // Replace the "#1" string in the intro with the hostname.  Trickier
-        // than it might seem since we want to preserve the <b> tags, but
-        // not allow for any injection by just using innerHTML.  Instead,
-        // just find the right target text node.
-        var intro = document.getElementById('introContentP1');
-        function replaceWithHost(node) {
-          if (node.textContent == "#1")
-            node.textContent = location.host;
-          else
-            for(var i = 0; i < node.childNodes.length; i++)
-              replaceWithHost(node.childNodes[i]);
-        };
-        replaceWithHost(intro);
+        for (let host of document.querySelectorAll(".hostname")) {
+          host.textContent = document.location.hostname;
+        }
 
         var cssClass = getCSSClass();
         if (cssClass == "expertBadCert") {
-          toggle('technicalContent');
-          toggle('expertContent');
+          toggleVisibility('advancedPanel');
         }
 
         // Disallow overrides if this is a Strict-Transport-Security
         // host and the cert is bad (STS Spec section 7.3) or if the
         // certerror is in a frame (bug 633691).
         if (cssClass == "badStsCert" || window != top) {
-          document.getElementById("expertContent").setAttribute("hidden", "true");
+          document.getElementById("advancedPanel").setAttribute("hidden", "true");
         }
         if (cssClass != "badStsCert") {
           document.getElementById("badStsCertExplanation").setAttribute("hidden", "true");
         }
 
         var tech = document.getElementById("technicalContentText");
         if (tech)
           tech.textContent = getDescription();
@@ -162,86 +167,64 @@
          * Make sure to include the "." ahead of thisHost so that
          * a MitM attack on paypal.com doesn't hyperlink to "notpaypal.com"
          *
          * We'd normally just use a RegExp here except that we lack a
          * library function to escape them properly (bug 248062), and
          * domain names are famous for having '.' characters in them,
          * which would allow spurious and possibly hostile matches.
          */
-        if (endsWith(okHost, "." + thisHost))
+        if (okHost.endsWith("." + thisHost))
           link.href = proto + okHost;
 
         /* case #2:
          * browser.garage.maemo.org uses an invalid security certificate.
          *
          * The certificate is only valid for garage.maemo.org
          */
-        if (endsWith(thisHost, "." + okHost))
+        if (thisHost.endsWith("." + okHost))
           link.href = proto + okHost;
 
         // If we set a link, meaning there's something helpful for
         // the user here, expand the section by default
         if (link.href && getCSSClass() != "expertBadCert")
-          toggle("technicalContent");
-      }
-
-      function endsWith(haystack, needle) {
-        return haystack.slice(-needle.length) == needle;
-      }
-
-      function toggle(id) {
-        var el = document.getElementById(id);
-        if (el.getAttribute("collapsed"))
-          el.removeAttribute("collapsed");
-        else
-          el.setAttribute("collapsed", true);
+          toggleVisibility("advancedPanel");
       }
     ]]></script>
   </head>
 
   <body dir="&locale.dir;">
-
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
 
       <!-- Error Title -->
       <div id="errorTitle">
-        <h1 id="errorTitleText">&certerror.longpagetitle;</h1>
+        <h1 id="errorTitleText">&certerror.longpagetitle1;</h1>
       </div>
 
       <!-- LONG CONTENT (the section most likely to require scrolling) -->
       <div id="errorLongContent">
-        <div id="introContent">
-          <p id="introContentP1">&certerror.introPara1;</p>
-          <p>&certerror.introPara2;</p>
+
+        <!-- Short Description -->
+        <div id="errorShortDesc">
+          <p>&certerror.introPara;</p>
         </div>
-
-        <div id="whatShouldIDoContent">
-          <h2>&certerror.whatShouldIDo.heading;</h2>
-          <div id="whatShouldIDoContentText">
-            <p>&certerror.whatShouldIDo.content;</p>
-            <p id="badStsCertExplanation">&certerror.whatShouldIDo.badStsCertExplanation;</p>
-            <button id='getMeOutOfHereButton'>&certerror.getMeOutOfHere.label;</button>
-          </div>
+        <p id="badStsCertExplanation">&certerror.whatShouldIDo.badStsCertExplanation;</p>
+        <div>
+          <p><a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&certerror.learnMore;</a></p>
         </div>
 
-        <!-- The following sections can be unhidden by default by setting the
-             "browser.xul.error_pages.expert_bad_cert" pref to true -->
-        <h2 id="technicalContent" class="expander" collapsed="true">
-          <button onclick="toggle('technicalContent');">&certerror.technical.heading;</button>
-        </h2>
-        <p id="technicalContentText"/>
-
-        <h2 id="expertContent" class="expander" collapsed="true">
-          <button onclick="toggle('expertContent');">&certerror.expert.heading;</button>
-        </h2>
-        <div>
-          <p>&certerror.expert.content;</p>
-          <p>&certerror.expert.contentPara2;</p>
+        <div id="buttonContainer">
+          <button id="returnButton" autocomplete="off" onclick="goBack(this);" autofocus="true">&certerror.returnToPreviousPage.label;</button>
+          <div id="buttonSpacer"></div>
+          <button id="advancedButton" autocomplete="off" onclick="toggleVisibility('advancedPanel');" autofocus="true">&certerror.advanced.label;</button>
+        </div>
+        <!-- Advanced panel, which is hidden by default -->
+        <div id="advancedPanel" style="visibility: hidden;">
+          <p id="technicalContentText"/>
           <button id='exceptionDialogButton'>&certerror.addException.label;</button>
         </div>
       </div>
     </div>
 
     <!--
     - Note: It is important to run the script this way, instead of using
     - an onload handler. This is because error pages are loaded as
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -117,16 +117,17 @@ support-files =
   file_bug1045809_2.html
 
 [browser_URLBarSetURI.js]
 skip-if = (os == "linux" || os == "mac") && debug # bug 970052, bug 970053
 [browser_aboutAccounts.js]
 skip-if = os == "linux" # Bug 958026
 support-files =
   content_aboutAccounts.js
+[browser_aboutCertError.js]
 [browser_aboutSupport_newtab_security_state.js]
 [browser_aboutHealthReport.js]
 skip-if = os == "linux" # Bug 924307
 [browser_aboutHome.js]
 skip-if = e10s # Bug 1093153 - no about:home support yet
 [browser_action_keyword.js]
 [browser_action_keyword_override.js]
 [browser_action_searchengine.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_aboutCertError.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This is testing the aboutCertError page (Bug 1207107).  It's a start,
+// but should be expanded to include cert_domain_link / badStsCert
+
+const GOOD_PAGE = "https://example.com/";
+const BAD_CERT = "https://expired.example.com/";
+
+add_task(function* checkReturnToAboutHome() {
+  info("Loading a bad cert page directly and making sure 'return to previous page' goes to about:home");
+  let browser;
+  let certErrorLoaded;
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+    gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
+    browser = gBrowser.selectedBrowser;
+    certErrorLoaded = waitForCertErrorLoad(browser);
+  }, false);
+
+  info("Loading and waiting for the cert error");
+  yield certErrorLoaded;
+
+  is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
+  is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
+
+  info("Clicking the go back button on about:certerror");
+  let pageshowPromise = promiseWaitForEvent(browser, "pageshow");
+  yield ContentTask.spawn(browser, null, function* () {
+    let doc = content.document;
+    let returnButton = doc.getElementById("returnButton");
+    returnButton.click();
+  });
+  yield pageshowPromise;
+
+  is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
+  is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
+  is(gBrowser.currentURI.spec, "about:home", "Went back");
+
+  gBrowser.removeCurrentTab();
+});
+
+add_task(function* checkReturnToPreviousPage() {
+  info("Loading a bad cert page and making sure 'return to previous page' goes back");
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
+  let browser = gBrowser.selectedBrowser;
+
+  info("Loading and waiting for the cert error");
+  let certErrorLoaded = waitForCertErrorLoad(browser);
+  BrowserTestUtils.loadURI(browser, BAD_CERT);
+  yield certErrorLoaded;
+
+  is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
+  is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
+
+  info("Clicking the go back button on about:certerror");
+  let pageshowPromise = promiseWaitForEvent(browser, "pageshow");
+  yield ContentTask.spawn(browser, null, function* () {
+    let doc = content.document;
+    let returnButton = doc.getElementById("returnButton");
+    returnButton.click();
+  });
+  yield pageshowPromise;
+
+  is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
+  is(browser.webNavigation.canGoForward, true, "webNavigation.canGoForward");
+  is(gBrowser.currentURI.spec, GOOD_PAGE, "Went back");
+
+  gBrowser.removeCurrentTab();
+});
+
+function waitForCertErrorLoad(browser) {
+  return new Promise(resolve => {
+    info("Waiting for DOMContentLoaded event");
+    browser.addEventListener("DOMContentLoaded", function load() {
+      browser.removeEventListener("DOMContentLoaded", load, false, true);
+      resolve();
+    }, false, true);
+  });
+}
--- a/browser/base/content/test/general/browser_bug431826.js
+++ b/browser/base/content/test/general/browser_bug431826.js
@@ -4,38 +4,39 @@ function test() {
   gBrowser.selectedTab = gBrowser.addTab();
 
   // Navigate to a site with a broken cert
   window.addEventListener("DOMContentLoaded", testBrokenCert, true);
   content.location = "https://nocert.example.com/";
 }
 
 function testBrokenCert() {
+  if (gBrowser.contentDocument.documentURI === "about:blank")
+    return;
   window.removeEventListener("DOMContentLoaded", testBrokenCert, true);
 
   // Confirm that we are displaying the contributed error page, not the default
   ok(gBrowser.contentDocument.documentURI.startsWith("about:certerror"), "Broken page should go to about:certerror, not about:neterror");
 
   // Confirm that the expert section is collapsed
-  var expertDiv = gBrowser.contentDocument.getElementById("expertContent");
-  ok(expertDiv, "Expert content div should exist");
-  ok(expertDiv.hasAttribute("collapsed"), "Expert content should be collapsed by default");
+  var advancedDiv = gBrowser.contentDocument.getElementById("advancedPanel");
+  ok(advancedDiv, "Advanced content div should exist");
+  is_element_hidden(advancedDiv, "Advanced content should not be visible by default");
 
   // Tweak the expert mode pref
   gPrefService.setBoolPref("browser.xul.error_pages.expert_bad_cert", true);
 
   window.addEventListener("DOMContentLoaded", testExpertPref, true);
   gBrowser.reload();
 }
 
 function testExpertPref() {
   window.removeEventListener("DOMContentLoaded", testExpertPref, true);
-  var expertDiv = gBrowser.contentDocument.getElementById("expertContent");
-  var technicalDiv = gBrowser.contentDocument.getElementById("technicalContent");
-  ok(!expertDiv.hasAttribute("collapsed"), "Expert content should not be collapsed with the expert mode pref set");
-  ok(!technicalDiv.hasAttribute("collapsed"), "Technical content should not be collapsed with the expert mode pref set");
+  var advancedDiv = gBrowser.contentDocument.getElementById("advancedPanel");
+  ok(advancedDiv, "Advanced content div should exist");
+  is_element_visible(advancedDiv, "Advanced content should be visible by default");
 
   // Clean up
   gBrowser.removeCurrentTab();
   if (gPrefService.prefHasUserValue("browser.xul.error_pages.expert_bad_cert"))
     gPrefService.clearUserPref("browser.xul.error_pages.expert_bad_cert");
   finish();
 }
--- a/browser/base/content/test/general/browser_bug633691.js
+++ b/browser/base/content/test/general/browser_bug633691.js
@@ -12,17 +12,17 @@ function test() {
 
 function testIframeCert(e) {
   if (e.target.location.href == "about:blank") {
     return;
   }
   gBrowser.selectedBrowser.removeEventListener("load", testIframeCert, true);
   // Confirm that the expert section is hidden
   var doc = gBrowser.contentDocument.getElementsByTagName('iframe')[0].contentDocument;
-  var eC = doc.getElementById("expertContent");
-  ok(eC, "Expert content should exist")
-  ok(eC.hasAttribute("hidden"), "Expert content should be hidded by default");
+  var aP = doc.getElementById("advancedPanel");
+  ok(aP, "Advanced content should exist");
+  is_element_hidden(aP, "Advanced content should not be visible by default")
 
   // Clean up
   gBrowser.removeCurrentTab();
-  
+
   finish();
 }
--- a/browser/themes/shared/aboutCertError.css
+++ b/browser/themes/shared/aboutCertError.css
@@ -1,72 +1,98 @@
 /* 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/. */
 
-
-html {
-  background: -moz-Dialog;
-}
+@import url("chrome://global/skin/in-content/common.css");
 
 body {
-  margin: 0;
-  padding: 0 1em;
-  color: -moz-FieldText;
-  font: message-box;
-}
-
-h1 {
-  margin: 0 0 .6em 0;
-  border-bottom: 1px solid ThreeDLightShadow;
-  font-size: 160%;
-}
-
-h2 {
-  font-size: 130%;
+  display: flex;
+  box-sizing: border-box;
+  min-height: 100vh;
+  padding: 0 48px;
+  align-items: center;
+  justify-content: center;
 }
 
 #errorPageContainer {
   position: relative;
-  min-width: 13em;
-  max-width: 52em;
-  margin: 4em auto;
-  border: 1px solid #FFBD09; /* pale yellow extracted from yellow passport icon */
-  border-radius: 10px;
-  padding: 3em;
-  -moz-padding-start: 30px;
-  background: url("chrome://global/skin/icons/sslWarning.png") left 0 no-repeat -moz-Field;
-  background-origin: content-box;
-}
-
-#errorPageContainer:-moz-dir(rtl) {
-  background-position: right 0;
+  min-width: 320px;
+  max-width: 512px;
 }
 
 #errorTitle {
-  -moz-margin-start: 80px;
+  background: url("chrome://browser/skin/cert-error.svg") left 0 no-repeat;
+  background-size: 3em;
+  margin-inline-start: -5em;
+  padding-inline-start: 5em;
 }
 
-#errorLongContent {
-  -moz-margin-start: 80px;
+#errorTitle:-moz-dir(rtl) {
+  background-position: right 0;
+}
+
+#errorTitleText {
+  border-bottom: 1px solid #C1C1C1;
+  padding-bottom: 0.4em;
 }
 
-.expander > button {
-  -moz-padding-start: 20px;
-  -moz-margin-start: -20px;
-  background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
-  border: none;
-  font: inherit;
-  color: inherit;
+@media (max-width: 675px) {
+  #errorTitle {
+    padding-top: 0;
+    background-image: none;
+    margin-inline-start: 0;
+    padding-inline-start: 0;
+  }
+}
+
+#buttonContainer {
+  display: flex;
+  flex-flow: row wrap;
+}
+
+#buttonSpacer {
+  flex: 1;
+}
+
+/* Pressing the retry button will cause the cursor to flicker from a pointer to
+ * not-allowed. Override the disabled cursor behaviour since we will never show
+ * the button disabled as the initial state. Remove this in Bug 1219861. */
+button:disabled {
   cursor: pointer;
 }
 
-.expander > button:-moz-dir(rtl) {
-  background-position: right center;
+#returnButton {
+  background-color: var(--in-content-primary-button-background);
+  border: none;
+  color: var(--in-content-selected-text);
+  min-width: 250px;
+  margin-inline-start: 0;
+}
+
+#returnButton:hover {
+  background-color: var(--in-content-primary-button-background-hover) !important;
+}
+
+#returnButton:hover:active {
+  background-color: var(--in-content-primary-button-background-active) !important;
 }
 
-.expander[collapsed] > button {
-  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
+#advancedButton {
+  min-width: 150px;
 }
 
-.expander[collapsed] > button:-moz-dir(rtl) {
-  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
+/* Advanced section is hidden via inline styles until the link is clicked */
+#advancedPanel {
+  background-color: white;
+  color: var(--in-content-text-color);
+  border: 1px lightgray solid;
+  /* Don't use top padding because the default p style has top padding, and it
+   * makes the overall div look uneven */
+  padding: 0 12px 10px;
+  margin-top: 10px;
+  box-shadow: 0 0 4px #ddd;
+  font-size: 0.9em;
 }
+
+.hostname {
+  font-weight: bold;
+}
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/incontent-icons/cert-error.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     width="45"
+     height="45"
+     viewBox="0 0 45 45">
+
+  <style>
+    .icon-default {
+      fill: #999;
+    }
+  </style>
+
+  <defs>
+    <rect id="shape-lock-clasp-outer" x="8" y="2" width="28" height="40" rx="14" ry="14" />
+    <rect id="shape-lock-clasp-inner" x="14" y="8" width="16" height="28" rx="8" ry="8" />
+    <rect id="shape-lock-base" x="4" y="18" width="36" height="24" rx="3" ry="3" />
+
+    <mask id="mask-clasp-cutout">
+      <rect width="48" height="48" fill="#000" />
+      <use xlink:href="#shape-lock-clasp-outer" fill="#fff" />
+      <use xlink:href="#shape-lock-clasp-inner" fill="#000" />
+      <line x1="4" y1="38" x2="41" y2="3" stroke="#000" stroke-width="5.5" />
+      <line x1="4" y1="46" x2="41" y2="11" stroke="#000" stroke-width="5.5" />
+      <rect x="4" y="18" width="36" height="26" rx="6" ry="6" />
+    </mask>
+
+    <mask id="mask-base-cutout">
+      <rect width="45" height="45" fill="#000" />
+      <use xlink:href="#shape-lock-base" fill="#fff" />
+      <line x1="2.5" y1="41.5" x2="41" y2="5" stroke="#000" stroke-width="8.5" />
+    </mask>
+  </defs>
+
+  <use xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)" fill="#999" />
+  <use xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)" fill="#999" />
+
+  <line x1="2.5" y1="41.5" x2="41" y2="5" stroke="#d92d21" stroke-width="5.5" />
+
+</svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -109,16 +109,17 @@
   skin/classic/browser/translation-16@2x.png                   (../shared/translation/translation-16@2x.png)
   skin/classic/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
   skin/classic/browser/undoCloseTab@2x.png                     (../shared/undoCloseTab@2x.png)
   skin/classic/browser/update-badge.svg                        (../shared/update-badge.svg)
   skin/classic/browser/update-badge-failed.svg                 (../shared/update-badge-failed.svg)
   skin/classic/browser/urlbar-arrow.png                        (../shared/urlbar-arrow.png)
   skin/classic/browser/urlbar-arrow@2x.png                     (../shared/urlbar-arrow@2x.png)
   skin/classic/browser/warning.svg                             (../shared/warning.svg)
+  skin/classic/browser/cert-error.svg                          (../shared/incontent-icons/cert-error.svg)
   skin/classic/browser/session-restore.svg                     (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                         (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/welcome-back.svg                        (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-tour.png                         (../shared/reader/reader-tour.png)
   skin/classic/browser/reader-tour@2x.png                      (../shared/reader/reader-tour@2x.png)
   skin/classic/browser/readerMode.svg                          (../shared/reader/readerMode.svg)
   skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
   skin/classic/browser/notification-pluginNormal@2x.png        (../shared/plugins/notification-pluginNormal@2x.png)