From 433a7a06832c49be5900515bbd7b26047a9d4922 Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Wed, 21 May 2014 18:02:21 +0200 Subject: [PATCH] Bug 1009809 - Use ManifestHelper::biggestIconURL in the desktop app installer. r=myk,jmaher --HG-- rename : toolkit/webapps/tests/test_hosted.xul => toolkit/webapps/tests/test_hosted_icons.xul rename : toolkit/webapps/tests/test_packaged.xul => toolkit/webapps/tests/test_packaged_icons.xul --- .../mochitest/tests/SimpleTest/SimpleTest.js | 2 +- toolkit/webapps/MacNativeApp.js | 19 +- toolkit/webapps/NativeApp.jsm | 89 +++++++-- toolkit/webapps/WebappsIconHelpers.js | 101 ---------- toolkit/webapps/tests/chrome.ini | 3 + toolkit/webapps/tests/data/icon.png | Bin 0 -> 2472 bytes toolkit/webapps/tests/head.js | 49 ++++- toolkit/webapps/tests/test_hosted_icons.xul | 159 ++++++++++++++++ toolkit/webapps/tests/test_packaged_icons.xul | 172 ++++++++++++++++++ .../webapps/tests/test_packaged_launch.xul | 4 - .../test_packaged_launch_no_registry.xul | 4 - ...st_packaged_update_from_webapp_runtime.xul | 4 - 12 files changed, 465 insertions(+), 141 deletions(-) delete mode 100644 toolkit/webapps/WebappsIconHelpers.js create mode 100644 toolkit/webapps/tests/data/icon.png create mode 100644 toolkit/webapps/tests/test_hosted_icons.xul create mode 100644 toolkit/webapps/tests/test_packaged_icons.xul diff --git a/testing/mochitest/tests/SimpleTest/SimpleTest.js b/testing/mochitest/tests/SimpleTest/SimpleTest.js index 10247b09396f..e1c6a222964f 100644 --- a/testing/mochitest/tests/SimpleTest/SimpleTest.js +++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js @@ -249,7 +249,7 @@ SimpleTest.is = function (a, b, name) { }; SimpleTest.isfuzzy = function (a, b, epsilon, name) { - var pass = (a > b - epsilon) && (a < b + epsilon); + var pass = (a >= b - epsilon) && (a <= b + epsilon); var diag = pass ? "" : "got " + repr(a) + ", expected " + repr(b) + " epsilon: +/- " + repr(epsilon) SimpleTest.ok(pass, name, diag); }; diff --git a/toolkit/webapps/MacNativeApp.js b/toolkit/webapps/MacNativeApp.js index d6dde3423c6f..8664ed635290 100644 --- a/toolkit/webapps/MacNativeApp.js +++ b/toolkit/webapps/MacNativeApp.js @@ -291,12 +291,23 @@ NativeApp.prototype = { _processIcon: function(aMimeType, aIcon, aDir) { let deferred = Promise.defer(); + let tmpIconPath = OS.Path.join(aDir, this.iconFile); + function conversionDone(aSubject, aTopic) { - if (aTopic == "process-finished") { - deferred.resolve(); - } else { + if (aTopic != "process-finished") { deferred.reject("Failure converting icon, exit code: " + aSubject.exitValue); + return; } + + // SIPS silently fails to convert the icon, so we need to verify if the + // icon was successfully converted. + OS.File.exists(tmpIconPath).then((aExists) => { + if (aExists) { + deferred.resolve(); + } else { + deferred.reject("Failure converting icon, unrecognized image format"); + } + }); } let process = Cc["@mozilla.org/process/util;1"]. @@ -306,7 +317,7 @@ NativeApp.prototype = { process.init(sipsFile); process.runAsync(["-s", "format", "icns", aIcon.path, - "--out", OS.Path.join(aDir, this.iconFile), + "--out", tmpIconPath, "-z", "128", "128"], 9, conversionDone); diff --git a/toolkit/webapps/NativeApp.jsm b/toolkit/webapps/NativeApp.jsm index 8d764a0639e5..d5b0081f3567 100644 --- a/toolkit/webapps/NativeApp.jsm +++ b/toolkit/webapps/NativeApp.jsm @@ -18,6 +18,8 @@ Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); +const DEFAULT_ICON_URL = "chrome://global/skin/icons/webapps-64.png"; + const ERR_NOT_INSTALLED = "The application isn't installed"; const ERR_UPDATES_UNSUPPORTED_OLD_NAMING_SCHEME = "Updates for apps installed with the old naming scheme unsupported"; @@ -100,20 +102,8 @@ CommonNativeApp.prototype = { let manifest = new ManifestHelper(aManifest, this.app.origin); let origin = Services.io.newURI(this.app.origin, null, null); - let biggestIcon = getBiggestIconURL(manifest.icons); - try { - let iconURI = Services.io.newURI(biggestIcon, null, null); - if (iconURI.scheme == "data") { - this.iconURI = iconURI; - } - } catch (ex) {} - - if (!this.iconURI) { - try { - this.iconURI = Services.io.newURI(origin.resolve(biggestIcon), null, null); - } - catch (ex) {} - } + this.iconURI = Services.io.newURI(manifest.biggestIconURL || DEFAULT_ICON_URL, + null, null); if (manifest.developer) { if (manifest.developer.name) { @@ -406,5 +396,72 @@ function getFile() { return file; } -/* More helpers for handling the app icon */ -#include WebappsIconHelpers.js +// Download an icon using either a temp file or a pipe. +function downloadIcon(aIconURI) { + let deferred = Promise.defer(); + + let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + let mimeType; + try { + let tIndex = aIconURI.path.indexOf(";"); + if("data" == aIconURI.scheme && tIndex != -1) { + mimeType = aIconURI.path.substring(0, tIndex); + } else { + mimeType = mimeService.getTypeFromURI(aIconURI); + } + } catch(e) { + deferred.reject("Failed to determine icon MIME type: " + e); + return deferred.promise; + } + + function onIconDownloaded(aStatusCode, aIcon) { + if (Components.isSuccessCode(aStatusCode)) { + deferred.resolve([ mimeType, aIcon ]); + } else { + deferred.reject("Failure downloading icon: " + aStatusCode); + } + } + + try { +#ifdef XP_MACOSX + let downloadObserver = { + onDownloadComplete: function(downloader, request, cx, aStatus, file) { + onIconDownloaded(aStatus, file); + } + }; + + let tmpIcon = Services.dirsvc.get("TmpD", Ci.nsIFile); + tmpIcon.append("tmpicon." + mimeService.getPrimaryExtension(mimeType, "")); + tmpIcon.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8)); + + let listener = Cc["@mozilla.org/network/downloader;1"] + .createInstance(Ci.nsIDownloader); + listener.init(downloadObserver, tmpIcon); +#else + let pipe = Cc["@mozilla.org/pipe;1"] + .createInstance(Ci.nsIPipe); + pipe.init(true, true, 0, 0xffffffff, null); + + let listener = Cc["@mozilla.org/network/simple-stream-listener;1"] + .createInstance(Ci.nsISimpleStreamListener); + listener.init(pipe.outputStream, { + onStartRequest: function() {}, + onStopRequest: function(aRequest, aContext, aStatusCode) { + pipe.outputStream.close(); + onIconDownloaded(aStatusCode, pipe.inputStream); + } + }); +#endif + + let channel = NetUtil.newChannel(aIconURI); + let { BadCertHandler } = Cu.import("resource://gre/modules/CertUtils.jsm", {}); + // Pass true to avoid optional redirect-cert-checking behavior. + channel.notificationCallbacks = new BadCertHandler(true); + + channel.asyncOpen(listener, null); + } catch(e) { + deferred.reject("Failure initiating download of icon: " + e); + } + + return deferred.promise; +} diff --git a/toolkit/webapps/WebappsIconHelpers.js b/toolkit/webapps/WebappsIconHelpers.js deleted file mode 100644 index 3d57d00ee295..000000000000 --- a/toolkit/webapps/WebappsIconHelpers.js +++ /dev/null @@ -1,101 +0,0 @@ -/* 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/. */ - -const DEFAULT_ICON_URL = "chrome://global/skin/icons/webapps-64.png"; - -/** - * This function receives a list of icon sizes - * and URLs and returns the url string for the biggest icon. - * - * @param aIcons An object where the keys are the icon sizes - * and the values are URL strings. E.g.: - * aIcons = { - * "16": "http://www.example.org/icon16.png", - * "32": "http://www.example.org/icon32.png" - * }; - * - * @returns the URL string for the largest specified icon - */ -function getBiggestIconURL(aIcons) { - if (!aIcons) { - return DEFAULT_ICON_URL; - } - - let iconSizes = Object.keys(aIcons); - if (iconSizes.length == 0) { - return DEFAULT_ICON_URL; - } - iconSizes.sort(function(a, b) a - b); - return aIcons[iconSizes.pop()]; -} - -// Download an icon using either a temp file or a pipe. -function downloadIcon(aIconURI) { - let deferred = Promise.defer(); - - let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); - let mimeType; - try { - let tIndex = aIconURI.path.indexOf(";"); - if("data" == aIconURI.scheme && tIndex != -1) { - mimeType = aIconURI.path.substring(0, tIndex); - } else { - mimeType = mimeService.getTypeFromURI(aIconURI); - } - } catch(e) { - deferred.reject("Failed to determine icon MIME type: " + e); - return deferred.promise; - } - - function onIconDownloaded(aStatusCode, aIcon) { - if (Components.isSuccessCode(aStatusCode)) { - deferred.resolve([ mimeType, aIcon ]); - } else { - deferred.reject("Failure downloading icon: " + aStatusCode); - } - } - - try { -#ifdef XP_MACOSX - let downloadObserver = { - onDownloadComplete: function(downloader, request, cx, aStatus, file) { - onIconDownloaded(aStatus, file); - } - }; - - let tmpIcon = Services.dirsvc.get("TmpD", Ci.nsIFile); - tmpIcon.append("tmpicon." + mimeService.getPrimaryExtension(mimeType, "")); - tmpIcon.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8)); - - let listener = Cc["@mozilla.org/network/downloader;1"] - .createInstance(Ci.nsIDownloader); - listener.init(downloadObserver, tmpIcon); -#else - let pipe = Cc["@mozilla.org/pipe;1"] - .createInstance(Ci.nsIPipe); - pipe.init(true, true, 0, 0xffffffff, null); - - let listener = Cc["@mozilla.org/network/simple-stream-listener;1"] - .createInstance(Ci.nsISimpleStreamListener); - listener.init(pipe.outputStream, { - onStartRequest: function() {}, - onStopRequest: function(aRequest, aContext, aStatusCode) { - pipe.outputStream.close(); - onIconDownloaded(aStatusCode, pipe.inputStream); - } - }); -#endif - - let channel = NetUtil.newChannel(aIconURI); - let { BadCertHandler } = Cu.import("resource://gre/modules/CertUtils.jsm", {}); - // Pass true to avoid optional redirect-cert-checking behavior. - channel.notificationCallbacks = new BadCertHandler(true); - - channel.asyncOpen(listener, null); - } catch(e) { - deferred.reject("Failure initiating download of icon: " + e); - } - - return deferred.promise; -} diff --git a/toolkit/webapps/tests/chrome.ini b/toolkit/webapps/tests/chrome.ini index 99637b4fb1a0..7606caad65b4 100644 --- a/toolkit/webapps/tests/chrome.ini +++ b/toolkit/webapps/tests/chrome.ini @@ -3,6 +3,7 @@ support-files = head.js app.sjs data/app/index.html + data/icon.png [test_hosted.xul] [test_packaged.xul] @@ -18,3 +19,5 @@ skip-if = asan skip-if = asan [test_packaged_update_from_webapp_runtime.xul] skip-if = asan +[test_hosted_icons.xul] +[test_packaged_icons.xul] diff --git a/toolkit/webapps/tests/data/icon.png b/toolkit/webapps/tests/data/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e9d5bbb4b29a5eb50de982bb66338e81d413364f GIT binary patch literal 2472 zcmV;Z30L-sP))fN8kymr@K+Z)?B z&dVVQjYA+%K}et_3Y0(zAR<9pP$f_$kjk@wT2zUaN=S&RYAci$P#=h@t%{(HCz|(mz&QHL_`Rq08bRqn{r`6cN;mH>R9<@f{X*a1$OMLqQy8s! zC`2)ebXJYYyVNFG!@Yo~{yLGgv0=}2oge|$RVUgO25`j! zWU6d9`1)g`IMv>kUUB73>tCO^_T{OkR$cHPQ!sSv(vnvcxj|}ZkW6aPp7_&tYsl(h~#$x_o&7(JOXK-m`1yjIKdLQ=JX!y+qWC{Uv?0q z@)8t&b+bIFW9_RlNlF%nDzv*rn8I(aiiYm+c%MKHO(lUj^R%bO5n z9M+H75Ta&Ii;!ut{SaxU$#H$8{Q#e9HSy^6X93esq9o)3!v^n;R>5ON(V z2l&N{d(ks@15n$6{)JUoOU_v6Wb;>jq7Rsc*)@N0L{)2Niqwc?Gewa>TP(2P;4q#l z-j4A_eJERPcx<>IuPj=pX@tS@G^h!SX|PxcRwN+_=+W1P@Qt-y=;^o&a0j?@&wBV( zy8PWo0A#G_KFNxeGAZXq^fZw$&@itmkUBhxQ>IEVx_hwIn1>XZ5G+GM=c4K+t1eH2 z00Q4fEeP<$*0*ru`C)@_-ecO=h@%0!l_8_HIA4QOLuC$m8)S?i!lR^}ROs$6(w;#fdU*yj5IMA{JhKCM}h%Dx- zYN7$Cs)Si7_h`B5r6{D8q!0Q(E{(}Kg#FSvU~gi?w%any)5i8yht5)g^exvJ|& z1)iL{41aa!pw4K0*M(nm>8J*GY6=nQmcEDBt0AgQBPvax!?AGZ)#pLkb0I?yN?1%m zKX$*@dGkyP;!yNy08CFp{gLQJ6Hw`ZKt-mox38C7(1J(DLKul)lK@D0RI4Py(JZKl zbaFMgPUeTP;kIQIARU+<_s^pqbYoYk-g5RE^UMT5gKZc*Xu_H! zg>z;;KEl9K8LLG78j@DL9&>J0(+~76R5(3Tf+~hgmo7IxKn7G3fG$HFy&2XCgy3Qg zpuvC>nJv5 z{*HTx&%i{GNdTU({VJUm|hcI!070!tN;`nvN;NG{SjGbhqgl`o7|kOCePQECQ^>U|Y@NuW zFm99Sm@PL*O470&teRcL#S69RXo}Xi4L0 zR)}6TKuiCog}uVm;x{05H`T`k9uP`QgA>YUPyO?rOF#8YxbmgJ0_kTOl=3|uGMPW0 zC(VG=1%9F}mQiEFWDOdTsX!$Tz+NKxTree29TkXKDT@2ZX^!R!LDl3y;2BpR^S$7? z<^4DD@&lw_*eQ{u!gd;L=uWB2Q%7igoB_m{F$%LA5p7e~yv`$V^e22ld$ySWJF}mvI z=WgA1@J@a1rA;3%03AzKgJ?C3ldqlCb?rIX?7FU$mDK=r^bHWA0YdkUBZpXhfQpnF z^P-WL$E&~pX@2~1UK*yA=t~~=yJ2(GT1_Cmwh+rVwC657Et6TDv#dVb6h?2#%JCp3 zhr^&4E9Fgu(V@vO-v4gR-MYQzzQ*5;(54!%4(fk + + + + + + + + diff --git a/toolkit/webapps/tests/test_packaged_icons.xul b/toolkit/webapps/tests/test_packaged_icons.xul new file mode 100644 index 000000000000..a912742a1372 --- /dev/null +++ b/toolkit/webapps/tests/test_packaged_icons.xul @@ -0,0 +1,172 @@ + + + + + + + + + diff --git a/toolkit/webapps/tests/test_packaged_launch.xul b/toolkit/webapps/tests/test_packaged_launch.xul index 142e5dcfc654..4fc626ac13d8 100644 --- a/toolkit/webapps/tests/test_packaged_launch.xul +++ b/toolkit/webapps/tests/test_packaged_launch.xul @@ -32,10 +32,6 @@ Cu.import("resource://gre/modules/NativeApp.jsm"); Cu.import("resource://gre/modules/WebappOSUtils.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); -const PR_RDWR = 0x04; -const PR_CREATE_FILE = 0x08; -const PR_TRUNCATE = 0x20; - let manifest = { name: "test_desktop_packaged_launch", version: "0.1a", diff --git a/toolkit/webapps/tests/test_packaged_launch_no_registry.xul b/toolkit/webapps/tests/test_packaged_launch_no_registry.xul index 64eb4c9ea36a..02b2932aac01 100644 --- a/toolkit/webapps/tests/test_packaged_launch_no_registry.xul +++ b/toolkit/webapps/tests/test_packaged_launch_no_registry.xul @@ -32,10 +32,6 @@ Cu.import("resource://gre/modules/NativeApp.jsm"); Cu.import("resource://gre/modules/WebappOSUtils.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); -const PR_RDWR = 0x04; -const PR_CREATE_FILE = 0x08; -const PR_TRUNCATE = 0x20; - let manifest = { name: "test_desktop_packaged_launch_no_registry", version: "0.1a", diff --git a/toolkit/webapps/tests/test_packaged_update_from_webapp_runtime.xul b/toolkit/webapps/tests/test_packaged_update_from_webapp_runtime.xul index 93a0a53d1cca..5c5d05a377e8 100644 --- a/toolkit/webapps/tests/test_packaged_update_from_webapp_runtime.xul +++ b/toolkit/webapps/tests/test_packaged_update_from_webapp_runtime.xul @@ -32,10 +32,6 @@ Cu.import("resource://gre/modules/NativeApp.jsm"); Cu.import("resource://gre/modules/WebappOSUtils.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); -const PR_RDWR = 0x04; -const PR_CREATE_FILE = 0x08; -const PR_TRUNCATE = 0x20; - let manifest = { name: "test_desktop_packaged_launch", version: "0.1a",