Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-10-03 16:31:55 -04:00
commit a64a253ff7
206 changed files with 56885 additions and 90445 deletions

View File

@ -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;
}

View File

@ -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 {

View File

@ -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>

View File

@ -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.

View File

@ -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);

View File

@ -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>

View File

@ -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");

View File

@ -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]

View 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");
}

View File

@ -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();

View File

@ -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 });

View File

@ -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>

View File

@ -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]

View 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);
}

View File

@ -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"

View File

@ -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();

View File

@ -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.");

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

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

View File

@ -1,2 +1,2 @@
0.9.2697
25bfcc9
0.9.2970
22f884f

View File

@ -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>

View File

@ -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);
}

View File

@ -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);

View File

@ -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).

View File

@ -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 -->

View File

@ -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. -->

View File

@ -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);

View File

@ -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);
}

View File

@ -8,6 +8,10 @@
padding: 4px;
}
#toggle-raw-headers {
padding: 4px;
}
.requests-menu-status-and-method {
width: 9em;
}

View File

@ -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);
}

View File

@ -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 {

View File

@ -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"],

View File

@ -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);
}

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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();
};

View File

@ -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() {

View File

@ -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^

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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)
{

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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',

View File

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = contentSandbox != 'off' # contentSandbox(Bug 1042735)
support-files =
head.js
constraints.js

View File

@ -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!

View File

@ -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

View File

@ -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

View File

@ -11,11 +11,12 @@
class mozSpellChecker;
namespace mozilla {
class RemoteSpellcheckEngineChild : public mozilla::PRemoteSpellcheckEngineChild
{
public:
explicit RemoteSpellcheckEngineChild(mozSpellChecker *aOwner);
~RemoteSpellcheckEngineChild();
virtual ~RemoteSpellcheckEngineChild();
private:
mozSpellChecker *mOwner;

View File

@ -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

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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() {

View File

@ -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);
}

View File

@ -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"

View File

@ -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;

View File

@ -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;';

View 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);
}

View 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 });

View File

@ -389,7 +389,7 @@ class SnapshotIteratorForBailout : public SnapshotIterator
SnapshotIteratorForBailout(const IonBailoutIterator &iter)
: SnapshotIterator(iter),
results_()
results_(iter.jsFrame())
{
}

View File

@ -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.

View File

@ -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;

View File

@ -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");

View File

@ -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; }
};

View File

@ -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.

View File

@ -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;

View File

@ -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();
}

View File

@ -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()

View File

@ -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.

View File

@ -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));
}

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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