merge fx-team to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-07-14 15:14:40 +02:00
commit b7dbeeb58b
39 changed files with 611 additions and 360 deletions

View File

@ -930,7 +930,7 @@ let RemoteDebugger = {
}
try {
DebuggerServer.closeListener();
DebuggerServer.closeAllListeners();
} catch (e) {
dump('Unable to stop debugger server: ' + e + '\n');
}

View File

@ -539,6 +539,7 @@ nsBrowserContentHandler.prototype = {
helpInfo : " -browser Open a browser window.\n" +
" -new-window <url> Open <url> in a new window.\n" +
" -new-tab <url> Open <url> in a new tab.\n" +
" -private-window <url> Open <url> in a new private window.\n" +
#ifdef XP_WIN
" -preferences Open Options dialog.\n" +
#else

View File

@ -23,7 +23,12 @@ let test = asyncTest(function*() {
yield navigate(usage, options);
yield checkPages(usage);
yield checkEditorReport(usage);
yield checkPageReport(usage);
// usage.createPageReport is not supported for usage.oneshot data as of
// bug 1035300 because the page report assumed we have preload data which
// oneshot can't gather. The ideal solution is to have a special no-preload
// mode for the page report, but since oneshot isn't needed for the UI to
// function, we're currently not supporting page report for oneshot data
// yield checkPageReport(usage);
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);

View File

@ -8,13 +8,15 @@ support-files =
doc_inspector_gcli-inspect-command.html
doc_inspector_highlighter-comments.html
doc_inspector_highlighter.html
doc_inspector_infobar.html
browser_inspector_infobar_01.html
browser_inspector_infobar_02.html
doc_inspector_menu.html
doc_inspector_remove-iframe-during-load.html
doc_inspector_search.html
doc_inspector_search-suggestions.html
doc_inspector_select-last-selected-01.html
doc_inspector_select-last-selected-02.html
browser_inspector_highlight_after_transition.html
head.js
[browser_inspector_breadcrumbs.js]
@ -29,8 +31,8 @@ support-files =
[browser_inspector_highlighter-comments.js]
[browser_inspector_highlighter-iframes.js]
[browser_inspector_iframe-navigation.js]
[browser_inspector_infobar.js]
skip-if = true # Bug 1028609
[browser_inspector_infobar_01.js]
[browser_inspector_infobar_02.js]
[browser_inspector_initialization.js]
[browser_inspector_inspect-object-element.js]
[browser_inspector_invalidate.js]

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
div {
opacity: 0;
height: 0;
background: red;
border-top: 1px solid #888;
transition-property: height, opacity;
transition-duration: 3000ms;
transition-timing-function: ease-in-out, ease-in-out, linear;
}
div[visible] {
opacity: 1;
height: 200px;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -0,0 +1,35 @@
/* 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";
const TEST_URI = "http://example.com/browser/browser/devtools/inspector/" +
"test/browser_inspector_highlight_after_transition.html";
// Test that the nodeinfobar is never displayed above the top or below the
// bottom of the content area.
let test = asyncTest(function*() {
info("Loading the test document and opening the inspector");
yield addTab(TEST_URI);
let {inspector} = yield openInspector();
yield checkDivHeight(inspector);
gBrowser.removeCurrentTab();
});
function* checkDivHeight(inspector) {
let div = getNode("div");
div.setAttribute("visible", "true");
yield once(div, "transitionend");
yield selectAndHighlightNode(div, inspector);
let height = div.getBoundingClientRect().height;
is (height, 201, "div is the correct height");
}

View File

@ -15,7 +15,7 @@ let test = asyncTest(function*() {
info("Selecting the simple, non-transformed DIV");
let div = getNode("#simple-div");
yield selectNode(div, inspector, "highlight");
yield selectAndHighlightNode(div, inspector);
testSimpleDivHighlighted(div);
yield zoomTo(2);
@ -25,7 +25,7 @@ let test = asyncTest(function*() {
info("Selecting the rotated DIV");
let rotated = getNode("#rotated-div");
let onBoxModelUpdate = waitForBoxModelUpdate();
yield selectNode(rotated, inspector, "highlight");
yield selectAndHighlightNode(rotated, inspector);
yield onBoxModelUpdate;
testMouseOverRotatedHighlights(rotated);
@ -33,7 +33,7 @@ let test = asyncTest(function*() {
info("Selecting the zero width height DIV");
let zeroWidthHeight = getNode("#widthHeightZero-div");
let onBoxModelUpdate = waitForBoxModelUpdate();
yield selectNode(zeroWidthHeight, inspector, "highlight");
yield selectAndHighlightNode(zeroWidthHeight, inspector);
yield onBoxModelUpdate;
testMouseOverWidthHeightZeroDiv(zeroWidthHeight);

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {
width: 100%;
height: 100%;
}
div {
position: absolute;
height: 100px;
width: 500px;
}
#bottom {
bottom: 0px;
background: blue;
}
#vertical {
height: 100%;
background: green;
}
</style>
</head>
<body>
<div id="vertical">Vertical</div>
<div id="top" class="class1 class2">Top</div>
<div id="bottom">Bottom</div>
</body>
</html>

View File

@ -5,8 +5,7 @@
"use strict";
const TEST_URI = "http://example.com/browser/browser/devtools/inspector/" +
"test/doc_inspector_infobar.html";
const DOORHANGER_ARROW_HEIGHT = 5;
"test/browser_inspector_infobar_01.html";
// Test that hovering over nodes in the markup-view shows the highlighter over
// those nodes
@ -51,23 +50,12 @@ let test = asyncTest(function*() {
classes: ""
// No dims as they will vary between computers
},
{
node: doc.querySelector("#farbottom"),
position: "top",
tag: "DIV",
id: "#farbottom",
classes: "",
dims: "500 x 100"
},
];
for (let currTest of testData) {
yield testPosition(currTest, inspector);
}
yield checkInfoBarAboveTop(inspector);
yield checkInfoBarBelowFindbar(inspector);
gBrowser.removeCurrentTab();
});
@ -77,7 +65,7 @@ function* testPosition(currTest, inspector) {
info("Testing " + currTest.id);
yield selectNode(currTest.node, inspector, "highlight");
yield selectAndHighlightNode(currTest.node, inspector);
let container = stack.querySelector(".highlighter-nodeinfobar-positioner");
is(container.getAttribute("position"),
@ -101,50 +89,3 @@ function* testPosition(currTest, inspector) {
is(dimBox.textContent, currTest.dims, "node " + currTest.id + ": dims match.");
}
}
function* checkInfoBarAboveTop(inspector) {
yield selectNode("#abovetop", inspector);
let positioner = getPositioner();
let insideContent = parseInt(positioner.style.top, 10) >= -DOORHANGER_ARROW_HEIGHT;
ok(insideContent, "Infobar is inside the content window (top = " +
parseInt(positioner.style.top, 10) + ", content = '" +
positioner.textContent +"')");
}
function* checkInfoBarBelowFindbar(inspector) {
gFindBar.open();
let body = content.document.body;
let farBottom = body.querySelector("#farbottom");
farBottom.scrollIntoView();
// Wait for scrollIntoView
yield waitForTick();
body.scrollTop -= 130;
yield selectNode(farBottom, inspector);
let positioner = getPositioner();
let insideContent = parseInt(positioner.style.top, 10) >= -DOORHANGER_ARROW_HEIGHT;
ok(insideContent, "Infobar does not overlap the findbar (top = " +
parseInt(positioner.style.top, 10) + ", content = '" +
positioner.textContent +"')");
gFindBar.close();
}
function getPositioner() {
let browser = gBrowser.selectedBrowser;
let stack = browser.parentNode;
return stack.querySelector(".highlighter-nodeinfobar-positioner");
}
function waitForTick() {
let deferred = promise.defer();
executeSoon(deferred.resolve);
return deferred.promise;
}

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {
width: 100%;
height: 100%;
}
div {
position: absolute;
height: 100px;
width: 500px;
}
#below-bottom {
bottom: -200px;
background: red;
}
#above-top {
top: -200px;
background: black;
color: white;
}";
</style>
</head>
<body>
<div id="above-top">Above top</div>
<div id="below-bottom">Far bottom</div>
</body>
</html>

View File

@ -0,0 +1,65 @@
/* 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";
const TEST_URI = "http://example.com/browser/browser/devtools/inspector/" +
"test/browser_inspector_infobar_02.html";
const DOORHANGER_ARROW_HEIGHT = 5;
// Test that the nodeinfobar is never displayed above the top or below the
// bottom of the content area.
let test = asyncTest(function*() {
info("Loading the test document and opening the inspector");
yield addTab(TEST_URI);
let {inspector} = yield openInspector();
yield checkInfoBarAboveTop(inspector);
yield checkInfoBarBelowFindbar(inspector);
gBrowser.removeCurrentTab();
});
function* checkInfoBarAboveTop(inspector) {
yield selectAndHighlightNode("#above-top", inspector);
let positioner = getPositioner();
let positionerTop = parseInt(positioner.style.top, 10);
let insideContent = positionerTop >= -DOORHANGER_ARROW_HEIGHT;
ok(insideContent, "Infobar is inside the content window (top = " +
positionerTop + ", content = '" +
positioner.textContent +"')");
}
function* checkInfoBarBelowFindbar(inspector) {
gFindBar.open();
// Ensure that the findbar is fully open.
yield once(gFindBar, "transitionend");
yield selectAndHighlightNode("#below-bottom", inspector);
let positioner = getPositioner();
let positionerBottom =
positioner.getBoundingClientRect().bottom - DOORHANGER_ARROW_HEIGHT;
let findBarTop = gFindBar.getBoundingClientRect().top;
let insideContent = positionerBottom <= findBarTop;
ok(insideContent, "Infobar does not overlap the findbar (findBarTop = " +
findBarTop + ", positionerBottom = " + positionerBottom +
", content = '" + positioner.textContent +"')");
gFindBar.close();
yield once(gFindBar, "transitionend");
}
function getPositioner() {
let browser = gBrowser.selectedBrowser;
let stack = browser.parentNode;
return stack.querySelector(".highlighter-nodeinfobar-positioner");
}

View File

@ -132,24 +132,42 @@ function getNode(nodeOrSelector, options = {}) {
return nodeOrSelector;
}
/**
* Highlight a node and set the inspector's current selection to the node or
* the first match of the given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectAndHighlightNode(nodeOrSelector, inspector) {
info("Highlighting and selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.toolbox.once("highlighter-ready");
inspector.selection.setNode(node, "test-highlight");
return updated;
}
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @param {String} reason Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @param {String} reason Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not to highlight the
* node upon selection
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectNode(nodeOrSelector, inspector, reason="test") {
info("Selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.once("inspector-updated", () => {
is(inspector.selection.node, node, "Correct node was selected");
});
let updated = inspector.once("inspector-updated");
inspector.selection.setNode(node, reason);
return updated;
}

View File

@ -101,20 +101,40 @@ function getNode(nodeOrSelector) {
nodeOrSelector;
}
/**
* Highlight a node and set the inspector's current selection to the node or
* the first match of the given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectAndHighlightNode(nodeOrSelector, inspector) {
info("Highlighting and selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.toolbox.once("highlighter-ready");
inspector.selection.setNode(node, "test-highlight");
return updated;
}
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @param {String} reason Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @param {String} reason Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not to highlight the
* node upon selection
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectNode(nodeOrSelector, inspector, reason="test") {
info("Selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.once("inspector-updated");
inspector.selection.setNode(node, reason);

View File

@ -134,16 +134,39 @@ function getNode(nodeOrSelector) {
}
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector
* Highlight a node and set the inspector's current selection to the node or
* the first match of the given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason Defaults to "test" which instructs the inspector not to highlight the node upon selection
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectAndHighlightNode(nodeOrSelector, inspector) {
info("Highlighting and selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.toolbox.once("highlighter-ready");
inspector.selection.setNode(node, "test-highlight");
return updated;
}
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not to highlight the
* node upon selection
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectNode(nodeOrSelector, inspector, reason="test") {
info("Selecting the node for '" + nodeOrSelector + "'");
info("Selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.once("inspector-updated");
inspector.selection.setNode(node, reason);

View File

@ -22,10 +22,10 @@ function test() {
loadTab(URL, function onTabLoad(tab, browser) {
DebuggerServer.init(function () true);
DebuggerServer.addBrowserActors();
is(DebuggerServer._socketConnections, 0);
is(DebuggerServer.listeningSockets, 0);
DebuggerServer.openListener(2929);
is(DebuggerServer._socketConnections, 1);
is(DebuggerServer.listeningSockets, 1);
let transport = debuggerSocketConnect("127.0.0.1", 2929);
let client = new DebuggerClient(transport);
@ -52,4 +52,4 @@ function test() {
});
});
});
}
}

View File

@ -128,19 +128,40 @@ function getNode(nodeOrSelector) {
nodeOrSelector;
}
/**
* Highlight a node and set the inspector's current selection to the node or
* the first match of the given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectAndHighlightNode(nodeOrSelector, inspector) {
info("Highlighting and selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.toolbox.once("highlighter-ready");
inspector.selection.setNode(node, "test-highlight");
return updated;
}
/**
* Set the inspector's current selection to a node or to the first match of the
* given css selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @param {String} reason Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @param {String} reason Defaults to "test" which instructs the inspector not to highlight the node upon selection
* given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not to highlight the
* node upon selection
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectNode(nodeOrSelector, inspector, reason="test") {
info("Selecting the node " + nodeOrSelector);
let node = getNode(nodeOrSelector);
let updated = inspector.once("inspector-updated");
inspector.selection.setNode(node, reason);

View File

@ -179,6 +179,10 @@ public class TabsPanel extends LinearLayout
}
public void showMenu() {
if (mCurrentPanel == Panel.REMOTE_TABS) {
return;
}
final Menu menu = mPopupMenu.getMenu();
// Each panel has a "+" shortcut button, so don't show it for that panel.

View File

@ -22,7 +22,7 @@ add_test(function() {
let DebuggerServer = window.DebuggerServer;
do_check_true(DebuggerServer.initialized);
do_check_true(!!DebuggerServer._listener);
do_check_eq(DebuggerServer.listeningSockets, 1);
run_next_test();
});

View File

@ -1523,8 +1523,9 @@ var BrowserApp = {
let url = data.url;
let flags;
if (/^[0-9]+$/.test(url)) {
// If the query is a number, force a search (see bug 993705; workaround for bug 693808).
if (!data.engine && /^[0-9]+$/.test(url)) {
// If the query is a number and we're not using a search engine,
// force a search (see bug 993705; workaround for bug 693808).
url = URIFixup.keywordToURI(url).spec;
} else {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
@ -3163,6 +3164,7 @@ Tab.prototype = {
this.browser.addEventListener("DOMContentLoaded", this, true);
this.browser.addEventListener("DOMFormHasPassword", this, true);
this.browser.addEventListener("DOMLinkAdded", this, true);
this.browser.addEventListener("DOMLinkChanged", this, true);
this.browser.addEventListener("DOMTitleChanged", this, true);
this.browser.addEventListener("DOMWindowClose", this, true);
this.browser.addEventListener("DOMWillOpenModalDialog", this, true);
@ -3335,6 +3337,7 @@ Tab.prototype = {
this.browser.removeEventListener("DOMContentLoaded", this, true);
this.browser.removeEventListener("DOMFormHasPassword", this, true);
this.browser.removeEventListener("DOMLinkAdded", this, true);
this.browser.removeEventListener("DOMLinkChanged", this, true);
this.browser.removeEventListener("DOMTitleChanged", this, true);
this.browser.removeEventListener("DOMWindowClose", this, true);
this.browser.removeEventListener("DOMWillOpenModalDialog", this, true);
@ -3748,7 +3751,8 @@ Tab.prototype = {
break;
}
case "DOMLinkAdded": {
case "DOMLinkAdded":
case "DOMLinkChanged": {
let target = aEvent.originalTarget;
if (!target.href || target.disabled)
return;
@ -3797,7 +3801,7 @@ Tab.prototype = {
size: maxSize
};
sendMessageToJava(json);
} else if (list.indexOf("[alternate]") != -1) {
} else if (list.indexOf("[alternate]") != -1 && aEvent.type == "DOMLinkAdded") {
let type = target.type.toLowerCase().replace(/^\s+|\s*(?:;.*)?$/g, "");
let isFeed = (type == "application/rss+xml" || type == "application/atom+xml");
@ -3818,7 +3822,7 @@ Tab.prototype = {
};
sendMessageToJava(json);
} catch (e) {}
} else if (list.indexOf("[search]" != -1)) {
} else if (list.indexOf("[search]" != -1) && aEvent.type == "DOMLinkAdded") {
let type = target.type && target.type.toLowerCase();
// Replace all starting or trailing spaces or spaces before "*;" globally w/ "".
@ -7215,7 +7219,7 @@ var RemoteDebugger = {
},
_stop: function rd_start() {
DebuggerServer.closeListener();
DebuggerServer.closeAllListeners();
dump("Remote debugger stopped");
}
};

View File

@ -15,9 +15,10 @@ package org.mozilla.search;
* https://github.com/ericedens/FirefoxSearch/issues/3
*/
public class Constants {
public static final String AUTO_COMPLETE_FRAGMENT = "org.mozilla.search.AUTO_COMPLETE_FRAGMENT";
public static final String CARD_STREAM_FRAGMENT = "org.mozilla.search.CARD_STREAM_FRAGMENT";
public static final String GECKO_VIEW_FRAGMENT = "org.mozilla.search.GECKO_VIEW_FRAGMENT";
public static final String POSTSEARCH_FRAGMENT = "org.mozilla.search.POSTSEARCH_FRAGMENT";
public static final String PRESEARCH_FRAGMENT = "org.mozilla.search.PRESEARCH_FRAGMENT";
public static final String SEARCH_FRAGMENT = "org.mozilla.search.SEARCH_FRAGMENT";
public static final String AUTOCOMPLETE_ROW_LIMIT = "5";
}

View File

@ -7,13 +7,9 @@ package org.mozilla.search;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import org.mozilla.search.autocomplete.AcceptsSearchQuery;
import org.mozilla.search.autocomplete.AutoCompleteFragment;
import org.mozilla.search.stream.CardStreamFragment;
/**
* The main entrance for the Android search intent.
@ -23,81 +19,52 @@ import org.mozilla.search.stream.CardStreamFragment;
* now, the only message passing occurs when a user wants to submit a search query. That
* passes through the onSearch method here.
*/
public class MainActivity extends FragmentActivity implements AcceptsSearchQuery,
FragmentManager.OnBackStackChangedListener {
public class MainActivity extends FragmentActivity implements AcceptsSearchQuery {
private DetailActivity detailActivity;
enum State {
START,
PRESEARCH,
POSTSEARCH
}
private State state = State.START;
@Override
protected void onCreate(Bundle stateBundle) {
super.onCreate(stateBundle);
// Sets the content view for the Activity
setContentView(R.layout.search_activity_main);
// Gets an instance of the support library FragmentManager
FragmentManager localFragmentManager = getSupportFragmentManager();
// If the incoming state of the Activity is null, sets the initial view to be thumbnails
if (null == stateBundle) {
// Starts a Fragment transaction to track the stack
FragmentTransaction localFragmentTransaction = localFragmentManager.beginTransaction();
localFragmentTransaction.add(R.id.header_fragments, new AutoCompleteFragment(),
Constants.AUTO_COMPLETE_FRAGMENT);
localFragmentTransaction.add(R.id.presearch_fragments, new CardStreamFragment(),
Constants.CARD_STREAM_FRAGMENT);
// Commits this transaction to display the Fragment
localFragmentTransaction.commit();
// The incoming state of the Activity isn't null.
}
}
@Override
protected void onStart() {
super.onStart();
if (null == detailActivity) {
detailActivity = new DetailActivity();
}
if (null == getSupportFragmentManager().findFragmentByTag(Constants.GECKO_VIEW_FRAGMENT)) {
FragmentTransaction txn = getSupportFragmentManager().beginTransaction();
txn.add(R.id.gecko_fragments, detailActivity, Constants.GECKO_VIEW_FRAGMENT);
txn.hide(detailActivity);
txn.commit();
}
startPresearch();
}
@Override
public void onSearch(String s) {
FragmentManager localFragmentManager = getSupportFragmentManager();
FragmentTransaction localFragmentTransaction = localFragmentManager.beginTransaction();
localFragmentTransaction
.hide(localFragmentManager.findFragmentByTag(Constants.CARD_STREAM_FRAGMENT))
.addToBackStack(null);
localFragmentTransaction
.show(localFragmentManager.findFragmentByTag(Constants.GECKO_VIEW_FRAGMENT))
.addToBackStack(null);
localFragmentTransaction.commit();
((DetailActivity) getSupportFragmentManager()
.findFragmentByTag(Constants.GECKO_VIEW_FRAGMENT))
startPostsearch();
((PostSearchFragment) getSupportFragmentManager().findFragmentById(R.id.gecko))
.setUrl("https://search.yahoo.com/search?p=" + Uri.encode(s));
}
@Override
public void onBackStackChanged() {
private void startPresearch() {
if (state != State.PRESEARCH) {
state = State.PRESEARCH;
findViewById(R.id.gecko).setVisibility(View.INVISIBLE);
findViewById(R.id.presearch).setVisibility(View.VISIBLE);
}
}
private void startPostsearch() {
if (state != State.POSTSEARCH) {
state = State.POSTSEARCH;
findViewById(R.id.presearch).setVisibility(View.INVISIBLE);
findViewById(R.id.gecko).setVisibility(View.VISIBLE);
}
}
@Override
public void onBackPressed() {
if (state == State.POSTSEARCH) {
startPresearch();
} else {
super.onBackPressed();
}
}
}

View File

@ -18,15 +18,15 @@ import org.mozilla.gecko.GeckoViewChrome;
import org.mozilla.gecko.GeckoViewContent;
import org.mozilla.gecko.PrefsHelper;
public class DetailActivity extends Fragment {
public class PostSearchFragment extends Fragment {
private static final String LOGTAG = "DetailActivity";
private static final String LOGTAG = "PostSearchFragment";
private GeckoView geckoView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle savedInstanceState) {
View mainView = inflater.inflate(R.layout.search_activity_detail, container, false);

View File

@ -2,14 +2,14 @@
* 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/. */
package org.mozilla.search.stream;
package org.mozilla.search;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import org.mozilla.search.R;
import org.mozilla.search.stream.PreloadAgent;
/**
@ -17,7 +17,7 @@ import org.mozilla.search.R;
* we only use this during pre-search, but we could also use it
* during post-search at some point.
*/
public class CardStreamFragment extends ListFragment {
public class PreSearchFragment extends ListFragment {
private ArrayAdapter<PreloadAgent.TmpItem> adapter;
@ -25,7 +25,7 @@ public class CardStreamFragment extends ListFragment {
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public CardStreamFragment() {
public PreSearchFragment() {
}
@Override

View File

@ -33,7 +33,7 @@ import org.mozilla.search.R;
* TODO: Add clear button to search input
* TODO: Add more search providers (other than the dictionary)
*/
public class AutoCompleteFragment extends Fragment implements AdapterView.OnItemClickListener,
public class SearchFragment extends Fragment implements AdapterView.OnItemClickListener,
TextView.OnEditorActionListener, AcceptsJumpTaps {
private View mainView;
@ -50,13 +50,13 @@ public class AutoCompleteFragment extends Fragment implements AdapterView.OnItem
RUNNING // The user is in search mode.
}
public AutoCompleteFragment() {
public SearchFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle savedInstanceState) {
mainView = inflater.inflate(R.layout.search_auto_complete, container, false);

View File

@ -12,10 +12,10 @@ import java.util.Map;
/**
* A temporary agent for loading cards into the pre-load card stream.
* <p/>
* When we have more agents, we'll want to put an agent manager between the CardStreamFragment
* When we have more agents, we'll want to put an agent manager between the PreSearchFragment
* and the set of all agents. See autocomplete.AutoCompleteFragmentManager.
*/
class PreloadAgent {
public class PreloadAgent {
public static final List<TmpItem> ITEMS = new ArrayList<TmpItem>();

View File

@ -10,7 +10,7 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="org.mozilla.search.DetailActivity">
tools:context="org.mozilla.search.PostSearchFragment">
<org.mozilla.gecko.GeckoView
android:id="@+id/gecko_view"

View File

@ -10,26 +10,25 @@
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/gecko_fragments"
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="45dp"
android:name="org.mozilla.search.PostSearchFragment"
android:id="@+id/gecko"
/>
<FrameLayout
android:id="@+id/presearch_fragments"
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.mozilla.search.PreSearchFragment"
android:id="@+id/presearch"
/>
<FrameLayout
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.mozilla.search.autocomplete.SearchFragment"
android:id="@+id/header_fragments"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</merge>
</merge>

View File

@ -9,13 +9,13 @@ search_activity_sources = [
'java/org/mozilla/search/autocomplete/AcceptsSearchQuery.java',
'java/org/mozilla/search/autocomplete/AutoCompleteAdapter.java',
'java/org/mozilla/search/autocomplete/AutoCompleteAgentManager.java',
'java/org/mozilla/search/autocomplete/AutoCompleteFragment.java',
'java/org/mozilla/search/autocomplete/AutoCompleteModel.java',
'java/org/mozilla/search/autocomplete/AutoCompleteRowView.java',
'java/org/mozilla/search/autocomplete/AutoCompleteWordListAgent.java',
'java/org/mozilla/search/autocomplete/SearchFragment.java',
'java/org/mozilla/search/Constants.java',
'java/org/mozilla/search/DetailActivity.java',
'java/org/mozilla/search/MainActivity.java',
'java/org/mozilla/search/stream/CardStreamFragment.java',
'java/org/mozilla/search/PostSearchFragment.java',
'java/org/mozilla/search/PreSearchFragment.java',
'java/org/mozilla/search/stream/PreloadAgent.java',
]

View File

@ -10,7 +10,7 @@ interface nsIDNSRecord;
/**
* nsIDNSListener
*/
[scriptable, uuid(41466a9f-f027-487d-a96c-af39e629b8d2)]
[scriptable, function, uuid(27d49bfe-280c-49e0-bbaa-f6200c232c3d)]
interface nsIDNSListener : nsISupports
{
/**

View File

@ -30,13 +30,21 @@ exports.items = [
name: "csscoverage start",
hidden: true,
description: l10n.lookup("csscoverageStartDesc2"),
params: [
{
name: "noreload",
type: "boolean",
description: l10n.lookup("csscoverageStartNoReloadDesc"),
manual: l10n.lookup("csscoverageStartNoReloadManual")
}
],
exec: function*(args, context) {
let usage = yield csscoverage.getUsage(context.environment.target);
if (usage == null) {
throw new Error(l10n.lookup("csscoverageNoRemoteError"));
}
yield usage.start(context.environment.chromeWindow,
context.environment.target);
context.environment.target, args.noreload);
}
},
{

View File

@ -108,12 +108,17 @@ let CSSUsageActor = protocol.ActorClass({
/**
* Begin recording usage data
* @param noreload It's best if we start by reloading the current page
* because that starts the test at a known point, but there could be reasons
* why we don't want to do that (e.g. the page contains state that will be
* lost across a reload)
*/
start: method(function() {
start: method(function(noreload) {
if (this._running) {
throw new Error(l10n.lookup("csscoverageRunningError"));
}
this._isOneShot = false;
this._visitedPages = new Set();
this._knownRules = new Map();
this._running = true;
@ -143,10 +148,18 @@ let CSSUsageActor = protocol.ActorClass({
.getInterface(Ci.nsIWebProgress);
this._progress.addProgressListener(this._progressListener, this._notifyOn);
this._populateKnownRules(this._tabActor.window.document);
this._updateUsage(this._tabActor.window.document, false);
if (noreload) {
// If we're not starting by reloading the page, then pretend that onload
// has just happened.
this._onTabLoad(this._tabActor.window.document);
}
else {
this._tabActor.window.location.reload();
}
events.emit(this, "state-change", { isRunning: true });
}, {
request: { url: Arg(0, "boolean") }
}),
/**
@ -180,6 +193,7 @@ let CSSUsageActor = protocol.ActorClass({
throw new Error(l10n.lookup("csscoverageRunningError"));
}
this._isOneShot = true;
this._visitedPages = new Set();
this._knownRules = new Map();
@ -392,6 +406,10 @@ let CSSUsageActor = protocol.ActorClass({
throw new Error(l10n.lookup("csscoverageNotRunError"));
}
if (this._isOneShot) {
throw new Error(l10n.lookup("csscoverageOneShotReportError"));
}
// Helper function to create a JSONable data structure representing a rule
const ruleToRuleReport = function(rule, ruleData) {
return {
@ -777,11 +795,11 @@ const CSSUsageFront = protocol.FrontClass(CSSUsageActor, {
/**
* Server-side start is above. Client-side start adds a notification box
*/
start: custom(function(newChromeWindow, newTarget) {
start: custom(function(newChromeWindow, newTarget, noreload=false) {
target = newTarget;
chromeWindow = newChromeWindow;
return this._start();
return this._start(noreload);
}, {
impl: "_start"
}),

View File

@ -162,11 +162,9 @@ function ModuleAPI() {
* Public API
*/
var DebuggerServer = {
_listener: null,
_listeners: [],
_initialized: false,
_transportInitialized: false,
// Number of currently open TCP connections.
_socketConnections: 0,
// Map of global actor names to actor constructors provided by extensions.
globalActorFactories: {},
// Map of tab actor names to actor constructors provided by extensions.
@ -212,7 +210,7 @@ var DebuggerServer = {
return true;
}
if (result == 2) {
DebuggerServer.closeListener(true);
DebuggerServer.closeAllListeners();
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", false);
}
return false;
@ -282,7 +280,7 @@ var DebuggerServer = {
}
gRegisteredModules = {};
this.closeListener();
this.closeAllListeners();
this.globalActorFactories = {};
this.tabActorFactories = {};
this._allowConnection = null;
@ -436,71 +434,62 @@ var DebuggerServer = {
return all(promises);
},
/**
* Listens on the given port or socket file for remote debugger connections.
*
* @param aPortOrPath int, string
* If given an integer, the port to listen on.
* Otherwise, the path to the unix socket domain file to listen on.
*/
openListener: function DS_openListener(aPortOrPath) {
if (!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")) {
return false;
}
this._checkInit();
get listeningSockets() {
return this._listeners.length;
},
// Return early if the server is already listening.
if (this._listener) {
return true;
}
let flags = Ci.nsIServerSocket.KeepWhenOffline;
// A preference setting can force binding on the loopback interface.
if (Services.prefs.getBoolPref("devtools.debugger.force-local")) {
flags |= Ci.nsIServerSocket.LoopbackOnly;
}
try {
let backlog = 4;
let socket;
let port = Number(aPortOrPath);
if (port) {
socket = new ServerSocket(port, flags, backlog);
} else {
let file = nsFile(aPortOrPath);
if (file.exists())
file.remove(false);
socket = new UnixDomainServerSocket(file, parseInt("666", 8), backlog);
}
socket.asyncListen(this);
this._listener = socket;
} catch (e) {
dumpn("Could not start debugging listener on '" + aPortOrPath + "': " + e);
throw Cr.NS_ERROR_NOT_AVAILABLE;
}
this._socketConnections++;
return true;
// TODO: Bug 1033079: Remove after cleaning up Gaia test:
// https://github.com/mozilla-b2g/gaia/blob/1ba15ce1ae7254badd25fd276556c1b4f36c0a45/tests/integration/devtools/server_test.js#L31
get _listener() {
return this.listeningSockets;
},
/**
* Close a previously-opened TCP listener.
* Listens on the given port or socket file for remote debugger connections.
*
* @param aForce boolean [optional]
* If set to true, then the socket will be closed, regardless of the
* number of open connections.
* @param portOrPath int, string
* If given an integer, the port to listen on.
* Otherwise, the path to the unix socket domain file to listen on.
* @return SocketListener
* A SocketListener instance that is already opened is returned. This
* single listener can be closed at any later time by calling |close|
* on the SocketListener. If a SocketListener could not be opened, an
* error is thrown. If remote connections are disabled, undefined is
* returned.
*/
closeListener: function DS_closeListener(aForce) {
if (!this._listener || this._socketConnections == 0) {
openListener: function(portOrPath) {
if (!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")) {
return;
}
this._checkInit();
let listener = new SocketListener(this);
listener.open(portOrPath);
this._listeners.push(listener);
return listener;
},
/**
* Remove a SocketListener instance from the server's set of active
* SocketListeners. This is called by a SocketListener after it is closed.
*/
_removeListener: function(listener) {
this._listeners = this._listeners.filter(l => l !== listener);
},
/**
* Closes and forgets all previously opened listeners.
*
* @return boolean
* Whether any listeners were actually closed.
*/
closeAllListeners: function() {
if (!this.listeningSockets) {
return false;
}
// Only close the listener when the last connection is closed, or if the
// aForce flag is passed.
if (--this._socketConnections == 0 || aForce) {
this._listener.close();
this._listener = null;
this._socketConnections = 0;
for (let listener of this._listeners) {
listener.close();
}
return true;
@ -665,25 +654,6 @@ var DebuggerServer = {
return deferred.promise;
},
// nsIServerSocketListener implementation
onSocketAccepted:
DevToolsUtils.makeInfallible(function DS_onSocketAccepted(aSocket, aTransport) {
if (Services.prefs.getBoolPref("devtools.debugger.prompt-connection") && !this._allowConnection()) {
return;
}
dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port);
let input = aTransport.openInputStream(0, 0, 0);
let output = aTransport.openOutputStream(0, 0, 0);
let transport = new DebuggerTransport(input, output);
DebuggerServer._onConnection(transport);
}, "DebuggerServer.onSocketAccepted"),
onStopListening: function DS_onStopListening(aSocket, status) {
dumpn("onStopListening, status: " + status);
},
/**
* Raises an exception if the server has not been properly initialized.
*/
@ -859,6 +829,94 @@ if (this.exports) {
exports.ActorPool = ActorPool;
}
/**
* Creates a new socket listener for remote connections to a given
* DebuggerServer. This helps contain and organize the parts of the server that
* may differ or are particular to one given listener mechanism vs. another.
*/
function SocketListener(server) {
this._server = server;
}
SocketListener.prototype = {
/**
* Listens on the given port or socket file for remote debugger connections.
*
* @param portOrPath int, string
* If given an integer, the port to listen on.
* Otherwise, the path to the unix socket domain file to listen on.
*/
open: function(portOrPath) {
let flags = Ci.nsIServerSocket.KeepWhenOffline;
// A preference setting can force binding on the loopback interface.
if (Services.prefs.getBoolPref("devtools.debugger.force-local")) {
flags |= Ci.nsIServerSocket.LoopbackOnly;
}
try {
let backlog = 4;
let port = Number(portOrPath);
if (port) {
this._socket = new ServerSocket(port, flags, backlog);
} else {
let file = nsFile(portOrPath);
if (file.exists())
file.remove(false);
this._socket = new UnixDomainServerSocket(file, parseInt("666", 8),
backlog);
}
this._socket.asyncListen(this);
} catch (e) {
dumpn("Could not start debugging listener on '" + portOrPath + "': " + e);
throw Cr.NS_ERROR_NOT_AVAILABLE;
}
},
/**
* Closes the SocketListener. Notifies the server to remove the listener from
* the set of active SocketListeners.
*/
close: function() {
this._socket.close();
this._server._removeListener(this);
this._server = null;
},
/**
* Gets the port that a TCP socket listener is listening on, or null if this
* is not a TCP socket (so there is no port).
*/
get port() {
if (!this._socket) {
return null;
}
return this._socket.port;
},
// nsIServerSocketListener implementation
onSocketAccepted:
DevToolsUtils.makeInfallible(function(aSocket, aTransport) {
if (Services.prefs.getBoolPref("devtools.debugger.prompt-connection") &&
!this._server._allowConnection()) {
return;
}
dumpn("New debugging connection on " +
aTransport.host + ":" + aTransport.port);
let input = aTransport.openInputStream(0, 0, 0);
let output = aTransport.openOutputStream(0, 0, 0);
let transport = new DebuggerTransport(input, output);
this._server._onConnection(transport);
}, "SocketListener.onSocketAccepted"),
onStopListening: function(aSocket, status) {
dumpn("onStopListening, status: " + status);
}
};
/**
* Creates a DebuggerServerConnection.
*

View File

@ -1107,7 +1107,9 @@ let Front = Class({
let deferred = this._requests.shift();
if (packet.error) {
deferred.reject(packet.error);
let message = (packet.error == "unknownError" && packet.message) ?
packet.message : packet.error;
deferred.reject(message);
} else {
deferred.resolve(packet);
}

View File

@ -11,7 +11,7 @@ function run_test()
check_except(function() {
DebuggerServer.openListener(-1);
});
check_except(DebuggerServer.closeListener);
check_except(DebuggerServer.closeAllListeners);
check_except(DebuggerServer.connectPipe);
// Allow incoming connections.
@ -22,14 +22,14 @@ function run_test()
check_except(function() {
DebuggerServer.openListener(-1);
});
check_except(DebuggerServer.closeListener);
check_except(DebuggerServer.closeAllListeners);
check_except(DebuggerServer.connectPipe);
DebuggerServer.registerModule("xpcshell-test/testactors");
// Now they should work.
DebuggerServer.openListener(-1);
DebuggerServer.closeListener();
DebuggerServer.closeAllListeners();
// Make sure we got the test's root actor all set up.
let client1 = DebuggerServer.connectPipe();

View File

@ -250,24 +250,13 @@ function writeTestTempFile(aFileName, aContent) {
}
}
function try_open_listener() {
if (DebuggerServer._listener) {
return DebuggerServer._listener.port;
}
try {
// Pick a random one between 2000 and 65000.
let port = Math.floor(Math.random() * (65000 - 2000 + 1)) + 2000;
do_check_true(DebuggerServer.openListener(port));
return port;
} catch (e) {
return try_open_listener();
}
}
/*** Transport Factories ***/
function socket_transport() {
let port = try_open_listener();
if (!DebuggerServer.listeningSockets) {
DebuggerServer.openListener(-1);
}
let port = DebuggerServer._listeners[0].port;
do_print("Debugger server port is " + port);
return debuggerSocketConnect("127.0.0.1", port);
}

View File

@ -4,7 +4,8 @@
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
let port = 2929;
let gPort;
let gExtraListener;
function run_test()
{
@ -18,27 +19,20 @@ function run_test()
run_next_test();
}
function really_long() {
let ret = "0123456789";
for (let i = 0; i < 18; i++) {
ret += ret;
}
return ret;
}
function test_socket_conn()
{
do_check_eq(DebuggerServer._socketConnections, 0);
try_open_listener();
do_print("Debugger server port is " + port);
do_check_eq(DebuggerServer._socketConnections, 1);
// Make sure opening the listener twice does nothing.
do_check_true(DebuggerServer.openListener(port));
do_check_eq(DebuggerServer._socketConnections, 1);
do_check_eq(DebuggerServer.listeningSockets, 0);
do_check_true(DebuggerServer.openListener(-1));
do_check_eq(DebuggerServer.listeningSockets, 1);
gPort = DebuggerServer._listeners[0].port;
do_print("Debugger server port is " + gPort);
// Open a second, separate listener
gExtraListener = DebuggerServer.openListener(-1);
do_check_eq(DebuggerServer.listeningSockets, 2);
do_print("Starting long and unicode tests at " + new Date().toTimeString());
let unicodeString = "(╯°□°)╯︵ ┻━┻";
let transport = debuggerSocketConnect("127.0.0.1", port);
let transport = debuggerSocketConnect("127.0.0.1", gPort);
transport.hooks = {
onPacket: function(aPacket) {
this.onPacket = function(aPacket) {
@ -62,15 +56,17 @@ function test_socket_conn()
function test_socket_shutdown()
{
do_check_eq(DebuggerServer._socketConnections, 1);
do_check_true(DebuggerServer.closeListener());
do_check_eq(DebuggerServer._socketConnections, 0);
do_check_eq(DebuggerServer.listeningSockets, 2);
gExtraListener.close();
do_check_eq(DebuggerServer.listeningSockets, 1);
do_check_true(DebuggerServer.closeAllListeners());
do_check_eq(DebuggerServer.listeningSockets, 0);
// Make sure closing the listener twice does nothing.
do_check_false(DebuggerServer.closeListener());
do_check_eq(DebuggerServer._socketConnections, 0);
do_check_false(DebuggerServer.closeAllListeners());
do_check_eq(DebuggerServer.listeningSockets, 0);
do_print("Connecting to a server socket at " + new Date().toTimeString());
let transport = debuggerSocketConnect("127.0.0.1", port);
let transport = debuggerSocketConnect("127.0.0.1", gPort);
transport.hooks = {
onPacket: function(aPacket) {
// Shouldn't reach this, should never connect.
@ -106,14 +102,3 @@ function test_pipe_conn()
transport.ready();
}
function try_open_listener()
{
try {
do_check_true(DebuggerServer.openListener(port));
} catch (e) {
// In case the port is unavailable, pick a random one between 2000 and 65000.
port = Math.floor(Math.random() * (65000 - 2000 + 1)) + 2000;
try_open_listener();
}
}

View File

@ -13,8 +13,6 @@ Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
const { RawPacket } = devtools.require("devtools/toolkit/transport/packets");
let port = 2929;
function run_test() {
do_print("Starting test at " + new Date().toTimeString());
initTestDebuggerServer();
@ -49,15 +47,15 @@ function test_socket_conn_drops_after_too_long_header() {
}
function test_helper(payload) {
try_open_listener();
let listener = DebuggerServer.openListener(-1);
let transport = debuggerSocketConnect("127.0.0.1", port);
let transport = debuggerSocketConnect("127.0.0.1", listener.port);
transport.hooks = {
onPacket: function(aPacket) {
this.onPacket = function(aPacket) {
do_throw(new Error("This connection should be dropped."));
transport.close();
}
};
// Inject the payload directly into the stream.
transport._outgoing.push(new RawPacket(transport, payload));
@ -70,13 +68,3 @@ function test_helper(payload) {
};
transport.ready();
}
function try_open_listener() {
try {
do_check_true(DebuggerServer.openListener(port));
} catch (e) {
// In case the port is unavailable, pick a random one between 2000 and 65000.
port = Math.floor(Math.random() * (65000 - 2000 + 1)) + 2000;
try_open_listener();
}
}

View File

@ -14,6 +14,8 @@ csscoverageStopDesc2=Stop collecting CSS coverage data
csscoverageOneShotDesc2=Collect instantaneous CSS coverage data
csscoverageToggleDesc2=Toggle collecting CSS coverage data
csscoverageReportDesc2=Show CSS coverage report
csscoverageStartNoReloadDesc=Don't start with a page reload
csscoverageStartNoReloadManual=It's best if we start by reloading the current page because that starts the test at a known point, but there could be reasons why we don't want to do that (e.g. the page contains state that will be lost across a reload)
# LOCALIZATION NOTE (csscoverageRunningReply, csscoverageDoneReply): Text that
# describes the current state of the css coverage system
@ -27,3 +29,4 @@ csscoverageRunningError=CSS coverage analysis already running
csscoverageNotRunningError=CSS coverage analysis not running
csscoverageNotRunError=CSS coverage analysis has not been run
csscoverageNoRemoteError=Target does not support CSS Coverage
csscoverageOneShotReportError=CSS coverage report is not available for 'oneshot' data. Please use start/stop.

View File

@ -19,6 +19,7 @@ extensions = [
'sphinx.ext.graphviz',
'sphinx.ext.todo',
'mozbuild.sphinx',
'javasphinx',
]
templates_path = ['_templates']