Merge m-c to b2ginbound a=merge

This commit is contained in:
Wes Kocher 2015-04-08 17:34:23 -07:00
commit 33422cc326
90 changed files with 1042 additions and 438 deletions

View File

@ -164,6 +164,9 @@ let handleContentContextMenu = function (event) {
let baseURI = doc.baseURI;
let referrer = doc.referrer;
let referrerPolicy = doc.referrerPolicy;
let frameOuterWindowID = doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
// Media related cache info parent needs for saving
let contentType = null;
@ -199,7 +202,8 @@ let handleContentContextMenu = function (event) {
sendSyncMessage("contextmenu",
{ editFlags, spellInfo, customMenuItems, addonInfo,
principal, docLocation, charSet, baseURI, referrer,
referrerPolicy, contentType, contentDisposition },
referrerPolicy, contentType, contentDisposition,
frameOuterWindowID },
{ event, popupNode: event.target });
}
else {

View File

@ -599,24 +599,31 @@ nsContextMenu.prototype = {
this.focusedWindow = win;
this.focusedElement = elt;
let ownerDoc = this.target.ownerDocument;
// If this is a remote context menu event, use the information from
// gContextMenuContentData instead.
if (this.isRemote) {
this.browser = gContextMenuContentData.browser;
this.principal = gContextMenuContentData.principal;
this.frameOuterWindowID = gContextMenuContentData.frameOuterWindowID;
} else {
editFlags = SpellCheckHelper.isEditable(this.target, window);
this.browser = this.target.ownerDocument.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
this.principal = this.target.ownerDocument.nodePrincipal;
this.browser = ownerDoc.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
this.principal = ownerDoc.nodePrincipal;
this.frameOuterWindowID = ownerDoc.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
}
this.onSocial = !!this.browser.getAttribute("origin");
// Check if we are in a synthetic document (stand alone image, video, etc.).
this.inSyntheticDoc = this.target.ownerDocument.mozSyntheticDocument;
this.inSyntheticDoc = ownerDoc.mozSyntheticDocument;
// First, do checks for nodes that never have children.
if (this.target.nodeType == Node.ELEMENT_NODE) {
// See if the user clicked on an image.
@ -635,7 +642,7 @@ nsContextMenu.prototype = {
var descURL = this.target.getAttribute("longdesc");
if (descURL) {
this.imageDescURL = makeURLAbsolute(this.target.ownerDocument.body.baseURI, descURL);
this.imageDescURL = makeURLAbsolute(ownerDoc.body.baseURI, descURL);
}
}
else if (this.target instanceof HTMLCanvasElement) {
@ -685,7 +692,7 @@ nsContextMenu.prototype = {
this.onKeywordField = (editFlags & SpellCheckHelper.KEYWORD);
}
else if (this.target instanceof HTMLHtmlElement) {
var bodyElt = this.target.ownerDocument.body;
var bodyElt = ownerDoc.body;
if (bodyElt) {
let computedURL;
try {
@ -776,11 +783,11 @@ nsContextMenu.prototype = {
this.onMathML = true;
// See if the user clicked in a frame.
var docDefaultView = this.target.ownerDocument.defaultView;
var docDefaultView = ownerDoc.defaultView;
if (docDefaultView != docDefaultView.top) {
this.inFrame = true;
if (this.target.ownerDocument.isSrcdocDocument) {
if (ownerDoc.isSrcdocDocument) {
this.inSrcdocFrame = true;
}
}
@ -805,7 +812,7 @@ nsContextMenu.prototype = {
InlineSpellCheckerUI.initFromRemote(gContextMenuContentData.spellInfo);
}
else {
var targetWin = this.target.ownerDocument.defaultView;
var targetWin = ownerDoc.defaultView;
var editingSession = targetWin.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)

View File

@ -3776,6 +3776,7 @@
referrerPolicy: aMessage.data.referrerPolicy,
contentType: aMessage.data.contentType,
contentDisposition: aMessage.data.contentDisposition,
frameOuterWindowID: aMessage.data.frameOuterWindowID,
};
let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
let event = gContextMenuContentData.event;

View File

@ -5,6 +5,7 @@
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
const TESTROOT2 = "http://example.org/browser/toolkit/mozapps/extensions/test/xpinstall/";
const SECUREROOT = "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
const PROGRESS_NOTIFICATION = "addon-progress";
@ -86,6 +87,52 @@ function wait_for_notification_close(aCallback) {
}, false);
}
function wait_for_install_dialog(aCallback) {
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
aCallback();
});
return;
}
info("Waiting for install dialog");
Services.wm.addListener({
onOpenWindow: function(aXULWindow) {
info("Install dialog opened, waiting for focus");
Services.wm.removeListener(this);
var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
waitForFocus(function() {
info("Saw install dialog");
is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
// Override the countdown timer on the accept button
var button = domwindow.document.documentElement.getButton("accept");
button.disabled = false;
aCallback();
}, domwindow);
},
onCloseWindow: function(aXULWindow) {
},
onWindowTitleChange: function(aXULWindow, aNewTitle) {
}
});
}
function accept_install_dialog() {
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
document.getElementById("addon-install-confirmation-accept").click();
} else {
let win = Services.wm.getMostRecentWindow("Addons:Install");
win.document.documentElement.acceptDialog();
}
}
function wait_for_single_notification(aCallback) {
function inner_waiter() {
info("Waiting for single notification");
@ -165,7 +212,7 @@ function test_blocked_install() {
"Should have seen the right message");
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
@ -183,7 +230,7 @@ function test_blocked_install() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
// Click on Allow
@ -208,7 +255,7 @@ function test_whitelisted_install() {
gBrowser.selectedTab = originalTab;
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
is(gBrowser.selectedTab, tab,
"tab selected in response to the addon-install-confirmation notification");
@ -230,7 +277,7 @@ function test_whitelisted_install() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -331,7 +378,7 @@ function test_restartless() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
@ -352,7 +399,7 @@ function test_restartless() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -370,7 +417,7 @@ function test_multiple() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
@ -393,7 +440,7 @@ function test_multiple() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -412,7 +459,7 @@ function test_url() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
@ -430,7 +477,7 @@ function test_url() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -499,7 +546,7 @@ function test_reload() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
@ -534,7 +581,7 @@ function test_reload() {
gBrowser.loadURI(TESTROOT2 + "enabled.html");
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -552,7 +599,7 @@ function test_theme() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
@ -577,7 +624,7 @@ function test_theme() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -630,7 +677,7 @@ function test_renotify_installed() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
// Wait for the complete notification
wait_for_notification("addon-install-complete", function(aPanel) {
// Dismiss the notification
@ -640,7 +687,7 @@ function test_renotify_installed() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_notification("addon-install-confirmation", function(aPanel) {
wait_for_install_dialog(function() {
info("Timeouts after this probably mean bug 589954 regressed");
// Wait for the complete notification
@ -655,7 +702,7 @@ function test_renotify_installed() {
});
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});
@ -667,7 +714,7 @@ function test_renotify_installed() {
aPanel.hidePopup();
});
document.getElementById("addon-install-confirmation-accept").click();
accept_install_dialog();
});
});

View File

@ -282,7 +282,10 @@ let LoopCallsInternal = {
*/
_startCall: function(callData) {
const openChat = () => {
this.conversationInProgress.id = MozLoopService.openChatWindow(callData);
let windowId = MozLoopService.openChatWindow(callData);
if (windowId) {
this.conversationInProgress.id = windowId;
}
};
if (callData.type == "incoming" && ("callerId" in callData) &&

View File

@ -62,11 +62,7 @@ const extend = function(target, source) {
*/
const containsParticipant = function(room, participant) {
for (let user of room.participants) {
// XXX until a bug 1100318 is implemented and deployed,
// we need to check the "id" field here as well - roomConnectionId is the
// official value for the interface.
if (user.roomConnectionId == participant.roomConnectionId &&
user.id == participant.id) {
if (user.roomConnectionId == participant.roomConnectionId) {
return true;
}
}
@ -451,10 +447,7 @@ let LoopRoomsInternal = {
let origRoom = this.rooms.get(roomToken);
let patchData = {
roomName: newRoomName,
// XXX We have to supply the max size and room owner due to bug 1099063.
maxSize: origRoom.maxSize,
roomOwner: origRoom.roomOwner
roomName: newRoomName
};
MozLoopService.hawkRequest(this.sessionType, url, "PATCH", patchData)
.then(response => {

View File

@ -827,7 +827,8 @@ let MozLoopServiceInternal = {
*
* @param {Object} conversationWindowData The data to be obtained by the
* window when it opens.
* @returns {Number} The id of the window.
* @returns {Number} The id of the window, null if a window could not
* be opened.
*/
openChatWindow: function(conversationWindowData) {
// So I guess the origin is the loop server!?
@ -913,7 +914,9 @@ let MozLoopServiceInternal = {
}.bind(this), true);
};
Chat.open(null, origin, "", url, undefined, undefined, callback);
if (!Chat.open(null, origin, "", url, undefined, undefined, callback)) {
return null;
}
return windowId;
},

View File

@ -33,7 +33,6 @@
<script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
<script type="text/javascript" src="loop/shared/js/otSdkDriver.js"></script>
<script type="text/javascript" src="loop/shared/js/store.js"></script>
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
<script type="text/javascript" src="loop/shared/js/conversationStore.js"></script>
<script type="text/javascript" src="loop/shared/js/roomStates.js"></script>
<script type="text/javascript" src="loop/shared/js/fxOSActiveRoomStore.js"></script>
@ -46,6 +45,7 @@
<script type="text/javascript" src="loop/js/conversationAppStore.js"></script>
<script type="text/javascript" src="loop/js/client.js"></script>
<script type="text/javascript" src="loop/js/conversationViews.js"></script>
<script type="text/javascript" src="loop/js/roomStore.js"></script>
<script type="text/javascript" src="loop/js/roomViews.js"></script>
<script type="text/javascript" src="loop/js/conversation.js"></script>
</body>

View File

@ -28,11 +28,11 @@
<script type="text/javascript" src="loop/shared/js/actions.js"></script>
<script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
<script type="text/javascript" src="loop/shared/js/store.js"></script>
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
<script type="text/javascript" src="loop/shared/js/roomStates.js"></script>
<script type="text/javascript" src="loop/shared/js/fxOSActiveRoomStore.js"></script>
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
<script type="text/javascript;version=1.8" src="loop/js/contacts.js"></script>
<script type="text/javascript" src="loop/js/roomStore.js"></script>
<script type="text/javascript" src="loop/js/panel.js"></script>
</body>
</html>

View File

@ -18,6 +18,7 @@ browser.jar:
content/browser/loop/js/panel.js (content/js/panel.js)
content/browser/loop/js/contacts.js (content/js/contacts.js)
content/browser/loop/js/conversationViews.js (content/js/conversationViews.js)
content/browser/loop/js/roomStore.js (content/js/roomStore.js)
content/browser/loop/js/roomViews.js (content/js/roomViews.js)
# Desktop styles
@ -71,7 +72,6 @@ browser.jar:
content/browser/loop/shared/js/actions.js (content/shared/js/actions.js)
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
content/browser/loop/shared/js/store.js (content/shared/js/store.js)
content/browser/loop/shared/js/roomStore.js (content/shared/js/roomStore.js)
content/browser/loop/shared/js/roomStates.js (content/shared/js/roomStates.js)
content/browser/loop/shared/js/fxOSActiveRoomStore.js (content/shared/js/fxOSActiveRoomStore.js)
content/browser/loop/shared/js/activeRoomStore.js (content/shared/js/activeRoomStore.js)

View File

@ -50,7 +50,6 @@
<script src="../../content/shared/js/otSdkDriver.js"></script>
<script src="../../content/shared/js/store.js"></script>
<script src="../../content/shared/js/conversationStore.js"></script>
<script src="../../content/shared/js/roomStore.js"></script>
<script src="../../content/shared/js/roomStates.js"></script>
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
<script src="../../content/shared/js/activeRoomStore.js"></script>
@ -59,6 +58,7 @@
<script src="../../content/shared/js/feedbackViews.js"></script>
<script src="../../content/js/client.js"></script>
<script src="../../content/js/conversationAppStore.js"></script>
<script src="../../content/js/roomStore.js"></script>
<script src="../../content/js/roomViews.js"></script>
<script src="../../content/js/conversationViews.js"></script>
<script src="../../content/js/conversation.js"></script>
@ -74,6 +74,7 @@
<script src="conversationViews_test.js"></script>
<script src="contacts_test.js"></script>
<script src="l10n_test.js"></script>
<script src="roomStore_test.js"></script>
<script>
// Stop the default init functions running to avoid conflicts in tests
document.removeEventListener('DOMContentLoaded', loop.panel.init);

View File

@ -54,7 +54,6 @@
<script src="../../content/shared/js/roomStates.js"></script>
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
<script src="../../content/shared/js/activeRoomStore.js"></script>
<script src="../../content/shared/js/roomStore.js"></script>
<script src="../../content/shared/js/conversationStore.js"></script>
<script src="../../content/shared/js/feedbackStore.js"></script>
<script src="../../content/shared/js/views.js"></script>
@ -77,7 +76,6 @@
<script src="feedbackStore_test.js"></script>
<script src="otSdkDriver_test.js"></script>
<script src="store_test.js"></script>
<script src="roomStore_test.js"></script>
<script>
describe("Uncaught Error Check", function() {
it("should load the tests without errors", function() {

View File

@ -33,6 +33,7 @@ add_task(function* test_busy_2fxa_calls() {
Chat.open = function(contentWindow, origin, title, url) {
opened++;
windowId = url.match(/about:loopconversation\#(\d+)$/)[1];
return windowId;
};
mockPushHandler.notify(1, MozLoopService.channelIDs.callsFxA);

View File

@ -19,6 +19,7 @@ add_task(function test_startDirectCall_opens_window() {
let openedUrl;
Chat.open = function(contentWindow, origin, title, url) {
openedUrl = url;
return 1;
};
LoopCalls.startDirectCall(contact, "audio-video");
@ -34,6 +35,7 @@ add_task(function test_startDirectCall_getConversationWindowData() {
let openedUrl;
Chat.open = function(contentWindow, origin, title, url) {
openedUrl = url;
return 2;
};
LoopCalls.startDirectCall(contact, "audio-video");
@ -49,6 +51,36 @@ add_task(function test_startDirectCall_getConversationWindowData() {
LoopCalls.clearCallInProgress(windowId);
});
add_task(function test_startDirectCall_not_busy_if_window_fails_to_open() {
let openedUrl;
// Simulate no window available to open.
Chat.open = function(contentWindow, origin, title, url) {
openedUrl = url;
return null;
};
LoopCalls.startDirectCall(contact, "audio-video");
do_check_true(!!openedUrl, "should have attempted to open chat window");
openedUrl = null;
// Window opens successfully this time.
Chat.open = function(contentWindow, origin, title, url) {
openedUrl = url;
return 3;
};
LoopCalls.startDirectCall(contact, "audio-video");
do_check_true(!!openedUrl, "should open a chat window");
// Stop the busy kicking in for following tests.
let windowId = openedUrl.match(/about:loopconversation\#(\d+)$/)[1];
LoopCalls.clearCallInProgress(windowId);
});
function run_test() {
do_register_cleanup(function() {
// Revert original Chat.open implementation

View File

@ -49,7 +49,6 @@
<script src="../content/shared/js/validate.js"></script>
<script src="../content/shared/js/dispatcher.js"></script>
<script src="../content/shared/js/store.js"></script>
<script src="../content/shared/js/roomStore.js"></script>
<script src="../content/shared/js/conversationStore.js"></script>
<script src="../content/shared/js/roomStates.js"></script>
<script src="../content/shared/js/fxOSActiveRoomStore.js"></script>
@ -57,6 +56,7 @@
<script src="../content/shared/js/feedbackStore.js"></script>
<script src="../content/shared/js/views.js"></script>
<script src="../content/shared/js/feedbackViews.js"></script>
<script src="../content/js/roomStore.js"></script>
<script src="../content/js/roomViews.js"></script>
<script src="../content/js/conversationViews.js"></script>
<script src="../content/js/client.js"></script>

View File

@ -3,6 +3,7 @@ tags = devtools
skip-if = e10s # Handle in Bug 1077464 for profiler
subsuite = devtools
support-files =
doc_innerHTML.html
doc_simple-test.html
head.js
@ -10,6 +11,9 @@ support-files =
# that need to be moved over to performance tool
[browser_perf-aaa-run-first-leaktest.js]
[browser_markers-parse-html.js]
[browser_perf-allocations-to-samples.js]
[browser_perf-compatibility-01.js]
[browser_perf-compatibility-02.js]

View File

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we get a "Parse HTML" marker when a page sets innerHTML.
*/
const TEST_URL = EXAMPLE_URL + "doc_innerHTML.html"
function* getMarkers(front) {
const { promise, resolve } = Promise.defer();
const handler = (_, markers) => {
resolve(markers);
};
front.on("markers", handler);
yield front.startRecording({ withTicks: true });
const markers = yield promise;
front.off("markers", handler);
yield front.stopRecording();
return markers;
}
function* spawnTest () {
let { target, front } = yield initBackend(TEST_URL);
const markers = yield getMarkers(front);
info("markers = " + JSON.stringify(markers, null, 2));
ok(markers.some(m => m.name === "Parse HTML" && m.stack != undefined),
"Should get some Parse HTML markers");
yield removeTab(target.tab);
finish();
}

View File

@ -0,0 +1,20 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Performance tool + innerHTML test page</title>
</head>
<body>
<script type="text/javascript">
window.test = function () {
document.body.innerHTML = "<h1>LOL</h1>";
};
setInterval(window.test, 100);
</script>
</body>
</html>

View File

@ -53,6 +53,16 @@ const TIMELINE_BLUEPRINT = {
colorName: "highlight-lightorange",
label: L10N.getStr("timeline.label.javascript2")
},
"Parse HTML": {
group: 1,
colorName: "highlight-lightorange",
label: L10N.getStr("timeline.label.parseHTML")
},
"Parse XML": {
group: 1,
colorName: "highlight-lightorange",
label: L10N.getStr("timeline.label.parseXML")
},
"ConsoleTime": {
group: 2,
colorName: "highlight-bluegrey",

View File

@ -40,6 +40,8 @@ timeline.label.styles2=Recalculate Style
timeline.label.reflow2=Layout
timeline.label.paint=Paint
timeline.label.javascript2=Function Call
timeline.label.parseHTML=Parse HTML
timeline.label.parseXML=Parse XML
timeline.label.domevent=DOM Event
timeline.label.consoleTime=Console

View File

@ -27,8 +27,8 @@
}
/* Square back and forward buttons */
#back-button:not(:-moz-lwtheme) > .toolbarbutton-icon,
#forward-button:not(:-moz-lwtheme) > .toolbarbutton-icon {
#back-button > .toolbarbutton-icon,
#forward-button > .toolbarbutton-icon {
margin: 0;
border: none;
padding: 2px 6px;

View File

@ -218,7 +218,7 @@ toolbar[brighttext] #downloads-indicator-counter {
:root[devtoolstheme="dark"] .browserContainer > findbar .findbar-textbox {
background-color: var(--url-and-searchbar-background-color) !important;
background-image: none !important;
color: var(--url-and-searchbar-color);
color: var(--url-and-searchbar-color) !important;
border: none !important;
box-shadow: none !important;
}

View File

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef AutoTimelineMarker_h__
#define AutoTimelineMarker_h__
#include "mozilla/GuardObjects.h"
#include "mozilla/Move.h"
#include "nsDocShell.h"
#include "nsRefPtr.h"
namespace mozilla {
// # AutoTimelineMarker
//
// An RAII class to trace some task in the platform by adding a start and end
// timeline marker pair. These markers are then rendered in the devtools'
// performance tool's waterfall graph.
//
// Example usage:
//
// {
// AutoTimelineMarker marker(mDocShell, "Parse CSS");
// nsresult rv = ParseTheCSSFile(mFile);
// ...
// }
class MOZ_STACK_CLASS AutoTimelineMarker
{
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
nsRefPtr<nsDocShell> mDocShell;
const char* mName;
bool
DocShellIsRecording(nsDocShell& aDocShell)
{
bool isRecording = false;
if (nsDocShell::gProfileTimelineRecordingsCount > 0) {
aDocShell.GetRecordProfileTimelineMarkers(&isRecording);
}
return isRecording;
}
public:
explicit AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mDocShell(nullptr)
, mName(aName)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
nsDocShell* docShell = static_cast<nsDocShell*>(aDocShell);
if (docShell && DocShellIsRecording(*docShell)) {
mDocShell = docShell;
mDocShell->AddProfileTimelineMarker(mName, TRACING_INTERVAL_START);
}
}
~AutoTimelineMarker()
{
if (mDocShell) {
mDocShell->AddProfileTimelineMarker(mName, TRACING_INTERVAL_END);
}
}
};
} // namespace mozilla
#endif /* AutoTimelineMarker_h__ */

View File

@ -42,6 +42,7 @@ EXPORTS += [
]
EXPORTS.mozilla += [
'AutoTimelineMarker.h',
'IHistory.h',
'LoadContext.h',
]

View File

@ -432,12 +432,40 @@ private:
WebSocketImpl* mImpl;
};
class CloseConnectionRunnable final : public nsRunnable
{
public:
CloseConnectionRunnable(WebSocketImpl* aImpl,
uint16_t aReasonCode,
const nsACString& aReasonString)
: mImpl(aImpl)
, mReasonCode(aReasonCode)
, mReasonString(aReasonString)
{}
NS_IMETHOD Run() override
{
return mImpl->CloseConnection(mReasonCode, mReasonString);
}
private:
nsRefPtr<WebSocketImpl> mImpl;
uint16_t mReasonCode;
const nsCString mReasonString;
};
} // anonymous namespace
nsresult
WebSocketImpl::CloseConnection(uint16_t aReasonCode,
const nsACString& aReasonString)
{
if (!IsTargetThread()) {
nsRefPtr<nsRunnable> runnable =
new CloseConnectionRunnable(this, aReasonCode, aReasonString);
return Dispatch(runnable, NS_DISPATCH_NORMAL);
}
AssertIsOnTargetThread();
if (mDisconnectingOrDisconnected) {
@ -471,7 +499,6 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
}
// No channel, but not disconnected: canceled or failed early
//
MOZ_ASSERT(readyState == WebSocket::CONNECTING,
"Should only get here for early websocket cancel/error");
@ -622,10 +649,12 @@ WebSocketImpl::DisconnectInternal()
mWeakLoadGroup = nullptr;
}
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
if (!mWorkerPrivate) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
}
}
}

View File

@ -30,6 +30,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/AutoTimelineMarker.h"
#include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
@ -4246,6 +4247,8 @@ nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
bool aQuirks,
bool aPreventScriptExecution)
{
AutoTimelineMarker m(aTargetNode->OwnerDoc()->GetDocShell(), "Parse HTML");
if (nsContentUtils::sFragmentParsingActive) {
NS_NOTREACHED("Re-entrant fragment parsing attempted.");
return NS_ERROR_DOM_INVALID_STATE_ERR;
@ -4272,6 +4275,8 @@ nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer,
nsIDocument* aTargetDocument,
bool aScriptingEnabledForNoscriptParsing)
{
AutoTimelineMarker m(aTargetDocument->GetDocShell(), "Parse HTML");
if (nsContentUtils::sFragmentParsingActive) {
NS_NOTREACHED("Re-entrant fragment parsing attempted.");
return NS_ERROR_DOM_INVALID_STATE_ERR;
@ -4297,6 +4302,8 @@ nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
bool aPreventScriptExecution,
nsIDOMDocumentFragment** aReturn)
{
AutoTimelineMarker m(aDocument->GetDocShell(), "Parse XML");
if (nsContentUtils::sFragmentParsingActive) {
NS_NOTREACHED("Re-entrant fragment parsing attempted.");
return NS_ERROR_DOM_INVALID_STATE_ERR;

View File

@ -25,7 +25,7 @@ class nsNPAPIPluginInstance;
* interface to mirror this interface when changing it.
*/
[scriptable, uuid(16c14177-52eb-49d3-9842-a1a0b92be11a)]
[scriptable, uuid(5efbd411-5bbe-4de1-9f3a-1c3459696eb2)]
interface nsIObjectLoadingContent : nsISupports
{
/**
@ -188,4 +188,12 @@ interface nsIObjectLoadingContent : nsISupports
* This method will disable the play-preview plugin state.
*/
void cancelPlayPreview();
/**
* If this plugin runs out-of-process, it has a runID to differentiate
* between different times the plugin process has been instantiated.
*
* This throws NS_ERROR_NOT_IMPLEMENTED for in-process plugins.
*/
readonly attribute unsigned long runID;
};

View File

@ -701,6 +701,8 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
nsObjectLoadingContent::nsObjectLoadingContent()
: mType(eType_Loading)
, mFallbackType(eFallbackAlternate)
, mRunID(0)
, mHasRunID(false)
, mChannelLoaded(false)
, mInstantiating(false)
, mNetworkCreated(true)
@ -815,6 +817,17 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
mInstanceOwner = newOwner;
if (mInstanceOwner) {
nsRefPtr<nsNPAPIPluginInstance> inst;
rv = mInstanceOwner->GetInstance(getter_AddRefs(inst));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = inst->GetRunID(&mRunID);
mHasRunID = NS_SUCCEEDED(rv);
}
// Ensure the frame did not change during instantiation re-entry (common).
// HasNewFrame would not have mInstanceOwner yet, so the new frame would be
// dangling. (Bug 854082)
@ -3145,6 +3158,24 @@ nsObjectLoadingContent::CancelPlayPreview()
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::GetRunID(uint32_t* aRunID)
{
if (NS_WARN_IF(!nsContentUtils::IsCallerChrome())) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_WARN_IF(!aRunID)) {
return NS_ERROR_INVALID_POINTER;
}
if (!mHasRunID) {
// The plugin instance must not have a run ID, so we must
// be running the plugin in-process.
return NS_ERROR_NOT_IMPLEMENTED;
}
*aRunID = mRunID;
return NS_OK;
}
static bool sPrefsInitialized;
static uint32_t sSessionTimeoutMinutes;
static uint32_t sPersistentTimeoutDays;

View File

@ -233,6 +233,18 @@ class nsObjectLoadingContent : public nsImageLoadingContent
JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aRv);
uint32_t GetRunID(mozilla::ErrorResult& aRv)
{
uint32_t runID;
nsresult rv = GetRunID(&runID);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return 0;
}
return runID;
}
protected:
/**
* Begins loading the object when called
@ -579,6 +591,9 @@ class nsObjectLoadingContent : public nsImageLoadingContent
// The type of fallback content we're showing (see ObjectState())
FallbackType mFallbackType : 8;
uint32_t mRunID;
bool mHasRunID;
// If true, we have opened a channel as the listener and it has reached
// OnStartRequest. Does not get set for channels that are passed directly to
// the plugin listener.

View File

@ -1022,17 +1022,21 @@ ContentParent::RecvGetGMPPluginVersionForAPI(const nsCString& aAPI,
}
bool
ContentParent::RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv)
ContentParent::RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv, uint32_t* aRunID)
{
*aRv = NS_OK;
return mozilla::plugins::SetupBridge(aPluginId, this, false, aRv);
return mozilla::plugins::SetupBridge(aPluginId, this, false, aRv, aRunID);
}
bool
ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv)
{
*aRv = NS_OK;
return mozilla::plugins::SetupBridge(aPluginId, this, true, aRv);
// We don't need to get the run ID for the plugin, since we already got it
// in the first call to SetupBridge in RecvLoadPlugin, so we pass in a dummy
// pointer and just throw it away.
uint32_t dummy = 0;
return mozilla::plugins::SetupBridge(aPluginId, this, true, aRv, &dummy);
}
bool

View File

@ -174,7 +174,7 @@ public:
bool* aHasPlugin,
nsCString* aVersion) override;
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv) override;
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv, uint32_t* aRunID) override;
virtual bool RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv) override;
virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
nsTArray<PluginTag>* aPlugins,

View File

@ -341,6 +341,14 @@ parent:
*/
sync SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint);
/**
* Returns the offset of this tab from the top level window
* origin in device pixels.
*
* aPoint offset values in device pixels.
*/
sync GetTabOffset() returns (LayoutDeviceIntPoint aPoint);
/**
* Gets the DPI of the screen corresponding to this browser.
*/

View File

@ -633,7 +633,7 @@ parent:
* via bridging. The corresponding PluginModuleChild will live in the plugin
* process.
*/
sync LoadPlugin(uint32_t pluginId) returns (nsresult rv);
sync LoadPlugin(uint32_t aPluginId) returns (nsresult aResult, uint32_t aRunID);
/**
* This call is used by asynchronous plugin instantiation to notify the

View File

@ -1776,6 +1776,13 @@ TabParent::RecvEnableDisableCommands(const nsString& aAction,
return true;
}
bool
TabParent::RecvGetTabOffset(LayoutDeviceIntPoint* aPoint)
{
*aPoint = GetChildProcessOffset();
return true;
}
NS_IMETHODIMP
TabParent::GetChildProcessOffset(int32_t* aOutCssX, int32_t* aOutCssY)
{

View File

@ -201,6 +201,7 @@ public:
virtual bool RecvSynthesizeNativeMouseMove(const mozilla::LayoutDeviceIntPoint& aPoint) override;
virtual bool RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip) override;
virtual bool RecvHideTooltip() override;
virtual bool RecvGetTabOffset(LayoutDeviceIntPoint* aPoint) override;
virtual bool RecvGetDPI(float* aValue) override;
virtual bool RecvGetDefaultScale(double* aValue) override;
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override;

View File

@ -243,8 +243,8 @@ public:
return true;
}
ConversionRequired
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
virtual ConversionRequired
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override
{
return kNeedNone;
}

View File

@ -122,6 +122,7 @@ public:
virtual nsresult EndUpdateBackground(NPP instance,
gfxContext* aCtx, const nsIntRect&) override;
virtual void GetLibraryPath(nsACString& aPath) { aPath.Assign(mFilePath); }
virtual nsresult GetRunID(uint32_t* aRunID) override { return NS_ERROR_NOT_IMPLEMENTED; }
private:
NP_InitializeFunc mNP_Initialize;

View File

@ -1778,3 +1778,22 @@ nsNPAPIPluginInstance::GetContentsScaleFactor()
}
return scaleFactor;
}
nsresult
nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID)
{
if (NS_WARN_IF(!aRunID)) {
return NS_ERROR_INVALID_POINTER;
}
if (NS_WARN_IF(!mPlugin)) {
return NS_ERROR_FAILURE;
}
PluginLibrary* library = mPlugin->GetLibrary();
if (!library) {
return NS_ERROR_FAILURE;
}
return library->GetRunID(aRunID);
}

View File

@ -286,6 +286,8 @@ public:
// Returns the contents scale factor of the screen the plugin is drawn on.
double GetContentsScaleFactor();
nsresult GetRunID(uint32_t *aRunID);
static bool InPluginCallUnsafeForReentry() { return gInUnsafePluginCalls > 0; }
static void BeginPluginCall(NSPluginCallReentry aReentryState)
{

View File

@ -3773,6 +3773,7 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin,
const nsAString& browserDumpID)
{
nsPluginTag* crashedPluginTag = TagForPlugin(aPlugin);
MOZ_ASSERT(crashedPluginTag);
// Notify the app's observer that a plugin crashed so it can submit
// a crashreport.
@ -3782,6 +3783,18 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin,
nsCOMPtr<nsIWritablePropertyBag2> propbag =
do_CreateInstance("@mozilla.org/hash-property-bag;1");
if (obsService && propbag) {
uint32_t runID = 0;
PluginLibrary* library = aPlugin->GetLibrary();
if (!NS_WARN_IF(!library)) {
library->GetRunID(&runID);
}
propbag->SetPropertyAsUint32(NS_LITERAL_STRING("runID"), runID);
nsCString pluginName;
crashedPluginTag->GetName(pluginName);
propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginName"),
NS_ConvertUTF8toUTF16(pluginName));
propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
pluginDumpID);
propbag->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),

View File

@ -17,7 +17,7 @@ namespace plugins {
bool
SetupBridge(uint32_t aPluginId, dom::ContentParent* aContentParent,
bool aForceBridgeNow, nsresult* rv);
bool aForceBridgeNow, nsresult* aResult, uint32_t* aRunID);
bool
FindPluginsForContent(uint32_t aPluginEpoch,

View File

@ -84,6 +84,7 @@ public:
const nsIntRect&, gfxContext**) = 0;
virtual nsresult EndUpdateBackground(NPP instance,
gfxContext*, const nsIntRect&) = 0;
virtual nsresult GetRunID(uint32_t* aRunID) = 0;
};

View File

@ -96,8 +96,13 @@ bool
mozilla::plugins::SetupBridge(uint32_t aPluginId,
dom::ContentParent* aContentParent,
bool aForceBridgeNow,
nsresult* rv)
nsresult* rv,
uint32_t* runID)
{
if (NS_WARN_IF(!rv) || NS_WARN_IF(!runID)) {
return false;
}
PluginModuleChromeParent::ClearInstantiationFlag();
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
nsRefPtr<nsNPAPIPlugin> plugin;
@ -106,6 +111,10 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId,
return true;
}
PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
*rv = chromeParent->GetRunID(runID);
if (NS_FAILED(*rv)) {
return true;
}
chromeParent->SetContentParent(aContentParent);
if (!aForceBridgeNow && chromeParent->IsStartingAsync() &&
PluginModuleChromeParent::DidInstantiate()) {
@ -365,7 +374,8 @@ PluginModuleContentParent::LoadModule(uint32_t aPluginId)
*/
dom::ContentChild* cp = dom::ContentChild::GetSingleton();
nsresult rv;
if (!cp->SendLoadPlugin(aPluginId, &rv) ||
uint32_t runID;
if (!cp->SendLoadPlugin(aPluginId, &rv, &runID) ||
NS_FAILED(rv)) {
return nullptr;
}
@ -381,6 +391,7 @@ PluginModuleContentParent::LoadModule(uint32_t aPluginId)
}
parent->mPluginId = aPluginId;
parent->mRunID = runID;
return parent;
}
@ -644,6 +655,10 @@ PluginModuleContentParent::~PluginModuleContentParent()
Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
}
// We start the Run IDs at 1 so that we can use 0 as a way of detecting
// errors in retrieving the run ID.
uint32_t PluginModuleChromeParent::sNextRunID = 1;
bool PluginModuleChromeParent::sInstantiated = false;
PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
@ -675,6 +690,7 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32
{
NS_ASSERTION(mSubprocess, "Out of memory!");
sInstantiated = true;
mRunID = sNextRunID++;
RegisterSettingsCallbacks();
@ -1499,6 +1515,16 @@ PluginModuleParent::ActorDestroy(ActorDestroyReason why)
}
}
nsresult
PluginModuleParent::GetRunID(uint32_t* aRunID)
{
if (NS_WARN_IF(!aRunID)) {
return NS_ERROR_INVALID_POINTER;
}
*aRunID = mRunID;
return NS_OK;
}
void
PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why)
{

View File

@ -128,6 +128,8 @@ public:
return mPluginName + mPluginVersion;
}
virtual nsresult GetRunID(uint32_t* aRunID) override;
protected:
virtual mozilla::ipc::RacyInterruptPolicy
MediateInterruptRace(const Message& parent, const Message& child) override
@ -305,6 +307,7 @@ protected:
bool mNPInitialized;
nsTArray<nsRefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
nsresult mAsyncNewRv;
uint32_t mRunID;
};
class PluginModuleContentParent : public PluginModuleParent
@ -551,6 +554,7 @@ private:
dom::ContentParent* mContentParent;
nsCOMPtr<nsIObserver> mOfflineObserver;
bool mIsBlocklisted;
static uint32_t sNextRunID;
static bool sInstantiated;
};

View File

@ -211,6 +211,9 @@ interface MozObjectLoadingContent {
*/
[ChromeOnly, Throws]
void cancelPlayPreview();
[ChromeOnly, Throws]
readonly attribute unsigned long runID;
};
/**

View File

@ -1,5 +1,7 @@
onconnect = function(evt) {
var blob = new Blob(['123'], { type: 'text/plain' });
var url = URL.createObjectURL(blob);
evt.ports[0].postMessage('alive \\o/');
evt.ports[0].onmessage = function(e) {
var blob = new Blob(['123'], { type: 'text/plain' });
var url = URL.createObjectURL(blob);
evt.ports[0].postMessage('alive \\o/');
};
}

View File

@ -16,9 +16,11 @@
SpecialPowers.pushPrefEnv({ set: [["dom.workers.sharedWorkers.enabled", true]] }, function() {
var sw = new SharedWorker('bug1132395_sharedWorker.js');
sw.port.onmessage = function(event) {
ok(true, "We didn't crash.");
ok(true, "We didn't crash.");
SimpleTest.finish();
}
sw.port.postMessage('go');
});
SimpleTest.waitForExplicitFinish();

View File

@ -14,6 +14,8 @@
#include "HwcComposer2D.h"
#endif
class nsIWidget;
namespace mozilla {
namespace gl {
@ -46,6 +48,10 @@ public:
return static_cast<GLContextEGL*>(gl);
}
static EGLSurface CreateSurfaceForWindow(nsIWidget* aWidget);
static void DestroySurface(EGLSurface aSurface);
bool Init() override;
virtual bool IsDoubleBuffered() const override {

View File

@ -360,7 +360,7 @@ GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
Screen()->AssureBlitted();
}
mSurfaceOverride = surf ? (EGLSurface) surf : mSurface;
mSurfaceOverride = surf;
MakeCurrent(true);
}
@ -444,7 +444,7 @@ GLContextEGL::RenewSurface() {
void
GLContextEGL::ReleaseSurface() {
if (mOwnsContext) {
DestroySurface(mSurface);
mozilla::gl::DestroySurface(mSurface);
}
mSurface = EGL_NO_SURFACE;
}
@ -459,17 +459,20 @@ GLContextEGL::SetupLookupFunction()
bool
GLContextEGL::SwapBuffers()
{
if (mSurface) {
EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
? mSurfaceOverride
: mSurface;
if (surface) {
#ifdef MOZ_WIDGET_GONK
if (!mIsOffscreen) {
if (mHwc) {
return mHwc->Render(EGL_DISPLAY(), mSurface);
return mHwc->Render(EGL_DISPLAY(), surface);
} else {
return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), surface);
}
} else
#endif
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), surface);
} else {
return false;
}
@ -482,6 +485,32 @@ GLContextEGL::HoldSurface(gfxASurface *aSurf) {
mThebesSurface = aSurf;
}
/* static */ EGLSurface
GLContextEGL::CreateSurfaceForWindow(nsIWidget* aWidget)
{
if (!sEGLLibrary.EnsureInitialized()) {
MOZ_CRASH("Failed to load EGL library!\n");
return nullptr;
}
EGLConfig config;
if (!CreateConfig(&config)) {
MOZ_CRASH("Failed to create EGLConfig!\n");
return nullptr;
}
EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config);
return surface;
}
/* static */ void
GLContextEGL::DestroySurface(EGLSurface aSurface)
{
if (aSurface != EGL_NO_SURFACE) {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), aSurface);
}
}
already_AddRefed<GLContextEGL>
GLContextEGL::CreateGLContext(const SurfaceCaps& caps,
GLContextEGL *shareContext,
@ -774,7 +803,7 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
if (!glContext) {
MOZ_CRASH("Failed to create EGLContext!\n");
DestroySurface(surface);
mozilla::gl::DestroySurface(surface);
return nullptr;
}

View File

@ -66,6 +66,56 @@ CurrentThreadIsIonCompiling()
{
return TlsPerThreadData.get()->ionCompiling;
}
static bool
GCIsSweepingOnMainThread(JSRuntime* rt, Zone* zone)
{
return rt->isHeapMajorCollecting() && rt->gc.state() == SWEEP &&
(zone->isGCSweeping() || rt->isAtomsZone(zone));
}
static bool
GCIsSweepingOnBackgroundThread(JSRuntime* rt, Zone* zone)
{
return rt->gc.isBackgroundSweeping() &&
(zone->isGCBackgroundSweeping() || rt->isAtomsZone(zone));
}
static bool
ThingMayHaveDifferentRuntime(TenuredCell* cell)
{
// Some GC things may be associated with another runtime.
AllocKind kind = cell->getAllocKind();
if (kind == AllocKind::STRING)
return static_cast<const JSString*>(cell)->isPermanentAtom();
else if (kind == AllocKind::SYMBOL)
return static_cast<const JS::Symbol*>(cell)->isWellKnownSymbol();
return false;
}
void
CheckGCIsSweepingZone(gc::Cell* cell)
{
MOZ_ASSERT(!IsInsideNursery(cell));
TenuredCell* tenured = &cell->asTenured();
if (ThingMayHaveDifferentRuntime(tenured))
return;
Zone* zone = tenured->zoneFromAnyThread();
JSRuntime* rt = zone->runtimeFromAnyThread();
if (CurrentThreadCanAccessRuntime(rt)) {
// We're on the main thread.
MOZ_ASSERT(GCIsSweepingOnMainThread(rt, zone));
} else {
// We're not on the main thread, so we're either on a helper thread run
// while the GC is active on the main thread or we are background
// sweeping.
MOZ_ASSERT(GCIsSweepingOnMainThread(rt, zone) ||
GCIsSweepingOnBackgroundThread(rt, zone));
}
}
#endif // DEBUG
bool

View File

@ -287,6 +287,11 @@ ZoneOfIdFromAnyThread(const jsid& id)
void
ValueReadBarrier(const Value& value);
#ifdef DEBUG
void
CheckGCIsSweepingZone(gc::Cell* cell);
#endif
template <typename T>
struct InternalGCMethods {};
@ -303,6 +308,13 @@ struct InternalGCMethods<T*>
static void postBarrierRemove(T** vp) { T::writeBarrierPostRemove(*vp, vp); }
static void readBarrier(T* v) { T::readBarrier(v); }
#ifdef DEBUG
static void checkGCIsSweeping(T* v) {
if (v)
CheckGCIsSweepingZone(v);
}
#endif
};
template <>
@ -380,6 +392,13 @@ struct InternalGCMethods<Value>
}
static void readBarrier(const Value& v) { ValueReadBarrier(v); }
#ifdef DEBUG
static void checkGCIsSweeping(const Value& v) {
if (v.isMarkable())
CheckGCIsSweepingZone(v.toGCThing());
}
#endif
};
template <>
@ -403,6 +422,13 @@ struct InternalGCMethods<jsid>
static void postBarrier(jsid* idp) {}
static void postBarrierRelocate(jsid* idp) {}
static void postBarrierRemove(jsid* idp) {}
#ifdef DEBUG
static void checkGCIsSweeping(jsid id) {
if (JSID_IS_GCTHING(id))
CheckGCIsSweepingZone(JSID_TO_GCTHING(id).asCell());
}
#endif
};
template <typename T>
@ -446,6 +472,10 @@ class BarrieredBase : public BarrieredBaseMixins<T>
protected:
void pre() { InternalGCMethods<T>::preBarrier(value); }
void pre(Zone* zone) { InternalGCMethods<T>::preBarrier(zone, value); }
#ifdef DEBUG
void checkGCIsSweeping() { InternalGCMethods<T>::checkGCIsSweeping(value); }
#endif
};
template <>
@ -493,14 +523,16 @@ class PreBarriered : public BarrieredBase<T>
/*
* A pre- and post-barriered heap pointer, for use inside the JS engine.
*
* It must only be stored in memory that has GC lifetime. HeapPtr must not be
* used in contexts where it may be implicitly moved or deleted, e.g. most
* containers.
*
* Not to be confused with JS::Heap<T>. This is a different class from the
* external interface and implements substantially different semantics.
*
* The post-barriers implemented by this class are faster than those
* implemented by RelocatablePtr<T> or JS::Heap<T> at the cost of not
* automatically handling deletion or movement. It should generally only be
* stored in memory that has GC lifetime. HeapPtr must not be used in contexts
* where it may be implicitly moved or deleted, e.g. most containers.
* automatically handling deletion or movement.
*/
template <class T>
class HeapPtr : public BarrieredBase<T>
@ -509,6 +541,9 @@ class HeapPtr : public BarrieredBase<T>
HeapPtr() : BarrieredBase<T>(GCMethods<T>::initial()) {}
explicit HeapPtr(T v) : BarrieredBase<T>(v) { post(); }
explicit HeapPtr(const HeapPtr<T>& v) : BarrieredBase<T>(v) { post(); }
#ifdef DEBUG
~HeapPtr() { this->checkGCIsSweeping(); }
#endif
void init(T v) {
this->value = v;
@ -613,9 +648,20 @@ class RelocatablePtr : public BarrieredBase<T>
DECLARE_POINTER_ASSIGN_OPS(RelocatablePtr, T);
/* Make this friend so it can access pre() and post(). */
template <class T1, class T2>
friend inline void
BarrieredSetPair(Zone* zone,
RelocatablePtr<T1*>& v1, T1* val1,
RelocatablePtr<T2*>& v2, T2* val2);
protected:
void set(const T& v) {
this->pre();
postBarrieredSet(v);
}
void postBarrieredSet(const T& v) {
if (GCMethods<T>::needsPostBarrier(v)) {
this->value = v;
post();
@ -658,6 +704,24 @@ BarrieredSetPair(Zone* zone,
v2.post();
}
/*
* This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
* barriers with only one branch to check if we're in an incremental GC.
*/
template <class T1, class T2>
static inline void
BarrieredSetPair(Zone* zone,
RelocatablePtr<T1*>& v1, T1* val1,
RelocatablePtr<T2*>& v2, T2* val2)
{
if (T1::needWriteBarrierPre(zone)) {
v1.pre();
v2.pre();
}
v1.postBarrieredSet(val1);
v2.postBarrieredSet(val2);
}
/* Useful for hashtables with a HeapPtr as key. */
template <class T>
struct HeapPtrHasher
@ -766,9 +830,17 @@ typedef PreBarriered<JSString*> PreBarrieredString;
typedef PreBarriered<JSAtom*> PreBarrieredAtom;
typedef RelocatablePtr<JSObject*> RelocatablePtrObject;
typedef RelocatablePtr<JSFunction*> RelocatablePtrFunction;
typedef RelocatablePtr<PlainObject*> RelocatablePtrPlainObject;
typedef RelocatablePtr<JSScript*> RelocatablePtrScript;
typedef RelocatablePtr<NativeObject*> RelocatablePtrNativeObject;
typedef RelocatablePtr<NestedScopeObject*> RelocatablePtrNestedScopeObject;
typedef RelocatablePtr<Shape*> RelocatablePtrShape;
typedef RelocatablePtr<ObjectGroup*> RelocatablePtrObjectGroup;
typedef RelocatablePtr<jit::JitCode*> RelocatablePtrJitCode;
typedef RelocatablePtr<JSLinearString*> RelocatablePtrLinearString;
typedef RelocatablePtr<JSString*> RelocatablePtrString;
typedef RelocatablePtr<JSAtom*> RelocatablePtrAtom;
typedef HeapPtr<NativeObject*> HeapPtrNativeObject;
typedef HeapPtr<ArrayObject*> HeapPtrArrayObject;

View File

@ -39,6 +39,9 @@ JS::Zone::Zone(JSRuntime* rt)
gcState_(NoGC),
gcScheduled_(false),
gcPreserveCode_(false),
#ifdef DEBUG
gcBackgroundSweeping_(false),
#endif
jitUsingBarriers_(false),
listNext_(NotOnList)
{
@ -270,6 +273,15 @@ Zone::notifyObservingDebuggers()
}
}
#ifdef DEBUG
void
Zone::setGCBackgroundSweeping(bool newState)
{
MOZ_ASSERT(gcBackgroundSweeping_ != newState);
gcBackgroundSweeping_ = newState;
}
#endif
JS::Zone*
js::ZoneOfValue(const JS::Value& value)
{

View File

@ -226,6 +226,9 @@ struct Zone : public JS::shadow::Zone,
// For testing purposes, return the index of the zone group which this zone
// was swept in in the last GC.
unsigned lastZoneGroupIndex() { return gcLastZoneGroupIndex; }
void setGCBackgroundSweeping(bool newState);
bool isGCBackgroundSweeping() { return gcBackgroundSweeping_; }
#endif
private:
@ -300,6 +303,9 @@ struct Zone : public JS::shadow::Zone,
GCState gcState_;
bool gcScheduled_;
bool gcPreserveCode_;
#ifdef DEBUG
bool gcBackgroundSweeping_;
#endif
bool jitUsingBarriers_;
// Allow zones to be linked into a list

View File

@ -119,11 +119,11 @@ struct BaselineScript
private:
// Code pointer containing the actual method.
HeapPtrJitCode method_;
RelocatablePtrJitCode method_;
// For heavyweight scripts, template objects to use for the call object and
// decl env object (linked via the call object's enclosing scope).
HeapPtrObject templateScope_;
RelocatablePtrObject templateScope_;
// Allocated space for fallback stubs.
FallbackICStubSpace fallbackStubSpace_;

View File

@ -3208,6 +3208,27 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink, AutoLockGC& lock)
decommitArenas(lock);
}
// In debug builds, set/unset the background sweeping flag on the zone.
struct AutoSetZoneBackgroundSweeping
{
#ifdef DEBUG
explicit AutoSetZoneBackgroundSweeping(Zone* zone)
: zone_(zone)
{
zone_->setGCBackgroundSweeping(true);
}
~AutoSetZoneBackgroundSweeping() {
zone_->setGCBackgroundSweeping(false);
}
private:
Zone* zone_;
#else
AutoSetZoneBackgroundSweeping(Zone* zone) {}
#endif
};
void
GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadType threadType)
{
@ -3221,6 +3242,7 @@ GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadT
FreeOp fop(rt, threadType);
for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) {
for (Zone* zone = zones.front(); zone; zone = zone->nextZone()) {
AutoSetZoneBackgroundSweeping zbs(zone);
for (unsigned index = 0 ; index < BackgroundFinalizePhases[phase].length ; ++index) {
AllocKind kind = BackgroundFinalizePhases[phase].kinds[index];
ArenaHeader* arenas = zone->arenas.arenaListsToSweep[kind];

View File

@ -201,7 +201,7 @@ class Bindings
friend class BindingIter;
friend class AliasedFormalIter;
HeapPtrShape callObjShape_;
RelocatablePtrShape callObjShape_;
uintptr_t bindingArrayAndFlag_;
uint16_t numArgs_;
uint16_t numBlockScoped_;

View File

@ -21,19 +21,19 @@ class RegExpStatics
{
/* The latest RegExp output, set after execution. */
VectorMatchPairs matches;
HeapPtrLinearString matchesInput;
RelocatablePtrLinearString matchesInput;
/*
* The previous RegExp input, used to resolve lazy state.
* A raw RegExpShared cannot be stored because it may be in
* a different compartment via evalcx().
*/
HeapPtrAtom lazySource;
RelocatablePtrAtom lazySource;
RegExpFlag lazyFlags;
size_t lazyIndex;
/* The latest RegExp input, set before execution. */
HeapPtrString pendingInput;
RelocatablePtrString pendingInput;
RegExpFlag flags;
/*

View File

@ -799,7 +799,7 @@ class PreliminaryObjectArray
class PreliminaryObjectArrayWithTemplate : public PreliminaryObjectArray
{
HeapPtrShape shape_;
RelocatablePtrShape shape_;
public:
explicit PreliminaryObjectArrayWithTemplate(Shape* shape)
@ -872,7 +872,7 @@ class TypeNewScript
private:
// Scripted function which this information was computed for.
HeapPtrFunction function_;
RelocatablePtrFunction function_;
// Any preliminary objects with the type. The analyses are not performed
// until this array is cleared.
@ -884,7 +884,7 @@ class TypeNewScript
// allocation kind to use. This is null if the new objects have an unboxed
// layout, in which case the UnboxedLayout provides the initial structure
// of the object.
HeapPtrPlainObject templateObject_;
RelocatablePtrPlainObject templateObject_;
// Order in which definite properties become initialized. We need this in
// case the definite properties are invalidated (such as by adding a setter
@ -901,11 +901,11 @@ class TypeNewScript
// shape contains all such additional properties (plus the definite
// properties). When an object of this group acquires this shape, it is
// fully initialized and its group can be changed to initializedGroup.
HeapPtrShape initializedShape_;
RelocatablePtrShape initializedShape_;
// Group with definite properties set for all properties found by
// both the definite and acquired properties analyses.
HeapPtrObjectGroup initializedGroup_;
RelocatablePtrObjectGroup initializedGroup_;
public:
TypeNewScript() { mozilla::PodZero(this); }

View File

@ -109,6 +109,10 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group)
for (GeneralRegisterForwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter)
masm.Push(*iter);
// The scratch double register might be used by MacroAssembler methods.
if (ScratchDoubleReg.volatile_())
masm.push(ScratchDoubleReg);
Label failure, tenuredObject, allocated;
masm.branch32(Assembler::NotEqual, newKindReg, Imm32(GenericObject), &tenuredObject);
masm.branchTest32(Assembler::NonZero, AbsoluteAddress(group->addressOfFlags()),
@ -206,6 +210,8 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group)
masm.movePtr(object, ReturnReg);
// Restore non-volatile registers which were saved on entry.
if (ScratchDoubleReg.volatile_())
masm.pop(ScratchDoubleReg);
for (GeneralRegisterBackwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter)
masm.Pop(*iter);
@ -650,7 +656,10 @@ UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup
}
#ifndef JS_CODEGEN_NONE
if (cx->isJSContext() && !layout.constructorCode()) {
if (cx->isJSContext() &&
!layout.constructorCode() &&
cx->asJSContext()->runtime()->jitSupportsFloatingPoint)
{
if (!UnboxedLayout::makeConstructorCode(cx->asJSContext(), group))
return nullptr;
}

View File

@ -625,6 +625,12 @@ nsPluginFrame::CallSetWindow(bool aCheckIsHidden)
nsRect bounds = GetContentRectRelativeToSelf() + GetOffsetToCrossDoc(rootFrame);
nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
// In e10s, this returns the offset to the top level window, in non-e10s
// it return 0,0.
LayoutDeviceIntPoint intOffset = GetRemoteTabChromeOffset();
intBounds.x += intOffset.x;
intBounds.y += intOffset.y;
// window must be in "display pixels"
double scaleFactor = 1.0;
if (NS_FAILED(mInstanceOwner->GetContentsScaleFactor(&scaleFactor))) {
@ -753,7 +759,30 @@ nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const
return false;
}
nsIntPoint nsPluginFrame::GetWindowOriginInPixels(bool aWindowless)
mozilla::LayoutDeviceIntPoint
nsPluginFrame::GetRemoteTabChromeOffset()
{
LayoutDeviceIntPoint offset;
if (XRE_GetProcessType() == GeckoProcessType_Content) {
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetContent()->OwnerDoc()->GetWindow());
if (window) {
nsCOMPtr<nsIDOMWindow> topWindow;
window->GetTop(getter_AddRefs(topWindow));
if (topWindow) {
dom::TabChild* tc = dom::TabChild::GetFrom(topWindow);
if (tc) {
LayoutDeviceIntPoint chromeOffset;
tc->SendGetTabOffset(&chromeOffset);
offset -= chromeOffset;
}
}
}
}
return offset;
}
nsIntPoint
nsPluginFrame::GetWindowOriginInPixels(bool aWindowless)
{
nsView * parentWithView;
nsPoint origin(0,0);
@ -769,8 +798,19 @@ nsIntPoint nsPluginFrame::GetWindowOriginInPixels(bool aWindowless)
}
origin += GetContentRectRelativeToSelf().TopLeft();
return nsIntPoint(PresContext()->AppUnitsToDevPixels(origin.x),
PresContext()->AppUnitsToDevPixels(origin.y));
nsIntPoint pt(PresContext()->AppUnitsToDevPixels(origin.x),
PresContext()->AppUnitsToDevPixels(origin.y));
// If we're in the content process offsetToWidget is tied to the top level
// widget we can access in the child process, which is the tab. We need the
// offset all the way up to the top level native window here. (If this is
// non-e10s this routine will return 0,0.)
if (aWindowless) {
mozilla::LayoutDeviceIntPoint lpt = GetRemoteTabChromeOffset();
pt += nsIntPoint(lpt.x, lpt.y);
}
return pt;
}
void

View File

@ -14,6 +14,7 @@
#include "nsRegion.h"
#include "nsDisplayList.h"
#include "nsIReflowCallback.h"
#include "Units.h"
#ifdef XP_WIN
#include <windows.h> // For HWND :(
@ -220,6 +221,13 @@ protected:
bool IsPaintedByGecko() const;
nsIntPoint GetWindowOriginInPixels(bool aWindowless);
/*
* If this frame is in a remote tab, return the tab offset to
* the origin of the chrome window. In non-e10s, this return 0,0.
* This api sends a sync ipc request so be careful about use.
*/
mozilla::LayoutDeviceIntPoint GetRemoteTabChromeOffset();
static void PaintPrintPlugin(nsIFrame* aFrame,
nsRenderingContext* aRenderingContext,

View File

@ -0,0 +1,10 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -10 20 20" preserveAspectRatio="none"
font-family="sans-serif">
<rect y="-10" width="20" height="20" fill="lime"/>
<text dominant-baseline="middle" fill="red">x</text>
<text y="0.5ex" fill="lime" stroke-width="1" stroke="lime">x</text>
</svg>

After

Width:  |  Height:  |  Size: 423 B

View File

@ -26,6 +26,7 @@ include moz-only/reftest.list
include svg-integration/reftest.list
== altGlyph-01.svg altGlyph-01-ref.svg
== baseline-middle-01.svg pass.svg
== border-radius-01.html pass.svg
== cssComment-in-attribute-01.svg cssComment-in-attribute-01-ref.svg
== clip-01.svg pass.svg

View File

@ -337,7 +337,8 @@ IsGlyphPositioningAttribute(nsIAtom* aAttribute)
static nscoord
GetBaselinePosition(nsTextFrame* aFrame,
gfxTextRun* aTextRun,
uint8_t aDominantBaseline)
uint8_t aDominantBaseline,
float aFontSizeScaleFactor)
{
// use a dummy WritingMode, because nsTextFrame::GetLogicalBaseLine
// doesn't use it anyway
@ -356,6 +357,10 @@ GetBaselinePosition(nsTextFrame* aFrame,
case NS_STYLE_DOMINANT_BASELINE_AUTO:
case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
return aFrame->GetLogicalBaseline(writingMode);
case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
return aFrame->GetLogicalBaseline(writingMode) -
SVGContentUtils::GetFontXHeight(aFrame) / 2.0 *
aFrame->PresContext()->AppUnitsPerCSSPixel() * aFontSizeScaleFactor;
}
gfxTextRun::Metrics metrics =
@ -367,7 +372,6 @@ GetBaselinePosition(nsTextFrame* aFrame,
case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
return metrics.mAscent + metrics.mDescent;
case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
return (metrics.mAscent + metrics.mDescent) / 2.0;
}
@ -1993,7 +1997,8 @@ TextRenderedRunIterator::Next()
frame->EnsureTextRun(nsTextFrame::eInflated);
baseline = GetBaselinePosition(frame,
frame->GetTextRun(nsTextFrame::eInflated),
mFrameIterator.DominantBaseline());
mFrameIterator.DominantBaseline(),
mFontSizeScaleFactor);
// Trim the offset/length to remove any leading/trailing white space.
uint32_t untrimmedOffset = offset;
@ -4607,7 +4612,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray<nsPoint>& aPositions)
if (textRun->IsRightToLeft()) {
position.x += frame->GetRect().width;
}
position.y += GetBaselinePosition(frame, textRun, frit.DominantBaseline());
position.y += GetBaselinePosition(frame, textRun, frit.DominantBaseline(),
mFontSizeScaleFactor);
// Any characters not in a frame, e.g. when display:none.
for (uint32_t i = 0; i < frit.UndisplayedCharacters(); i++) {

View File

@ -297,14 +297,16 @@ final class GeckoEditable
}
}
/**
* Remove the head of the queue. Throw if queue is empty.
*/
void poll() {
if (DEBUG) {
ThreadUtils.assertOnGeckoThread();
}
if (mActions.isEmpty()) {
if (mActions.poll() == null) {
throw new IllegalStateException("empty actions queue");
}
mActions.poll();
synchronized(this) {
if (mActions.isEmpty()) {
@ -313,13 +315,15 @@ final class GeckoEditable
}
}
/**
* Return, but don't remove, the head of the queue, or null if queue is empty.
*
* @return head of the queue or null if empty.
*/
Action peek() {
if (DEBUG) {
ThreadUtils.assertOnGeckoThread();
}
if (mActions.isEmpty()) {
throw new IllegalStateException("empty actions queue");
}
return mActions.peek();
}
@ -669,7 +673,11 @@ final class GeckoEditable
// GeckoEditableListener methods should all be called from the Gecko thread
ThreadUtils.assertOnGeckoThread();
}
final Action action = mActionQueue.peek();
if (action == null) {
throw new IllegalStateException("empty actions queue");
}
if (DEBUG) {
Log.d(LOGTAG, "reply: Action(" +
@ -834,8 +842,8 @@ final class GeckoEditable
/* An event (keypress, etc.) has potentially changed the selection,
synchronize the selection here. There is not a race with the IC thread
because the IC thread should be blocked on the event action */
if (!mActionQueue.isEmpty() &&
mActionQueue.peek().mType == Action.TYPE_EVENT) {
final Action action = mActionQueue.peek();
if (action != null && action.mType == Action.TYPE_EVENT) {
Selection.setSelection(mText, start, end);
return;
}
@ -868,6 +876,11 @@ final class GeckoEditable
mText.insert(start, newText);
}
private boolean isSameText(int start, int oldEnd, CharSequence newText) {
return oldEnd - start == newText.length() &&
TextUtils.regionMatches(mText, start, newText, 0, oldEnd - start);
}
@Override
public void onTextChange(final CharSequence text, final int start,
final int unboundedOldEnd, final int unboundedNewEnd) {
@ -909,46 +922,51 @@ final class GeckoEditable
TextUtils.copySpansFrom(mText, start, Math.min(oldEnd, newEnd),
Object.class, mChangedText, 0);
if (!mActionQueue.isEmpty()) {
final Action action = mActionQueue.peek();
if ((action.mType == Action.TYPE_REPLACE_TEXT ||
action.mType == Action.TYPE_COMPOSE_TEXT) &&
start <= action.mStart &&
action.mStart + action.mSequence.length() <= newEnd) {
final Action action = mActionQueue.peek();
if (action != null &&
(action.mType == Action.TYPE_REPLACE_TEXT ||
action.mType == Action.TYPE_COMPOSE_TEXT) &&
start <= action.mStart &&
action.mStart + action.mSequence.length() <= newEnd) {
// actionNewEnd is the new end of the original replacement action
final int actionNewEnd = action.mStart + action.mSequence.length();
int selStart = Selection.getSelectionStart(mText);
int selEnd = Selection.getSelectionEnd(mText);
// actionNewEnd is the new end of the original replacement action
final int actionNewEnd = action.mStart + action.mSequence.length();
int selStart = Selection.getSelectionStart(mText);
int selEnd = Selection.getSelectionEnd(mText);
// Replace old spans with new spans
mChangedText.replace(action.mStart - start, actionNewEnd - start,
action.mSequence);
geckoReplaceText(start, oldEnd, mChangedText);
// Replace old spans with new spans
mChangedText.replace(action.mStart - start, actionNewEnd - start,
action.mSequence);
geckoReplaceText(start, oldEnd, mChangedText);
// delete/insert above might have moved our selection to somewhere else
// this happens when the Gecko text change covers a larger range than
// the original replacement action. Fix selection here
if (selStart >= start && selStart <= oldEnd) {
selStart = selStart < action.mStart ? selStart :
selStart < action.mEnd ? actionNewEnd :
selStart + actionNewEnd - action.mEnd;
mText.setSpan(Selection.SELECTION_START, selStart, selStart,
Spanned.SPAN_POINT_POINT);
}
if (selEnd >= start && selEnd <= oldEnd) {
selEnd = selEnd < action.mStart ? selEnd :
selEnd < action.mEnd ? actionNewEnd :
selEnd + actionNewEnd - action.mEnd;
mText.setSpan(Selection.SELECTION_END, selEnd, selEnd,
Spanned.SPAN_POINT_POINT);
}
} else {
geckoReplaceText(start, oldEnd, mChangedText);
// delete/insert above might have moved our selection to somewhere else
// this happens when the Gecko text change covers a larger range than
// the original replacement action. Fix selection here
if (selStart >= start && selStart <= oldEnd) {
selStart = selStart < action.mStart ? selStart :
selStart < action.mEnd ? actionNewEnd :
selStart + actionNewEnd - action.mEnd;
mText.setSpan(Selection.SELECTION_START, selStart, selStart,
Spanned.SPAN_POINT_POINT);
}
if (selEnd >= start && selEnd <= oldEnd) {
selEnd = selEnd < action.mStart ? selEnd :
selEnd < action.mEnd ? actionNewEnd :
selEnd + actionNewEnd - action.mEnd;
mText.setSpan(Selection.SELECTION_END, selEnd, selEnd,
Spanned.SPAN_POINT_POINT);
}
} else {
// Gecko side initiated the text change.
if (isSameText(start, oldEnd, mChangedText)) {
// Nothing to do because the text is the same.
// This could happen when the composition is updated for example.
return;
}
geckoReplaceText(start, oldEnd, mChangedText);
}
geckoPostToIc(new Runnable() {
@Override
public void run() {

View File

@ -385,6 +385,12 @@ var SelectionHandler = {
return this.START_ERROR_NONTEXT_INPUT;
}
const focus = Services.focus.focusedWindow;
if (focus) {
// Make sure any previous focus is cleared.
Services.focus.clearFocus(focus);
}
this._initTargetInfo(aElement, this.TYPE_SELECTION);
// Perform the appropriate selection method, if we can't determine method, or it fails, return

View File

@ -184,8 +184,8 @@ public:
NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages) override;
NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable) override;
NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable) override;
NS_IMETHOD GetNetworkInterfaceId(nsACString& aNetworkInterfaceId);
NS_IMETHOD SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId);
NS_IMETHOD GetNetworkInterfaceId(nsACString& aNetworkInterfaceId) override;
NS_IMETHOD SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId) override;
NS_IMETHOD AddRedirect(nsIPrincipal *aRedirect) override;
NS_IMETHOD ForcePending(bool aForcePending) override;
NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime) override;

View File

@ -13,8 +13,6 @@ const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1";
const nsIPKIParamBlock = Components.interfaces.nsIPKIParamBlock;
const nsPKIParamBlock = "@mozilla.org/security/pkiparamblock;1";
const nsINSSCertCache = Components.interfaces.nsINSSCertCache;
const nsNSSCertCache = "@mozilla.org/security/nsscertcache;1";
const gCertFileTypes = "*.p7b; *.crt; *.cert; *.cer; *.pem; *.der";
@ -52,9 +50,7 @@ function LoadCerts()
Services.obs.addObserver(smartCardObserver, "smartcard-remove", false);
certdb = Components.classes[nsX509CertDB].getService(nsIX509CertDB);
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
certcache.cacheAllCerts();
var certcache = certdb.getCerts();
caTreeView = Components.classes[nsCertTree]
.createInstance(nsICertTree);
@ -378,8 +374,7 @@ function restoreCerts()
certdb.importPKCS12File(null, fp.file);
}
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
certcache.cacheAllCerts();
var certcache = certdb.getCerts();
userTreeView.loadCertsFromCache(certcache, nsIX509Cert.USER_CERT);
userTreeView.selection.clearSelection();
caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
@ -521,10 +516,9 @@ function addCACerts()
function onSmartCardChange()
{
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
var certcache = certdb.getCerts();
// We've change the state of the smart cards inserted or removed
// that means the available certs may have changed. Update the display
certcache.cacheAllCerts();
userTreeView.loadCertsFromCache(certcache, nsIX509Cert.USER_CERT);
userTreeView.selection.clearSelection();
caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
@ -549,8 +543,7 @@ function addEmailCert()
fp.appendFilters(nsIFilePicker.filterAll);
if (fp.show() == nsIFilePicker.returnOK) {
certdb.importCertsFromFile(null, fp.file, nsIX509Cert.EMAIL_CERT);
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
certcache.cacheAllCerts();
var certcache = certdb.getCerts();
emailTreeView.loadCertsFromCache(certcache, nsIX509Cert.EMAIL_CERT);
emailTreeView.selection.clearSelection();
caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
@ -571,8 +564,7 @@ function addWebSiteCert()
if (fp.show() == nsIFilePicker.returnOK) {
certdb.importCertsFromFile(null, fp.file, nsIX509Cert.SERVER_CERT);
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
certcache.cacheAllCerts();
var certcache = certdb.getCerts();
serverTreeView.loadCertsFromCache(certcache, nsIX509Cert.SERVER_CERT);
serverTreeView.selection.clearSelection();
caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
@ -584,8 +576,7 @@ function addException()
{
window.openDialog('chrome://pippki/content/exceptionDialog.xul', "",
'chrome,centerscreen,modal');
var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
certcache.cacheAllCerts();
var certcache = certdb.getCerts();
serverTreeView.loadCertsFromCache(certcache, nsIX509Cert.SERVER_CERT);
serverTreeView.selection.clearSelection();
orphanTreeView.loadCertsFromCache(certcache, nsIX509Cert.UNKNOWN_CERT);

View File

@ -18,7 +18,6 @@ XPIDL_SOURCES += [
'nsIGenKeypairInfoDlg.idl',
'nsIKeygenThread.idl',
'nsIKeyModule.idl',
'nsINSSCertCache.idl',
'nsINSSVersion.idl',
'nsIPK11Token.idl',
'nsIPK11TokenDB.idl',

View File

@ -7,8 +7,8 @@
#include "nsISupports.idl"
#include "nsITreeView.idl"
interface nsINSSCertCache;
interface nsIX509Cert;
interface nsIX509CertList;
[scriptable, uuid(d0180863-606e-49e6-8324-cf45ed4dd891)]
interface nsICertTreeItem : nsISupports {
@ -16,16 +16,16 @@ interface nsICertTreeItem : nsISupports {
readonly attribute AString hostPort;
};
[scriptable, uuid(a8cd1c89-a901-4735-831b-7198b7b8b6b1)]
[scriptable, uuid(55d5ad6b-5572-47fe-941c-f01fe723659e)]
interface nsICertTree : nsITreeView {
void loadCerts(in unsigned long type);
void loadCertsFromCache(in nsINSSCertCache cache, in unsigned long type);
void loadCertsFromCache(in nsIX509CertList cache, in unsigned long type);
nsIX509Cert getCert(in unsigned long index);
nsICertTreeItem getTreeItem(in unsigned long index);
boolean isHostPortOverride(in unsigned long index);
void deleteEntryObject(in unsigned long index);
};

View File

@ -1,44 +0,0 @@
/* 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/. */
#include "nsISupports.idl"
interface nsIX509CertList;
[scriptable, uuid(1b75bdae-1757-4322-9d1e-cfcaa18cb710)]
interface nsINSSCertCache : nsISupports {
/*
* cacheAllCerts
*
* Creates a cache of all certificates currently known to NSS.
*/
void cacheAllCerts();
void cacheCertList(in nsIX509CertList list);
/*
* get an X509CertList
*/
nsIX509CertList getX509CachedCerts();
/*
* getCachedCerts
*
* Returns the cached CERTCertList*
*/
[notxpcom, noscript] voidPtr getCachedCerts();
};
%{C++
#define NS_NSSCERTCACHE_CID { /* 3f429a14-dffe-417d-8cb8-fdf09bacd09e */ \
0x3f429a14, \
0xdffe, \
0x417d, \
{0x8c, 0xb8, 0xfd, 0xf0, 0x9b, 0xac, 0xd0, 0x9e} \
}
#define NS_NSSCERTCACHE_CONTRACTID "@mozilla.org/security/nsscertcache;1"
%}

View File

@ -38,7 +38,6 @@ UNIFIED_SOURCES += [
'nsKeyModule.cpp',
'nsNSSASN1Object.cpp',
'nsNSSCallbacks.cpp',
'nsNSSCertCache.cpp',
'nsNSSCertHelper.cpp',
'nsNSSCertificate.cpp',
'nsNSSCertificateFakeTransport.cpp',

View File

@ -15,14 +15,13 @@
#include "nsUnicharUtils.h"
#include "nsNSSCertificate.h"
#include "nsNSSCertHelper.h"
#include "nsINSSCertCache.h"
#include "nsIMutableArray.h"
#include "nsArrayUtils.h"
#include "nsISupportsPrimitives.h"
#include "nsXPCOMCID.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "prlog.h"
using namespace mozilla;
@ -631,14 +630,23 @@ nsCertTree::GetCertsByType(uint32_t aType,
aCertCmpFnArg);
}
nsresult
nsCertTree::GetCertsByTypeFromCache(nsINSSCertCache *aCache,
nsresult
nsCertTree::GetCertsByTypeFromCache(nsIX509CertList *aCache,
uint32_t aType,
nsCertCompareFunc aCertCmpFn,
void *aCertCmpFnArg)
{
NS_ENSURE_ARG_POINTER(aCache);
CERTCertList *certList = reinterpret_cast<CERTCertList*>(aCache->GetCachedCerts());
// GetRawCertList checks for NSS shutdown since we can't do it ourselves here
// easily. We still have to acquire a shutdown prevention lock to prevent NSS
// shutting down after GetRawCertList has returned. While cumbersome, this is
// at least mostly correct. The rest of this implementation doesn't even go
// this far in attempting to check for or prevent NSS shutdown at the
// appropriate times. If this were reimplemented at a higher level using
// more encapsulated types that handled NSS shutdown themselves, we wouldn't
// be having these kinds of problems.
nsNSSShutDownPreventionLock locker;
CERTCertList *certList = reinterpret_cast<CERTCertList*>(aCache->GetRawCertList());
if (!certList)
return NS_ERROR_FAILURE;
return GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg);
@ -648,8 +656,8 @@ nsCertTree::GetCertsByTypeFromCache(nsINSSCertCache *aCache,
//
// Load all of the certificates in the DB for this type. Sort them
// by token, organization, then common name.
NS_IMETHODIMP
nsCertTree::LoadCertsFromCache(nsINSSCertCache *aCache, uint32_t aType)
NS_IMETHODIMP
nsCertTree::LoadCertsFromCache(nsIX509CertList *aCache, uint32_t aType)
{
if (mTreeArray) {
FreeCertArray();

View File

@ -114,7 +114,7 @@ protected:
nsresult GetCertsByType(uint32_t aType, nsCertCompareFunc aCertCmpFn,
void *aCertCmpFnArg);
nsresult GetCertsByTypeFromCache(nsINSSCertCache *aCache, uint32_t aType,
nsresult GetCertsByTypeFromCache(nsIX509CertList *aCache, uint32_t aType,
nsCertCompareFunc aCertCmpFn, void *aCertCmpFnArg);
private:
nsTArray< mozilla::RefPtr<nsCertTreeDispInfo> > mDispInfo;

View File

@ -1,103 +0,0 @@
/* 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/. */
#include "nsNSSCertCache.h"
#include "nsNSSCertificate.h"
#include "cert.h"
#include "nsCOMPtr.h"
#include "nsIInterfaceRequestor.h"
#include "nsNSSHelper.h"
using namespace mozilla;
NS_IMPL_ISUPPORTS(nsNSSCertCache, nsINSSCertCache)
nsNSSCertCache::nsNSSCertCache()
:mutex("nsNSSCertCache.mutex"), mCertList(nullptr)
{
}
nsNSSCertCache::~nsNSSCertCache()
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return;
}
destructorSafeDestroyNSSReference();
shutdown(calledFromObject);
}
void nsNSSCertCache::virtualDestroyNSSReference()
{
destructorSafeDestroyNSSReference();
}
void nsNSSCertCache::destructorSafeDestroyNSSReference()
{
}
NS_IMETHODIMP
nsNSSCertCache::CacheAllCerts()
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
ScopedCERTCertList newList(PK11_ListCerts(PK11CertListUnique, cxt));
if (newList) {
MutexAutoLock lock(mutex);
mCertList = new nsNSSCertList(newList, locker);
}
return NS_OK;
}
NS_IMETHODIMP
nsNSSCertCache::CacheCertList(nsIX509CertList *list)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
{
MutexAutoLock lock(mutex);
mCertList = list;
//NS_ADDREF(mCertList);
}
return NS_OK;
}
NS_IMETHODIMP
nsNSSCertCache::GetX509CachedCerts(nsIX509CertList **list)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
{
MutexAutoLock lock(mutex);
if (!mCertList) {
return NS_ERROR_NOT_AVAILABLE;
}
*list = mCertList;
NS_ADDREF(*list);
}
return NS_OK;
}
void* nsNSSCertCache::GetCachedCerts()
{
if (isAlreadyShutDown())
return nullptr;
MutexAutoLock lock(mutex);
return mCertList->GetRawCertList();
}

View File

@ -1,34 +0,0 @@
/* 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/. */
#ifndef _NSNSSCERTCACHE_H_
#define _NSNSSCERTCACHE_H_
#include "nsINSSCertCache.h"
#include "nsIX509CertList.h"
#include "certt.h"
#include "mozilla/Mutex.h"
#include "nsNSSShutDown.h"
#include "nsCOMPtr.h"
class nsNSSCertCache : public nsINSSCertCache,
public nsNSSShutDownObject
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSINSSCERTCACHE
nsNSSCertCache();
protected:
virtual ~nsNSSCertCache();
private:
mozilla::Mutex mutex;
nsCOMPtr<nsIX509CertList> mCertList;
virtual void virtualDestroyNSSReference() override;
void destructorSafeDestroyNSSReference();
};
#endif

View File

@ -1626,8 +1626,17 @@ nsNSSCertList::DupCertList(CERTCertList* aCertList,
void*
nsNSSCertList::GetRawCertList()
{
// This function should only be called after adquiring a
// nsNSSShutDownPreventionLock
// This function should only be called after acquiring a
// nsNSSShutDownPreventionLock. It's difficult to enforce this in code since
// this is an implementation of an XPCOM interface function (albeit a
// C++-only one), so we acquire the (reentrant) lock and check for shutdown
// ourselves here. At the moment it appears that only nsCertTree uses this
// function. When that gets removed and replaced by a more reasonable
// implementation of the certificate manager, this function can be removed.
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return nullptr;
}
return mCertList.get();
}

View File

@ -20,7 +20,6 @@
#include "nsNSSCertificate.h"
#include "nsNSSHelper.h"
#include "nsNSSCertHelper.h"
#include "nsNSSCertCache.h"
#include "nsCRT.h"
#include "nsICertificateDialogs.h"
#include "nsNSSCertTrust.h"

View File

@ -18,7 +18,6 @@
#include "nsNSSCertificate.h"
#include "nsNSSCertificateFakeTransport.h"
#include "nsNSSCertificateDB.h"
#include "nsNSSCertCache.h"
#ifdef MOZ_XUL
#include "nsCertTree.h"
#endif
@ -188,7 +187,6 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_BYPROCESS(nssEnsureOnChromeOnly,
nsNSSCertificate,
nsNSSCertificateFakeTransport)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsNSSCertificateDB)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsNSSCertCache)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_BYPROCESS(nssEnsureOnChromeOnly,
nsNSSCertList,
nsNSSCertListFakeTransport)
@ -222,7 +220,6 @@ NS_DEFINE_NAMED_CID(NS_PSMCONTENTLISTEN_CID);
NS_DEFINE_NAMED_CID(NS_X509CERT_CID);
NS_DEFINE_NAMED_CID(NS_X509CERTDB_CID);
NS_DEFINE_NAMED_CID(NS_X509CERTLIST_CID);
NS_DEFINE_NAMED_CID(NS_NSSCERTCACHE_CID);
NS_DEFINE_NAMED_CID(NS_FORMPROCESSOR_CID);
#ifdef MOZ_XUL
NS_DEFINE_NAMED_CID(NS_CERTTREE_CID);
@ -253,7 +250,6 @@ static const mozilla::Module::CIDEntry kNSSCIDs[] = {
{ &kNS_X509CERT_CID, false, nullptr, nsNSSCertificateConstructor },
{ &kNS_X509CERTDB_CID, false, nullptr, nsNSSCertificateDBConstructor },
{ &kNS_X509CERTLIST_CID, false, nullptr, nsNSSCertListConstructor },
{ &kNS_NSSCERTCACHE_CID, false, nullptr, nsNSSCertCacheConstructor },
{ &kNS_FORMPROCESSOR_CID, false, nullptr, nsKeygenFormProcessor::Create },
#ifdef MOZ_XUL
{ &kNS_CERTTREE_CID, false, nullptr, nsCertTreeConstructor },
@ -287,7 +283,6 @@ static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
{ NS_PSMCONTENTLISTEN_CONTRACTID, &kNS_PSMCONTENTLISTEN_CID },
{ NS_X509CERTDB_CONTRACTID, &kNS_X509CERTDB_CID },
{ NS_X509CERTLIST_CONTRACTID, &kNS_X509CERTLIST_CID },
{ NS_NSSCERTCACHE_CONTRACTID, &kNS_NSSCERTCACHE_CID },
{ NS_FORMPROCESSOR_CONTRACTID, &kNS_FORMPROCESSOR_CID },
#ifdef MOZ_XUL
{ NS_CERTTREE_CONTRACTID, &kNS_CERTTREE_CID },

View File

@ -20,10 +20,9 @@ function onUnload() {
// does not cause assertion failures.
function test() {
waitForExplicitFinish();
let certCache = Cc["@mozilla.org/security/nsscertcache;1"]
.getService(Ci.nsINSSCertCache);
certCache.cacheAllCerts();
let certList = certCache.getX509CachedCerts();
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
let certList = certdb.getCerts();
let enumerator = certList.getEnumerator();
ok(enumerator.hasMoreElements(), "we have at least one certificate");
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);

View File

@ -184,7 +184,7 @@ let TimelineActor = exports.TimelineActor = protocol.ActorClass({
let markers = [];
for (let docShell of this.docShells) {
markers = [...markers, ...docShell.popProfileTimelineMarkers()];
markers.push(...docShell.popProfileTimelineMarkers());
}
// The docshell may return markers with stack traces attached.

View File

@ -217,10 +217,10 @@ private:
void* const mStackTop;
ThreadResponsiveness mRespInfo;
// Only Linux is using a signal sender, instead of stopping the thread, so we
// Linux and OSX use a signal sender, instead of stopping the thread, so we
// need some space to store the data which cannot be collected in the signal
// handler code.
#ifdef XP_LINUX
#if defined(XP_LINUX) || defined(XP_MACOSX)
public:
int64_t mRssMemory;
int64_t mUssMemory;

View File

@ -57,11 +57,38 @@ struct SamplerRegistry {
Sampler *SamplerRegistry::sampler = NULL;
// The following variables are used to communicate between the signal
// sender thread and the signal handler on the sampled thread.
//
// sCurrentThreadProfile is used to pass the current thread profile INTO
// the signal handler. sSignalHandlingDone is used by the handler to
// indicate when it's finished. The signal-sender thread spins on
// sSignalHandlingDone (using sched_yield). This is to avoid usage of
// synchronization primitives like condvars in the signal handler code.
static mozilla::Atomic<ThreadProfile*> sCurrentThreadProfile;
static mozilla::Atomic<bool> sSignalHandlingDone;
#ifdef DEBUG
// 0 is never a valid thread id on MacOSX since a pthread_t is a pointer.
static const pthread_t kNoThread = (pthread_t) 0;
#endif
static void SetSampleContext(TickSample* sample, void* context)
{
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t& mcontext = ucontext->uc_mcontext;
#if defined(SPS_PLAT_amd64_darwin)
sample->pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
sample->sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
sample->fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
#elif defined(SPS_PLAT_x86_darwin)
sample->pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
sample->sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
sample->fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
#endif
}
void OS::Startup() {
}
@ -133,6 +160,48 @@ void Thread::Join() {
pthread_join(thread_, NULL);
}
namespace {
void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
if (!Sampler::GetActiveSampler()) {
sSignalHandlingDone = true;
return;
}
TickSample sample_obj;
TickSample* sample = &sample_obj;
sample->context = context;
// If profiling, we extract the current pc and sp.
if (Sampler::GetActiveSampler()->IsProfiling()) {
SetSampleContext(sample, context);
}
sample->threadProfile = sCurrentThreadProfile;
sample->timestamp = mozilla::TimeStamp::Now();
sample->rssMemory = sample->threadProfile->mRssMemory;
sample->ussMemory = sample->threadProfile->mUssMemory;
Sampler::GetActiveSampler()->Tick(sample);
sCurrentThreadProfile = NULL;
sSignalHandlingDone = true;
}
} // namespace
static void ProfilerSignalThread(ThreadProfile *profile,
bool isFirstProfiledThread)
{
if (isFirstProfiledThread && Sampler::GetActiveSampler()->ProfileMemory()) {
profile->mRssMemory = nsMemoryReporterManager::ResidentFast();
profile->mUssMemory = nsMemoryReporterManager::ResidentUnique();
} else {
profile->mRssMemory = 0;
profile->mUssMemory = 0;
}
}
class PlatformData : public Malloced {
public:
PlatformData() : profiled_thread_(mach_thread_self())
@ -226,6 +295,9 @@ class SamplerThread : public Thread {
info->Profile()->GetThreadResponsiveness()->Update();
ThreadProfile* thread_profile = info->Profile();
sCurrentThreadProfile = thread_profile;
ProfilerSignalThread(sCurrentThreadProfile, isFirstProfiledThread);
SampleContext(SamplerRegistry::sampler, thread_profile,
isFirstProfiledThread);
@ -246,58 +318,15 @@ class SamplerThread : public Thread {
void SampleContext(Sampler* sampler, ThreadProfile* thread_profile,
bool isFirstProfiledThread)
{
thread_act_t profiled_thread =
thread_profile->GetPlatformData()->profiled_thread();
pthread_t profiled_pthread =
thread_profile->GetPlatformData()->profiled_pthread();
TickSample sample_obj;
TickSample* sample = &sample_obj;
if (isFirstProfiledThread && Sampler::GetActiveSampler()->ProfileMemory()) {
sample->rssMemory = nsMemoryReporterManager::ResidentFast();
} else {
sample->rssMemory = 0;
MOZ_ASSERT(sSignalHandlingDone == false);
pthread_kill(profiled_pthread, SIGPROF);
while (!sSignalHandlingDone) {
sched_yield();
}
// Unique Set Size is not supported on Mac.
sample->ussMemory = 0;
if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
#if V8_HOST_ARCH_X64
thread_state_flavor_t flavor = x86_THREAD_STATE64;
x86_thread_state64_t state;
mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __r ## name
#else
#define REGISTER_FIELD(name) r ## name
#endif // __DARWIN_UNIX03
#elif V8_HOST_ARCH_IA32
thread_state_flavor_t flavor = i386_THREAD_STATE;
i386_thread_state_t state;
mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __e ## name
#else
#define REGISTER_FIELD(name) e ## name
#endif // __DARWIN_UNIX03
#else
#error Unsupported Mac OS X host architecture.
#endif // V8_HOST_ARCH
if (thread_get_state(profiled_thread,
flavor,
reinterpret_cast<natural_t*>(&state),
&count) == KERN_SUCCESS) {
sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
sample->timestamp = mozilla::TimeStamp::Now();
sample->threadProfile = thread_profile;
sampler->Tick(sample);
}
thread_resume(profiled_thread);
sSignalHandlingDone = false;
}
int intervalMicro_;
@ -330,8 +359,29 @@ Sampler::~Sampler() {
void Sampler::Start() {
ASSERT(!IsActive());
// Initialize signal handler communication
sCurrentThreadProfile = NULL;
sSignalHandlingDone = false;
// Request profiling signals.
LOG("Request signal");
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGPROF, &sa, &old_sigprof_signal_handler_) != 0) {
LOG("Error installing signal");
return;
}
signal_handler_installed_ = true;
// Start a thread that sends SIGPROF signal to VM thread.
// Sending the signal ourselves instead of relying on itimer provides
// much better accuracy.
SetActive(true);
SamplerThread::AddActiveSampler(this);
LOG("Profiler thread started");
}
@ -339,6 +389,12 @@ void Sampler::Stop() {
ASSERT(IsActive());
SetActive(false);
SamplerThread::RemoveActiveSampler(this);
// Restore old signal handler
if (signal_handler_installed_) {
sigaction(SIGPROF, &old_sigprof_signal_handler_, 0);
signal_handler_installed_ = false;
}
}
pthread_t

View File

@ -397,6 +397,10 @@ class Sampler {
bool signal_sender_launched_;
pthread_t signal_sender_thread_;
#endif
#if defined(SPS_OS_darwin)
bool signal_handler_installed_;
struct sigaction old_sigprof_signal_handler_;
#endif
};
class ThreadInfo {

View File

@ -32,6 +32,7 @@ using mozilla::unused;
#include "nsFocusManager.h"
#include "nsIWidgetListener.h"
#include "nsViewManager.h"
#include "nsISelection.h"
#include "nsIDOMSimpleGestureEvent.h"
@ -178,7 +179,6 @@ nsWindow::nsWindow() :
mParent(nullptr),
mFocus(nullptr),
mIMEMaskSelectionUpdate(false),
mIMEMaskTextUpdate(false),
mIMEMaskEventsCount(1), // Mask IME events since there's no focus yet
mIMERanges(new TextRangeArray()),
mIMEUpdatingContext(false),
@ -1692,7 +1692,6 @@ nsWindow::RemoveIMEComposition()
nsRefPtr<nsWindow> kungFuDeathGrip(this);
AutoIMEMask selMask(mIMEMaskSelectionUpdate);
AutoIMEMask textMask(mIMEMaskTextUpdate);
WidgetCompositionEvent compositionCommitEvent(true,
NS_COMPOSITION_COMMIT_AS_IS,
@ -1704,7 +1703,6 @@ nsWindow::RemoveIMEComposition()
void
nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
{
MOZ_ASSERT(!mIMEMaskTextUpdate);
MOZ_ASSERT(!mIMEMaskSelectionUpdate);
/*
Rules for managing IME between Gecko and Java:
@ -1781,9 +1779,6 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
Selection updates are masked so the result of our temporary
selection event is not passed on to Java
Text updates are passed on, so the Java text can shadow the
Gecko text
*/
AutoIMEMask selMask(mIMEMaskSelectionUpdate);
const auto composition(GetIMEComposition());
@ -1932,11 +1927,10 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
to eliminate the possibility of this event altering the
text content unintentionally.
Selection and text updates are masked so the result of
Selection updates are masked so the result of
temporary events are not passed on to Java
*/
AutoIMEMask selMask(mIMEMaskSelectionUpdate);
AutoIMEMask textMask(mIMEMaskTextUpdate);
const auto composition(GetIMEComposition());
MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
@ -2006,11 +2000,10 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
* Remove any previous composition. This is only used for
* visual indication and does not affect the text content.
*
* Selection and text updates are masked so the result of
* Selection updates are masked so the result of
* temporary events are not passed on to Java
*/
AutoIMEMask selMask(mIMEMaskSelectionUpdate);
AutoIMEMask textMask(mIMEMaskTextUpdate);
RemoveIMEComposition();
mIMERanges->Clear();
}
@ -2197,7 +2190,19 @@ nsWindow::PostFlushIMEChanges()
void
nsWindow::FlushIMEChanges()
{
// Only send change notifications if we are *not* masking events,
// i.e. if we have a focused editor,
NS_ENSURE_TRUE_VOID(!mIMEMaskEventsCount);
nsCOMPtr<nsISelection> imeSelection;
nsCOMPtr<nsIContent> imeRoot;
// If we are receiving notifications, we must have selection/root content.
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(IMEStateManager::GetFocusSelectionAndRoot(
getter_AddRefs(imeSelection), getter_AddRefs(imeRoot))));
nsRefPtr<nsWindow> kungFuDeathGrip(this);
for (uint32_t i = 0; i < mIMETextChanges.Length(); i++) {
IMEChange &change = mIMETextChanges[i];
@ -2213,8 +2218,8 @@ nsWindow::FlushIMEChanges()
event.InitForQueryTextContent(change.mStart,
change.mNewEnd - change.mStart);
DispatchEvent(&event);
if (!event.mSucceeded)
return;
NS_ENSURE_TRUE_VOID(event.mSucceeded);
NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get());
}
GeckoAppShell::NotifyIMEChange(event.mReply.mString, change.mStart,
@ -2227,8 +2232,8 @@ nsWindow::FlushIMEChanges()
InitEvent(event, nullptr);
DispatchEvent(&event);
if (!event.mSucceeded)
return;
NS_ENSURE_TRUE_VOID(event.mSucceeded);
NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get());
GeckoAppShell::NotifyIMEChange(EmptyString(),
int32_t(event.GetSelectionStart()),
@ -2243,9 +2248,6 @@ nsWindow::NotifyIMEOfTextChange(const IMENotification& aIMENotification)
MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
"NotifyIMEOfTextChange() is called with invaild notification");
if (mIMEMaskTextUpdate)
return NS_OK;
ALOGIME("IME: NotifyIMEOfTextChange: s=%d, oe=%d, ne=%d",
aIMENotification.mTextChangeData.mStartOffset,
aIMENotification.mTextChangeData.mOldEndOffset,

View File

@ -217,7 +217,7 @@ protected:
nsCOMPtr<nsIIdleServiceInternal> mIdleService;
bool mIMEMaskSelectionUpdate, mIMEMaskTextUpdate;
bool mIMEMaskSelectionUpdate;
int32_t mIMEMaskEventsCount; // Mask events when > 0
nsRefPtr<mozilla::TextRangeArray> mIMERanges;
bool mIMEUpdatingContext;

View File

@ -536,7 +536,7 @@ public:
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) override;
NS_IMETHOD SetPluginFocused(bool& aFocused);
NS_IMETHOD SetPluginFocused(bool& aFocused) override;
bool IsPluginFocused() { return mPluginFocused; }
@ -560,6 +560,7 @@ protected:
}
void ConfigureAPZCTreeManager() override;
void ConfigureAPZControllerThread() override;
void DoRemoteComposition(const nsIntRect& aRenderRect);

View File

@ -60,6 +60,7 @@
#include "ScopedGLHelpers.h"
#include "HeapCopyOfStackArray.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/APZThreadUtils.h"
#include "mozilla/layers/GLManager.h"
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/CompositorParent.h"
@ -1890,6 +1891,14 @@ nsChildView::ConfigureAPZCTreeManager()
gNumberOfWidgetsNeedingEventThread++;
}
void
nsChildView::ConfigureAPZControllerThread()
{
// On OS X the EventThreadRunner is the controller thread, but it doesn't
// have a MessageLoop.
APZThreadUtils::SetControllerThread(nullptr);
}
nsIntRect
nsChildView::RectContainingTitlebarControls()
{