author | Patrick Brosset <pbrosset@mozilla.com> |
Wed, 10 Dec 2014 09:09:19 +0100 | |
changeset 219029 | e0bcde09cbeb2cf2e8cc36d1087e9330944221b4 |
parent 218984 | 219d81afdd503110fd28def92d7a2076b715f78c |
child 219030 | 1ee8cdb3f47c2b88b93925fa5d5910dcbe079e23 |
push id | 27953 |
push user | ryanvm@gmail.com |
push date | Wed, 10 Dec 2014 20:52:05 +0000 |
treeherder | mozilla-central@7900b789d1fc [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bgrins, ochameau |
bugs | 1103993 |
milestone | 37.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/devtools/debugger/test/browser_dbg_pause-warning.js +++ b/browser/devtools/debugger/test/browser_dbg_pause-warning.js @@ -22,17 +22,19 @@ function test() { }); } function testPause() { gDebugger.gThreadClient.addOneTimeListener("paused", () => { ok(gTarget.isThreadPaused, "target.isThreadPaused has been updated to true."); - gToolbox.once("inspector-selected", testNotificationIsUp1); + gToolbox.once("inspector-selected").then(inspector => { + inspector.once("inspector-updated").then(testNotificationIsUp1); + }); gToolbox.selectTool("inspector"); }); EventUtils.sendMouseEvent({ type: "mousedown" }, gDebugger.document.getElementById("resume"), gDebugger); }
--- a/browser/devtools/inspector/inspector-panel.js +++ b/browser/devtools/inspector/inspector-panel.js @@ -413,19 +413,28 @@ InspectorPanel.prototype = { // client know. let selection = this.selection.nodeFront; // On any new selection made by the user, store the unique css selector // of the selected node so it can be restored after reload of the same page if (reason !== "navigateaway" && this.canGetUniqueSelector && this.selection.isElementNode()) { - selection.getUniqueSelector().then((selector) => { + selection.getUniqueSelector().then(selector => { this.selectionCssSelector = selector; - }).then(null, console.error); + }).then(null, e => { + // Only log this as an error if the panel hasn't been destroyed in the + // meantime. + if (!this._panelDestroyer) { + console.error(e); + } else { + console.warn("Could not set the unique selector for the newly "+ + "selected node, the inspector was destroyed."); + } + }); } let selfUpdate = this.updating("inspector-panel"); Services.tm.mainThread.dispatch(() => { try { selfUpdate(selection); } catch(ex) { console.error(ex);
--- a/browser/devtools/inspector/test/browser.ini +++ b/browser/devtools/inspector/test/browser.ini @@ -25,16 +25,17 @@ support-files = head.js [browser_inspector_breadcrumbs.js] [browser_inspector_breadcrumbs_highlight_hover.js] [browser_inspector_delete-selected-node-01.js] [browser_inspector_delete-selected-node-02.js] [browser_inspector_delete-selected-node-03.js] [browser_inspector_destroy-after-navigation.js] +[browser_inspector_destroy-before-ready.js] [browser_inspector_gcli-inspect-command.js] [browser_inspector_highlighter-01.js] [browser_inspector_highlighter-02.js] [browser_inspector_highlighter-03.js] [browser_inspector_highlighter-04.js] [browser_inspector_highlighter-by-type.js] [browser_inspector_highlighter-comments.js] [browser_inspector_highlighter-csstransform_01.js]
new file mode 100644 --- /dev/null +++ b/browser/devtools/inspector/test/browser_inspector_destroy-before-ready.js @@ -0,0 +1,26 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that switching to the inspector panel and not waiting for it to be fully +// loaded doesn't fail the test with unhandled rejected promises. + +add_task(function*() { + // At least one assertion is needed to avoid failing the test, but really, + // what we're interested in is just having the test pass when switching to the + // inspector. + ok(true); + + yield addTab("data:text/html;charset=utf-8,test inspector destroy"); + + info("Open the toolbox on the debugger panel"); + let target = TargetFactory.forTab(gBrowser.selectedTab); + let toolbox = yield gDevTools.showToolbox(target, "jsdebugger"); + + info("Switch to the inspector panel and immediately end the test"); + let onInspectorSelected = toolbox.once("inspector-selected"); + toolbox.selectTool("inspector"); + let inspector = yield onInspectorSelected; +});
--- a/browser/devtools/inspector/test/browser_inspector_pseudoclass-lock.js +++ b/browser/devtools/inspector/test/browser_inspector_pseudoclass-lock.js @@ -75,17 +75,16 @@ function* testNavigate(inspector, rulevi info("Make sure the pseudoclass is removed after navigating to a non-hierarchy node"); res = yield executeInContent("Test:HasPseudoClassLock", {pseudo: PSEUDO}, {node: getNode("#div-1")}); ok(!res.data, "pseudo-class lock is removed after inspecting sibling node"); yield selectNode("#div-1", inspector); yield togglePseudoClass(inspector); - yield inspector.once("computed-view-refreshed"); } function* showPickerOn(selector, inspector) { let highlighter = inspector.toolbox.highlighter; let nodeFront = yield getNodeFront(selector, inspector); yield highlighter.showBoxModel(nodeFront); }
--- a/browser/devtools/layoutview/test/head.js +++ b/browser/devtools/layoutview/test/head.js @@ -227,20 +227,18 @@ let openLayoutView = Task.async(function * Wait for the layoutview-updated event and for all of the inspector's panels * to update too. * Use this to make sure the inspector is updated and ready after a change was * made in one of the layout-view editable fields. * @return a promise */ function waitForUpdate(inspector) { let onLayoutView = inspector.once("layoutview-updated"); - let onRuleView = inspector.once("rule-view-refreshed"); - let onComputedView = inspector.once("computed-view-refreshed"); let onInspector = inspector.once("inspector-updated"); - return promise.all([onLayoutView, onRuleView, onComputedView, onInspector]); + return promise.all([onLayoutView, onInspector]); } /** * The addTest/runTests function couple provides a simple way to define * subsequent test cases in a test file. Example: * * addTest("what this test does", function*() { * ... actual code for the test ...
--- a/browser/devtools/layoutview/view.js +++ b/browser/devtools/layoutview/view.js @@ -543,17 +543,19 @@ window.setPanel = function(panel) { getService(Ci.nsIXULChromeRegistry); let dir = chromeReg.isLocaleRTL("global"); document.body.setAttribute("dir", dir ? "rtl" : "ltr"); window.parent.postMessage("layoutview-ready", "*"); }; window.onunload = function() { - this.layoutview.destroy(); + if (this.layoutview) { + this.layoutview.destroy(); + } if (elts) { for (let i = 0; i < elts.length; i++) { let elt = elts[i]; elt.removeEventListener("mouseover", onmouseover, true); elt.removeEventListener("mouseout", onmouseout, true); } } };
--- a/browser/devtools/markupview/markup-view.js +++ b/browser/devtools/markupview/markup-view.js @@ -742,16 +742,25 @@ MarkupView.prototype = { this.expandNode(parent); } return this._waitForChildren().then(() => { return this._ensureVisible(aNode); }).then(() => { // Why is this not working? this.layoutHelpers.scrollIntoViewIfNeeded(this.getContainer(aNode).editor.elt, centered); + }, e => { + // Only report this rejection as an error if the panel hasn't been + // destroyed in the meantime. + if (!this._destroyer) { + console.error(e); + } else { + console.warn("Could not show the node, the markup-view was destroyed " + + "while waiting for children"); + } }); }, /** * Expand the container's children. */ _expandContainer: function(aContainer) { return this._updateChildren(aContainer, {expand: true}).then(() => {
--- a/browser/devtools/styleinspector/computed-view.js +++ b/browser/devtools/styleinspector/computed-view.js @@ -583,17 +583,24 @@ CssHtmlTree.prototype = { CssHtmlTree.propertyNames.push(prop); } } CssHtmlTree.propertyNames.sort(); CssHtmlTree.propertyNames.push.apply(CssHtmlTree.propertyNames, mozProps.sort()); - this._createPropertyViews(); + this._createPropertyViews().then(null, e => { + if (!this.styleInspector) { + console.warn("The creation of property views was cancelled because the " + + "computed-view was destroyed before it was done creating views"); + } else { + console.error(e); + } + }); }, /** * Get a set of properties that have matched selectors. * * @return {Set} If a property name is in the set, it has matching selectors. */ get matchedProperties()
--- a/browser/devtools/styleinspector/rule-view.js +++ b/browser/devtools/styleinspector/rule-view.js @@ -1455,20 +1455,22 @@ CssRuleView.prototype = { }, _onSourcePrefChanged: function() { if (this.menuitemSources) { let isEnabled = Services.prefs.getBoolPref(PREF_ORIG_SOURCES); this.menuitemSources.setAttribute("checked", isEnabled); } - // update text of source links - for (let rule of this._elementStyle.rules) { - if (rule.editor) { - rule.editor.updateSourceLink(); + // update text of source links if the rule-view is populated + if (this._elementStyle) { + for (let rule of this._elementStyle.rules) { + if (rule.editor) { + rule.editor.updateSourceLink(); + } } } }, destroy: function() { this.isDestroyed = true; this.clear();
--- a/browser/devtools/styleinspector/style-inspector.js +++ b/browser/devtools/styleinspector/style-inspector.js @@ -27,35 +27,45 @@ function RuleViewTool(inspector, window, this.doc.documentElement.appendChild(this.view.element); this.onLinkClicked = this.onLinkClicked.bind(this); this.onSelected = this.onSelected.bind(this); this.refresh = this.refresh.bind(this); this.clearUserProperties = this.clearUserProperties.bind(this); this.onPropertyChanged = this.onPropertyChanged.bind(this); this.onViewRefreshed = this.onViewRefreshed.bind(this); + this.onPanelSelected = this.onPanelSelected.bind(this); this.view.element.addEventListener("CssRuleViewChanged", this.onPropertyChanged); this.view.element.addEventListener("CssRuleViewRefreshed", this.onViewRefreshed); this.view.element.addEventListener("CssRuleViewCSSLinkClicked", this.onLinkClicked); this.inspector.selection.on("detached", this.onSelected); this.inspector.selection.on("new-node-front", this.onSelected); this.inspector.on("layout-change", this.refresh); this.inspector.selection.on("pseudoclass", this.refresh); this.inspector.target.on("navigate", this.clearUserProperties); + this.inspector.sidebar.on("ruleview-selected", this.onPanelSelected); this.onSelected(); } RuleViewTool.prototype = { + isSidebarActive: function() { + return this.inspector.sidebar.getCurrentTabID() == "ruleview"; + }, + onSelected: function(event) { - // Ignore the event if the view has been destroyed - if (!this.view) { + // Ignore the event if the view has been destroyed, or if it's inactive. + // But only if the current selection isn't null. If it's been set to null, + // let the update go through as this is needed to empty the view on navigation. + let isDestroyed = !this.view; + let isInactive = !this.isSidebarActive() && this.inspector.selection.nodeFront; + if (isDestroyed || isInactive) { return; } this.view.setPageStyle(this.inspector.pageStyle); if (!this.inspector.selection.isConnected() || !this.inspector.selection.isElementNode()) { this.view.selectElement(null); @@ -64,25 +74,35 @@ RuleViewTool.prototype = { if (!event || event == "new-node-front") { let done = this.inspector.updating("rule-view"); this.view.selectElement(this.inspector.selection.nodeFront).then(done, done); } }, refresh: function() { - this.view.refreshPanel(); + if (this.isSidebarActive()) { + this.view.refreshPanel(); + } }, clearUserProperties: function() { if (this.view && this.view.store && this.view.store.userProperties) { this.view.store.userProperties.clear(); } }, + onPanelSelected: function() { + if (this.inspector.selection.nodeFront === this.view.viewedElement) { + this.refresh(); + } else { + this.onSelected(); + } + }, + onLinkClicked: function(event) { let rule = event.detail.rule; let sheet = rule.parentStyleSheet; // Chrome stylesheets are not listed in the style editor, so show // these sheets in the view source window instead. if (!sheet || sheet.isSystem) { let contentDoc = this.inspector.selection.document; @@ -116,16 +136,17 @@ RuleViewTool.prototype = { this.inspector.emit("rule-view-refreshed"); }, destroy: function() { this.inspector.off("layout-change", this.refresh); this.inspector.selection.off("pseudoclass", this.refresh); this.inspector.selection.off("new-node-front", this.onSelected); this.inspector.target.off("navigate", this.clearUserProperties); + this.inspector.sidebar.off("ruleview-selected", this.onPanelSelected); this.view.element.removeEventListener("CssRuleViewCSSLinkClicked", this.onLinkClicked); this.view.element.removeEventListener("CssRuleViewChanged", this.onPropertyChanged); this.view.element.removeEventListener("CssRuleViewRefreshed", this.onViewRefreshed); this.doc.documentElement.removeChild(this.view.element); this.view.destroy(); @@ -137,33 +158,44 @@ RuleViewTool.prototype = { function ComputedViewTool(inspector, window, iframe) { this.inspector = inspector; this.doc = window.document; this.view = new ComputedView.CssHtmlTree(this, inspector.pageStyle); this.onSelected = this.onSelected.bind(this); this.refresh = this.refresh.bind(this); + this.onPanelSelected = this.onPanelSelected.bind(this); this.inspector.selection.on("detached", this.onSelected); this.inspector.selection.on("new-node-front", this.onSelected); this.inspector.on("layout-change", this.refresh); this.inspector.selection.on("pseudoclass", this.refresh); + this.inspector.sidebar.on("computedview-selected", this.onPanelSelected); this.view.selectElement(null); this.onSelected(); } ComputedViewTool.prototype = { + isSidebarActive: function() { + return this.inspector.sidebar.getCurrentTabID() == "computedview"; + }, + onSelected: function(event) { - // Ignore the event if the view has been destroyed - if (!this.view) { + // Ignore the event if the view has been destroyed, or if it's inactive. + // But only if the current selection isn't null. If it's been set to null, + // let the update go through as this is needed to empty the view on navigation. + let isDestroyed = !this.view; + let isInactive = !this.isSidebarActive() && this.inspector.selection.nodeFront; + if (isDestroyed || isInactive) { return; } + this.view.setPageStyle(this.inspector.pageStyle); if (!this.inspector.selection.isConnected() || !this.inspector.selection.isElementNode()) { this.view.selectElement(null); return; } @@ -171,24 +203,35 @@ ComputedViewTool.prototype = { let done = this.inspector.updating("computed-view"); this.view.selectElement(this.inspector.selection.nodeFront).then(() => { done(); }); } }, refresh: function() { - this.view.refreshPanel(); + if (this.isSidebarActive()) { + this.view.refreshPanel(); + } + }, + + onPanelSelected: function() { + if (this.inspector.selection.nodeFront === this.view.viewedElement) { + this.refresh(); + } else { + this.onSelected(); + } }, destroy: function() { this.inspector.off("layout-change", this.refresh); this.inspector.sidebar.off("computedview-selected", this.refresh); this.inspector.selection.off("pseudoclass", this.refresh); this.inspector.selection.off("new-node-front", this.onSelected); + this.inspector.sidebar.off("computedview-selected", this.onPanelSelected); this.view.destroy(); this.view = this.cssLogic = this.cssHtmlTree = null; this.doc = this.inspector = null; } };
--- a/browser/devtools/styleinspector/test/browser.ini +++ b/browser/devtools/styleinspector/test/browser.ini @@ -32,17 +32,16 @@ support-files = [browser_computedview_matched-selectors-toggle.js] [browser_computedview_matched-selectors_01.js] [browser_computedview_matched-selectors_02.js] [browser_computedview_media-queries.js] [browser_computedview_no-results-placeholder.js] [browser_computedview_original-source-link.js] [browser_computedview_pseudo-element_01.js] [browser_computedview_refresh-on-style-change_01.js] -[browser_computedview_refresh-on-style-change_02.js] [browser_computedview_search-filter.js] [browser_computedview_select-and-copy-styles.js] [browser_computedview_style-editor-link.js] [browser_ruleview_add-property-and-reselect.js] [browser_ruleview_add-property-cancel_01.js] [browser_ruleview_add-property-cancel_02.js] [browser_ruleview_add-property-cancel_03.js] [browser_ruleview_add-property_01.js] @@ -108,16 +107,17 @@ skip-if = e10s # bug 1040670 Cannot open [browser_ruleview_urls-clickable.js] [browser_ruleview_user-agent-styles.js] [browser_ruleview_user-agent-styles-uneditable.js] [browser_ruleview_user-property-reset.js] [browser_styleinspector_context-menu-copy-color_01.js] [browser_styleinspector_context-menu-copy-color_02.js] [browser_styleinspector_csslogic-content-stylesheets.js] [browser_styleinspector_output-parser.js] +[browser_styleinspector_refresh_when_active.js] [browser_styleinspector_tooltip-background-image.js] [browser_styleinspector_tooltip-closes-on-new-selection.js] [browser_styleinspector_tooltip-longhand-fontfamily.js] [browser_styleinspector_tooltip-multiple-background-images.js] [browser_styleinspector_tooltip-shorthand-fontfamily.js] [browser_styleinspector_tooltip-size.js] [browser_styleinspector_transform-highlighter-01.js] [browser_styleinspector_transform-highlighter-02.js]
deleted file mode 100644 --- a/browser/devtools/styleinspector/test/browser_computedview_refresh-on-style-change_02.js +++ /dev/null @@ -1,37 +0,0 @@ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Test that the computed view refreshes when the current node has its style -// changed, even if the view is not the active one - -const TESTCASE_URI = 'data:text/html;charset=utf-8,' + - '<div id="testdiv" style="font-size:10px;">Test div!</div>'; - -let test = asyncTest(function*() { - yield addTab(TESTCASE_URI); - - info("Opening the computed view and selecting the test node"); - let {toolbox, inspector, view} = yield openComputedView(); - yield selectNode("#testdiv", inspector); - - let fontSize = getComputedViewPropertyValue(view, "font-size"); - is(fontSize, "10px", "The computed view shows the right font-size"); - - info("Now switching to the rule view"); - yield openRuleView(); - - info("Changing the node's style and waiting for the update"); - let onUpdated = inspector.once("computed-view-refreshed"); - getNode("#testdiv").style.cssText = "font-size: 20px; color: blue; text-align: center"; - yield onUpdated; - - fontSize = getComputedViewPropertyValue(view, "font-size"); - is(fontSize, "20px", "The computed view shows the updated font-size"); - let color = getComputedViewPropertyValue(view, "color"); - is(color, "#00F", "The computed view also shows the color now"); - let textAlign = getComputedViewPropertyValue(view, "text-align"); - is(textAlign, "center", "The computed view also shows the text-align now"); -});
new file mode 100644 --- /dev/null +++ b/browser/devtools/styleinspector/test/browser_styleinspector_refresh_when_active.js @@ -0,0 +1,43 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that the style-inspector views only refresh when they are active. + +const TEST_URL = 'data:text/html;charset=utf-8,' + + '<div id="one" style="color:red;">one</div>' + + '<div id="two" style="color:blue;">two</div>'; + +let test = asyncTest(function*() { + yield addTab(TEST_URL); + + info("Opening the rule-view and selecting test node one"); + let {inspector, view: rView} = yield openRuleView(); + yield selectNode("#one", inspector); + + is(getRuleViewPropertyValue(rView, "element", "color"), "#F00", + "The rule-view shows the properties for test node one"); + + let cView = inspector.sidebar.getWindowForTab("computedview")["computedview"].view; + let prop = getComputedViewProperty(cView, "color"); + ok(!prop, "The computed-view doesn't show the properties for test node one"); + + info("Switching to the computed-view"); + let onComputedViewReady = inspector.once("computed-view-refreshed"); + yield openComputedView(); + yield onComputedViewReady; + + ok(getComputedViewPropertyValue(cView, "color"), "#F00", + "The computed-view shows the properties for test node one"); + + info("Selecting test node two"); + yield selectNode("#two", inspector); + + ok(getComputedViewPropertyValue(cView, "color"), "#00F", + "The computed-view shows the properties for test node two"); + + is(getRuleViewPropertyValue(rView, "element", "color"), "#F00", + "The rule-view doesn't the properties for test node two"); +}); \ No newline at end of file
--- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js @@ -37,17 +37,19 @@ let test = asyncTest(function*() { yield selectNode(".test-element", inspector); info("Testing the the background property on the .test-element rule"); yield testDivRuleView(view); info("Testing that image preview tooltips show even when there are fields being edited"); yield testTooltipAppearsEvenInEditMode(view); info("Switching over to the computed-view"); + let onComputedViewReady = inspector.once("computed-view-refreshed"); ({view} = yield openComputedView()); + yield onComputedViewReady; info("Testing that the background-image computed style has a tooltip too"); yield testComputedView(view); }); function* testBodyRuleView(view) { info("Testing tooltips in the rule view"); let panel = view.tooltips.previewTooltip.panel;
--- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js @@ -27,17 +27,19 @@ let test = asyncTest(function*() { let {toolbox, inspector, view} = yield openRuleView(); info("Selecting the test node"); yield selectNode("#testElement", inspector); yield testRuleView(view, inspector.selection.nodeFront); info("Opening the computed view"); + let onComputedViewReady = inspector.once("computed-view-refreshed"); ({toolbox, inspector, view} = yield openComputedView()); + yield onComputedViewReady; yield testComputedView(view, inspector.selection.nodeFront); yield testExpandedComputedViewProperty(view, inspector.selection.nodeFront); }); function* testRuleView(ruleView, nodeFront) { info("Testing font-family tooltips in the rule view");
--- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-multiple-background-images.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-multiple-background-images.js @@ -27,27 +27,28 @@ let test = asyncTest(function* () { yield testRuleViewUrls(); yield testComputedViewUrls(); }); function* testRuleViewUrls() { info("Testing tooltips in the rule view"); - let { view, inspector } = yield openRuleView(); + let {view, inspector} = yield openRuleView(); yield selectNode("h1", inspector); let {valueSpan} = getRuleViewProperty(view, "h1", "background"); yield performChecks(view, valueSpan); } function* testComputedViewUrls() { info("Testing tooltips in the computed view"); - let {view} = yield openComputedView(); + let {view, inspector} = yield openComputedView(); + yield inspector.once("computed-view-refreshed"); let {valueSpan} = getComputedViewProperty(view, "background-image"); yield performChecks(view, valueSpan); } /** * A helper that checks url() tooltips contain correct images */
--- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js @@ -15,27 +15,29 @@ const PAGE_CONTENT = [ 'Test the css transform highlighter' ].join("\n"); const TYPE = "CssTransformHighlighter"; let test = asyncTest(function*() { yield addTab("data:text/html;charset=utf-8," + PAGE_CONTENT); - let {view: rView} = yield openRuleView(); + let {inspector, view: rView} = yield openRuleView(); let overlay = rView.highlighters; ok(!overlay.highlighters[TYPE], "No highlighter exists in the rule-view"); let h = yield overlay._getHighlighter(TYPE); ok(overlay.highlighters[TYPE], "The highlighter has been created in the rule-view"); is(h, overlay.highlighters[TYPE], "The right highlighter has been created"); let h2 = yield overlay._getHighlighter(TYPE); is(h, h2, "The same instance of highlighter is returned everytime in the rule-view"); + let onComputedViewReady = inspector.once("computed-view-refreshed"); let {view: cView} = yield openComputedView(); + yield onComputedViewReady; overlay = cView.highlighters; ok(!overlay.highlighters[TYPE], "No highlighter exists in the computed-view"); h = yield overlay._getHighlighter(TYPE); ok(overlay.highlighters[TYPE], "The highlighter has been created in the computed-view"); is(h, overlay.highlighters[TYPE], "The right highlighter has been created"); h2 = yield overlay._getHighlighter(TYPE); is(h, h2, "The same instance of highlighter is returned everytime in the computed-view");
--- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js @@ -17,18 +17,17 @@ const PAGE_CONTENT = [ 'Test the css transform highlighter' ].join("\n"); let TYPE = "CssTransformHighlighter"; let test = asyncTest(function*() { yield addTab("data:text/html;charset=utf-8," + PAGE_CONTENT); - - let {view: rView} = yield openRuleView(); + let {inspector, view: rView} = yield openRuleView(); let hs = rView.highlighters; ok(!hs.highlighters[TYPE], "No highlighter exists in the rule-view (1)"); ok(!hs.promises[TYPE], "No highlighter is being created in the rule-view (1)"); info("Faking a mousemove on a non-transform property"); let {valueSpan} = getRuleViewProperty(rView, "body", "color"); hs._onMouseMove({target: valueSpan}); @@ -37,17 +36,19 @@ let test = asyncTest(function*() { info("Faking a mousemove on a transform property"); ({valueSpan} = getRuleViewProperty(rView, "body", "transform")); hs._onMouseMove({target: valueSpan}); ok(hs.promises[TYPE], "The highlighter is being initialized"); let h = yield hs.promises[TYPE]; is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one"); + let onComputedViewReady = inspector.once("computed-view-refreshed"); let {view: cView} = yield openComputedView(); + yield onComputedViewReady; hs = cView.highlighters; ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (1)"); ok(!hs.promises[TYPE], "No highlighter is being created in the computed-view (1)"); info("Faking a mousemove on a non-transform property"); ({valueSpan} = getComputedViewProperty(cView, "color")); hs._onMouseMove({target: valueSpan});
--- a/browser/devtools/styleinspector/test/head.js +++ b/browser/devtools/styleinspector/test/head.js @@ -38,16 +38,17 @@ registerCleanupFunction(function*() { // Set the testing flag on gDevTools and reset it when the test ends gDevTools.testing = true; registerCleanupFunction(() => gDevTools.testing = false); // Clean-up all prefs that might have been changed during a test run // (safer here because if the test fails, then the pref is never reverted) registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.inspector.activeSidebar"); Services.prefs.clearUserPref("devtools.dump.emit"); Services.prefs.clearUserPref("devtools.defaultColorUnit"); }); /** * The functions found below are here to ease test development and maintenance. * Most of these functions are stateless and will require some form of context * (the instance of the current toolbox, or inspector panel for instance).
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js @@ -48,32 +48,36 @@ function createDocument() { setupHighlighterTests(); } function setupHighlighterTests() { ok(h1, "we have the header node"); openInspector(runSelectionTests); } -function runSelectionTests(aInspector) { +let runSelectionTests = Task.async(function*(aInspector) { inspector = aInspector; + let onPickerStarted = inspector.toolbox.once("picker-started"); inspector.toolbox.highlighterUtils.startPicker(); - inspector.toolbox.once("picker-started", () => { - info("Picker mode started, now clicking on H1 to select that node"); - executeSoon(() => { - h1.scrollIntoView(); - EventUtils.synthesizeMouseAtCenter(h1, {}, content); - inspector.toolbox.once("picker-stopped", () => { - info("Picker mode stopped, H1 selected, now switching to the console"); - openConsole(gBrowser.selectedTab).then(performWebConsoleTests); - }); - }); - }); -} + yield onPickerStarted; + + info("Picker mode started, now clicking on H1 to select that node"); + h1.scrollIntoView(); + let onPickerStopped = inspector.toolbox.once("picker-stopped"); + let onInspectorUpdated = inspector.once("inspector-updated"); + EventUtils.synthesizeMouseAtCenter(h1, {}, content); + yield onPickerStopped; + yield onInspectorUpdated; + + info("Picker mode stopped, H1 selected, now switching to the console"); + let hud = yield openConsole(gBrowser.selectedTab); + + performWebConsoleTests(hud); +}); function performWebConsoleTests(hud) { let target = TargetFactory.forTab(gBrowser.selectedTab); let jsterm = hud.jsterm; outputNode = hud.outputNode; jsterm.clearOutput(); jsterm.execute("$0", onNodeOutput);
--- a/toolkit/devtools/server/actors/styles.js +++ b/toolkit/devtools/server/actors/styles.js @@ -123,16 +123,33 @@ var PageStyleActor = protocol.ActorClass this.refMap = new Map; this.onFrameUnload = this.onFrameUnload.bind(this); events.on(this.inspector.tabActor, "will-navigate", this.onFrameUnload); }, get conn() this.inspector.conn, + form: function(detail) { + if (detail === "actorid") { + return this.actorID; + } + + return { + actor: this.actorID, + traits: { + // Whether the actor has had bug 1103993 fixed, which means that the + // getApplied method calls cssLogic.highlight(node) to recreate the + // style cache. Clients requesting getApplied from actors that have not + // been fixed must make sure cssLogic.highlight(node) was called before. + getAppliedCreatesStyleCache: true + } + }; + }, + /** * Return or create a StyleRuleActor for the given item. * @param item Either a CSSStyleRule or a DOM element. */ _styleRef: function(item) { if (this.refMap.has(item)) { return this.refMap.get(item); } @@ -411,16 +428,17 @@ var PageStyleActor = protocol.ActorClass * 'user': Include properties from user style sheets. * 'ua': Include properties from user and user-agent sheets. * Default value is 'ua' * `inherited`: Include styles inherited from parent nodes. * `matchedSeletors`: Include an array of specific selectors that * caused this rule to match its node. */ getApplied: method(function(node, options) { + this.cssLogic.highlight(node.rawNode); let entries = []; entries = entries.concat(this._getAllElementRules(node, undefined, options)); return this.getAppliedProps(node, entries, options); }, { request: { node: Arg(0, "domnode"), inherited: Option(1, "boolean"), matchedSelectors: Option(1, "boolean"), @@ -798,37 +816,51 @@ exports.PageStyleActor = PageStyleActor; * Front object for the PageStyleActor */ var PageStyleFront = protocol.FrontClass(PageStyleActor, { initialize: function(conn, form, ctx, detail) { protocol.Front.prototype.initialize.call(this, conn, form, ctx, detail); this.inspector = this.parent(); }, + form: function(form, detail) { + if (detail === "actorid") { + this.actorID = form; + return; + } + this._form = form; + }, + destroy: function() { protocol.Front.prototype.destroy.call(this); }, get walker() { return this.inspector.walker; }, getMatchedSelectors: protocol.custom(function(node, property, options) { return this._getMatchedSelectors(node, property, options).then(ret => { return ret.matched; }); }, { impl: "_getMatchedSelectors" }), - getApplied: protocol.custom(function(node, options={}) { - return this._getApplied(node, options).then(ret => { - return ret.entries; - }); - }, { + getApplied: protocol.custom(Task.async(function*(node, options={}) { + // If the getApplied method doesn't recreate the style cache itself, this + // means a call to cssLogic.highlight is required before trying to access + // the applied rules. Issue a request to getLayout if this is the case. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1103993#c16. + if (!this._form.traits || !this._form.traits.getAppliedCreatesStyleCache) { + yield this.getLayout(node); + } + let ret = yield this._getApplied(node, options); + return ret.entries; + }), { impl: "_getApplied" }), addNewRule: protocol.custom(function(node) { return this._addNewRule(node).then(ret => { return ret.entries[0]; }); }, {
--- a/toolkit/devtools/styleinspector/css-logic.js +++ b/toolkit/devtools/styleinspector/css-logic.js @@ -159,16 +159,20 @@ CssLogic.prototype = { if (!aViewedElement) { this.viewedElement = null; this.viewedDocument = null; this._computedStyle = null; this.reset(); return; } + if (aViewedElement === this.viewedElement) { + return; + } + this.viewedElement = aViewedElement; let doc = this.viewedElement.ownerDocument; if (doc != this.viewedDocument) { // New document: clear/rebuild the cache. this.viewedDocument = doc; // Hunt down top level stylesheets, and cache them.