зеркало из https://github.com/mozilla/gecko-dev.git
Bug 650968 - Enabling a lightweight theme (Persona) causes significant startup slowness; r=felipe
This commit is contained in:
Родитель
4bc32fff08
Коммит
f2bb0c882c
|
@ -4,10 +4,20 @@
|
|||
|
||||
let EXPORTED_SYMBOLS = ["LightweightThemeConsumer"];
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer",
|
||||
"resource://gre/modules/LightweightThemeImageOptimizer.jsm");
|
||||
|
||||
function LightweightThemeConsumer(aDocument) {
|
||||
this._doc = aDocument;
|
||||
this._win = aDocument.defaultView;
|
||||
this._footerId = aDocument.documentElement.getAttribute("lightweightthemesfooter");
|
||||
|
||||
let screen = this._win.screen;
|
||||
this._lastScreenWidth = screen.width;
|
||||
this._lastScreenHeight = screen.height;
|
||||
|
||||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService)
|
||||
.addObserver(this, "lightweight-theme-styling-update", false);
|
||||
|
@ -15,9 +25,14 @@ function LightweightThemeConsumer(aDocument) {
|
|||
var temp = {};
|
||||
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", temp);
|
||||
this._update(temp.LightweightThemeManager.currentThemeForDisplay);
|
||||
this._win.addEventListener("resize", this);
|
||||
}
|
||||
|
||||
LightweightThemeConsumer.prototype = {
|
||||
_lastData: null,
|
||||
_lastScreenWidth: null,
|
||||
_lastScreenHeight: null,
|
||||
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
if (aTopic != "lightweight-theme-styling-update")
|
||||
return;
|
||||
|
@ -25,18 +40,32 @@ LightweightThemeConsumer.prototype = {
|
|||
this._update(JSON.parse(aData));
|
||||
},
|
||||
|
||||
handleEvent: function (aEvent) {
|
||||
let {width, height} = this._win.screen;
|
||||
|
||||
if (this._lastScreenWidth != width || this._lastScreenHeight != height) {
|
||||
this._lastScreenWidth = width;
|
||||
this._lastScreenHeight = height;
|
||||
this._update(this._lastData);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService)
|
||||
.removeObserver(this, "lightweight-theme-styling-update");
|
||||
|
||||
this._doc = null;
|
||||
this._win.removeEventListener("resize", this);
|
||||
this._win = this._doc = null;
|
||||
},
|
||||
|
||||
_update: function (aData) {
|
||||
if (!aData)
|
||||
aData = { headerURL: "", footerURL: "", textcolor: "", accentcolor: "" };
|
||||
|
||||
this._lastData = aData;
|
||||
aData = LightweightThemeImageOptimizer.optimize(aData, this._win.screen);
|
||||
|
||||
var root = this._doc.documentElement;
|
||||
var active = !!aData.headerURL;
|
||||
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
let EXPORTED_SYMBOLS = ["LightweightThemeImageOptimizer"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
const ORIGIN_TOP_RIGHT = 1;
|
||||
const ORIGIN_BOTTOM_LEFT = 2;
|
||||
|
||||
let LightweightThemeImageOptimizer = {
|
||||
optimize: function LWTIO_optimize(aThemeData, aScreen) {
|
||||
let data = Utils.createCopy(aThemeData);
|
||||
if (!data.headerURL) {
|
||||
return data;
|
||||
}
|
||||
|
||||
data.headerURL = ImageCropper.getCroppedImageURL(
|
||||
data.headerURL, aScreen, ORIGIN_TOP_RIGHT);
|
||||
|
||||
if (data.footerURL) {
|
||||
data.footerURL = ImageCropper.getCroppedImageURL(
|
||||
data.footerURL, aScreen, ORIGIN_BOTTOM_LEFT);
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
purge: function LWTIO_purge() {
|
||||
let dir = FileUtils.getDir("ProfD", ["lwtheme"]);
|
||||
dir.followLinks = false;
|
||||
try {
|
||||
dir.remove(true);
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
|
||||
Object.freeze(LightweightThemeImageOptimizer);
|
||||
|
||||
let ImageCropper = {
|
||||
_inProgress: {},
|
||||
|
||||
getCroppedImageURL:
|
||||
function ImageCropper_getCroppedImageURL(aImageURL, aScreen, aOrigin) {
|
||||
// We can crop local files, only.
|
||||
if (!aImageURL.startsWith("file://")) {
|
||||
return aImageURL;
|
||||
}
|
||||
|
||||
// Generate the cropped image's file name using its
|
||||
// base name and the current screen size.
|
||||
let uri = Services.io.newURI(aImageURL, null, null);
|
||||
let file = uri.QueryInterface(Ci.nsIFileURL).file;
|
||||
|
||||
// Make sure the source file exists.
|
||||
if (!file.exists()) {
|
||||
return aImageURL;
|
||||
}
|
||||
|
||||
let fileName = file.leafName + "-" + aScreen.width + "x" + aScreen.height;
|
||||
let croppedFile = FileUtils.getFile("ProfD", ["lwtheme", fileName]);
|
||||
|
||||
// If we have a local file that is not in progress, return it.
|
||||
if (croppedFile.exists() && !(croppedFile.path in this._inProgress)) {
|
||||
let fileURI = Services.io.newFileURI(croppedFile);
|
||||
|
||||
// Copy the query part to avoid wrong caching.
|
||||
fileURI.QueryInterface(Ci.nsIURL).query = uri.query;
|
||||
return fileURI.spec;
|
||||
}
|
||||
|
||||
// Crop the given image in the background.
|
||||
this._crop(uri, croppedFile, aScreen, aOrigin);
|
||||
|
||||
// Return the original image while we're waiting for the cropped version
|
||||
// to be written to disk.
|
||||
return aImageURL;
|
||||
},
|
||||
|
||||
_crop: function ImageCropper_crop(aURI, aTargetFile, aScreen, aOrigin) {
|
||||
let inProgress = this._inProgress;
|
||||
inProgress[aTargetFile.path] = true;
|
||||
|
||||
function resetInProgress() {
|
||||
delete inProgress[aTargetFile.path];
|
||||
}
|
||||
|
||||
ImageFile.read(aURI, function (aInputStream, aContentType) {
|
||||
if (aInputStream && aContentType) {
|
||||
let image = ImageTools.decode(aInputStream, aContentType);
|
||||
if (image && image.width && image.height) {
|
||||
let stream = ImageTools.encode(image, aScreen, aOrigin, aContentType);
|
||||
if (stream) {
|
||||
ImageFile.write(aTargetFile, stream, resetInProgress);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetInProgress();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let ImageFile = {
|
||||
read: function ImageFile_read(aURI, aCallback) {
|
||||
this._netUtil.asyncFetch(aURI, function (aInputStream, aStatus, aRequest) {
|
||||
if (Components.isSuccessCode(aStatus) && aRequest instanceof Ci.nsIChannel) {
|
||||
let channel = aRequest.QueryInterface(Ci.nsIChannel);
|
||||
aCallback(aInputStream, channel.contentType);
|
||||
} else {
|
||||
aCallback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
write: function ImageFile_write(aFile, aInputStream, aCallback) {
|
||||
let fos = FileUtils.openSafeFileOutputStream(aFile);
|
||||
this._netUtil.asyncCopy(aInputStream, fos, function (aResult) {
|
||||
FileUtils.closeSafeFileOutputStream(fos);
|
||||
|
||||
// Remove the file if writing was not successful.
|
||||
if (!Components.isSuccessCode(aResult)) {
|
||||
try {
|
||||
aFile.remove(false);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(ImageFile, "_netUtil",
|
||||
"resource://gre/modules/NetUtil.jsm", "NetUtil");
|
||||
|
||||
let ImageTools = {
|
||||
decode: function ImageTools_decode(aInputStream, aContentType) {
|
||||
let outParam = {value: null};
|
||||
|
||||
try {
|
||||
this._imgTools.decodeImageData(aInputStream, aContentType, outParam);
|
||||
} catch (e) {}
|
||||
|
||||
return outParam.value;
|
||||
},
|
||||
|
||||
encode: function ImageTools_encode(aImage, aScreen, aOrigin, aContentType) {
|
||||
let stream;
|
||||
let width = Math.min(aImage.width, aScreen.width);
|
||||
let height = Math.min(aImage.height, aScreen.height);
|
||||
let x = aOrigin == ORIGIN_TOP_RIGHT ? aImage.width - width : 0;
|
||||
|
||||
try {
|
||||
stream = this._imgTools.encodeCroppedImage(aImage, aContentType, x, 0,
|
||||
width, height);
|
||||
} catch (e) {}
|
||||
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(ImageTools, "_imgTools",
|
||||
"@mozilla.org/image/tools;1", "imgITools");
|
||||
|
||||
let Utils = {
|
||||
createCopy: function Utils_createCopy(aData) {
|
||||
let copy = {};
|
||||
for (let [k, v] in Iterator(aData)) {
|
||||
copy[k] = v;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
};
|
|
@ -9,6 +9,7 @@ var EXPORTED_SYMBOLS = ["LightweightThemeManager"];
|
|||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -38,6 +39,9 @@ const PERSIST_FILES = {
|
|||
footerURL: "lightweighttheme-footer"
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer",
|
||||
"resource://gre/modules/LightweightThemeImageOptimizer.jsm");
|
||||
|
||||
__defineGetter__("_prefs", function () {
|
||||
delete this._prefs;
|
||||
return this._prefs = Services.prefs.getBranch("lightweightThemes.");
|
||||
|
@ -227,8 +231,12 @@ var LightweightThemeManager = {
|
|||
let usedThemes = _usedThemesExceptId(aData.id);
|
||||
usedThemes.unshift(aData);
|
||||
_updateUsedThemes(usedThemes);
|
||||
if (PERSIST_ENABLED)
|
||||
_persistImages(aData);
|
||||
if (PERSIST_ENABLED) {
|
||||
LightweightThemeImageOptimizer.purge();
|
||||
_persistImages(aData, function () {
|
||||
_notifyWindows(this.currentThemeForDisplay);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
_prefs.setBoolPref("isThemeSelected", aData != null);
|
||||
|
@ -716,17 +724,24 @@ function _prefObserver(aSubject, aTopic, aData) {
|
|||
}
|
||||
}
|
||||
|
||||
function _persistImages(aData) {
|
||||
function _persistImages(aData, aCallback) {
|
||||
function onSuccess(key) function () {
|
||||
let current = LightweightThemeManager.currentTheme;
|
||||
if (current && current.id == aData.id)
|
||||
if (current && current.id == aData.id) {
|
||||
_prefs.setBoolPref("persisted." + key, true);
|
||||
}
|
||||
if (--numFilesToPersist == 0 && aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
};
|
||||
|
||||
let numFilesToPersist = 0;
|
||||
for (let key in PERSIST_FILES) {
|
||||
_prefs.setBoolPref("persisted." + key, false);
|
||||
if (aData[key])
|
||||
if (aData[key]) {
|
||||
numFilesToPersist++;
|
||||
_persistImage(aData[key], PERSIST_FILES[key], onSuccess(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ EXTRA_JS_MODULES = \
|
|||
AddonRepository.jsm \
|
||||
AddonUpdateChecker.jsm \
|
||||
ChromeManifestParser.jsm \
|
||||
LightweightThemeImageOptimizer.jsm \
|
||||
LightweightThemeManager.jsm \
|
||||
PluginProvider.jsm \
|
||||
SpellCheckDictionaryBootstrap.js \
|
||||
|
|
Загрузка…
Ссылка в новой задаче