toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 this.EXPORTED_SYMBOLS = ["LightweightThemeImageOptimizer"];
michael@0 8
michael@0 9 const Cu = Components.utils;
michael@0 10 const Ci = Components.interfaces;
michael@0 11
michael@0 12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 13
michael@0 14 XPCOMUtils.defineLazyModuleGetter(this, "Services",
michael@0 15 "resource://gre/modules/Services.jsm");
michael@0 16
michael@0 17 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
michael@0 18 "resource://gre/modules/FileUtils.jsm");
michael@0 19
michael@0 20 const ORIGIN_TOP_RIGHT = 1;
michael@0 21 const ORIGIN_BOTTOM_LEFT = 2;
michael@0 22
michael@0 23 this.LightweightThemeImageOptimizer = {
michael@0 24 optimize: function LWTIO_optimize(aThemeData, aScreen) {
michael@0 25 let data = Utils.createCopy(aThemeData);
michael@0 26 if (!data.headerURL) {
michael@0 27 return data;
michael@0 28 }
michael@0 29
michael@0 30 data.headerURL = ImageCropper.getCroppedImageURL(
michael@0 31 data.headerURL, aScreen, ORIGIN_TOP_RIGHT);
michael@0 32
michael@0 33 if (data.footerURL) {
michael@0 34 data.footerURL = ImageCropper.getCroppedImageURL(
michael@0 35 data.footerURL, aScreen, ORIGIN_BOTTOM_LEFT);
michael@0 36 }
michael@0 37
michael@0 38 return data;
michael@0 39 },
michael@0 40
michael@0 41 purge: function LWTIO_purge() {
michael@0 42 let dir = FileUtils.getDir("ProfD", ["lwtheme"]);
michael@0 43 dir.followLinks = false;
michael@0 44 try {
michael@0 45 dir.remove(true);
michael@0 46 } catch (e) {}
michael@0 47 }
michael@0 48 };
michael@0 49
michael@0 50 Object.freeze(LightweightThemeImageOptimizer);
michael@0 51
michael@0 52 let ImageCropper = {
michael@0 53 _inProgress: {},
michael@0 54
michael@0 55 getCroppedImageURL:
michael@0 56 function ImageCropper_getCroppedImageURL(aImageURL, aScreen, aOrigin) {
michael@0 57 // We can crop local files, only.
michael@0 58 if (!aImageURL.startsWith("file://")) {
michael@0 59 return aImageURL;
michael@0 60 }
michael@0 61
michael@0 62 // Generate the cropped image's file name using its
michael@0 63 // base name and the current screen size.
michael@0 64 let uri = Services.io.newURI(aImageURL, null, null);
michael@0 65 let file = uri.QueryInterface(Ci.nsIFileURL).file;
michael@0 66
michael@0 67 // Make sure the source file exists.
michael@0 68 if (!file.exists()) {
michael@0 69 return aImageURL;
michael@0 70 }
michael@0 71
michael@0 72 let fileName = file.leafName + "-" + aScreen.width + "x" + aScreen.height;
michael@0 73 let croppedFile = FileUtils.getFile("ProfD", ["lwtheme", fileName]);
michael@0 74
michael@0 75 // If we have a local file that is not in progress, return it.
michael@0 76 if (croppedFile.exists() && !(croppedFile.path in this._inProgress)) {
michael@0 77 let fileURI = Services.io.newFileURI(croppedFile);
michael@0 78
michael@0 79 // Copy the query part to avoid wrong caching.
michael@0 80 fileURI.QueryInterface(Ci.nsIURL).query = uri.query;
michael@0 81 return fileURI.spec;
michael@0 82 }
michael@0 83
michael@0 84 // Crop the given image in the background.
michael@0 85 this._crop(uri, croppedFile, aScreen, aOrigin);
michael@0 86
michael@0 87 // Return the original image while we're waiting for the cropped version
michael@0 88 // to be written to disk.
michael@0 89 return aImageURL;
michael@0 90 },
michael@0 91
michael@0 92 _crop: function ImageCropper_crop(aURI, aTargetFile, aScreen, aOrigin) {
michael@0 93 let inProgress = this._inProgress;
michael@0 94 inProgress[aTargetFile.path] = true;
michael@0 95
michael@0 96 function resetInProgress() {
michael@0 97 delete inProgress[aTargetFile.path];
michael@0 98 }
michael@0 99
michael@0 100 ImageFile.read(aURI, function crop_readImageFile(aInputStream, aContentType) {
michael@0 101 if (aInputStream && aContentType) {
michael@0 102 let image = ImageTools.decode(aInputStream, aContentType);
michael@0 103 if (image && image.width && image.height) {
michael@0 104 let stream = ImageTools.encode(image, aScreen, aOrigin, aContentType);
michael@0 105 if (stream) {
michael@0 106 ImageFile.write(aTargetFile, stream, resetInProgress);
michael@0 107 return;
michael@0 108 }
michael@0 109 }
michael@0 110 }
michael@0 111
michael@0 112 resetInProgress();
michael@0 113 });
michael@0 114 }
michael@0 115 };
michael@0 116
michael@0 117 let ImageFile = {
michael@0 118 read: function ImageFile_read(aURI, aCallback) {
michael@0 119 this._netUtil.asyncFetch(aURI, function read_asyncFetch(aInputStream, aStatus, aRequest) {
michael@0 120 if (Components.isSuccessCode(aStatus) && aRequest instanceof Ci.nsIChannel) {
michael@0 121 let channel = aRequest.QueryInterface(Ci.nsIChannel);
michael@0 122 aCallback(aInputStream, channel.contentType);
michael@0 123 } else {
michael@0 124 aCallback();
michael@0 125 }
michael@0 126 });
michael@0 127 },
michael@0 128
michael@0 129 write: function ImageFile_write(aFile, aInputStream, aCallback) {
michael@0 130 let fos = FileUtils.openSafeFileOutputStream(aFile);
michael@0 131 this._netUtil.asyncCopy(aInputStream, fos, function write_asyncCopy(aResult) {
michael@0 132 FileUtils.closeSafeFileOutputStream(fos);
michael@0 133
michael@0 134 // Remove the file if writing was not successful.
michael@0 135 if (!Components.isSuccessCode(aResult)) {
michael@0 136 try {
michael@0 137 aFile.remove(false);
michael@0 138 } catch (e) {}
michael@0 139 }
michael@0 140
michael@0 141 aCallback();
michael@0 142 });
michael@0 143 }
michael@0 144 };
michael@0 145
michael@0 146 XPCOMUtils.defineLazyModuleGetter(ImageFile, "_netUtil",
michael@0 147 "resource://gre/modules/NetUtil.jsm", "NetUtil");
michael@0 148
michael@0 149 let ImageTools = {
michael@0 150 decode: function ImageTools_decode(aInputStream, aContentType) {
michael@0 151 let outParam = {value: null};
michael@0 152
michael@0 153 try {
michael@0 154 this._imgTools.decodeImageData(aInputStream, aContentType, outParam);
michael@0 155 } catch (e) {}
michael@0 156
michael@0 157 return outParam.value;
michael@0 158 },
michael@0 159
michael@0 160 encode: function ImageTools_encode(aImage, aScreen, aOrigin, aContentType) {
michael@0 161 let stream;
michael@0 162 let width = Math.min(aImage.width, aScreen.width);
michael@0 163 let height = Math.min(aImage.height, aScreen.height);
michael@0 164 let x = aOrigin == ORIGIN_TOP_RIGHT ? aImage.width - width : 0;
michael@0 165
michael@0 166 try {
michael@0 167 stream = this._imgTools.encodeCroppedImage(aImage, aContentType, x, 0,
michael@0 168 width, height);
michael@0 169 } catch (e) {}
michael@0 170
michael@0 171 return stream;
michael@0 172 }
michael@0 173 };
michael@0 174
michael@0 175 XPCOMUtils.defineLazyServiceGetter(ImageTools, "_imgTools",
michael@0 176 "@mozilla.org/image/tools;1", "imgITools");
michael@0 177
michael@0 178 let Utils = {
michael@0 179 createCopy: function Utils_createCopy(aData) {
michael@0 180 let copy = {};
michael@0 181 for (let [k, v] in Iterator(aData)) {
michael@0 182 copy[k] = v;
michael@0 183 }
michael@0 184 return copy;
michael@0 185 }
michael@0 186 };

mercurial