Bug 692543 - Make the Style Inspector UI faster; r=dcamp

This commit is contained in:
Mihai Sucan 2011-11-02 19:50:15 +02:00
Родитель 5177bed31c
Коммит 4e75493f67
3 изменённых файлов: 371 добавлений и 249 удалений

Просмотреть файл

@ -133,10 +133,14 @@ XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
CssHtmlTree.prototype = {
// Cache the list of properties that have matched and unmatched properties.
_matchedProperties: null,
_unmatchedProperties: null,
htmlComplete: false,
// Used for cancelling timeouts in the style filter.
filterChangedTimeout: null,
_filterChangedTimeout: null,
// The search filter
searchField: null,
@ -167,12 +171,18 @@ CssHtmlTree.prototype = {
}
this.viewedElement = aElement;
this._unmatchedProperties = null;
this._matchedProperties = null;
CssHtmlTree.processTemplate(this.templatePath, this.path, this);
if (this.htmlComplete) {
this.refreshPanel();
} else {
if (this._panelRefreshTimeout) {
this.win.clearTimeout(this._panelRefreshTimeout);
}
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// We use a setTimeout loop to display the properties in batches of 15 at a
@ -194,14 +204,17 @@ CssHtmlTree.prototype = {
if (i < max) {
// There are still some properties to display. We loop here to display
// the next batch of 15.
this.win.setTimeout(displayProperties.bind(this), 50);
this._panelRefreshTimeout =
this.win.setTimeout(displayProperties.bind(this), 15);
} else {
this.htmlComplete = true;
this._panelRefreshTimeout = null;
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
}
}
}
this.win.setTimeout(displayProperties.bind(this), 50);
this._panelRefreshTimeout =
this.win.setTimeout(displayProperties.bind(this), 15);
}
},
@ -210,7 +223,9 @@ CssHtmlTree.prototype = {
*/
refreshPanel: function CssHtmlTree_refreshPanel()
{
if (this._panelRefreshTimeout) {
this.win.clearTimeout(this._panelRefreshTimeout);
}
// Reset zebra striping.
this._darkStripe = true;
@ -228,12 +243,13 @@ CssHtmlTree.prototype = {
if (i < max) {
// There are still some property views to refresh. We loop here to
// display the next batch of 15.
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 0);
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
} else {
this._panelRefreshTimeout = null;
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
}
}
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 0);
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
},
/**
@ -258,13 +274,14 @@ CssHtmlTree.prototype = {
filterChanged: function CssHtmlTree_filterChanged(aEvent)
{
let win = this.styleWin.contentWindow;
if (this.filterChangedTimeout) {
win.clearTimeout(this.filterChangedTimeout);
this.filterChangeTimeout = null;
if (this._filterChangedTimeout) {
win.clearTimeout(this._filterChangedTimeout);
}
this.filterChangedTimeout = win.setTimeout(function() {
this._filterChangedTimeout = win.setTimeout(function() {
this.refreshPanel();
this._filterChangeTimeout = null;
}.bind(this), FILTER_CHANGED_TIMEOUT);
},
@ -279,6 +296,7 @@ CssHtmlTree.prototype = {
*/
onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
{
this._matchedProperties = null;
this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
CssLogic.FILTER.ALL :
CssLogic.FILTER.UA;
@ -326,6 +344,56 @@ CssHtmlTree.prototype = {
mozProps.sort());
},
/**
* Get a list of properties that have matched selectors.
*
* @return {object} the object maps property names (keys) to booleans (values)
* that tell if the given property has matched selectors or not.
*/
get matchedProperties()
{
if (!this._matchedProperties) {
this._matchedProperties =
this.cssLogic.hasMatchedSelectors(CssHtmlTree.propertyNames);
}
return this._matchedProperties;
},
/**
* Check if a property has unmatched selectors. Result is cached.
*
* @param {string} aProperty the name of the property you want to check.
* @return {boolean} true if the property has unmatched selectors, false
* otherwise.
*/
hasUnmatchedSelectors: function CssHtmlTree_hasUnmatchedSelectors(aProperty)
{
// Initially check all of the properties that return false for
// hasMatchedSelectors(). This speeds-up the UI.
if (!this._unmatchedProperties) {
let properties = [];
CssHtmlTree.propertyNames.forEach(function(aName) {
if (!this.matchedProperties[aName]) {
properties.push(aName);
}
}, this);
if (properties.indexOf(aProperty) == -1) {
properties.push(aProperty);
}
this._unmatchedProperties = this.cssLogic.hasUnmatchedSelectors(properties);
}
// Lazy-get the result for properties we do not have cached.
if (!(aProperty in this._unmatchedProperties)) {
let result = this.cssLogic.hasUnmatchedSelectors([aProperty]);
this._unmatchedProperties[aProperty] = result[aProperty];
}
return this._unmatchedProperties[aProperty];
},
/**
* Destructor for CssHtmlTree.
*/
@ -446,7 +514,7 @@ PropertyView.prototype = {
*/
get hasMatchedSelectors()
{
return this.propertyInfo.hasMatchedSelectors();
return this.tree.matchedProperties[this.name];
},
/**
@ -454,7 +522,7 @@ PropertyView.prototype = {
*/
get hasUnmatchedSelectors()
{
return this.propertyInfo.hasUnmatchedSelectors();
return this.tree.hasUnmatchedSelectors(this.name);
},
/**

Просмотреть файл

@ -151,6 +151,7 @@ CssLogic.prototype = {
// in processUnmatchedSelectors().
_matchId: 0,
_matchedRules: null,
_matchedSelectors: null,
_unmatchedSelectors: null,
@ -166,6 +167,7 @@ CssLogic.prototype = {
this._sheetIndex = 0;
this._sheets = {};
this._sheetsCached = false;
this._matchedRules = null;
this._matchedSelectors = null;
this._unmatchedSelectors = null;
},
@ -200,6 +202,7 @@ CssLogic.prototype = {
this._propertyInfos = {};
}
this._matchedRules = null;
this._matchedSelectors = null;
this._unmatchedSelectors = null;
let win = this.viewedDocument.defaultView;
@ -242,6 +245,7 @@ CssLogic.prototype = {
aValue == CssLogic.FILTER.UA);
if (needFullUpdate) {
this._matchedRules = null;
this._matchedSelectors = null;
this._unmatchedSelectors = null;
this._propertyInfos = {};
@ -309,19 +313,19 @@ CssLogic.prototype = {
}
// Only work with stylesheets that have their media allowed.
if (!CssLogic.sheetMediaAllowed(aDomSheet)) {
if (!this.mediaMatches(aDomSheet)) {
return;
}
// Cache the sheet.
let cssSheet = this.getSheet(aDomSheet, false, this._sheetIndex++);
let cssSheet = this.getSheet(aDomSheet, this._sheetIndex++);
if (cssSheet._passId != this._passId) {
cssSheet._passId = this._passId;
// Find import rules.
Array.prototype.forEach.call(aDomSheet.cssRules, function(aDomRule) {
if (aDomRule.type == Ci.nsIDOMCSSRule.IMPORT_RULE && aDomRule.styleSheet &&
CssLogic.sheetMediaAllowed(aDomRule)) {
this.mediaMatches(aDomRule)) {
this._cacheSheet(aDomRule.styleSheet);
}
}, this);
@ -355,20 +359,18 @@ CssLogic.prototype = {
* otherwise the new CSSStyleSheet object is cached.
*
* @param {CSSStyleSheet} aDomSheet the CSSStyleSheet object you want.
* @param {boolean} aSystemSheet tells if the stylesheet is a browser-provided
* sheet or not.
* @param {number} aIndex the index, within the document, of the stylesheet.
*
* @return {CssSheet} the CssSheet object for the given CSSStyleSheet object.
*/
getSheet: function CL_getSheet(aDomSheet, aSystemSheet, aIndex)
getSheet: function CL_getSheet(aDomSheet, aIndex)
{
let cacheId = aSystemSheet ? "1" : "0";
let cacheId = "";
if (aDomSheet.href) {
cacheId += aDomSheet.href;
cacheId = aDomSheet.href;
} else if (aDomSheet.ownerNode && aDomSheet.ownerNode.ownerDocument) {
cacheId += aDomSheet.ownerNode.ownerDocument.location;
cacheId = aDomSheet.ownerNode.ownerDocument.location;
}
let sheet = null;
@ -377,8 +379,10 @@ CssLogic.prototype = {
if (cacheId in this._sheets) {
for (let i = 0, numSheets = this._sheets[cacheId].length; i < numSheets; i++) {
sheet = this._sheets[cacheId][i];
if (sheet.domSheet == aDomSheet) {
if (sheet.domSheet === aDomSheet) {
if (aIndex != -1) {
sheet.index = aIndex;
}
sheetFound = true;
break;
}
@ -390,8 +394,8 @@ CssLogic.prototype = {
this._sheets[cacheId] = [];
}
sheet = new CssSheet(this, aDomSheet, aSystemSheet, aIndex);
if (sheet.sheetAllowed && !aSystemSheet) {
sheet = new CssSheet(this, aDomSheet, aIndex);
if (sheet.sheetAllowed && !sheet.systemSheet) {
this._ruleCount += sheet.ruleCount;
}
@ -486,45 +490,22 @@ CssLogic.prototype = {
return;
}
if (!this._matchedRules) {
this._buildMatchedRules();
}
this._matchedSelectors = [];
this._unmatchedSelectors = null;
this._passId++;
this._matchId++;
let element = this.viewedElement;
let filter = this.sourceFilter;
let sheetIndex = 0;
let domRules = null;
do {
try {
domRules = this.domUtils.getCSSStyleRules(element);
} catch (ex) {
Services.console.
logStringMessage("CssLogic_processMatchedSelectors error: " + ex);
continue;
}
let status = (this.viewedElement == element) ?
CssLogic.STATUS.MATCHED : CssLogic.STATUS.PARENT_MATCH;
for (let i = 0, numRules = domRules.Count(); i < numRules; i++) {
let domRule = domRules.GetElementAt(i);
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
let domSheet = domRule.parentStyleSheet;
let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
if (filter !== CssLogic.FILTER.UA && systemSheet) {
continue;
}
let sheet = this.getSheet(domSheet, systemSheet, sheetIndex);
let rule = sheet.getRule(domRule);
for (let i = 0; i < this._matchedRules.length; i++) {
let rule = this._matchedRules[i][0];
let status = this._matchedRules[i][1];
rule.selectors.forEach(function (aSelector) {
if (aSelector._matchId !== this._matchId &&
element.mozMatchesSelector(aSelector)) {
(aSelector.elementStyle ||
this._selectorMatchesElement(aSelector))) {
aSelector._matchId = this._matchId;
this._matchedSelectors.push([ aSelector, status ]);
if (aCallback) {
@ -533,30 +514,30 @@ CssLogic.prototype = {
}
}, this);
if (sheet._passId !== this._passId) {
sheetIndex++;
sheet._passId = this._passId;
}
if (rule._passId !== this._passId) {
rule._passId = this._passId;
}
}
},
// Add element.style information.
if (element.style.length > 0) {
let rule = new CssRule(null, { style: element.style }, element);
let selector = rule.selectors[0];
selector._matchId = this._matchId;
this._matchedSelectors.push([ selector, status ]);
if (aCallback) {
aCallback.call(aScope, selector, status);
}
rule._passId = this._passId;
/**
* Check if the given selector matches the highlighted element or any of its
* parents.
*
* @private
* @param {string} aSelector the selector string you want to check.
* @return {boolean} true if the given selector matches the highlighted
* element or any of its parents, otherwise false is returned.
*/
_selectorMatchesElement: function CL__selectorMatchesElement(aSelector)
{
let element = this.viewedElement;
do {
if (element.mozMatchesSelector(aSelector)) {
return true;
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
return false;
},
/**
@ -573,9 +554,6 @@ CssLogic.prototype = {
*/
processUnmatchedSelectors: function CL_processUnmatchedSelectors(aCallback, aScope)
{
if (!this._matchedSelectors) {
this.processMatchedSelectors();
}
if (this._unmatchedSelectors) {
if (aCallback) {
this._unmatchedSelectors.forEach(aCallback, aScope);
@ -583,17 +561,21 @@ CssLogic.prototype = {
return;
}
if (!this._matchedSelectors) {
this.processMatchedSelectors();
}
this._unmatchedSelectors = [];
this.forEachSheet(function (aSheet) {
// We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
return;
}
aSheet.forEachRule(function (aRule) {
aRule.selectors.forEach(function (aSelector) {
if (aSelector._matchId != this._matchId) {
if (aSelector._matchId !== this._matchId) {
this._unmatchedSelectors.push(aSelector);
if (aCallback) {
aCallback.call(aScope, aSelector);
@ -607,87 +589,204 @@ CssLogic.prototype = {
/**
* Check if the highlighted element or it's parents have matched selectors.
*
* @param {function} [aCallback] Simple callback method. If aCallback is
* provided then the domRules for each element in the loop are passed to
* the callback function. When the element has .style properties, the callback
* receives {style: element.style}. If the callback returns true then the
* element has matched rules, otherwise not.
* @return {Boolean} true if the current element or it's parents have
* matching CssSelector objects, false otherwise
* @param {array} aProperties The list of properties you want to check if they
* have matched selectors or not.
* @return {object} An object that tells for each property if it has matched
* selectors or not. Object keys are property names and values are booleans.
*/
hasMatchedSelectors: function CL_hasMatchedSelectors(aCallback)
hasMatchedSelectors: function CL_hasMatchedSelectors(aProperties)
{
if (!this._matchedRules) {
this._buildMatchedRules();
}
let result = {};
this._matchedRules.some(function(aValue) {
let rule = aValue[0];
aProperties = aProperties.filter(function(aProperty) {
if (rule.getPropertyValue(aProperty)) {
// We just need to find if a rule has this property while it matches
// the viewedElement (or its parents).
result[aProperty] = true;
return false;
}
return true; // Keep the property for the next rule.
});
return aProperties.length == 0;
}, this);
return result;
},
/**
* Build the array of matched rules for the currently highlighted element.
* The array will hold rules that match the viewedElement and its parents.
*
* @private
*/
_buildMatchedRules: function CL__buildMatchedRules()
{
let domRules;
let element = this.viewedElement;
let matched = false;
let filter = this.sourceFilter;
let sheetIndex = 0;
this._matchId++;
this._passId++;
this._matchedRules = [];
do {
let status = this.viewedElement === element ?
CssLogic.STATUS.MATCHED : CssLogic.STATUS.PARENT_MATCH;
try {
domRules = this.domUtils.getCSSStyleRules(element);
} catch (ex) {
Services.console.
logStringMessage("CssLogic_hasMatchedSelectors error: " + ex);
logStringMessage("CL__buildMatchedRules error: " + ex);
continue;
}
// Check if the are DOM rules that we can consider as matched rules
// (depending on the callback).
if (domRules.Count() && (!aCallback || aCallback(domRules))) {
matched = true;
for (let i = 0, n = domRules.Count(); i < n; i++) {
let domRule = domRules.GetElementAt(i);
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
// Check if the element has any element.style properties that we can
// consider as "matched" (depending on the callback).
if (element.style.length > 0 &&
(!aCallback || aCallback({style: element.style}))) {
matched = true;
let sheet = this.getSheet(domRule.parentStyleSheet, -1);
if (sheet._passId !== this._passId) {
sheet.index = sheetIndex++;
sheet._passId = this._passId;
}
if (matched) {
break;
if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) {
continue;
}
let rule = sheet.getRule(domRule);
if (rule._passId === this._passId) {
continue;
}
rule._matchId = this._matchId;
rule._passId = this._passId;
this._matchedRules.push([rule, status]);
}
// Add element.style information.
if (element.style.length > 0) {
let rule = new CssRule(null, { style: element.style }, element);
rule._matchId = this._matchId;
rule._passId = this._passId;
this._matchedRules.push([rule, status]);
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
return matched;
},
/**
* Check if the highlighted element or it's parents have unmatched selectors.
*
* @param {String} aProperty The CSS property to check against
* @return {Boolean} true if the current element or it's parents have
* unmatched CssSelector objects, false otherwise
* Please note that this method is far slower than hasMatchedSelectors()
* because it needs to do a lot more checks in the DOM.
*
* @param {array} aProperties The list of properties you want to check if they
* have unmatched selectors or not.
* @return {object} An object that tells for each property if it has unmatched
* selectors or not. Object keys are property names and values are booleans.
*/
hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperty)
hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperties)
{
return this.forSomeSheets(function (aSheet) {
// We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet) {
if (!this._matchedRules) {
this._buildMatchedRules();
}
let result = {};
this.forSomeSheets(function (aSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
return false;
}
return aSheet.forSomeRules(function (aRule) {
if (aRule.getPropertyValue(aProperty)) {
let unmatched = aRule._matchId !== this._matchId ||
this._ruleHasUnmatchedSelector(aRule);
if (!unmatched) {
return false;
}
aProperties = aProperties.filter(function(aProperty) {
if (!aRule.getPropertyValue(aProperty)) {
// Keep this property for the next rule. We need to find a rule
// which has the property.
return true;
}
result[aProperty] = true;
// We found a rule that has the current property while it does not
// match the current element. We can remove this property from the
// array.
return false;
});
return aProperties.length == 0;
}, this);
}, this);
aProperties.forEach(function(aProperty) { result[aProperty] = false; });
return result;
},
/**
* Check if a CssRule has an unmatched selector for the highlighted element or
* its parents.
*
* @private
* @param {CssRule} aRule The rule you want to check if it has an unmatched
* selector.
* @return {boolean} True if the rule has an unmatched selector, false
* otherwise.
*/
_ruleHasUnmatchedSelector: function CL__ruleHasUnmatchedSelector(aRule)
{
if (!aRule._cssSheet && aRule.sourceElement) {
// CssRule wraps element.style, which never has unmatched selectors.
return false;
}
let element = this.viewedElement;
let selectorText = aRule._domRule.selectorText;
let matches = false;
let selectors = aRule.selectors;
do {
if (element.mozMatchesSelector(selectorText)) {
matches = true;
selectors = selectors.filter(function(aSelector) {
return !element.mozMatchesSelector(aSelector);
});
if (selectors.length == 0) {
break;
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
if (!matches) {
// Now we know that there are rules but none match.
return true;
}
}
}, this);
}, this);
return selectors.length > 0;
},
/**
* Tells if the given DOM CSS object matches the current view media.
*
* @param {object} aDomObject The DOM CSS object to check.
* @return {boolean} True if the DOM CSS object matches the current view
* media, or false otherwise.
*/
mediaMatches: function CL_mediaMatches(aDomObject)
{
let mediaText = aDomObject.media.mediaText;
return !mediaText || this.viewedDocument.defaultView.
matchMedia(mediaText).matches;
},
};
@ -789,37 +888,6 @@ CssLogic.isSystemStyleSheet = function CssLogic_isSystemStyleSheet(aSheet)
return false;
};
/**
* Check if the given DOM CSS object holds an allowed media. Currently we only
* allow media screen or all.
*
* @param {CSSStyleSheet|CSSImportRule|CSSMediaRule} aDomObject the
* DOM object you want checked.
* @return {boolean} true if the media description is allowed, or false
* otherwise.
*/
CssLogic.sheetMediaAllowed = function CssLogic_sheetMediaAllowed(aDomObject)
{
let result = false;
let media = aDomObject.media;
if (media.length > 0) {
let mediaItem = null;
for (let m = 0, mediaLen = media.length; m < mediaLen; m++) {
mediaItem = media.item(m).toLowerCase();
if (mediaItem === CssLogic.MEDIA.SCREEN ||
mediaItem === CssLogic.MEDIA.ALL) {
result = true;
break;
}
}
} else {
result = true;
}
return result;
};
/**
* Return a shortened version of a style sheet's source.
*
@ -833,8 +901,14 @@ CssLogic.shortSource = function CssLogic_shortSource(aSheet)
}
// We try, in turn, the filename, filePath, query string, whole thing
let url = Services.io.newURI(aSheet.href, null, null);
let url = {};
try {
url = Services.io.newURI(aSheet.href, null, null);
url = url.QueryInterface(Ci.nsIURL);
} catch (ex) {
// Some UA-provided stylesheets are not valid URLs.
}
if (url.fileName) {
return url.fileName;
}
@ -847,7 +921,7 @@ CssLogic.shortSource = function CssLogic_shortSource(aSheet)
return url.query;
}
return this.domSheet.href;
return aSheet.href;
}
/**
@ -857,15 +931,13 @@ CssLogic.shortSource = function CssLogic_shortSource(aSheet)
* @param {CssLogic} aCssLogic pointer to the CssLogic instance working with
* this CssSheet object.
* @param {CSSStyleSheet} aDomSheet reference to a DOM CSSStyleSheet object.
* @param {boolean} aSystemSheet tells if the stylesheet is system-provided.
* @param {number} aIndex tells the index/position of the stylesheet within the
* main document.
*/
function CssSheet(aCssLogic, aDomSheet, aSystemSheet, aIndex)
function CssSheet(aCssLogic, aDomSheet, aIndex)
{
this._cssLogic = aCssLogic;
this.domSheet = aDomSheet;
this.systemSheet = aSystemSheet;
this.index = this.systemSheet ? -100 * aIndex : aIndex;
// Cache of the sheets href. Cached by the getter.
@ -884,6 +956,44 @@ function CssSheet(aCssLogic, aDomSheet, aSystemSheet, aIndex)
CssSheet.prototype = {
_passId: null,
_systemSheet: null,
_mediaMatches: null,
/**
* Tells if the stylesheet is provided by the browser or not.
*
* @return {boolean} true if this is a browser-provided stylesheet, or false
* otherwise.
*/
get systemSheet()
{
if (this._systemSheet === null) {
this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet);
}
return this._systemSheet;
},
/**
* Tells if the stylesheet is disabled or not.
* @return {boolean} true if this stylesheet is disabled, or false otherwise.
*/
get disabled()
{
return this.domSheet.disabled;
},
/**
* Tells if the stylesheet matches the current browser view media.
* @return {boolean} true if this stylesheet matches the current browser view
* media, or false otherwise.
*/
get mediaMatches()
{
if (this._mediaMatches === null) {
this._mediaMatches = this._cssLogic.mediaMatches(this.domSheet);
}
return this._mediaMatches;
},
/**
* Get a source for a stylesheet, taking into account embedded stylesheets
@ -976,7 +1086,7 @@ CssSheet.prototype = {
if (cacheId in this._rules) {
for (let i = 0, rulesLen = this._rules[cacheId].length; i < rulesLen; i++) {
rule = this._rules[cacheId][i];
if (rule._domRule == aDomRule) {
if (rule._domRule === aDomRule) {
ruleFound = true;
break;
}
@ -1018,7 +1128,7 @@ CssSheet.prototype = {
aCallback.call(aScope, this.getRule(aDomRule));
ruleCount++;
} else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
aDomRule.cssRules && this._cssLogic.mediaMatches(aDomRule)) {
Array.prototype.forEach.call(aDomRule.cssRules, _iterator, this);
}
}
@ -1051,7 +1161,7 @@ CssSheet.prototype = {
if (aDomRule.type == Ci.nsIDOMCSSRule.STYLE_RULE) {
return aCallback.call(aScope, this.getRule(aDomRule));
} else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
aDomRule.cssRules && this._cssLogic.mediaMatches(aDomRule)) {
return Array.prototype.some.call(aDomRule.cssRules, _iterator, this);
}
}
@ -1409,8 +1519,6 @@ function CssPropertyInfo(aCssLogic, aProperty)
// that have sheetAllowed = false).
this._matchedSelectors = null;
this._unmatchedSelectors = null;
this._hasMatchedSelectors = null;
this._hasUnmatchedSelectors = null;
}
CssPropertyInfo.prototype = {
@ -1508,60 +1616,6 @@ CssPropertyInfo.prototype = {
return this._unmatchedSelectors;
},
/**
* Check if the property has any matched selectors.
*
* @return {Boolean} true if the current element or it's parents have
* matching CssSelector objects, false otherwise
*/
hasMatchedSelectors: function CssPropertyInfo_hasMatchedSelectors()
{
if (this._hasMatchedSelectors === null) {
this._hasMatchedSelectors = this._cssLogic.hasMatchedSelectors(function(aDomRules) {
if (!aDomRules.Count) {
// For element.style.
return !!aDomRules.style.getPropertyValue(this.property);
}
for (let i = 0; i < aDomRules.Count(); i++) {
let domRule = aDomRules.GetElementAt(i);
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
let domSheet = domRule.parentStyleSheet;
let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
let filter = this._cssLogic.sourceFilter;
if (filter !== CssLogic.FILTER.UA && systemSheet) {
continue;
}
if (domRule.style.getPropertyValue(this.property)) {
return true;
}
}
return false;
}.bind(this));
}
return this._hasMatchedSelectors;
},
/**
* Check if the property has any matched selectors.
*
* @return {Boolean} true if the current element or it's parents have
* unmatched CssSelector objects, false otherwise
*/
hasUnmatchedSelectors: function CssPropertyInfo_hasUnmatchedSelectors()
{
if (this._hasUnmatchedSelectors === null) {
this._hasUnmatchedSelectors = this._cssLogic.hasUnmatchedSelectors(this.property);
}
return this._hasUnmatchedSelectors;
},
/**
* Find the selectors that match the highlighted element and its parents.
* Uses CssLogic.processMatchedSelectors() to find the matched selectors,

Просмотреть файл

@ -65,7 +65,7 @@ function testMatchedSelectors()
is(numMatchedSelectors, 6,
"CssLogic returns the correct number of matched selectors for div");
is(propertyView.propertyInfo.hasMatchedSelectors(), true,
is(propertyView.hasMatchedSelectors, true,
"hasMatchedSelectors returns true");
}
@ -89,7 +89,7 @@ function testUnmatchedSelectors()
is(numUnmatchedSelectors, 13,
"CssLogic returns the correct number of unmatched selectors for body");
is(propertyView.propertyInfo.hasUnmatchedSelectors(), true,
is(propertyView.hasUnmatchedSelectors, true,
"hasUnmatchedSelectors returns true");
}