# HG changeset patch # User Chelsea Carr # Date 1354491769 18000 # Node ID 32eb1e57d1aa43008b7eb9aadcc198bd9c3b0814 # Parent 541ccce39563cf1e660747e1bcbede359a6cccaf Bug 793920: Moved Readability.js and JSDOMparser.js to reader/toolkit * * * Bug 795973:Kevin added a preference * * * Bug 795981:Made fixes to previous patch. * * * Bug test: Reader Mode is working. diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -21,6 +21,8 @@ #endif #endif + + pref("browser.chromeURL","chrome://browser/content/"); pref("browser.hiddenWindowChromeURL", "chrome://browser/content/hiddenWindow.xul"); @@ -1192,3 +1194,10 @@ pref("social.toast-notifications.enabled", true); pref("dom.identity.enabled", false); + +//Reader settings +pref("reader.margin_size", 5); +pref("reader.font_size", 12); +pref("reader.color_scheme", "light"); +pref("reader.has_used_toolbar", false); +pref("reader.enabled", false); diff --git a/browser/base/content/aboutReader.html b/browser/base/content/aboutReader.html new file mode 100644 --- /dev/null +++ b/browser/base/content/aboutReader.html @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + +
+
+

+
+
+ +
+
+ +
+ +
+ + + + diff --git a/browser/base/content/aboutReader.js b/browser/base/content/aboutReader.js new file mode 100644 --- /dev/null +++ b/browser/base/content/aboutReader.js @@ -0,0 +1,561 @@ +/* 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/. */ + +let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm") +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyGetter(window, "gChromeWin", function () + window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow) + .QueryInterface(Ci.nsIDOMChromeWindow)); + +function dump(s) { + Services.console.logStringMessage("AboutReader: " + s); +} + +let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutReader.properties"); + +let AboutReader = function(doc, win) { + this._docRef = Cu.getWeakReference(doc); + this._winRef = Cu.getWeakReference(win); + + this._article = null; + + dump("Feching toolbar, header and content notes from about:reader"); + this._headerElementRef = Cu.getWeakReference(doc.getElementById("reader-header")); + this._domainElementRef = Cu.getWeakReference(doc.getElementById("reader-domain")); + + this._titleElementRef = Cu.getWeakReference(doc.getElementById("reader-title")); + + this._creditsElementRef = Cu.getWeakReference(doc.getElementById("reader-credits")); + this._contentElementRef = Cu.getWeakReference(doc.getElementById("reader-content")); + this._toolbarElementRef = Cu.getWeakReference(doc.getElementById("reader-toolbar")); + + this._toolbarEnabled = true; + + this._scrollOffset = win.pageYOffset; + + win.addEventListener("click", this, false); + + win.addEventListener("scroll", this, false); + win.addEventListener("popstate", this, false); + win.addEventListener("resize", this, false); + + this._setupAllDropdowns(); + + let colorSchemeOptions = [ + { name: gStrings.GetStringFromName("aboutReader.colorSchemeLight"), + value: "light"}, + { name: gStrings.GetStringFromName("aboutReader.colorSchemeDark"), + value: "dark"} + ]; + + let colorScheme = Services.prefs.getCharPref("reader.color_scheme"); + this._setupSegmentedButton("color-scheme-buttons", colorSchemeOptions, colorScheme, this._setColorScheme.bind(this)); + this._setColorScheme(colorScheme); + + let fontTitle = gStrings.GetStringFromName("aboutReader.textTitle"); + this._setupStepControl("font-size-control", fontTitle, this._onFontSizeChange.bind(this)); + this._fontSize = 0; + this._setFontSize(Services.prefs.getIntPref("reader.font_size")); + + let marginTitle = gStrings.GetStringFromName("aboutReader.marginTitle"); + this._setupStepControl("margin-size-control", marginTitle, this._onMarginSizeChange.bind(this)); + this._marginSize = 0; + this._setMarginSize(Services.prefs.getIntPref("reader.margin_size")); + + dump("Decoding query arguments"); + let queryArgs = this._decodeQueryString(win.location.href); + + let url = queryArgs.url; + let tabId = 1; + if (tabId) { + dump("Loading from tab with ID: " + tabId + ", URL: " + url); + this._loadFromTab(tabId, url); + } else { + dump("Fetching page with URL: " + url); + this._loadFromURL(url); + } +} + +AboutReader.prototype = { + _STEP_INCREMENT: 0, + _STEP_DECREMENT: 1, + + _BLOCK_IMAGES_SELECTOR: ".content p > img:only-child, " + + ".content p > a:only-child > img:only-child, " + + ".content .wp-caption img, " + + ".content figure img", + + get _doc() { + return this._docRef.get(); + }, + + get _win() { + return this._winRef.get(); + }, + + get _headerElement() { + return this._headerElementRef.get(); + }, + + get _domainElement() { + return this._domainElementRef.get(); + }, + + get _titleElement() { + return this._titleElementRef.get(); + }, + + get _creditsElement() { + return this._creditsElementRef.get(); + }, + + get _contentElement() { + return this._contentElementRef.get(); + }, + + get _toolbarElement() { + return this._toolbarElementRef.get(); + }, + + handleEvent: function Reader_handleEvent(aEvent) { + if (!aEvent.isTrusted) + return; + + switch (aEvent.type) { + case "click": + this._scrolled = false; + if (!this._scrolled) + this._toggleToolbarVisibility(); + break; + case "scroll": + if (!this._scrolled) { + this._scrolled = true; + this._setToolbarVisibility(false); + } + break; + case "popstate": + if (!aEvent.state) + this._closeAllDropdowns(); + break; + case "resize": + this._updateImageMargins(); + break; + } + }, + + _onMarginSizeChange: function Reader_onMarginSizeChange(operation) { + if (operation == this._STEP_INCREMENT) + this._setMarginSize(this._marginSize + 5); + else + this._setMarginSize(this._marginSize - 5); + }, + + _setMarginSize: function Reader_setMarginSize(newMarginSize) { + if (this._marginSize === newMarginSize) + return; + + let doc = this._doc; + + this._marginSize = Math.max(5, Math.min(25, newMarginSize)); + doc.body.style.marginLeft = this._marginSize + "%"; + doc.body.style.marginRight = this._marginSize + "%"; + + this._updateImageMargins(); + + Services.prefs.setIntPref("reader.margin_size", this._marginSize); + }, + + _onFontSizeChange: function Reader_onFontSizeChange(operation) { + if (operation == this._STEP_INCREMENT) + this._setFontSize(this._fontSize + 1); + else + this._setFontSize(this._fontSize - 1); + }, + + _setFontSize: function Reader_setFontSize(newFontSize) { + if (this._fontSize === newFontSize) + return; + + let bodyClasses = this._doc.body.classList; + + if (this._fontSize > 0) + bodyClasses.remove("font-size" + this._fontSize); + + this._fontSize = Math.max(1, Math.min(7, newFontSize)); + bodyClasses.add("font-size" + this._fontSize); + + Services.prefs.setIntPref("reader.font_size", this._fontSize); + }, + + _setColorScheme: function Reader_setColorScheme(newColorScheme) { + if (this._colorScheme === newColorScheme) + return; + + let bodyClasses = this._doc.body.classList; + + if (this._colorScheme) + bodyClasses.remove(this._colorScheme); + + this._colorScheme = newColorScheme; + bodyClasses.add(this._colorScheme); + + Services.prefs.setCharPref("reader.color_scheme", this._colorScheme); + }, + + _getToolbarVisibility: function Reader_getToolbarVisibility() { + return !this._toolbarElement.classList.contains("toolbar-hidden"); + }, + + _setToolbarVisibility: function Reader_setToolbarVisibility(visible) { + let win = this._win; + if (win.history.state) + win.history.back(); + + if (!this._toolbarEnabled) + return; + + if (this._getToolbarVisibility() === visible) + return; + + this._toolbarElement.classList.toggle("toolbar-hidden"); + + if (!visible && !this._hasUsedToolbar) { + this._hasUsedToolbar = Services.prefs.getBoolPref("reader.has_used_toolbar"); + if (!this._hasUsedToolbar) { + Services.prefs.setBoolPref("reader.has_used_toolbar", true); + this._hasUsedToolbar = true; + } + } + }, + + _toggleToolbarVisibility: function Reader_toggleToolbarVisibility(visible) { + this._setToolbarVisibility(!this._getToolbarVisibility()); + }, + + _loadFromURL: function Reader_loadFromURL(url) { + this._showProgress(); + gChromeWin.Reader.parseDocumentFromURL(url, function(article) { + + if (article) { + this._showContent(article); + } + else { + this._showError(gStrings.GetStringFromName("aboutReader.loadError")); + } + }.bind(this)); + }, + + _loadFromTab: function Reader_loadFromTab(tabId, url) { + this._showProgress(); + + gChromeWin.Reader.getArticleForTab(tabId, url, function(article) { + if (article) + this._showContent(article); + else + this._showError(gStrings.GetStringFromName("aboutReader.loadError")); + }.bind(this)); + }, + + + + _updateImageMargins: function Reader_updateImageMargins() { + let windowWidth = this._win.innerWidth; + let contentWidth = this._contentElement.offsetWidth; + let maxWidthStyle = windowWidth + "px !important"; + + let setImageMargins = function(img) { + if (!img._originalWidth) + img._originalWidth = img.offsetWidth; + + let imgWidth = img._originalWidth; + + // If the image is taking more than half of the screen, just make + // it fill edge-to-edge. + if (imgWidth < contentWidth && imgWidth > windowWidth * 0.55) + imgWidth = windowWidth; + + let sideMargin = Math.max((contentWidth - windowWidth) / 2, + (contentWidth - imgWidth) / 2); + + let imageStyle = sideMargin + "px !important"; + let widthStyle = imgWidth + "px !important"; + + let cssText = "max-width: " + maxWidthStyle + ";" + + "width: " + widthStyle + ";" + + "margin-left: " + imageStyle + ";" + + "margin-right: " + imageStyle + ";"; + + img.style.cssText = cssText; + } + + let imgs = this._doc.querySelectorAll(this._BLOCK_IMAGES_SELECTOR); + for (let i = imgs.length; --i >= 0;) { + let img = imgs[i]; + + if (img.width > 0) { + setImageMargins(img); + } else { + img.onload = function() { + setImageMargins(img); + } + } + } + }, + + _showError: function Reader_showError(error) { + this._headerElement.style.display = "none"; + this._contentElement.innerHTML = error; + this._contentElement.style.display = "block"; + + this._doc.title = error; + }, + + _showContent: function Reader_showContent(article) { + this._article = article; + + let domain = Services.io.newURI(article.url, null, null).host; + this._domainElement.innerHTML = domain; + + this._creditsElement.innerHTML = article.byline; + + this._titleElement.innerHTML = article.title; + this._doc.title = article.title; + + this._headerElement.style.display = "block"; + + this._contentElement.innerHTML = article.content; + this._updateImageMargins(); + + this._contentElement.style.display = "block"; + + + this._toolbarEnabled = true; + this._setToolbarVisibility(true); + }, + + _hideContent: function Reader_hideContent() { + this._headerElement.style.display = "none"; + this._contentElement.style.display = "none"; + }, + + _showProgress: function Reader_showProgress() { + this._headerElement.style.display = "none"; + this._contentElement.innerHTML = gStrings.GetStringFromName("aboutReader.loading"); + this._contentElement.style.display = "block"; + }, + + _decodeQueryString: function Reader_decodeQueryString(url) { + let result = {}; + let query = url.split("?")[1]; + if (query) { + let pairs = query.split("&"); + for (let i = 0; i < pairs.length; i++) { + let [name, value] = pairs[i].split("="); + result[name] = decodeURIComponent(value); + } + } + + return result; + }, + + _setupStepControl: function Reader_setupStepControl(id, name, callback) { + let doc = this._doc; + let stepControl = doc.getElementById(id); + + while (stepControl.hasChildNodes()) { + stepControl.removeChild(stepControl.lastChild); + } + + let title = this._doc.createElement("h1"); + title.innerHTML = name; + stepControl.appendChild(title); + + let plusButton = doc.createElement("div"); + plusButton.className = "button plus-button"; + stepControl.appendChild(plusButton); + + let minusButton = doc.createElement("div"); + minusButton.className = "button minus-button"; + stepControl.appendChild(minusButton); + + plusButton.addEventListener("click", function(aEvent) { + if (!aEvent.isTrusted) + return; + + aEvent.stopPropagation(); + callback(this._STEP_INCREMENT); + }.bind(this), true); + + minusButton.addEventListener("click", function(aEvent) { + if (!aEvent.isTrusted) + return; + + aEvent.stopPropagation(); + callback(this._STEP_DECREMENT); + }.bind(this), true); + }, + + _setupSegmentedButton: function Reader_setupSegmentedButton(id, options, initialValue, callback) { + let doc = this._doc; + let segmentedButton = doc.getElementById(id); + + if (segmentedButton != null) { + while (segmentedButton.hasChildNodes()) { + if (segmentedButton.lastChild.tagName == "LI") { + segmentedButton.removeChild(segmentedButton.lastChild); + } + } + } + for (let i = 0; i < options.length; i++) { + let option = options[i]; + + let item = doc.createElement("li"); + let link = doc.createElement("a"); + link.innerHTML = option.name; + item.appendChild(link); + + segmentedButton.appendChild(item); + + link.addEventListener("click", function(aEvent) { + if (!aEvent.isTrusted) + return; + + aEvent.stopPropagation(); + + let items = segmentedButton.children; + for (let j = items.length - 1; j >= 0; j--) { + items[j].classList.remove("selected"); + } + + item.classList.add("selected"); + callback(option.value); + }.bind(this), true); + + if (option.value === initialValue) + item.classList.add("selected"); + } + }, + + _setupButton: function Reader_setupButton(id, callback) { + let button = this._doc.getElementById(id); + + button.addEventListener("click", function(aEvent) { + if (!aEvent.isTrusted) + return; + + aEvent.stopPropagation(); + callback(); + }, true); + }, + + _setupAllDropdowns: function Reader_setupAllDropdowns() { + let doc = this._doc; + let win = this._win; + + let dropdowns = doc.getElementsByClassName("dropdown"); + + for (let i = dropdowns.length - 1; i >= 0; i--) { + let dropdown = dropdowns[i]; + + let dropdownToggle = dropdown.getElementsByClassName("dropdown-toggle")[0]; + let dropdownPopup = dropdown.getElementsByClassName("dropdown-popup")[0]; + + if (!dropdownToggle || !dropdownPopup) + continue; + + for (var j = 0; j < dropdownPopup.childNodes.length; j++) { + if (dropdownPopup.childNodes[j].className == "dropdown-arrow") { + dropdownPopup.removeChild(dropdownPopup.childNodes[j]); + } + } + + let dropdownArrow = doc.createElement("div"); + dropdownArrow.className = "dropdown-arrow"; + dropdownPopup.appendChild(dropdownArrow); + + let updatePopupPosition = function() { + let popupWidth = dropdownPopup.offsetWidth + 30; + let arrowWidth = dropdownArrow.offsetWidth; + let toggleWidth = dropdownToggle.offsetWidth; + let toggleLeft = dropdownToggle.offsetLeft; + + let popupShift = (toggleWidth - popupWidth) / 2; + let popupLeft = Math.max(0, Math.min(win.innerWidth - popupWidth, toggleLeft + popupShift)); + dropdownPopup.style.left = popupLeft + "px"; + + let arrowShift = (toggleWidth - arrowWidth) / 2; + let arrowLeft = toggleLeft - popupLeft + arrowShift; + dropdownArrow.style.left = arrowLeft + "px"; + }; + + win.addEventListener("resize", function(aEvent) { + if (!aEvent.isTrusted) + return; + + updatePopupPosition(); + }, true); + + dropdownToggle.addEventListener("click", function(aEvent) { + if (!aEvent.isTrusted) + return; + + aEvent.stopPropagation(); + + let dropdownClasses = dropdown.classList; + + if (dropdownClasses.contains("open")) { + win.history.back(); + } else { + updatePopupPosition(); + if (!this._closeAllDropdowns()) + this._pushDropdownState(); + + dropdownClasses.add("open"); + } + }.bind(this), true); + } + }, + + _pushDropdownState: function Reader_pushDropdownState() { + // FIXME: We're getting a NS_ERROR_UNEXPECTED error when we try + // to do win.history.pushState() here (see bug 682296). This is + // a workaround that allows us to push history state on the target + // content document. + + let doc = this._doc; + let body = doc.body; + + if (this._pushStateScript) + body.removeChild(this._pushStateScript); + + for (var j = 0; j < body.childNodes.length; j++) { + if (body.childNodes[j].type == "text/javascript") { + body.removeChild(body.childNodes[j]); + } + } + + this._pushStateScript = doc.createElement('script'); + this._pushStateScript.type = "text/javascript"; + this._pushStateScript.innerHTML = 'history.pushState({ dropdown: 1 }, document.title);'; + + body.appendChild(this._pushStateScript); + }, + + _closeAllDropdowns : function Reader_closeAllDropdowns() { + let dropdowns = this._doc.querySelectorAll(".dropdown.open"); + for (let i = dropdowns.length - 1; i >= 0; i--) { + dropdowns[i].classList.remove("open"); + } + + return (dropdowns.length > 0) + } +}; diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -44,6 +44,17 @@ }); }); + [ + ["AboutReader", "chrome://browser/content/aboutReader.js"], + ].forEach(function (aScript) { + let [name, script] = aScript; + XPCOMUtils.defineLazyGetter(window, name, function() { + let sandbox = {}; + Services.scriptloader.loadSubScript(script, sandbox); + return sandbox[name]; + }); + }); + // Smart getter for the findbar. If you don't wish to force the creation of // the findbar, check gFindBarInitialized first. var gFindBarInitialized = false; @@ -154,7 +165,8 @@ "about:newtab", "about:home", "about:privatebrowsing", - "about:sessionrestore" + "about:sessionrestore", + "about:reader" ]; #include browser-addons.js @@ -211,14 +223,17 @@ * one listener that calls all real handlers. */ function pageShowEventHandlers(event) { - charsetLoadListener(); - XULBrowserWindow.asyncUpdateUI(); - - // The PluginClickToPlay events are not fired when navigating using the - // BF cache. |event.persisted| is true when the page is loaded from the - // BF cache, so this code reshows the notification if necessary. - if (event.persisted) - gPluginHandler.reshowClickToPlayNotification(); + charsetLoadListener(); + XULBrowserWindow.asyncUpdateUI(); + + // The PluginClickToPlay events are not fired when navigating using the + // BF cache. |event.persisted| is true when the page is loaded from the + // BF cache, so this code reshows the notification if necessary. + if (event.persisted) { + gPluginHandler.reshowClickToPlayNotification(); + } + + ReaderMode.PageShowHandler(); } function UpdateBackForwardCommands(aWebNavigation) { @@ -1180,6 +1195,8 @@ #endif // Misc. inits. + ReaderMode.init(); + Reader.init(); CombinedStopReload.init(); allTabs.readPref(); TabsOnTop.init(); @@ -1266,14 +1283,16 @@ gFormSubmitObserver.init(); SocialUI.init(); AddonManager.addAddonListener(AddonsMgrListener); - + gBrowser.addEventListener("pageshow", function(event) { - // Filter out events that are not about the document load we are interested in - if (event.target == content.document) - setTimeout(pageShowEventHandlers, 0, event); - }, true); - - // Ensure login manager is up and running. +      // Filter out events that are not about the document load we are interested in +      if (event.target == content.document) +        setTimeout(pageShowEventHandlers, 0, event); +    }, true); + + gBrowser.tabContainer.addEventListener("TabSelect", function(evt) { setTimeout(ReaderMode.TabSwitchHandler, 0, evt); }, true); + + // Ensure login manager is up and running. Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); if (mustLoadSidebar) { @@ -5657,6 +5676,85 @@ gPageStyleMenu.disableStyle(); } +var newTabBrowser = null; +var savedArticle = null; +var ar = null; + +var ReaderMode = { + _inited: false, + + //////////////////////////// + // ReaderMode Public Methods + init: function () + { + //Reader Button disable/enable + document.getElementById("reader-button").hidden = true;//!gPrefService.getBoolPref("reader.enabled"); + }, + +  //Reader Mode On-Click + BrowserOpenReaderMode: function(aEvent) { + document.getElementById("reader-button").hidden = true;                             + openUILink("about:reader?url=" + gBrowser.currentURI.specIgnoringRef, {target:gBrowser.selectedTab}); + newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab); + newTabBrowser.addEventListener("DOMContentLoaded", ReaderMode.handleDomContentLoaded, true); + }, + + PageShowHandler: function() { + ReaderMode.checkReaderMode(); + if (savedArticle == null) { + document.getElementById("reader-button").hidden = true; + } + else { + document.getElementById("reader-button").hidden = false; + } + }, + + TabSwitchHandler: function(event) { + ReaderMode.checkReaderMode(); + if (savedArticle == null) { + document.getElementById("reader-button").hidden = true; + } + else { + document.getElementById("reader-button").hidden = false; + } + }, + + handleDomContentLoaded: function(event) { +  if (/^about:reader/.test(newTabBrowser.currentURI.specIgnoringRef)) { + new AboutReader(newTabBrowser.contentDocument, newTabBrowser.contentWindow); + newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab); +      newTabBrowser.removeEventListener("DOMContentLoaded", ReaderMode.handleDomContentLoaded, true);   + }  + }, + + checkReaderMode: function() { + savedArticle = null; + if (gPrefService.getBoolPref("reader.enabled")) { + + Reader.parseDocumentFromTab(gBrowser.selectedTab, function (article) { +     // Do nothing if there's no article or the page in this tab has +     // changed +      let tabURL = gBrowser.currentURI.specIgnoringRef; +      if (article == null || (article.url != tabURL)) { +        // Don't clear the article for about:reader pages since we want to +        // use the article from the previous page +        if (tabURL.startsWith("about:reader")) +          savedArticle = null; +                               +        return; +      }                +      savedArticle = article; + if (savedArticle != null) { + document.getElementById("reader-button").hidden = false; + } + else { + document.getElementById("reader-button").hidden = true; + alert("Not a readable page"); + } + }.bind(this)); + } + } +}; var BrowserOffline = { _inited: false, @@ -7657,3 +7755,428 @@ if (element.ownerDocument == document) focusAndSelectUrlBar(); } + + +let Reader = { + // Version of the cache database schema +DB_VERSION: 1, + +DEBUG: 1, + + // Don't try to parse the page if it has too many elements (for memory and + // performance reasons) +MAX_ELEMS_TO_PARSE: 3000, + +init: function Reader_init() { + this.log("Init()"); + this._requests = {}; + + Services.obs.addObserver(this, "Reader:Add", false); + Services.obs.addObserver(this, "Reader:Remove", false); +}, + +observe: function(aMessage, aTopic, aData) { + switch(aTopic) { + case "Reader:Add": { + //let tab = gBrowser.selectedTab; + let currentURI = gBrowser.currentURI; + let url = currentURI.spec; + + let sendResult = function(success, title) { + this.log("Reader:Add success=" + success + ", url=" + url + ", title=" + title); + + /*sendMessageToJava({ + gecko: { + type: "Reader:Added", + success: success, + title: title, + url: url, + } + });*/ + }.bind(this); + + this.getArticleForTab(aData, currentURI.specIgnoringRef, function (article) { + if (!article) { + sendResult(false, ""); + return; + } + + this.storeArticleInCache(article, function(success) { + sendResult(success, article.title); + }); + }.bind(this)); + break; + } + + case "Reader:Remove": { + this.removeArticleFromCache(aData, function(success) { + this.log("Reader:Remove success=" + success + ", url=" + aData); + }.bind(this)); + break; + } + } +}, + +parseDocumentFromURL: function Reader_parseDocumentFromURL(url, callback) { + // If there's an on-going request for the same URL, simply append one + // more callback to it to be called when the request is done. + if (url in this._requests) { + let request = this._requests[url]; + request.callbacks.push(callback); + return; + } + + let request = { url: url, callbacks: [callback] }; + this._requests[url] = request; + + try { + this.log("parseDocumentFromURL: " + url); + + // First, try to find a cached parsed article in the DB + this.getArticleFromCache(url, function(article) { + if (article) { + //this.log("Page found in cache, return article immediately"); + this._runCallbacksAndFinish(request, article); + return; + } + + if (!this._requests) { + this.log("Reader has been destroyed, abort"); + return; + } + + // Article hasn't been found in the cache DB, we need to + // download the page and parse the article out of it. + this._downloadAndParseDocument(url, request); + }.bind(this)); + } catch (e) { + this.log("Error parsing document from URL: " + e); + this._runCallbacksAndFinish(request, null); + } +}, + +getArticleForTab: function Reader_getArticleForTab(tabId, url, callback) { + //let tab = gBrowser.getTabForId(tabId); + let article = savedArticle; + + if (article && article.url == url) { + this.log("Saved article found in tab"); + callback(article); + } else { + this.parseDocumentFromURL(url, callback); + } +}, + +parseDocumentFromTab: function(tabId, callback) { + try { + this.log("parseDocumentFromTab: " + tabId); + + //let tab = gBrowser.getTabForId(tabId); + let url = gBrowser.contentWindow.location.href; + let uri = Services.io.newURI(url, null, null); + + if (!this._shouldCheckUri(uri)) { + callback(null); + return; + } + + // First, try to find a cached parsed article in the DB + this.getArticleFromCache(url, function(article) { + if (article) { + this.log("Page found in cache, return article immediately"); + callback(article); + return; + } + + let doc = gBrowser.contentWindow.document; + this._readerParse(uri, doc, function (article) { + if (!article) { + this.log("Failed to parse page"); + callback(null); + return; + } + callback(article); + }.bind(this)); + }.bind(this)); + } catch (e) { + this.log("Error parsing document from tab: " + e); + callback(null); + } +}, + +getArticleFromCache: function Reader_getArticleFromCache(url, callback) { + this._getCacheDB(function(cacheDB) { + if (!cacheDB) { + callback(false); + return; + } + let transaction = cacheDB.transaction(cacheDB.objectStoreNames); + let articles = transaction.objectStore(cacheDB.objectStoreNames[0]); + + let request = articles.get(url); + + request.onerror = function(event) { + this.log("Error getting article from the cache DB: " + url); + callback(null); + }.bind(this); + + request.onsuccess = function(event) { + this.log("Got article from the cache DB! "); + callback(event.target.result); + }.bind(this); + }.bind(this)); +}, + +storeArticleInCache: function Reader_storeArticleInCache(article, callback) { + this._getCacheDB(function(cacheDB) { + if (!cacheDB) { + callback(false); + return; + } + + let transaction = cacheDB.transaction(cacheDB.objectStoreNames, "readwrite"); + let articles = transaction.objectStore(cacheDB.objectStoreNames[0]); + + let request = articles.add(article); + + request.onerror = function(event) { + this.log("Error storing article in the cache DB: " + article.url); + callback(false); + }.bind(this); + + request.onsuccess = function(event) { + //this.log("Stored article in the cache DB: " + article.url); + callback(true); + }.bind(this); + }.bind(this)); +}, + +removeArticleFromCache: function Reader_removeArticleFromCache(url, callback) { + this._getCacheDB(function(cacheDB) { + if (!cacheDB) { + callback(false); + return; + } + + let transaction = cacheDB.transaction(cacheDB.objectStoreNames, "readwrite"); + let articles = transaction.objectStore(cacheDB.objectStoreNames[0]); + + let request = articles.delete(url); + + request.onerror = function(event) { + this.log("Error removing article from the cache DB: " + url); + callback(false); + }.bind(this); + + request.onsuccess = function(event) { + this.log("Removed article from the cache DB: " + url); + callback(true); + }.bind(this); + }.bind(this)); +}, + +uninit: function Reader_uninit() { + Services.obs.removeObserver(this, "Reader:Add", false); + Services.obs.removeObserver(this, "Reader:Remove", false); + + let requests = this._requests; + for (let url in requests) { + let request = requests[url]; + if (request.browser) { + let browser = request.browser; + browser.parentNode.removeChild(browser); + } + } + delete this._requests; + + if (this._cacheDB) { + this._cacheDB.close(); + delete this._cacheDB; + } +}, + +log: function(msg) { + if (this.DEBUG) + dump("Reader: " + msg); +}, + +_shouldCheckUri: function Reader_shouldCheckUri(uri) { + if ((uri.prePath + "/") === uri.spec) { + //this.log("Not parsing home page: " + uri.spec); + return false; + } + + if (!(uri.schemeIs("http") || uri.schemeIs("https") || uri.schemeIs("file"))) { + //this.log("Not parsing URI scheme: " + uri.scheme); + return false; + } + + return true; +}, + +_readerParse: function Reader_readerParse(uri, doc, callback) { + let numTags = doc.getElementsByTagName("*").length; + if (numTags > this.MAX_ELEMS_TO_PARSE) { + //this.log("Aborting parse for " + uri.spec + "; " + numTags + " elements found"); + callback(null); + return; + } + + let worker = new ChromeWorker("resource://gre/modules/readerWorker.jsm"); + worker.onmessage = function (evt) { + let article = evt.data; + + // Append URL to the article data. specIgnoringRef will ignore any hash + // in the URL. + if (article) + article.url = uri.specIgnoringRef; + + callback(article); + }; + + try { + worker.postMessage({ + uri: { + spec: uri.spec, + host: uri.host, + prePath: uri.prePath, + scheme: uri.scheme, + pathBase: Services.io.newURI(".", null, uri).spec + }, + doc: new XMLSerializer().serializeToString(doc) + }); + } catch (e) { + this.log("Reader: could not build Readability arguments: " + e); + callback(null); + } +}, + +_runCallbacksAndFinish: function Reader_runCallbacksAndFinish(request, result) { + delete this._requests[request.url]; + + request.callbacks.forEach(function(callback) { + callback(result); + }); +}, + +_downloadDocument: function Reader_downloadDocument(url, callback) { + // We want to parse those arbitrary pages safely, outside the privileged + // context of chrome. We create a hidden browser element to fetch the + // loaded page's document object then discard the browser element. + + let browser = document.createElement("browser"); + browser.setAttribute("type", "content"); + browser.setAttribute("collapsed", "true"); + + document.documentElement.appendChild(browser); + browser.stop(); + + browser.webNavigation.allowAuth = false; + browser.webNavigation.allowImages = false; + browser.webNavigation.allowJavascript = false; + browser.webNavigation.allowMetaRedirects = true; + browser.webNavigation.allowPlugins = false; + + browser.addEventListener("DOMContentLoaded", function (event) { + let doc = event.originalTarget; + + // ignore on frames and other documents + if (doc != browser.contentDocument) + return; + + this.log("Done loading: " + doc); + if (doc.location.href == "about:blank") { + callback(null); + + // Request has finished with error, remove browser element + browser.parentNode.removeChild(browser); + return; + } + + callback(doc); + }.bind(this)); + + browser.loadURIWithFlags(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, null, null); + + return browser; +}, + +_downloadAndParseDocument: function Reader_downloadAndParseDocument(url, request) { + try { + this.log("Needs to fetch page, creating request: " + url); + + request.browser = this._downloadDocument(url, function(doc) { + this.log("Finished loading page: " + doc); + + if (!doc) { + this.log("Error loading page"); + this._runCallbacksAndFinish(request, null); + return; + } + + this.log("Parsing response with Readability"); + + let uri = Services.io.newURI(url, null, null); + this._readerParse(uri, doc, function (article) { + // Delete reference to the browser element as we've finished parsing. + let browser = request.browser; + if (browser) { + browser.parentNode.removeChild(browser); + delete request.browser; + } + + if (!article) { + this.log("Failed to parse page"); + this._runCallbacksAndFinish(request, null); + return; + } + + this.log("Parsing has been successful"); + + this._runCallbacksAndFinish(request, article); + }.bind(this)); + }.bind(this)); + } catch (e) { + this.log("Error downloading and parsing document: " + e); + this._runCallbacksAndFinish(request, null); + } +}, + +_getCacheDB: function Reader_getCacheDB(callback) { + if (this._cacheDB) { + callback(this._cacheDB); + return; + } + + let request = window.indexedDB.open("about:reader", this.DB_VERSION); + + request.onerror = function(event) { + //this.log("Error connecting to the cache DB"); + this._cacheDB = null; + callback(null); + }.bind(this); + + request.onsuccess = function(event) { + //this.log("Successfully connected to the cache DB"); + this._cacheDB = event.target.result; + callback(this._cacheDB); + }.bind(this); + + request.onupgradeneeded = function(event) { + this.log("Database schema upgrade from " + + event.oldVersion + " to " + event.newVersion); + + let cacheDB = event.target.result; + + // Create the articles object store + this.log("Creating articles object store"); + cacheDB.createObjectStore("articles", { keyPath: "url" }); + + this.log("Database upgrade done: " + this.DB_VERSION); + }.bind(this); +} +}; + + + diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -606,7 +606,9 @@ class="urlbar-icon" hidden="true" onclick="SocialShareButton.onClick(event);"/> - + diff --git a/browser/base/jar.mn b/browser/base/jar.mn --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -19,6 +19,8 @@ * content/browser/aboutDialog.js (content/aboutDialog.js) content/browser/aboutDialog.css (content/aboutDialog.css) content/browser/aboutRobots.xhtml (content/aboutRobots.xhtml) + content/browser/aboutReader.html (content/aboutReader.html) + content/browser/aboutReader.js (content/aboutReader.js) content/browser/abouthome/aboutHome.xhtml (content/abouthome/aboutHome.xhtml) * content/browser/abouthome/aboutHome.js (content/abouthome/aboutHome.js) * content/browser/abouthome/aboutHome.css (content/abouthome/aboutHome.css) diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -80,6 +80,9 @@ nsIAboutModule::ALLOW_SCRIPT }, { "preferences", "chrome://browser/content/preferences/in-content/preferences.xul", nsIAboutModule::ALLOW_SCRIPT }, + { "reader", "chrome://browser/content/aboutReader.html", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::ALLOW_SCRIPT }, }; static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap); diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp --- a/browser/components/build/nsModule.cpp +++ b/browser/components/build/nsModule.cpp @@ -108,6 +108,7 @@ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #if defined(XP_WIN) { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID }, #elif defined(XP_MACOSX) diff --git a/mobile/android/locales/en-US/chrome/aboutReader.properties b/browser/locales/en-US/chrome/browser/aboutReader.properties copy from mobile/android/locales/en-US/chrome/aboutReader.properties copy to browser/locales/en-US/chrome/browser/aboutReader.properties diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -9,6 +9,7 @@ locale/browser/aboutCertError.dtd (%chrome/browser/aboutCertError.dtd) locale/browser/aboutDialog.dtd (%chrome/browser/aboutDialog.dtd) locale/browser/aboutPrivateBrowsing.dtd (%chrome/browser/aboutPrivateBrowsing.dtd) + locale/browser/aboutReader.properties (%chrome/browser/aboutReader.properties) locale/browser/aboutRobots.dtd (%chrome/browser/aboutRobots.dtd) locale/browser/aboutHome.dtd (%chrome/browser/aboutHome.dtd) locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd) diff --git a/browser/themes/gnomestripe/browser.css b/browser/themes/gnomestripe/browser.css --- a/browser/themes/gnomestripe/browser.css +++ b/browser/themes/gnomestripe/browser.css @@ -1430,6 +1430,11 @@ list-style-image: url("chrome://browser/skin/places/pageStarred.png"); } +/* Reader Button */ +#reader-button { + list-style-image: url("chrome://browser/skin/places/reader.png"); +} + /* Bookmarking panel */ #editBookmarkPanelStarIcon { list-style-image: url("chrome://browser/skin/places/starred48.png"); diff --git a/browser/themes/gnomestripe/jar.mn b/browser/themes/gnomestripe/jar.mn --- a/browser/themes/gnomestripe/jar.mn +++ b/browser/themes/gnomestripe/jar.mn @@ -75,6 +75,13 @@ skin/classic/browser/places/organizer.xml (places/organizer.xml) skin/classic/browser/places/query.png (places/query.png) skin/classic/browser/places/starPage.png (places/starPage.png) + skin/classic/browser/places/reader.png (places/reader.png) + skin/classic/browser/places/readerDropdownArrow@2x.png (places/readerDropdownArrow@2x.png) + skin/classic/browser/places/readerMinusIcon@2x.png (places/readerMinusIcon@2x.png) + skin/classic/browser/places/readerPlusIcon@2x.png (places/readerPlusIcon@2x.png) + skin/classic/browser/places/readerStyleIcon@2x.png (places/readerStyleIcon@2x.png) + skin/classic/browser/places/readerToolbarBg@2x.png (places/readerToolbarBg@2x.png) + skin/classic/browser/places/aboutReader.css (places/aboutReader.css) skin/classic/browser/places/tag.png (places/tag.png) skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png) skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png) diff --git a/mobile/android/themes/core/aboutReader.css b/browser/themes/gnomestripe/places/aboutReader.css copy from mobile/android/themes/core/aboutReader.css copy to browser/themes/gnomestripe/places/aboutReader.css --- a/mobile/android/themes/core/aboutReader.css +++ b/browser/themes/gnomestripe/places/aboutReader.css @@ -7,7 +7,7 @@ } body { - font-family: "OpenSansRegular","Droid Sans",sans-serif; + font-family: sans-serif; margin-top: 20px; margin-bottom: 20px; } @@ -42,7 +42,7 @@ } .header > h1 { - font-family: "OpenSansLight","Droid Sans",sans-serif; + font-family: sans-serif; font-weight: normal; line-height: 1.1em; width: 100%; @@ -321,19 +321,18 @@ } .toolbar { - font-family: "Droid Sans",helvetica,arial,clean,sans-serif; - -moz-transition-property: visibility, opacity; - -moz-transition-duration: 0.7s; - visibility: visible; - opacity: 1.0; - position: fixed; - width: 100%; - bottom: 0px; - left: 0px; - margin: 0; - padding: 0; - list-style: none; - background-repeat: repeat; + font-family: helvetica,arial,clean,sans-serif; + visibility: visible; + opacity: 1.0; + position: fixed; + width: 3%; + height: 45px; + bottom: 0px; + margin: 0; + padding: 10px 4px 0 24px; + list-style: none; + background-repeat: repeat; + left: 1%; } .toolbar-hidden { @@ -343,10 +342,10 @@ opacity: 0.0; } -.toolbar > * { +/*.toolbar > * { float: right; - width: 25%; -} + width: 5%; +}*/ .button { color: white; @@ -364,6 +363,7 @@ display: inline-block; list-style: none; margin: 0px; + margin-left: -15px; padding: 0px; } @@ -380,7 +380,6 @@ .dropdown-popup { text-align: left; position: absolute; - left: 0px; z-index: 1000; float: left; background: #dde2e7; @@ -391,6 +390,7 @@ font-size: 14px; box-shadow: 0px -1px 12px #333; visibility: hidden; + width: 225px; } .dropdown-popup > hr { @@ -416,11 +416,11 @@ .dropdown-arrow { position: absolute; - width: 40px; - height: 18px; + width: 60px; + height: 24px; bottom: -18px; - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png'); - background-size: 40px 18px; + background-image: url('chrome://browser/skin/places/readerDropdownArrow@2x.png'); + background-size: 60px 24px; background-position: center; display: block; } @@ -482,296 +482,27 @@ } .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-mdpi.png'); + background-image: url('chrome://browser/skin/places/readerPlusIcon@2x.png'); border-left: 1px solid #ccc; margin-right: 4px; + width: 30px; + height: 30px; } .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-mdpi.png'); + background-image: url('chrome://browser/skin/places/readerMinusIcon@2x.png'); + width: 30px; + height: 30px; } -@media screen and (orientation: portrait) { - .button { - height: 48px; - background-size: 30px 24px - } - - .toolbar { - background-size: 48px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-mdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-mdpi.png'); - } +.toolbar { + background-image: url('chrome://browser/skin/places/readerToolbarBg@2x.png'); } -@media screen and (orientation: landscape) { - .button { - height: 40px; - background-size: 24px 20px - } - - .toolbar { - background-size: 40px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-mdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-mdpi.png'); - } +.style-button { + background-image: url('chrome://browser/skin/places/readerStyleIcon@2x.png'); + width: 45px; + height: 36px; + left: -10px; } -@media screen and (min-width: 960px) { - .button { - width: 56px; - height: 56px; - background-size: 36px 28px - } - - .toolbar { - background-size: 56px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-mdpi.png'); - } - - .toolbar > * { - width: 56px; - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-mdpi.png'); - } -} - -@media screen and (min-resolution: 200dpi) { - .dropdown-arrow { - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png'); - } - - .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png'); - } - - .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png'); - } -} - -@media screen and (min-resolution: 300dpi) { - .dropdown-arrow { - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png'); - } - - .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png'); - } - - .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png'); - } -} - -@media screen and (orientation: portrait) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-hdpi.png'); - } -} - -@media screen and (orientation: landscape) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-hdpi.png'); - } -} - -@media screen and (orientation: portrait) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-xhdpi.png'); - } -} - -@media screen and (orientation: landscape) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-xhdpi.png'); - } -} - -@media screen and (min-width: 960px) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-hdpi.png'); - } -} - -@media screen and (min-width: 960px) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-xhdpi.png'); - } -} diff --git a/browser/themes/gnomestripe/places/reader.png b/browser/themes/gnomestripe/places/reader.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc9457f4f280bcbd05af7add0ccc26a18678eb6 GIT binary patch literal 1306 zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3 zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#| zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA zC8*vMazafX=oo#pu^El!~gYja^C!P*k>nDoEZ3f z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=wCbEEchU{U{`*I;s^PBfrm^1&0&nX zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~ z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK vOE_bq^@Lx%CKd7 h1 { - font-family: "OpenSansLight","Droid Sans",sans-serif; + font-family: sans-serif; font-weight: normal; line-height: 1.1em; width: 100%; @@ -321,19 +321,18 @@ } .toolbar { - font-family: "Droid Sans",helvetica,arial,clean,sans-serif; - -moz-transition-property: visibility, opacity; - -moz-transition-duration: 0.7s; - visibility: visible; - opacity: 1.0; - position: fixed; - width: 100%; - bottom: 0px; - left: 0px; - margin: 0; - padding: 0; - list-style: none; - background-repeat: repeat; + font-family: helvetica,arial,clean,sans-serif; + visibility: visible; + opacity: 1.0; + position: fixed; + width: 36px; + height: 45px; + bottom: 0px; + margin: 0; + padding: 10px 4px 0 24px; + list-style: none; + background-repeat: repeat; + left: 1%; } .toolbar-hidden { @@ -343,11 +342,6 @@ opacity: 0.0; } -.toolbar > * { - float: right; - width: 25%; -} - .button { color: white; display: block; @@ -364,6 +358,7 @@ display: inline-block; list-style: none; margin: 0px; + margin-left: -15px; padding: 0px; } @@ -380,7 +375,6 @@ .dropdown-popup { text-align: left; position: absolute; - left: 0px; z-index: 1000; float: left; background: #dde2e7; @@ -391,6 +385,7 @@ font-size: 14px; box-shadow: 0px -1px 12px #333; visibility: hidden; + width: 225px; } .dropdown-popup > hr { @@ -416,11 +411,11 @@ .dropdown-arrow { position: absolute; - width: 40px; - height: 18px; + width: 60px; + height: 24px; bottom: -18px; - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png'); - background-size: 40px 18px; + background-image: url('chrome://browser/skin/places/readerDropdownArrow@2x.png'); + background-size: 60px 24px; background-position: center; display: block; } @@ -482,296 +477,27 @@ } .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-mdpi.png'); + background-image: url('chrome://browser/skin/places/readerPlusIcon@2x.png'); border-left: 1px solid #ccc; margin-right: 4px; + width: 30px; + height: 30px; } .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-mdpi.png'); + background-image: url('chrome://browser/skin/places/readerMinusIcon@2x.png'); + width: 30px; + height: 30px; } -@media screen and (orientation: portrait) { - .button { - height: 48px; - background-size: 30px 24px - } - - .toolbar { - background-size: 48px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-mdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-mdpi.png'); - } +.toolbar { + background-image: url('chrome://browser/skin/places/readerToolbarBg@2x.png'); } -@media screen and (orientation: landscape) { - .button { - height: 40px; - background-size: 24px 20px - } - - .toolbar { - background-size: 40px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-mdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-mdpi.png'); - } +.style-button { + background-image: url('chrome://browser/skin/places/readerStyleIcon@2x.png'); + width: 45px; + height: 36px; + left: -10px; } -@media screen and (min-width: 960px) { - .button { - width: 56px; - height: 56px; - background-size: 36px 28px - } - - .toolbar { - background-size: 56px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-mdpi.png'); - } - - .toolbar > * { - width: 56px; - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-mdpi.png'); - } -} - -@media screen and (min-resolution: 200dpi) { - .dropdown-arrow { - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png'); - } - - .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png'); - } - - .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png'); - } -} - -@media screen and (min-resolution: 300dpi) { - .dropdown-arrow { - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png'); - } - - .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png'); - } - - .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png'); - } -} - -@media screen and (orientation: portrait) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-hdpi.png'); - } -} - -@media screen and (orientation: landscape) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-hdpi.png'); - } -} - -@media screen and (orientation: portrait) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-xhdpi.png'); - } -} - -@media screen and (orientation: landscape) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-xhdpi.png'); - } -} - -@media screen and (min-width: 960px) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-hdpi.png'); - } -} - -@media screen and (min-width: 960px) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-xhdpi.png'); - } -} diff --git a/browser/themes/pinstripe/places/reader.png b/browser/themes/pinstripe/places/reader.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc9457f4f280bcbd05af7add0ccc26a18678eb6 GIT binary patch literal 1306 zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3 zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#| zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA zC8*vMazafX=oo#pu^El!~gYja^C!P*k>nDoEZ3f z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=wCbEEchU{U{`*I;s^PBfrm^1&0&nX zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~ z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK vOE_bq^@Lx%CKd7 h1 { - font-family: "OpenSansLight","Droid Sans",sans-serif; + font-family: sans-serif; font-weight: normal; line-height: 1.1em; width: 100%; @@ -321,19 +321,18 @@ } .toolbar { - font-family: "Droid Sans",helvetica,arial,clean,sans-serif; - -moz-transition-property: visibility, opacity; - -moz-transition-duration: 0.7s; - visibility: visible; - opacity: 1.0; - position: fixed; - width: 100%; - bottom: 0px; - left: 0px; - margin: 0; - padding: 0; - list-style: none; - background-repeat: repeat; + font-family: helvetica,arial,clean,sans-serif; + visibility: visible; + opacity: 1.0; + position: fixed; + width: 3%; + height: 45px; + bottom: 0px; + margin: 0; + padding: 10px 4px 0 24px; + list-style: none; + background-repeat: repeat; + left: 1%; } .toolbar-hidden { @@ -343,10 +342,10 @@ opacity: 0.0; } -.toolbar > * { +/*.toolbar > * { float: right; - width: 25%; -} + width: 5%; +}*/ .button { color: white; @@ -364,6 +363,7 @@ display: inline-block; list-style: none; margin: 0px; + margin-left: -15px; padding: 0px; } @@ -380,7 +380,6 @@ .dropdown-popup { text-align: left; position: absolute; - left: 0px; z-index: 1000; float: left; background: #dde2e7; @@ -391,6 +390,7 @@ font-size: 14px; box-shadow: 0px -1px 12px #333; visibility: hidden; + width: 225px; } .dropdown-popup > hr { @@ -416,11 +416,11 @@ .dropdown-arrow { position: absolute; - width: 40px; - height: 18px; + width: 60px; + height: 24px; bottom: -18px; - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png'); - background-size: 40px 18px; + background-image: url('chrome://browser/skin/places/readerDropdownArrow@2x.png'); + background-size: 60px 24px; background-position: center; display: block; } @@ -482,296 +482,27 @@ } .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-mdpi.png'); + background-image: url('chrome://browser/skin/places/readerPlusIcon@2x.png'); border-left: 1px solid #ccc; margin-right: 4px; + width: 30px; + height: 30px; } .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-mdpi.png'); + background-image: url('chrome://browser/skin/places/readerMinusIcon@2x.png'); + width: 30px; + height: 30px; } -@media screen and (orientation: portrait) { - .button { - height: 48px; - background-size: 30px 24px - } - - .toolbar { - background-size: 48px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-mdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-mdpi.png'); - } +.toolbar { + background-image: url('chrome://browser/skin/places/readerToolbarBg@2x.png'); } -@media screen and (orientation: landscape) { - .button { - height: 40px; - background-size: 24px 20px - } - - .toolbar { - background-size: 40px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-mdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-mdpi.png'); - } +.style-button { + background-image: url('chrome://browser/skin/places/readerStyleIcon@2x.png'); + width: 45px; + height: 36px; + left: -10px; } -@media screen and (min-width: 960px) { - .button { - width: 56px; - height: 56px; - background-size: 36px 28px - } - - .toolbar { - background-size: 56px; - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-mdpi.png'); - } - - .toolbar > * { - width: 56px; - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-mdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-mdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-mdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-mdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-mdpi.png'); - } -} - -@media screen and (min-resolution: 200dpi) { - .dropdown-arrow { - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png'); - } - - .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png'); - } - - .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png'); - } -} - -@media screen and (min-resolution: 300dpi) { - .dropdown-arrow { - background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png'); - } - - .step-control > .plus-button { - background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png'); - } - - .step-control > .minus-button { - background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png'); - } -} - -@media screen and (orientation: portrait) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-hdpi.png'); - } -} - -@media screen and (orientation: landscape) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-hdpi.png'); - } -} - -@media screen and (orientation: portrait) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-port-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-port-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-port-xhdpi.png'); - } -} - -@media screen and (orientation: landscape) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-land-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-land-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-land-xhdpi.png'); - } -} - -@media screen and (min-width: 960px) and (min-resolution: 200dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-hdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-hdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-hdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-hdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-hdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-hdpi.png'); - } -} - -@media screen and (min-width: 960px) and (min-resolution: 300dpi) { - .toolbar { - background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-xhdpi.png'); - } - - .toggle-button.on { - background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-xhdpi.png'); - } - - .toggle-button { - background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-xhdpi.png'); - } - - .list-button { - background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-xhdpi.png'); - } - - .share-button { - background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-xhdpi.png'); - } - - .style-button { - background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-xhdpi.png'); - } -} diff --git a/browser/themes/winstripe/places/reader.png b/browser/themes/winstripe/places/reader.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc9457f4f280bcbd05af7add0ccc26a18678eb6 GIT binary patch literal 1306 zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3 zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#| zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA zC8*vMazafX=oo#pu^El!~gYja^C!P*k>nDoEZ3f z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=wCbEEchU{U{`*I;s^PBfrm^1&0&nX zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~ z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK vOE_bq^@Lx%CKd7