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