Bug 1111601 - Avoid using hiddenwindow in DevTools code r=pbrosset

This commit is contained in:
Michael Ratcliffe 2014-12-17 13:43:30 +00:00
parent 1d577898d9
commit 93673abdb9
6 changed files with 57 additions and 126 deletions

View File

@ -6,6 +6,7 @@ const {Cc, Ci, Cu} = require("chrome");
const {rgbToHsl} = require("devtools/css-color").colorUtils;
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
Cu.import("resource://gre/modules/Services.jsm");
@ -546,7 +547,7 @@ Eyedropper.prototype = {
* Callback to be called when the color is in the clipboard.
*/
copyColor: function(callback) {
Services.appShell.hiddenDOMWindow.clearTimeout(this._copyTimeout);
clearTimeout(this._copyTimeout);
let color = this._colorValue.value;
clipboardHelper.copyString(color);
@ -554,7 +555,7 @@ Eyedropper.prototype = {
this._colorValue.classList.add("highlight");
this._colorValue.value = "✓ " + l10n.GetStringFromName("colorValue.copied");
this._copyTimeout = Services.appShell.hiddenDOMWindow.setTimeout(() => {
this._copyTimeout = setTimeout(() => {
this._colorValue.classList.remove("highlight");
this._colorValue.value = color;

View File

@ -14,6 +14,7 @@ const promise = require("projecteditor/helpers/promise");
const { on, forget } = require("projecteditor/helpers/event");
const { FileResource } = require("projecteditor/stores/resource");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
const CHECK_LINKED_DIRECTORY_DELAY = 5000;
const SHOULD_LIVE_REFRESH = true;
@ -35,7 +36,6 @@ var LocalStore = Class({
initialize: function(path) {
this.initStore();
this.window = Services.appShell.hiddenDOMWindow;
this.path = OS.Path.normalize(path);
this.rootPath = this.path;
this.displayName = this.path;
@ -46,9 +46,8 @@ var LocalStore = Class({
},
destroy: function() {
if (this.window) {
this.window.clearTimeout(this._refreshTimeout);
}
clearTimeout(this._refreshTimeout);
if (this._refreshDeferred) {
this._refreshDeferred.reject("destroy");
}
@ -58,7 +57,6 @@ var LocalStore = Class({
this._refreshTimeout = null;
this._refreshDeferred = null;
this.window = null;
this.worker = null;
if (this.root) {
@ -132,7 +130,7 @@ var LocalStore = Class({
// XXX: Once Bug 958280 adds a watch function, will not need to forever loop here.
this.refresh().then(() => {
if (SHOULD_LIVE_REFRESH) {
this._refreshTimeout = this.window.setTimeout(this.refreshLoop,
this._refreshTimeout = setTimeout(this.refreshLoop,
CHECK_LINKED_DIRECTORY_DELAY);
}
});

View File

@ -17,7 +17,7 @@ function test() {
waitForFocus(init, content);
}, true);
content.location = "data:text/html,browser_css_color.js";
content.location = "data:text/html;charset=utf-8,browser_css_color.js";
}
function init() {

View File

@ -2822,32 +2822,10 @@ TextPropertyEditor.prototype = {
* Validate this property. Does it make sense for this value to be assigned
* to this property name? This does not apply the property value
*
* @param {string} [aValue]
* The property value used for validation.
* Defaults to the current value for this.prop
*
* @return {bool} true if the property value is valid, false otherwise.
*/
isValid: function(aValue) {
let name = this.prop.name;
let value = typeof aValue == "undefined" ? this.prop.value : aValue;
let val = parseSingleValue(value);
let style = this.doc.createElementNS(HTML_NS, "div").style;
let prefs = Services.prefs;
// We toggle output of errors whilst the user is typing a property value.
let prefVal = prefs.getBoolPref("layout.css.report_errors");
prefs.setBoolPref("layout.css.report_errors", false);
let validValue = false;
try {
style.setProperty(name, val.value, val.priority);
validValue = style.getPropertyValue(name) !== "" || val.value === "";
} finally {
prefs.setBoolPref("layout.css.report_errors", prefVal);
}
return validValue;
isValid: function() {
return domUtils.cssPropertyIsValid(this.prop.name, this.prop.value);
}
};

View File

@ -10,8 +10,6 @@ const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
const REGEX_JUST_QUOTES = /^""$/;
const REGEX_RGB_3_TUPLE = /^rgb\(([\d.]+),\s*([\d.]+),\s*([\d.]+)\)$/i;
const REGEX_RGBA_4_TUPLE = /^rgba\(([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+|1|0)\)$/i;
const REGEX_HSL_3_TUPLE = /^\bhsl\(([\d.]+),\s*([\d.]+%),\s*([\d.]+%)\)$/i;
/**
@ -106,7 +104,7 @@ CssColor.prototype = {
},
get valid() {
return this._validateColor(this.authored);
return DOMUtils.isValidCSSColor(this.authored);
},
/**
@ -126,11 +124,9 @@ CssColor.prototype = {
},
get name() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
try {
@ -147,11 +143,9 @@ CssColor.prototype = {
},
get hex() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
if (this.hasAlpha) {
return this.rgba;
@ -167,11 +161,9 @@ CssColor.prototype = {
},
get longHex() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
if (this.hasAlpha) {
return this.rgba;
@ -182,11 +174,9 @@ CssColor.prototype = {
},
get rgb() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
if (!this.hasAlpha) {
if (this.authored.startsWith("rgb(")) {
@ -200,11 +190,9 @@ CssColor.prototype = {
},
get rgba() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
if (this.authored.startsWith("rgba(")) {
// The color is valid and begins with rgba(. Return the authored value.
@ -218,11 +206,9 @@ CssColor.prototype = {
},
get hsl() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
if (this.authored.startsWith("hsl(")) {
// The color is valid and begins with hsl(. Return the authored value.
@ -235,11 +221,9 @@ CssColor.prototype = {
},
get hsla() {
if (!this.valid) {
return "";
}
if (this.specialValue) {
return this.specialValue;
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
if (invalidOrSpecialValue !== false) {
return invalidOrSpecialValue;
}
if (this.authored.startsWith("hsla(")) {
// The color is valid and begins with hsla(. Return the authored value.
@ -252,6 +236,27 @@ CssColor.prototype = {
return this._hslNoAlpha().replace("hsl", "hsla").replace(")", ", 1)");
},
/**
* Check whether the current color value is in the special list e.g.
* transparent or invalid.
*
* @return {String|Boolean}
* - If the current color is a special value e.g. "transparent" then
* return the color.
* - If the color is invalid return an empty string.
* - If the color is a regular color e.g. #F06 so we return false
* to indicate that the color is neither invalid or special.
*/
_getInvalidOrSpecialValue: function() {
if (this.specialValue) {
return this.specialValue;
}
if (!this.valid) {
return "";
}
return false;
},
/**
* Change color
*
@ -298,27 +303,11 @@ CssColor.prototype = {
* appropriate.
*/
_getRGBATuple: function() {
let win = Services.appShell.hiddenDOMWindow;
let doc = win.document;
let span = doc.createElement("span");
span.style.color = this.authored;
let computed = win.getComputedStyle(span).color;
let tuple = DOMUtils.colorToRGBA(this.authored);
if (computed === "transparent") {
return {r: 0, g: 0, b: 0, a: 0};
}
tuple.a = parseFloat(tuple.a.toFixed(1));
let rgba = computed.match(REGEX_RGBA_4_TUPLE);
if (rgba) {
let [, r, g, b, a] = rgba;
return {r: r, g: g, b: b, a: a};
} else {
let rgb = computed.match(REGEX_RGB_3_TUPLE);
let [, r, g, b] = rgb;
return {r: r, g: g, b: b, a: 1};
}
return tuple;
},
_hslNoAlpha: function() {
@ -342,33 +331,6 @@ CssColor.prototype = {
valueOf: function() {
return this.rgba;
},
_validateColor: function(color) {
if (typeof color !== "string" || color === "") {
return false;
}
let win = Services.appShell.hiddenDOMWindow;
let doc = win.document;
// Create a black span in a hidden window.
let span = doc.createElement("span");
span.style.color = "rgb(0, 0, 0)";
// Attempt to set the color. If the color is no longer black we know that
// color is valid.
span.style.color = color;
if (span.style.color !== "rgb(0, 0, 0)") {
return true;
}
// If the color is black then the above check will have failed. We change
// the span to white and attempt to reapply the color. If the span is not
// white then we know that the color is valid otherwise we return invalid.
span.style.color = "rgb(255, 255, 255)";
span.style.color = color;
return span.style.color !== "rgb(255, 255, 255)";
},
};
/**

View File

@ -337,15 +337,7 @@ OutputParser.prototype = {
* CSS Property value to check
*/
_cssPropertySupportsValue: function(name, value) {
let win = Services.appShell.hiddenDOMWindow;
let doc = win.document;
value = value.replace("!important", "");
let div = doc.createElement("div");
div.style.setProperty(name, value);
return !!div.style.getPropertyValue(name);
return DOMUtils.cssPropertyIsValid(name, value);
},
/**