Merge fx-team to m-c a=merge

This commit is contained in:
Wes Kocher 2014-10-20 17:45:14 -07:00
commit 2af9289c66
65 changed files with 460 additions and 346 deletions

View File

@ -1048,8 +1048,11 @@ if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
let win = aContainer.ownerDocument.defaultView;
for (let item of variableHeightItems) {
if (aSetHeights) {
let height = win.getComputedStyle(item, null).getPropertyValue("height");
let cs = win.getComputedStyle(item, null);
let height = cs.getPropertyValue("height");
let width = cs.getPropertyValue("width");
item.style.height = height;
item.style.width = width;
// In the main menu panel, need to set the height of the container of this
// description because otherwise the text will overflow:
if (item.id == "PanelUI-panic-mainDesc" &&
@ -1060,6 +1063,7 @@ if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
}
} else {
item.style.removeProperty("height");
item.style.removeProperty("width");
if (item.id == "PanelUI-panic-mainDesc") {
item.parentNode.style.removeProperty("min-height");
}

View File

@ -400,9 +400,12 @@ loop.conversation = (function(mozL10n) {
return;
}
if (progressData.reason === "timeout" &&
(previousState === "init" || previousState === "alerting")) {
this._abortIncomingCall();
if (progressData.reason === "timeout") {
if (previousState === "init" || previousState === "alerting") {
this._abortIncomingCall();
} else {
this.setState({callFailed: true, callStatus: "end"});
}
}
},

View File

@ -400,9 +400,12 @@ loop.conversation = (function(mozL10n) {
return;
}
if (progressData.reason === "timeout" &&
(previousState === "init" || previousState === "alerting")) {
this._abortIncomingCall();
if (progressData.reason === "timeout") {
if (previousState === "init" || previousState === "alerting") {
this._abortIncomingCall();
} else {
this.setState({callFailed: true, callStatus: "end"});
}
}
},

View File

@ -833,7 +833,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
* Handles ending a call by resetting the view to the start state.
*/
_endCall: function() {
this.setState({callStatus: "end"});
if (this.state.callStatus !== "failure") {
this.setState({callStatus: "end"});
}
},
});

View File

@ -833,7 +833,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
* Handles ending a call by resetting the view to the start state.
*/
_endCall: function() {
this.setState({callStatus: "end"});
if (this.state.callStatus !== "failure") {
this.setState({callStatus: "end"});
}
},
});

View File

@ -39,7 +39,7 @@ describe("loop.conversation", function() {
return "en-US";
},
setLoopCharPref: sinon.stub(),
getLoopCharPref: sinon.stub().returns(null),
getLoopCharPref: sinon.stub().returns("http://fakeurl"),
getLoopBoolPref: sinon.stub(),
getCallData: sinon.stub(),
releaseCallData: sinon.stub(),
@ -410,6 +410,8 @@ describe("loop.conversation", function() {
describe("WebSocket Events", function() {
describe("Call cancelled or timed out before acceptance", function() {
beforeEach(function() {
// Mounting the test component automatically calls the required
// setup functions
icView = mountTestComponent();
promise = new Promise(function(resolve, reject) {
resolve();
@ -539,6 +541,22 @@ describe("loop.conversation", function() {
});
});
});
describe("progress - terminated - timeout (previousState not init" +
" nor alerting)",
function() {
it("should set the state to end", function(done) {
promise.then(function() {
icView._websocket.trigger("progress", {
state: "terminated",
reason: "timeout"
}, "connecting");
expect(icView.state.callStatus).eql("end");
done();
});
});
});
});
});
});

View File

@ -308,12 +308,24 @@ describe("loop.webapp", function() {
});
describe("session:ended", function() {
it("should set display the StartConversationView", function() {
it("should display the StartConversationView", function() {
conversation.trigger("session:ended");
TestUtils.findRenderedComponentWithType(ocView,
loop.webapp.EndedConversationView);
});
it("should display the FailedConversationView if callStatus is failure",
function() {
ocView.setState({
callStatus: "failure"
});
conversation.trigger("session:ended");
var failedView = TestUtils.findRenderedComponentWithType(ocView,
loop.webapp.FailedConversationView);
expect(failedView).to.not.equal(null);
});
});
describe("session:peer-hungup", function() {

View File

@ -106,6 +106,10 @@ InspectorPanel.prototype = {
return this._target.client.traits.urlToImageDataResolver;
},
get canGetUniqueSelector() {
return this._target.client.traits.getUniqueSelector;
},
_deferredOpen: function(defaultSelection) {
let deferred = promise.defer();
@ -624,6 +628,9 @@ InspectorPanel.prototype = {
copyInnerHTML.setAttribute("disabled", "true");
copyOuterHTML.setAttribute("disabled", "true");
}
if (!this.canGetUniqueSelector) {
unique.hidden = true;
}
// Enable the "edit HTML" item if the selection is an element and the root
// actor has the appropriate trait (isOuterHTMLEditable)
@ -842,10 +849,9 @@ InspectorPanel.prototype = {
return;
}
let toCopy = CssLogic.findCssSelector(this.selection.node);
if (toCopy) {
clipboardHelper.copyString(toCopy);
}
this.selection.nodeFront.getUniqueSelector().then((selector) => {
clipboardHelper.copyString(selector);
}).then(null, console.error);
},
/**

View File

@ -7,8 +7,6 @@ support-files =
doc_buffer-and-array.html
doc_media-node-creation.html
doc_destroy-nodes.html
doc_connect-toggle.html
doc_connect-toggle-param.html
doc_connect-param.html
doc_connect-multi-param.html
doc_iframe-context.html

View File

@ -6,7 +6,7 @@
*/
function spawnTest() {
let { target, panel } = yield initWebAudioEditor(CONNECT_TOGGLE_URL);
let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
let { panelWin } = panel;
let { gFront, $, $$, EVENTS } = panelWin;
@ -17,15 +17,18 @@ function spawnTest() {
waitForGraphRendered(panelWin, 3, 2)
]);
let nodeIDs = actors.map(actor => actor.actorID);
let [dest, osc, gain] = actors;
yield clickGraphNode(panelWin, nodeIDs[1]);
ok(findGraphNode(panelWin, nodeIDs[1]).classList.contains("selected"),
yield clickGraphNode(panelWin, gain.actorID);
ok(findGraphNode(panelWin, gain.actorID).classList.contains("selected"),
"Node selected once.");
// Disconnect a node to trigger a rerender
osc.disconnect();
yield once(panelWin, EVENTS.UI_GRAPH_RENDERED);
ok(findGraphNode(panelWin, nodeIDs[1]).classList.contains("selected"),
ok(findGraphNode(panelWin, gain.actorID).classList.contains("selected"),
"Node still selected after rerender.");
yield teardown(panel);

View File

@ -6,7 +6,7 @@
*/
function spawnTest() {
let { target, panel } = yield initWebAudioEditor(CONNECT_TOGGLE_PARAM_URL);
let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
let { panelWin } = panel;
let { gFront, $, $$, EVENTS } = panelWin;
@ -14,10 +14,14 @@ function spawnTest() {
let [actors] = yield Promise.all([
getN(gFront, "create-node", 3),
waitForGraphRendered(panelWin, 3, 1, 0)
waitForGraphRendered(panelWin, 3, 2, 0)
]);
ok(true, "Graph rendered without param connection");
let [dest, osc, gain] = actors;
yield osc.disconnect();
osc.connectParam(gain, "gain");
yield waitForGraphRendered(panelWin, 3, 1, 1);
ok(true, "Graph re-rendered upon param connection");

View File

@ -1,27 +0,0 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Web Audio Editor test page</title>
</head>
<body>
<script type="text/javascript;version=1.8">
"use strict";
let i = 0;
let ctx = new AudioContext();
let osc = ctx.createOscillator();
let gain = ctx.createGain();
gain.gain.value = 0;
gain.connect(ctx.destination);
osc.start(0);
setTimeout(() => osc.connect(gain.gain), 500);
</script>
</body>
</html>

View File

@ -1,27 +0,0 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Web Audio Editor test page</title>
</head>
<body>
<script type="text/javascript;version=1.8">
"use strict";
let i = 0;
let ctx = new AudioContext();
let osc = ctx.createOscillator();
let gain = ctx.createGain();
gain.gain.value = 0;
gain.connect(ctx.destination);
osc.start(0);
setInterval(() => ++i && (i % 2 ? osc.connect(gain) : osc.disconnect()), 1000);
</script>
</body>
</html>

View File

@ -27,8 +27,6 @@ const SIMPLE_NODES_URL = EXAMPLE_URL + "doc_simple-node-creation.html";
const MEDIA_NODES_URL = EXAMPLE_URL + "doc_media-node-creation.html";
const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html";
const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html";
const CONNECT_TOGGLE_PARAM_URL = EXAMPLE_URL + "doc_connect-toggle-param.html";
const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
const CONNECT_MULTI_PARAM_URL = EXAMPLE_URL + "doc_connect-multi-param.html";
const IFRAME_CONTEXT_URL = EXAMPLE_URL + "doc_iframe-context.html";

View File

@ -2454,14 +2454,14 @@ Widgets.ObjectRenderers.add({
let anchorText = this.objectActor.class;
let anchorClass = "cm-variable";
if ("timestamp" in preview && typeof preview.timestamp != "number") {
if (preview && "timestamp" in preview && typeof preview.timestamp != "number") {
anchorText = new Date(preview.timestamp).toString(); // invalid date
anchorClass = "";
}
this._anchor(anchorText, { className: anchorClass });
if (!("timestamp" in preview) || typeof preview.timestamp != "number") {
if (!preview || !("timestamp" in preview) || typeof preview.timestamp != "number") {
return;
}

View File

@ -61,13 +61,22 @@ let inputTests = [
},
// 7
{
input: "Date.prototype",
output: "Date",
printOutput: "Invalid Date",
inspectable: true,
variablesViewLabel: "Date",
},
// 8
{
input: "new Number(43)",
output: "43",
inspectable: true,
},
// 8
// 9
{
input: "new String('hello')",
output: 'String [ "h", "e", "l", "l", "o" ]',

View File

@ -50,7 +50,7 @@ let PanelFrameInternal = {
let notificationFrameId = aOrigin ? aType + "-status-" + aOrigin : aType;
let frame = aWindow.document.getElementById(notificationFrameId);
// If the button was customized to a new location, we we'll destroy the
// If the button was customized to a new location, destroy the
// iframe and start fresh.
if (frame && frame.parentNode != aParent) {
SharedFrame.forgetGroup(frame.id);
@ -157,11 +157,6 @@ let PanelFrame = {
panel.addEventListener("popupshown", function onpopupshown() {
panel.removeEventListener("popupshown", onpopupshown);
SharedFrame.setOwner(notificationFrameId, notificationFrame);
// This attribute is needed on both the button and the
// containing toolbaritem since the buttons on OS X have
// moz-appearance:none, while their container gets
// moz-appearance:toolbarbutton due to the way that toolbar buttons
// get combined on OS X.
let initFrameShow = () => {
notificationFrame.docShell.isActive = true;
notificationFrame.docShell.isAppTab = true;
@ -169,6 +164,11 @@ let PanelFrame = {
dynamicResizer.start(panel, notificationFrame);
dispatchPanelEvent(aType + "FrameShow");
};
// This attribute is needed on both the button and the
// containing toolbaritem since the buttons on OS X have
// moz-appearance:none, while their container gets
// moz-appearance:toolbarbutton due to the way that toolbar buttons
// get combined on OS X.
anchorBtn.setAttribute("open", "true");
if (notificationFrame.contentDocument &&
notificationFrame.contentDocument.readyState == "complete") {

View File

@ -421,13 +421,17 @@ function sizeSocialPanelToContent(panel, iframe) {
let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight);
width = Math.max(computedWidth, width);
}
// add extra space the panel needs if any
width += panel.boxObject.width - iframe.boxObject.width;
height += panel.boxObject.height - iframe.boxObject.height;
// only add the extra space if the iframe has been loaded
if (iframe.boxObject.width && iframe.boxObject.height) {
// add extra space the panel needs if any
width += panel.boxObject.width - iframe.boxObject.width;
height += panel.boxObject.height - iframe.boxObject.height;
}
// when size is computed, we want to be sure changes are "significant" since
// some sites will resize when the iframe is resized by a small amount, making
// the panel slowely shrink to some minimum.
// the panel slowly shrink to some minimum.
if (Math.abs(panel.boxObject.width - width) > 2 || Math.abs(panel.boxObject.height - height) > 2) {
panel.sizeTo(width, height);
}

View File

@ -1210,12 +1210,13 @@ public class BrowserApp extends GeckoApp
// Make sure the toolbar is fully hidden or fully shown when the user
// lifts their finger. If the page is shorter than the viewport or if
// the user has reached the end of the page, the toolbar is always
// shown.
// the user has reached the end of a long (longer than twice the viewport height) page,
// the toolbar is always shown.
ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics();
final float height = metrics.viewportRectBottom - metrics.viewportRectTop;
if (metrics.getPageHeight() < metrics.getHeight()
|| metrics.marginTop >= mToolbarHeight / 2
|| metrics.pageRectBottom == metrics.viewportRectBottom) {
|| (metrics.pageRectBottom == metrics.viewportRectBottom && metrics.pageRectBottom > 2*height)) {
mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
} else {
mDynamicToolbar.setVisible(false, VisibilityTransition.ANIMATE);

View File

@ -1190,8 +1190,6 @@ public abstract class GeckoApp
Class.forName("android.os.AsyncTask");
} catch (ClassNotFoundException e) {}
MemoryMonitor.getInstance().init(getApplicationContext());
// GeckoAppShell is tightly coupled to us, rather than
// the app context, because various parts of Fennec (e.g.,
// GeckoScreenOrientation) use GAS to access the Activity in
@ -1201,13 +1199,6 @@ public abstract class GeckoApp
GeckoAppShell.setContextGetter(this);
GeckoAppShell.setGeckoInterface(this);
Tabs.getInstance().attachToContext(this);
try {
Favicons.initializeWithContext(this);
} catch (Exception e) {
Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
}
// Did the OS locale change while we were backgrounded? If so,
// we need to die so that Gecko will re-init add-ons that touch
// the UI.
@ -1254,6 +1245,20 @@ public abstract class GeckoApp
}, 1000 * 5 /* 5 seconds */);
}
// Heavy load on the Gecko thread can slow down the time it takes for UI to appear on
// single-core devices. By minimizing the Gecko thread priority, we ensure that the UI
// appears quickly. The priority is reset to normal once thumbnails are loaded.
ThreadUtils.reduceGeckoPriority();
MemoryMonitor.getInstance().init(getApplicationContext());
Tabs.getInstance().attachToContext(this);
try {
Favicons.initializeWithContext(this);
} catch (Exception e) {
Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
}
Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE);
if (stateBundle != null) {
// Use the state bundle if it was given as an intent extra. This is
@ -1630,6 +1635,10 @@ public abstract class GeckoApp
} else if (NotificationHelper.HELPER_BROADCAST_ACTION.equals(action)) {
NotificationHelper.getInstance(getApplicationContext()).handleNotificationIntent(intent);
}
// Reset Gecko to normal priority. We may reduce the
// priority again later, e.g. for loading thumbnails.
ThreadUtils.resetGeckoPriority();
}
private String restoreSessionTabs(final boolean isExternalURL) throws SessionRestoreException {

View File

@ -51,6 +51,7 @@ public class GeckoThread extends Thread implements GeckoEventListener {
if (isCreated())
return false;
sGeckoThread = new GeckoThread(sArgs, sAction, sUri);
ThreadUtils.sGeckoThread = sGeckoThread;
return true;
}
@ -164,7 +165,6 @@ public class GeckoThread extends Thread implements GeckoEventListener {
@Override
public void run() {
Looper.prepare();
ThreadUtils.sGeckoThread = this;
ThreadUtils.sGeckoHandler = new Handler();
ThreadUtils.sGeckoQueue = Looper.myQueue();

View File

@ -163,11 +163,6 @@ public class RestrictedProfiles {
@WrapElementForJNI
public static boolean isAllowed(int action, String url) {
// Guest users can't do anything.
if (getInGuest()) {
return false;
}
final Restriction restriction;
try {
restriction = geckoActionToRestriction(action);
@ -178,8 +173,13 @@ public class RestrictedProfiles {
return false;
}
if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
return canLoadUrl(url);
if (getInGuest()) {
if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
return canLoadUrl(url);
}
// Guest users can't do anything.
return false;
}
// NOTE: Restrictions hold the opposite intention, so we need to flip it.

View File

@ -98,9 +98,6 @@ public class TopSitesPanel extends HomeFragment {
// Max number of entries shown in the grid from the cursor.
private int mMaxGridEntries;
// Time in ms until the Gecko thread is reset to normal priority.
private static final long PRIORITY_RESET_TIMEOUT = 10000;
public static TopSitesPanel newInstance() {
return new TopSitesPanel();
}
@ -347,7 +344,7 @@ public class TopSitesPanel extends HomeFragment {
// appear, especially during startup (bug 897162). By minimizing the
// Gecko thread priority, we ensure that the UI appears quickly. The
// priority is reset to normal once thumbnails are loaded.
ThreadUtils.reduceGeckoPriority(PRIORITY_RESET_TIMEOUT);
ThreadUtils.reduceGeckoPriority();
}
/**

View File

@ -414,6 +414,7 @@ gbjar.sources += [
'toolbar/BrowserToolbarTabletBase.java',
'toolbar/CanvasDelegate.java',
'toolbar/ForwardButton.java',
'toolbar/NavButton.java',
'toolbar/PageActionLayout.java',
'toolbar/PhoneTabsButton.java',
'toolbar/ShapedButton.java',

View File

@ -35,7 +35,7 @@
android:paddingTop="6dip" >
<TextView
android:id="@+android:id/account_server_title"
android:id="@+id/account_server_title"
style="@style/FxAccountTextItem"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@ -46,7 +46,7 @@
</TextView>
<TextView
android:id="@+android:id/account_server_summary"
android:id="@+id/account_server_summary"
style="@style/FxAccountTextItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -88,7 +88,7 @@
android:paddingTop="6dip" >
<TextView
android:id="@+android:id/sync_server_title"
android:id="@+id/sync_server_title"
style="@style/FxAccountTextItem"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@ -99,7 +99,7 @@
</TextView>
<TextView
android:id="@+android:id/sync_server_summary"
android:id="@+id/sync_server_summary"
style="@style/FxAccountTextItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -113,4 +113,4 @@
</LinearLayout>
</LinearLayout>
</merge>
</merge>

View File

@ -110,6 +110,9 @@
<color name="url_bar_blockedtext">#b14646</color>
<color name="url_bar_shadow">#12000000</color>
<color name="nav_button_border_color">#BFBFBF</color>
<color name="nav_button_border_color_private">#5F6368</color>
<color name="home_button_bar_bg">#FFF5F7F9</color>
<!-- Colour used for share overlay button labels -->

View File

@ -14,8 +14,8 @@ public class testLinkContextMenu extends ContentContextMenuTest {
LINK_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BIG_LINK_URL);
BLANK_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
inputAndLoadUrl(LINK_PAGE_URL);
waitForText(LINK_PAGE_TITLE);
loadAndPaint(LINK_PAGE_URL);
verifyPageTitle(LINK_PAGE_TITLE, LINK_PAGE_URL);
verifyContextMenuItems(linkMenuItems); // Verify context menu items are correct
openTabFromContextMenu(linkMenuItems[0],2); // Test the "Open in New Tab" option - expecting 2 tabs: the original and the new one

View File

@ -12,8 +12,8 @@ public class testMailToContextMenu extends ContentContextMenuTest {
blockForGeckoReady();
MAILTO_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BIG_MAILTO_URL);
inputAndLoadUrl(MAILTO_PAGE_URL);
waitForText(MAILTO_PAGE_TITLE);
loadAndPaint(MAILTO_PAGE_URL);
verifyPageTitle(MAILTO_PAGE_TITLE, MAILTO_PAGE_URL);
verifyContextMenuItems(mailtoMenuItems);
verifyCopyOption(mailtoMenuItems[0], "foo.bar@example.com"); // Test the "Copy Email Address" option

View File

@ -4,44 +4,13 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.R;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
public class BackButton extends ShapedButton {
private final Path mBorderPath;
private final Paint mBorderPaint;
private final float mBorderWidth;
public class BackButton extends NavButton {
public BackButton(Context context, AttributeSet attrs) {
super(context, attrs);
mBorderWidth = getResources().getDimension(R.dimen.nav_button_border_width);
// Paint to draw the border.
mBorderPaint = new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderPaint.setStyle(Paint.Style.STROKE);
// Path is masked.
mBorderPath = new Path();
setPrivateMode(false);
}
@Override
public void setPrivateMode(boolean isPrivate) {
super.setPrivateMode(isPrivate);
mBorderPaint.setColor(isPrivate ? 0xFF363B40 : 0xFFB5B5B5);
}
@Override
@ -54,35 +23,4 @@ public class BackButton extends ShapedButton {
mBorderPath.reset();
mBorderPath.addCircle(width/2, height/2, (width/2) - (mBorderWidth/2), Path.Direction.CW);
}
@Override
public void draw(Canvas canvas) {
mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight());
// Draw the border on top.
canvas.drawPath(mBorderPath, mBorderPaint);
}
// The drawable is constructed as per @drawable/url_bar_nav_button.
@Override
public void onLightweightThemeChanged() {
final Drawable drawable = mTheme.getDrawable(this);
if (drawable == null)
return;
final StateListDrawable stateList = new StateListDrawable();
stateList.addState(PRIVATE_PRESSED_STATE_SET, getColorDrawable(R.color.highlight_nav_pb));
stateList.addState(PRESSED_ENABLED_STATE_SET, getColorDrawable(R.color.highlight_nav));
stateList.addState(PRIVATE_FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused_pb));
stateList.addState(FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused));
stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
stateList.addState(EMPTY_STATE_SET, drawable);
setBackgroundDrawable(stateList);
}
@Override
public void onLightweightThemeReset() {
setBackgroundResource(R.drawable.url_bar_nav_button);
}
}

View File

@ -4,43 +4,12 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.R;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
public class ForwardButton extends ShapedButton {
private final Path mBorderPath;
private final Paint mBorderPaint;
private final float mBorderWidth;
public class ForwardButton extends NavButton {
public ForwardButton(Context context, AttributeSet attrs) {
super(context, attrs);
mBorderWidth = getResources().getDimension(R.dimen.nav_button_border_width);
// Paint to draw the border.
mBorderPaint = new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPath = new Path();
setPrivateMode(false);
}
@Override
public void setPrivateMode(boolean isPrivate) {
super.setPrivateMode(isPrivate);
mBorderPaint.setColor(isPrivate ? 0xFF363B40 : 0xFFBFBFBF);
}
@Override
@ -51,35 +20,4 @@ public class ForwardButton extends ShapedButton {
mBorderPath.moveTo(width - mBorderWidth, 0);
mBorderPath.lineTo(width - mBorderWidth, height);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// Draw the border on top.
canvas.drawPath(mBorderPath, mBorderPaint);
}
// The drawable is constructed as per @drawable/url_bar_nav_button.
@Override
public void onLightweightThemeChanged() {
final Drawable drawable = mTheme.getDrawable(this);
if (drawable == null)
return;
final StateListDrawable stateList = new StateListDrawable();
stateList.addState(PRIVATE_PRESSED_STATE_SET, getColorDrawable(R.color.highlight_nav_pb));
stateList.addState(PRESSED_ENABLED_STATE_SET, getColorDrawable(R.color.highlight_nav));
stateList.addState(PRIVATE_FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused_pb));
stateList.addState(FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused));
stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
stateList.addState(EMPTY_STATE_SET, drawable);
setBackgroundDrawable(stateList);
}
@Override
public void onLightweightThemeReset() {
setBackgroundResource(R.drawable.url_bar_nav_button);
}
}

View File

@ -0,0 +1,82 @@
/* 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/. */
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.R;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.AttributeSet;
abstract class NavButton extends ShapedButton {
protected final Path mBorderPath;
protected final Paint mBorderPaint;
protected final float mBorderWidth;
protected final int mBorderColor;
protected final int mBorderColorPrivate;
public NavButton(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = getResources();
mBorderColor = res.getColor(R.color.nav_button_border_color);
mBorderColorPrivate = res.getColor(R.color.nav_button_border_color_private);
mBorderWidth = res.getDimension(R.dimen.nav_button_border_width);
// Paint to draw the border.
mBorderPaint = new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderPaint.setStyle(Paint.Style.STROKE);
// Path is masked.
mBorderPath = new Path();
setPrivateMode(false);
}
@Override
public void setPrivateMode(boolean isPrivate) {
super.setPrivateMode(isPrivate);
mBorderPaint.setColor(isPrivate ? mBorderColorPrivate : mBorderColor);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// Draw the border on top.
canvas.drawPath(mBorderPath, mBorderPaint);
}
// The drawable is constructed as per @drawable/url_bar_nav_button.
@Override
public void onLightweightThemeChanged() {
final Drawable drawable = mTheme.getDrawable(this);
if (drawable == null)
return;
final StateListDrawable stateList = new StateListDrawable();
stateList.addState(PRIVATE_PRESSED_STATE_SET, getColorDrawable(R.color.highlight_nav_pb));
stateList.addState(PRESSED_ENABLED_STATE_SET, getColorDrawable(R.color.highlight_nav));
stateList.addState(PRIVATE_FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused_pb));
stateList.addState(FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused));
stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
stateList.addState(EMPTY_STATE_SET, drawable);
setBackgroundDrawable(stateList);
}
@Override
public void onLightweightThemeReset() {
setBackgroundResource(R.drawable.url_bar_nav_button);
}
}

View File

@ -17,6 +17,9 @@ import android.util.Log;
public final class ThreadUtils {
private static final String LOGTAG = "ThreadUtils";
// Time in ms until the Gecko thread is reset to normal priority.
private static final long PRIORITY_RESET_TIMEOUT = 10000;
/**
* Controls the action taken when a method like
* {@link ThreadUtils#assertOnUiThread(AssertBehavior)} detects a problem.
@ -209,10 +212,8 @@ public final class ThreadUtils {
*
* Note that there are no guards in place to prevent multiple calls
* to this method from conflicting with each other.
*
* @param timeout Timeout in ms after which the priority will be reset
*/
public static void reduceGeckoPriority(long timeout) {
public static void reduceGeckoPriority() {
if (Runtime.getRuntime().availableProcessors() > 1) {
// Don't reduce priority for multicore devices. We use availableProcessors()
// for its fast performance. It may give false negatives (i.e. multicore
@ -222,7 +223,7 @@ public final class ThreadUtils {
if (!sIsGeckoPriorityReduced && sGeckoThread != null) {
sIsGeckoPriorityReduced = true;
sGeckoThread.setPriority(Thread.MIN_PRIORITY);
getUiHandler().postDelayed(sPriorityResetRunnable, timeout);
getUiHandler().postDelayed(sPriorityResetRunnable, PRIORITY_RESET_TIMEOUT);
}
}

View File

@ -86,12 +86,8 @@ if test ! "$RELEASE_BUILD"; then
MOZ_ANDROID_SHARE_OVERLAY=1
fi
# Enable the Mozilla Location Service stumbler in Nightly.
if test "$NIGHTLY_BUILD"; then
MOZ_ANDROID_MLS_STUMBLER=1
else
MOZ_ANDROID_MLS_STUMBLER=
fi
# Enable the Mozilla Location Service stumbler.
MOZ_ANDROID_MLS_STUMBLER=1
# Enable adding to the system downloads list in pre-release builds.
if test ! "$RELEASE_BUILD"; then

View File

@ -184,7 +184,6 @@ footer {
padding: 15px;
font-size: 16px;
width: 100%;
background-color: #0092DB;
border-radius: 4px;
border-width: 0;
color: #fff;
@ -195,6 +194,14 @@ footer {
text-decoration: underline;
}
.description:invalid ~ .send-feedback {
background-color: #8698A8;
}
.description:valid ~ .send-feedback {
background-color: #0092DB;
}
@media screen and (max-height: 400px) {
body {
padding-top: 40px;

View File

@ -680,7 +680,7 @@ SimpleTest.waitForFocus = function (callback, targetWindow, expectBlankPage) {
!SimpleTest.waitForFocus_started) {
SimpleTest._pendingWaitForFocusCount--;
SimpleTest.waitForFocus_started = true;
setTimeout(callback, 0, targetWindow);
SimpleTest.executeSoon(function() { callback(targetWindow) });
}
}

View File

@ -743,8 +743,8 @@ Search.prototype = {
for (let [query, params] of queries) {
let hasResult = yield conn.executeCached(query, params, this._onResultRow.bind(this));
if (this.pending && params.query_type == QUERYTYPE_AUTOFILL_URL &&
!hasResult) {
if (this.pending && this._enableActions && !hasResult &&
params.query_type == QUERYTYPE_AUTOFILL_URL) {
// If we predicted that our URL autofill query might have gotten a
// result, but it didn't, then we need to recover.
yield this._matchHeuristicFallback();

View File

@ -183,6 +183,7 @@ add_task(function* test_default_behavior_url() {
// RESTRICT TO HISTORY.
Services.prefs.setIntPref("browser.urlbar.default.behavior", 1);
Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
do_log_info("URL: Restrict history, common visit, should not autoFill");
yield check_autocomplete({

View File

@ -562,6 +562,18 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
response: {}
}),
/**
* Get a unique selector string for this node.
*/
getUniqueSelector: method(function() {
return CssLogic.findCssSelector(this.rawNode);
}, {
request: {},
response: {
value: RetVal("string")
}
}),
/**
* Get the node's image data if any (for canvas and img nodes).
* Returns an imageData object with the actual data being a LongStringActor

View File

@ -143,7 +143,9 @@ RootActor.prototype = {
selectorEditable: true,
// Whether the page style actor implements the addNewRule method that
// adds new rules to the page
addNewRule: true
addNewRule: true,
// Whether the dom node actor implements the getUniqueSelector method
getUniqueSelector: true
},
/**

View File

@ -138,20 +138,24 @@ let TimelineActor = exports.TimelineActor = protocol.ActorClass({
if (!this._isRecording) {
return;
}
if (!this.docShells.length) {
return;
}
let endTime = this.docShells[0].now();
let markers = [];
for (let docShell of this.docShells) {
markers = [...markers, ...docShell.popProfileTimelineMarkers()];
}
if (markers.length > 0) {
let endTime = this.docShells[0].now();
events.emit(this, "markers", markers, endTime);
}
if (this._memoryActor) {
events.emit(this, "memory", Date.now(), this._memoryActor.measure());
events.emit(this, "memory", endTime, this._memoryActor.measure());
}
if (this._framerateActor) {
events.emit(this, "ticks", Date.now(), this._framerateActor.getPendingTicks());
events.emit(this, "ticks", endTime, this._framerateActor.getPendingTicks());
}
this._dataPullTimeout = setTimeout(() => {

View File

@ -1,5 +1,4 @@
[DEFAULT]
skip-if = e10s # Bug ?????? - addon installation seems broken (gXPInstallObserver._findChildShell tries to directly use a content docShell)
support-files =
authRedirect.sjs
bug540558.html
@ -34,6 +33,7 @@ support-files =
[browser_auth2.js]
[browser_auth3.js]
[browser_auth4.js]
skip-if = e10s # Bug 1082871
[browser_badargs.js]
[browser_badargs2.js]
[browser_badhash.js]
@ -41,6 +41,7 @@ support-files =
[browser_bug540558.js]
[browser_bug611242.js]
[browser_bug638292.js]
skip-if = e10s # Bug 1083269
[browser_bug645699.js]
# [browser_bug672485.js]
# disabled due to a leak. See bug 682410.
@ -50,6 +51,7 @@ support-files =
[browser_cookies2.js]
[browser_cookies3.js]
[browser_cookies4.js]
skip-if = true # Bug 1084646
[browser_corrupt.js]
[browser_empty.js]
[browser_enabled.js]
@ -62,12 +64,16 @@ support-files =
[browser_httphash4.js]
[browser_httphash5.js]
[browser_httphash6.js]
skip-if = e10s # Bug 1084558
[browser_installchrome.js]
[browser_localfile.js]
skip-if = e10s # Bug 1082764
[browser_localfile2.js]
[browser_localfile3.js]
skip-if = e10s # Bug 1082764
[browser_localfile4.js]
[browser_multipackage.js]
skip-if = e10s # bug 1082764
[browser_navigateaway.js]
[browser_navigateaway2.js]
[browser_offline.js]
@ -78,16 +84,20 @@ support-files =
[browser_signed_trigger.js]
[browser_signed_untrusted.js]
[browser_signed_url.js]
skip-if = e10s # bug 1082764
[browser_softwareupdate.js]
[browser_trigger_redirect.js]
[browser_unsigned_trigger.js]
[browser_unsigned_trigger_iframe.js]
skip-if = buildapp == "mulet"
[browser_unsigned_url.js]
skip-if = e10s # bug 1082764
[browser_whitelist.js]
[browser_whitelist2.js]
[browser_whitelist3.js]
skip-if = e10s # bug 1082764
[browser_whitelist4.js]
skip-if = e10s # bug 1082764
[browser_whitelist5.js]
[browser_whitelist6.js]
[browser_whitelist7.js]

View File

@ -11,7 +11,11 @@ function test() {
// Allow the in-page load handler to run first
executeSoon(page_loaded);
}, true);
expectUncaughtException();
// In non-e10s the exception in the content page would trigger a test failure
if (!gMultiProcessBrowser)
expectUncaughtException();
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
}

View File

@ -15,7 +15,11 @@ function test() {
// Allow the in-page load handler to run first
executeSoon(page_loaded);
}, true);
expectUncaughtException();
// In non-e10s the exception in the content page would trigger a test failure
if (!gMultiProcessBrowser)
expectUncaughtException();
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
}

View File

@ -16,7 +16,11 @@ function test() {
}
function allow_blocked(installInfo) {
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
// installInfo.originator is different depending on whether we are in e10s(!)
if (gMultiProcessBrowser)
is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
else
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
return false;
}

View File

@ -7,6 +7,20 @@ let gConcurrentTabs = [];
let gQueuedForInstall = [];
let gResults = [];
function frame_script() {
addMessageListener("Test:StartInstall", () => {
content.document.getElementById("installnow").click()
});
addEventListener("load", () => {
sendAsyncMessage("Test:Loaded");
content.addEventListener("InstallComplete", (e) => {
sendAsyncMessage("Test:InstallComplete", e.detail);
}, true);
}, true);
}
let gAddonAndWindowListener = {
onOpenWindow: function(win) {
var window = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
@ -33,11 +47,25 @@ let gAddonAndWindowListener = {
function installNext() {
let tab = gQueuedForInstall.shift();
tab.linkedBrowser.contentDocument.getElementById("installnow").click();
tab.linkedBrowser.messageManager.sendAsyncMessage("Test:StartInstall");
}
function winForTab(t) {
return t.linkedBrowser.contentDocument.defaultView;
return t.linkedBrowser.contentWindow;
}
function createTab(url) {
let tab = gBrowser.addTab(url);
tab.linkedBrowser.messageManager.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
tab.linkedBrowser.messageManager.addMessageListener("Test:InstallComplete", ({data}) => {
gResults.push(data);
if (gResults.length == 2) {
executeSoon(endThisTest);
}
});
return tab;
}
function test() {
@ -63,24 +91,13 @@ function test() {
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
pm.add(makeURI("http://example.org/"), "install", pm.ALLOW_ACTION);
gConcurrentTabs.push(gBrowser.addTab(TESTROOT + "concurrent_installs.html"));
gConcurrentTabs.push(gBrowser.addTab(TESTROOT2 + "concurrent_installs.html"));
gConcurrentTabs.push(createTab(TESTROOT + "concurrent_installs.html"));
gConcurrentTabs.push(createTab(TESTROOT2 + "concurrent_installs.html"));
let promises = gConcurrentTabs.map((t) => {
let deferred = Promise.defer();
t.linkedBrowser.addEventListener("load", () => {
let win = winForTab(t);
if (win.location.host.startsWith("example")) {
win.wrappedJSObject.installTriggerCallback = function(rv) {
gResults.push(rv);
if (gResults.length == 2) {
executeSoon(endThisTest);
}
};
deferred.resolve();
}
}, true);
return deferred.promise;
return new Promise(resolve => {
t.linkedBrowser.messageManager.addMessageListener("Test:Loaded", resolve);
});
});
Promise.all(promises).then(() => {

View File

@ -10,7 +10,7 @@ function test() {
var cm = Components.classes["@mozilla.org/cookiemanager;1"]
.getService(Components.interfaces.nsICookieManager2);
cm.add("example.com", "/browser/" + RELATIVE_DIR, "xpinstall", "true", false,
cm.add("example.org", "/browser/" + RELATIVE_DIR, "xpinstall", "true", false,
false, true, (Date.now() / 1000) + 60);
var pm = Services.perms;
@ -33,7 +33,7 @@ function finish_test(count) {
is(count, 0, "No add-ons should have been installed");
var cm = Components.classes["@mozilla.org/cookiemanager;1"]
.getService(Components.interfaces.nsICookieManager2);
cm.remove("example.com", "xpinstall", "/browser/" + RELATIVE_DIR, false);
cm.remove("example.org", "xpinstall", "/browser/" + RELATIVE_DIR, false);
Services.prefs.clearUserPref("network.cookie.cookieBehavior");
Services.perms.remove("example.com", "install");

View File

@ -3,6 +3,7 @@
function test() {
Harness.downloadFailedCallback = download_failed;
Harness.installsCompletedCallback = finish_test;
Harness.finalContentEvent = "InstallComplete";
Harness.setup();
var pm = Services.perms;

View File

@ -4,15 +4,19 @@ function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
// Allow the in-page load handler to run first
executeSoon(page_loaded);
}, true);
function loadListener() {
gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
gBrowser.contentWindow.addEventListener("PageLoaded", page_loaded, false);
}
gBrowser.selectedBrowser.addEventListener("load", loadListener, true);
gBrowser.loadURI(TESTROOT + "enabled.html");
}
function page_loaded() {
gBrowser.contentWindow.removeEventListener("PageLoaded", page_loaded, false);
var doc = gBrowser.contentDocument;
is(doc.getElementById("enabled").textContent, "true", "installTrigger should have been enabled");
gBrowser.removeCurrentTab();

View File

@ -6,15 +6,18 @@ function test() {
Services.prefs.setBoolPref("xpinstall.enabled", false);
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
// Allow the in-page load handler to run first
executeSoon(page_loaded);
}, true);
function loadListener() {
gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
gBrowser.contentWindow.addEventListener("PageLoaded", page_loaded, false);
}
gBrowser.selectedBrowser.addEventListener("load", loadListener, true);
gBrowser.loadURI(TESTROOT + "enabled.html");
}
function page_loaded() {
gBrowser.contentWindow.removeEventListener("PageLoaded", page_loaded, false);
Services.prefs.clearUserPref("xpinstall.enabled");
var doc = gBrowser.contentDocument;

View File

@ -12,11 +12,13 @@ function test() {
"Unsigned XPI": TESTROOT + "unsigned.xpi"
}));
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
// Allow the in-page load handler to run first
executeSoon(page_loaded);
}, true);
function loadListener() {
gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
gBrowser.contentWindow.addEventListener("InstallTriggered", page_loaded, false);
}
gBrowser.selectedBrowser.addEventListener("load", loadListener, true);
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
}
@ -35,6 +37,7 @@ function confirm_install(window) {
}
function page_loaded() {
gBrowser.contentWindow.removeEventListener("InstallTriggered", page_loaded, false);
Services.prefs.clearUserPref("xpinstall.enabled");
var doc = gBrowser.contentDocument;

View File

@ -23,7 +23,11 @@ function test() {
// Allow the in-page load handler to run first
executeSoon(page_loaded);
}, true);
expectUncaughtException();
// In non-e10s the exception in the content page would trigger a test failure
if (!gMultiProcessBrowser)
expectUncaughtException();
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
}

View File

@ -4,6 +4,7 @@ function test() {
Harness.installConfirmCallback = confirm_install;
Harness.installEndedCallback = install_ended;
Harness.installsCompletedCallback = finish_test;
Harness.finalContentEvent = "InstallComplete";
Harness.setup();
var pm = Services.perms;

View File

@ -4,6 +4,7 @@ function test() {
Harness.installConfirmCallback = confirm_install;
Harness.installEndedCallback = install_ended;
Harness.installsCompletedCallback = finish_test;
Harness.finalContentEvent = "InstallComplete";
Harness.setup();
var pm = Services.perms;

View File

@ -5,6 +5,7 @@ function test() {
Harness.installConfirmCallback = confirm_install;
Harness.installEndedCallback = install_ended;
Harness.installsCompletedCallback = finish_test;
Harness.finalContentEvent = "InstallComplete";
Harness.setup();
var pm = Services.perms;

View File

@ -6,6 +6,7 @@ function test() {
Harness.installConfirmCallback = confirm_install;
Harness.installEndedCallback = install_ended;
Harness.installsCompletedCallback = finish_test;
Harness.finalContentEvent = "InstallComplete";
Harness.setup();
var pm = Services.perms;

View File

@ -17,7 +17,11 @@ function test() {
}
function allow_blocked(installInfo) {
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
// installInfo.originator is different depending on whether we are in e10s(!)
if (gMultiProcessBrowser)
is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
else
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
return true;
}

View File

@ -18,7 +18,11 @@ function test() {
}
function allow_blocked(installInfo) {
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
// installInfo.originator is different depending on whether we are in e10s(!)
if (gMultiProcessBrowser)
is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
else
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
return false;
}

View File

@ -17,7 +17,11 @@ function test() {
}
function allow_blocked(installInfo) {
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
// installInfo.originator is different depending on whether we are in e10s(!)
if (gMultiProcessBrowser)
is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
else
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
is(installInfo.originatingURI.spec, TESTROOT2 + "test.html", "Install should have been triggered by the right uri");
return false;
}

View File

@ -12,7 +12,11 @@ function test() {
}
function allow_blocked(installInfo) {
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
// installInfo.originator is different depending on whether we are in e10s(!)
if (gMultiProcessBrowser)
is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
else
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
return false;
}

View File

@ -12,8 +12,11 @@ function test() {
}
function allow_blocked(installInfo) {
// XXX Check this for e10s.
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
// installInfo.originator is different depending on whether we are in e10s(!)
if (gMultiProcessBrowser)
is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
else
is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
return false;
}

View File

@ -8,8 +8,11 @@
<title>Concurrent InstallTrigger tests</title>
<script type="text/javascript">
function installCallback(url, status) {
window.installTriggerCallback({loc: location.href, xpi: url});
document.getElementById("status").textContent = status;
dump("Sending InstallComplete\n");
var event = new CustomEvent("InstallComplete", {detail: {loc: location.href, xpi: url}});
window.dispatchEvent(event);
}
function startInstall() {

View File

@ -10,6 +10,9 @@
<script type="text/javascript">
function init() {
document.getElementById("enabled").textContent = InstallTrigger.enabled() ? "true" : "false";
dump("Sending PageLoaded\n");
var event = new CustomEvent("PageLoaded");
window.dispatchEvent(event);
}
</script>
</head>

View File

@ -71,7 +71,11 @@ var Harness = {
// If set will be called when all triggered items are installed or the install
// is canceled.
installsCompletedCallback: null,
// If set the harness will wait for this DOM event before calling
// installsCompletedCallback
finalContentEvent: null,
waitingForEvent: false,
pendingCount: null,
installCount: null,
runningInstalls: null,
@ -128,35 +132,30 @@ var Harness = {
},
endTest: function() {
// Defer the final notification to allow things like the InstallTrigger
// callback to complete
var self = this;
executeSoon(function() {
let callback = self.installsCompletedCallback;
let count = self.installCount;
let callback = this.installsCompletedCallback;
let count = this.installCount;
is(self.runningInstalls.length, 0, "Should be no running installs left");
self.runningInstalls.forEach(function(aInstall) {
info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
});
self.installBlockedCallback = null;
self.authenticationCallback = null;
self.installConfirmCallback = null;
self.downloadStartedCallback = null;
self.downloadProgressCallback = null;
self.downloadCancelledCallback = null;
self.downloadFailedCallback = null;
self.downloadEndedCallback = null;
self.installStartedCallback = null;
self.installFailedCallback = null;
self.installEndedCallback = null;
self.installsCompletedCallback = null;
self.runningInstalls = null;
if (callback)
callback(count);
is(this.runningInstalls.length, 0, "Should be no running installs left");
this.runningInstalls.forEach(function(aInstall) {
info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
});
this.installBlockedCallback = null;
this.authenticationCallback = null;
this.installConfirmCallback = null;
this.downloadStartedCallback = null;
this.downloadProgressCallback = null;
this.downloadCancelledCallback = null;
this.downloadFailedCallback = null;
this.downloadEndedCallback = null;
this.installStartedCallback = null;
this.installFailedCallback = null;
this.installEndedCallback = null;
this.installsCompletedCallback = null;
this.runningInstalls = null;
if (callback)
callback(count);
},
// Window open handling
@ -274,6 +273,20 @@ var Harness = {
onNewInstall: function(install) {
this.runningInstalls.push(install);
if (this.finalContentEvent && !this.waitingForEvent) {
this.waitingForEvent = true;
info("Waiting for " + this.finalContentEvent);
let win = gBrowser.contentWindow;
let listener = () => {
info("Saw " + this.finalContentEvent);
win.removeEventListener(this.finalContentEvent, listener, false);
this.waitingForEvent = false;
if (this.pendingCount == 0)
this.endTest();
}
win.addEventListener(this.finalContentEvent, listener, false);
}
},
onDownloadStarted: function(install) {
@ -327,7 +340,7 @@ var Harness = {
},
checkTestEnded: function() {
if (--this.pendingCount == 0)
if (--this.pendingCount == 0 && !this.waitingForEvent)
this.endTest();
},

View File

@ -10,16 +10,26 @@
<script type="text/javascript">
function installCallback(url, status) {
document.getElementById("status").textContent = status;
dump("Sending InstallComplete\n");
var event = new CustomEvent("InstallComplete");
var target = window.parent ? window.parent : window;
target.dispatchEvent(event);
}
function startInstall() {
var event = new CustomEvent("InstallTriggered");
var text = decodeURIComponent(document.location.search.substring(1));
var triggers = JSON.parse(text);
try {
document.getElementById("return").textContent = InstallTrigger.install(triggers, installCallback);
dump("Sending InstallTriggered\n");
window.dispatchEvent(event);
}
catch (e) {
document.getElementById("return").textContent = "exception";
dump("Sending InstallTriggered\n");
window.dispatchEvent(event);
throw e;
}
}

View File

@ -10,6 +10,10 @@
<script type="text/javascript">
function installCallback(url, status) {
document.location = "#foo";
dump("Sending InstallComplete\n");
var event = new CustomEvent("InstallComplete");
window.dispatchEvent(event);
}
function startInstall() {