зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c a=merge
This commit is contained in:
Коммит
6ec4b5852a
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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>
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
|
@ -42,6 +42,7 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AutoTimelineMarker.h',
|
||||
'IHistory.h',
|
||||
'LoadContext.h',
|
||||
]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче