mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound. a=merge
This commit is contained in:
commit
a64a253ff7
@ -252,6 +252,11 @@ toolbar[customizing] > .overflow-button {
|
||||
|
||||
%endif
|
||||
|
||||
#main-window[inFullscreen] #global-notificationbox,
|
||||
#main-window[inFullscreen] #high-priority-global-notificationbox {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
/* Rules to help integrate SDK widgets */
|
||||
toolbaritem[sdkstylewidget="true"] > toolbarbutton,
|
||||
toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe,
|
||||
@ -824,23 +829,15 @@ html|*#gcli-output-frame,
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""])::after {
|
||||
content: attr(badge);
|
||||
}
|
||||
|
||||
toolbarbutton[type="badged"] {
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#toolbarbutton-badged");
|
||||
}
|
||||
|
||||
toolbarbutton[type="socialmark"] {
|
||||
-moz-binding: url("chrome://browser/content/socialmarks.xml#toolbarbutton-marks");
|
||||
}
|
||||
|
||||
toolbarbutton[type="badged"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
max-width: 16px;
|
||||
}
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[type="badged"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
max-width: 32px;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@ let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/ContentWebRTC.jsm");
|
||||
Cu.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
Cu.import("resource://gre/modules/InlineSpellCheckerContent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
|
||||
"resource:///modules/E10SUtils.jsm");
|
||||
@ -100,7 +102,15 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
}
|
||||
|
||||
if (!defaultPrevented) {
|
||||
sendSyncMessage("contextmenu", {}, { event: event });
|
||||
let editFlags = SpellCheckHelper.isEditable(event.target, content);
|
||||
let spellInfo;
|
||||
if (editFlags &
|
||||
(SpellCheckHelper.EDITABLE | SpellCheckHelper.CONTENTEDITABLE)) {
|
||||
spellInfo =
|
||||
InlineSpellCheckerContent.initContextMenu(event, editFlags, this);
|
||||
}
|
||||
|
||||
sendSyncMessage("contextmenu", { editFlags, spellInfo }, { event });
|
||||
}
|
||||
}, false);
|
||||
} else {
|
||||
|
@ -95,8 +95,8 @@
|
||||
<input id="newtab-customize-button" type="button" title="&newtab.customize.title;"/>
|
||||
</div>
|
||||
|
||||
<xul:script type="text/javascript;version=1.8"
|
||||
src="chrome://browser/content/newtab/newTab.js"/>
|
||||
<xul:script type="text/javascript;version=1.8"
|
||||
src="chrome://browser/content/searchSuggestionUI.js"/>
|
||||
<xul:script type="text/javascript;version=1.8"
|
||||
src="chrome://browser/content/newtab/newTab.js"/>
|
||||
</xul:window>
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* vim: set ts=2 sw=2 sts=2 et 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/.
|
||||
|
||||
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
|
||||
var gContextMenuContentData = null;
|
||||
|
||||
@ -518,11 +520,13 @@ nsContextMenu.prototype = {
|
||||
setTarget: function (aNode, aRangeParent, aRangeOffset) {
|
||||
// If gContextMenuContentData is not null, this event was forwarded from a
|
||||
// child process, so use that information instead.
|
||||
let editFlags;
|
||||
if (gContextMenuContentData) {
|
||||
this.isRemote = true;
|
||||
aNode = gContextMenuContentData.event.target;
|
||||
aRangeParent = gContextMenuContentData.event.rangeParent;
|
||||
aRangeOffset = gContextMenuContentData.event.rangeOffset;
|
||||
editFlags = gContextMenuContentData.editFlags;
|
||||
} else {
|
||||
this.isRemote = false;
|
||||
}
|
||||
@ -578,6 +582,7 @@ nsContextMenu.prototype = {
|
||||
if (this.isRemote) {
|
||||
this.browser = gContextMenuContentData.browser;
|
||||
} else {
|
||||
editFlags = SpellCheckHelper.isEditable(this.target, window);
|
||||
this.browser = this.target.ownerDocument.defaultView
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
@ -628,24 +633,19 @@ nsContextMenu.prototype = {
|
||||
this.onAudio = true;
|
||||
this.mediaURL = this.target.currentSrc || this.target.src;
|
||||
}
|
||||
else if (this.target instanceof HTMLInputElement ) {
|
||||
this.onTextInput = this.isTargetATextBox(this.target);
|
||||
// Allow spellchecking UI on all text and search inputs.
|
||||
if (this.onTextInput && ! this.target.readOnly &&
|
||||
(this.target.type == "text" || this.target.type == "search")) {
|
||||
this.onEditableArea = true;
|
||||
InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
|
||||
InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
|
||||
}
|
||||
this.onKeywordField = this.isTargetAKeywordField(this.target);
|
||||
}
|
||||
else if (this.target instanceof HTMLTextAreaElement) {
|
||||
this.onTextInput = true;
|
||||
if (!this.target.readOnly) {
|
||||
this.onEditableArea = true;
|
||||
InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
|
||||
InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
|
||||
else if (editFlags & (SpellCheckHelper.INPUT | SpellCheckHelper.TEXTAREA)) {
|
||||
this.onTextInput = (editFlags & SpellCheckHelper.TEXTINPUT) !== 0;
|
||||
this.onEditableArea = (editFlags & SpellCheckHelper.EDITABLE) !== 0;
|
||||
if (this.onEditableArea) {
|
||||
if (gContextMenuContentData) {
|
||||
InlineSpellCheckerUI.initFromRemote(gContextMenuContentData.spellInfo);
|
||||
}
|
||||
else {
|
||||
InlineSpellCheckerUI.init(this.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
|
||||
InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
|
||||
}
|
||||
}
|
||||
this.onKeywordField = (editFlags & SpellCheckHelper.KEYWORD);
|
||||
}
|
||||
else if (this.target instanceof HTMLHtmlElement) {
|
||||
var bodyElt = this.target.ownerDocument.body;
|
||||
@ -748,41 +748,35 @@ nsContextMenu.prototype = {
|
||||
|
||||
// if the document is editable, show context menu like in text inputs
|
||||
if (!this.onEditableArea) {
|
||||
win = this.target.ownerDocument.defaultView;
|
||||
if (win) {
|
||||
var isEditable = false;
|
||||
try {
|
||||
var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession);
|
||||
if (editingSession.windowIsEditable(win) &&
|
||||
this.getComputedStyle(this.target, "-moz-user-modify") == "read-write") {
|
||||
isEditable = true;
|
||||
}
|
||||
if (editFlags & SpellCheckHelper.CONTENTEDITABLE) {
|
||||
// If this.onEditableArea is false but editFlags is CONTENTEDITABLE, then
|
||||
// the document itself must be editable.
|
||||
this.onTextInput = true;
|
||||
this.onKeywordField = false;
|
||||
this.onImage = false;
|
||||
this.onLoadedImage = false;
|
||||
this.onCompletedImage = false;
|
||||
this.onMathML = false;
|
||||
this.inFrame = false;
|
||||
this.inSrcdocFrame = false;
|
||||
this.hasBGImage = false;
|
||||
this.isDesignMode = true;
|
||||
this.onEditableArea = true;
|
||||
if (gContextMenuContentData) {
|
||||
InlineSpellCheckerUI.initFromRemote(gContextMenuContentData.spellInfo);
|
||||
}
|
||||
catch(ex) {
|
||||
// If someone built with composer disabled, we can't get an editing session.
|
||||
}
|
||||
|
||||
if (isEditable) {
|
||||
this.onTextInput = true;
|
||||
this.onKeywordField = false;
|
||||
this.onImage = false;
|
||||
this.onLoadedImage = false;
|
||||
this.onCompletedImage = false;
|
||||
this.onMathML = false;
|
||||
this.inFrame = false;
|
||||
this.inSrcdocFrame = false;
|
||||
this.hasBGImage = false;
|
||||
this.isDesignMode = true;
|
||||
this.onEditableArea = true;
|
||||
InlineSpellCheckerUI.init(editingSession.getEditorForWindow(win));
|
||||
var canSpell = InlineSpellCheckerUI.canSpellCheck && this.canSpellCheck;
|
||||
else {
|
||||
var targetWin = this.target.ownerDocument.defaultView;
|
||||
var editingSession = targetWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession);
|
||||
InlineSpellCheckerUI.init(editingSession.getEditorForWindow(targetWin));
|
||||
InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
|
||||
this.showItem("spell-check-enabled", canSpell);
|
||||
this.showItem("spell-separator", canSpell);
|
||||
}
|
||||
var canSpell = InlineSpellCheckerUI.canSpellCheck && this.canSpellCheck;
|
||||
this.showItem("spell-check-enabled", canSpell);
|
||||
this.showItem("spell-separator", canSpell);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1502,30 +1496,6 @@ nsContextMenu.prototype = {
|
||||
return (node instanceof HTMLTextAreaElement);
|
||||
},
|
||||
|
||||
isTargetAKeywordField: function(aNode) {
|
||||
if (!(aNode instanceof HTMLInputElement))
|
||||
return false;
|
||||
|
||||
var form = aNode.form;
|
||||
if (!form || aNode.type == "password")
|
||||
return false;
|
||||
|
||||
var method = form.method.toUpperCase();
|
||||
|
||||
// These are the following types of forms we can create keywords for:
|
||||
//
|
||||
// method encoding type can create keyword
|
||||
// GET * YES
|
||||
// * YES
|
||||
// POST YES
|
||||
// POST application/x-www-form-urlencoded YES
|
||||
// POST text/plain NO (a little tricky to do)
|
||||
// POST multipart/form-data NO
|
||||
// POST everything else YES
|
||||
return (method == "GET" || method == "") ||
|
||||
(form.enctype != "text/plain") && (form.enctype != "multipart/form-data");
|
||||
},
|
||||
|
||||
// Determines whether or not the separator with the specified ID should be
|
||||
// shown or not by determining if there are any non-hidden items between it
|
||||
// and the previous separator.
|
||||
|
@ -3049,8 +3049,13 @@
|
||||
break;
|
||||
}
|
||||
case "contextmenu": {
|
||||
let spellInfo = aMessage.data.spellInfo;
|
||||
if (spellInfo)
|
||||
spellInfo.target = aMessage.target.messageManager;
|
||||
gContextMenuContentData = { event: aMessage.objects.event,
|
||||
browser: browser };
|
||||
browser: browser,
|
||||
editFlags: aMessage.data.editFlags,
|
||||
spellInfo: spellInfo };
|
||||
let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
|
||||
let event = gContextMenuContentData.event;
|
||||
let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
|
||||
|
@ -2581,20 +2581,4 @@
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="toolbarbutton-badged" display="xul:button"
|
||||
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:hbox class="toolbarbutton-badge-container" align="start" pack="end">
|
||||
<xul:hbox class="toolbarbutton-badge" xbl:inherits="badge"/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
|
||||
</xul:hbox>
|
||||
<xul:label class="toolbarbutton-text" crop="right" flex="1"
|
||||
xbl:inherits="value=label,accesskey,crop,wrap"/>
|
||||
<xul:label class="toolbarbutton-multiline-text" flex="1"
|
||||
xbl:inherits="xbl:text=label,accesskey,wrap"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
||||
|
@ -915,7 +915,7 @@ const CustomizableWidgets = [
|
||||
node.setAttribute("id", this.id);
|
||||
node.classList.add("toolbarbutton-1");
|
||||
node.classList.add("chromeclass-toolbar-additional");
|
||||
node.setAttribute("type", "badged");
|
||||
node.classList.add("badged-button");
|
||||
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
|
||||
node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
|
||||
node.setAttribute("removable", "true");
|
||||
|
@ -113,6 +113,7 @@ skip-if = os == "linux" # Intemittent failures - bug 979207
|
||||
[browser_969661_character_encoding_navbar_disabled.js]
|
||||
[browser_970511_undo_restore_default.js]
|
||||
[browser_972267_customizationchange_events.js]
|
||||
[browser_973641_button_addon.js]
|
||||
[browser_973932_addonbar_currentset.js]
|
||||
[browser_975719_customtoolbars_behaviour.js]
|
||||
|
||||
|
72
browser/components/customizableui/test/browser_973641_button_addon.js
Executable file
72
browser/components/customizableui/test/browser_973641_button_addon.js
Executable file
@ -0,0 +1,72 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const kButton = "test_button_for_addon";
|
||||
let initialLocation = gBrowser.currentURI.spec;
|
||||
|
||||
add_task(function() {
|
||||
info("Check addon button functionality");
|
||||
|
||||
// create mocked addon button on the navigation bar
|
||||
let widgetSpec = {
|
||||
id: kButton,
|
||||
type: 'button',
|
||||
onClick: function() {
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:addons");
|
||||
}
|
||||
};
|
||||
CustomizableUI.createWidget(widgetSpec);
|
||||
CustomizableUI.addWidgetToArea(kButton, CustomizableUI.AREA_NAVBAR);
|
||||
|
||||
// check the button's functionality in navigation bar
|
||||
let addonButton = document.getElementById(kButton);
|
||||
let navBar = document.getElementById("nav-bar");
|
||||
ok(addonButton, "Addon button exists");
|
||||
ok(navBar.contains(addonButton), "Addon button is in the navbar");
|
||||
yield checkButtonFunctionality(addonButton);
|
||||
|
||||
resetTabs();
|
||||
|
||||
//move the add-on button in the Panel Menu
|
||||
CustomizableUI.addWidgetToArea(kButton, CustomizableUI.AREA_PANEL);
|
||||
let addonButtonInNavbar = navBar.getElementsByAttribute("id", kButton);
|
||||
ok(!navBar.contains(addonButton), "Addon button was removed from the browser bar");
|
||||
|
||||
// check the addon button's functionality in the Panel Menu
|
||||
yield PanelUI.show();
|
||||
var panelMenu = document.getElementById("PanelUI-mainView");
|
||||
let addonButtonInPanel = panelMenu.getElementsByAttribute("id", kButton);
|
||||
ok(panelMenu.contains(addonButton), "Addon button was added to the Panel Menu");
|
||||
yield checkButtonFunctionality(addonButtonInPanel[0]);
|
||||
});
|
||||
|
||||
add_task(function asyncCleanup() {
|
||||
resetTabs();
|
||||
|
||||
// reset the UI to the default state
|
||||
yield resetCustomization();
|
||||
ok(CustomizableUI.inDefaultState, "The UI is in default state again.");
|
||||
|
||||
// destroy the widget
|
||||
CustomizableUI.destroyWidget(kButton);
|
||||
});
|
||||
|
||||
function resetTabs() {
|
||||
//close all opened tabs
|
||||
while(gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
|
||||
//restore the initial tab
|
||||
gBrowser.addTab(initialLocation);
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
|
||||
function checkButtonFunctionality(aButton) {
|
||||
aButton.click();
|
||||
yield waitForCondition(() => gBrowser.currentURI &&
|
||||
gBrowser.currentURI.spec == "about:addons");
|
||||
}
|
@ -2,14 +2,15 @@
|
||||
* 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/. */
|
||||
|
||||
const Cu = Components.utils;
|
||||
const {utils: Cu, interfaces: Ci} = Components;
|
||||
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
||||
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const {require} = devtools;
|
||||
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
|
||||
const promise = require("devtools/toolkit/deprecated-sync-thenables");
|
||||
const prefs = require('sdk/preferences/service');
|
||||
|
||||
const prefs = require("sdk/preferences/service");
|
||||
const Services = require("Services");
|
||||
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/app-manager.properties");
|
||||
|
||||
let UI = {
|
||||
_toolboxTabCursor: 0,
|
||||
@ -34,6 +35,7 @@ let UI = {
|
||||
let defaultPanel = prefs.get("devtools.appmanager.lastTab");
|
||||
let panelExists = !!document.querySelector("." + defaultPanel + "-panel");
|
||||
this.selectTab(panelExists ? defaultPanel : "projects");
|
||||
this.showDeprecationNotice();
|
||||
},
|
||||
|
||||
onUnload: function() {
|
||||
@ -178,7 +180,33 @@ let UI = {
|
||||
} else {
|
||||
return gDevTools.showToolbox(target, null, host);
|
||||
}
|
||||
},
|
||||
|
||||
showDeprecationNotice: function() {
|
||||
let message = Strings.GetStringFromName("index.deprecationNotice");
|
||||
|
||||
let buttons = [
|
||||
{
|
||||
label: Strings.GetStringFromName("index.launchWebIDE"),
|
||||
callback: gDevToolsBrowser.openWebIDE
|
||||
},
|
||||
{
|
||||
label: Strings.GetStringFromName("index.readMoreAboutWebIDE"),
|
||||
callback: () => {
|
||||
window.open("https://developer.mozilla.org/docs/Tools/WebIDE");
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let browser = docShell.chromeEventHandler;
|
||||
let nbox = browser.ownerDocument.defaultView.gBrowser
|
||||
.getNotificationBox(browser);
|
||||
nbox.appendNotification(message, "app-manager-deprecation", null,
|
||||
nbox.PRIORITY_WARNING_LOW, buttons);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
UI.init();
|
||||
|
@ -370,12 +370,14 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
this._onContextCopyUrlCommand = this.copyUrl.bind(this);
|
||||
this._onContextCopyImageAsDataUriCommand = this.copyImageAsDataUri.bind(this);
|
||||
this._onContextResendCommand = this.cloneSelectedRequest.bind(this);
|
||||
this._onContextToggleRawHeadersCommand = this.toggleRawHeaders.bind(this);
|
||||
this._onContextPerfCommand = () => NetMonitorView.toggleFrontendMode();
|
||||
this._onReloadCommand = () => NetMonitorView.reloadPage();
|
||||
|
||||
this.sendCustomRequestEvent = this.sendCustomRequest.bind(this);
|
||||
this.closeCustomRequestEvent = this.closeCustomRequest.bind(this);
|
||||
this.cloneSelectedRequestEvent = this.cloneSelectedRequest.bind(this);
|
||||
this.toggleRawHeadersEvent = this.toggleRawHeaders.bind(this);
|
||||
|
||||
$("#toolbar-labels").addEventListener("click", this.requestsMenuSortEvent, false);
|
||||
$("#requests-menu-footer").addEventListener("click", this.requestsMenuFilterEvent, false);
|
||||
@ -384,6 +386,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
$("#request-menu-context-newtab").addEventListener("command", this._onContextNewTabCommand, false);
|
||||
$("#request-menu-context-copy-url").addEventListener("command", this._onContextCopyUrlCommand, false);
|
||||
$("#request-menu-context-copy-image-as-data-uri").addEventListener("command", this._onContextCopyImageAsDataUriCommand, false);
|
||||
$("#toggle-raw-headers").addEventListener("click", this.toggleRawHeadersEvent, false);
|
||||
|
||||
window.once("connected", this._onConnect.bind(this));
|
||||
},
|
||||
@ -447,6 +450,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
$("#custom-request-send-button").removeEventListener("click", this.sendCustomRequestEvent, false);
|
||||
$("#custom-request-close-button").removeEventListener("click", this.closeCustomRequestEvent, false);
|
||||
$("#headers-summary-resend").removeEventListener("click", this.cloneSelectedRequestEvent, false);
|
||||
$("#toggle-raw-headers").removeEventListener("click", this.toggleRawHeadersEvent, false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -638,6 +642,28 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
NetMonitorView.Sidebar.toggle(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows raw request/response headers in textboxes.
|
||||
*/
|
||||
toggleRawHeaders: function() {
|
||||
let requestTextarea = $("#raw-request-headers-textarea");
|
||||
let responseTextare = $("#raw-response-headers-textarea");
|
||||
let rawHeadersHidden = $("#raw-headers").getAttribute("hidden");
|
||||
|
||||
if (rawHeadersHidden) {
|
||||
let selected = this.selectedItem.attachment;
|
||||
let selectedRequestHeaders = selected.requestHeaders.headers;
|
||||
let selectedResponseHeaders = selected.responseHeaders.headers;
|
||||
requestTextarea.value = writeHeaderText(selectedRequestHeaders);
|
||||
responseTextare.value = writeHeaderText(selectedResponseHeaders);
|
||||
$("#raw-headers").hidden = false;
|
||||
} else {
|
||||
requestTextarea.value = null;
|
||||
responseTextare.value = null;
|
||||
$("#raw-headers").hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Filters all network requests in this container by a specified type.
|
||||
*
|
||||
@ -2013,6 +2039,7 @@ NetworkDetailsView.prototype = {
|
||||
$("#response-content-info-header").hidden = true;
|
||||
$("#response-content-json-box").hidden = true;
|
||||
$("#response-content-textarea-box").hidden = true;
|
||||
$("#raw-headers").hidden = true;
|
||||
$("#response-content-image-box").hidden = true;
|
||||
|
||||
let isHtml = RequestsMenuView.prototype.isHtml({ attachment: aData });
|
||||
|
@ -307,6 +307,9 @@
|
||||
<button id="headers-summary-resend"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&netmonitorUI.summary.editAndResend;"/>
|
||||
<button id="toggle-raw-headers"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&netmonitorUI.summary.rawHeaders;"/>
|
||||
</hbox>
|
||||
<hbox id="headers-summary-version"
|
||||
class="tabpanel-summary-container"
|
||||
@ -318,6 +321,25 @@
|
||||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
<hbox id="raw-headers"
|
||||
class="tabpanel-summary-container"
|
||||
align="center"
|
||||
hidden="true">
|
||||
<vbox id="raw-request-headers-textarea-box" flex="1" hidden="false">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.summary.rawHeaders.requestHeaders;"/>
|
||||
<textbox id="raw-request-headers-textarea"
|
||||
class="raw-response-textarea"
|
||||
flex="1" multiline="true" readonly="true"/>
|
||||
</vbox>
|
||||
<vbox id="raw-response-headers-textarea-box" flex="1" hidden="false">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
value="&netmonitorUI.summary.rawHeaders.responseHeaders;"/>
|
||||
<textbox id="raw-response-headers-textarea"
|
||||
class="raw-response-textarea"
|
||||
flex="1" multiline="true" readonly="true"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<vbox id="all-headers" flex="1"/>
|
||||
</vbox>
|
||||
</tabpanel>
|
||||
|
@ -77,6 +77,7 @@ skip-if= buildapp == 'mulet'
|
||||
[browser_net_post-data-03.js]
|
||||
[browser_net_prefs-and-l10n.js]
|
||||
[browser_net_prefs-reload.js]
|
||||
[browser_net_raw_headers.js]
|
||||
[browser_net_reload-button.js]
|
||||
[browser_net_req-resp-bodies.js]
|
||||
[browser_net_resend.js]
|
||||
|
72
browser/devtools/netmonitor/test/browser_net_raw_headers.js
Normal file
72
browser/devtools/netmonitor/test/browser_net_raw_headers.js
Normal file
@ -0,0 +1,72 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let gPanelWin;
|
||||
let gPanelDoc;
|
||||
|
||||
/**
|
||||
* Tests if showing raw headers works.
|
||||
*/
|
||||
|
||||
function test() {
|
||||
initNetMonitor(POST_DATA_URL).then(([aTab, aDebuggee, aMonitor]) => {
|
||||
info("Starting test... ");
|
||||
|
||||
gPanelWin = aMonitor.panelWin;
|
||||
gPanelDoc = gPanelWin.document;
|
||||
|
||||
let { document, Editor, NetMonitorView } = gPanelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
let TAB_UPDATED = gPanelWin.EVENTS.TAB_UPDATED;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
waitForNetworkEvents(aMonitor, 0, 2).then(() => {
|
||||
let origItem = RequestsMenu.getItemAtIndex(0);
|
||||
RequestsMenu.selectedItem = origItem;
|
||||
|
||||
waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, document.getElementById("toggle-raw-headers"));
|
||||
testShowRawHeaders(origItem.attachment);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, document.getElementById("toggle-raw-headers"));
|
||||
testHideRawHeaders(document);
|
||||
finishUp(aMonitor);
|
||||
});
|
||||
});
|
||||
|
||||
aDebuggee.performRequests();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that raw headers were displayed correctly
|
||||
*/
|
||||
function testShowRawHeaders(aData) {
|
||||
let requestHeaders = gPanelDoc.getElementById("raw-request-headers-textarea").value;
|
||||
for (let header of aData.requestHeaders.headers) {
|
||||
ok(requestHeaders.indexOf(header.name + ": " + header.value) >= 0, "textarea contains request headers");
|
||||
}
|
||||
let responseHeaders = gPanelDoc.getElementById("raw-response-headers-textarea").value;
|
||||
for (let header of aData.responseHeaders.headers) {
|
||||
ok(responseHeaders.indexOf(header.name + ": " + header.value) >= 0, "textarea contains response headers");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that raw headers textareas are hidden and empty
|
||||
*/
|
||||
function testHideRawHeaders(document) {
|
||||
let rawHeadersHidden = document.getElementById("raw-headers").getAttribute("hidden");
|
||||
let requestTextarea = document.getElementById("raw-request-headers-textarea");
|
||||
let responseTextare = document.getElementById("raw-response-headers-textarea");
|
||||
ok(rawHeadersHidden, "raw headers textareas are hidden");
|
||||
ok(requestTextarea.value == '', "raw request headers textarea is empty");
|
||||
ok(responseTextare.value == '', "raw response headers textarea is empty");
|
||||
}
|
||||
|
||||
function finishUp(aMonitor) {
|
||||
gPanelWin = null;
|
||||
gPanelDoc = null;
|
||||
|
||||
teardown(aMonitor).then(finish);
|
||||
}
|
@ -107,11 +107,19 @@
|
||||
<label class="plain call-tree-header"
|
||||
type="duration"
|
||||
crop="end"
|
||||
value="&profilerUI.table.duration;"/>
|
||||
value="&profilerUI.table.totalDuration;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-duration"
|
||||
crop="end"
|
||||
value="&profilerUI.table.selfDuration;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="percentage"
|
||||
crop="end"
|
||||
value="&profilerUI.table.percentage;"/>
|
||||
value="&profilerUI.table.totalPercentage;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-percentage"
|
||||
crop="end"
|
||||
value="&profilerUI.table.selfPercentage;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="samples"
|
||||
crop="end"
|
||||
|
@ -22,9 +22,9 @@ function test() {
|
||||
is(container.childNodes[0].className, "call-tree-item",
|
||||
"The root node in the tree has the correct class name.");
|
||||
|
||||
is(container.childNodes[0].childNodes.length, 4,
|
||||
is(container.childNodes[0].childNodes.length, 6,
|
||||
"The root node in the tree has the correct number of children.");
|
||||
is(container.childNodes[0].querySelectorAll(".call-tree-cell").length, 4,
|
||||
is(container.childNodes[0].querySelectorAll(".call-tree-cell").length, 6,
|
||||
"The root node in the tree has only 'call-tree-cell' children.");
|
||||
|
||||
is(container.childNodes[0].childNodes[0].getAttribute("type"), "duration",
|
||||
@ -32,19 +32,29 @@ function test() {
|
||||
is(container.childNodes[0].childNodes[0].getAttribute("value"), "18",
|
||||
"The root node in the tree has the correct duration cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[1].getAttribute("type"), "percentage",
|
||||
is(container.childNodes[0].childNodes[1].getAttribute("type"), "self-duration",
|
||||
"The root node in the tree has a self-duration cell.");
|
||||
is(container.childNodes[0].childNodes[1].getAttribute("value"), "0",
|
||||
"The root node in the tree has the correct self-duration cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[2].getAttribute("type"), "percentage",
|
||||
"The root node in the tree has a percentage cell.");
|
||||
is(container.childNodes[0].childNodes[1].getAttribute("value"), "100%",
|
||||
is(container.childNodes[0].childNodes[2].getAttribute("value"), "100%",
|
||||
"The root node in the tree has the correct percentage cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[2].getAttribute("type"), "samples",
|
||||
is(container.childNodes[0].childNodes[3].getAttribute("type"), "self-percentage",
|
||||
"The root node in the tree has a self-percentage cell.");
|
||||
is(container.childNodes[0].childNodes[3].getAttribute("value"), "0%",
|
||||
"The root node in the tree has the correct self-percentage cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[4].getAttribute("type"), "samples",
|
||||
"The root node in the tree has an samples cell.");
|
||||
is(container.childNodes[0].childNodes[2].getAttribute("value"), "3",
|
||||
is(container.childNodes[0].childNodes[4].getAttribute("value"), "3",
|
||||
"The root node in the tree has the correct samples cell value.");
|
||||
|
||||
is(container.childNodes[0].childNodes[3].getAttribute("type"), "function",
|
||||
is(container.childNodes[0].childNodes[5].getAttribute("type"), "function",
|
||||
"The root node in the tree has a function cell.");
|
||||
is(container.childNodes[0].childNodes[3].style.MozMarginStart, "0px",
|
||||
is(container.childNodes[0].childNodes[5].style.MozMarginStart, "0px",
|
||||
"The root node in the tree has the correct indentation.");
|
||||
|
||||
finish();
|
||||
|
@ -42,18 +42,22 @@ function test() {
|
||||
ok(!A.target.querySelector(".call-tree-category").hidden,
|
||||
"The .A.B.C node's category label cell should not be hidden.");
|
||||
|
||||
is(C.target.childNodes.length, 4,
|
||||
is(C.target.childNodes.length, 6,
|
||||
"The number of columns displayed for tree items is correct.");
|
||||
is(C.target.childNodes[0].getAttribute("type"), "duration",
|
||||
"The first column displayed for tree items is correct.");
|
||||
is(C.target.childNodes[1].getAttribute("type"), "percentage",
|
||||
is(C.target.childNodes[1].getAttribute("type"), "self-duration",
|
||||
"The second column displayed for tree items is correct.");
|
||||
is(C.target.childNodes[2].getAttribute("type"), "samples",
|
||||
is(C.target.childNodes[2].getAttribute("type"), "percentage",
|
||||
"The third column displayed for tree items is correct.");
|
||||
is(C.target.childNodes[3].getAttribute("type"), "function",
|
||||
is(C.target.childNodes[3].getAttribute("type"), "self-percentage",
|
||||
"The fourth column displayed for tree items is correct.");
|
||||
is(C.target.childNodes[4].getAttribute("type"), "samples",
|
||||
"The fifth column displayed for tree items is correct.");
|
||||
is(C.target.childNodes[5].getAttribute("type"), "function",
|
||||
"The sixth column displayed for tree items is correct.");
|
||||
|
||||
let functionCell = C.target.childNodes[3];
|
||||
let functionCell = C.target.childNodes[5];
|
||||
|
||||
is(functionCell.childNodes.length, 8,
|
||||
"The number of columns displayed for function cells is correct.");
|
||||
|
@ -18,6 +18,9 @@ const ZOOM_BUTTON_TOOLTIP = L10N.getStr("table.zoom.tooltiptext");
|
||||
const CALL_TREE_INDENTATION = 16; // px
|
||||
const CALL_TREE_AUTO_EXPAND = 3; // depth
|
||||
|
||||
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
||||
const sum = vals => vals.reduce((a, b) => a + b, 0);
|
||||
|
||||
exports.CallView = CallView;
|
||||
|
||||
/**
|
||||
@ -63,10 +66,17 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
this.document = document;
|
||||
|
||||
let frameInfo = this.frame.getInfo();
|
||||
let framePercentage = this.frame.samples / this.root.frame.samples * 100;
|
||||
let framePercentage = this._getPercentage(this.frame.samples);
|
||||
let childrenPercentage = sum([this._getPercentage(c.samples)
|
||||
for (c of this._getChildCalls())]);
|
||||
let selfPercentage = clamp(framePercentage - childrenPercentage, 0, 100);
|
||||
let selfDuration = this.frame.duration - sum([c.duration
|
||||
for (c of this._getChildCalls())]);
|
||||
|
||||
let durationCell = this._createTimeCell(this.frame.duration);
|
||||
let selfDurationCell = this._createTimeCell(selfDuration, true);
|
||||
let percentageCell = this._createExecutionCell(framePercentage);
|
||||
let selfPercentageCell = this._createExecutionCell(selfPercentage, true);
|
||||
let samplesCell = this._createSamplesCell(this.frame.samples);
|
||||
let functionCell = this._createFunctionCell(arrowNode, frameInfo, this.level);
|
||||
|
||||
@ -83,13 +93,29 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
}
|
||||
|
||||
targetNode.appendChild(durationCell);
|
||||
targetNode.appendChild(selfDurationCell);
|
||||
targetNode.appendChild(percentageCell);
|
||||
targetNode.appendChild(selfPercentageCell);
|
||||
targetNode.appendChild(samplesCell);
|
||||
targetNode.appendChild(functionCell);
|
||||
|
||||
return targetNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate what percentage of all samples the given number of samples is.
|
||||
*/
|
||||
_getPercentage: function (samples) {
|
||||
return samples / this.root.frame.samples * 100;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return an array of this frame's child calls.
|
||||
*/
|
||||
_getChildCalls: function () {
|
||||
return Object.keys(this.frame.calls).map(k => this.frame.calls[k]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates this node in the call tree with the corresponding "callees".
|
||||
* These are defined in the `frame` data source for this call view.
|
||||
@ -98,7 +124,7 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
_populateSelf: function(children) {
|
||||
let newLevel = this.level + 1;
|
||||
|
||||
for (let [, newFrame] of _Iterator(this.frame.calls)) {
|
||||
for (let newFrame of this._getChildCalls()) {
|
||||
children.push(new CallView({
|
||||
caller: this,
|
||||
frame: newFrame,
|
||||
@ -114,18 +140,18 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
* Functions creating each cell in this call view.
|
||||
* Invoked by `_displaySelf`.
|
||||
*/
|
||||
_createTimeCell: function(duration) {
|
||||
_createTimeCell: function(duration, isSelf = false) {
|
||||
let cell = this.document.createElement("label");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", "duration");
|
||||
cell.setAttribute("type", isSelf ? "self-duration" : "duration");
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", L10N.numberWithDecimals(duration, 2));
|
||||
return cell;
|
||||
},
|
||||
_createExecutionCell: function(percentage) {
|
||||
_createExecutionCell: function(percentage, isSelf = false) {
|
||||
let cell = this.document.createElement("label");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", "percentage");
|
||||
cell.setAttribute("type", isSelf ? "self-percentage" : "percentage");
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", L10N.numberWithDecimals(percentage, 2) + "%");
|
||||
return cell;
|
||||
|
@ -752,6 +752,7 @@ let UI = {
|
||||
let playCmd = document.querySelector("#cmd_play");
|
||||
let stopCmd = document.querySelector("#cmd_stop");
|
||||
let debugCmd = document.querySelector("#cmd_toggleToolbox");
|
||||
let playButton = document.querySelector('#action-button-play');
|
||||
|
||||
if (!AppManager.selectedProject || AppManager.connection.status != Connection.Status.CONNECTED) {
|
||||
playCmd.setAttribute("disabled", "true");
|
||||
@ -760,9 +761,11 @@ let UI = {
|
||||
} else {
|
||||
let isProjectRunning = AppManager.isProjectRunning();
|
||||
if (isProjectRunning) {
|
||||
playButton.classList.add("reload");
|
||||
stopCmd.removeAttribute("disabled");
|
||||
debugCmd.removeAttribute("disabled");
|
||||
} else {
|
||||
playButton.classList.remove("reload");
|
||||
stopCmd.setAttribute("disabled", "true");
|
||||
debugCmd.setAttribute("disabled", "true");
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
@ -54,13 +54,13 @@ window.busy-determined #action-busy-undetermined {
|
||||
|
||||
.panel-button-anchor {
|
||||
list-style-image: url('icons.png');
|
||||
-moz-image-region: rect(0px,391px,16px,364px);
|
||||
-moz-image-region: rect(0px,491px,16px,464px);
|
||||
width: 12px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.panel-button:hover > .panel-button-anchor {
|
||||
-moz-image-region: rect(0px,445px,16px,418px);
|
||||
-moz-image-region: rect(0px,545px,16px,518px);
|
||||
}
|
||||
|
||||
/* Panel buttons - projects */
|
||||
@ -83,7 +83,7 @@ window.busy-determined #action-busy-undetermined {
|
||||
|
||||
#project-panel-button.no-project > .panel-button-image {
|
||||
list-style-image: url("icons.png");
|
||||
-moz-image-region: rect(260px,338px,286px,312px);
|
||||
-moz-image-region: rect(260px,438px,286px,412px);
|
||||
}
|
||||
|
||||
#project-panel-button > .panel-button-label {
|
||||
@ -94,13 +94,13 @@ window.busy-determined #action-busy-undetermined {
|
||||
|
||||
#runtime-panel-button > .panel-button-image {
|
||||
list-style-image: url('icons.png');
|
||||
-moz-image-region: rect(78px,338px,104px,312px);
|
||||
-moz-image-region: rect(78px,438px,104px,412px);
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
#runtime-panel-button[active="true"] > .panel-button-image {
|
||||
-moz-image-region: rect(78px,364px,104px,338px);
|
||||
-moz-image-region: rect(78px,464px,104px,438px);
|
||||
}
|
||||
|
||||
/* Action buttons */
|
||||
@ -134,6 +134,9 @@ window.busy-determined #action-busy-undetermined {
|
||||
#action-button-stop:not([disabled="true"]):hover { -moz-image-region: rect(200px,200px,300px,100px) }
|
||||
#action-button-debug:not([disabled="true"]):not([active="true"]):hover { -moz-image-region: rect(200px,300px,300px,200px) }
|
||||
|
||||
#action-button-play.reload { -moz-image-region: rect(0,400px,100px,303px) }
|
||||
#action-button-play.reload:hover { -moz-image-region: rect(200px,400px,300px,303px) }
|
||||
|
||||
#action-button-debug[active="true"] { -moz-image-region: rect(100px,300px,200px,200px) }
|
||||
|
||||
/* Panels */
|
||||
@ -196,9 +199,9 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
list-style-image: url("icons.png");
|
||||
}
|
||||
|
||||
.project-panel-item-newapp { -moz-image-region: rect(234px,338px,260px,312px) }
|
||||
.project-panel-item-openpackaged { -moz-image-region: rect(260px,338px,286px,312px) }
|
||||
.project-panel-item-openhosted { -moz-image-region: rect(208px,338px,234px,312px) }
|
||||
.project-panel-item-newapp { -moz-image-region: rect(234px,438px,260px,412px) }
|
||||
.project-panel-item-openpackaged { -moz-image-region: rect(260px,438px,286px,412px) }
|
||||
.project-panel-item-openhosted { -moz-image-region: rect(208px,438px,234px,412px) }
|
||||
|
||||
/* runtime panel */
|
||||
|
||||
@ -224,17 +227,17 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
list-style-image: url("icons.png");
|
||||
}
|
||||
|
||||
#runtime-details { -moz-image-region: rect(156px,338px,182px,312px) }
|
||||
#runtime-screenshot { -moz-image-region: rect(130px,338px,156px,312px) }
|
||||
#runtime-permissions { -moz-image-region: rect(104px,338px,130px,312px) }
|
||||
#runtime-disconnect { -moz-image-region: rect(52px,338px,78px,312px) }
|
||||
#runtime-panel-nousbdevice { -moz-image-region: rect(156px,338px,182px,312px) }
|
||||
#runtime-panel-noadbhelper { -moz-image-region: rect(234px,338px,260px,312px) }
|
||||
#runtime-panel-installsimulator { -moz-image-region: rect(0px,338px,26px,312px) }
|
||||
.runtime-panel-item-usb { -moz-image-region: rect(52px,338px,78px,312px) }
|
||||
.runtime-panel-item-wifi { -moz-image-region: rect(208px,338px,234px,312px) }
|
||||
.runtime-panel-item-custom { -moz-image-region: rect(26px,338px,52px,312px) }
|
||||
.runtime-panel-item-simulator { -moz-image-region: rect(0px,338px,26px,312px) }
|
||||
#runtime-details { -moz-image-region: rect(156px,438px,182px,412px) }
|
||||
#runtime-screenshot { -moz-image-region: rect(130px,438px,156px,412px) }
|
||||
#runtime-permissions { -moz-image-region: rect(104px,438px,130px,412px) }
|
||||
#runtime-disconnect { -moz-image-region: rect(52px,438px,78px,412px) }
|
||||
#runtime-panel-nousbdevice { -moz-image-region: rect(156px,438px,182px,412px) }
|
||||
#runtime-panel-noadbhelper { -moz-image-region: rect(234px,438px,260px,412px) }
|
||||
#runtime-panel-installsimulator { -moz-image-region: rect(0px,438px,26px,412px) }
|
||||
.runtime-panel-item-usb { -moz-image-region: rect(52px,438px,78px,412px) }
|
||||
.runtime-panel-item-wifi { -moz-image-region: rect(208px,438px,234px,412px) }
|
||||
.runtime-panel-item-custom { -moz-image-region: rect(26px,438px,52px,412px) }
|
||||
.runtime-panel-item-simulator { -moz-image-region: rect(0px,438px,26px,412px) }
|
||||
|
||||
#runtime-actions {
|
||||
border-top: 1px solid rgba(221,221,221,1);
|
||||
|
@ -31,6 +31,7 @@ const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
|
||||
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
|
||||
|
||||
const MAX_CLIPBOARD_DATA_SIZE = 8000;
|
||||
const MAX_USER_INPUT_TIMEOUT = 250; // ms
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
@ -256,6 +257,7 @@ function ChromeActions(url, window, document) {
|
||||
this.document = document;
|
||||
this.externalComInitialized = false;
|
||||
this.allowScriptAccess = false;
|
||||
this.lastUserInput = 0;
|
||||
this.crossdomainRequestsCache = Object.create(null);
|
||||
this.telemetry = {
|
||||
startTime: Date.now(),
|
||||
@ -416,9 +418,10 @@ ChromeActions.prototype = {
|
||||
fallbackToNativePlugin(this.window, !automatic, automatic);
|
||||
},
|
||||
setClipboard: function (data) {
|
||||
// We don't trust our Shumway non-privileged code just yet to verify the
|
||||
// user input -- using monitorUserInput function below to track that.
|
||||
if (typeof data !== 'string' ||
|
||||
data.length > MAX_CLIPBOARD_DATA_SIZE ||
|
||||
!this.document.hasFocus()) {
|
||||
(Date.now() - this.lastUserInput) > MAX_USER_INPUT_TIMEOUT) {
|
||||
return;
|
||||
}
|
||||
// TODO other security checks?
|
||||
@ -472,25 +475,33 @@ ChromeActions.prototype = {
|
||||
}
|
||||
},
|
||||
reportIssue: function(exceptions) {
|
||||
var base = "http://shumway-issue-reporter.paas.allizom.org/input?";
|
||||
var urlTemplate = "https://bugzilla.mozilla.org/enter_bug.cgi?op_sys=All&priority=--" +
|
||||
"&rep_platform=All&target_milestone=---&version=Trunk&product=Firefox" +
|
||||
"&component=Shumway&short_desc=&comment={comment}" +
|
||||
"&bug_file_loc={url}";
|
||||
var windowUrl = this.window.parent.wrappedJSObject.location + '';
|
||||
var params = 'url=' + encodeURIComponent(windowUrl);
|
||||
params += '&swf=' + encodeURIComponent(this.url);
|
||||
var url = urlTemplate.split('{url}').join(encodeURIComponent(windowUrl));
|
||||
var params = {
|
||||
swf: encodeURIComponent(this.url)
|
||||
};
|
||||
getVersionInfo().then(function (versions) {
|
||||
params += '&ffbuild=' + encodeURIComponent(versions.geckoMstone + ' (' +
|
||||
versions.geckoBuildID + ')');
|
||||
params += '&shubuild=' + encodeURIComponent(versions.shumwayVersion);
|
||||
params.versions = versions;
|
||||
}).then(function () {
|
||||
var postDataStream = StringInputStream.
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
postDataStream.data = 'exceptions=' + encodeURIComponent(exceptions);
|
||||
var postData = MimeInputStream.createInstance(Ci.nsIMIMEInputStream);
|
||||
postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
postData.addContentLength = true;
|
||||
postData.setData(postDataStream);
|
||||
this.window.openDialog('chrome://browser/content', '_blank',
|
||||
'all,dialog=no', base + params, null, null,
|
||||
postData);
|
||||
params.ffbuild = encodeURIComponent(params.versions.geckoMstone +
|
||||
' (' + params.versions.geckoBuildID + ')');
|
||||
params.shubuild = encodeURIComponent(params.versions.shumwayVersion);
|
||||
params.exceptions = encodeURIComponent(exceptions);
|
||||
var comment = '%2B%2B%2B This bug was initially via the problem reporting functionality in ' +
|
||||
'Shumway %2B%2B%2B%0A%0A' +
|
||||
'Please add any further information that you deem helpful here:%0A%0A%0A' +
|
||||
'----------------------%0A%0A' +
|
||||
'Technical Information:%0A' +
|
||||
'Firefox version: ' + params.ffbuild + '%0A' +
|
||||
'Shumway version: ' + params.shubuild;
|
||||
url = url.split('{comment}').join(comment);
|
||||
//this.window.openDialog('chrome://browser/content', '_blank', 'all,dialog=no', url);
|
||||
dump(111);
|
||||
this.window.open(url);
|
||||
}.bind(this));
|
||||
},
|
||||
externalCom: function (data) {
|
||||
@ -526,6 +537,23 @@ ChromeActions.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function monitorUserInput(actions) {
|
||||
function notifyUserInput() {
|
||||
var win = actions.window;
|
||||
var winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
if (winUtils.isHandlingUserInput) {
|
||||
actions.lastUserInput = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
var document = actions.document;
|
||||
document.addEventListener('mousedown', notifyUserInput, false);
|
||||
document.addEventListener('mouseup', notifyUserInput, false);
|
||||
document.addEventListener('keydown', notifyUserInput, false);
|
||||
document.addEventListener('keyup', notifyUserInput, false);
|
||||
}
|
||||
|
||||
// Event listener to trigger chrome privedged code.
|
||||
function RequestListener(actions) {
|
||||
this.actions = actions;
|
||||
@ -737,11 +765,12 @@ function initExternalCom(wrappedWindow, wrappedObject, targetDocument) {
|
||||
return '<undefined/>';
|
||||
}
|
||||
};
|
||||
var sandbox = new Cu.Sandbox(wrappedWindow, {sandboxPrototype: wrappedWindow});
|
||||
wrappedWindow.__flash__eval = function (evalInSandbox, sandbox, expr) {
|
||||
wrappedWindow.__flash__eval = function (expr) {
|
||||
this.console.log('__flash__eval: ' + expr);
|
||||
return evalInSandbox(expr, sandbox);
|
||||
}.bind(wrappedWindow, Cu.evalInSandbox, sandbox);
|
||||
// allowScriptAccess protects page from unwanted swf scripts,
|
||||
// we can execute script in the page context without restrictions.
|
||||
return this.eval(expr);
|
||||
}.bind(wrappedWindow);
|
||||
wrappedWindow.__flash__call = function (expr) {
|
||||
this.console.log('__flash__call (ignored): ' + expr);
|
||||
};
|
||||
@ -989,6 +1018,7 @@ ShumwayStreamConverterBase.prototype = {
|
||||
domWindow.addEventListener('shumway.message', function(event) {
|
||||
requestListener.receive(event);
|
||||
}, false, true);
|
||||
monitorUserInput(actions);
|
||||
|
||||
listener.onStopRequest(aRequest, context, statusCode);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ let Cu = Components.utils;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://shumway/ShumwayStreamConverter.jsm');
|
||||
|
||||
let Svc = {};
|
||||
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
|
||||
@ -111,6 +110,7 @@ let ShumwayUtils = {
|
||||
return;
|
||||
|
||||
// Load the component and register it.
|
||||
Cu.import('resource://shumway/ShumwayStreamConverter.jsm');
|
||||
converterFactory.register(ShumwayStreamConverter);
|
||||
overlayConverterFactory.register(ShumwayStreamOverlayConverter);
|
||||
|
||||
@ -130,6 +130,7 @@ let ShumwayUtils = {
|
||||
// Remove the contract/component.
|
||||
converterFactory.unregister();
|
||||
overlayConverterFactory.unregister();
|
||||
Cu.unload('resource://shumway/ShumwayStreamConverter.jsm');
|
||||
|
||||
Svc.pluginHost.unregisterPlayPreviewMimeType(SWF_CONTENT_TYPE);
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
0.9.2697
|
||||
25bfcc9
|
||||
0.9.2970
|
||||
22f884f
|
||||
|
@ -24,13 +24,17 @@ limitations under the License.
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: rgba(0, 0, 0, 0.78);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
body.started {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
body.started iframe {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#stageContainer {
|
||||
position:fixed !important;
|
||||
left:0;top:0;bottom:0;right:0;
|
||||
@ -106,7 +110,8 @@ limitations under the License.
|
||||
<menuitem label="Show URL" id="showURLMenu"></menuitem>
|
||||
<menuitem label="Open in Inspector" id="inspectorMenu"></menuitem>
|
||||
<menuitem label="Report Problems" id="reportMenu"></menuitem>
|
||||
<menuitem label="Fallback to Flash" id="fallbackMenu" hidden></menuitem>
|
||||
<menuitem label="Reload in Adobe Flash Player" id="fallbackMenu" hidden></menuitem>
|
||||
<menuitem label="About Shumway" id="aboutMenu"></menuitem>
|
||||
</menu>
|
||||
</section>
|
||||
</body>
|
||||
|
@ -144,12 +144,10 @@ function runViewer() {
|
||||
fallbackMenu.removeAttribute('hidden');
|
||||
fallbackMenu.addEventListener('click', fallback);
|
||||
}
|
||||
var showURLMenu = document.getElementById('showURLMenu');
|
||||
showURLMenu.addEventListener('click', showURL);
|
||||
var inspectorMenu = document.getElementById('inspectorMenu');
|
||||
inspectorMenu.addEventListener('click', showInInspector);
|
||||
var reportMenu = document.getElementById('reportMenu');
|
||||
reportMenu.addEventListener('click', reportIssue);
|
||||
document.getElementById('showURLMenu').addEventListener('click', showURL);
|
||||
document.getElementById('inspectorMenu').addEventListener('click', showInInspector);
|
||||
document.getElementById('reportMenu').addEventListener('click', reportIssue);
|
||||
document.getElementById('aboutMenu').addEventListener('click', showAbout);
|
||||
}
|
||||
|
||||
function showURL() {
|
||||
@ -166,23 +164,28 @@ function showInInspector() {
|
||||
}
|
||||
|
||||
function reportIssue() {
|
||||
var duplicatesMap = Object.create(null);
|
||||
var prunedExceptions = [];
|
||||
avm2.exceptions.forEach(function(e) {
|
||||
var ident = e.source + e.message + e.stack;
|
||||
var entry = duplicatesMap[ident];
|
||||
if (!entry) {
|
||||
entry = duplicatesMap[ident] = {
|
||||
source: e.source,
|
||||
message: e.message,
|
||||
stack: e.stack,
|
||||
count: 0
|
||||
};
|
||||
prunedExceptions.push(entry);
|
||||
}
|
||||
entry.count++;
|
||||
});
|
||||
FirefoxCom.requestSync('reportIssue', JSON.stringify(prunedExceptions));
|
||||
//var duplicatesMap = Object.create(null);
|
||||
//var prunedExceptions = [];
|
||||
//avm2.exceptions.forEach(function(e) {
|
||||
// var ident = e.source + e.message + e.stack;
|
||||
// var entry = duplicatesMap[ident];
|
||||
// if (!entry) {
|
||||
// entry = duplicatesMap[ident] = {
|
||||
// source: e.source,
|
||||
// message: e.message,
|
||||
// stack: e.stack,
|
||||
// count: 0
|
||||
// };
|
||||
// prunedExceptions.push(entry);
|
||||
// }
|
||||
// entry.count++;
|
||||
//});
|
||||
//FirefoxCom.requestSync('reportIssue', JSON.stringify(prunedExceptions));
|
||||
FirefoxCom.requestSync('reportIssue');
|
||||
}
|
||||
|
||||
function showAbout() {
|
||||
window.open('http://areweflashyet.com/');
|
||||
}
|
||||
|
||||
var movieUrl, movieParams, objectParams;
|
||||
@ -202,6 +205,12 @@ window.addEventListener("message", function handlerMessage(e) {
|
||||
case 'reportTelemetry':
|
||||
FirefoxCom.request('reportTelemetry', args.data, null);
|
||||
break;
|
||||
case 'setClipboard':
|
||||
FirefoxCom.request('setClipboard', args.data, null);
|
||||
break;
|
||||
case 'started':
|
||||
document.body.classList.add('started');
|
||||
break;
|
||||
}
|
||||
}, true);
|
||||
|
||||
@ -240,7 +249,19 @@ function parseSwf(url, movieParams, objectParams) {
|
||||
FirefoxCom.request('endActivation', null);
|
||||
}
|
||||
|
||||
var easel = createEasel();
|
||||
var bgcolor;
|
||||
if (objectParams) {
|
||||
var m;
|
||||
if (objectParams.bgcolor && (m = /#([0-9A-F]{6})/i.exec(objectParams.bgcolor))) {
|
||||
var hexColor = parseInt(m[1], 16);
|
||||
bgcolor = hexColor << 8 | 0xff;
|
||||
}
|
||||
if (objectParams.wmode === 'transparent') {
|
||||
bgcolor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var easel = createEasel(bgcolor);
|
||||
easelHost = new Shumway.GFX.Window.WindowEaselHost(easel, playerWindow, window);
|
||||
easelHost.processExternalCommand = processExternalCommand;
|
||||
|
||||
@ -252,6 +273,7 @@ function parseSwf(url, movieParams, objectParams) {
|
||||
movieParams: movieParams,
|
||||
objectParams: objectParams,
|
||||
turboMode: turboMode,
|
||||
bgcolor: bgcolor,
|
||||
url: url,
|
||||
baseUrl: url
|
||||
}
|
||||
@ -259,12 +281,12 @@ function parseSwf(url, movieParams, objectParams) {
|
||||
playerWindow.postMessage(data, '*');
|
||||
}
|
||||
|
||||
function createEasel() {
|
||||
function createEasel(bgcolor) {
|
||||
var Stage = Shumway.GFX.Stage;
|
||||
var Easel = Shumway.GFX.Easel;
|
||||
var Canvas2DStageRenderer = Shumway.GFX.Canvas2DStageRenderer;
|
||||
|
||||
Shumway.GFX.WebGL.SHADER_ROOT = SHUMWAY_ROOT + "gfx/gl/shaders/";
|
||||
var backend = Shumway.GFX.backend.value | 0;
|
||||
return new Easel(document.getElementById("stageContainer"), backend);
|
||||
return new Easel(document.getElementById("stageContainer"), backend, false, bgcolor);
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ function runSwfPlayer(flashParams) {
|
||||
Shumway.createAVM2(builtinPath, viewerPlayerglobalInfo, avm1Path, sysMode, appMode, function (avm2) {
|
||||
function runSWF(file) {
|
||||
var player = new Shumway.Player.Window.WindowPlayer(window, window.parent);
|
||||
player.defaultStageColor = flashParams.bgcolor;
|
||||
|
||||
Shumway.ExternalInterfaceService.instance = player.createExternalInterfaceService();
|
||||
|
||||
@ -79,10 +80,17 @@ function setupServices() {
|
||||
}
|
||||
};
|
||||
|
||||
Shumway.ClipboardService.instance = {
|
||||
setClipboard: function (data) {
|
||||
window.parent.postMessage({
|
||||
callback: 'setClipboard',
|
||||
data: data
|
||||
}, '*');
|
||||
}
|
||||
};
|
||||
|
||||
Shumway.FileLoadingService.instance = {
|
||||
get baseUrl() {
|
||||
return movieUrl;
|
||||
},
|
||||
baseUrl: null,
|
||||
nextSessionId: 1, // 0 - is reserved
|
||||
sessions: [],
|
||||
createSession: function () {
|
||||
@ -168,7 +176,11 @@ window.addEventListener('message', function onWindowMessage(e) {
|
||||
}
|
||||
setupServices();
|
||||
runSwfPlayer(data.flashParams);
|
||||
|
||||
document.body.style.backgroundColor = 'green';
|
||||
window.parent.postMessage({
|
||||
callback: 'started'
|
||||
}, '*');
|
||||
break;
|
||||
}
|
||||
}, true);
|
||||
|
@ -2,6 +2,9 @@
|
||||
# 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/.
|
||||
|
||||
index.deprecationNotice=The App Manager will be removed in a future release. Your projects have been migrated to WebIDE.
|
||||
index.launchWebIDE=Launch WebIDE
|
||||
index.readMoreAboutWebIDE=Read More
|
||||
# LOCALIZATION NOTE (device.deviceSize): %1$S is the device's width, %2$S is
|
||||
# the device's height, %3$S is the device's pixel density.
|
||||
# Example: 800x480 (86 DPI).
|
||||
|
@ -231,6 +231,19 @@
|
||||
- for the "Edit and Resend" menu item displayed in the context menu for a request -->
|
||||
<!ENTITY netmonitorUI.summary.editAndResend.accesskey "R">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.summary.rawHeaders): This is the label displayed
|
||||
- on the button in the headers tab that toggle view for raw request/response headers
|
||||
from the currently displayed request -->
|
||||
<!ENTITY netmonitorUI.summary.rawHeaders "Raw headers">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.summary.rawHeaders.requestHeaders): This is the label displayed
|
||||
- in the network details headers tab identifying the raw request headers textarea -->
|
||||
<!ENTITY netmonitorUI.summary.rawHeaders.requestHeaders "Request headers:">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.summary.rawHeaders.responseHeaders): This is the label displayed
|
||||
- in the network details headers tab identifying the raw response headers textarea -->
|
||||
<!ENTITY netmonitorUI.summary.rawHeaders.responseHeaders "Response headers:">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.context.newTab): This is the label
|
||||
- for the Open in New Tab menu item displayed in the context menu of the
|
||||
- network container -->
|
||||
|
@ -39,10 +39,12 @@
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.table.*): These strings are displayed
|
||||
- in the call tree headers for a recording. -->
|
||||
<!ENTITY profilerUI.table.duration "Time (ms)">
|
||||
<!ENTITY profilerUI.table.percentage "Cost">
|
||||
<!ENTITY profilerUI.table.samples "Samples">
|
||||
<!ENTITY profilerUI.table.function "Function">
|
||||
<!ENTITY profilerUI.table.totalDuration "Total Time (ms)">
|
||||
<!ENTITY profilerUI.table.selfDuration "Self Time (ms)">
|
||||
<!ENTITY profilerUI.table.totalPercentage "Total Cost">
|
||||
<!ENTITY profilerUI.table.selfPercentage "Self Cost">
|
||||
<!ENTITY profilerUI.table.samples "Samples">
|
||||
<!ENTITY profilerUI.table.function "Function">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.newtab.tooltiptext): The tooltiptext shown
|
||||
- on the "+" (new tab) button for a profile when a selection is available. -->
|
||||
|
@ -271,8 +271,7 @@ function CreateSocialStatusWidget(aId, aProvider) {
|
||||
onBuild: function(aDocument) {
|
||||
let node = aDocument.createElement('toolbarbutton');
|
||||
node.id = this.id;
|
||||
node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional social-status-button');
|
||||
node.setAttribute('type', "badged");
|
||||
node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional social-status-button badged-button');
|
||||
node.style.listStyleImage = "url(" + (aProvider.icon32URL || aProvider.iconURL) + ")";
|
||||
node.setAttribute("origin", aProvider.origin);
|
||||
node.setAttribute("label", aProvider.name);
|
||||
|
@ -565,7 +565,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
padding: 3px 7px;
|
||||
}
|
||||
|
||||
toolbarbutton[type="badged"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
max-width: 32px !important;
|
||||
}
|
||||
@ -2077,35 +2077,6 @@ toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge-container {
|
||||
margin: 5px 3px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
toolbar[iconsize="small"] .toolbarbutton-badge-container {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""])::after {
|
||||
/* The |content| property is set in the content stylesheet. */
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
padding: 0 1px;
|
||||
color: #fff;
|
||||
background-color: rgb(240,61,37);
|
||||
border: 1px solid rgb(216,55,34);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 0 rgba(0,39,121,0.77);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after {
|
||||
left: 2px;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
|
@ -8,6 +8,10 @@
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#toggle-raw-headers {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.requests-menu-status-and-method {
|
||||
width: 9em;
|
||||
}
|
||||
|
@ -4419,48 +4419,6 @@ menulist.translate-infobar-element > .menulist-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge-container {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""]) {
|
||||
/* The |content| property is set in the content stylesheet. */
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
padding: 0 1px;
|
||||
color: #fff;
|
||||
background-color: rgb(240,61,37);
|
||||
border: 1px solid rgb(216,55,34);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 0 rgba(0,39,121,0.77);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""]):-moz-window-inactive {
|
||||
background-color: rgb(230,230,230);
|
||||
box-shadow: none;
|
||||
border: 1px solid rgb(206,206,206);
|
||||
color: rgb(192,192,192);
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl) {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] > *|* > .toolbarbutton-badge[badge]:not([badge=""]) {
|
||||
right: -2px;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] > *|* > .toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl) {
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
|
@ -485,6 +485,15 @@ label.requests-menu-status-code {
|
||||
-moz-margin-end: 6px;
|
||||
}
|
||||
|
||||
#toggle-raw-headers {
|
||||
margin-top: -10px;
|
||||
-moz-margin-end: 6px;
|
||||
}
|
||||
|
||||
.raw-response-textarea {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
/* Response tabpanel */
|
||||
|
||||
#response-content-info-header {
|
||||
|
@ -251,13 +251,17 @@
|
||||
}
|
||||
|
||||
.call-tree-header[type="duration"],
|
||||
.call-tree-cell[type="duration"] {
|
||||
width: 7em;
|
||||
.call-tree-cell[type="duration"],
|
||||
.call-tree-header[type="self-duration"],
|
||||
.call-tree-cell[type="self-duration"] {
|
||||
width: 9em;
|
||||
}
|
||||
|
||||
.call-tree-header[type="percentage"],
|
||||
.call-tree-cell[type="percentage"] {
|
||||
width: 5em;
|
||||
.call-tree-cell[type="percentage"],
|
||||
.call-tree-header[type="self-percentage"],
|
||||
.call-tree-cell[type="self-percentage"] {
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.call-tree-header[type="samples"],
|
||||
|
@ -2699,59 +2699,6 @@ toolbarpaletteitem[place="palette"] > #switch-to-metro-button {
|
||||
list-style-image: url(chrome://browser/skin/Metro_Glyph-menuPanel.png);
|
||||
}
|
||||
|
||||
.toolbarbutton-badge-container {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container {
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-badge-container > .toolbar-icon {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge-container > .toolbarbutton-icon[label]:not([label=""]) {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge=""] {
|
||||
display: none;
|
||||
}
|
||||
.toolbarbutton-badge[badge]:not([badge=""])::after {
|
||||
/* The |content| property is set in the content stylesheet. */
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
padding: 0 1px;
|
||||
color: #fff;
|
||||
background-color: rgb(240,61,37);
|
||||
border: 1px solid rgb(216,55,34);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 0 rgba(0,39,121,0.77);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-badge[badge]:not([badge=""])::after {
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after {
|
||||
left: 1px;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
|
@ -326,20 +326,6 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$DEVELOPER_OPTIONS"; then
|
||||
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
|
||||
fi
|
||||
fi
|
||||
|
||||
# bionic in Android < 4.1 doesn't support PIE
|
||||
if test "$GNU_CC" -a "$OS_TARGET" != Android; then
|
||||
AC_MSG_CHECKING([for PIE support])
|
||||
_SAVE_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -pie"
|
||||
AC_TRY_LINK(,,AC_MSG_RESULT([yes])
|
||||
[MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
|
||||
AC_MSG_RESULT([no]))
|
||||
LDFLAGS=$_SAVE_LDFLAGS
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_PROGRAM_LDFLAGS)
|
||||
|
||||
])
|
||||
|
||||
dnl GCC and clang will fail if given an unknown warning option like -Wfoobar.
|
||||
|
@ -637,8 +637,6 @@ endif
|
||||
|
||||
endif # NO_PROFILE_GUIDED_OPTIMIZE
|
||||
|
||||
MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRAM_LDFLAGS)
|
||||
|
||||
##############################################
|
||||
|
||||
checkout:
|
||||
@ -671,7 +669,7 @@ $(PROGRAM): $(PROGOBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESF
|
||||
$(REPORT_BUILD)
|
||||
@$(RM) $@.manifest
|
||||
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
|
||||
$(EXPAND_LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
|
||||
$(EXPAND_LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
|
||||
ifdef MSMANIFEST_TOOL
|
||||
@if test -f $@.manifest; then \
|
||||
if test -f '$(srcdir)/$@.manifest'; then \
|
||||
@ -692,7 +690,7 @@ ifdef MOZ_PROFILE_GENERATE
|
||||
touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
|
||||
endif
|
||||
else # !WINNT || GNU_CC
|
||||
$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
|
||||
$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
|
||||
$(call CHECK_BINARY,$@)
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
@ -740,7 +738,7 @@ endif
|
||||
$(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
$(REPORT_BUILD)
|
||||
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
|
||||
$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
|
||||
$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
|
||||
ifdef MSMANIFEST_TOOL
|
||||
@if test -f $@.manifest; then \
|
||||
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
|
||||
@ -748,7 +746,7 @@ ifdef MSMANIFEST_TOOL
|
||||
fi
|
||||
endif # MSVC with manifest tool
|
||||
else
|
||||
$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
|
||||
$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
|
||||
$(call CHECK_BINARY,$@)
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
|
17
configure.in
17
configure.in
@ -2141,6 +2141,9 @@ ia64*-hpux*)
|
||||
# and requires workarounds for perfectly valid code. Also, GCC/clang
|
||||
# don't warn about it by default. So for consistency/sanity, we turn
|
||||
# it off on MSVC, too.
|
||||
# MSVC warning C4267 warns for narrowing type conversions from size_t
|
||||
# to 32-bit integer types on 64-bit platforms. Since this is virtually
|
||||
# the same thing as C4244, we disable C4267, too.
|
||||
# MSVC warning C4345 warns of newly conformant behavior as of VS2003.
|
||||
# MSVC warning C4351 warns of newly conformant behavior as of VS2005.
|
||||
# MSVC warning C4482 warns when an enum value is refered specifing the
|
||||
@ -2152,8 +2155,8 @@ ia64*-hpux*)
|
||||
# that behavior) that it's better to turn it off.
|
||||
# MSVC warning C4819 warns some UTF-8 characters (e.g. copyright sign)
|
||||
# on non-Western system locales even if it is in a comment.
|
||||
CFLAGS="$CFLAGS -wd4244 -wd4819"
|
||||
CXXFLAGS="$CXXFLAGS -wd4251 -wd4244 -wd4345 -wd4351 -wd4482 -wd4800 -wd4819"
|
||||
CFLAGS="$CFLAGS -wd4244 -wd4267 -wd4819"
|
||||
CXXFLAGS="$CXXFLAGS -wd4251 -wd4244 -wd4267 -wd4345 -wd4351 -wd4482 -wd4800 -wd4819"
|
||||
# make 'foo == bar;' error out
|
||||
CFLAGS="$CFLAGS -we4553"
|
||||
CXXFLAGS="$CXXFLAGS -we4553"
|
||||
@ -3849,6 +3852,7 @@ MOZ_ANDROID_SEARCH_ACTIVITY=
|
||||
MOZ_ANDROID_DOWNLOADS_INTEGRATION=
|
||||
MOZ_ANDROID_MLS_STUMBLER=
|
||||
MOZ_ANDROID_SHARE_OVERLAY=
|
||||
MOZ_ANDROID_NEW_TABLET_UI=
|
||||
ACCESSIBILITY=1
|
||||
MOZ_TIME_MANAGER=
|
||||
MOZ_PAY=
|
||||
@ -4908,6 +4912,14 @@ if test -n "$MOZ_ANDROID_SHARE_OVERLAY"; then
|
||||
AC_DEFINE(MOZ_ANDROID_SHARE_OVERLAY)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Include New Tablet UI on Android
|
||||
dnl = Temporary build flag to allow development in Nightly
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_ANDROID_NEW_TABLET_UI"; then
|
||||
AC_DEFINE(MOZ_ANDROID_NEW_TABLET_UI)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable IPDL's "expensive" unit tests
|
||||
dnl ========================================================
|
||||
@ -8517,6 +8529,7 @@ AC_SUBST(MOZ_LOCALE_SWITCHER)
|
||||
AC_SUBST(MOZ_DISABLE_GECKOVIEW)
|
||||
AC_SUBST(MOZ_ANDROID_SEARCH_ACTIVITY)
|
||||
AC_SUBST(MOZ_ANDROID_SHARE_OVERLAY)
|
||||
AC_SUBST(MOZ_ANDROID_NEW_TABLET_UI)
|
||||
AC_SUBST(MOZ_ANDROID_MLS_STUMBLER)
|
||||
AC_SUBST(MOZ_ANDROID_DOWNLOADS_INTEGRATION)
|
||||
AC_SUBST(ENABLE_STRIP)
|
||||
|
@ -55,10 +55,18 @@ AudioSink::Init()
|
||||
nullptr,
|
||||
MEDIA_THREAD_STACK_SIZE);
|
||||
if (NS_FAILED(rv)) {
|
||||
mStateMachine->OnAudioSinkError();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop);
|
||||
return mThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
mStateMachine->OnAudioSinkError();
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int64_t
|
||||
@ -138,6 +146,8 @@ AudioSink::AudioLoop()
|
||||
|
||||
if (NS_FAILED(InitializeAudioStream())) {
|
||||
NS_WARNING("Initializing AudioStream failed.");
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mStateMachine->OnAudioSinkError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -197,10 +207,13 @@ AudioSink::InitializeAudioStream()
|
||||
// circumstances, so we take care to drop the decoder monitor while
|
||||
// initializing.
|
||||
RefPtr<AudioStream> audioStream(new AudioStream());
|
||||
audioStream->Init(mInfo.mChannels, mInfo.mRate,
|
||||
mChannel, AudioStream::HighLatency);
|
||||
// TODO: Check Init's return value and bail on error. Unfortunately this
|
||||
// causes some tests to fail due to playback failing.
|
||||
nsresult rv = audioStream->Init(mInfo.mChannels, mInfo.mRate,
|
||||
mChannel, AudioStream::HighLatency);
|
||||
if (NS_FAILED(rv)) {
|
||||
audioStream->Shutdown();
|
||||
return rv;
|
||||
}
|
||||
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mAudioStream = audioStream;
|
||||
UpdateStreamSettings();
|
||||
|
@ -1154,9 +1154,9 @@ void MediaDecoderStateMachine::StartPlayback()
|
||||
SetPlayStartTime(TimeStamp::Now());
|
||||
|
||||
NS_ASSERTION(IsPlaying(), "Should report playing by end of StartPlayback()");
|
||||
if (NS_FAILED(StartAudioThread())) {
|
||||
DECODER_WARN("Failed to create audio thread");
|
||||
}
|
||||
nsresult rv = StartAudioThread();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
mDecoder->UpdateStreamBlockingForStateMachinePlaying();
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
@ -1791,15 +1791,12 @@ MediaDecoderStateMachine::StartAudioThread()
|
||||
mStopAudioThread = false;
|
||||
if (HasAudio() && !mAudioSink) {
|
||||
mAudioCompleted = false;
|
||||
mAudioSink = new AudioSink(this,
|
||||
mAudioStartTime, mInfo.mAudio, mDecoder->GetAudioChannel());
|
||||
mAudioSink = new AudioSink(this, mAudioStartTime,
|
||||
mInfo.mAudio, mDecoder->GetAudioChannel());
|
||||
// OnAudioSinkError() will be called before Init() returns if an error
|
||||
// occurs during initialization.
|
||||
nsresult rv = mAudioSink->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
DECODER_WARN("Changed state to SHUTDOWN because audio sink initialization failed");
|
||||
SetState(DECODER_STATE_SHUTDOWN);
|
||||
mScheduler->ScheduleAndShutdown();
|
||||
return rv;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mAudioSink->SetVolume(mVolume);
|
||||
mAudioSink->SetPlaybackRate(mPlaybackRate);
|
||||
@ -3124,6 +3121,25 @@ void MediaDecoderStateMachine::OnAudioSinkComplete()
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::OnAudioSinkError()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
// AudioSink not used with captured streams, so ignore errors in this case.
|
||||
if (mAudioCaptured) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAudioCompleted = true;
|
||||
|
||||
// Notify media decoder/element about this error.
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnDecodeError));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
if (NS_FAILED(rv)) {
|
||||
DECODER_WARN("Failed to dispatch OnDecodeError");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// avoid redefined macro in unified build
|
||||
|
@ -636,6 +636,9 @@ protected:
|
||||
// and the sink is shutting down.
|
||||
void OnAudioSinkComplete();
|
||||
|
||||
// Called by the AudioSink to signal errors.
|
||||
void OnAudioSinkError();
|
||||
|
||||
// The decoder object that created this state machine. The state machine
|
||||
// holds a strong reference to the decoder to ensure that the decoder stays
|
||||
// alive once media element has started the decoder shutdown process, and has
|
||||
|
@ -98,6 +98,9 @@ public:
|
||||
private:
|
||||
void NotifyDataArrived()
|
||||
{
|
||||
if (mOmxReader->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
const char* buffer = mBuffer.get();
|
||||
|
||||
while (mLength) {
|
||||
@ -118,15 +121,23 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<MediaOmxReader> mOmxReader;
|
||||
nsRefPtr<MediaOmxReader> mOmxReader;
|
||||
nsAutoArrayPtr<const char> mBuffer;
|
||||
uint64_t mLength;
|
||||
int64_t mOffset;
|
||||
uint64_t mFullLength;
|
||||
};
|
||||
|
||||
void MediaOmxReader::CancelProcessCachedData()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(mMutex);
|
||||
mIsShutdown = true;
|
||||
}
|
||||
|
||||
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
|
||||
: MediaOmxCommonReader(aDecoder)
|
||||
, mMutex("MediaOmxReader.Data")
|
||||
, mMP3FrameParser(-1)
|
||||
, mHasVideo(false)
|
||||
, mHasAudio(false)
|
||||
@ -135,6 +146,7 @@ MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
|
||||
, mSkipCount(0)
|
||||
, mUseParserDuration(false)
|
||||
, mLastParserDuration(-1)
|
||||
, mIsShutdown(false)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gMediaDecoderLog) {
|
||||
@ -164,6 +176,10 @@ void MediaOmxReader::ReleaseDecoder()
|
||||
|
||||
void MediaOmxReader::Shutdown()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> cancelEvent =
|
||||
NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData);
|
||||
NS_DispatchToMainThread(cancelEvent);
|
||||
|
||||
ReleaseMediaResources();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &MediaOmxReader::ReleaseDecoder);
|
||||
@ -449,7 +465,9 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
if (HasVideo()) {
|
||||
return;
|
||||
}
|
||||
@ -547,6 +565,10 @@ void MediaOmxReader::EnsureActive() {
|
||||
|
||||
int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
|
||||
{
|
||||
// Could run on decoder thread or IO thread.
|
||||
if (IsShutdown()) {
|
||||
return -1;
|
||||
}
|
||||
// We read data in chunks of 32 KiB. We can reduce this
|
||||
// value if media, such as sdcards, is too slow.
|
||||
// Because of SD card's slowness, need to keep sReadSize to small size.
|
||||
|
@ -30,6 +30,8 @@ class AbstractMediaDecoder;
|
||||
|
||||
class MediaOmxReader : public MediaOmxCommonReader
|
||||
{
|
||||
// This flag protect the mIsShutdown variable, that may access by decoder / main / IO thread.
|
||||
Mutex mMutex;
|
||||
nsCString mType;
|
||||
bool mHasVideo;
|
||||
bool mHasAudio;
|
||||
@ -40,6 +42,7 @@ class MediaOmxReader : public MediaOmxCommonReader
|
||||
int64_t mLastParserDuration;
|
||||
int32_t mSkipCount;
|
||||
bool mUseParserDuration;
|
||||
bool mIsShutdown;
|
||||
protected:
|
||||
android::sp<android::OmxDecoder> mOmxDecoder;
|
||||
android::sp<android::MediaExtractor> mExtractor;
|
||||
@ -91,10 +94,17 @@ public:
|
||||
|
||||
virtual void Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
bool IsShutdown() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mIsShutdown;
|
||||
}
|
||||
|
||||
void ReleaseDecoder();
|
||||
|
||||
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
|
||||
|
||||
void CancelProcessCachedData();
|
||||
|
||||
android::sp<android::MediaSource> GetAudioOffloadTrack();
|
||||
};
|
||||
|
||||
|
@ -819,11 +819,13 @@ function MediaTestManager() {
|
||||
if (this.onFinished) {
|
||||
this.onFinished();
|
||||
}
|
||||
mediaTestCleanup();
|
||||
var end = new Date();
|
||||
SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
|
||||
SimpleTest.info("Running time: " + (end.getTime() - this.startTime.getTime())/1000 + "s");
|
||||
SimpleTest.finish();
|
||||
var onCleanup = function() {
|
||||
var end = new Date();
|
||||
SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
|
||||
SimpleTest.info("Running time: " + (end.getTime() - this.startTime.getTime())/1000 + "s");
|
||||
SimpleTest.finish();
|
||||
}.bind(this);
|
||||
mediaTestCleanup(onCleanup);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -832,7 +834,7 @@ function MediaTestManager() {
|
||||
// Ensures we've got no active video or audio elements in the document, and
|
||||
// forces a GC to release the address space reserved by the decoders' threads'
|
||||
// stacks.
|
||||
function mediaTestCleanup() {
|
||||
function mediaTestCleanup(callback) {
|
||||
var V = document.getElementsByTagName("video");
|
||||
for (i=0; i<V.length; i++) {
|
||||
removeNodeAndSource(V[i]);
|
||||
@ -843,7 +845,12 @@ function mediaTestCleanup() {
|
||||
removeNodeAndSource(A[i]);
|
||||
A[i] = null;
|
||||
}
|
||||
SpecialPowers.forceGC();
|
||||
var cb = function() {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
SpecialPowers.exactGC(window, cb);
|
||||
}
|
||||
|
||||
(function() {
|
||||
|
@ -22,7 +22,7 @@
|
||||
# do ok(true, "Type not supported") and stop the test.
|
||||
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'mulet'
|
||||
skip-if = buildapp == 'mulet' || contentSandbox != 'off' # contentSandbox(Bug 1042735)
|
||||
support-files =
|
||||
320x240.ogv
|
||||
320x240.ogv^headers^
|
||||
|
@ -39,6 +39,7 @@ function stopped(event) {
|
||||
return;
|
||||
v._finished = true;
|
||||
ok(v.paused, "Video should be paused after removing from the Document");
|
||||
removeNodeAndSource(v);
|
||||
manager.finished(v.token);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ function seekEnded(e) {
|
||||
v.currentTime + " for " + v._name);
|
||||
ok(!v.ended, "Checking ended is false for " + v._name);
|
||||
v._finished = true;
|
||||
v.parentNode.removeChild(v);
|
||||
removeNodeAndSource(v);
|
||||
manager.finished(v.token);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) #b2g-debug,b2g-desktop(bug 916135)
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || contentSandbox != 'off' #b2g-debug,b2g-desktop(bug 916135); contentSandbox(Bug 1042735)
|
||||
support-files =
|
||||
audio-expected.wav
|
||||
audio-mono-expected-2.wav
|
||||
|
@ -53,6 +53,7 @@
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "mozInlineSpellChecker.h"
|
||||
#include "nsIConsoleListener.h"
|
||||
#include "nsICycleCollectorListener.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
@ -77,6 +78,7 @@
|
||||
#include "nsIJSRuntimeService.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsAnonymousTemporaryFile.h"
|
||||
#include "nsISpellChecker.h"
|
||||
|
||||
#include "IHistory.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -693,7 +695,7 @@ ContentChild::InitXPCOM()
|
||||
NS_WARNING("Couldn't register console listener for child process");
|
||||
|
||||
bool isOffline;
|
||||
SendGetXPCOMProcessAttributes(&isOffline);
|
||||
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries);
|
||||
RecvSetOffline(isOffline);
|
||||
|
||||
DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
|
||||
@ -1125,6 +1127,12 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries)
|
||||
{
|
||||
aDictionaries = mAvailableDictionaries;
|
||||
}
|
||||
|
||||
PFileDescriptorSetChild*
|
||||
ContentChild::AllocPFileDescriptorSetChild(const FileDescriptor& aFD)
|
||||
{
|
||||
@ -1153,7 +1161,7 @@ ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
|
||||
mozilla::PRemoteSpellcheckEngineChild *
|
||||
ContentChild::AllocPRemoteSpellcheckEngineChild()
|
||||
{
|
||||
NS_NOTREACHED("Default Constructor for PRemoteSpellcheckEngineChilf should never be called");
|
||||
NS_NOTREACHED("Default Constructor for PRemoteSpellcheckEngineChild should never be called");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1742,6 +1750,14 @@ ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvUpdateDictionaryList(const InfallibleTArray<nsString>& aDictionaries)
|
||||
{
|
||||
mAvailableDictionaries = aDictionaries;
|
||||
mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvAddPermission(const IPC::Permission& permission)
|
||||
{
|
||||
|
@ -293,6 +293,8 @@ public:
|
||||
|
||||
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvUpdateDictionaryList(const InfallibleTArray<nsString>& aDictionaries) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvAddPermission(const IPC::Permission& permission) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvScreenSizeChanged(const gfxIntSize &size) MOZ_OVERRIDE;
|
||||
@ -381,6 +383,8 @@ public:
|
||||
const bool& aIsForApp,
|
||||
const bool& aIsForBrowser) MOZ_OVERRIDE;
|
||||
|
||||
void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
|
||||
|
||||
private:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
@ -397,6 +401,8 @@ private:
|
||||
|
||||
nsTHashtable<nsPtrHashKey<nsIObserver>> mIdleObservers;
|
||||
|
||||
InfallibleTArray<nsString> mAvailableDictionaries;
|
||||
|
||||
/**
|
||||
* An ID unique to the process containing our corresponding
|
||||
* content parent.
|
||||
|
@ -101,6 +101,7 @@
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsISiteSecurityService.h"
|
||||
#include "nsISpellChecker.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIURIFixup.h"
|
||||
@ -2496,7 +2497,8 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
|
||||
// Update offline settings.
|
||||
bool isOffline;
|
||||
RecvGetXPCOMProcessAttributes(&isOffline);
|
||||
InfallibleTArray<nsString> unusedDictionaries;
|
||||
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries);
|
||||
content->SendSetOffline(isOffline);
|
||||
|
||||
PreallocatedProcessManager::PublishSpareProcess(content);
|
||||
@ -2744,12 +2746,18 @@ ContentParent::RecvGetProcessAttributes(uint64_t* aId,
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline)
|
||||
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
InfallibleTArray<nsString>* dictionaries)
|
||||
{
|
||||
nsCOMPtr<nsIIOService> io(do_GetIOService());
|
||||
NS_ASSERTION(io, "No IO service?");
|
||||
MOZ_ASSERT(io, "No IO service?");
|
||||
DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed getting offline?");
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
|
||||
|
||||
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
|
||||
MOZ_ASSERT(spellChecker, "No spell checker?");
|
||||
|
||||
spellChecker->GetDictionaryList(dictionaries);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -4053,6 +4061,23 @@ ContentParent::IgnoreIPCPrincipal()
|
||||
return sIgnoreIPCPrincipal;
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::NotifyUpdatedDictionaries()
|
||||
{
|
||||
nsAutoTArray<ContentParent*, 8> processes;
|
||||
GetAll(processes);
|
||||
|
||||
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
|
||||
MOZ_ASSERT(spellChecker, "No spell checker?");
|
||||
|
||||
InfallibleTArray<nsString> dictionaries;
|
||||
spellChecker->GetDictionaryList(&dictionaries);
|
||||
|
||||
for (size_t i = 0; i < processes.Length(); ++i) {
|
||||
unused << processes[i]->SendUpdateDictionaryList(dictionaries);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -139,6 +139,8 @@ public:
|
||||
|
||||
static bool IgnoreIPCPrincipal();
|
||||
|
||||
static void NotifyUpdatedDictionaries();
|
||||
|
||||
virtual bool RecvCreateChildProcess(const IPCTabContext& aContext,
|
||||
const hal::ProcessPriority& aPriority,
|
||||
uint64_t* aId,
|
||||
@ -410,7 +412,9 @@ private:
|
||||
virtual bool RecvGetProcessAttributes(uint64_t* aId,
|
||||
bool* aIsForApp,
|
||||
bool* aIsForBrowser) MOZ_OVERRIDE;
|
||||
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline) MOZ_OVERRIDE;
|
||||
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
|
||||
InfallibleTArray<nsString>* dictionaries)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -433,6 +433,8 @@ child:
|
||||
|
||||
GeolocationUpdate(GeoPosition somewhere);
|
||||
|
||||
UpdateDictionaryList(nsString[] dictionaries);
|
||||
|
||||
// nsIPermissionManager messages
|
||||
AddPermission(Permission permission);
|
||||
|
||||
@ -442,7 +444,7 @@ child:
|
||||
|
||||
GarbageCollect();
|
||||
CycleCollect();
|
||||
|
||||
|
||||
/**
|
||||
* Start accessibility engine in content process.
|
||||
*/
|
||||
@ -504,7 +506,7 @@ parent:
|
||||
sync GetProcessAttributes()
|
||||
returns (uint64_t id, bool isForApp, bool isForBrowser);
|
||||
sync GetXPCOMProcessAttributes()
|
||||
returns (bool isOffline);
|
||||
returns (bool isOffline, nsString[] dictionaries);
|
||||
|
||||
sync CreateChildProcess(IPCTabContext context,
|
||||
ProcessPriority priority)
|
||||
|
@ -109,7 +109,9 @@ LOCAL_INCLUDES += [
|
||||
'/dom/geolocation',
|
||||
'/dom/mobilemessage/ipc',
|
||||
'/dom/storage',
|
||||
'/editor/libeditor',
|
||||
'/extensions/cookie',
|
||||
'/extensions/spellcheck/src',
|
||||
'/hal/sandbox',
|
||||
'/js/ipc',
|
||||
'/layout/base',
|
||||
|
@ -1,4 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = contentSandbox != 'off' # contentSandbox(Bug 1042735)
|
||||
support-files =
|
||||
head.js
|
||||
constraints.js
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 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/. */
|
||||
@ -46,16 +47,16 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
class UpdateDictionnaryHolder {
|
||||
class UpdateDictionaryHolder {
|
||||
private:
|
||||
nsEditorSpellCheck* mSpellCheck;
|
||||
public:
|
||||
explicit UpdateDictionnaryHolder(nsEditorSpellCheck* esc): mSpellCheck(esc) {
|
||||
explicit UpdateDictionaryHolder(nsEditorSpellCheck* esc): mSpellCheck(esc) {
|
||||
if (mSpellCheck) {
|
||||
mSpellCheck->BeginUpdateDictionary();
|
||||
}
|
||||
}
|
||||
~UpdateDictionnaryHolder() {
|
||||
~UpdateDictionaryHolder() {
|
||||
if (mSpellCheck) {
|
||||
mSpellCheck->EndUpdateDictionary();
|
||||
}
|
||||
@ -699,23 +700,15 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba
|
||||
}
|
||||
NS_ENSURE_TRUE(rootContent, NS_ERROR_FAILURE);
|
||||
|
||||
DictionaryFetcher* fetcher = new DictionaryFetcher(this, aCallback,
|
||||
mDictionaryFetcherGroup);
|
||||
nsRefPtr<DictionaryFetcher> fetcher =
|
||||
new DictionaryFetcher(this, aCallback, mDictionaryFetcherGroup);
|
||||
rootContent->GetLang(fetcher->mRootContentLang);
|
||||
nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
|
||||
NS_ENSURE_STATE(doc);
|
||||
doc->GetContentLanguage(fetcher->mRootDocContentLang);
|
||||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
// Content prefs don't work in E10S (Bug 1027898) pretend that we
|
||||
// didn't have any & trigger the asynchrous completion.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethodWithArg<uint16_t>(fetcher, &DictionaryFetcher::HandleCompletion, 0);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
} else {
|
||||
rv = fetcher->Fetch(mEditor);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = fetcher->Fetch(mEditor);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -723,14 +716,13 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba
|
||||
nsresult
|
||||
nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
|
||||
{
|
||||
MOZ_ASSERT(aFetcher);
|
||||
nsRefPtr<nsEditorSpellCheck> kungFuDeathGrip = this;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Important: declare the holder after the callback caller so that the former
|
||||
// is destructed first so that it's not active when the callback is called.
|
||||
CallbackCaller callbackCaller(aFetcher->mCallback);
|
||||
UpdateDictionnaryHolder holder(this);
|
||||
UpdateDictionaryHolder holder(this);
|
||||
|
||||
if (aFetcher->mGroup < mDictionaryFetcherGroup) {
|
||||
// SetCurrentDictionary was called after the fetch started. Don't overwrite
|
||||
@ -742,10 +734,9 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
|
||||
|
||||
// If we successfully fetched a dictionary from content prefs, do not go
|
||||
// further. Use this exact dictionary.
|
||||
nsAutoString dictName;
|
||||
dictName.Assign(aFetcher->mDictionary);
|
||||
nsAutoString dictName(aFetcher->mDictionary);
|
||||
if (!dictName.IsEmpty()) {
|
||||
if (NS_FAILED(SetCurrentDictionary(dictName))) {
|
||||
if (NS_FAILED(SetCurrentDictionary(dictName))) {
|
||||
// may be dictionary was uninstalled ?
|
||||
ClearCurrentDictionary(mEditor);
|
||||
}
|
||||
@ -773,8 +764,8 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
|
||||
dictName.Assign(preferedDict);
|
||||
}
|
||||
|
||||
if (dictName.IsEmpty())
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (dictName.IsEmpty()) {
|
||||
// Prefs didn't give us a dictionary name, so just get the current
|
||||
// locale and use that as the default dictionary name!
|
||||
|
||||
|
@ -6,17 +6,17 @@ include protocol PContent;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
rpc protocol PRemoteSpellcheckEngine {
|
||||
sync protocol PRemoteSpellcheckEngine {
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
__delete__();
|
||||
|
||||
rpc Check(nsString aWord) returns (bool aIsMisspelled);
|
||||
sync Check(nsString aWord) returns (bool aIsMisspelled);
|
||||
|
||||
rpc CheckAndSuggest(nsString aWord) returns (bool aIsMisspelled, nsString[] aSuggestions);
|
||||
sync CheckAndSuggest(nsString aWord) returns (bool aIsMisspelled, nsString[] aSuggestions);
|
||||
|
||||
rpc SetDictionary(nsString aDictionary) returns (bool success);
|
||||
sync SetDictionary(nsString aDictionary) returns (bool success);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -5,8 +5,9 @@
|
||||
#include "RemoteSpellCheckEngineChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
RemoteSpellcheckEngineChild::RemoteSpellcheckEngineChild(mozSpellChecker *aOwner)
|
||||
:mOwner(aOwner)
|
||||
: mOwner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
@ -15,7 +16,6 @@ RemoteSpellcheckEngineChild::~RemoteSpellcheckEngineChild()
|
||||
// null out the owner's SpellcheckEngineChild to prevent state corruption
|
||||
// during shutdown
|
||||
mOwner->DeleteRemoteEngine();
|
||||
|
||||
}
|
||||
|
||||
} //namespace mozilla
|
||||
|
@ -11,11 +11,12 @@
|
||||
class mozSpellChecker;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class RemoteSpellcheckEngineChild : public mozilla::PRemoteSpellcheckEngineChild
|
||||
{
|
||||
public:
|
||||
explicit RemoteSpellcheckEngineChild(mozSpellChecker *aOwner);
|
||||
~RemoteSpellcheckEngineChild();
|
||||
virtual ~RemoteSpellcheckEngineChild();
|
||||
|
||||
private:
|
||||
mozSpellChecker *mOwner;
|
||||
|
@ -1,18 +1,17 @@
|
||||
/* vim: set ts=2 sw=2 sts=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/. */
|
||||
|
||||
#include "RemoteSpellCheckEngineParent.h"
|
||||
#include "mozISpellCheckingEngine.h"
|
||||
#include "nsISpellChecker.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
RemoteSpellcheckEngineParent::RemoteSpellcheckEngineParent()
|
||||
{
|
||||
mEngine = do_GetService(DEFAULT_SPELL_CHECKER);
|
||||
mSpellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID);
|
||||
}
|
||||
|
||||
RemoteSpellcheckEngineParent::~RemoteSpellcheckEngineParent()
|
||||
@ -20,43 +19,38 @@ RemoteSpellcheckEngineParent::~RemoteSpellcheckEngineParent()
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteSpellcheckEngineParent::AnswerSetDictionary(
|
||||
RemoteSpellcheckEngineParent::RecvSetDictionary(
|
||||
const nsString& aDictionary,
|
||||
bool* success)
|
||||
{
|
||||
nsresult rv = mEngine->SetDictionary(aDictionary.get());
|
||||
nsresult rv = mSpellChecker->SetCurrentDictionary(aDictionary);
|
||||
*success = NS_SUCCEEDED(rv);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteSpellcheckEngineParent::AnswerCheck(
|
||||
RemoteSpellcheckEngineParent::RecvCheck(
|
||||
const nsString& aWord,
|
||||
bool* aIsMisspelled)
|
||||
{
|
||||
bool isCorrect = true;
|
||||
mEngine->Check(aWord.get(), &isCorrect);
|
||||
*aIsMisspelled = !isCorrect;
|
||||
nsresult rv = mSpellChecker->CheckWord(aWord, aIsMisspelled, nullptr);
|
||||
|
||||
// If CheckWord failed, we can't tell whether the word is correctly spelled.
|
||||
if (NS_FAILED(rv))
|
||||
*aIsMisspelled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RemoteSpellcheckEngineParent::AnswerCheckAndSuggest(
|
||||
RemoteSpellcheckEngineParent::RecvCheckAndSuggest(
|
||||
const nsString& aWord,
|
||||
bool* aIsMisspelled,
|
||||
InfallibleTArray<nsString>* aSuggestions)
|
||||
{
|
||||
bool isCorrect = true;
|
||||
mEngine->Check(aWord.get(), &isCorrect);
|
||||
*aIsMisspelled = !isCorrect;
|
||||
if (!isCorrect) {
|
||||
char16_t **suggestions;
|
||||
uint32_t count = 0;
|
||||
mEngine->Suggest(aWord.get(), &suggestions, &count);
|
||||
|
||||
for (uint32_t i=0; i<count; i++) {
|
||||
aSuggestions->AppendElement(nsDependentString(suggestions[i]));
|
||||
}
|
||||
nsresult rv = mSpellChecker->CheckWord(aWord, aIsMisspelled, aSuggestions);
|
||||
if (NS_FAILED(rv)) {
|
||||
aSuggestions->Clear();
|
||||
*aIsMisspelled = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -67,4 +61,3 @@ RemoteSpellcheckEngineParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -4,34 +4,34 @@
|
||||
#ifndef RemoteSpellcheckEngineParent_h_
|
||||
#define RemoteSpellcheckEngineParent_h_
|
||||
|
||||
#include "mozISpellCheckingEngine.h"
|
||||
#include "mozilla/PRemoteSpellcheckEngineParent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsISpellChecker;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class RemoteSpellcheckEngineParent : public mozilla::PRemoteSpellcheckEngineParent {
|
||||
|
||||
class RemoteSpellcheckEngineParent : public PRemoteSpellcheckEngineParent
|
||||
{
|
||||
public:
|
||||
RemoteSpellcheckEngineParent();
|
||||
|
||||
~RemoteSpellcheckEngineParent();
|
||||
virtual ~RemoteSpellcheckEngineParent();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy);
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
bool AnswerSetDictionary(const nsString& aDictionary, bool* success);
|
||||
|
||||
bool AnswerCheck( const nsString& aWord, bool* aIsMisspelled);
|
||||
|
||||
bool AnswerCheckAndSuggest(
|
||||
const nsString& aWord,
|
||||
bool* aIsMisspelled,
|
||||
InfallibleTArray<nsString>* aSuggestions);
|
||||
virtual bool RecvSetDictionary(const nsString& aDictionary,
|
||||
bool* success) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCheck(const nsString& aWord, bool* aIsMisspelled) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCheckAndSuggest(const nsString& aWord,
|
||||
bool* aIsMisspelled,
|
||||
InfallibleTArray<nsString>* aSuggestions)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsCOMPtr<mozISpellCheckingEngine> mEngine;
|
||||
nsCOMPtr<nsISpellChecker> mSpellChecker;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -76,7 +76,9 @@
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::dom::EncodingUtils;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell)
|
||||
@ -113,7 +115,7 @@ mozHunspell::mozHunspell()
|
||||
nsresult
|
||||
mozHunspell::Init()
|
||||
{
|
||||
LoadDictionaryList();
|
||||
LoadDictionaryList(false);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
@ -344,7 +346,7 @@ NS_IMETHODIMP mozHunspell::GetDictionaryList(char16_t ***aDictionaries,
|
||||
}
|
||||
|
||||
void
|
||||
mozHunspell::LoadDictionaryList()
|
||||
mozHunspell::LoadDictionaryList(bool aNotifyChildProcesses)
|
||||
{
|
||||
mDictionaries.Clear();
|
||||
|
||||
@ -424,6 +426,10 @@ mozHunspell::LoadDictionaryList()
|
||||
// dictionary and any editors which may use it.
|
||||
mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
|
||||
|
||||
if (aNotifyChildProcesses) {
|
||||
ContentParent::NotifyUpdatedDictionaries();
|
||||
}
|
||||
|
||||
// Check if the current dictionary is still available.
|
||||
// If not, try to replace it with another dictionary of the same language.
|
||||
if (!mDictionary.IsEmpty()) {
|
||||
@ -589,7 +595,7 @@ mozHunspell::Observe(nsISupports* aSubj, const char *aTopic,
|
||||
|| !strcmp(aTopic, "profile-after-change"),
|
||||
"Unexpected observer topic");
|
||||
|
||||
LoadDictionaryList();
|
||||
LoadDictionaryList(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -598,7 +604,7 @@ mozHunspell::Observe(nsISupports* aSubj, const char *aTopic,
|
||||
NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir)
|
||||
{
|
||||
mDynamicDirectories.AppendObject(aDir);
|
||||
LoadDictionaryList();
|
||||
LoadDictionaryList(true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -606,6 +612,6 @@ NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir)
|
||||
NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir)
|
||||
{
|
||||
mDynamicDirectories.RemoveObject(aDir);
|
||||
LoadDictionaryList();
|
||||
LoadDictionaryList(true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
|
||||
nsresult Init();
|
||||
|
||||
void LoadDictionaryList();
|
||||
void LoadDictionaryList(bool aNotifyChildProcesses);
|
||||
|
||||
// helper method for converting a word to the charset of the dictionary
|
||||
nsresult ConvertCharset(const char16_t* aStr, char ** aDst);
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* vim: set ts=2 sts=2 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/. */
|
||||
@ -34,38 +35,41 @@ NS_IMPL_CYCLE_COLLECTION(mozSpellChecker,
|
||||
mPersonalDictionary)
|
||||
|
||||
mozSpellChecker::mozSpellChecker()
|
||||
: mEngine(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
mozSpellChecker::~mozSpellChecker()
|
||||
{
|
||||
if(mPersonalDictionary){
|
||||
if (mPersonalDictionary) {
|
||||
// mPersonalDictionary->Save();
|
||||
mPersonalDictionary->EndSession();
|
||||
}
|
||||
mSpellCheckingEngine = nullptr;
|
||||
mPersonalDictionary = nullptr;
|
||||
|
||||
if(XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
if (mEngine) {
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
|
||||
mEngine->Send__delete__(mEngine);
|
||||
MOZ_ASSERT(!mEngine);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsresult
|
||||
mozSpellChecker::Init()
|
||||
{
|
||||
mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
|
||||
|
||||
mSpellCheckingEngine = nullptr;
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton();
|
||||
MOZ_ASSERT(contentChild);
|
||||
mEngine = new RemoteSpellcheckEngineChild(this);
|
||||
contentChild->SendPRemoteSpellcheckEngineConstructor(mEngine);
|
||||
} else {
|
||||
mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSpellChecker::SetDocument(nsITextServicesDocument *aDoc, bool aFromStartofDoc)
|
||||
@ -130,9 +134,9 @@ mozSpellChecker::CheckWord(const nsAString &aWord, bool *aIsMisspelled, nsTArray
|
||||
nsString wordwrapped = nsString(aWord);
|
||||
bool rv;
|
||||
if (aSuggestions) {
|
||||
rv = mEngine->CallCheckAndSuggest(wordwrapped, aIsMisspelled, aSuggestions);
|
||||
rv = mEngine->SendCheckAndSuggest(wordwrapped, aIsMisspelled, aSuggestions);
|
||||
} else {
|
||||
rv = mEngine->CallCheck(wordwrapped, aIsMisspelled);
|
||||
rv = mEngine->SendCheck(wordwrapped, aIsMisspelled);
|
||||
}
|
||||
return rv ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
@ -302,9 +306,15 @@ mozSpellChecker::GetPersonalDictionary(nsTArray<nsString> *aWordList)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_IMETHODIMP
|
||||
mozSpellChecker::GetDictionaryList(nsTArray<nsString> *aDictionaryList)
|
||||
{
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
ContentChild *child = ContentChild::GetSingleton();
|
||||
child->GetAvailableDictionaries(*aDictionaryList);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// For catching duplicates
|
||||
@ -344,9 +354,14 @@ mozSpellChecker::GetDictionaryList(nsTArray<nsString> *aDictionaryList)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_IMETHODIMP
|
||||
mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary)
|
||||
{
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
aDictionary = mCurrentDictionary;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mSpellCheckingEngine) {
|
||||
aDictionary.Truncate();
|
||||
return NS_OK;
|
||||
@ -358,14 +373,20 @@ mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_IMETHODIMP
|
||||
mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
|
||||
{
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
nsString wrappedDict = nsString(aDictionary);
|
||||
bool isSuccess;
|
||||
mEngine->CallSetDictionary(wrappedDict, &isSuccess);
|
||||
return isSuccess ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
mEngine->SendSetDictionary(wrappedDict, &isSuccess);
|
||||
if (!isSuccess) {
|
||||
mCurrentDictionary.Truncate();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mCurrentDictionary = wrappedDict;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Calls to mozISpellCheckingEngine::SetDictionary might destroy us
|
||||
@ -402,7 +423,7 @@ mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
|
||||
}
|
||||
|
||||
mSpellCheckingEngine = nullptr;
|
||||
|
||||
|
||||
// We could not find any engine with the requested dictionary
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
@ -515,6 +536,8 @@ mozSpellChecker::GetCurrentBlockIndex(nsITextServicesDocument *aDoc, int32_t *ou
|
||||
nsresult
|
||||
mozSpellChecker::GetEngineList(nsCOMArray<mozISpellCheckingEngine>* aSpellCheckingEngines)
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Content);
|
||||
|
||||
nsresult rv;
|
||||
bool hasMoreEngines;
|
||||
|
||||
@ -564,7 +587,3 @@ mozSpellChecker::GetEngineList(nsCOMArray<mozISpellCheckingEngine>* aSpellChecki
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void mozSpellChecker::DeleteRemoteEngine() {
|
||||
mEngine = nullptr;
|
||||
}
|
||||
|
@ -49,7 +49,10 @@ public:
|
||||
NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary);
|
||||
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary);
|
||||
NS_IMETHOD CheckCurrentDictionary();
|
||||
void DeleteRemoteEngine();
|
||||
|
||||
void DeleteRemoteEngine() {
|
||||
mEngine = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~mozSpellChecker();
|
||||
@ -61,6 +64,8 @@ protected:
|
||||
nsCOMPtr<mozISpellCheckingEngine> mSpellCheckingEngine;
|
||||
bool mFromStart;
|
||||
|
||||
nsString mCurrentDictionary;
|
||||
|
||||
nsresult SetupDoc(int32_t *outBlockOffset);
|
||||
|
||||
nsresult GetCurrentBlockIndex(nsITextServicesDocument *aDoc, int32_t *outBlockIndex);
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
/**
|
||||
* Schedules a runnable to run on the controller/UI thread at some time
|
||||
* in the future.
|
||||
* This method must always be called on the controller thread.
|
||||
*/
|
||||
virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0;
|
||||
|
||||
|
@ -3138,6 +3138,7 @@ AsyncPanZoomController::GetZoomConstraints() const
|
||||
|
||||
|
||||
void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) {
|
||||
AssertOnControllerThread();
|
||||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
controller->PostDelayedTask(aTask, aDelayMs);
|
||||
|
@ -55,6 +55,7 @@ GestureEventListener::GestureEventListener(AsyncPanZoomController* aAsyncPanZoom
|
||||
mSpanChange(0.0f),
|
||||
mPreviousSpan(0.0f),
|
||||
mLastTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0),
|
||||
mLastTapInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0),
|
||||
mLongTapTimeoutTask(nullptr),
|
||||
mMaxTapTimeoutTask(nullptr)
|
||||
{
|
||||
@ -168,6 +169,7 @@ nsEventStatus GestureEventListener::HandleInputTouchMultiStart()
|
||||
// Cancel wait for double tap
|
||||
CancelMaxTapTimeoutTask();
|
||||
SetState(GESTURE_MULTI_TOUCH_DOWN);
|
||||
TriggerSingleTapConfirmedEvent();
|
||||
// Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event
|
||||
rv = nsEventStatus_eConsumeNoDefault;
|
||||
break;
|
||||
@ -175,6 +177,7 @@ nsEventStatus GestureEventListener::HandleInputTouchMultiStart()
|
||||
// Cancel wait for single tap
|
||||
CancelMaxTapTimeoutTask();
|
||||
SetState(GESTURE_MULTI_TOUCH_DOWN);
|
||||
TriggerSingleTapConfirmedEvent();
|
||||
// Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event
|
||||
rv = nsEventStatus_eConsumeNoDefault;
|
||||
break;
|
||||
@ -441,10 +444,10 @@ void GestureEventListener::HandleInputTimeoutMaxTap()
|
||||
void GestureEventListener::TriggerSingleTapConfirmedEvent()
|
||||
{
|
||||
TapGestureInput tapEvent(TapGestureInput::TAPGESTURE_CONFIRMED,
|
||||
mLastTouchInput.mTime,
|
||||
mLastTouchInput.mTimeStamp,
|
||||
mLastTouchInput.mTouches[0].mScreenPoint,
|
||||
mLastTouchInput.modifiers);
|
||||
mLastTapInput.mTime,
|
||||
mLastTapInput.mTimeStamp,
|
||||
mLastTapInput.mTouches[0].mScreenPoint,
|
||||
mLastTapInput.modifiers);
|
||||
mAsyncPanZoomController->HandleGestureEvent(tapEvent);
|
||||
}
|
||||
|
||||
@ -498,6 +501,8 @@ void GestureEventListener::CancelMaxTapTimeoutTask()
|
||||
|
||||
void GestureEventListener::CreateMaxTapTimeoutTask()
|
||||
{
|
||||
mLastTapInput = mLastTouchInput;
|
||||
|
||||
mMaxTapTimeoutTask =
|
||||
NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap);
|
||||
|
||||
|
@ -175,6 +175,15 @@ private:
|
||||
*/
|
||||
MultiTouchInput mLastTouchInput;
|
||||
|
||||
/**
|
||||
* Cached copy of the last tap gesture input.
|
||||
* In the situation when we have a tap followed by a pinch we lose info
|
||||
* about tap since we keep only last input and to dispatch it correctly
|
||||
* we save last tap copy into this variable.
|
||||
* For more info see bug 947892.
|
||||
*/
|
||||
MultiTouchInput mLastTapInput;
|
||||
|
||||
/**
|
||||
* Position of the last touch starting. This is only valid during an attempt
|
||||
* to determine if a touch is a tap. If a touch point moves away from
|
||||
|
@ -1478,6 +1478,62 @@ TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) {
|
||||
apzc->AssertStateIsReset();
|
||||
}
|
||||
|
||||
// Test for bug 947892
|
||||
// We test whether we dispatch tap event when the tap is followed by pinch.
|
||||
TEST_F(APZCGestureDetectorTester, TapFollowedByPinch) {
|
||||
MakeApzcZoomable();
|
||||
|
||||
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
|
||||
int time = 0;
|
||||
ApzcTap(apzc, 10, 10, time, 100);
|
||||
|
||||
int inputId = 0;
|
||||
MultiTouchInput mti;
|
||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
||||
apzc->ReceiveInputEvent(mti);
|
||||
|
||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, time, TimeStamp(), 0);
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
||||
apzc->ReceiveInputEvent(mti);
|
||||
|
||||
while (mcc->RunThroughDelayedTasks());
|
||||
|
||||
apzc->AssertStateIsReset();
|
||||
}
|
||||
|
||||
TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) {
|
||||
MakeApzcZoomable();
|
||||
|
||||
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
|
||||
int time = 0;
|
||||
ApzcTap(apzc, 10, 10, time, 100);
|
||||
|
||||
int inputId = 0;
|
||||
MultiTouchInput mti;
|
||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
||||
apzc->ReceiveInputEvent(mti);
|
||||
|
||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
||||
apzc->ReceiveInputEvent(mti);
|
||||
|
||||
mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, time, TimeStamp(), 0);
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
|
||||
mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
|
||||
apzc->ReceiveInputEvent(mti);
|
||||
|
||||
while (mcc->RunThroughDelayedTasks());
|
||||
|
||||
apzc->AssertStateIsReset();
|
||||
}
|
||||
|
||||
class APZCTreeManagerTester : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
|
@ -1051,16 +1051,19 @@ obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
|
||||
return JSObject::preventExtensions(cx, obj);
|
||||
}
|
||||
|
||||
// ES6 draft rev27 (2014/08/24) 19.1.2.5 Object.freeze(O)
|
||||
static bool
|
||||
obj_freeze(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject obj(cx);
|
||||
if (!GetFirstArgumentAsObject(cx, args, "Object.freeze", &obj))
|
||||
return false;
|
||||
args.rval().set(args.get(0));
|
||||
|
||||
args.rval().setObject(*obj);
|
||||
// Step 1.
|
||||
if (!args.get(0).isObject())
|
||||
return true;
|
||||
|
||||
// Steps 2-5.
|
||||
RootedObject obj(cx, &args.get(0).toObject());
|
||||
return JSObject::freeze(cx, obj);
|
||||
}
|
||||
|
||||
|
@ -1701,8 +1701,11 @@ ia64*-hpux*)
|
||||
# and requires workarounds for perfectly valid code. Also, GCC/clang
|
||||
# don't warn about it by default. So for consistency/sanity, we turn
|
||||
# it off on MSVC, too.
|
||||
CFLAGS="$CFLAGS -wd4244"
|
||||
CXXFLAGS="$CXXFLAGS -wd4244 -wd4251"
|
||||
# MSVC warning C4267 warns for narrowing type conversions from size_t
|
||||
# to 32-bit integer types on 64-bit platforms. Since this is virtually
|
||||
# the same thing as C4244, we disable C4267, too.
|
||||
CFLAGS="$CFLAGS -wd4244 -wd4267"
|
||||
CXXFLAGS="$CXXFLAGS -wd4244 -wd4267 -wd4251"
|
||||
# make 'foo == bar;' error out
|
||||
CFLAGS="$CFLAGS -we4553"
|
||||
CXXFLAGS="$CXXFLAGS -we4553"
|
||||
|
@ -1320,7 +1320,9 @@ NativeRegExpMacroAssembler::CheckSpecialCharacterClass(char16_t type, Label* on_
|
||||
bool
|
||||
NativeRegExpMacroAssembler::CanReadUnaligned()
|
||||
{
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
return !jit::HasAlignmentFault();
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
|
@ -515,9 +515,9 @@ assertAsmTypeFail('glob', USE_ASM + I32 + "var lt=i4.lessThanOrEqual; function f
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var ge=i4.greaterThanOrEqual; function f() {} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var ne=i4.notEqual; function f() {} return f");
|
||||
|
||||
const LTI32 = 'var lt = i4.lessThan';
|
||||
const GTI32 = 'var gt = i4.greaterThan';
|
||||
const EQI32 = 'var eq = i4.equal';
|
||||
const LTI32 = 'var lt = i4.lessThan;';
|
||||
const GTI32 = 'var gt = i4.greaterThan;';
|
||||
const EQI32 = 'var eq = i4.equal;';
|
||||
|
||||
CheckI4(LTI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=lt(x,y)', [F, F, F, F]);
|
||||
CheckI4(LTI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=lt(x,y)', [T, T, T, T]);
|
||||
@ -531,38 +531,44 @@ CheckI4(GTI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=gt(x,y)', [T, T, T, T])
|
||||
CheckI4(GTI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=gt(x,y)', [F, F, F, F]);
|
||||
CheckI4(GTI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=gt(x,y)', [F, F, F, T]);
|
||||
|
||||
const LTF32 = 'var lt=f4.lessThan';
|
||||
const LEF32 = 'var le=f4.lessThanOrEqual';
|
||||
const GTF32 = 'var gt=f4.greaterThan';
|
||||
const GEF32 = 'var ge=f4.greaterThanOrEqual';
|
||||
const EQF32 = 'var eq=f4.equal';
|
||||
const NEF32 = 'var ne=f4.notEqual';
|
||||
const LTF32 = 'var lt=f4.lessThan;';
|
||||
const LEF32 = 'var le=f4.lessThanOrEqual;';
|
||||
const GTF32 = 'var gt=f4.greaterThan;';
|
||||
const GEF32 = 'var ge=f4.greaterThanOrEqual;';
|
||||
const EQF32 = 'var eq=f4.equal;';
|
||||
const NEF32 = 'var ne=f4.notEqual;';
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "var lt=f4.lessThan; function f() {var x=f4(1,2,3,4); var y=f4(5,6,7,8); x=lt(x,y);} return f");
|
||||
|
||||
CheckF4Comp(LTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=lt(y,z)', [F, F, F, F]);
|
||||
CheckF4Comp(LTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=lt(y,z)', [T, T, T, T]);
|
||||
CheckF4Comp(LTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=lt(y,z)', [F, T, T, F]);
|
||||
CheckF4Comp(LTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=lt(y,z);', [F, F, F, F]);
|
||||
|
||||
CheckF4Comp(LEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=le(y,z)', [F, F, F, F]);
|
||||
CheckF4Comp(LEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=le(y,z)', [T, T, T, T]);
|
||||
CheckF4Comp(LEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=le(y,z)', [T, T, T, F]);
|
||||
CheckF4Comp(LEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=le(y,z);', [T, T, F, F]);
|
||||
|
||||
CheckF4Comp(EQF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=eq(y,z)', [F, F, F, F]);
|
||||
CheckF4Comp(EQF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=eq(y,z)', [F, F, F, F]);
|
||||
CheckF4Comp(EQF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=eq(y,z)', [T, F, F, F]);
|
||||
CheckF4Comp(EQF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=eq(y,z);', [T, T, F, F]);
|
||||
|
||||
CheckF4Comp(NEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=ne(y,z)', [T, T, T, T]);
|
||||
CheckF4Comp(NEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=ne(y,z)', [T, T, T, T]);
|
||||
CheckF4Comp(NEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=ne(y,z)', [F, T, T, T]);
|
||||
CheckF4Comp(NEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ne(y,z);', [F, F, T, T]);
|
||||
|
||||
CheckF4Comp(GTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=gt(y,z)', [T, T, T, T]);
|
||||
CheckF4Comp(GTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=gt(y,z)', [F, F, F, F]);
|
||||
CheckF4Comp(GTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=gt(y,z)', [F, F, F, T]);
|
||||
CheckF4Comp(GTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=gt(y,z);', [F, F, F, F]);
|
||||
|
||||
CheckF4Comp(GEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=ge(y,z)', [T, T, T, T]);
|
||||
CheckF4Comp(GEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=ge(y,z)', [F, F, F, F]);
|
||||
CheckF4Comp(GEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=ge(y,z)', [T, F, F, T]);
|
||||
CheckF4Comp(GEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ge(y,z);', [T, T, F, F]);
|
||||
|
||||
// Conversions operators
|
||||
const CVTIF = 'var cvt=f4.fromInt32x4;';
|
||||
|
24
js/src/jit-test/tests/ion/bug1072188.js
Normal file
24
js/src/jit-test/tests/ion/bug1072188.js
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
setJitCompilerOption("baseline.warmup.trigger", 10);
|
||||
setJitCompilerOption("ion.warmup.trigger", 30);
|
||||
var i;
|
||||
|
||||
var uceFault = function (i) {
|
||||
if (i > 98)
|
||||
uceFault = function (i) { return true; };
|
||||
return false;
|
||||
}
|
||||
|
||||
var sqrt5 = Math.sqrt(5);
|
||||
var phi = (1 + sqrt5) / 2;
|
||||
function range_analysis_truncate(i) {
|
||||
var fib = (Math.pow(phi, i) - Math.pow(1 - phi, i)) / sqrt5;
|
||||
var x = (fib >> 8) * (fib >> 6);
|
||||
if (uceFault(i) || uceFault(i))
|
||||
assertEq(x, (fib >> 8) * (fib >> 6));
|
||||
return x | 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
range_analysis_truncate(i);
|
||||
}
|
44
js/src/jit-test/tests/ion/bug1074833.js
Normal file
44
js/src/jit-test/tests/ion/bug1074833.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
var i = 0;
|
||||
function cond() {
|
||||
return i++ < 20;
|
||||
}
|
||||
|
||||
function inline() {
|
||||
({ b: 1 })
|
||||
}
|
||||
|
||||
function f() {
|
||||
do {
|
||||
({ b: 1 })
|
||||
} while (cond())
|
||||
}
|
||||
|
||||
i = 0;
|
||||
f();
|
||||
|
||||
function g() {
|
||||
do {
|
||||
if (cond()) { }
|
||||
({ b: 1 })
|
||||
} while (cond())
|
||||
}
|
||||
|
||||
i = 0;
|
||||
g();
|
||||
|
||||
|
||||
function h() {
|
||||
do {
|
||||
inline();
|
||||
} while (cond())
|
||||
}
|
||||
|
||||
i = 0;
|
||||
h();
|
||||
|
||||
|
||||
i = 0;
|
||||
for (i = 0; cond(); i++)
|
||||
({ set: Math.w });
|
||||
|
@ -389,7 +389,7 @@ class SnapshotIteratorForBailout : public SnapshotIterator
|
||||
|
||||
SnapshotIteratorForBailout(const IonBailoutIterator &iter)
|
||||
: SnapshotIterator(iter),
|
||||
results_()
|
||||
results_(iter.jsFrame())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1437,17 +1437,19 @@ OsiIndex::returnPointDisplacement() const
|
||||
return callPointDisplacement_ + Assembler::PatchWrite_NearCallSize();
|
||||
}
|
||||
|
||||
RInstructionResults::RInstructionResults()
|
||||
RInstructionResults::RInstructionResults(IonJSFrameLayout *fp)
|
||||
: results_(nullptr),
|
||||
fp_(nullptr)
|
||||
fp_(fp),
|
||||
initialized_(false)
|
||||
{
|
||||
}
|
||||
|
||||
RInstructionResults::RInstructionResults(RInstructionResults&& src)
|
||||
: results_(mozilla::Move(src.results_)),
|
||||
fp_(src.fp_)
|
||||
fp_(src.fp_),
|
||||
initialized_(src.initialized_)
|
||||
{
|
||||
src.fp_ = nullptr;
|
||||
src.initialized_ = false;
|
||||
}
|
||||
|
||||
RInstructionResults&
|
||||
@ -1465,7 +1467,7 @@ RInstructionResults::~RInstructionResults()
|
||||
}
|
||||
|
||||
bool
|
||||
RInstructionResults::init(JSContext *cx, uint32_t numResults, IonJSFrameLayout *fp)
|
||||
RInstructionResults::init(JSContext *cx, uint32_t numResults)
|
||||
{
|
||||
if (numResults) {
|
||||
results_ = cx->make_unique<Values>();
|
||||
@ -1477,21 +1479,20 @@ RInstructionResults::init(JSContext *cx, uint32_t numResults, IonJSFrameLayout *
|
||||
(*results_)[i].init(guard);
|
||||
}
|
||||
|
||||
fp_ = fp;
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RInstructionResults::isInitialized() const
|
||||
{
|
||||
MOZ_ASSERT_IF(results_, fp_);
|
||||
return fp_;
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
IonJSFrameLayout *
|
||||
RInstructionResults::frame() const
|
||||
{
|
||||
MOZ_ASSERT(isInitialized());
|
||||
MOZ_ASSERT(fp_);
|
||||
return fp_;
|
||||
}
|
||||
|
||||
@ -1798,9 +1799,8 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback &fallback)
|
||||
// before we initialize the list such as if any recover instruction
|
||||
// cause a GC, we can ensure that the results are properly traced by the
|
||||
// activation.
|
||||
RInstructionResults tmp;
|
||||
if (!fallback.activation->registerIonFrameRecovery(fallback.frame->jsFrame(),
|
||||
mozilla::Move(tmp)))
|
||||
RInstructionResults tmp(fallback.frame->jsFrame());
|
||||
if (!fallback.activation->registerIonFrameRecovery(mozilla::Move(tmp)))
|
||||
return false;
|
||||
|
||||
results = fallback.activation->maybeIonFrameRecovery(fp);
|
||||
@ -1832,7 +1832,7 @@ SnapshotIterator::computeInstructionResults(JSContext *cx, RInstructionResults *
|
||||
// The last instruction will always be a resume point.
|
||||
size_t numResults = recover_.numInstructions() - 1;
|
||||
if (!results->isInitialized()) {
|
||||
if (!results->init(cx, numResults, fp_))
|
||||
if (!results->init(cx, numResults))
|
||||
return false;
|
||||
|
||||
// No need to iterate over the only resume point.
|
||||
|
@ -276,15 +276,20 @@ class RInstructionResults
|
||||
// bailed out.
|
||||
IonJSFrameLayout *fp_;
|
||||
|
||||
// Record if we tried and succeed at allocating and filling the vector of
|
||||
// recover instruction results, if needed. This flag is needed in order to
|
||||
// avoid evaluating the recover instruction twice.
|
||||
bool initialized_;
|
||||
|
||||
public:
|
||||
RInstructionResults();
|
||||
RInstructionResults(IonJSFrameLayout *fp);
|
||||
RInstructionResults(RInstructionResults&& src);
|
||||
|
||||
RInstructionResults& operator=(RInstructionResults&& rhs);
|
||||
|
||||
~RInstructionResults();
|
||||
|
||||
bool init(JSContext *cx, uint32_t numResults, IonJSFrameLayout *fp);
|
||||
bool init(JSContext *cx, uint32_t numResults);
|
||||
bool isInitialized() const;
|
||||
|
||||
IonJSFrameLayout *frame() const;
|
||||
|
@ -3808,12 +3808,12 @@ LIRGenerator::visitSimdBinaryComp(MSimdBinaryComp *ins)
|
||||
|
||||
if (ins->compareType() == MSimdBinaryComp::CompareInt32x4) {
|
||||
LSimdBinaryCompIx4 *add = new(alloc()) LSimdBinaryCompIx4();
|
||||
return lowerForFPU(add, ins, ins->lhs(), ins->rhs());
|
||||
return lowerForCompIx4(add, ins, ins->lhs(), ins->rhs());
|
||||
}
|
||||
|
||||
if (ins->compareType() == MSimdBinaryComp::CompareFloat32x4) {
|
||||
LSimdBinaryCompFx4 *add = new(alloc()) LSimdBinaryCompFx4();
|
||||
return lowerForFPU(add, ins, ins->lhs(), ins->rhs());
|
||||
return lowerForCompFx4(add, ins, ins->lhs(), ins->rhs());
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unknown compare type when comparing values");
|
||||
|
@ -513,8 +513,14 @@ class MDefinition : public MNode
|
||||
Truncate = 3
|
||||
};
|
||||
|
||||
// Apply the given truncate to this node itself.
|
||||
virtual bool truncate(TruncateKind kind);
|
||||
// |needTruncation| records the truncation kind of the results, such that it
|
||||
// can be used to truncate the operands of this instruction. If
|
||||
// |needTruncation| function returns true, then the |truncate| function is
|
||||
// called on the same instruction to mutate the instruction, such as
|
||||
// updating the return type, the range and the specialization of the
|
||||
// instruction.
|
||||
virtual bool needTruncation(TruncateKind kind);
|
||||
virtual void truncate();
|
||||
|
||||
// Determine what kind of truncate this node prefers for the operand at the
|
||||
// given index.
|
||||
@ -1195,7 +1201,7 @@ class MLimitedTruncate
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
TruncateKind truncateKind() const {
|
||||
return truncate_;
|
||||
@ -1253,7 +1259,8 @@ class MConstant : public MNullaryInstruction
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
|
||||
bool canProduceFloat32() const;
|
||||
|
||||
@ -1604,6 +1611,21 @@ class MSimdBinaryComp : public MBinaryInstruction
|
||||
Operation operation() const { return operation_; }
|
||||
CompareType compareType() const { return compareType_; }
|
||||
|
||||
// Swap the operands and reverse the comparison predicate.
|
||||
void reverse() {
|
||||
switch (operation()) {
|
||||
case greaterThan: operation_ = lessThan; break;
|
||||
case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
|
||||
case lessThan: operation_ = greaterThan; break;
|
||||
case lessThanOrEqual: operation_ = greaterThanOrEqual; break;
|
||||
case equal:
|
||||
case notEqual:
|
||||
break;
|
||||
default: MOZ_CRASH("Unexpected compare operation");
|
||||
}
|
||||
swapOperands();
|
||||
}
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
if (!binaryCongruentTo(ins))
|
||||
return false;
|
||||
@ -3437,7 +3459,8 @@ class MCompare
|
||||
|
||||
void trySpecializeFloat32(TempAllocator &alloc);
|
||||
bool isFloat32Commutative() const { return true; }
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
# ifdef DEBUG
|
||||
@ -4026,7 +4049,8 @@ class MToDouble
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -5218,7 +5242,8 @@ class MAdd : public MBinaryArithInstruction
|
||||
|
||||
bool fallible() const;
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
@ -5261,7 +5286,8 @@ class MSub : public MBinaryArithInstruction
|
||||
|
||||
bool fallible() const;
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
@ -5362,7 +5388,8 @@ class MMul : public MBinaryArithInstruction
|
||||
bool isFloat32Commutative() const { return true; }
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
Mode mode() const { return mode_; }
|
||||
@ -5466,7 +5493,8 @@ class MDiv : public MBinaryArithInstruction
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool fallible() const;
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
void collectRangeInfoPreTrunc();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
@ -5547,7 +5575,8 @@ class MMod : public MBinaryArithInstruction
|
||||
bool fallible() const;
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
void collectRangeInfoPreTrunc();
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
@ -5959,7 +5988,8 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
|
||||
}
|
||||
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
void truncate();
|
||||
};
|
||||
|
||||
// The goal of a Beta node is to split a def at a conditionally taken
|
||||
@ -7908,7 +7938,7 @@ class MLoadTypedArrayElementStatic
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
bool needTruncation(TruncateKind kind);
|
||||
bool canProduceFloat32() const { return viewType() == Scalar::Float32; }
|
||||
};
|
||||
|
||||
|
@ -2149,17 +2149,28 @@ Range::wrapAroundToBoolean()
|
||||
}
|
||||
|
||||
bool
|
||||
MDefinition::truncate(TruncateKind kind)
|
||||
MDefinition::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// No procedure defined for truncating this instruction.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MConstant::truncate(TruncateKind kind)
|
||||
void
|
||||
MDefinition::truncate()
|
||||
{
|
||||
if (!value_.isDouble())
|
||||
return false;
|
||||
MOZ_CRASH("No procedure defined for truncating this instruction.");
|
||||
}
|
||||
|
||||
bool
|
||||
MConstant::needTruncation(TruncateKind kind)
|
||||
{
|
||||
return value_.isDouble();
|
||||
}
|
||||
|
||||
void
|
||||
MConstant::truncate()
|
||||
{
|
||||
MOZ_ASSERT(needTruncation(Truncate));
|
||||
|
||||
// Truncate the double to int, since all uses truncates it.
|
||||
int32_t res = ToInt32(value_.toDouble());
|
||||
@ -2167,147 +2178,164 @@ MConstant::truncate(TruncateKind kind)
|
||||
setResultType(MIRType_Int32);
|
||||
if (range())
|
||||
range()->setInt32(res, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MPhi::truncate(TruncateKind kind)
|
||||
MPhi::needTruncation(TruncateKind kind)
|
||||
{
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
truncateKind_ = kind;
|
||||
setResultType(MIRType_Int32);
|
||||
if (kind >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MPhi::truncate()
|
||||
{
|
||||
setResultType(MIRType_Int32);
|
||||
if (truncateKind_ >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
|
||||
bool
|
||||
MAdd::truncate(TruncateKind kind)
|
||||
MAdd::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (kind >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
return true;
|
||||
}
|
||||
return type() == MIRType_Double || type() == MIRType_Int32;
|
||||
}
|
||||
|
||||
return false;
|
||||
void
|
||||
MAdd::truncate()
|
||||
{
|
||||
MOZ_ASSERT(needTruncation(truncateKind()));
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (truncateKind() >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
|
||||
bool
|
||||
MSub::truncate(TruncateKind kind)
|
||||
MSub::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (kind >= IndirectTruncate && range())
|
||||
return type() == MIRType_Double || type() == MIRType_Int32;
|
||||
}
|
||||
|
||||
void
|
||||
MSub::truncate()
|
||||
{
|
||||
MOZ_ASSERT(needTruncation(truncateKind()));
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (truncateKind() >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
|
||||
bool
|
||||
MMul::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncateKind(kind);
|
||||
|
||||
return type() == MIRType_Double || type() == MIRType_Int32;
|
||||
}
|
||||
|
||||
void
|
||||
MMul::truncate()
|
||||
{
|
||||
MOZ_ASSERT(needTruncation(truncateKind()));
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (truncateKind() >= IndirectTruncate) {
|
||||
setCanBeNegativeZero(false);
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MMul::truncate(TruncateKind kind)
|
||||
MDiv::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (kind >= IndirectTruncate) {
|
||||
setCanBeNegativeZero(false);
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return type() == MIRType_Double || type() == MIRType_Int32;
|
||||
}
|
||||
|
||||
return false;
|
||||
void
|
||||
MDiv::truncate()
|
||||
{
|
||||
MOZ_ASSERT(needTruncation(truncateKind()));
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
|
||||
// Divisions where the lhs and rhs are unsigned and the result is
|
||||
// truncated can be lowered more efficiently.
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
}
|
||||
|
||||
bool
|
||||
MDiv::truncate(TruncateKind kind)
|
||||
MMod::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
|
||||
// Divisions where the lhs and rhs are unsigned and the result is
|
||||
// truncated can be lowered more efficiently.
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// No modifications.
|
||||
return false;
|
||||
return type() == MIRType_Double || type() == MIRType_Int32;
|
||||
}
|
||||
|
||||
bool
|
||||
MMod::truncate(TruncateKind kind)
|
||||
void
|
||||
MMod::truncate()
|
||||
{
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncateKind(kind);
|
||||
|
||||
// As for division, handle unsigned modulus with a truncated result.
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
MOZ_ASSERT(needTruncation(truncateKind()));
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// No modifications.
|
||||
return false;
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
}
|
||||
|
||||
bool
|
||||
MToDouble::truncate(TruncateKind kind)
|
||||
MToDouble::needTruncation(TruncateKind kind)
|
||||
{
|
||||
MOZ_ASSERT(type() == MIRType_Double);
|
||||
|
||||
setTruncateKind(kind);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MToDouble::truncate()
|
||||
{
|
||||
MOZ_ASSERT(needTruncation(truncateKind()));
|
||||
|
||||
// We use the return type to flag that this MToDouble should be replaced by
|
||||
// a MTruncateToInt32 when modifying the graph.
|
||||
setResultType(MIRType_Int32);
|
||||
if (kind >= IndirectTruncate) {
|
||||
if (truncateKind() >= IndirectTruncate) {
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MLoadTypedArrayElementStatic::truncate(TruncateKind kind)
|
||||
MLoadTypedArrayElementStatic::needTruncation(TruncateKind kind)
|
||||
{
|
||||
if (kind >= IndirectTruncate)
|
||||
setInfallible();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MLimitedTruncate::truncate(TruncateKind kind)
|
||||
MLimitedTruncate::needTruncation(TruncateKind kind)
|
||||
{
|
||||
setTruncateKind(kind);
|
||||
setResultType(MIRType_Int32);
|
||||
@ -2316,6 +2344,38 @@ MLimitedTruncate::truncate(TruncateKind kind)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MCompare::needTruncation(TruncateKind kind)
|
||||
{
|
||||
// If we're compiling AsmJS, don't try to optimize the comparison type, as
|
||||
// the code presumably is already using the type it wants. Also, AsmJS
|
||||
// doesn't support bailouts, so we woudn't be able to rely on
|
||||
// TruncateAfterBailouts to convert our inputs.
|
||||
if (block()->info().compilingAsmJS())
|
||||
return false;
|
||||
|
||||
if (!isDoubleComparison())
|
||||
return false;
|
||||
|
||||
// If both operands are naturally in the int32 range, we can convert from
|
||||
// a double comparison to being an int32 comparison.
|
||||
if (!Range(lhs()).isInt32() || !Range(rhs()).isInt32())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MCompare::truncate()
|
||||
{
|
||||
compareType_ = Compare_Int32;
|
||||
|
||||
// Truncating the operands won't change their value because we don't force a
|
||||
// truncation, but it will change their type, which we need because we
|
||||
// now expect integer inputs.
|
||||
truncateOperands_ = true;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MDefinition::operandTruncateKind(size_t index) const
|
||||
{
|
||||
@ -2413,34 +2473,6 @@ MMod::operandTruncateKind(size_t index) const
|
||||
return Min(truncateKind(), TruncateAfterBailouts);
|
||||
}
|
||||
|
||||
bool
|
||||
MCompare::truncate(TruncateKind kind)
|
||||
{
|
||||
// If we're compiling AsmJS, don't try to optimize the comparison type, as
|
||||
// the code presumably is already using the type it wants. Also, AsmJS
|
||||
// doesn't support bailouts, so we woudn't be able to rely on
|
||||
// TruncateAfterBailouts to convert our inputs.
|
||||
if (block()->info().compilingAsmJS())
|
||||
return false;
|
||||
|
||||
if (!isDoubleComparison())
|
||||
return false;
|
||||
|
||||
// If both operands are naturally in the int32 range, we can convert from
|
||||
// a double comparison to being an int32 comparison.
|
||||
if (!Range(lhs()).isInt32() || !Range(rhs()).isInt32())
|
||||
return false;
|
||||
|
||||
compareType_ = Compare_Int32;
|
||||
|
||||
// Truncating the operands won't change their value because we don't force a
|
||||
// truncation, but it will change their type, which we need because we
|
||||
// now expect integer inputs.
|
||||
truncateOperands_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MCompare::operandTruncateKind(size_t index) const
|
||||
{
|
||||
@ -2486,40 +2518,133 @@ TruncateTest(TempAllocator &alloc, MTest *test)
|
||||
phi->setResultType(MIRType_Int32);
|
||||
}
|
||||
|
||||
// Truncating instruction result is an optimization which implies
|
||||
// knowing all uses of an instruction. This implies that if one of
|
||||
// the uses got removed, then Range Analysis is not be allowed to do
|
||||
// any modification which can change the result, especially if the
|
||||
// result can be observed.
|
||||
//
|
||||
// This corner can easily be understood with UCE examples, but it
|
||||
// might also happen with type inference assumptions. Note: Type
|
||||
// inference is implicitly branches where other types might be
|
||||
// flowing into.
|
||||
static bool
|
||||
CloneForDeadBranches(TempAllocator &alloc, MInstruction *candidate)
|
||||
{
|
||||
// Compare returns a boolean so it doesn't have to be recovered on bailout
|
||||
// because the output would remain correct.
|
||||
if (candidate->isCompare())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(candidate->canClone());
|
||||
|
||||
MDefinitionVector operands(alloc);
|
||||
size_t end = candidate->numOperands();
|
||||
for (size_t i = 0; i < end; i++) {
|
||||
if (!operands.append(candidate->getOperand(i)))
|
||||
return false;
|
||||
}
|
||||
|
||||
MInstruction *clone = candidate->clone(alloc, operands);
|
||||
clone->setRange(nullptr);
|
||||
|
||||
// Set UseRemoved flag on the cloned instruction in order to chain recover
|
||||
// instruction for the bailout path.
|
||||
clone->setUseRemovedUnchecked();
|
||||
|
||||
candidate->block()->insertBefore(candidate, clone);
|
||||
|
||||
if (!candidate->isConstant()) {
|
||||
MOZ_ASSERT(clone->canRecoverOnBailout());
|
||||
clone->setRecoveredOnBailout();
|
||||
}
|
||||
|
||||
// Replace the candidate by its recovered on bailout clone within recovered
|
||||
// instructions and resume points operands.
|
||||
for (MUseIterator i(candidate->usesBegin()); i != candidate->usesEnd(); ) {
|
||||
MUse *use = *i++;
|
||||
MNode *ins = use->consumer();
|
||||
if (ins->isDefinition() && !ins->toDefinition()->isRecoveredOnBailout())
|
||||
continue;
|
||||
|
||||
use->replaceProducer(clone);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Examine all the users of |candidate| and determine the most aggressive
|
||||
// truncate kind that satisfies all of them.
|
||||
static MDefinition::TruncateKind
|
||||
ComputeRequestedTruncateKind(MDefinition *candidate)
|
||||
ComputeRequestedTruncateKind(MDefinition *candidate, bool *shouldClone)
|
||||
{
|
||||
// If the value naturally produces an int32 value (before bailout checks)
|
||||
// that needs no conversion, we don't have to worry about resume points
|
||||
// seeing truncated values.
|
||||
bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
|
||||
bool isCapturedResult = false;
|
||||
bool isObservableResult = false;
|
||||
bool hasUseRemoved = candidate->isUseRemoved();
|
||||
|
||||
MDefinition::TruncateKind kind = MDefinition::Truncate;
|
||||
for (MUseIterator use(candidate->usesBegin()); use != candidate->usesEnd(); use++) {
|
||||
if (!use->consumer()->isDefinition()) {
|
||||
if (use->consumer()->isResumePoint()) {
|
||||
// Truncation is a destructive optimization, as such, we need to pay
|
||||
// attention to removed branches and prevent optimization
|
||||
// destructive optimizations if we have no alternative. (see
|
||||
// UseRemoved flag)
|
||||
if (candidate->isUseRemoved() && needsConversion)
|
||||
kind = Min(kind, MDefinition::TruncateAfterBailouts);
|
||||
isCapturedResult = true;
|
||||
isObservableResult = isObservableResult ||
|
||||
use->consumer()->toResumePoint()->isObservableOperand(*use);
|
||||
continue;
|
||||
}
|
||||
|
||||
MDefinition *consumer = use->consumer()->toDefinition();
|
||||
if (consumer->isRecoveredOnBailout()) {
|
||||
isCapturedResult = true;
|
||||
hasUseRemoved = hasUseRemoved || consumer->isUseRemoved();
|
||||
continue;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind consumerKind = consumer->operandTruncateKind(consumer->indexOf(*use));
|
||||
kind = Min(kind, consumerKind);
|
||||
if (kind == MDefinition::NoTruncate)
|
||||
break;
|
||||
}
|
||||
|
||||
// If the value naturally produces an int32 value (before bailout checks)
|
||||
// that needs no conversion, we don't have to worry about resume points
|
||||
// seeing truncated values.
|
||||
bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
|
||||
|
||||
// If the candidate instruction appears as operand of a resume point or a
|
||||
// recover instruction, and we have to truncate its result, then we might
|
||||
// have to either recover the result during the bailout, or avoid the
|
||||
// truncation.
|
||||
if (isCapturedResult && needsConversion) {
|
||||
|
||||
// 1. Recover instructions are useless if there is no removed uses. Not
|
||||
// having removed uses means that we know everything about where this
|
||||
// results flows into.
|
||||
//
|
||||
// 2. If the result is observable, then we cannot recover it.
|
||||
//
|
||||
// 3. The cloned instruction is expected to be used as a recover
|
||||
// instruction.
|
||||
if (hasUseRemoved && !isObservableResult && candidate->canRecoverOnBailout())
|
||||
*shouldClone = true;
|
||||
|
||||
// 1. If uses are removed, then we need to keep the expected result for
|
||||
// dead branches.
|
||||
//
|
||||
// 2. If the result is observable, then the result might be read while
|
||||
// the frame is on the stack.
|
||||
else if (hasUseRemoved || isObservableResult)
|
||||
kind = Min(kind, MDefinition::TruncateAfterBailouts);
|
||||
|
||||
}
|
||||
|
||||
return kind;
|
||||
}
|
||||
|
||||
static MDefinition::TruncateKind
|
||||
ComputeTruncateKind(MDefinition *candidate)
|
||||
ComputeTruncateKind(MDefinition *candidate, bool *shouldClone)
|
||||
{
|
||||
// Compare operations might coerce its inputs to int32 if the ranges are
|
||||
// correct. So we do not need to check if all uses are coerced.
|
||||
@ -2542,7 +2667,7 @@ ComputeTruncateKind(MDefinition *candidate)
|
||||
return MDefinition::NoTruncate;
|
||||
|
||||
// Ensure all observable uses are truncated.
|
||||
return ComputeRequestedTruncateKind(candidate);
|
||||
return ComputeRequestedTruncateKind(candidate, shouldClone);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2630,6 +2755,9 @@ RangeAnalysis::truncate()
|
||||
|
||||
for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd(); block++) {
|
||||
for (MInstructionReverseIterator iter(block->rbegin()); iter != block->rend(); iter++) {
|
||||
if (iter->isRecoveredOnBailout())
|
||||
continue;
|
||||
|
||||
if (iter->type() == MIRType_None) {
|
||||
if (iter->isTest())
|
||||
TruncateTest(alloc(), iter->toTest());
|
||||
@ -2649,14 +2777,23 @@ RangeAnalysis::truncate()
|
||||
default:;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind kind = ComputeTruncateKind(*iter);
|
||||
bool shouldClone = false;
|
||||
MDefinition::TruncateKind kind = ComputeTruncateKind(*iter, &shouldClone);
|
||||
if (kind == MDefinition::NoTruncate)
|
||||
continue;
|
||||
|
||||
// Truncate this instruction if possible.
|
||||
if (!iter->truncate(kind))
|
||||
if (!iter->needTruncation(kind))
|
||||
continue;
|
||||
|
||||
// If needed, clone the current instruction for keeping it for the
|
||||
// bailout path. This give us the ability to truncate instructions
|
||||
// even after the removal of branches.
|
||||
if (shouldClone && !CloneForDeadBranches(alloc(), *iter))
|
||||
return false;
|
||||
|
||||
iter->truncate();
|
||||
|
||||
// Delay updates of inputs/outputs to avoid creating node which
|
||||
// would be removed by the truncation of the next operations.
|
||||
iter->setInWorklist();
|
||||
@ -2664,13 +2801,15 @@ RangeAnalysis::truncate()
|
||||
return false;
|
||||
}
|
||||
for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ++iter) {
|
||||
MDefinition::TruncateKind kind = ComputeTruncateKind(*iter);
|
||||
bool shouldClone = false;
|
||||
MDefinition::TruncateKind kind = ComputeTruncateKind(*iter, &shouldClone);
|
||||
if (kind == MDefinition::NoTruncate)
|
||||
continue;
|
||||
|
||||
// Truncate this phi if possible.
|
||||
if (!iter->truncate(kind))
|
||||
if (shouldClone || !iter->needTruncation(kind))
|
||||
continue;
|
||||
iter->truncate();
|
||||
|
||||
// Delay updates of inputs/outputs to avoid creating node which
|
||||
// would be removed by the truncation of the next operations.
|
||||
|
@ -139,6 +139,12 @@ IsObjectEscaped(MInstruction *ins)
|
||||
MOZ_ASSERT(ins->type() == MIRType_Object);
|
||||
MOZ_ASSERT(ins->isNewObject() || ins->isGuardShape() || ins->isCreateThisWithTemplate());
|
||||
|
||||
JSObject *obj = nullptr;
|
||||
if (ins->isNewObject())
|
||||
obj = ins->toNewObject()->templateObject();
|
||||
else if (ins->isCreateThisWithTemplate())
|
||||
obj = ins->toCreateThisWithTemplate()->templateObject();
|
||||
|
||||
// Check if the object is escaped. If the object is not the first argument
|
||||
// of either a known Store / Load, then we consider it as escaped. This is a
|
||||
// cheap and conservative escape analysis.
|
||||
@ -184,7 +190,7 @@ IsObjectEscaped(MInstruction *ins)
|
||||
case MDefinition::Op_GuardShape: {
|
||||
MGuardShape *guard = def->toGuardShape();
|
||||
MOZ_ASSERT(!ins->isGuardShape());
|
||||
if (ins->toNewObject()->templateObject()->lastProperty() != guard->shape()) {
|
||||
if (obj->lastProperty() != guard->shape()) {
|
||||
JitSpewDef(JitSpew_Escape, "Object ", ins);
|
||||
JitSpewDef(JitSpew_Escape, " has a non-matching guard shape\n", guard);
|
||||
return true;
|
||||
@ -333,7 +339,8 @@ ObjectMemoryView::mergeIntoSuccessorState(MBasicBlock *curr, MBasicBlock *succ,
|
||||
*pSuccState = succState;
|
||||
}
|
||||
|
||||
if (succ->numPredecessors() > 1 && succState->numSlots()) {
|
||||
MOZ_ASSERT_IF(succ == startBlock_, startBlock_->isLoopHeader());
|
||||
if (succ->numPredecessors() > 1 && succState->numSlots() && succ != startBlock_) {
|
||||
// We need to re-compute successorWithPhis as the previous EliminatePhis
|
||||
// phase might have removed all the Phis from the successor block.
|
||||
size_t currIndex;
|
||||
@ -787,7 +794,8 @@ ArrayMemoryView::mergeIntoSuccessorState(MBasicBlock *curr, MBasicBlock *succ,
|
||||
*pSuccState = succState;
|
||||
}
|
||||
|
||||
if (succ->numPredecessors() > 1 && succState->numElements()) {
|
||||
MOZ_ASSERT_IF(succ == startBlock_, startBlock_->isLoopHeader());
|
||||
if (succ->numPredecessors() > 1 && succState->numElements() && succ != startBlock_) {
|
||||
// We need to re-compute successorWithPhis as the previous EliminatePhis
|
||||
// phase might have removed all the Phis from the successor block.
|
||||
size_t currIndex;
|
||||
|
@ -153,6 +153,7 @@ ReplaceAllUsesWith(MDefinition *from, MDefinition *to)
|
||||
{
|
||||
MOZ_ASSERT(from != to, "GVN shouldn't try to replace a value with itself");
|
||||
MOZ_ASSERT(from->type() == to->type(), "Def replacement has different type");
|
||||
MOZ_ASSERT(!to->isDiscarded(), "GVN replaces an instruction by a removed instruction");
|
||||
|
||||
// We don't need the extra setting of UseRemoved flags that the regular
|
||||
// replaceAllUsesWith does because we do it ourselves.
|
||||
@ -639,7 +640,7 @@ ValueNumberer::leader(MDefinition *def)
|
||||
VisibleValues::AddPtr p = values_.findLeaderForAdd(def);
|
||||
if (p) {
|
||||
MDefinition *rep = *p;
|
||||
if (rep->block()->dominates(def->block())) {
|
||||
if (!rep->isDiscarded() && rep->block()->dominates(def->block())) {
|
||||
// We found a dominating congruent value.
|
||||
return rep;
|
||||
}
|
||||
@ -829,6 +830,8 @@ ValueNumberer::visitControlInstruction(MBasicBlock *block, const MBasicBlock *do
|
||||
return false;
|
||||
block->discardIgnoreOperands(control);
|
||||
block->end(newControl);
|
||||
if (block->entryResumePoint() && newNumSuccs != oldNumSuccs)
|
||||
block->flagOperandsOfPrunedBranches(newControl);
|
||||
return processDeadDefs();
|
||||
}
|
||||
|
||||
|
@ -38,20 +38,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Not part of the HWCAP flag, but we need to know these and these bits are not used.
|
||||
|
||||
// A bit to flag the use of the ARMv7 arch, otherwise ARMv6.
|
||||
#define HWCAP_ARMv7 (1 << 28)
|
||||
|
||||
// A bit to flag the use of the hardfp ABI.
|
||||
#define HWCAP_USE_HARDFP_ABI (1 << 27)
|
||||
|
||||
// A bit to flag when alignment faults are enabled and signal.
|
||||
#define HWCAP_ALIGNMENT_FAULT (1 << 26)
|
||||
|
||||
// A bit to flag when the flags are uninitialized, so they can be atomically set.
|
||||
#define HWCAP_UNINITIALIZED (1 << 25)
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
@ -142,7 +128,7 @@ CanonicalizeARMHwCapFlags(uint32_t flags)
|
||||
|
||||
// The override flags parsed from the ARMHWCAP environment variable or from the
|
||||
// --arm-hwcap js shell argument.
|
||||
volatile static uint32_t armHwCapFlags = HWCAP_UNINITIALIZED;
|
||||
volatile uint32_t armHwCapFlags = HWCAP_UNINITIALIZED;
|
||||
|
||||
bool
|
||||
ParseARMHwCapFlags(const char *armHwCap)
|
||||
@ -317,14 +303,6 @@ bool HasIDIV()
|
||||
return armHwCapFlags & HWCAP_IDIVA;
|
||||
}
|
||||
|
||||
// Returns true when cpu alignment faults are enabled and signaled, and thus we
|
||||
// should ensure loads and stores are aligned.
|
||||
bool HasAlignmentFault()
|
||||
{
|
||||
MOZ_ASSERT(armHwCapFlags != HWCAP_UNINITIALIZED);
|
||||
return armHwCapFlags & HWCAP_ALIGNMENT_FAULT;
|
||||
}
|
||||
|
||||
// This is defined in the header and inlined when not using the simulator.
|
||||
#if defined(JS_ARM_SIMULATOR)
|
||||
bool UseHardFpABI()
|
||||
|
@ -521,7 +521,31 @@ bool HasVFPv3();
|
||||
bool HasVFP();
|
||||
bool Has32DP();
|
||||
bool HasIDIV();
|
||||
bool HasAlignmentFault();
|
||||
|
||||
extern volatile uint32_t armHwCapFlags;
|
||||
|
||||
// Not part of the HWCAP flag, but we need to know these and these bits are not
|
||||
// used. Define these here so that their use can be inlined by the simulator.
|
||||
|
||||
// A bit to flag when the flags are uninitialized, so they can be atomically set.
|
||||
#define HWCAP_UNINITIALIZED (1 << 25)
|
||||
|
||||
// A bit to flag when alignment faults are enabled and signal.
|
||||
#define HWCAP_ALIGNMENT_FAULT (1 << 26)
|
||||
|
||||
// A bit to flag the use of the hardfp ABI.
|
||||
#define HWCAP_USE_HARDFP_ABI (1 << 27)
|
||||
|
||||
// A bit to flag the use of the ARMv7 arch, otherwise ARMv6.
|
||||
#define HWCAP_ARMv7 (1 << 28)
|
||||
|
||||
// Returns true when cpu alignment faults are enabled and signaled, and thus we
|
||||
// should ensure loads and stores are aligned.
|
||||
inline bool HasAlignmentFault()
|
||||
{
|
||||
MOZ_ASSERT(armHwCapFlags != HWCAP_UNINITIALIZED);
|
||||
return armHwCapFlags & HWCAP_ALIGNMENT_FAULT;
|
||||
}
|
||||
|
||||
// Arm/D32 has double registers that can NOT be treated as float32 and this
|
||||
// requires some dances in lowering.
|
||||
|
@ -172,7 +172,7 @@ LIRGeneratorARM::visitReturn(MReturn *ret)
|
||||
bool
|
||||
LIRGeneratorARM::lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir, MDefinition *input)
|
||||
{
|
||||
ins->setOperand(0, useRegister(input));
|
||||
ins->setOperand(0, ins->snapshot() ? useRegister(input) : useRegisterAtStart(input));
|
||||
return define(ins, mir,
|
||||
LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
|
||||
}
|
||||
@ -181,8 +181,11 @@ LIRGeneratorARM::lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
|
||||
bool
|
||||
LIRGeneratorARM::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
ins->setOperand(0, useRegister(lhs));
|
||||
ins->setOperand(1, useRegisterOrConstant(rhs));
|
||||
// Some operations depend on checking inputs after writing the result, e.g.
|
||||
// MulI, but only for bail out paths so useAtStart when no bailouts.
|
||||
ins->setOperand(0, ins->snapshot() ? useRegister(lhs) : useRegisterAtStart(lhs));
|
||||
ins->setOperand(1, ins->snapshot() ? useRegisterOrConstant(rhs) :
|
||||
useRegisterOrConstantAtStart(rhs));
|
||||
return define(ins, mir,
|
||||
LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
|
||||
}
|
||||
@ -190,7 +193,7 @@ LIRGeneratorARM::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
|
||||
bool
|
||||
LIRGeneratorARM::lowerForFPU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir, MDefinition *input)
|
||||
{
|
||||
ins->setOperand(0, useRegister(input));
|
||||
ins->setOperand(0, useRegisterAtStart(input));
|
||||
return define(ins, mir,
|
||||
LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
|
||||
|
||||
@ -199,8 +202,8 @@ LIRGeneratorARM::lowerForFPU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
|
||||
bool
|
||||
LIRGeneratorARM::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
ins->setOperand(0, useRegister(lhs));
|
||||
ins->setOperand(1, useRegister(rhs));
|
||||
ins->setOperand(0, useRegisterAtStart(lhs));
|
||||
ins->setOperand(1, useRegisterAtStart(rhs));
|
||||
return define(ins, mir,
|
||||
LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::REGISTER));
|
||||
}
|
||||
|
@ -58,6 +58,18 @@ class LIRGeneratorARM : public LIRGeneratorShared
|
||||
MDefinition *src);
|
||||
bool lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
|
||||
MDefinition *lhs, MDefinition *rhs);
|
||||
|
||||
bool lowerForCompIx4(LSimdBinaryCompIx4 *ins, MSimdBinaryComp *mir,
|
||||
MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
return lowerForFPU(ins, mir, lhs, rhs);
|
||||
}
|
||||
bool lowerForCompFx4(LSimdBinaryCompFx4 *ins, MSimdBinaryComp *mir,
|
||||
MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
return lowerForFPU(ins, mir, lhs, rhs);
|
||||
}
|
||||
|
||||
bool lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
|
||||
MDefinition *lhs, MDefinition *rhs);
|
||||
bool lowerConstantDouble(double d, MInstruction *ins);
|
||||
|
@ -1493,8 +1493,13 @@ Simulator::readW(int32_t addr, SimInstruction *instr)
|
||||
{
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
return *ptr;
|
||||
if ((addr & 3) == 0 || !HasAlignmentFault()) {
|
||||
intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
return *ptr;
|
||||
} else {
|
||||
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1514,8 +1519,13 @@ Simulator::readHU(int32_t addr, SimInstruction *instr)
|
||||
{
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
if ((addr & 1) == 0 || !HasAlignmentFault()) {
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t
|
||||
|
@ -58,6 +58,18 @@ class LIRGeneratorMIPS : public LIRGeneratorShared
|
||||
MDefinition *src);
|
||||
bool lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
|
||||
MDefinition *lhs, MDefinition *rhs);
|
||||
|
||||
bool lowerForCompIx4(LSimdBinaryCompIx4 *ins, MSimdBinaryComp *mir,
|
||||
MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
return lowerForFPU(ins, mir, lhs, rhs);
|
||||
}
|
||||
bool lowerForCompFx4(LSimdBinaryCompFx4 *ins, MSimdBinaryComp *mir,
|
||||
MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
return lowerForFPU(ins, mir, lhs, rhs);
|
||||
}
|
||||
|
||||
bool lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
|
||||
MDefinition *lhs, MDefinition *rhs);
|
||||
bool lowerConstantDouble(double d, MInstruction *ins);
|
||||
|
@ -42,6 +42,14 @@ class LIRGeneratorNone : public LIRGeneratorShared
|
||||
bool lowerForALU(T, MDefinition *, MDefinition *, MDefinition *v = nullptr) { MOZ_CRASH(); }
|
||||
template <typename T>
|
||||
bool lowerForFPU(T, MDefinition *, MDefinition *, MDefinition *v = nullptr) { MOZ_CRASH(); }
|
||||
bool lowerForCompIx4(LSimdBinaryCompIx4 *ins, MSimdBinaryComp *mir,
|
||||
MDefinition *lhs, MDefinition *rhs) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
bool lowerForCompFx4(LSimdBinaryCompFx4 *ins, MSimdBinaryComp *mir,
|
||||
MDefinition *lhs, MDefinition *rhs) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
bool lowerForBitAndAndBranch(LBitAndAndBranch *, MInstruction *,
|
||||
MDefinition *, MDefinition *) {
|
||||
MOZ_CRASH();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user