mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1161802 part 1 - Add FullscreenChanged callback in WidgetListener. r=roc (caee485f4) - Bug 1058712, e10s, support for copy image command, r=ehsan,mconley (42d1bcc2c) - Bug 1122090 - Make ContentHelper take a LayoutDeviceIntPoint instead of an nsIntPoint. r=botond (21588cadb) - Bug 1122090 - Send the allowed behaviour notification to APZ for touch blocks when touch-action is enabled. r=botond (5bb0aad4a) - remove unneeded include (b77797920) - Add wheel transaction support to APZ. (bug 1142866 part 1, r=kats) (a4ed2150a) - End APZ wheel transactions when the mouse moves out of frame. (bug 1142866 part 2, r=kats,botond) (b26b0eb89) - Add APZ support for test.mousescroll callbacks. (bug 1142866 part 3, r=kats) (424ef3ad7) - Add helper for applying async transforms to widget input events. (bug 1143567 part 1, r=kats) (221cf7b02) - Ensure input events account for APZ transforms on Gtk. (bug 1143567 part 2, r=kats) (a62991076) - Allow synthetic input events to be dispatched asynchronously. (bug 1146243, r=kats) (0878aac4e) - Bug 1120300 - Export WritingModes.h as mozilla/WritingModes.h. r=jfkthame (67838dec2) - Bug 1075670 - Make event.screen[XY] work in content processes (r=smaug,kats,tn,joshmoz) (7c800e2a1) - Bug 1150563 - Intermittent test_compartments.js | test_measure - [test_measure : 125] At least 10ms counted for built-in statistics (0) - false == true;r=yoric (72ce9c7fc) - Bug 1143847 - Fix bogus asserts in x64 Assembler::finish(). r=sunfish (36aecaf48) - pointer style (a1a5a7b0f) - Bug 1148232 - OdinMonkey: Mark x86 disassembler code as MOZ_COLD and use MOZ_RELEASE_ASSERT r=luke (346cf1fdd) - Bug 1148232 - OdinMonkey: Update an asm.js error message r=luke (98c72b0b1) - Bug 1148232 - OdinMonkey: Update tests to avoid using legacy syntax. r=luke (d212510f3) - Bug 1148232 - OdinMonkey: Misc CheckArrayAccess cleanups r=luke (e5cda1cf0) - pointer style (23135ba24) - Bug 1148232 - OdinMonkey: Always put asm.js heap alignment masks just before their accesses r=luke (d604adf5d) - pointer style (9a5d58741) - Bug 1148232 - IonMonkey: Delete unused code r=luke (ea5bc5edc) - pointer style (73be379e1) - Bug 1143704 part 1 - Make Emit1/Emit2 return bool instead of ptrdiff_t. r=luke (2ca42caa9) - pointer style (eb30078f0) - Bug 1143704 part 2 - Make Emit3/EmitCall/EmitBackPatchOp return bool instead of ptrdiff_t. r=jorendorff (7275c56af) - Bug 1143704 part 3 - Make EmitLoopHead return bool instead of ptrdiff_t. r=shu (aff098096) - Bug 1143704 part 4 - Turn Emit1 into a BytecodeEmitter method. r=bhackett (5ca0356ba) - Bug 1143704 part 5 - Add a cx member to BytecodeEmitter. r=Waldo (8ce42c388) - Bug 1143704 part 6 - Move more functions into BytecodeEmitter. r=efaust (b26f60b2f) - pointer style (39e0e76ab) - Bug 1143704 part 7 - Move more functions into BytecodeEmitter. r=bhackett (7397bc2e5) - pointer style (f08664ab1) - Bug 1143704 part 8 - Move more functions into BytecodeEmitter. r=luke (2b0411545) - pointer style (5042217ea) - Bug 1143704 part 9 - Move more functions into BytecodeEmitter. r=shu (97501236a) - pointer style (4248e54fa) - Bug 1143704 part 10 - Move more functions into BytecodeEmitter. r=efaust (cd1fcb6a4) - pointer style (06026238e) - Bug 1143704 part 11 - Move more functions into BytecodeEmitter. r=jorendorff (300cdd416) - Bug 1145491 part 1. Only do the fast path for JSOP_BINDGNAME when the script doesn't have a polluted global. r=luke,jandem (75d663d20) - Bug 1145491 part 2. Only do the fast path for JSOP_GETGNAME when the script doesn't have a polluted global. r=luke,jandem (776bb0b37) - Bug 1145491 part 3. Only do the fast path for JSOP_SETGNAME and JSOP_STRICTSETGNAME when the script doesn't have a polluted global. r=luke,jandem (dfc5781e2) - Bug 537013 - Make the find bar exist on a per-tab basis. r=dao (cf361fd57) - Bug 1145491 part 4. Emit JSOP_IMPLICITTHIS for JSOP_GETGNAME as well, because otherwise bareword calls in polluted-global scripts won't work right. r=luk (2a4c829e2) - Bug 1145491 part 5. Fix up various other places that check for JSOP_GET/SETNAME without checking for the GNAME versions too. r=luke (08ebda6b5) - pointer style (dbdd1393a) - Bug 1145491 part 6. Fix script cloning to propagate the polluted-global-scope state to the lambda templates in the script. r=luke (a0c85b629) - pointer style (906b885ff) - Bug 1145491 part 7. Stop checking compileAndGo before emitting GNAME ops. r=luke (33e64a432)
This commit is contained in:
@@ -49,20 +49,13 @@ var gEditUIVisible = true;
|
||||
|
||||
// Smart getter for the findbar. If you don't wish to force the creation of
|
||||
// the findbar, check gFindBarInitialized first.
|
||||
var gFindBarInitialized = false;
|
||||
XPCOMUtils.defineLazyGetter(window, "gFindBar", function() {
|
||||
let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
let findbar = document.createElementNS(XULNS, "findbar");
|
||||
findbar.id = "FindToolbar";
|
||||
|
||||
let browserBottomBox = document.getElementById("browser-bottombox");
|
||||
browserBottomBox.insertBefore(findbar, browserBottomBox.firstChild);
|
||||
this.__defineGetter__("gFindBar", function() {
|
||||
return window.gBrowser.getFindBar();
|
||||
});
|
||||
|
||||
// Force a style flush to ensure that our binding is attached.
|
||||
findbar.clientTop;
|
||||
findbar.browser = gBrowser;
|
||||
window.gFindBarInitialized = true;
|
||||
return findbar;
|
||||
this.__defineGetter__("gFindBarInitialized", function() {
|
||||
return window.gBrowser.isFindBarInitialized();
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gPrefService", function() {
|
||||
@@ -3831,16 +3824,7 @@ var XULBrowserWindow = {
|
||||
else
|
||||
elt.removeAttribute("disabled");
|
||||
}
|
||||
if (gFindBarInitialized) {
|
||||
if (!gFindBar.hidden && aDisable) {
|
||||
gFindBar.hidden = true;
|
||||
this._findbarTemporarilyHidden = true;
|
||||
} else if (this._findbarTemporarilyHidden && !aDisable) {
|
||||
gFindBar.hidden = false;
|
||||
this._findbarTemporarilyHidden = false;
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
var onContentRSChange = function onContentRSChange(e) {
|
||||
if (e.target.readyState != "interactive" && e.target.readyState != "complete")
|
||||
|
||||
@@ -250,13 +250,18 @@ Sanitizer.prototype = {
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var windows = windowManager.getEnumerator("navigator:browser");
|
||||
while (windows.hasMoreElements()) {
|
||||
let currentDocument = windows.getNext().document;
|
||||
let currentWindow = windows.getNext();
|
||||
let currentDocument = currentWindow.document;
|
||||
let searchBar = currentDocument.getElementById("searchbar");
|
||||
if (searchBar)
|
||||
searchBar.textbox.reset();
|
||||
let findBar = currentDocument.getElementById("FindToolbar");
|
||||
if (findBar)
|
||||
findBar.clear();
|
||||
let tabBrowser = currentWindow.gBrowser;
|
||||
for (let tab of tabBrowser.tabs) {
|
||||
if (tabBrowser.isFindBarInitialized(tab))
|
||||
tabBrowser.getFindBar(tab).clear();
|
||||
}
|
||||
// Clear any saved find value
|
||||
tabBrowser._lastFindValue = "";
|
||||
}
|
||||
|
||||
let change = { op: "remove" };
|
||||
@@ -272,7 +277,8 @@ Sanitizer.prototype = {
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var windows = windowManager.getEnumerator("navigator:browser");
|
||||
while (windows.hasMoreElements()) {
|
||||
let currentDocument = windows.getNext().document;
|
||||
let currentWindow = windows.getNext();
|
||||
let currentDocument = currentWindow.document;
|
||||
let searchBar = currentDocument.getElementById("searchbar");
|
||||
if (searchBar) {
|
||||
let transactionMgr = searchBar.textbox.editor.transactionManager;
|
||||
@@ -283,8 +289,12 @@ Sanitizer.prototype = {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let findBar = currentDocument.getElementById("FindToolbar");
|
||||
if (findBar && findBar.canClear) {
|
||||
let tabBrowser = currentWindow.gBrowser;
|
||||
let findBarCanClear = Array.some(tabBrowser.tabs, function (aTab) {
|
||||
return tabBrowser.isFindBarInitialized(aTab) &&
|
||||
tabBrowser.getFindBar(aTab).canClear;
|
||||
});
|
||||
if (findBarCanClear) {
|
||||
aCallback("formdata", true, aArg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,10 @@
|
||||
false
|
||||
</field>
|
||||
|
||||
<field name="_lastFindValue">
|
||||
""
|
||||
</field>
|
||||
|
||||
<property name="_numPinnedTabs" readonly="true">
|
||||
<getter><![CDATA[
|
||||
for (var i = 0; i < this.tabs.length; i++) {
|
||||
@@ -159,6 +163,39 @@
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="isFindBarInitialized">
|
||||
<parameter name="aTab"/>
|
||||
<body><![CDATA[
|
||||
return (aTab || this.selectedTab)._findBar != undefined;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="getFindBar">
|
||||
<parameter name="aTab"/>
|
||||
<body><![CDATA[
|
||||
if (!aTab)
|
||||
aTab = this.selectedTab;
|
||||
|
||||
if (aTab._findBar)
|
||||
return aTab._findBar;
|
||||
|
||||
let findBar = document.createElementNS(this.namespaceURI, "findbar");
|
||||
let browser = this.getBrowserForTab(aTab);
|
||||
let browserContainer = this.getBrowserContainer(browser);
|
||||
browserContainer.appendChild(findBar);
|
||||
|
||||
// Force a style flush to ensure that our binding is attached.
|
||||
findBar.clientTop;
|
||||
|
||||
findBar.browser = browser;
|
||||
findBar._findField.value = this._lastFindValue;
|
||||
|
||||
aTab._findBar = findBar;
|
||||
|
||||
return findBar;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="updateWindowResizers">
|
||||
<body><![CDATA[
|
||||
if (!window.gShowPageResizers)
|
||||
@@ -1053,9 +1090,11 @@
|
||||
this.mCurrentTab.removeAttribute("unread");
|
||||
this.selectedTab.lastAccessed = Date.now();
|
||||
|
||||
// Bug 666816 - TypeAheadFind support for e10s
|
||||
if (!gMultiProcessBrowser)
|
||||
this._fastFind.setDocShell(this.mCurrentBrowser.docShell);
|
||||
let oldFindBar = oldTab._findBar;
|
||||
if (oldFindBar &&
|
||||
oldFindBar.findMode == oldFindBar.FIND_NORMAL &&
|
||||
!oldFindBar.hidden)
|
||||
this._lastFindValue = oldFindBar._findField.value;
|
||||
|
||||
this.updateTitlebar();
|
||||
|
||||
@@ -1574,7 +1613,6 @@
|
||||
this.mTabListeners[position] = tabListener;
|
||||
this.mTabFilters[position] = filter;
|
||||
|
||||
b._fastFind = this.fastFind;
|
||||
b.droppedLinkHandler = handleDroppedLink;
|
||||
|
||||
// If we just created a new tab that loads the default
|
||||
@@ -2234,6 +2272,15 @@
|
||||
this._swapBrowserDocShells(aOurTab, otherBrowser);
|
||||
}
|
||||
|
||||
// Handle findbar data (if any)
|
||||
let otherFindBar = aOtherTab._findBar;
|
||||
if (otherFindBar &&
|
||||
otherFindBar.findMode == otherFindBar.FIND_NORMAL) {
|
||||
let ourFindBar = this.getFindBar(aOurTab);
|
||||
ourFindBar.hidden = otherFindBar.hidden;
|
||||
ourFindBar._findField.value = otherFindBar._findField.value;
|
||||
}
|
||||
|
||||
// Finish tearing down the tab that's going away.
|
||||
remoteBrowser._endRemoveTab(aOtherTab);
|
||||
|
||||
@@ -2800,21 +2847,6 @@
|
||||
onget="return this.mCurrentBrowser.currentURI;"
|
||||
readonly="true"/>
|
||||
|
||||
<field name="_fastFind">null</field>
|
||||
<property name="fastFind"
|
||||
readonly="true">
|
||||
<getter>
|
||||
<![CDATA[
|
||||
if (!this._fastFind) {
|
||||
this._fastFind = Components.classes["@mozilla.org/typeaheadfind;1"]
|
||||
.createInstance(Components.interfaces.nsITypeAheadFind);
|
||||
this._fastFind.init(this.docShell);
|
||||
}
|
||||
return this._fastFind;
|
||||
]]>
|
||||
</getter>
|
||||
</property>
|
||||
|
||||
<field name="_lastSearchString">null</field>
|
||||
<field name="_lastSearchHighlight">false</field>
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* Tests for bug 537013 to ensure proper tab-sequestration of find bar. */
|
||||
|
||||
let tabs = [];
|
||||
let texts = [
|
||||
"This side up.",
|
||||
"The world is coming to an end. Please log off.",
|
||||
"Klein bottle for sale. Inquire within.",
|
||||
"To err is human; to forgive is not company policy."
|
||||
];
|
||||
|
||||
function addTabWithText(aText, aCallback) {
|
||||
let newTab = gBrowser.addTab("data:text/html,<h1 id='h1'>" + aText + "</h1>");
|
||||
tabs.push(newTab);
|
||||
gBrowser.selectedTab = newTab;
|
||||
}
|
||||
|
||||
function setFindString(aString) {
|
||||
gFindBar.open();
|
||||
gFindBar._findField.select();
|
||||
EventUtils.sendString(aString);
|
||||
is(gFindBar._findField.value, aString, "Set the field correctly!");
|
||||
}
|
||||
|
||||
let newWindow;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function () {
|
||||
while (tabs.length) {
|
||||
gBrowser.removeTab(tabs.pop());
|
||||
}
|
||||
});
|
||||
texts.forEach(function(aText) addTabWithText(aText));
|
||||
|
||||
// Set up the first tab
|
||||
gBrowser.selectedTab = tabs[0];
|
||||
|
||||
setFindString(texts[0]);
|
||||
|
||||
// Make sure the second tab is correct, then set it up
|
||||
gBrowser.selectedTab = tabs[1];
|
||||
ok(gFindBar.hidden, "Second tab doesn't show find bar!");
|
||||
gFindBar.open();
|
||||
is(gFindBar._findField.value, texts[0],
|
||||
"Second tab kept old find value for new initialization!");
|
||||
setFindString(texts[1]);
|
||||
|
||||
// Confirm the first tab is still correct, ensure re-hiding works as expected
|
||||
gBrowser.selectedTab = tabs[0];
|
||||
ok(!gFindBar.hidden, "First tab shows find bar!");
|
||||
is(gFindBar._findField.value, texts[0], "First tab persists find value!");
|
||||
gFindBar.close();
|
||||
ok(gFindBar.hidden, "First tab doesn't show find bar!");
|
||||
gBrowser.selectedTab = tabs[1];
|
||||
ok(!gFindBar.hidden, "Second tab shows find bar!");
|
||||
gBrowser.selectedTab = tabs[0];
|
||||
ok(gFindBar.hidden, "First tab doesn't show find bar!");
|
||||
|
||||
// Set up a third tab, no tests here
|
||||
gBrowser.selectedTab = tabs[2];
|
||||
setFindString(texts[2]);
|
||||
|
||||
// Now we jump to the second, then first, and then fourth
|
||||
gBrowser.selectedTab = tabs[1];
|
||||
gBrowser.selectedTab = tabs[0];
|
||||
gBrowser.selectedTab = tabs[3];
|
||||
ok(gFindBar.hidden, "Fourth tab doesn't show find bar!");
|
||||
is(gFindBar, gBrowser.getFindBar(), "Find bar is right one!");
|
||||
gFindBar.open();
|
||||
is(gFindBar._findField.value, texts[1],
|
||||
"Fourth tab has second tab's find value!");
|
||||
|
||||
newWindow = gBrowser.replaceTabWithWindow(tabs.pop());
|
||||
whenDelayedStartupFinished(newWindow, checkNewWindow);
|
||||
}
|
||||
|
||||
// Test that findbar gets restored when a tab is moved to a new window.
|
||||
function checkNewWindow() {
|
||||
ok(!newWindow.gFindBar.hidden, "New window shows find bar!");
|
||||
is(newWindow.gFindBar._findField.value, texts[1],
|
||||
"New window find bar has correct find value!");
|
||||
newWindow.close();
|
||||
finish();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gTab = null;
|
||||
|
||||
function load(url, cb) {
|
||||
gTab = gBrowser.addTab(url);
|
||||
gBrowser.addEventListener("load", function (event) {
|
||||
if (event.target.location != url)
|
||||
return;
|
||||
|
||||
gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
// Trigger onLocationChange by switching tabs.
|
||||
gBrowser.selectedTab = gTab;
|
||||
cb();
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
ok(gFindBar.hidden, "Find bar should not be visible by default");
|
||||
|
||||
// Open the Find bar before we navigate to pages that shouldn't have it.
|
||||
EventUtils.synthesizeKey("f", { accelKey: true });
|
||||
ok(!gFindBar.hidden, "Find bar should be visible");
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
let urls = [
|
||||
"about:config",
|
||||
"about:addons",
|
||||
"about:permissions"
|
||||
];
|
||||
|
||||
function nextTest() {
|
||||
let url = urls.shift();
|
||||
if (url) {
|
||||
testFindDisabled(url, nextTest);
|
||||
} else {
|
||||
// Make sure the find bar is re-enabled after disabled page is closed.
|
||||
testFindEnabled("about:blank", finish);
|
||||
}
|
||||
}
|
||||
|
||||
function testFindDisabled(url, cb) {
|
||||
load(url, function() {
|
||||
ok(gFindBar.hidden, "Find bar should not be visible");
|
||||
EventUtils.synthesizeKey("/", {}, gTab.linkedBrowser.contentWindow);
|
||||
ok(gFindBar.hidden, "Find bar should not be visible");
|
||||
EventUtils.synthesizeKey("f", { accelKey: true });
|
||||
ok(gFindBar.hidden, "Find bar should not be visible");
|
||||
ok(document.getElementById("cmd_find").getAttribute("disabled"),
|
||||
"Find command should be disabled");
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
function testFindEnabled(url, cb) {
|
||||
load(url, function() {
|
||||
ok(!document.getElementById("cmd_find").getAttribute("disabled"),
|
||||
"Find command should not be disabled");
|
||||
|
||||
// Open Find bar and then close it.
|
||||
EventUtils.synthesizeKey("f", { accelKey: true });
|
||||
ok(!gFindBar.hidden, "Find bar should be visible again");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", { });
|
||||
ok(gFindBar.hidden, "Find bar should now be hidden");
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(AF13EA3A-D488-4308-B843-526E055AB943)]
|
||||
interface nsIDOMNode;
|
||||
|
||||
[scriptable, uuid(35BE2D7E-F29B-48EC-BF7E-80A30A724DE3)]
|
||||
interface nsIContentViewerEdit : nsISupports
|
||||
{
|
||||
void clearSelection();
|
||||
@@ -27,4 +29,8 @@ interface nsIContentViewerEdit : nsISupports
|
||||
|
||||
AString getContents(in string aMimeType, in boolean aSelectionOnly);
|
||||
readonly attribute boolean canGetContents;
|
||||
|
||||
// Set the node that will be the subject of the editing commands above.
|
||||
// Usually this will be the node that was context-clicked.
|
||||
void setCommandNode(in nsIDOMNode aNode);
|
||||
};
|
||||
|
||||
@@ -812,22 +812,26 @@ nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
|
||||
event.refPoint = ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
|
||||
event.ignoreRootScrollFrame = aIgnoreRootScrollFrame;
|
||||
|
||||
nsEventStatus status;
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
if (aToWindow) {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsView* view = GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
|
||||
if (!presShell || !view) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
status = nsEventStatus_eIgnore;
|
||||
return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
|
||||
}
|
||||
nsresult rv = widget->DispatchEvent(&event, status);
|
||||
if (gfxPrefs::TestEventsAsyncEnabled()) {
|
||||
status = widget->DispatchInputEvent(&event);
|
||||
} else {
|
||||
nsresult rv = widget->DispatchEvent(&event, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
if (aPreventDefault) {
|
||||
*aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
|
||||
}
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
||||
@@ -884,8 +884,7 @@ nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
||||
|
||||
// Don't show remote iframe if we are waiting for the completion of reflow.
|
||||
if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
nsIntPoint chromeDisp = aFrame->GetChromeDisplacement();
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1386,6 +1385,12 @@ nsFrameLoader::StartDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
// If the TabParent has installed any event listeners on the window, this is
|
||||
// its last chance to remove them while we're still in the document.
|
||||
if (mRemoteBrowser) {
|
||||
mRemoteBrowser->RemoveWindowListeners();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
bool dynamicSubframeRemoval = false;
|
||||
if (mOwnerContent) {
|
||||
@@ -2064,8 +2069,7 @@ nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
|
||||
ScreenIntSize size = aIFrame->GetSubdocumentSize();
|
||||
nsIntRect dimensions;
|
||||
NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
|
||||
nsIntPoint chromeDisp = aIFrame->GetChromeDisplacement();
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -230,6 +230,9 @@ public:
|
||||
void ActivateUpdateHitRegion();
|
||||
void DeactivateUpdateHitRegion();
|
||||
|
||||
// Properly retrieves documentSize of any subdocument type.
|
||||
nsresult GetWindowDimensions(nsIntRect& aRect);
|
||||
|
||||
private:
|
||||
|
||||
void SetOwnerContent(mozilla::dom::Element* aContent);
|
||||
@@ -285,9 +288,6 @@ private:
|
||||
nsresult MaybeCreateDocShell();
|
||||
nsresult EnsureMessageManager();
|
||||
|
||||
// Properly retrieves documentSize of any subdocument type.
|
||||
nsresult GetWindowDimensions(nsIntRect& aRect);
|
||||
|
||||
// Updates the subdocument position and size. This gets called only
|
||||
// when we have our own in-process DocShell.
|
||||
void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);
|
||||
|
||||
+17
-2
@@ -55,7 +55,8 @@ using mozilla::CSSToScreenScale from "Units.h";
|
||||
using mozilla::CommandInt from "mozilla/EventForwards.h";
|
||||
using mozilla::Modifiers from "mozilla/EventForwards.h";
|
||||
using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
|
||||
using mozilla::WritingMode from "WritingModes.h";
|
||||
using mozilla::WritingMode from "mozilla/WritingModes.h";
|
||||
using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -439,6 +440,13 @@ parent:
|
||||
*/
|
||||
SetTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
|
||||
|
||||
/**
|
||||
* Notifies the APZ code of the allowed touch-behaviours for a particular
|
||||
* input block. Each item in the aFlags array corresponds to one touch point
|
||||
* in the touch event.
|
||||
*/
|
||||
SetAllowedTouchBehavior(uint64_t aInputBlockId, TouchBehaviorFlags[] aFlags);
|
||||
|
||||
/**
|
||||
* Updates the zoom constraints for a scrollable frame in this tab.
|
||||
* The zoom controller code lives on the parent side and so this allows it to
|
||||
@@ -484,7 +492,9 @@ parent:
|
||||
*/
|
||||
async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
|
||||
|
||||
prio(high) sync SynthesizedMouseWheelEvent(WidgetWheelEvent event);
|
||||
prio(high) sync DispatchWheelEvent(WidgetWheelEvent event);
|
||||
prio(high) sync DispatchMouseEvent(WidgetMouseEvent event);
|
||||
prio(high) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
|
||||
|
||||
child:
|
||||
/**
|
||||
@@ -564,6 +574,11 @@ child:
|
||||
int32_t aModifiers,
|
||||
bool aPreventDefault);
|
||||
|
||||
/**
|
||||
* APZ notification for mouse scroll testing events.
|
||||
*/
|
||||
MouseScrollTestEvent(ViewID aScrollId, nsString aEvent);
|
||||
|
||||
CompositionEvent(WidgetCompositionEvent event);
|
||||
|
||||
SelectionEvent(WidgetSelectionEvent event);
|
||||
|
||||
+30
-2
@@ -810,6 +810,22 @@ private:
|
||||
nsWeakPtr mTabChild;
|
||||
};
|
||||
|
||||
class TabChildSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback {
|
||||
public:
|
||||
explicit TabChildSetAllowedTouchBehaviorCallback(TabChild* aTabChild)
|
||||
: mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
|
||||
{}
|
||||
|
||||
void Run(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) const override {
|
||||
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild)) {
|
||||
static_cast<TabChild*>(tabChild.get())->SendSetAllowedTouchBehavior(aInputBlockId, aFlags);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsWeakPtr mTabChild;
|
||||
};
|
||||
|
||||
class TabChildContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback {
|
||||
public:
|
||||
explicit TabChildContentReceivedInputBlockCallback(TabChild* aTabChild)
|
||||
@@ -845,6 +861,7 @@ TabChild::TabChild(nsIContentChild* aManager,
|
||||
, mUpdateHitRegion(false)
|
||||
, mIgnoreKeyPressEvent(false)
|
||||
, mSetTargetAPZCCallback(new TabChildSetTargetAPZCCallback(this))
|
||||
, mSetAllowedTouchBehaviorCallback(new TabChildSetAllowedTouchBehaviorCallback(this))
|
||||
, mHasValidInnerSize(false)
|
||||
, mDestroyed(false)
|
||||
, mUniqueId(aTabId)
|
||||
@@ -2002,8 +2019,8 @@ TabChild::RecvUpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
|
||||
mOrientation = orientation;
|
||||
ScreenIntSize oldScreenSize = mInnerSize;
|
||||
mInnerSize = size;
|
||||
mWidget->Resize(0, 0, size.width, size.height,
|
||||
true);
|
||||
mWidget->Resize(rect.x + chromeDisp.x, rect.y + chromeDisp.y, size.width, size.height,
|
||||
true);
|
||||
|
||||
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
|
||||
baseWin->SetPositionAndSize(0, 0, size.width, size.height,
|
||||
@@ -2184,6 +2201,13 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
|
||||
{
|
||||
APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Touch*
|
||||
GetTouchForIdentifier(const WidgetTouchEvent& aEvent, int32_t aId)
|
||||
{
|
||||
@@ -2353,6 +2377,10 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
mWidget->GetDefaultScale(), GetPresShellResolution());
|
||||
|
||||
if (localEvent.message == NS_TOUCH_START && gfxPrefs::AsyncPanZoomEnabled()) {
|
||||
if (gfxPrefs::TouchActionEnabled()) {
|
||||
APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(WebWidget(),
|
||||
localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback);
|
||||
}
|
||||
nsCOMPtr<nsIDocument> document = GetDocument();
|
||||
APZCCallbackHelper::SendSetTargetAPZCNotification(WebWidget(), document,
|
||||
localEvent, aGuid, aInputBlockId, mSetTargetAPZCCallback);
|
||||
|
||||
@@ -47,6 +47,7 @@ class RenderFrameChild;
|
||||
namespace layers {
|
||||
class APZEventState;
|
||||
struct SetTargetAPZCCallback;
|
||||
struct SetAllowedTouchBehaviorCallback;
|
||||
}
|
||||
|
||||
namespace widget {
|
||||
@@ -243,6 +244,7 @@ class TabChild final : public TabChildBase,
|
||||
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
|
||||
typedef mozilla::layers::APZEventState APZEventState;
|
||||
typedef mozilla::layers::SetTargetAPZCCallback SetTargetAPZCCallback;
|
||||
typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -367,6 +369,8 @@ public:
|
||||
const int32_t& aCharCode,
|
||||
const int32_t& aModifiers,
|
||||
const bool& aPreventDefault) override;
|
||||
virtual bool RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId,
|
||||
const nsString& aEvent) override;
|
||||
virtual bool RecvCompositionEvent(const mozilla::WidgetCompositionEvent& event) override;
|
||||
virtual bool RecvSelectionEvent(const mozilla::WidgetSelectionEvent& event) override;
|
||||
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture) override;
|
||||
@@ -620,6 +624,7 @@ private:
|
||||
bool mIgnoreKeyPressEvent;
|
||||
nsRefPtr<APZEventState> mAPZEventState;
|
||||
nsRefPtr<SetTargetAPZCCallback> mSetTargetAPZCCallback;
|
||||
nsRefPtr<SetAllowedTouchBehaviorCallback> mSetAllowedTouchBehaviorCallback;
|
||||
bool mHasValidInnerSize;
|
||||
bool mDestroyed;
|
||||
// Position of tab, relative to parent widget (typically the window)
|
||||
|
||||
+114
-6
@@ -80,6 +80,7 @@
|
||||
#include "nsICancelable.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsILoginManagerPrompter.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla::dom;
|
||||
@@ -267,6 +268,7 @@ TabParent::TabParent(nsIContentParent* aManager,
|
||||
, mDefaultScale(0)
|
||||
, mShown(false)
|
||||
, mUpdatedDimensions(false)
|
||||
, mChromeOffset(0, 0)
|
||||
, mManager(aManager)
|
||||
, mMarkedDestroying(false)
|
||||
, mIsDestroyed(false)
|
||||
@@ -324,10 +326,36 @@ TabParent::CacheFrameLoader(nsFrameLoader* aFrameLoader)
|
||||
void
|
||||
TabParent::SetOwnerElement(Element* aElement)
|
||||
{
|
||||
// If we held previous content then unregister for its events.
|
||||
RemoveWindowListeners();
|
||||
|
||||
// Update to the new content, and register to listen for events from it.
|
||||
mFrameElement = aElement;
|
||||
if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
|
||||
nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
|
||||
nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
|
||||
if (eventTarget) {
|
||||
eventTarget->AddEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
|
||||
this, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
TryCacheDPIAndScale();
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::RemoveWindowListeners()
|
||||
{
|
||||
if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
|
||||
nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
|
||||
nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
|
||||
if (eventTarget) {
|
||||
eventTarget->RemoveEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
|
||||
this, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::GetAppType(nsAString& aOut)
|
||||
{
|
||||
@@ -879,8 +907,7 @@ TabParent::RecvSetDimensions(const uint32_t& aFlags,
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
|
||||
const nsIntPoint& aChromeDisp)
|
||||
TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size)
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return;
|
||||
@@ -888,15 +915,25 @@ TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
|
||||
hal::ScreenConfiguration config;
|
||||
hal::GetCurrentScreenConfiguration(&config);
|
||||
ScreenOrientation orientation = config.orientation();
|
||||
nsIntPoint chromeOffset = -LayoutDevicePixel::ToUntyped(GetChildProcessOffset());
|
||||
|
||||
if (!mUpdatedDimensions || mOrientation != orientation ||
|
||||
mDimensions != size || !mRect.IsEqualEdges(rect)) {
|
||||
mDimensions != size || !mRect.IsEqualEdges(rect) ||
|
||||
chromeOffset != mChromeOffset) {
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
nsIntRect contentRect = rect;
|
||||
if (widget) {
|
||||
contentRect.x += widget->GetClientOffset().x;
|
||||
contentRect.y += widget->GetClientOffset().y;
|
||||
}
|
||||
|
||||
mUpdatedDimensions = true;
|
||||
mRect = rect;
|
||||
mRect = contentRect;
|
||||
mDimensions = size;
|
||||
mOrientation = orientation;
|
||||
mChromeOffset = chromeOffset;
|
||||
|
||||
unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, aChromeDisp);
|
||||
unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, mChromeOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,6 +1019,14 @@ void TabParent::NotifyAPZStateChange(ViewID aViewId,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::NotifyMouseScrollTestEvent(const ViewID& aScrollId, const nsString& aEvent)
|
||||
{
|
||||
if (!mIsDestroyed) {
|
||||
unused << SendMouseScrollTestEvent(aScrollId, aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Activate()
|
||||
{
|
||||
@@ -1229,7 +1274,7 @@ bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event)
|
||||
return PBrowserParent::SendMouseWheelEvent(event, guid, blockId);
|
||||
}
|
||||
|
||||
bool TabParent::RecvSynthesizedMouseWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
|
||||
bool TabParent::RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
@@ -1244,6 +1289,38 @@ bool TabParent::RecvSynthesizedMouseWheelEvent(const mozilla::WidgetWheelEvent&
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return true;
|
||||
}
|
||||
|
||||
WidgetMouseEvent localEvent(aEvent);
|
||||
localEvent.widget = widget;
|
||||
localEvent.refPoint -= GetChildProcessOffset();
|
||||
|
||||
widget->DispatchInputEvent(&localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return true;
|
||||
}
|
||||
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
localEvent.widget = widget;
|
||||
localEvent.refPoint -= GetChildProcessOffset();
|
||||
|
||||
widget->DispatchInputEvent(&localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
DoCommandCallback(mozilla::Command aCommand, void* aData)
|
||||
{
|
||||
@@ -2489,6 +2566,16 @@ TabParent::RecvSetTargetAPZC(const uint64_t& aInputBlockId,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
|
||||
nsTArray<TouchBehaviorFlags>&& aFlags)
|
||||
{
|
||||
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
||||
rfp->SetAllowedTouchBehavior(aInputBlockId, aFlags);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<nsILoadContext>
|
||||
TabParent::GetLoadContext()
|
||||
{
|
||||
@@ -2703,6 +2790,27 @@ TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aAc
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TabParent::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
|
||||
if (eventType.EqualsLiteral("MozUpdateWindowPos") && !mIsDestroyed) {
|
||||
// This event is sent when the widget moved. Therefore we only update
|
||||
// the position.
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
if (!frameLoader) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsIntRect windowDims;
|
||||
NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims), NS_ERROR_FAILURE);
|
||||
UpdateDimensions(windowDims, mDimensions);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class FakeChannel final : public nsIChannel,
|
||||
public nsIAuthPromptCallback,
|
||||
public nsIInterfaceRequestor,
|
||||
|
||||
+18
-8
@@ -7,22 +7,22 @@
|
||||
#ifndef mozilla_tabs_TabParent_h
|
||||
#define mozilla_tabs_TabParent_h
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/PBrowserParent.h"
|
||||
#include "mozilla/dom/PFilePickerParent.h"
|
||||
#include "mozilla/dom/TabContext.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAuthPromptProvider.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsITabParent.h"
|
||||
#include "nsIXULBrowserWindow.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "Units.h"
|
||||
#include "WritingModes.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "TabMessageUtils.h"
|
||||
|
||||
class nsFrameLoader;
|
||||
class nsIFrameLoader;
|
||||
@@ -60,6 +60,7 @@ class Element;
|
||||
struct StructuredCloneData;
|
||||
|
||||
class TabParent final : public PBrowserParent
|
||||
, public nsIDOMEventListener
|
||||
, public nsITabParent
|
||||
, public nsIAuthPromptProvider
|
||||
, public nsISecureBrowserUI
|
||||
@@ -73,6 +74,8 @@ class TabParent final : public PBrowserParent
|
||||
public:
|
||||
// nsITabParent
|
||||
NS_DECL_NSITABPARENT
|
||||
// nsIDOMEventListener interfaces
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
TabParent(nsIContentParent* aManager,
|
||||
const TabId& aTabId,
|
||||
@@ -107,6 +110,8 @@ public:
|
||||
|
||||
void Destroy();
|
||||
|
||||
void RemoveWindowListeners();
|
||||
|
||||
virtual bool RecvMoveFocus(const bool& aForward) override;
|
||||
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
|
||||
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
|
||||
@@ -210,7 +215,11 @@ public:
|
||||
const bool& aPreventDefault) override;
|
||||
virtual bool RecvSetTargetAPZC(const uint64_t& aInputBlockId,
|
||||
nsTArray<ScrollableLayerGuid>&& aTargets) override;
|
||||
virtual bool RecvSynthesizedMouseWheelEvent(const mozilla::WidgetWheelEvent& aEvent) override;
|
||||
virtual bool RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
|
||||
nsTArray<TouchBehaviorFlags>&& aTargets) override;
|
||||
virtual bool RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent) override;
|
||||
virtual bool RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent) override;
|
||||
virtual bool RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent) override;
|
||||
|
||||
virtual PColorPickerParent*
|
||||
AllocPColorPickerParent(const nsString& aTitle, const nsString& aInitialColor) override;
|
||||
@@ -221,8 +230,7 @@ public:
|
||||
// message-sending functions under a layer of indirection and
|
||||
// eating the return values
|
||||
void Show(const ScreenIntSize& size, bool aParentIsActive);
|
||||
void UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
|
||||
const nsIntPoint& chromeDisp);
|
||||
void UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size);
|
||||
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
|
||||
void UIResolutionChanged();
|
||||
void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
|
||||
@@ -244,6 +252,7 @@ public:
|
||||
void NotifyAPZStateChange(ViewID aViewId,
|
||||
APZStateChange aChange,
|
||||
int aArg);
|
||||
void NotifyMouseScrollTestEvent(const ViewID& aScrollId, const nsString& aEvent);
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
@@ -426,6 +435,7 @@ protected:
|
||||
CSSToLayoutDeviceScale mDefaultScale;
|
||||
bool mShown;
|
||||
bool mUpdatedDimensions;
|
||||
nsIntPoint mChromeOffset;
|
||||
|
||||
private:
|
||||
already_AddRefed<nsFrameLoader> GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const;
|
||||
|
||||
@@ -798,7 +798,6 @@ NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
|
||||
tabContentBounds.ScaleInverseRoundOut(scaleFactor);
|
||||
int32_t windowH = tabContentBounds.height + int(chromeSize.y);
|
||||
|
||||
// This is actually relative to window-chrome.
|
||||
nsPoint pluginPosition = AsNsPoint(pluginFrame->GetScreenRect().TopLeft());
|
||||
|
||||
// Convert (sourceX, sourceY) to 'real' (not PuppetWidget) screen space.
|
||||
@@ -808,8 +807,8 @@ NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
|
||||
nsPoint screenPoint;
|
||||
switch (sourceSpace) {
|
||||
case NPCoordinateSpacePlugin:
|
||||
screenPoint = sourcePoint + pluginFrame->GetContentRectRelativeToSelf().TopLeft() +
|
||||
chromeSize + pluginPosition + windowPosition;
|
||||
screenPoint = sourcePoint + pluginPosition +
|
||||
pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
|
||||
break;
|
||||
case NPCoordinateSpaceWindow:
|
||||
screenPoint = nsPoint(sourcePoint.x, windowH-sourcePoint.y) +
|
||||
@@ -832,8 +831,8 @@ NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
|
||||
nsPoint destPoint;
|
||||
switch (destSpace) {
|
||||
case NPCoordinateSpacePlugin:
|
||||
destPoint = screenPoint - pluginFrame->GetContentRectRelativeToSelf().TopLeft() -
|
||||
chromeSize - pluginPosition - windowPosition;
|
||||
destPoint = screenPoint - pluginPosition -
|
||||
pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
|
||||
break;
|
||||
case NPCoordinateSpaceWindow:
|
||||
destPoint = screenPoint - windowPosition;
|
||||
|
||||
@@ -1452,9 +1452,15 @@ ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
|
||||
if (textFound) {
|
||||
nsString tipText(tooltipText);
|
||||
LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
|
||||
self->ShowTooltip(self->mMouseScreenX - screenDot.x,
|
||||
self->mMouseScreenY - screenDot.y,
|
||||
tipText);
|
||||
double scaleFactor = 1.0;
|
||||
if (shell->GetPresContext()) {
|
||||
scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
|
||||
shell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
|
||||
}
|
||||
// ShowTooltip expects widget-relative position.
|
||||
self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor,
|
||||
self->mMouseScreenY - screenDot.y / scaleFactor,
|
||||
tipText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,6 @@ public:
|
||||
EndTouch,
|
||||
APZStateChangeSentinel
|
||||
};
|
||||
|
||||
/**
|
||||
* General notices of APZ state changes for consumers.
|
||||
* |aGuid| identifies the APZC originating the state change.
|
||||
@@ -165,6 +164,12 @@ public:
|
||||
APZStateChange aChange,
|
||||
int aArg = 0) {}
|
||||
|
||||
/**
|
||||
* Notify content of a MozMouseScrollFailed event.
|
||||
*/
|
||||
virtual void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
|
||||
{}
|
||||
|
||||
GeckoContentController() {}
|
||||
virtual void Destroy() {}
|
||||
|
||||
|
||||
@@ -804,6 +804,47 @@ APZCTreeManager::TransformCoordinateToGoanna(const ScreenIntPoint& aPoint,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::UpdateWheelTransaction(WidgetInputEvent& aEvent)
|
||||
{
|
||||
WheelBlockState* txn = mInputQueue->GetCurrentWheelTransaction();
|
||||
if (!txn) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the transaction has simply timed out, we don't need to do anything
|
||||
// else.
|
||||
if (txn->MaybeTimeout(TimeStamp::Now())) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.message) {
|
||||
case NS_MOUSE_MOVE:
|
||||
case NS_DRAGDROP_OVER: {
|
||||
WidgetMouseEvent* mouseEvent = aEvent.AsMouseEvent();
|
||||
if (!mouseEvent->IsReal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenIntPoint point =
|
||||
ViewAs<ScreenPixel>(aEvent.refPoint, PixelCastJustification::LayoutDeviceToScreenForUntransformedEvent);
|
||||
txn->OnMouseMove(point);
|
||||
return;
|
||||
}
|
||||
case NS_KEY_PRESS:
|
||||
case NS_KEY_UP:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_MOUSE_BUTTON_UP:
|
||||
case NS_MOUSE_BUTTON_DOWN:
|
||||
case NS_MOUSE_DOUBLECLICK:
|
||||
case NS_MOUSE_CLICK:
|
||||
case NS_CONTEXTMENU:
|
||||
case NS_DRAGDROP_DROP:
|
||||
txn->EndTransaction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid,
|
||||
@@ -812,6 +853,9 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsEventStatus result = nsEventStatus_eIgnore;
|
||||
|
||||
// Note, we call this before having transformed the reference point.
|
||||
UpdateWheelTransaction(aEvent);
|
||||
|
||||
// Transform the refPoint.
|
||||
// If the event hits an overscrolled APZC, instruct the caller to ignore it.
|
||||
HitTestResult hitResult = HitNothing;
|
||||
|
||||
@@ -441,6 +441,7 @@ private:
|
||||
nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid,
|
||||
uint64_t* aOutInputBlockId);
|
||||
void UpdateWheelTransaction(WidgetInputEvent& aEvent);
|
||||
void UpdateZoomConstraintsRecursively(HitTestingTreeNode* aNode,
|
||||
const ZoomConstraints& aConstraints);
|
||||
void FlushRepaintsRecursively(HitTestingTreeNode* aNode);
|
||||
|
||||
@@ -682,7 +682,11 @@ public:
|
||||
, mYAxisModel(aInitialPosition.y, aDestination.y, aInitialVelocity.y,
|
||||
aSpringConstant, aDampingRatio)
|
||||
, mSource(aSource)
|
||||
, mAllowOverscroll(true)
|
||||
{
|
||||
if (mSource == ScrollSource::Wheel) {
|
||||
mAllowOverscroll = mApzc.AllowScrollHandoffInWheelTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -739,8 +743,7 @@ public:
|
||||
// This can happen if either the layout.css.scroll-behavior.damping-ratio
|
||||
// preference is set to less than 1 (underdamped) or if a smooth scroll
|
||||
// inherits velocity from a fling gesture.
|
||||
if (!IsZero(overscroll)) {
|
||||
|
||||
if (!IsZero(overscroll) && mAllowOverscroll) {
|
||||
// Hand off a fling with the remaining momentum to the next APZC in the
|
||||
// overscroll handoff chain.
|
||||
|
||||
@@ -778,6 +781,7 @@ private:
|
||||
AsyncPanZoomController& mApzc;
|
||||
AxisPhysicsMSDModel mXAxisModel, mYAxisModel;
|
||||
ScrollSource mSource;
|
||||
bool mAllowOverscroll;
|
||||
};
|
||||
|
||||
void
|
||||
@@ -1416,20 +1420,73 @@ AsyncPanZoomController::ConvertToGoanna(const ParentLayerPoint& aPoint, CSSPoint
|
||||
return false;
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
|
||||
void
|
||||
AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent,
|
||||
double& aOutDeltaX,
|
||||
double& aOutDeltaY) const
|
||||
{
|
||||
double deltaX = aEvent.mDeltaX;
|
||||
double deltaY = aEvent.mDeltaY;
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
aOutDeltaX = aEvent.mDeltaX;
|
||||
aOutDeltaY = aEvent.mDeltaY;
|
||||
switch (aEvent.mDeltaType) {
|
||||
case ScrollWheelInput::SCROLLDELTA_LINE: {
|
||||
LayoutDeviceIntSize scrollAmount = mFrameMetrics.GetLineScrollAmount();
|
||||
deltaX *= scrollAmount.width;
|
||||
deltaY *= scrollAmount.height;
|
||||
aOutDeltaX *= scrollAmount.width;
|
||||
aOutDeltaY *= scrollAmount.height;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected scroll delta type");
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
|
||||
// Return whether or not the underlying layer can be scrolled on either axis.
|
||||
bool
|
||||
AsyncPanZoomController::CanScroll(const ScrollWheelInput& aEvent) const
|
||||
{
|
||||
double deltaX, deltaY;
|
||||
GetScrollWheelDelta(aEvent, deltaX, deltaY);
|
||||
|
||||
if (!deltaX && !deltaY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CanScroll(deltaX, deltaY);
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncPanZoomController::CanScroll(double aDeltaX, double aDeltaY) const
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
return mX.CanScroll(aDeltaX) || mY.CanScroll(aDeltaY);
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncPanZoomController::AllowScrollHandoffInWheelTransaction() const
|
||||
{
|
||||
WheelBlockState* block = mInputQueue->CurrentWheelBlock();
|
||||
return block->AllowScrollHandoff();
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
|
||||
{
|
||||
double deltaX, deltaY;
|
||||
GetScrollWheelDelta(aEvent, deltaX, deltaY);
|
||||
|
||||
if ((deltaX || deltaY) &&
|
||||
!CanScroll(deltaX, deltaY) &&
|
||||
mInputQueue->GetCurrentWheelTransaction())
|
||||
{
|
||||
// We can't scroll this apz anymore, so we simply drop the event.
|
||||
if (gfxPrefs::MouseScrollTestingEnabled()) {
|
||||
if (nsRefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
controller->NotifyMozMouseScrollEvent(
|
||||
mFrameMetrics.GetScrollId(),
|
||||
NS_LITERAL_STRING("MozMouseScrollFailed"));
|
||||
}
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
switch (aEvent.mScrollMode) {
|
||||
@@ -1482,6 +1539,17 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
void
|
||||
AsyncPanZoomController::NotifyMozMouseScrollEvent(const nsString& aString) const
|
||||
{
|
||||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller->NotifyMozMouseScrollEvent(mFrameMetrics.GetScrollId(), aString);
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnPanMayBegin(const PanGestureInput& aEvent) {
|
||||
APZC_LOG("%p got a pan-maybegin in state %d\n", this, mState);
|
||||
|
||||
@@ -1731,6 +1799,19 @@ ParentLayerPoint AsyncPanZoomController::ToParentLayerCoordinates(const ScreenPo
|
||||
return TransformVector<ParentLayerPixel>(GetTransformToThis(), aVector, aAnchor);
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::Contains(const ScreenIntPoint& aPoint) const
|
||||
{
|
||||
Matrix4x4 transformToThis = GetTransformToThis();
|
||||
ParentLayerIntPoint point = TransformTo<ParentLayerPixel>(transformToThis, aPoint);
|
||||
|
||||
ParentLayerIntRect cb;
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
GetFrameMetrics().mCompositionBounds.ToIntRect(&cb);
|
||||
}
|
||||
return cb.Contains(point);
|
||||
}
|
||||
|
||||
ScreenCoord AsyncPanZoomController::PanDistance() const {
|
||||
ParentLayerPoint panVector;
|
||||
ParentLayerPoint panStart;
|
||||
@@ -1922,6 +2003,13 @@ bool AsyncPanZoomController::AttemptScroll(const ParentLayerPoint& aStartPoint,
|
||||
return true;
|
||||
}
|
||||
|
||||
// If in a wheel transaction that has not ended, we drop overscroll.
|
||||
if (aOverscrollHandoffState.mScrollSource == ScrollSource::Wheel &&
|
||||
!AllowScrollHandoffInWheelTransaction())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is overscroll, first try to hand it off to an APZC later
|
||||
// in the handoff chain to consume (either as a normal scroll or as
|
||||
// overscroll).
|
||||
|
||||
@@ -355,6 +355,16 @@ public:
|
||||
ParentLayerPoint ToParentLayerCoordinates(const ScreenPoint& aVector,
|
||||
const ScreenPoint& aAnchor) const;
|
||||
|
||||
// Return whether or not a wheel event will be able to scroll in either
|
||||
// direction.
|
||||
bool CanScroll(const ScrollWheelInput& aEvent) const;
|
||||
|
||||
// Return whether or not a scroll delta will be able to scroll in either
|
||||
// direction.
|
||||
bool CanScroll(double aDeltaX, double aDeltaY) const;
|
||||
|
||||
void NotifyMozMouseScrollEvent(const nsString& aString) const;
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
~AsyncPanZoomController();
|
||||
@@ -417,6 +427,10 @@ protected:
|
||||
*/
|
||||
nsEventStatus OnScrollWheel(const ScrollWheelInput& aEvent);
|
||||
|
||||
void GetScrollWheelDelta(const ScrollWheelInput& aEvent,
|
||||
double& aOutDeltaX,
|
||||
double& aOutDeltaY) const;
|
||||
|
||||
/**
|
||||
* Helper methods for long press gestures.
|
||||
*/
|
||||
@@ -843,6 +857,9 @@ private:
|
||||
|
||||
void StartSmoothScroll(ScrollSource aSource);
|
||||
|
||||
// Returns whether overscroll is allowed during a wheel event.
|
||||
bool AllowScrollHandoffInWheelTransaction() const;
|
||||
|
||||
/* ===================================================================
|
||||
* The functions and members in this section are used to make ancestor chains
|
||||
* out of APZC instances. These chains can only be walked or manipulated
|
||||
@@ -978,6 +995,10 @@ public:
|
||||
return mAncestorTransform;
|
||||
}
|
||||
|
||||
// Returns whether or not this apzc contains the given screen point within
|
||||
// its composition bounds.
|
||||
bool Contains(const ScreenIntPoint& aPoint) const;
|
||||
|
||||
bool IsOverscrolled() const {
|
||||
return mX.IsOverscrolled() || mY.IsOverscrolled();
|
||||
}
|
||||
|
||||
@@ -393,6 +393,16 @@ bool Axis::CanScroll() const {
|
||||
return GetPageLength() - GetCompositionLength() > COORDINATE_EPSILON;
|
||||
}
|
||||
|
||||
bool Axis::CanScroll(double aDelta) const
|
||||
{
|
||||
if (!CanScroll() || mAxisLocked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ParentLayerCoord delta = aDelta;
|
||||
return DisplacementWillOverscrollAmount(delta) != delta;
|
||||
}
|
||||
|
||||
bool Axis::CanScrollNow() const {
|
||||
return !mAxisLocked && CanScroll();
|
||||
}
|
||||
|
||||
@@ -157,6 +157,11 @@ public:
|
||||
*/
|
||||
bool CanScroll() const;
|
||||
|
||||
/**
|
||||
* Returns whether this axis can scroll any more in a particular direction.
|
||||
*/
|
||||
bool CanScroll(double aDelta) const;
|
||||
|
||||
/**
|
||||
* Returns true if the page has room to be scrolled along this axis
|
||||
* and this axis is not scroll-locked.
|
||||
|
||||
@@ -49,11 +49,17 @@ InputBlockState::SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>&
|
||||
printf_stderr("%p replacing unconfirmed target %p with real target %p\n",
|
||||
this, mTargetApzc.get(), aTargetApzc.get());
|
||||
|
||||
UpdateTargetApzc(aTargetApzc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
InputBlockState::UpdateTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc)
|
||||
{
|
||||
// note that aTargetApzc MAY be null here.
|
||||
mTargetApzc = aTargetApzc;
|
||||
mTransformToApzc = aTargetApzc ? aTargetApzc->GetTransformToThis() : gfx::Matrix4x4();
|
||||
mOverscrollHandoffChain = (mTargetApzc ? mTargetApzc->BuildOverscrollHandoffChain() : nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
const nsRefPtr<AsyncPanZoomController>&
|
||||
@@ -142,10 +148,63 @@ CancelableBlockState::DispatchImmediate(const InputData& aEvent) const
|
||||
GetTargetApzc()->HandleInputEvent(aEvent, mTransformToApzc);
|
||||
}
|
||||
|
||||
// This is used to track the current wheel transaction.
|
||||
static uint64_t sLastWheelBlockId = InputBlockState::NO_BLOCK_ID;
|
||||
|
||||
WheelBlockState::WheelBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed)
|
||||
bool aTargetConfirmed,
|
||||
const ScrollWheelInput& aInitialEvent)
|
||||
: CancelableBlockState(aTargetApzc, aTargetConfirmed)
|
||||
, mTransactionEnded(false)
|
||||
{
|
||||
sLastWheelBlockId = GetBlockId();
|
||||
|
||||
if (aTargetConfirmed) {
|
||||
// Find the nearest APZC in the overscroll handoff chain that is scrollable.
|
||||
// If we get a content confirmation later that the apzc is different, then
|
||||
// content should have found a scrollable apzc, so we don't need to handle
|
||||
// that case.
|
||||
nsRefPtr<AsyncPanZoomController> apzc =
|
||||
mOverscrollHandoffChain->FindFirstScrollable(aInitialEvent);
|
||||
|
||||
// If nothing is scrollable, we don't consider this block as starting a
|
||||
// transaction.
|
||||
if (!apzc) {
|
||||
EndTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
if (apzc != GetTargetApzc()) {
|
||||
UpdateTargetApzc(apzc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WheelBlockState::Update(const ScrollWheelInput& aEvent)
|
||||
{
|
||||
// We might not be in a transaction if the block never started in a
|
||||
// transaction - for example, if nothing was scrollable.
|
||||
if (!InTransaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we can't scroll in the direction of the wheel event, we don't update
|
||||
// the last move time. This allows us to timeout a transaction even if the
|
||||
// mouse isn't moving.
|
||||
//
|
||||
// We skip this check if the target is not yet confirmed, so that when it is
|
||||
// confirmed, we don't timeout the transaction.
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetApzc();
|
||||
if (IsTargetConfirmed() && !apzc->CanScroll(aEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the time of the last known good event, and reset the mouse move
|
||||
// time to null. This will reset the delays on both the general transaction
|
||||
// timeout and the mouse-move-in-frame timeout.
|
||||
mLastEventTime = aEvent.mTimeStamp;
|
||||
mLastMouseMove = TimeStamp();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -190,7 +249,7 @@ WheelBlockState::HandleEvents()
|
||||
bool
|
||||
WheelBlockState::MustStayActive()
|
||||
{
|
||||
return false;
|
||||
return !mTransactionEnded;
|
||||
}
|
||||
|
||||
const char*
|
||||
@@ -199,6 +258,108 @@ WheelBlockState::Type()
|
||||
return "scroll wheel";
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::ShouldAcceptNewEvent() const
|
||||
{
|
||||
if (!InTransaction()) {
|
||||
// If we're not in a transaction, start a new one.
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetApzc();
|
||||
if (!apzc || apzc->IsDestroyed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::MaybeTimeout(const ScrollWheelInput& aEvent)
|
||||
{
|
||||
if (MaybeTimeout(aEvent.mTimeStamp)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mLastMouseMove.IsNull()) {
|
||||
// If there's a recent mouse movement, we can time out the transaction early.
|
||||
TimeDuration duration = TimeStamp::Now() - mLastMouseMove;
|
||||
if (duration.ToMilliseconds() >= gfxPrefs::MouseWheelIgnoreMoveDelayMs()) {
|
||||
TBS_LOG("%p wheel transaction timed out after mouse move\n", this);
|
||||
EndTransaction();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::MaybeTimeout(const TimeStamp& aTimeStamp)
|
||||
{
|
||||
// End the transaction if the event occurred > 1.5s after the most recently
|
||||
// seen wheel event.
|
||||
TimeDuration duration = aTimeStamp - mLastEventTime;
|
||||
if (duration.ToMilliseconds() < gfxPrefs::MouseWheelTransactionTimeoutMs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TBS_LOG("%p wheel transaction timed out\n", this);
|
||||
|
||||
if (gfxPrefs::MouseScrollTestingEnabled()) {
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetApzc();
|
||||
apzc->NotifyMozMouseScrollEvent(NS_LITERAL_STRING("MozMouseScrollTransactionTimeout"));
|
||||
}
|
||||
|
||||
EndTransaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WheelBlockState::OnMouseMove(const ScreenIntPoint& aPoint)
|
||||
{
|
||||
if (!GetTargetApzc()->Contains(aPoint)) {
|
||||
EndTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLastMouseMove.IsNull()) {
|
||||
// If the cursor is moving inside the frame, and it is more than the
|
||||
// ignoremovedelay time since the last scroll operation, we record
|
||||
// this as the most recent mouse movement.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration duration = now - mLastEventTime;
|
||||
if (duration.ToMilliseconds() >= gfxPrefs::MouseWheelIgnoreMoveDelayMs()) {
|
||||
mLastMouseMove = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::InTransaction() const
|
||||
{
|
||||
// We consider a wheel block to be in a transaction if it has a confirmed
|
||||
// target and is the most recent wheel input block to be created.
|
||||
if (GetBlockId() != sLastWheelBlockId) {
|
||||
return false;
|
||||
}
|
||||
return !mTransactionEnded;
|
||||
}
|
||||
|
||||
bool
|
||||
WheelBlockState::AllowScrollHandoff() const
|
||||
{
|
||||
// If we're in a wheel transaction, we do not allow overscroll handoff until
|
||||
// a new event ends the wheel transaction.
|
||||
return !IsTargetConfirmed() || !InTransaction();
|
||||
}
|
||||
|
||||
void
|
||||
WheelBlockState::EndTransaction()
|
||||
{
|
||||
TBS_LOG("%p ending wheel transaction\n", this);
|
||||
mTransactionEnded = true;
|
||||
}
|
||||
|
||||
TouchBlockState::TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed)
|
||||
: CancelableBlockState(aTargetApzc, aTargetConfirmed)
|
||||
|
||||
@@ -45,12 +45,16 @@ public:
|
||||
|
||||
bool IsTargetConfirmed() const;
|
||||
|
||||
protected:
|
||||
void UpdateTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncPanZoomController> mTargetApzc;
|
||||
nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
|
||||
bool mTargetConfirmed;
|
||||
const uint64_t mBlockId;
|
||||
protected:
|
||||
nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
|
||||
|
||||
// Used to transform events from global screen space to |mTargetApzc|'s
|
||||
// screen space. It's cached at the beginning of the input block so that
|
||||
// all events in the block are in the same coordinate space.
|
||||
@@ -154,7 +158,8 @@ class WheelBlockState : public CancelableBlockState
|
||||
{
|
||||
public:
|
||||
WheelBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed);
|
||||
bool aTargetConfirmed,
|
||||
const ScrollWheelInput& aEvent);
|
||||
|
||||
bool IsReadyForHandling() const override;
|
||||
bool HasEvents() const override;
|
||||
@@ -169,8 +174,61 @@ public:
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this wheel block is accepting new events.
|
||||
*/
|
||||
bool ShouldAcceptNewEvent() const;
|
||||
|
||||
/**
|
||||
* Call to check whether a wheel event will cause the current transaction to
|
||||
* timeout.
|
||||
*/
|
||||
bool MaybeTimeout(const ScrollWheelInput& aEvent);
|
||||
|
||||
/**
|
||||
* Called from APZCTM when a mouse move or drag+drop event occurs, before
|
||||
* the event has been processed.
|
||||
*/
|
||||
void OnMouseMove(const ScreenIntPoint& aPoint);
|
||||
|
||||
/**
|
||||
* Returns whether or not the block is participating in a wheel transaction.
|
||||
* This means that the block is the most recent input block to be created,
|
||||
* and no events have occurred that would require scrolling a different
|
||||
* frame.
|
||||
*
|
||||
* @return True if in a transaction, false otherwise.
|
||||
*/
|
||||
bool InTransaction() const;
|
||||
|
||||
/**
|
||||
* Mark the block as no longer participating in a wheel transaction. This
|
||||
* will force future wheel events to begin a new input block.
|
||||
*/
|
||||
void EndTransaction();
|
||||
|
||||
/**
|
||||
* @return Whether or not overscrolling is prevented for this wheel block.
|
||||
*/
|
||||
bool AllowScrollHandoff() const;
|
||||
|
||||
/**
|
||||
* Called to check and possibly end the transaction due to a timeout.
|
||||
*
|
||||
* @return True if the transaction ended, false otherwise.
|
||||
*/
|
||||
bool MaybeTimeout(const TimeStamp& aTimeStamp);
|
||||
|
||||
/**
|
||||
* Update the wheel transaction state for a new event.
|
||||
*/
|
||||
void Update(const ScrollWheelInput& aEvent);
|
||||
|
||||
private:
|
||||
nsTArray<ScrollWheelInput> mEvents;
|
||||
TimeStamp mLastEventTime;
|
||||
TimeStamp mLastMouseMove;
|
||||
bool mTransactionEnded;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,14 +147,20 @@ InputQueue::ReceiveScrollWheelInput(const nsRefPtr<AsyncPanZoomController>& aTar
|
||||
if (!mInputBlockQueue.IsEmpty()) {
|
||||
block = mInputBlockQueue.LastElement()->AsWheelBlock();
|
||||
|
||||
// If the block's APZC has been destroyed, request a new block.
|
||||
if (block && block->GetTargetApzc()->IsDestroyed()) {
|
||||
// If the block is not accepting new events we'll create a new input block
|
||||
// (and therefore a new wheel transaction).
|
||||
if (block &&
|
||||
(!block->ShouldAcceptNewEvent() ||
|
||||
block->MaybeTimeout(aEvent)))
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!block || block->InTransaction());
|
||||
|
||||
if (!block) {
|
||||
block = new WheelBlockState(aTarget, aTargetConfirmed);
|
||||
block = new WheelBlockState(aTarget, aTargetConfirmed, aEvent);
|
||||
INPQ_LOG("started new scroll wheel block %p for target %p\n", block, aTarget.get());
|
||||
|
||||
SweepDepletedBlocks();
|
||||
@@ -170,6 +176,8 @@ InputQueue::ReceiveScrollWheelInput(const nsRefPtr<AsyncPanZoomController>& aTar
|
||||
*aOutInputBlockId = block->GetBlockId();
|
||||
}
|
||||
|
||||
block->Update(aEvent);
|
||||
|
||||
// Note that the |aTarget| the APZCTM sent us may contradict the confirmed
|
||||
// target set on the block. In this case the confirmed target (which may be
|
||||
// null) should take priority. This is equivalent to just always using the
|
||||
@@ -278,11 +286,32 @@ InputQueue::CurrentBlock() const
|
||||
TouchBlockState*
|
||||
InputQueue::CurrentTouchBlock() const
|
||||
{
|
||||
TouchBlockState *block = CurrentBlock()->AsTouchBlock();
|
||||
TouchBlockState* block = CurrentBlock()->AsTouchBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
WheelBlockState*
|
||||
InputQueue::CurrentWheelBlock() const
|
||||
{
|
||||
WheelBlockState* block = CurrentBlock()->AsWheelBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
WheelBlockState*
|
||||
InputQueue::GetCurrentWheelTransaction() const
|
||||
{
|
||||
if (mInputBlockQueue.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
WheelBlockState* block = CurrentBlock()->AsWheelBlock();
|
||||
if (!block || !block->InTransaction()) {
|
||||
return nullptr;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::HasReadyTouchBlock() const
|
||||
{
|
||||
@@ -418,7 +447,7 @@ InputQueue::ProcessInputBlocks() {
|
||||
|
||||
// If we get here, we know there are more touch blocks in the queue after
|
||||
// |curBlock|, so we can remove |curBlock| and try to process the next one.
|
||||
INPQ_LOG("discarding depleted touch block %p\n", curBlock);
|
||||
INPQ_LOG("discarding processed %s block %p\n", curBlock->Type(), curBlock);
|
||||
mInputBlockQueue.RemoveElementAt(0);
|
||||
} while (!mInputBlockQueue.IsEmpty());
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class AsyncPanZoomController;
|
||||
class OverscrollHandoffChain;
|
||||
class CancelableBlockState;
|
||||
class TouchBlockState;
|
||||
class WheelBlockState;
|
||||
|
||||
/**
|
||||
* This class stores incoming input events, separated into "input blocks", until
|
||||
@@ -80,15 +81,25 @@ public:
|
||||
*/
|
||||
CancelableBlockState* CurrentBlock() const;
|
||||
/**
|
||||
* Returns the current pending input block as a touch block. It must only
|
||||
* Returns the current pending input block as a touch block. It must only be
|
||||
* called if the current pending block is a touch block.
|
||||
*/
|
||||
TouchBlockState* CurrentTouchBlock() const;
|
||||
/**
|
||||
* Returns the current pending input block as a wheel block. It must only be
|
||||
* called if the current pending block is a wheel block.
|
||||
*/
|
||||
WheelBlockState* CurrentWheelBlock() const;
|
||||
/**
|
||||
* Returns true iff the pending block at the head of the queue is ready for
|
||||
* handling.
|
||||
*/
|
||||
bool HasReadyTouchBlock() const;
|
||||
/**
|
||||
* If there is a wheel transaction, returns the WheelBlockState representing
|
||||
* the transaction. Otherwise, returns null.
|
||||
*/
|
||||
WheelBlockState* GetCurrentWheelTransaction() const;
|
||||
|
||||
private:
|
||||
~InputQueue();
|
||||
|
||||
@@ -63,7 +63,6 @@ OverscrollHandoffChain::IndexOf(const AsyncPanZoomController* aApzc) const
|
||||
void
|
||||
OverscrollHandoffChain::ForEachApzc(APZCMethod aMethod) const
|
||||
{
|
||||
MOZ_ASSERT(Length() > 0);
|
||||
for (uint32_t i = 0; i < Length(); ++i) {
|
||||
(mChain[i]->*aMethod)();
|
||||
}
|
||||
@@ -156,6 +155,16 @@ OverscrollHandoffChain::HasFastMovingApzc() const
|
||||
return AnyApzc(&AsyncPanZoomController::IsMovingFast);
|
||||
}
|
||||
|
||||
nsRefPtr<AsyncPanZoomController>
|
||||
OverscrollHandoffChain::FindFirstScrollable(const ScrollWheelInput& aInput) const
|
||||
{
|
||||
for (size_t i = 0; i < Length(); i++) {
|
||||
if (mChain[i]->CanScroll(aInput)) {
|
||||
return mChain[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -113,6 +113,8 @@ public:
|
||||
// Determine whether any APZC along this handoff chain is moving fast.
|
||||
bool HasFastMovingApzc() const;
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> FindFirstScrollable(const ScrollWheelInput& aInput) const;
|
||||
|
||||
private:
|
||||
std::vector<nsRefPtr<AsyncPanZoomController>> mChain;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "APZCCallbackHelper.h"
|
||||
|
||||
#include "ContentHelper.h"
|
||||
#include "gfxPlatform.h" // For gfxPlatform::UseTiling
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
@@ -651,6 +652,39 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(
|
||||
nsIWidget* aWidget,
|
||||
const WidgetTouchEvent& aEvent,
|
||||
uint64_t aInputBlockId,
|
||||
const nsRefPtr<SetAllowedTouchBehaviorCallback>& aCallback)
|
||||
{
|
||||
nsTArray<TouchBehaviorFlags> flags;
|
||||
for (uint32_t i = 0; i < aEvent.touches.Length(); i++) {
|
||||
flags.AppendElement(widget::ContentHelper::GetAllowedTouchBehavior(aWidget, aEvent.touches[i]->mRefPoint));
|
||||
}
|
||||
aCallback->Run(aInputBlockId, flags);
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHelper::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIContent> targetContent = nsLayoutUtils::FindContentFor(aScrollId);
|
||||
if (!targetContent) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> ownerDoc = targetContent->OwnerDoc();
|
||||
if (!ownerDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(
|
||||
ownerDoc, targetContent,
|
||||
aEvent,
|
||||
true, true);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "FrameMetrics.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/layers/APZUtils.h"
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
|
||||
class nsIContent;
|
||||
@@ -29,6 +30,16 @@ protected:
|
||||
virtual ~SetTargetAPZCCallback() {}
|
||||
};
|
||||
|
||||
/* A base class for callbacks to be passed to
|
||||
* APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification. */
|
||||
struct SetAllowedTouchBehaviorCallback {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(SetAllowedTouchBehaviorCallback)
|
||||
virtual void Run(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) const = 0;
|
||||
protected:
|
||||
virtual ~SetAllowedTouchBehaviorCallback() {}
|
||||
};
|
||||
|
||||
/* This class contains some helper methods that facilitate implementing the
|
||||
GeckoContentController callback interface required by the AsyncPanZoomController.
|
||||
Since different platforms need to implement this interface in similar-but-
|
||||
@@ -163,6 +174,16 @@ public:
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
uint64_t aInputBlockId,
|
||||
const nsRefPtr<SetTargetAPZCCallback>& aCallback);
|
||||
|
||||
/* Figure out the allowed touch behaviors of each touch point in |aEvent|
|
||||
* and send that information to the provided callback. */
|
||||
static void SendSetAllowedTouchBehaviorNotification(nsIWidget* aWidget,
|
||||
const WidgetTouchEvent& aEvent,
|
||||
uint64_t aInputBlockId,
|
||||
const nsRefPtr<SetAllowedTouchBehaviorCallback>& aCallback);
|
||||
|
||||
/* Notify content of a mouse scroll testing event. */
|
||||
static void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent);
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
||||
@@ -214,4 +214,15 @@ ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
|
||||
mAPZEventState->ProcessAPZStateChange(GetDocument(), aGuid.mScrollId, aChange, aArg);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &ChromeProcessController::NotifyMozMouseScrollEvent, aScrollId, aEvent));
|
||||
return;
|
||||
}
|
||||
|
||||
APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
|
||||
APZStateChange aChange,
|
||||
int aArg) override;
|
||||
virtual void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
|
||||
const nsString& aEvent) override;
|
||||
private:
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsRefPtr<APZEventState> mAPZEventState;
|
||||
|
||||
@@ -347,8 +347,14 @@ private:
|
||||
// This affects whether events will be routed through APZ or not.
|
||||
DECL_GFX_PREF(Once, "mousewheel.system_scroll_override_on_root_content.enabled",
|
||||
MouseWheelHasScrollDeltaOverride, bool, false);
|
||||
DECL_GFX_PREF(Live, "mousewheel.transaction.ignoremovedelay",MouseWheelIgnoreMoveDelayMs, int32_t, (int32_t)100);
|
||||
DECL_GFX_PREF(Live, "mousewheel.transaction.timeout", MouseWheelTransactionTimeoutMs, int32_t, (int32_t)1500);
|
||||
|
||||
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "test.events.async.enabled", TestEventsAsyncEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "test.mousescroll", MouseScrollTestingEnabled, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
|
||||
DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false);
|
||||
DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false);
|
||||
|
||||
@@ -3850,7 +3850,7 @@ CheckTypeAnnotation(ModuleCompiler& m, ParseNode* coercionNode, AsmJSCoercion* c
|
||||
default:;
|
||||
}
|
||||
|
||||
return m.fail(coercionNode, "must be of the form +x, fround(x), simdType(x) or x|0");
|
||||
return m.fail(coercionNode, "must be of the form +x, x|0, fround(x), or a SIMD check(x)");
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -4474,9 +4474,12 @@ FoldMaskedArrayIndex(FunctionCompiler& f, ParseNode** indexExpr, int32_t* mask,
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int32_t NoMask = -1;
|
||||
|
||||
static bool
|
||||
CheckArrayAccess(FunctionCompiler& f, ParseNode* viewName, ParseNode* indexExpr,
|
||||
Scalar::Type* viewType, MDefinition** def, NeedsBoundsCheck* needsBoundsCheck)
|
||||
CheckArrayAccess(FunctionCompiler &f, ParseNode *viewName, ParseNode *indexExpr,
|
||||
Scalar::Type *viewType, MDefinition **def, NeedsBoundsCheck *needsBoundsCheck,
|
||||
int32_t *mask)
|
||||
{
|
||||
*needsBoundsCheck = NEEDS_BOUNDS_CHECK;
|
||||
|
||||
@@ -4502,6 +4505,7 @@ CheckArrayAccess(FunctionCompiler& f, ParseNode* viewName, ParseNode* indexExpr,
|
||||
f.m().minHeapLength(), f.m().module().maxHeapLength());
|
||||
}
|
||||
|
||||
*mask = NoMask;
|
||||
*needsBoundsCheck = NO_BOUNDS_CHECK;
|
||||
*def = f.constant(Int32Value(byteOffset), Type::Int);
|
||||
return true;
|
||||
@@ -4510,7 +4514,7 @@ CheckArrayAccess(FunctionCompiler& f, ParseNode* viewName, ParseNode* indexExpr,
|
||||
// Mask off the low bits to account for the clearing effect of a right shift
|
||||
// followed by the left shift implicit in the array access. E.g., H32[i>>2]
|
||||
// loses the low two bits.
|
||||
int32_t mask = ~(TypedArrayElemSize(*viewType) - 1);
|
||||
*mask = ~(TypedArrayElemSize(*viewType) - 1);
|
||||
|
||||
MDefinition* pointerDef;
|
||||
if (indexExpr->isKind(PNK_RSH)) {
|
||||
@@ -4527,7 +4531,7 @@ CheckArrayAccess(FunctionCompiler& f, ParseNode* viewName, ParseNode* indexExpr,
|
||||
ParseNode* pointerNode = BitwiseLeft(indexExpr);
|
||||
|
||||
if (pointerNode->isKind(PNK_BITAND))
|
||||
FoldMaskedArrayIndex(f, &pointerNode, &mask, needsBoundsCheck);
|
||||
FoldMaskedArrayIndex(f, &pointerNode, mask, needsBoundsCheck);
|
||||
|
||||
f.enterHeapExpression();
|
||||
|
||||
@@ -4538,53 +4542,63 @@ CheckArrayAccess(FunctionCompiler& f, ParseNode* viewName, ParseNode* indexExpr,
|
||||
f.leaveHeapExpression();
|
||||
|
||||
if (!pointerType.isIntish())
|
||||
return f.failf(indexExpr, "%s is not a subtype of int", pointerType.toChars());
|
||||
return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
|
||||
} else {
|
||||
// For legacy compatibility, accept Int8/Uint8 accesses with no shift.
|
||||
if (TypedArrayShift(*viewType) != 0)
|
||||
return f.fail(indexExpr, "index expression isn't shifted; must be an Int8/Uint8 access");
|
||||
|
||||
MOZ_ASSERT(mask == -1);
|
||||
MOZ_ASSERT(*mask == NoMask);
|
||||
bool folded = false;
|
||||
|
||||
if (indexExpr->isKind(PNK_BITAND))
|
||||
folded = FoldMaskedArrayIndex(f, &indexExpr, &mask, needsBoundsCheck);
|
||||
ParseNode *pointerNode = indexExpr;
|
||||
|
||||
if (pointerNode->isKind(PNK_BITAND))
|
||||
folded = FoldMaskedArrayIndex(f, &pointerNode, mask, needsBoundsCheck);
|
||||
|
||||
f.enterHeapExpression();
|
||||
|
||||
Type pointerType;
|
||||
if (!CheckExpr(f, indexExpr, &pointerDef, &pointerType))
|
||||
if (!CheckExpr(f, pointerNode, &pointerDef, &pointerType))
|
||||
return false;
|
||||
|
||||
f.leaveHeapExpression();
|
||||
|
||||
if (folded) {
|
||||
if (!pointerType.isIntish())
|
||||
return f.failf(indexExpr, "%s is not a subtype of intish", pointerType.toChars());
|
||||
return f.failf(pointerNode, "%s is not a subtype of intish", pointerType.toChars());
|
||||
} else {
|
||||
if (!pointerType.isInt())
|
||||
return f.failf(indexExpr, "%s is not a subtype of int", pointerType.toChars());
|
||||
return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
|
||||
}
|
||||
}
|
||||
|
||||
// Don't generate the mask op if there is no need for it which could happen for
|
||||
// a shift of zero.
|
||||
if (mask == -1)
|
||||
*def = pointerDef;
|
||||
else
|
||||
*def = f.bitwise<MBitAnd>(pointerDef, f.constant(Int32Value(mask), Type::Int));
|
||||
|
||||
*def = pointerDef;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
PrepareArrayIndex(FunctionCompiler &f, MDefinition **def, NeedsBoundsCheck needsBoundsCheck,
|
||||
int32_t mask)
|
||||
{
|
||||
// Don't generate the mask op if there is no need for it which could happen for
|
||||
// a shift of zero or a SIMD access.
|
||||
if (mask != NoMask)
|
||||
*def = f.bitwise<MBitAnd>(*def, f.constant(Int32Value(mask), Type::Int));
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckLoadArray(FunctionCompiler& f, ParseNode* elem, MDefinition** def, Type* type)
|
||||
CheckLoadArray(FunctionCompiler &f, ParseNode *elem, MDefinition **def, Type *type)
|
||||
{
|
||||
Scalar::Type viewType;
|
||||
MDefinition* pointerDef;
|
||||
MDefinition *pointerDef;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckArrayAccess(f, ElemBase(elem), ElemIndex(elem), &viewType, &pointerDef, &needsBoundsCheck))
|
||||
int32_t mask;
|
||||
if (!CheckArrayAccess(f, ElemBase(elem), ElemIndex(elem), &viewType, &pointerDef, &needsBoundsCheck, &mask))
|
||||
return false;
|
||||
|
||||
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
|
||||
|
||||
*def = f.loadHeap(viewType, pointerDef, needsBoundsCheck);
|
||||
*type = TypedArrayLoadType(viewType);
|
||||
return true;
|
||||
@@ -4641,7 +4655,8 @@ CheckStoreArray(FunctionCompiler& f, ParseNode* lhs, ParseNode* rhs, MDefinition
|
||||
Scalar::Type viewType;
|
||||
MDefinition* pointerDef;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), &viewType, &pointerDef, &needsBoundsCheck))
|
||||
int32_t mask;
|
||||
if (!CheckArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), &viewType, &pointerDef, &needsBoundsCheck, &mask))
|
||||
return false;
|
||||
|
||||
f.enterHeapExpression();
|
||||
@@ -4679,6 +4694,8 @@ CheckStoreArray(FunctionCompiler& f, ParseNode* lhs, ParseNode* rhs, MDefinition
|
||||
MOZ_CRASH("Unexpected view type");
|
||||
}
|
||||
|
||||
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
|
||||
|
||||
f.storeHeap(viewType, pointerDef, rhsDef, needsBoundsCheck);
|
||||
|
||||
*def = rhsDef;
|
||||
@@ -4893,11 +4910,11 @@ CheckMathMinMax(FunctionCompiler& f, ParseNode* callNode, MDefinition** def, boo
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSharedArrayAtomicAccess(FunctionCompiler& f, ParseNode* viewName, ParseNode* indexExpr,
|
||||
Scalar::Type* viewType, MDefinition** pointerDef,
|
||||
NeedsBoundsCheck* needsBoundsCheck)
|
||||
CheckSharedArrayAtomicAccess(FunctionCompiler &f, ParseNode *viewName, ParseNode *indexExpr,
|
||||
Scalar::Type *viewType, MDefinition** pointerDef,
|
||||
NeedsBoundsCheck *needsBoundsCheck, int32_t *mask)
|
||||
{
|
||||
if (!CheckArrayAccess(f, viewName, indexExpr, viewType, pointerDef, needsBoundsCheck))
|
||||
if (!CheckArrayAccess(f, viewName, indexExpr, viewType, pointerDef, needsBoundsCheck, mask))
|
||||
return false;
|
||||
|
||||
// Atomic accesses may be made on shared integer arrays only.
|
||||
@@ -4943,11 +4960,14 @@ CheckAtomicsLoad(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
|
||||
ParseNode* indexArg = NextNode(arrayArg);
|
||||
|
||||
Scalar::Type viewType;
|
||||
MDefinition* pointerDef;
|
||||
MDefinition *pointerDef;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck))
|
||||
int32_t mask;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck, &mask))
|
||||
return false;
|
||||
|
||||
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
|
||||
|
||||
*def = f.atomicLoadHeap(viewType, pointerDef, needsBoundsCheck);
|
||||
*type = Type::Signed;
|
||||
return true;
|
||||
@@ -4964,12 +4984,13 @@ CheckAtomicsStore(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
|
||||
ParseNode* valueArg = NextNode(indexArg);
|
||||
|
||||
Scalar::Type viewType;
|
||||
MDefinition* pointerDef;
|
||||
MDefinition *pointerDef;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck))
|
||||
int32_t mask;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck, &mask))
|
||||
return false;
|
||||
|
||||
MDefinition* rhsDef;
|
||||
MDefinition *rhsDef;
|
||||
Type rhsType;
|
||||
if (!CheckExpr(f, valueArg, &rhsDef, &rhsType))
|
||||
return false;
|
||||
@@ -4977,6 +4998,8 @@ CheckAtomicsStore(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
|
||||
if (!rhsType.isIntish())
|
||||
return f.failf(arrayArg, "%s is not a subtype of intish", rhsType.toChars());
|
||||
|
||||
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
|
||||
|
||||
f.atomicStoreHeap(viewType, pointerDef, rhsDef, needsBoundsCheck);
|
||||
|
||||
*def = rhsDef;
|
||||
@@ -4995,12 +5018,13 @@ CheckAtomicsBinop(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
|
||||
ParseNode* valueArg = NextNode(indexArg);
|
||||
|
||||
Scalar::Type viewType;
|
||||
MDefinition* pointerDef;
|
||||
MDefinition *pointerDef;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck))
|
||||
int32_t mask;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck, &mask))
|
||||
return false;
|
||||
|
||||
MDefinition* valueArgDef;
|
||||
MDefinition *valueArgDef;
|
||||
Type valueArgType;
|
||||
if (!CheckExpr(f, valueArg, &valueArgDef, &valueArgType))
|
||||
return false;
|
||||
@@ -5008,6 +5032,8 @@ CheckAtomicsBinop(FunctionCompiler& f, ParseNode* call, MDefinition** def, Type*
|
||||
if (!valueArgType.isIntish())
|
||||
return f.failf(valueArg, "%s is not a subtype of intish", valueArgType.toChars());
|
||||
|
||||
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
|
||||
|
||||
*def = f.atomicBinopHeap(op, viewType, pointerDef, valueArgDef, needsBoundsCheck);
|
||||
*type = Type::Signed;
|
||||
return true;
|
||||
@@ -5019,23 +5045,24 @@ CheckAtomicsCompareExchange(FunctionCompiler& f, ParseNode* call, MDefinition**
|
||||
if (CallArgListLength(call) != 4)
|
||||
return f.fail(call, "Atomics.compareExchange must be passed 4 arguments");
|
||||
|
||||
ParseNode* arrayArg = CallArgList(call);
|
||||
ParseNode* indexArg = NextNode(arrayArg);
|
||||
ParseNode* oldValueArg = NextNode(indexArg);
|
||||
ParseNode* newValueArg = NextNode(oldValueArg);
|
||||
ParseNode *arrayArg = CallArgList(call);
|
||||
ParseNode *indexArg = NextNode(arrayArg);
|
||||
ParseNode *oldValueArg = NextNode(indexArg);
|
||||
ParseNode *newValueArg = NextNode(oldValueArg);
|
||||
|
||||
Scalar::Type viewType;
|
||||
MDefinition* pointerDef;
|
||||
MDefinition *pointerDef;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck))
|
||||
int32_t mask;
|
||||
if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType, &pointerDef, &needsBoundsCheck, &mask))
|
||||
return false;
|
||||
|
||||
MDefinition* oldValueArgDef;
|
||||
MDefinition *oldValueArgDef;
|
||||
Type oldValueArgType;
|
||||
if (!CheckExpr(f, oldValueArg, &oldValueArgDef, &oldValueArgType))
|
||||
return false;
|
||||
|
||||
MDefinition* newValueArgDef;
|
||||
MDefinition *newValueArgDef;
|
||||
Type newValueArgType;
|
||||
if (!CheckExpr(f, newValueArg, &newValueArgDef, &newValueArgType))
|
||||
return false;
|
||||
@@ -5046,6 +5073,8 @@ CheckAtomicsCompareExchange(FunctionCompiler& f, ParseNode* call, MDefinition**
|
||||
if (!newValueArgType.isIntish())
|
||||
return f.failf(newValueArg, "%s is not a subtype of intish", newValueArgType.toChars());
|
||||
|
||||
PrepareArrayIndex(f, &pointerDef, needsBoundsCheck, mask);
|
||||
|
||||
*def = f.atomicCompareExchangeHeap(viewType, pointerDef, oldValueArgDef, newValueArgDef,
|
||||
needsBoundsCheck);
|
||||
*type = Type::Signed;
|
||||
@@ -5088,9 +5117,9 @@ CheckCallArgs(FunctionCompiler& f, ParseNode* callNode, CheckArgType checkArg,
|
||||
{
|
||||
f.startCallArgs(call);
|
||||
|
||||
ParseNode* argNode = CallArgList(callNode);
|
||||
ParseNode *argNode = CallArgList(callNode);
|
||||
for (unsigned i = 0; i < CallArgListLength(callNode); i++, argNode = NextNode(argNode)) {
|
||||
MDefinition* def;
|
||||
MDefinition *def;
|
||||
Type type;
|
||||
if (!CheckExpr(f, argNode, &def, &type))
|
||||
return false;
|
||||
@@ -5239,7 +5268,7 @@ CheckFuncPtrCall(FunctionCompiler& f, ParseNode* callNode, RetType retType, MDef
|
||||
if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
|
||||
return f.fail(maskNode, "function-pointer table index mask value must be a power of two minus 1");
|
||||
|
||||
MDefinition* indexDef;
|
||||
MDefinition *indexDef;
|
||||
Type indexType;
|
||||
if (!CheckExpr(f, indexNode, &indexDef, &indexType))
|
||||
return false;
|
||||
@@ -5252,7 +5281,7 @@ CheckFuncPtrCall(FunctionCompiler& f, ParseNode* callNode, RetType retType, MDef
|
||||
if (!CheckCallArgs(f, callNode, CheckIsVarType, &call))
|
||||
return false;
|
||||
|
||||
ModuleCompiler::FuncPtrTable* table;
|
||||
ModuleCompiler::FuncPtrTable *table;
|
||||
if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(call.sig()), mask, &table))
|
||||
return false;
|
||||
|
||||
@@ -5756,11 +5785,11 @@ CheckSimdShuffle(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType, MDe
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSimdLoadStoreArgs(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType,
|
||||
unsigned numElems, Scalar::Type* viewType, MDefinition** index,
|
||||
NeedsBoundsCheck* needsBoundsCheck)
|
||||
CheckSimdLoadStoreArgs(FunctionCompiler &f, ParseNode *call, AsmJSSimdType opType,
|
||||
Scalar::Type *viewType, MDefinition **index,
|
||||
NeedsBoundsCheck *needsBoundsCheck)
|
||||
{
|
||||
ParseNode* view = CallArgList(call);
|
||||
ParseNode *view = CallArgList(call);
|
||||
if (!view->isKind(PNK_NAME))
|
||||
return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument");
|
||||
|
||||
@@ -5810,19 +5839,21 @@ CheckSimdLoadStoreArgs(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opTyp
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSimdLoad(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType,
|
||||
unsigned numElems, MDefinition** def, Type* type)
|
||||
CheckSimdLoad(FunctionCompiler &f, ParseNode *call, AsmJSSimdType opType,
|
||||
unsigned numElems, MDefinition **def, Type *type)
|
||||
{
|
||||
unsigned numArgs = CallArgListLength(call);
|
||||
if (numArgs != 2)
|
||||
return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs);
|
||||
|
||||
Scalar::Type viewType;
|
||||
MDefinition* index;
|
||||
MDefinition *index;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckSimdLoadStoreArgs(f, call, opType, numElems, &viewType, &index, &needsBoundsCheck))
|
||||
if (!CheckSimdLoadStoreArgs(f, call, opType, &viewType, &index, &needsBoundsCheck))
|
||||
return false;
|
||||
|
||||
PrepareArrayIndex(f, &index, needsBoundsCheck, NoMask);
|
||||
|
||||
*def = f.loadSimdHeap(viewType, index, needsBoundsCheck, numElems);
|
||||
*type = opType;
|
||||
return true;
|
||||
@@ -5837,20 +5868,22 @@ CheckSimdStore(FunctionCompiler& f, ParseNode* call, AsmJSSimdType opType,
|
||||
return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs);
|
||||
|
||||
Scalar::Type viewType;
|
||||
MDefinition* index;
|
||||
MDefinition *index;
|
||||
NeedsBoundsCheck needsBoundsCheck;
|
||||
if (!CheckSimdLoadStoreArgs(f, call, opType, numElems, &viewType, &index, &needsBoundsCheck))
|
||||
if (!CheckSimdLoadStoreArgs(f, call, opType, &viewType, &index, &needsBoundsCheck))
|
||||
return false;
|
||||
|
||||
Type retType = opType;
|
||||
ParseNode* vecExpr = NextNode(NextNode(CallArgList(call)));
|
||||
MDefinition* vec;
|
||||
ParseNode *vecExpr = NextNode(NextNode(CallArgList(call)));
|
||||
MDefinition *vec;
|
||||
Type vecType;
|
||||
if (!CheckExpr(f, vecExpr, &vec, &vecType))
|
||||
return false;
|
||||
if (!(vecType <= retType))
|
||||
return f.failf(vecExpr, "%s is not a subtype of %s", vecType.toChars(), retType.toChars());
|
||||
|
||||
PrepareArrayIndex(f, &index, needsBoundsCheck, NoMask);
|
||||
|
||||
f.storeSimdHeap(viewType, index, vec, needsBoundsCheck, numElems);
|
||||
*def = vec;
|
||||
*type = vecType;
|
||||
@@ -6292,7 +6325,7 @@ CheckBitNot(FunctionCompiler& f, ParseNode* neg, MDefinition** def, Type* type)
|
||||
if (operand->isKind(PNK_BITNOT))
|
||||
return CheckCoerceToInt(f, operand, def, type);
|
||||
|
||||
MDefinition* operandDef;
|
||||
MDefinition *operandDef;
|
||||
Type operandType;
|
||||
if (!CheckExpr(f, operand, &operandDef, &operandType))
|
||||
return false;
|
||||
@@ -8213,7 +8246,7 @@ StackDecrementForCall(MacroAssembler& masm, uint32_t alignment, const VectorT& a
|
||||
// The ARM system ABI also includes d15 & s31 in the non volatile float registers.
|
||||
// Also exclude lr (a.k.a. r14) as we preserve it manually)
|
||||
static const RegisterSet NonVolatileRegs =
|
||||
RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask&
|
||||
RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask &
|
||||
~(uint32_t(1) << Registers::lr)),
|
||||
FloatRegisterSet(FloatRegisters::NonVolatileMask
|
||||
| (1ULL << FloatRegisters::d15)
|
||||
@@ -9015,7 +9048,7 @@ GenerateOnOutOfBoundsLabelExit(ModuleCompiler& m, Label* throwLabel)
|
||||
}
|
||||
|
||||
static const RegisterSet AllRegsExceptSP =
|
||||
RegisterSet(GeneralRegisterSet(Registers::AllMask&
|
||||
RegisterSet(GeneralRegisterSet(Registers::AllMask &
|
||||
~(uint32_t(1) << Registers::StackPointer)),
|
||||
FloatRegisterSet(FloatRegisters::AllDoubleMask));
|
||||
|
||||
|
||||
@@ -2396,6 +2396,23 @@ SetImmutablePrototype(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetLazyParsingEnabled(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (argc < 1) {
|
||||
JS_ReportError(cx, "setLazyParsingEnabled: need an argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arg = ToBoolean(args.get(0));
|
||||
JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(!arg);
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
JS_FN_HELP("gc", ::GC, 0, 0,
|
||||
"gc([obj] | 'compartment' [, 'shrinking'])",
|
||||
@@ -2766,6 +2783,10 @@ gc::ZealModeHelpText),
|
||||
" of internal error, or if the operation doesn't even make sense (for example,\n"
|
||||
" because the object is a revoked proxy)."),
|
||||
|
||||
JS_FN_HELP("setLazyParsingEnabled", SetLazyParsingEnabled, 1, 0,
|
||||
"setLazyParsingEnabled(bool)",
|
||||
" Enable or disable lazy parsing in the current compartment. The default is enabled."),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
|
||||
|
||||
@@ -142,8 +142,7 @@ CanLazilyParse(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
|
||||
static void
|
||||
MarkFunctionsWithinEvalScript(JSScript* script)
|
||||
{
|
||||
// Mark top level functions in an eval script as being within an eval and,
|
||||
// if applicable, inside a with statement.
|
||||
// Mark top level functions in an eval script as being within an eval.
|
||||
|
||||
if (!script->hasObjects())
|
||||
return;
|
||||
@@ -279,17 +278,14 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
|
||||
if (!script)
|
||||
return nullptr;
|
||||
|
||||
// We can specialize a bit for the given scope chain if that scope chain is the global object.
|
||||
JSObject* globalScope =
|
||||
scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : nullptr;
|
||||
MOZ_ASSERT_IF(globalScope, globalScope->isNative());
|
||||
MOZ_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
|
||||
|
||||
bool insideNonGlobalEval =
|
||||
evalStaticScope && evalStaticScope->enclosingScopeForStaticScopeIter();
|
||||
BytecodeEmitter::EmitterMode emitterMode =
|
||||
options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
|
||||
BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script,
|
||||
/* lazyScript = */ js::NullPtr(), options.forEval,
|
||||
evalCaller, evalStaticScope, !!globalScope, options.lineno, emitterMode);
|
||||
evalCaller, evalStaticScope, insideNonGlobalEval,
|
||||
options.lineno, emitterMode);
|
||||
if (!bce.init())
|
||||
return nullptr;
|
||||
|
||||
@@ -363,7 +359,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate the maximum block scope depth, so that EmitTree can assert
|
||||
// Accumulate the maximum block scope depth, so that emitTree can assert
|
||||
// when emitting JSOP_GETLOCAL that the local is indeed within the fixed
|
||||
// part of the stack frame.
|
||||
script->bindings.updateNumBlockScoped(pc->blockScopeDepth);
|
||||
@@ -382,7 +378,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
|
||||
if (!bce.updateLocalsToFrameSlots())
|
||||
return nullptr;
|
||||
|
||||
if (!EmitTree(cx, &bce, pn))
|
||||
if (!bce.emitTree(pn))
|
||||
return nullptr;
|
||||
|
||||
parser.handler.freeTree(pn);
|
||||
@@ -417,7 +413,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
|
||||
* Nowadays the threaded interpreter needs a last return instruction, so we
|
||||
* do have to emit that here.
|
||||
*/
|
||||
if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
|
||||
if (!bce.emit1(JSOP_RETRVAL))
|
||||
return nullptr;
|
||||
|
||||
// Global/eval script bindings are always empty (all names are added to the
|
||||
@@ -503,10 +499,17 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
if (lazy->hasBeenCloned())
|
||||
script->setHasBeenCloned();
|
||||
|
||||
/*
|
||||
* We just pass false for insideNonGlobalEval and insideEval, because we
|
||||
* don't actually know whether we are or not. The only consumer of those
|
||||
* booleans is TryConvertFreeName, and it has special machinery to avoid
|
||||
* doing bad things when a lazy function is inside eval.
|
||||
*/
|
||||
MOZ_ASSERT(!options.forEval);
|
||||
BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
|
||||
options.forEval, /* evalCaller = */ js::NullPtr(),
|
||||
/* insideEval = */ false, /* evalCaller = */ js::NullPtr(),
|
||||
/* evalStaticScope = */ js::NullPtr(),
|
||||
/* hasGlobalScope = */ true, options.lineno,
|
||||
/* insideNonGlobalEval = */ false, options.lineno,
|
||||
BytecodeEmitter::LazyFunction);
|
||||
if (!bce.init())
|
||||
return false;
|
||||
@@ -517,11 +520,11 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
// Compile a JS function body, which might appear as the value of an event
|
||||
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
|
||||
static bool
|
||||
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
|
||||
const AutoNameVector& formals, SourceBufferHolder& srcBuf,
|
||||
HandleObject enclosingScope, GeneratorKind generatorKind)
|
||||
CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
|
||||
const AutoNameVector &formals, SourceBufferHolder &srcBuf,
|
||||
HandleObject enclosingStaticScope, GeneratorKind generatorKind)
|
||||
{
|
||||
js::TraceLoggerThread* logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
js::TraceLoggerThread *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileFunction);
|
||||
@@ -620,7 +623,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp
|
||||
if (fn->pn_funbox->function()->isInterpreted()) {
|
||||
MOZ_ASSERT(fun == fn->pn_funbox->function());
|
||||
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingScope, false, options,
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingStaticScope, false, options,
|
||||
/* staticLevel = */ 0, sourceObject,
|
||||
/* sourceStart = */ 0, srcBuf.length()));
|
||||
if (!script)
|
||||
@@ -628,19 +631,11 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp
|
||||
|
||||
script->bindings = fn->pn_funbox->bindings;
|
||||
|
||||
/*
|
||||
* The reason for checking fun->environment() below is that certain
|
||||
* consumers of JS::CompileFunction, namely
|
||||
* EventListenerManager::CompileEventHandlerInternal, passes in a
|
||||
* nullptr environment. This compiled function is never used, but
|
||||
* instead is cloned immediately onto the right scope chain.
|
||||
*/
|
||||
BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script,
|
||||
/* lazyScript = */ js::NullPtr(), /* insideEval = */ false,
|
||||
/* evalCaller = */ js::NullPtr(),
|
||||
/* evalStaticScope = */ js::NullPtr(),
|
||||
fun->environment() && fun->environment()->is<GlobalObject>(),
|
||||
options.lineno);
|
||||
/* insideNonGlobalEval = */ false, options.lineno);
|
||||
if (!funbce.init())
|
||||
return false;
|
||||
|
||||
|
||||
+1458
-1564
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,8 @@
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "frontend/ParseMaps.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/SourceNotes.h"
|
||||
|
||||
namespace js {
|
||||
@@ -88,17 +90,31 @@ struct StmtInfoBCE;
|
||||
typedef Vector<jsbytecode, 0> BytecodeVector;
|
||||
typedef Vector<jssrcnote, 0> SrcNotesVector;
|
||||
|
||||
// This enum tells EmitVariables and the destructuring functions how emit the
|
||||
// given Parser::variables parse tree. In the base case, DefineVars, the caller
|
||||
// only wants variables to be defined in the prologue (if necessary). For
|
||||
// PushInitialValues, variable initializer expressions are evaluated and left
|
||||
// on the stack. For InitializeVars, the initializer expressions values are
|
||||
// assigned (to local variables) and popped.
|
||||
enum VarEmitOption {
|
||||
DefineVars = 0,
|
||||
PushInitialValues = 1,
|
||||
InitializeVars = 2
|
||||
};
|
||||
|
||||
struct BytecodeEmitter
|
||||
{
|
||||
typedef StmtInfoBCE StmtInfo;
|
||||
|
||||
SharedContext* const sc; /* context shared between parsing and bytecode generation */
|
||||
SharedContext *const sc; /* context shared between parsing and bytecode generation */
|
||||
|
||||
BytecodeEmitter* const parent; /* enclosing function or global context */
|
||||
ExclusiveContext *const cx;
|
||||
|
||||
BytecodeEmitter *const parent; /* enclosing function or global context */
|
||||
|
||||
Rooted<JSScript*> script; /* the JSScript we're ultimately producing */
|
||||
|
||||
Rooted<LazyScript*> lazyScript; /* the lazy script if mode is LazyFunction,
|
||||
Rooted<LazyScript *> lazyScript; /* the lazy script if mode is LazyFunction,
|
||||
nullptr otherwise. */
|
||||
|
||||
struct EmitSection {
|
||||
@@ -109,7 +125,7 @@ struct BytecodeEmitter
|
||||
uint32_t lastColumn; /* zero-based column index on currentLine of
|
||||
last SRC_COLSPAN-annotated opcode */
|
||||
|
||||
EmitSection(ExclusiveContext* cx, uint32_t lineNum)
|
||||
EmitSection(ExclusiveContext *cx, uint32_t lineNum)
|
||||
: code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0)
|
||||
{}
|
||||
};
|
||||
@@ -122,8 +138,8 @@ struct BytecodeEmitter
|
||||
Handle<StaticEvalObject*> evalStaticScope;
|
||||
/* compile time scope for eval; does not imply stmt stack */
|
||||
|
||||
StmtInfoBCE* topStmt; /* top of statement info stack */
|
||||
StmtInfoBCE* topScopeStmt; /* top lexical scope statement */
|
||||
StmtInfoBCE *topStmt; /* top of statement info stack */
|
||||
StmtInfoBCE *topScopeStmt; /* top lexical scope statement */
|
||||
Rooted<NestedScopeObject*> staticScope;
|
||||
/* compile time scope chain */
|
||||
|
||||
@@ -142,7 +158,7 @@ struct BytecodeEmitter
|
||||
|
||||
uint32_t arrayCompDepth; /* stack depth of array in comprehension */
|
||||
|
||||
unsigned emitLevel; /* js::frontend::EmitTree recursion level */
|
||||
unsigned emitLevel; /* emitTree recursion level */
|
||||
|
||||
CGConstList constList; /* constants to be included with the script */
|
||||
|
||||
@@ -174,8 +190,8 @@ struct BytecodeEmitter
|
||||
bool insideEval:1; /* True if compiling an eval-expression or a function
|
||||
nested inside an eval. */
|
||||
|
||||
const bool hasGlobalScope:1; /* frontend::CompileScript's scope chain is the
|
||||
global object */
|
||||
const bool insideNonGlobalEval:1; /* True if this is a direct eval
|
||||
call in some non-global scope. */
|
||||
|
||||
enum EmitterMode {
|
||||
Normal,
|
||||
@@ -202,10 +218,10 @@ struct BytecodeEmitter
|
||||
* tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
|
||||
* destruction.
|
||||
*/
|
||||
BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc,
|
||||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
|
||||
HandleScript script, Handle<LazyScript *> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
Handle<StaticEvalObject*> evalStaticScope, bool hasGlobalScope,
|
||||
Handle<StaticEvalObject *> evalStaticScope, bool insideNonGlobalEval,
|
||||
uint32_t lineNum, EmitterMode emitterMode = Normal);
|
||||
bool init();
|
||||
bool updateLocalsToFrameSlots();
|
||||
@@ -250,45 +266,232 @@ struct BytecodeEmitter
|
||||
unsigned lastColumn() const { return current->lastColumn; }
|
||||
|
||||
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...);
|
||||
bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...);
|
||||
|
||||
bool setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset);
|
||||
|
||||
void setJumpOffsetAt(ptrdiff_t off);
|
||||
|
||||
// Emit code for the tree rooted at pn.
|
||||
bool emitTree(ParseNode *pn);
|
||||
|
||||
// If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
|
||||
// reserve a type set to store its result.
|
||||
void checkTypeSet(JSOp op);
|
||||
|
||||
void updateDepth(ptrdiff_t target);
|
||||
bool updateLineNumberNotes(uint32_t offset);
|
||||
bool updateSourceCoordNotes(uint32_t offset);
|
||||
|
||||
bool bindNameToSlot(ParseNode *pn);
|
||||
|
||||
void popStatement();
|
||||
void pushStatement(StmtInfoBCE *stmt, StmtType type, ptrdiff_t top);
|
||||
void pushStatementInner(StmtInfoBCE *stmt, StmtType type, ptrdiff_t top);
|
||||
|
||||
bool flushPops(int *npops);
|
||||
|
||||
ptrdiff_t emitCheck(ptrdiff_t delta);
|
||||
|
||||
// Emit one bytecode.
|
||||
bool emit1(JSOp op);
|
||||
|
||||
// Emit two bytecodes, an opcode (op) with a byte of immediate operand
|
||||
// (op1).
|
||||
bool emit2(JSOp op, jsbytecode op1);
|
||||
|
||||
// Emit three bytecodes, an opcode with two bytes of immediate operands.
|
||||
bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
|
||||
|
||||
// Dup the var in operand stack slot "slot". The first item on the operand
|
||||
// stack is one slot past the last fixed slot. The last (most recent) item is
|
||||
// slot bce->stackDepth - 1.
|
||||
//
|
||||
// The instruction that is written (JSOP_DUPAT) switches the depth around so
|
||||
// that it is addressed from the sp instead of from the fp. This is useful when
|
||||
// you don't know the size of the fixed stack segment (nfixed), as is the case
|
||||
// when compiling scripts (because each statement is parsed and compiled
|
||||
// separately, but they all together form one script with one fixed stack
|
||||
// frame).
|
||||
bool emitDupAt(unsigned slot);
|
||||
|
||||
// Emit a bytecode followed by an uint16 immediate operand stored in
|
||||
// big-endian order.
|
||||
bool emitUint16Operand(JSOp op, uint32_t i);
|
||||
|
||||
// Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
|
||||
ptrdiff_t emitN(JSOp op, size_t extra);
|
||||
|
||||
bool emitNumberOp(double dval);
|
||||
|
||||
ptrdiff_t emitJump(JSOp op, ptrdiff_t off);
|
||||
bool emitCall(JSOp op, uint16_t argc, ParseNode *pn = nullptr);
|
||||
|
||||
bool emitLoopHead(ParseNode *nextpn);
|
||||
bool emitLoopEntry(ParseNode *nextpn);
|
||||
|
||||
// Emit a backpatch op with offset pointing to the previous jump of this
|
||||
// type, so that we can walk back up the chain fixing up the op and jump
|
||||
// offset.
|
||||
bool emitBackPatchOp(ptrdiff_t *lastp);
|
||||
void backPatch(ptrdiff_t last, jsbytecode *target, jsbytecode op);
|
||||
|
||||
ptrdiff_t emitGoto(StmtInfoBCE *toStmt, ptrdiff_t *lastp, SrcNoteType noteType = SRC_NULL);
|
||||
|
||||
bool emitIndex32(JSOp op, uint32_t index);
|
||||
bool emitIndexOp(JSOp op, uint32_t index);
|
||||
|
||||
bool emitAtomOp(JSAtom *atom, JSOp op);
|
||||
bool emitAtomOp(ParseNode *pn, JSOp op);
|
||||
|
||||
bool emitArray(ParseNode *pn, uint32_t count);
|
||||
bool emitArrayComp(ParseNode *pn);
|
||||
|
||||
bool emitInternedObjectOp(uint32_t index, JSOp op);
|
||||
bool emitObjectOp(ObjectBox *objbox, JSOp op);
|
||||
bool emitObjectPairOp(ObjectBox *objbox1, ObjectBox *objbox2, JSOp op);
|
||||
bool emitRegExp(uint32_t index);
|
||||
|
||||
MOZ_NEVER_INLINE bool emitObject(ParseNode *pn);
|
||||
|
||||
bool emitPropertyList(ParseNode *pn, MutableHandlePlainObject objp, PropListType type);
|
||||
|
||||
// To catch accidental misuse, emitUint16Operand/emit3 assert that they are
|
||||
// not used to unconditionally emit JSOP_GETLOCAL. Variable access should
|
||||
// instead be emitted using EmitVarOp. In special cases, when the caller
|
||||
// definitely knows that a given local slot is unaliased, this function may be
|
||||
// used as a non-asserting version of emitUint16Operand.
|
||||
bool emitLocalOp(JSOp op, uint32_t slot);
|
||||
|
||||
bool emitScopeCoordOp(JSOp op, ScopeCoordinate sc);
|
||||
bool emitAliasedVarOp(JSOp op, ParseNode *pn);
|
||||
bool emitAliasedVarOp(JSOp op, ScopeCoordinate sc, MaybeCheckLexical checkLexical);
|
||||
bool emitUnaliasedVarOp(JSOp op, uint32_t slot, MaybeCheckLexical checkLexical);
|
||||
|
||||
bool emitVarOp(ParseNode *pn, JSOp op);
|
||||
bool emitVarIncDec(ParseNode *pn);
|
||||
|
||||
bool emitNameOp(ParseNode *pn, bool callContext);
|
||||
bool emitNameIncDec(ParseNode *pn);
|
||||
|
||||
bool maybeEmitVarDecl(JSOp prologOp, ParseNode *pn, jsatomid *result);
|
||||
bool emitVariables(ParseNode *pn, VarEmitOption emitOption, bool isLetExpr = false);
|
||||
|
||||
bool emitNewInit(JSProtoKey key);
|
||||
bool emitSingletonInitialiser(ParseNode *pn);
|
||||
|
||||
bool emitPrepareIteratorResult();
|
||||
bool emitFinishIteratorResult(bool done);
|
||||
|
||||
bool emitYield(ParseNode *pn);
|
||||
bool emitYieldOp(JSOp op);
|
||||
bool emitYieldStar(ParseNode *iter, ParseNode *gen);
|
||||
|
||||
bool emitPropLHS(ParseNode *pn, JSOp op);
|
||||
bool emitPropOp(ParseNode *pn, JSOp op);
|
||||
bool emitPropIncDec(ParseNode *pn);
|
||||
|
||||
// Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
|
||||
// opcode onto the stack in the right order. In the case of SETELEM, the
|
||||
// value to be assigned must already be pushed.
|
||||
bool emitElemOperands(ParseNode *pn, JSOp op);
|
||||
|
||||
bool emitElemOpBase(JSOp op);
|
||||
bool emitElemOp(ParseNode *pn, JSOp op);
|
||||
bool emitElemIncDec(ParseNode *pn);
|
||||
|
||||
bool emitCatch(ParseNode *pn);
|
||||
bool emitIf(ParseNode *pn);
|
||||
bool emitWith(ParseNode *pn);
|
||||
|
||||
MOZ_NEVER_INLINE bool emitSwitch(ParseNode *pn);
|
||||
MOZ_NEVER_INLINE bool emitTry(ParseNode *pn);
|
||||
|
||||
// EmitDestructuringLHS assumes the to-be-destructured value has been pushed on
|
||||
// the stack and emits code to destructure a single lhs expression (either a
|
||||
// name or a compound []/{} expression).
|
||||
//
|
||||
// If emitOption is InitializeVars, the to-be-destructured value is assigned to
|
||||
// locals and ultimately the initial slot is popped (-1 total depth change).
|
||||
//
|
||||
// If emitOption is PushInitialValues, the to-be-destructured value is replaced
|
||||
// with the initial values of the N (where 0 <= N) variables assigned in the
|
||||
// lhs expression. (Same post-condition as EmitDestructuringOpsHelper)
|
||||
bool emitDestructuringLHS(ParseNode *target, VarEmitOption emitOption);
|
||||
|
||||
// emitIterator expects the iterable to already be on the stack.
|
||||
// It will replace that stack value with the corresponding iterator
|
||||
bool emitIterator();
|
||||
|
||||
// Pops iterator from the top of the stack. Pushes the result of |.next()|
|
||||
// onto the stack.
|
||||
bool emitIteratorNext(ParseNode *pn);
|
||||
|
||||
// Check if the value on top of the stack is "undefined". If so, replace
|
||||
// that value on the stack with the value defined by |defaultExpr|.
|
||||
bool emitDefault(ParseNode *defaultExpr);
|
||||
|
||||
bool emitCallSiteObject(ParseNode *pn);
|
||||
bool emitTemplateString(ParseNode *pn);
|
||||
bool emitAssignment(ParseNode *lhs, JSOp op, ParseNode *rhs);
|
||||
|
||||
bool emitReturn(ParseNode *pn);
|
||||
bool emitStatement(ParseNode *pn);
|
||||
bool emitStatementList(ParseNode *pn, ptrdiff_t top);
|
||||
|
||||
bool emitDelete(ParseNode *pn);
|
||||
bool emitLogical(ParseNode *pn);
|
||||
bool emitUnary(ParseNode *pn);
|
||||
|
||||
MOZ_NEVER_INLINE bool emitIncOrDec(ParseNode *pn);
|
||||
|
||||
bool emitConditionalExpression(ConditionalExpression &conditional);
|
||||
|
||||
bool emitCallOrNew(ParseNode *pn);
|
||||
bool emitSelfHostedCallFunction(ParseNode *pn);
|
||||
bool emitSelfHostedResumeGenerator(ParseNode *pn);
|
||||
bool emitSelfHostedForceInterpreter(ParseNode *pn);
|
||||
|
||||
bool emitDo(ParseNode *pn);
|
||||
bool emitFor(ParseNode *pn, ptrdiff_t top);
|
||||
bool emitForIn(ParseNode *pn, ptrdiff_t top);
|
||||
bool emitForInOrOfVariables(ParseNode *pn, bool *letDecl);
|
||||
bool emitNormalFor(ParseNode *pn, ptrdiff_t top);
|
||||
bool emitWhile(ParseNode *pn, ptrdiff_t top);
|
||||
|
||||
bool emitBreak(PropertyName *label);
|
||||
bool emitContinue(PropertyName *label);
|
||||
|
||||
bool emitDefaults(ParseNode *pn);
|
||||
bool emitLexicalInitialization(ParseNode *pn, JSOp globalDefOp);
|
||||
|
||||
// emitSpread expects the current index (I) of the array, the array itself
|
||||
// and the iterator to be on the stack in that order (iterator on the bottom).
|
||||
// It will pop the iterator and I, then iterate over the iterator by calling
|
||||
// |.next()| and put the results into the I-th element of array with
|
||||
// incrementing I, then push the result I (it will be original I +
|
||||
// iteration count). The stack after iteration will look like |ARRAY INDEX|.
|
||||
bool emitSpread();
|
||||
|
||||
// If type is STMT_FOR_OF_LOOP, emit bytecode for a for-of loop.
|
||||
// pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
|
||||
//
|
||||
// If type is STMT_SPREAD, emit bytecode for spread operator.
|
||||
// pn should be nullptr.
|
||||
//
|
||||
// Please refer the comment above emitSpread for additional information about
|
||||
// stack convention.
|
||||
bool emitForOf(StmtType type, ParseNode *pn, ptrdiff_t top);
|
||||
|
||||
bool emitClass(ParseNode *pn);
|
||||
};
|
||||
|
||||
/*
|
||||
* Emit one bytecode.
|
||||
*/
|
||||
ptrdiff_t
|
||||
Emit1(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp op);
|
||||
|
||||
/*
|
||||
* Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
|
||||
*/
|
||||
ptrdiff_t
|
||||
Emit2(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp op, jsbytecode op1);
|
||||
|
||||
/*
|
||||
* Emit three bytecodes, an opcode with two bytes of immediate operands.
|
||||
*/
|
||||
ptrdiff_t
|
||||
Emit3(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp op, jsbytecode op1, jsbytecode op2);
|
||||
|
||||
/*
|
||||
* Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
|
||||
*/
|
||||
ptrdiff_t
|
||||
EmitN(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp op, size_t extra);
|
||||
|
||||
/*
|
||||
* Emit code into bce for the tree rooted at pn.
|
||||
*/
|
||||
bool
|
||||
EmitTree(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn);
|
||||
|
||||
/*
|
||||
* Emit function code using bce for the tree rooted at body.
|
||||
*/
|
||||
bool
|
||||
EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* body);
|
||||
EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body);
|
||||
|
||||
/*
|
||||
* Append a new source note of the given type (and therefore size) to bce's
|
||||
@@ -297,24 +500,24 @@ EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* body);
|
||||
* memory.
|
||||
*/
|
||||
int
|
||||
NewSrcNote(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType type);
|
||||
NewSrcNote(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type);
|
||||
|
||||
int
|
||||
NewSrcNote2(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType type, ptrdiff_t offset);
|
||||
NewSrcNote2(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset);
|
||||
|
||||
int
|
||||
NewSrcNote3(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType type, ptrdiff_t offset1,
|
||||
NewSrcNote3(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
|
||||
ptrdiff_t offset2);
|
||||
|
||||
/* NB: this function can add at most one extra extended delta note. */
|
||||
bool
|
||||
AddToSrcNoteDelta(ExclusiveContext* cx, BytecodeEmitter* bce, jssrcnote* sn, ptrdiff_t delta);
|
||||
AddToSrcNoteDelta(ExclusiveContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta);
|
||||
|
||||
bool
|
||||
FinishTakingSrcNotes(ExclusiveContext* cx, BytecodeEmitter* bce, uint32_t* out);
|
||||
FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t *out);
|
||||
|
||||
void
|
||||
CopySrcNotes(BytecodeEmitter* bce, jssrcnote* destination, uint32_t nsrcnotes);
|
||||
CopySrcNotes(BytecodeEmitter *bce, jssrcnote *destination, uint32_t nsrcnotes);
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
@@ -25,6 +25,7 @@ var f = asmLink(code, this, null, BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
assertEq(f(i), i);
|
||||
|
||||
// For legacy compatibility, test Int8/Uint8 accesses with no shift.
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i,j) {i=i|0;j=j|0; u8[i+20 & 0xffff] = j } return f');
|
||||
var f = asmLink(code, this, null, BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
@@ -37,6 +38,18 @@ var f = asmLink(code, this, null, BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
assertEq(f(i), i);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i,j) {i=i|0;j=j|0; u8[(i+20 & 0xffff)>>0] = j } return f');
|
||||
var f = asmLink(code, this, null, BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
f(i, i);
|
||||
var u8 = new Uint8Array(BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
assertEq(u8[i+20], i);
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; return u8[(i+20 & 0xffff)>>0]|0 } return f');
|
||||
var f = asmLink(code, this, null, BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
assertEq(f(i), i);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i,j,k) {i=i|0;j=j|0;k=k|0; i32[(i + (j<<2) & 0xffff) >> 2] = k } return f');
|
||||
var f = asmLink(code, this, null, BUF_64KB);
|
||||
for (var i = 0; i < 100; i++)
|
||||
|
||||
@@ -173,10 +173,15 @@ assertEq(f(1), 0xfffeeee);
|
||||
var f = asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; return i32[((i<<2)+4)>>2]|0 }; return f'), this, null, i32.buffer);
|
||||
assertEq(f(0), 0xfffeeee);
|
||||
|
||||
// For legacy compatibility, test Int8/Uint8 accesses with no shift.
|
||||
asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { u8[7&0xffff] = 41 } return f'), this, null, BUF_64KB)();
|
||||
assertEq(new Uint8Array(BUF_64KB)[7], 41);
|
||||
asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { i8[7&0xffff] = -41 } return f'), this, null, BUF_64KB)();
|
||||
assertEq(new Int8Array(BUF_64KB)[7], -41);
|
||||
asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { u8[(7&0xffff)>>0] = 41 } return f'), this, null, BUF_64KB)();
|
||||
assertEq(new Uint8Array(BUF_64KB)[7], 41);
|
||||
asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { i8[(7&0xffff)>>0] = -41 } return f'), this, null, BUF_64KB)();
|
||||
assertEq(new Int8Array(BUF_64KB)[7], -41);
|
||||
asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { u16[(6&0xffff)>>1] = 0xabc } return f'), this, null, BUF_64KB)();
|
||||
assertEq(new Uint16Array(BUF_64KB)[3], 0xabc);
|
||||
asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { i16[(6&0xffff)>>1] = -0xabc } return f'), this, null, BUF_64KB)();
|
||||
@@ -197,7 +202,9 @@ new Float64Array(BUF_64KB)[1] = 1.3;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return +f64[(8&0xffff)>>3] } return f'), this, null, BUF_64KB)(), 1.3);
|
||||
|
||||
asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; u8[255]; u8[i] } return f');
|
||||
// For legacy compatibility, test Int8/Uint8 accesses with no shift.
|
||||
asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; u8[i&0xff]; u8[255] } return f');
|
||||
asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; u8[(i&0xff)>>0]; u8[255] } return f');
|
||||
asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; u32[63]; u32[i>>2] } return f');
|
||||
asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; u32[i>>2]; u32[63] } return f');
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
var x = "wrong";
|
||||
var t = {x: "x"};
|
||||
var hits = 0;
|
||||
var p = new Proxy(t, {
|
||||
has(t, id) {
|
||||
var found = id in t;
|
||||
if (++hits == 2)
|
||||
delete t[id];
|
||||
return found;
|
||||
},
|
||||
get(t, id) { return t[id]; }
|
||||
});
|
||||
evaluate(`function testFunc() {
|
||||
x += " x";
|
||||
}`, { compileAndGo: false });
|
||||
|
||||
var cloneFunc = clone(testFunc, p);
|
||||
cloneFunc();
|
||||
assertEq(hits, 2);
|
||||
assertEq(t.x, "undefined x");
|
||||
@@ -12,5 +12,8 @@ var p = new Proxy(t, {
|
||||
});
|
||||
with (p)
|
||||
x += " x";
|
||||
// If you change this testcase (e.g. because we fix the number of
|
||||
// has() calls we end up making to match spec better), don't forget to
|
||||
// update bug1106982-2.js too. See also bug 1145641.
|
||||
assertEq(hits, 2);
|
||||
assertEq(t.x, "undefined x");
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
function bytecode(f) {
|
||||
if (typeof disassemble !== "function")
|
||||
return "unavailable";
|
||||
var d = disassemble(f);
|
||||
return d.slice(d.indexOf("main:"), d.indexOf("\n\n"));
|
||||
}
|
||||
|
||||
function hasGname(f, v, hasIt = true) {
|
||||
// Do a try-catch that prints the full stack, so we can tell
|
||||
// _which_ part of this test failed.
|
||||
try {
|
||||
var b = bytecode(f);
|
||||
if (b != "unavailable") {
|
||||
assertEq(b.contains(`getgname "${v}"`), hasIt);
|
||||
assertEq(b.contains(`getname "${v}"`), !hasIt);
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.stack);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var x = "outer";
|
||||
|
||||
setLazyParsingEnabled(false);
|
||||
{
|
||||
let x = "inner";
|
||||
eval("function g() { assertEq(x, 'inner');} g()");
|
||||
eval("function g2() { (function nest() { assertEq(x, 'inner'); })(); } g2()");
|
||||
}
|
||||
eval(`
|
||||
function g3() {
|
||||
assertEq(x, 'outer');
|
||||
}
|
||||
g3();
|
||||
hasGname(g3, 'x');
|
||||
`);
|
||||
eval(`
|
||||
function g4() {
|
||||
function nest() { assertEq(x, 'outer'); }
|
||||
nest();
|
||||
return nest;
|
||||
}
|
||||
hasGname(g4(), 'x');
|
||||
`);
|
||||
setLazyParsingEnabled(true);
|
||||
|
||||
{
|
||||
let x = "inner";
|
||||
eval("function h() { assertEq(x, 'inner');} h()");
|
||||
eval("function h2() { (function nest() { assertEq(x, 'inner'); })(); } h2()");
|
||||
}
|
||||
// It sure would be nice if we could run the h3/h4 tests below, but it turns out
|
||||
// that lazy functions and eval don't play together all that well. See bug
|
||||
// 1146080. For now, assert we have no gname, so people will notice if they
|
||||
// accidentally fix it and adjust this test accordingly.
|
||||
eval(`
|
||||
function h3() {
|
||||
assertEq(x, 'outer');
|
||||
}
|
||||
h3();
|
||||
hasGname(h3, 'x', false);
|
||||
`);
|
||||
eval(`
|
||||
function h4() {
|
||||
function nest() { assertEq(x, 'outer'); }
|
||||
nest();
|
||||
return nest;
|
||||
}
|
||||
hasGname(h4(), 'x', false);
|
||||
`);
|
||||
|
||||
setLazyParsingEnabled(false);
|
||||
with ({}) {
|
||||
let x = "inner";
|
||||
eval("function i() { assertEq(x, 'inner');} i()");
|
||||
eval("function i2() { (function nest() { assertEq(x, 'inner'); })(); } i2()");
|
||||
}
|
||||
setLazyParsingEnabled(true);
|
||||
|
||||
with ({}) {
|
||||
let x = "inner";
|
||||
eval("function j() { assertEq(x, 'inner');} j()");
|
||||
eval("function j2() { (function nest() { assertEq(x, 'inner'); })(); } j2()");
|
||||
}
|
||||
|
||||
setLazyParsingEnabled(false);
|
||||
(function () {
|
||||
var x = "inner";
|
||||
eval("function k() { assertEq(x, 'inner');} k()");
|
||||
eval("function k2() { (function nest() { assertEq(x, 'inner'); })(); } k2()");
|
||||
})();
|
||||
setLazyParsingEnabled(true);
|
||||
|
||||
(function () {
|
||||
let x = "inner";
|
||||
eval("function l() { assertEq(x, 'inner');} l()");
|
||||
eval("function l2() { (function nest() { assertEq(x, 'inner'); })(); } l2()");
|
||||
})();
|
||||
|
||||
var y1 = 5;
|
||||
eval(`
|
||||
'use strict';
|
||||
var y1 = 6;
|
||||
assertEq(y1, 6);
|
||||
(function() { assertEq(y1, 6); })()
|
||||
`);
|
||||
assertEq(y1, 5);
|
||||
|
||||
eval(`
|
||||
'use strict';
|
||||
var y2 = 6;
|
||||
assertEq(y2, 6);
|
||||
(function() { assertEq(y2, 6); })()
|
||||
`);
|
||||
|
||||
setLazyParsingEnabled(false);
|
||||
|
||||
var y3 = 5;
|
||||
eval(`
|
||||
'use strict';
|
||||
var y3 = 6;
|
||||
assertEq(y3, 6);
|
||||
(function() { assertEq(y3, 6); })()
|
||||
`);
|
||||
assertEq(y3, 5);
|
||||
|
||||
eval(`
|
||||
'use strict';
|
||||
var y4 = 6;
|
||||
assertEq(y4, 6);
|
||||
(function() { assertEq(y4, 6); })()
|
||||
`);
|
||||
|
||||
setLazyParsingEnabled(true);
|
||||
@@ -0,0 +1,49 @@
|
||||
function bytecode(f) {
|
||||
if (typeof disassemble !== "function")
|
||||
return "unavailable";
|
||||
var d = disassemble(f);
|
||||
return d.slice(d.indexOf("main:"), d.indexOf("\n\n"));
|
||||
}
|
||||
|
||||
function hasGname(f, v) {
|
||||
// Do a try-catch that prints the full stack, so we can tell
|
||||
// _which_ part of this test failed.
|
||||
try {
|
||||
var b = bytecode(f);
|
||||
if (b != "unavailable") {
|
||||
assertEq(b.contains(`getgname "${v}"`), true);
|
||||
assertEq(b.contains(`getname "${v}"`), false);
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.stack);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var x = "outer";
|
||||
|
||||
var f1 = new Function("assertEq(x, 'outer')");
|
||||
f1();
|
||||
hasGname(f1, 'x');
|
||||
|
||||
setLazyParsingEnabled(false);
|
||||
var f2 = new Function("assertEq(x, 'outer')");
|
||||
f2();
|
||||
hasGname(f2, 'x');
|
||||
setLazyParsingEnabled(true);
|
||||
|
||||
{
|
||||
let x = "inner";
|
||||
var f3 = new Function("assertEq(x, 'outer')");
|
||||
f3();
|
||||
hasGname(f3, 'x');
|
||||
}
|
||||
|
||||
setLazyParsingEnabled(false);
|
||||
{
|
||||
let x = "inner";
|
||||
var f4 = new Function("assertEq(x, 'outer')");
|
||||
f4();
|
||||
hasGname(f4, 'x');
|
||||
}
|
||||
setLazyParsingEnabled(true);
|
||||
@@ -0,0 +1,36 @@
|
||||
function checkNameLookup() {
|
||||
return "global";
|
||||
}
|
||||
|
||||
function assertWithMessage(got, expected, message) {
|
||||
assertEq(message + ": " + got, message + ": " + expected);
|
||||
}
|
||||
|
||||
// Create our test func via "evaluate" so it won't be compileAndGo and
|
||||
// we can clone it.
|
||||
evaluate(`function testFunc() {
|
||||
assertWithMessage(checkNameLookup(), "local", "nameLookup");
|
||||
assertWithMessage(checkThisBinding(), "local", "thisBinding");
|
||||
|
||||
// Important: lambda needs to close over "reason", so it won't just get the
|
||||
// scope of testFunc as its scope. Instead it'll get the Call object
|
||||
// "reason" lives in.
|
||||
var reason = " in lambda in Call";
|
||||
(function() {
|
||||
assertWithMessage(checkNameLookup(), "local", "nameLookup" + reason);
|
||||
assertWithMessage(checkThisBinding(), "local", "thisBinding" + reason);
|
||||
})();
|
||||
}`, { compileAndGo: false });
|
||||
|
||||
var obj = {
|
||||
checkNameLookup: function() {
|
||||
return "local";
|
||||
},
|
||||
|
||||
checkThisBinding: function() {
|
||||
return this.checkNameLookup();
|
||||
},
|
||||
};
|
||||
|
||||
var cloneFunc = clone(testFunc, obj);
|
||||
cloneFunc();
|
||||
@@ -2056,6 +2056,9 @@ BaselineCompiler::emit_JSOP_IN()
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_GETGNAME()
|
||||
{
|
||||
if (script->hasPollutedGlobalScope())
|
||||
return emit_JSOP_GETNAME();
|
||||
|
||||
RootedPropertyName name(cx, script->getName(pc));
|
||||
|
||||
if (name == cx->names().undefined) {
|
||||
@@ -2088,8 +2091,12 @@ BaselineCompiler::emit_JSOP_GETGNAME()
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_BINDGNAME()
|
||||
{
|
||||
frame.push(ObjectValue(script->global()));
|
||||
return true;
|
||||
if (!script->hasPollutedGlobalScope()) {
|
||||
frame.push(ObjectValue(script->global()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return emit_JSOP_BINDNAME();
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -6085,6 +6085,8 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
|
||||
|
||||
RootedPropertyName name(cx, script->getName(pc));
|
||||
|
||||
static_assert(JSOP_GETGNAME_LENGTH == JSOP_GETNAME_LENGTH,
|
||||
"Otherwise our check for JSOP_TYPEOF isn't ok");
|
||||
if (JSOp(pc[JSOP_GETGNAME_LENGTH]) == JSOP_TYPEOF) {
|
||||
if (!GetScopeNameForTypeOf(cx, scopeChain, name, res))
|
||||
return false;
|
||||
@@ -6111,7 +6113,7 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
|
||||
|
||||
bool attached = false;
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
if (js_CodeSpec[*pc].format & JOF_GNAME) {
|
||||
if (IsGlobalOp(JSOp(*pc)) && !script->hasPollutedGlobalScope()) {
|
||||
Handle<GlobalObject*> global = scopeChain.as<GlobalObject>();
|
||||
if (!TryAttachGlobalNameStub(cx, script, pc, stub, global, name, &attached,
|
||||
&isTemporarilyUnoptimizable))
|
||||
@@ -6226,7 +6228,7 @@ DoBindNameFallback(JSContext* cx, BaselineFrame* frame, ICBindName_Fallback* stu
|
||||
mozilla::DebugOnly<JSOp> op = JSOp(*pc);
|
||||
FallbackICSpew(cx, stub, "BindName(%s)", js_CodeName[JSOp(*pc)]);
|
||||
|
||||
MOZ_ASSERT(op == JSOP_BINDNAME);
|
||||
MOZ_ASSERT(op == JSOP_BINDNAME || op == JSOP_BINDGNAME);
|
||||
|
||||
RootedPropertyName name(cx, frame->script()->getName(pc));
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
|
||||
case JSOP_GETNAME:
|
||||
case JSOP_BINDNAME:
|
||||
case JSOP_SETNAME:
|
||||
case JSOP_STRICTSETNAME:
|
||||
case JSOP_DELNAME:
|
||||
case JSOP_GETALIASEDVAR:
|
||||
case JSOP_SETALIASEDVAR:
|
||||
@@ -168,6 +169,13 @@ BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
|
||||
usesScopeChain_ = true;
|
||||
break;
|
||||
|
||||
case JSOP_GETGNAME:
|
||||
case JSOP_SETGNAME:
|
||||
case JSOP_STRICTSETGNAME:
|
||||
if (script_->hasPollutedGlobalScope())
|
||||
usesScopeChain_ = true;
|
||||
break;
|
||||
|
||||
case JSOP_FINALLY:
|
||||
hasTryFinally_ = true;
|
||||
break;
|
||||
|
||||
+16
-11
@@ -1825,18 +1825,19 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
|
||||
case JSOP_GETGNAME:
|
||||
{
|
||||
PropertyName* name = info().getAtom(pc)->asPropertyName();
|
||||
return jsop_getgname(name);
|
||||
PropertyName *name = info().getAtom(pc)->asPropertyName();
|
||||
if (!script()->hasPollutedGlobalScope())
|
||||
return jsop_getgname(name);
|
||||
return jsop_getname(name);
|
||||
}
|
||||
|
||||
case JSOP_BINDGNAME:
|
||||
return pushConstant(ObjectValue(script()->global()));
|
||||
|
||||
case JSOP_SETGNAME:
|
||||
case JSOP_STRICTSETGNAME:
|
||||
{
|
||||
PropertyName* name = info().getAtom(pc)->asPropertyName();
|
||||
JSObject* obj = &script()->global();
|
||||
PropertyName *name = info().getAtom(pc)->asPropertyName();
|
||||
if (script()->hasPollutedGlobalScope())
|
||||
return jsop_setprop(name);
|
||||
JSObject *obj = &script()->global();
|
||||
return setStaticName(obj, name);
|
||||
}
|
||||
|
||||
@@ -1852,6 +1853,10 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
return jsop_intrinsic(name);
|
||||
}
|
||||
|
||||
case JSOP_BINDGNAME:
|
||||
if (!script()->hasPollutedGlobalScope())
|
||||
return pushConstant(ObjectValue(script()->global()));
|
||||
// Fall through to JSOP_BINDNAME
|
||||
case JSOP_BINDNAME:
|
||||
return jsop_bindname(info().getName(pc));
|
||||
|
||||
@@ -7572,11 +7577,11 @@ IonBuilder::jsop_getgname(PropertyName* name)
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_getname(PropertyName* name)
|
||||
IonBuilder::jsop_getname(PropertyName *name)
|
||||
{
|
||||
MDefinition* object;
|
||||
if (js_CodeSpec[*pc].format & JOF_GNAME) {
|
||||
MInstruction* global = constant(ObjectValue(script()->global()));
|
||||
MDefinition *object;
|
||||
if (IsGlobalOp(JSOp(*pc)) && !script()->hasPollutedGlobalScope()) {
|
||||
MInstruction *global = constant(ObjectValue(script()->global()));
|
||||
object = global;
|
||||
} else {
|
||||
current->push(current->scopeChain());
|
||||
|
||||
@@ -39,9 +39,8 @@ CodeGeneratorShared::ensureMasm(MacroAssembler* masmArg)
|
||||
return *maybeMasm_;
|
||||
}
|
||||
|
||||
CodeGeneratorShared::CodeGeneratorShared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masmArg)
|
||||
: oolIns(nullptr),
|
||||
maybeMasm_(),
|
||||
CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masmArg)
|
||||
: maybeMasm_(),
|
||||
masm(ensureMasm(masmArg)),
|
||||
gen(gen),
|
||||
graph(*graph),
|
||||
@@ -129,10 +128,8 @@ CodeGeneratorShared::generateOutOfLineCode()
|
||||
lastPC_ = outOfLineCode_[i]->pc();
|
||||
outOfLineCode_[i]->bind(&masm);
|
||||
|
||||
oolIns = outOfLineCode_[i];
|
||||
outOfLineCode_[i]->generate(this);
|
||||
}
|
||||
oolIns = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -62,10 +62,9 @@ struct NativeToTrackedOptimizations
|
||||
|
||||
class CodeGeneratorShared : public LElementVisitor
|
||||
{
|
||||
js::Vector<OutOfLineCode*, 0, SystemAllocPolicy> outOfLineCode_;
|
||||
OutOfLineCode* oolIns;
|
||||
js::Vector<OutOfLineCode *, 0, SystemAllocPolicy> outOfLineCode_;
|
||||
|
||||
MacroAssembler& ensureMasm(MacroAssembler* masm);
|
||||
MacroAssembler &ensureMasm(MacroAssembler *masm);
|
||||
mozilla::Maybe<MacroAssembler> maybeMasm_;
|
||||
|
||||
public:
|
||||
@@ -483,12 +482,11 @@ class CodeGeneratorShared : public LElementVisitor
|
||||
ReciprocalMulConstants computeDivisionConstants(int d);
|
||||
|
||||
protected:
|
||||
void addOutOfLineCode(OutOfLineCode* code, const MInstruction* mir);
|
||||
void addOutOfLineCode(OutOfLineCode* code, const BytecodeSite* site);
|
||||
bool hasOutOfLineCode() { return !outOfLineCode_.empty(); }
|
||||
void addOutOfLineCode(OutOfLineCode *code, const MInstruction *mir);
|
||||
void addOutOfLineCode(OutOfLineCode *code, const BytecodeSite *site);
|
||||
bool generateOutOfLineCode();
|
||||
|
||||
Label* labelForBackedgeWithImplicitCheck(MBasicBlock* mir);
|
||||
Label *labelForBackedgeWithImplicitCheck(MBasicBlock *mir);
|
||||
|
||||
// Generate a jump to the start of the specified block, adding information
|
||||
// if this is a loop backedge. Use this in place of jumping directly to
|
||||
|
||||
@@ -13,51 +13,51 @@ using namespace js::jit;
|
||||
using namespace js::jit::X86Encoding;
|
||||
using namespace js::jit::Disassembler;
|
||||
|
||||
static bool REX_W(uint8_t rex) { return (rex >> 3) & 0x1; }
|
||||
static bool REX_R(uint8_t rex) { return (rex >> 2) & 0x1; }
|
||||
static bool REX_X(uint8_t rex) { return (rex >> 1) & 0x1; }
|
||||
static bool REX_B(uint8_t rex) { return (rex >> 0) & 0x1; }
|
||||
MOZ_COLD static bool REX_W(uint8_t rex) { return (rex >> 3) & 0x1; }
|
||||
MOZ_COLD static bool REX_R(uint8_t rex) { return (rex >> 2) & 0x1; }
|
||||
MOZ_COLD static bool REX_X(uint8_t rex) { return (rex >> 1) & 0x1; }
|
||||
MOZ_COLD static bool REX_B(uint8_t rex) { return (rex >> 0) & 0x1; }
|
||||
|
||||
static uint8_t
|
||||
MOZ_COLD static uint8_t
|
||||
MakeREXFlags(bool w, bool r, bool x, bool b)
|
||||
{
|
||||
uint8_t rex = (w << 3) | (r << 2) | (x << 1) | (b << 0);
|
||||
MOZ_ASSERT(REX_W(rex) == w);
|
||||
MOZ_ASSERT(REX_R(rex) == r);
|
||||
MOZ_ASSERT(REX_X(rex) == x);
|
||||
MOZ_ASSERT(REX_B(rex) == b);
|
||||
MOZ_RELEASE_ASSERT(REX_W(rex) == w);
|
||||
MOZ_RELEASE_ASSERT(REX_R(rex) == r);
|
||||
MOZ_RELEASE_ASSERT(REX_X(rex) == x);
|
||||
MOZ_RELEASE_ASSERT(REX_B(rex) == b);
|
||||
return rex;
|
||||
}
|
||||
|
||||
static ModRmMode
|
||||
MOZ_COLD static ModRmMode
|
||||
ModRM_Mode(uint8_t modrm)
|
||||
{
|
||||
return ModRmMode((modrm >> 6) & 0x3);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
MOZ_COLD static uint8_t
|
||||
ModRM_Reg(uint8_t modrm)
|
||||
{
|
||||
return (modrm >> 3) & 0x7;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
MOZ_COLD static uint8_t
|
||||
ModRM_RM(uint8_t modrm)
|
||||
{
|
||||
return (modrm >> 0) & 0x7;
|
||||
}
|
||||
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
ModRM_hasSIB(uint8_t modrm)
|
||||
{
|
||||
return ModRM_Mode(modrm) != ModRmRegister && ModRM_RM(modrm) == hasSib;
|
||||
}
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
ModRM_hasDisp8(uint8_t modrm)
|
||||
{
|
||||
return ModRM_Mode(modrm) == ModRmMemoryDisp8;
|
||||
}
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
ModRM_hasRIP(uint8_t modrm)
|
||||
{
|
||||
#ifdef JS_CODEGEN_X64
|
||||
@@ -66,50 +66,50 @@ ModRM_hasRIP(uint8_t modrm)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
ModRM_hasDisp32(uint8_t modrm)
|
||||
{
|
||||
return ModRM_Mode(modrm) == ModRmMemoryDisp32 ||
|
||||
ModRM_hasRIP(modrm);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
MOZ_COLD static uint8_t
|
||||
SIB_SS(uint8_t sib)
|
||||
{
|
||||
return (sib >> 6) & 0x3;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
MOZ_COLD static uint8_t
|
||||
SIB_Index(uint8_t sib)
|
||||
{
|
||||
return (sib >> 3) & 0x7;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
MOZ_COLD static uint8_t
|
||||
SIB_Base(uint8_t sib)
|
||||
{
|
||||
return (sib >> 0) & 0x7;
|
||||
}
|
||||
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
SIB_hasRIP(uint8_t sib)
|
||||
{
|
||||
return SIB_Base(sib) == noBase && SIB_Index(sib) == noIndex;
|
||||
}
|
||||
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
HasRIP(uint8_t modrm, uint8_t sib, uint8_t rex)
|
||||
{
|
||||
return ModRM_hasRIP(modrm) && SIB_hasRIP(sib);
|
||||
}
|
||||
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
HasDisp8(uint8_t modrm)
|
||||
{
|
||||
return ModRM_hasDisp8(modrm);
|
||||
}
|
||||
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
HasDisp32(uint8_t modrm, uint8_t sib)
|
||||
{
|
||||
return ModRM_hasDisp32(modrm) ||
|
||||
@@ -118,13 +118,13 @@ HasDisp32(uint8_t modrm, uint8_t sib)
|
||||
ModRM_Mode(modrm) == ModRmMemoryNoDisp);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
MOZ_COLD static uint32_t
|
||||
Reg(uint8_t modrm, uint8_t sib, uint8_t rex)
|
||||
{
|
||||
return ModRM_Reg(modrm) | (REX_R(rex) << 3);
|
||||
}
|
||||
|
||||
static bool
|
||||
MOZ_COLD static bool
|
||||
HasBase(uint8_t modrm, uint8_t sib)
|
||||
{
|
||||
return !ModRM_hasSIB(modrm) ||
|
||||
@@ -133,7 +133,7 @@ HasBase(uint8_t modrm, uint8_t sib)
|
||||
ModRM_Mode(modrm) != ModRmMemoryNoDisp;
|
||||
}
|
||||
|
||||
static RegisterID
|
||||
MOZ_COLD static RegisterID
|
||||
DecodeBase(uint8_t modrm, uint8_t sib, uint8_t rex)
|
||||
{
|
||||
return HasBase(modrm, sib)
|
||||
@@ -141,14 +141,14 @@ DecodeBase(uint8_t modrm, uint8_t sib, uint8_t rex)
|
||||
: invalid_reg;
|
||||
}
|
||||
|
||||
static RegisterID
|
||||
MOZ_COLD static RegisterID
|
||||
DecodeIndex(uint8_t modrm, uint8_t sib, uint8_t rex)
|
||||
{
|
||||
RegisterID index = RegisterID(SIB_Index(sib) | (REX_X(rex) << 3));
|
||||
return ModRM_hasSIB(modrm) && index != noIndex ? index : invalid_reg;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
MOZ_COLD static uint32_t
|
||||
DecodeScale(uint8_t modrm, uint8_t sib, uint8_t rex)
|
||||
{
|
||||
return ModRM_hasSIB(modrm) ? SIB_SS(sib) : 0;
|
||||
@@ -377,25 +377,25 @@ js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
|
||||
case OP_GROUP11_EvIb:
|
||||
if (gpr != RegisterID(GROUP11_MOV))
|
||||
MOZ_CRASH("Unable to disassemble instruction");
|
||||
MOZ_ASSERT(haveImm);
|
||||
MOZ_RELEASE_ASSERT(haveImm);
|
||||
memSize = 1;
|
||||
kind = HeapAccess::Store;
|
||||
break;
|
||||
case OP_GROUP11_EvIz:
|
||||
if (gpr != RegisterID(GROUP11_MOV))
|
||||
MOZ_CRASH("Unable to disassemble instruction");
|
||||
MOZ_ASSERT(haveImm);
|
||||
MOZ_RELEASE_ASSERT(haveImm);
|
||||
memSize = opsize;
|
||||
kind = HeapAccess::Store;
|
||||
break;
|
||||
case OP_MOV_GvEv:
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(gpr);
|
||||
memSize = opsize;
|
||||
kind = HeapAccess::Load;
|
||||
break;
|
||||
case OP_MOV_GvEb:
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(gpr);
|
||||
memSize = 1;
|
||||
kind = HeapAccess::Load;
|
||||
@@ -413,38 +413,38 @@ js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
|
||||
kind = HeapAccess::Store;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVZX_GvEb):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(gpr);
|
||||
memSize = 1;
|
||||
kind = HeapAccess::Load;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVZX_GvEw):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(gpr);
|
||||
memSize = 2;
|
||||
kind = HeapAccess::Load;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVSX_GvEb):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(gpr);
|
||||
memSize = 1;
|
||||
kind = HeapAccess::LoadSext32;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVSX_GvEw):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(gpr);
|
||||
memSize = 2;
|
||||
kind = HeapAccess::LoadSext32;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVDQ_VdqWdq): // aka OP2_MOVDQ_VsdWsd
|
||||
case Pack2ByteOpcode(OP2_MOVAPS_VsdWsd):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
memSize = 16;
|
||||
kind = HeapAccess::Load;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVSD_VsdWsd): // aka OP2_MOVPS_VpsWps
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
switch (type) {
|
||||
case VEX_SS: memSize = 4; break;
|
||||
@@ -456,13 +456,13 @@ js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
|
||||
kind = HeapAccess::Load;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVDQ_WdqVdq):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
memSize = 16;
|
||||
kind = HeapAccess::Store;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVSD_WsdVsd): // aka OP2_MOVPS_WpsVps
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
switch (type) {
|
||||
case VEX_SS: memSize = 4; break;
|
||||
@@ -474,7 +474,7 @@ js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
|
||||
kind = HeapAccess::Store;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVD_VdEd):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
switch (type) {
|
||||
case VEX_PD: memSize = 4; break;
|
||||
@@ -483,7 +483,7 @@ js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
|
||||
kind = HeapAccess::Load;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVQ_WdVd):
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
switch (type) {
|
||||
case VEX_PD: memSize = 8; break;
|
||||
@@ -492,7 +492,7 @@ js::jit::Disassembler::DisassembleHeapAccess(uint8_t* ptr, HeapAccess* access)
|
||||
kind = HeapAccess::Store;
|
||||
break;
|
||||
case Pack2ByteOpcode(OP2_MOVD_EdVd): // aka OP2_MOVQ_VdWd
|
||||
MOZ_ASSERT(!haveImm);
|
||||
MOZ_RELEASE_ASSERT(!haveImm);
|
||||
otherOperand = OtherOperand(xmm);
|
||||
switch (type) {
|
||||
case VEX_SS: memSize = 8; kind = HeapAccess::Load; break;
|
||||
|
||||
@@ -204,14 +204,14 @@ Assembler::finish()
|
||||
size_t oldSize = masm.size();
|
||||
#endif
|
||||
masm.jmp_rip(2);
|
||||
MOZ_ASSERT(masm.size() - oldSize == 6);
|
||||
MOZ_ASSERT_IF(!masm.oom(), masm.size() - oldSize == 6);
|
||||
// Following an indirect branch with ud2 hints to the hardware that
|
||||
// there's no fall-through. This also aligns the 64-bit immediate.
|
||||
masm.ud2();
|
||||
MOZ_ASSERT(masm.size() - oldSize == 8);
|
||||
MOZ_ASSERT_IF(!masm.oom(), masm.size() - oldSize == 8);
|
||||
masm.immediate64(0);
|
||||
MOZ_ASSERT(masm.size() - oldSize == SizeOfExtendedJump);
|
||||
MOZ_ASSERT(masm.size() - oldSize == SizeOfJumpTableEntry);
|
||||
MOZ_ASSERT_IF(!masm.oom(), masm.size() - oldSize == SizeOfExtendedJump);
|
||||
MOZ_ASSERT_IF(!masm.oom(), masm.size() - oldSize == SizeOfJumpTableEntry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -629,13 +629,14 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
|
||||
}
|
||||
|
||||
template bool
|
||||
js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleObject, HandleScript, MutableHandleFunction);
|
||||
js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, MutableHandleFunction);
|
||||
|
||||
template bool
|
||||
js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleObject, HandleScript, MutableHandleFunction);
|
||||
js::XDRInterpretedFunction(XDRState<XDR_DECODE> *, HandleObject, HandleScript, MutableHandleFunction);
|
||||
|
||||
JSObject*
|
||||
js::CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFunction srcFun)
|
||||
JSObject *
|
||||
js::CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction srcFun,
|
||||
PollutedGlobalScopeOption polluted)
|
||||
{
|
||||
/* NB: Keep this in sync with XDRInterpretedFunction. */
|
||||
RootedObject cloneProto(cx);
|
||||
@@ -657,7 +658,7 @@ js::CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFun
|
||||
RootedScript srcScript(cx, srcFun->getOrCreateScript(cx));
|
||||
if (!srcScript)
|
||||
return nullptr;
|
||||
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript));
|
||||
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript, polluted));
|
||||
if (!clonedScript)
|
||||
return nullptr;
|
||||
|
||||
|
||||
+3
-2
@@ -687,8 +687,9 @@ bool
|
||||
XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope,
|
||||
HandleScript enclosingScript, MutableHandleFunction objp);
|
||||
|
||||
extern JSObject*
|
||||
CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun);
|
||||
extern JSObject *
|
||||
CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
PollutedGlobalScopeOption polluted);
|
||||
|
||||
/*
|
||||
* Report an error that call.thisv is not compatible with the specified class,
|
||||
|
||||
+1
-1
@@ -3030,7 +3030,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
else
|
||||
enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
|
||||
|
||||
clone = CloneFunctionAndScript(cx, enclosingScope, innerFun);
|
||||
clone = CloneFunctionAndScript(cx, enclosingScope, innerFun, polluted);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
||||
@@ -303,8 +303,10 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s
|
||||
*pc == JSOP_STRICTSETNAME ||
|
||||
*pc == JSOP_SETGNAME ||
|
||||
*pc == JSOP_STRICTSETGNAME);
|
||||
MOZ_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME, scope == cx->global());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_SETGNAME && !script->hasPollutedGlobalScope(),
|
||||
scope == cx->global());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME && !script->hasPollutedGlobalScope(),
|
||||
scope == cx->global());
|
||||
|
||||
bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME;
|
||||
RootedPropertyName name(cx, script->getName(pc));
|
||||
|
||||
+27
-15
@@ -292,7 +292,7 @@ GetNameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHan
|
||||
* the actual behavior even if the id could be found on the scope chain
|
||||
* before the global object.
|
||||
*/
|
||||
if (IsGlobalOp(JSOp(*pc)))
|
||||
if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasPollutedGlobalScope())
|
||||
obj = &obj->global();
|
||||
|
||||
Shape* shape = nullptr;
|
||||
@@ -2302,28 +2302,33 @@ CASE(JSOP_SETCONST)
|
||||
}
|
||||
END_CASE(JSOP_SETCONST)
|
||||
|
||||
CASE(JSOP_BINDGNAME)
|
||||
PUSH_OBJECT(REGS.fp()->global());
|
||||
END_CASE(JSOP_BINDGNAME)
|
||||
|
||||
CASE(JSOP_BINDINTRINSIC)
|
||||
PUSH_OBJECT(*cx->global()->intrinsicsHolder());
|
||||
END_CASE(JSOP_BINDINTRINSIC)
|
||||
|
||||
CASE(JSOP_BINDGNAME)
|
||||
CASE(JSOP_BINDNAME)
|
||||
{
|
||||
RootedObject& scopeChain = rootObject0;
|
||||
scopeChain = REGS.fp()->scopeChain();
|
||||
JSOp op = JSOp(*REGS.pc);
|
||||
if (op == JSOP_BINDNAME || script->hasPollutedGlobalScope()) {
|
||||
RootedObject &scopeChain = rootObject0;
|
||||
scopeChain = REGS.fp()->scopeChain();
|
||||
|
||||
RootedPropertyName& name = rootName0;
|
||||
name = script->getName(REGS.pc);
|
||||
RootedPropertyName &name = rootName0;
|
||||
name = script->getName(REGS.pc);
|
||||
|
||||
/* Assigning to an undeclared name adds a property to the global object. */
|
||||
RootedObject& scope = rootObject1;
|
||||
if (!LookupNameUnqualified(cx, name, scopeChain, &scope))
|
||||
goto error;
|
||||
/* Assigning to an undeclared name adds a property to the global object. */
|
||||
RootedObject &scope = rootObject1;
|
||||
if (!LookupNameUnqualified(cx, name, scopeChain, &scope))
|
||||
goto error;
|
||||
|
||||
PUSH_OBJECT(*scope);
|
||||
PUSH_OBJECT(*scope);
|
||||
} else {
|
||||
PUSH_OBJECT(REGS.fp()->global());
|
||||
}
|
||||
|
||||
static_assert(JSOP_BINDNAME_LENGTH == JSOP_BINDGNAME_LENGTH,
|
||||
"We're sharing the END_CASE so the lengths better match");
|
||||
}
|
||||
END_CASE(JSOP_BINDNAME)
|
||||
|
||||
@@ -2742,7 +2747,10 @@ CASE(JSOP_STRICTSETNAME)
|
||||
"setname and strictsetname must be the same size");
|
||||
static_assert(JSOP_SETGNAME_LENGTH == JSOP_STRICTSETGNAME_LENGTH,
|
||||
"setganem adn strictsetgname must be the same size");
|
||||
RootedObject& scope = rootObject0;
|
||||
static_assert(JSOP_SETNAME_LENGTH == JSOP_SETGNAME_LENGTH,
|
||||
"We're sharing the END_CASE so the lengths better match");
|
||||
|
||||
RootedObject &scope = rootObject0;
|
||||
scope = ®S.sp[-2].toObject();
|
||||
HandleValue value = REGS.stackHandleAt(-1);
|
||||
|
||||
@@ -2997,6 +3005,8 @@ CASE(JSOP_GIMPLICITTHIS)
|
||||
// Treat it like JSOP_UNDEFINED.
|
||||
PUSH_UNDEFINED();
|
||||
}
|
||||
static_assert(JSOP_IMPLICITTHIS_LENGTH == JSOP_GIMPLICITTHIS_LENGTH,
|
||||
"We're sharing the END_CASE so the lengths better match");
|
||||
}
|
||||
END_CASE(JSOP_IMPLICITTHIS)
|
||||
|
||||
@@ -3010,6 +3020,8 @@ CASE(JSOP_GETNAME)
|
||||
|
||||
PUSH_COPY(rval);
|
||||
TypeScript::Monitor(cx, script, REGS.pc, rval);
|
||||
static_assert(JSOP_GETNAME_LENGTH == JSOP_GETGNAME_LENGTH,
|
||||
"We're sharing the END_CASE so the lengths better match");
|
||||
}
|
||||
END_CASE(JSOP_GETNAME)
|
||||
|
||||
|
||||
+10
-5
@@ -1507,7 +1507,9 @@
|
||||
macro(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
\
|
||||
/*
|
||||
* Looks up name on global scope and pushes its value onto the stack.
|
||||
* Looks up name on global scope and pushes its value onto the stack, unless
|
||||
* the script has a polluted global, in which case it acts just like
|
||||
* JSOP_NAME.
|
||||
*
|
||||
* Free variable references that must either be found on the global or a
|
||||
* ReferenceError.
|
||||
@@ -1521,7 +1523,8 @@
|
||||
* Pops the top two values on the stack as 'val' and 'scope', sets property
|
||||
* of 'scope' as 'val' and pushes 'val' back on the stack.
|
||||
*
|
||||
* 'scope' should be the global scope.
|
||||
* 'scope' should be the global scope unless the script has a polluted
|
||||
* global scope, in which case acts like JSOP_SETNAME.
|
||||
* Category: Variables and Scopes
|
||||
* Type: Free Variables
|
||||
* Operands: uint32_t nameIndex
|
||||
@@ -1534,7 +1537,8 @@
|
||||
* of 'scope' as 'val' and pushes 'val' back on the stack. Throws a
|
||||
* TypeError if the set fails, per strict mode semantics.
|
||||
*
|
||||
* 'scope' should be the global scope.
|
||||
* 'scope' should be the global scope unless the script has a polluted
|
||||
* global scope, in which case acts like JSOP_STRICTSETNAME.
|
||||
* Category: Variables and Scopes
|
||||
* Type: Free Variables
|
||||
* Operands: uint32_t nameIndex
|
||||
@@ -1787,9 +1791,10 @@
|
||||
macro(JSOP_UNUSED212, 212, "unused212", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED213, 213, "unused213", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* Pushes the global scope onto the stack.
|
||||
* Pushes the global scope onto the stack if the script doesn't have a
|
||||
* polluted global scope. Otherwise will act like JSOP_BINDNAME.
|
||||
*
|
||||
* 'nameIndex' is not used.
|
||||
* 'nameIndex' is only used when acting like JSOP_BINDNAME.
|
||||
* Category: Variables and Scopes
|
||||
* Type: Free Variables
|
||||
* Operands: uint32_t nameIndex
|
||||
|
||||
@@ -2624,9 +2624,19 @@ RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remai
|
||||
switch (JSOp(*pc)) {
|
||||
case JSOP_GETNAME:
|
||||
case JSOP_SETNAME:
|
||||
case JSOP_STRICTSETNAME:
|
||||
name = script->getName(pc);
|
||||
break;
|
||||
|
||||
case JSOP_GETGNAME:
|
||||
case JSOP_SETGNAME:
|
||||
case JSOP_STRICTSETGNAME:
|
||||
if (script->hasPollutedGlobalScope())
|
||||
name = script->getName(pc);
|
||||
else
|
||||
name = nullptr;
|
||||
break;
|
||||
|
||||
case JSOP_GETALIASEDVAR:
|
||||
case JSOP_SETALIASEDVAR:
|
||||
name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 258;
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 260;
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||
|
||||
|
||||
@@ -30,7 +30,12 @@ enum class PixelCastJustification : uint8_t {
|
||||
// The transform that is usually used to convert between two coordinate
|
||||
// systems is not available (for example, because the object that stores it
|
||||
// is being destroyed), so fall back to the identity.
|
||||
TransformNotAvailable
|
||||
TransformNotAvailable,
|
||||
// When an OS event is initially constructed, its reference point is
|
||||
// technically in screen pixels, as it has not yet accounted for any
|
||||
// asynchronous transforms. This justification is for viewing the initial
|
||||
// reference point as a screen point.
|
||||
LayoutDeviceToScreenForUntransformedEvent
|
||||
};
|
||||
|
||||
template <class TargetUnits, class SourceUnits>
|
||||
@@ -45,6 +50,10 @@ template <class TargetUnits, class SourceUnits>
|
||||
gfx::PointTyped<TargetUnits> ViewAs(const gfx::PointTyped<SourceUnits>& aPoint, PixelCastJustification) {
|
||||
return gfx::PointTyped<TargetUnits>(aPoint.x, aPoint.y);
|
||||
}
|
||||
template <class TargetUnits, class SourceUnits>
|
||||
gfx::IntPointTyped<TargetUnits> ViewAs(const gfx::IntPointTyped<SourceUnits>& aPoint, PixelCastJustification) {
|
||||
return gfx::IntPointTyped<TargetUnits>(aPoint.x, aPoint.y);
|
||||
}
|
||||
template <class NewTargetUnits, class OldTargetUnits, class SourceUnits>
|
||||
gfx::ScaleFactor<SourceUnits, NewTargetUnits> ViewTargetAs(
|
||||
const gfx::ScaleFactor<SourceUnits, OldTargetUnits>& aScaleFactor,
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
/* implementation of CSS counters (for numbering things) */
|
||||
|
||||
#include "nsCounterManager.h"
|
||||
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsBulletFrame.h" // legacy location for list style type to text code
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "nsIContent.h"
|
||||
#include "WritingModes.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -895,6 +895,7 @@ nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
|
||||
if (widget) {
|
||||
nsIntRect widgetBounds;
|
||||
widget->GetBounds(widgetBounds);
|
||||
widgetBounds.MoveTo(0,0);
|
||||
metrics.mCompositionBounds = ParentLayerRect(ViewAs<ParentLayerPixel>(widgetBounds));
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (frameBounds.height < metrics.mCompositionBounds.height) {
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsCopySupport.h"
|
||||
#include "nsIDOMHTMLFrameSetElement.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
@@ -2789,6 +2790,20 @@ NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocumentViewer::SetCommandNode(nsIDOMNode* aNode)
|
||||
{
|
||||
nsIDocument* document = GetDocument();
|
||||
NS_ENSURE_STATE(document);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window(document->GetWindow());
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
|
||||
NS_ENSURE_STATE(root);
|
||||
|
||||
root->SetPopupNode(aNode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* ========================================================================================
|
||||
* nsIContentViewerFile
|
||||
@@ -3611,8 +3626,16 @@ NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage)
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
|
||||
|
||||
// if we made it here, we're in an image
|
||||
*aInImage = true;
|
||||
// Make sure there is a URI assigned. This allows <input type="image"> to
|
||||
// be an image but rejects other <input> types. This matches what
|
||||
// nsContextMenu.js does.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
node->GetCurrentURI(getter_AddRefs(uri));
|
||||
if (uri) {
|
||||
// if we made it here, we're in an image
|
||||
*aInImage = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define mozilla_JustificationUtils_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCoord.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ EXPORTS += [
|
||||
'RubyUtils.h',
|
||||
'ScrollbarActivity.h',
|
||||
'Selection.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'WritingModes.h',
|
||||
]
|
||||
|
||||
|
||||
@@ -10,12 +10,11 @@
|
||||
#define nsFloatManager_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsIntervalSet.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsCoord.h"
|
||||
#include "WritingModes.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsFrameList.h" // for DEBUG_FRAME_DUMP
|
||||
#include "nsIntervalSet.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIPresShell;
|
||||
class nsIFrame;
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#ifndef nsHTMLReflowMetrics_h___
|
||||
#define nsHTMLReflowMetrics_h___
|
||||
|
||||
#include "nsRect.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsBoundingMetrics.h"
|
||||
#include "WritingModes.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
+12
-11
@@ -20,21 +20,22 @@
|
||||
we're midway through this process, so you will see inlined functions and member
|
||||
variables in this file. -dwh */
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "CaretAssociationHint.h"
|
||||
#include "FramePropertyTable.h"
|
||||
#include "mozilla/layout/FrameChildList.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsDirection.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsFrameState.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
#include "nsITheme.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsQueryFrame.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "mozilla/layout/FrameChildList.h"
|
||||
#include "FramePropertyTable.h"
|
||||
#include "nsDirection.h"
|
||||
#include "WritingModes.h"
|
||||
#include <algorithm>
|
||||
#include "nsITheme.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsFrameState.h"
|
||||
#include "CaretAssociationHint.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/AccTypes.h"
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
/* representation of one line within a block frame, a CSS line box */
|
||||
|
||||
#include "nsLineBox.h"
|
||||
#include "prprf.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsPresArena.h"
|
||||
#include "nsBidiPresUtils.h"
|
||||
#include "nsIFrameInlines.h"
|
||||
#include "WritingModes.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsBidiPresUtils.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsIFrameInlines.h"
|
||||
#include "nsPresArena.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static int32_t ctorCount;
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
#ifndef nsLineLayout_h___
|
||||
#define nsLineLayout_h___
|
||||
|
||||
#include "nsLineBox.h"
|
||||
#include "nsBlockReflowState.h"
|
||||
#include "plarena.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "WritingModes.h"
|
||||
#include "JustificationUtils.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsBlockReflowState.h"
|
||||
#include "nsLineBox.h"
|
||||
#include "plarena.h"
|
||||
|
||||
class nsFloatManager;
|
||||
struct nsStyleText;
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#include "nsRubyBaseContainerFrame.h"
|
||||
#include "nsRubyTextContainerFrame.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsRubyBaseFrame.h"
|
||||
#include "nsRubyTextFrame.h"
|
||||
#include "nsContentUtils.h"
|
||||
@@ -15,11 +19,8 @@
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsStyleStructInlines.h"
|
||||
#include "WritingModes.h"
|
||||
#include "RubyUtils.h"
|
||||
#include "nsTextFrame.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "RubyUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
/* rendering object for CSS "display: ruby-base" */
|
||||
|
||||
#include "nsRubyBaseFrame.h"
|
||||
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "WritingModes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -5,15 +5,17 @@
|
||||
* http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* rendering object for CSS "display: ruby" */
|
||||
|
||||
#include "nsRubyFrame.h"
|
||||
|
||||
#include "RubyUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "WritingModes.h"
|
||||
#include "RubyUtils.h"
|
||||
#include "nsRubyBaseContainerFrame.h"
|
||||
#include "nsRubyTextContainerFrame.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsStyleContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
/* rendering object for CSS "display: ruby-text-container" */
|
||||
|
||||
#include "nsRubyTextContainerFrame.h"
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "WritingModes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
/* rendering object for CSS "display: ruby-text" */
|
||||
|
||||
#include "nsRubyTextFrame.h"
|
||||
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsLineLayout.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "WritingModes.h"
|
||||
#include "nsLineLayout.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -1302,24 +1302,3 @@ nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIntPoint
|
||||
nsSubDocumentFrame::GetChromeDisplacement()
|
||||
{
|
||||
nsIFrame* nextFrame = nsLayoutUtils::GetCrossDocParentFrame(this);
|
||||
if (!nextFrame) {
|
||||
NS_WARNING("Couldn't find window chrome to calculate displacement to.");
|
||||
return nsIntPoint();
|
||||
}
|
||||
|
||||
nsIFrame* rootFrame = nextFrame;
|
||||
while (nextFrame) {
|
||||
rootFrame = nextFrame;
|
||||
nextFrame = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
|
||||
}
|
||||
|
||||
nsPoint offset = GetOffsetToCrossDoc(rootFrame);
|
||||
int32_t appUnitsPerDevPixel = rootFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
return nsIntPoint((int)(offset.x/appUnitsPerDevPixel),
|
||||
(int)(offset.y/appUnitsPerDevPixel));
|
||||
}
|
||||
|
||||
@@ -130,8 +130,6 @@ public:
|
||||
*/
|
||||
bool PassPointerEventsToChildren();
|
||||
|
||||
nsIntPoint GetChromeDisplacement();
|
||||
|
||||
protected:
|
||||
friend class AsyncFrameInit;
|
||||
|
||||
|
||||
@@ -275,6 +275,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent) override {
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &RemoteContentController::NotifyMozMouseScrollEvent, aScrollId, aEvent));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRenderFrame) {
|
||||
TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
|
||||
browser->NotifyMouseScrollTestEvent(aScrollId, aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// Methods used by RenderFrameParent to set fields stored here.
|
||||
|
||||
void SaveZoomConstraints(const ZoomConstraints& aConstraints)
|
||||
@@ -578,6 +592,17 @@ RenderFrameParent::SetTargetAPZC(uint64_t aInputBlockId,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RenderFrameParent::SetAllowedTouchBehavior(uint64_t aInputBlockId,
|
||||
const nsTArray<TouchBehaviorFlags>& aFlags)
|
||||
{
|
||||
if (GetApzcTreeManager()) {
|
||||
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
|
||||
GetApzcTreeManager(), &APZCTreeManager::SetAllowedTouchBehavior,
|
||||
aInputBlockId, aFlags));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId,
|
||||
ViewID aViewId,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include <map>
|
||||
|
||||
#include "mozilla/layers/APZUtils.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layout/PRenderFrameParent.h"
|
||||
#include "nsDisplayList.h"
|
||||
@@ -45,6 +46,7 @@ class RenderFrameParent : public PRenderFrameParent
|
||||
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
|
||||
typedef mozilla::layers::TextureFactoryIdentifier TextureFactoryIdentifier;
|
||||
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
|
||||
typedef mozilla::layers::TouchBehaviorFlags TouchBehaviorFlags;
|
||||
typedef mozilla::layers::ZoomConstraints ZoomConstraints;
|
||||
typedef FrameMetrics::ViewID ViewID;
|
||||
|
||||
@@ -86,6 +88,8 @@ public:
|
||||
bool aPreventDefault);
|
||||
void SetTargetAPZC(uint64_t aInputBlockId,
|
||||
const nsTArray<ScrollableLayerGuid>& aTargets);
|
||||
void SetAllowedTouchBehavior(uint64_t aInputBlockId,
|
||||
const nsTArray<TouchBehaviorFlags>& aFlags);
|
||||
|
||||
void UpdateZoomConstraints(uint32_t aPresShellId,
|
||||
ViewID aViewId,
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
|
||||
#include "CounterStyleManager.h"
|
||||
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "prprf.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "WritingModes.h"
|
||||
#include "prprf.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
@@ -9,14 +9,15 @@
|
||||
*/
|
||||
|
||||
#include "nsCSSDataBlock.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "mozilla/css/Declaration.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "WritingModes.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsStyleSet.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
||||
@@ -65,16 +65,16 @@ function hasLowPrecision() {
|
||||
let [sysName, sysVersion] = [Services.sysinfo.getPropertyAsAString("name"), Services.sysinfo.getPropertyAsDouble("version")];
|
||||
do_print(`Running ${sysName} version ${sysVersion}`);
|
||||
|
||||
if (sysName != "Windows_NT") {
|
||||
do_print("Not running Windows, precision should be good.");
|
||||
return false;
|
||||
if (sysName == "Windows_NT" && sysVersion < 6) {
|
||||
do_print("Running old Windows, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
}
|
||||
if (sysVersion >= 6) {
|
||||
do_print("Running a recent version of Windows, precision should be good.");
|
||||
return false;
|
||||
if (sysName == "Linux" && sysVersion <= 2.6) {
|
||||
do_print("Running old Linux, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
}
|
||||
do_print("Running old Windows, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
do_print("This platform has good precision.")
|
||||
return false;
|
||||
}
|
||||
|
||||
add_task(function* test_measure() {
|
||||
|
||||
@@ -81,9 +81,8 @@ this.AutoCompleteE10S = {
|
||||
this.popup.hidden = false;
|
||||
this.popup.setAttribute("width", rect.width);
|
||||
|
||||
let {x, y} = this.browser.mapScreenCoordinatesFromContent(rect.left, rect.top + rect.height);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.x = rect.left;
|
||||
this.y = rect.top + rect.height;
|
||||
},
|
||||
|
||||
_showPopup: function(results) {
|
||||
|
||||
@@ -909,8 +909,7 @@
|
||||
if (!this.autoscrollEnabled) {
|
||||
return false;
|
||||
}
|
||||
let pos = this.mapScreenCoordinatesFromContent(data.screenX, data.screenY);
|
||||
this.startScroll(data.scrolldir, pos.x, pos.y);
|
||||
this.startScroll(data.scrolldir, data.screenX, data.screenY);
|
||||
return true;
|
||||
}
|
||||
case "Autoscroll:Cancel":
|
||||
@@ -1091,25 +1090,6 @@
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
For out-of-process code, event.screen[XY] is relative to the
|
||||
left/top of the content view. For in-process code,
|
||||
event.screen[XY] is relative to the left/top of the screen. We
|
||||
use this method to map screen coordinates received from a
|
||||
(possibly out-of-process) <browser> element to coordinates
|
||||
that are relative to the screen. This code handles the
|
||||
in-process case, where we return the coordinates unchanged.
|
||||
-->
|
||||
<method name="mapScreenCoordinatesFromContent">
|
||||
<parameter name="aScreenX"/>
|
||||
<parameter name="aScreenY"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
return { x: aScreenX, y: aScreenY };
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="swapDocShells">
|
||||
<parameter name="aOtherBrowser"/>
|
||||
<body>
|
||||
|
||||
@@ -398,27 +398,6 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
For out-of-process code, event.screen[XY] is relative to the
|
||||
left/top of the content view. For in-process code,
|
||||
event.screen[XY] is relative to the left/top of the screen. We
|
||||
use this method to map screen coordinates received from a
|
||||
(possibly out-of-process) <browser> element to coordinates
|
||||
that are relative to the screen. This code handles the
|
||||
out-of-process case, where we need to translate by the screen
|
||||
position of the <browser> element.
|
||||
-->
|
||||
<method name="mapScreenCoordinatesFromContent">
|
||||
<parameter name="aScreenX"/>
|
||||
<parameter name="aScreenY"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
return { x: aScreenX + this.boxObject.screenX,
|
||||
y: aScreenY + this.boxObject.screenY };
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="enableDisableCommands">
|
||||
<parameter name="aAction"/>
|
||||
<parameter name="aEnabledLength"/>
|
||||
|
||||
@@ -28,8 +28,7 @@ this.SelectParentHelper = {
|
||||
currentBrowser = browser;
|
||||
this._registerListeners(menulist.menupopup);
|
||||
|
||||
let {x, y} = browser.mapScreenCoordinatesFromContent(rect.left, rect.top + rect.height);
|
||||
menulist.menupopup.openPopupAtScreen(x, y);
|
||||
menulist.menupopup.openPopupAtScreen(rect.left, rect.top + rect.height);
|
||||
menulist.selectedItem.scrollIntoView();
|
||||
},
|
||||
|
||||
|
||||
@@ -44,14 +44,13 @@ ContentHelper::UpdateAllowedBehavior(uint32_t aTouchActionValue, bool aConsiderP
|
||||
}
|
||||
|
||||
ContentHelper::TouchBehaviorFlags
|
||||
ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPoint)
|
||||
ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const LayoutDeviceIntPoint& aPoint)
|
||||
{
|
||||
nsView *view = nsView::GetViewFor(aWidget);
|
||||
nsIFrame *viewFrame = view->GetFrame();
|
||||
|
||||
nsPoint relativePoint =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(
|
||||
aWidget, LayoutDeviceIntPoint::FromUntyped(aPoint), viewFrame);
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, viewFrame);
|
||||
|
||||
nsIFrame *target = nsLayoutUtils::GetFrameForPoint(viewFrame, relativePoint, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
|
||||
nsIScrollableFrame *nearestScrollableParent = nsLayoutUtils::GetNearestScrollableFrame(target, 0);
|
||||
|
||||
@@ -30,10 +30,10 @@ public:
|
||||
* touch-action css property value from it according the rules specified in the spec:
|
||||
* http://www.w3.org/TR/pointerevents/#the-touch-action-css-property.
|
||||
*/
|
||||
static TouchBehaviorFlags GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPoint);
|
||||
static TouchBehaviorFlags GetAllowedTouchBehavior(nsIWidget* aWidget, const LayoutDeviceIntPoint& aPoint);
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /*__mozilla_widget_ContentHelper_h__ */
|
||||
#endif /*__mozilla_widget_ContentHelper_h__ */
|
||||
|
||||
+32
-1
@@ -17,6 +17,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/TextComposition.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "PuppetWidget.h"
|
||||
#include "nsIWidgetListener.h"
|
||||
|
||||
@@ -327,6 +328,28 @@ PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
PuppetWidget::DispatchInputEvent(WidgetInputEvent* aEvent)
|
||||
{
|
||||
if (!mTabChild) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
switch (aEvent->mClass) {
|
||||
case eMouseEventClass:
|
||||
unused <<
|
||||
mTabChild->SendDispatchMouseEvent(*aEvent->AsMouseEvent());
|
||||
break;
|
||||
case eKeyboardEventClass:
|
||||
unused <<
|
||||
mTabChild->SendDispatchKeyboardEvent(*aEvent->AsKeyboardEvent());
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unsupported event type");
|
||||
}
|
||||
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
PuppetWidget::DispatchAPZAwareEvent(WidgetInputEvent* aEvent)
|
||||
@@ -343,7 +366,8 @@ PuppetWidget::DispatchAPZAwareEvent(WidgetInputEvent* aEvent)
|
||||
|
||||
switch (aEvent->mClass) {
|
||||
case eWheelEventClass:
|
||||
mTabChild->SendSynthesizedMouseWheelEvent(*aEvent->AsWheelEvent());
|
||||
unused <<
|
||||
mTabChild->SendDispatchWheelEvent(*aEvent->AsWheelEvent());
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unsupported event type");
|
||||
@@ -992,6 +1016,13 @@ PuppetWidget::GetWindowPosition()
|
||||
return nsIntPoint(winX, winY);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
PuppetWidget::GetScreenBounds(nsIntRect &aRect) {
|
||||
aRect.MoveTo(LayoutDeviceIntPoint::ToUntyped(WidgetToScreenOffset()));
|
||||
aRect.SizeTo(mBounds.Size());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PuppetScreen::PuppetScreen(void *nativeScreen)
|
||||
{
|
||||
}
|
||||
|
||||
+13
-5
@@ -78,7 +78,7 @@ public:
|
||||
int32_t* aY) override
|
||||
{ *aX = kMaxDimension; *aY = kMaxDimension; return NS_OK; }
|
||||
|
||||
// We're always at <0, 0>, and so ignore move requests.
|
||||
// Widget position is controlled by the parent process via TabChild.
|
||||
NS_IMETHOD Move(double aX, double aY) override
|
||||
{ return NS_OK; }
|
||||
|
||||
@@ -90,8 +90,14 @@ public:
|
||||
double aWidth,
|
||||
double aHeight,
|
||||
bool aRepaint) override
|
||||
// (we're always at <0, 0>)
|
||||
{ return Resize(aWidth, aHeight, aRepaint); }
|
||||
{
|
||||
if (mBounds.x != aX || mBounds.y != aY) {
|
||||
NotifyWindowMoved(aX, aY);
|
||||
}
|
||||
mBounds.x = aX;
|
||||
mBounds.y = aY;
|
||||
return Resize(aWidth, aHeight, aRepaint);
|
||||
}
|
||||
|
||||
// XXX/cjones: copying gtk behavior here; unclear what disabling a
|
||||
// widget is supposed to entail
|
||||
@@ -121,14 +127,14 @@ public:
|
||||
NS_IMETHOD SetTitle(const nsAString& aTitle) override
|
||||
{ return NS_ERROR_UNEXPECTED; }
|
||||
|
||||
// PuppetWidgets are always at <0, 0>.
|
||||
virtual mozilla::LayoutDeviceIntPoint WidgetToScreenOffset() override
|
||||
{ return mozilla::LayoutDeviceIntPoint(0, 0); }
|
||||
{ return LayoutDeviceIntPoint::FromUntyped(GetWindowPosition() + GetChromeDimensions()); }
|
||||
|
||||
void InitEvent(WidgetGUIEvent& aEvent, nsIntPoint* aPoint = nullptr);
|
||||
|
||||
NS_IMETHOD DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override;
|
||||
nsEventStatus DispatchAPZAwareEvent(WidgetInputEvent* aEvent) override;
|
||||
nsEventStatus DispatchInputEvent(WidgetInputEvent* aEvent) override;
|
||||
|
||||
NS_IMETHOD CaptureRollupEvents(nsIRollupListener* aListener,
|
||||
bool aDoCapture) override
|
||||
@@ -197,6 +203,8 @@ public:
|
||||
// Get the screen position of the application window.
|
||||
nsIntPoint GetWindowPosition();
|
||||
|
||||
NS_IMETHOD GetScreenBounds(nsIntRect &aRect) override;
|
||||
|
||||
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
|
||||
int32_t aPanelX, int32_t aPanelY,
|
||||
nsString& aCommitted) override;
|
||||
|
||||
@@ -124,7 +124,16 @@ TextEventDispatcher::DispatchEvent(nsIWidget* aWidget,
|
||||
nsRefPtr<TextEventDispatcher> kungFuDeathGrip(this);
|
||||
nsCOMPtr<nsIWidget> widget(aWidget);
|
||||
mDispatchingEvent++;
|
||||
nsresult rv = widget->DispatchEvent(&aEvent, aStatus);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (aEvent.AsInputEvent() &&
|
||||
(!aEvent.mFlags.mIsSynthesizedForTests || gfxPrefs::TestEventsAsyncEnabled()))
|
||||
{
|
||||
aStatus = widget->DispatchInputEvent(aEvent.AsInputEvent());
|
||||
} else {
|
||||
rv = widget->DispatchEvent(&aEvent, aStatus);
|
||||
}
|
||||
|
||||
mDispatchingEvent--;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1284,6 +1284,9 @@ void nsCocoaWindow::EnteredFullScreen(bool aFullScreen)
|
||||
mInFullScreenTransition = false;
|
||||
mFullScreen = aFullScreen;
|
||||
DispatchSizeModeEvent();
|
||||
if (mWidgetListener) {
|
||||
mWidgetListener->FullscreenChanged(aFullScreen);
|
||||
}
|
||||
}
|
||||
|
||||
NS_METHOD nsCocoaWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
|
||||
|
||||
@@ -635,6 +635,10 @@ nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*)
|
||||
sVirtualBounds.width, sVirtualBounds.height,
|
||||
/*repaint*/true);
|
||||
}
|
||||
|
||||
if (nsIWidgetListener* listener = GetWidgetListener()) {
|
||||
listener->FullscreenChanged(aFullScreen);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
+20
-23
@@ -2538,8 +2538,7 @@ nsWindow::OnEnterNotifyEvent(GdkEventCrossing *aEvent)
|
||||
|
||||
LOG(("OnEnterNotify: %p\n", (void *)this));
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
DispatchInputEvent(&event);
|
||||
}
|
||||
|
||||
// XXX Is this the right test for embedding cases?
|
||||
@@ -2583,8 +2582,7 @@ nsWindow::OnLeaveNotifyEvent(GdkEventCrossing *aEvent)
|
||||
|
||||
LOG(("OnLeaveNotify: %p\n", (void *)this));
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
DispatchInputEvent(&event);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2662,8 +2660,7 @@ nsWindow::OnMotionNotifyEvent(GdkEventMotion *aEvent)
|
||||
|
||||
KeymapWrapper::InitInputEvent(event, modifierState);
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
DispatchInputEvent(&event);
|
||||
}
|
||||
|
||||
// If the automatic pointer grab on ButtonPress has deactivated before
|
||||
@@ -2713,8 +2710,7 @@ nsWindow::DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent)
|
||||
WidgetMouseEvent synthEvent(true, NS_MOUSE_BUTTON_UP, this,
|
||||
WidgetMouseEvent::eSynthesized);
|
||||
synthEvent.button = buttonType;
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&synthEvent, status);
|
||||
DispatchInputEvent(&synthEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2780,8 +2776,6 @@ nsWindow::OnButtonPressEvent(GdkEventButton *aEvent)
|
||||
{
|
||||
LOG(("Button %u press on %p\n", aEvent->button, (void *)this));
|
||||
|
||||
nsEventStatus status;
|
||||
|
||||
// If you double click in GDK, it will actually generate a second
|
||||
// GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
|
||||
// different than the DOM spec. GDK puts this in the queue
|
||||
@@ -2844,7 +2838,7 @@ nsWindow::OnButtonPressEvent(GdkEventButton *aEvent)
|
||||
InitButtonEvent(event, aEvent);
|
||||
event.pressure = mLastMotionPressure;
|
||||
|
||||
DispatchEvent(&event, status);
|
||||
DispatchInputEvent(&event);
|
||||
|
||||
// right menu click on linux should also pop up a context menu
|
||||
if (domButton == WidgetMouseEvent::eRightButton &&
|
||||
@@ -2853,7 +2847,7 @@ nsWindow::OnButtonPressEvent(GdkEventButton *aEvent)
|
||||
WidgetMouseEvent::eReal);
|
||||
InitButtonEvent(contextMenuEvent, aEvent);
|
||||
contextMenuEvent.pressure = mLastMotionPressure;
|
||||
DispatchEvent(&contextMenuEvent, status);
|
||||
DispatchInputEvent(&contextMenuEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2887,8 +2881,7 @@ nsWindow::OnButtonReleaseEvent(GdkEventButton *aEvent)
|
||||
gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
|
||||
event.pressure = pressure ? pressure : mLastMotionPressure;
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
DispatchInputEvent(&event);
|
||||
mLastMotionPressure = pressure;
|
||||
}
|
||||
|
||||
@@ -3011,10 +3004,9 @@ nsWindow::DispatchKeyDownEvent(GdkEventKey *aEvent, bool *aCancelled)
|
||||
}
|
||||
|
||||
// send the key down event
|
||||
nsEventStatus status;
|
||||
WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this);
|
||||
KeymapWrapper::InitKeyEvent(downEvent, aEvent);
|
||||
DispatchEvent(&downEvent, status);
|
||||
nsEventStatus status = DispatchInputEvent(&downEvent);
|
||||
*aCancelled = (status == nsEventStatus_eConsumeNoDefault);
|
||||
return true;
|
||||
}
|
||||
@@ -3124,14 +3116,14 @@ nsWindow::OnKeyPressEvent(GdkEventKey *aEvent)
|
||||
contextMenuEvent.time = aEvent->time;
|
||||
contextMenuEvent.clickCount = 1;
|
||||
KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
|
||||
DispatchEvent(&contextMenuEvent, status);
|
||||
status = DispatchInputEvent(&contextMenuEvent);
|
||||
}
|
||||
else {
|
||||
// If the character code is in the BMP, send the key press event.
|
||||
// Otherwise, send a compositionchange event with the equivalent UTF-16
|
||||
// string.
|
||||
if (IS_IN_BMP(event.charCode)) {
|
||||
DispatchEvent(&event, status);
|
||||
status = DispatchInputEvent(&event);
|
||||
}
|
||||
else {
|
||||
WidgetCompositionEvent compositionChangeEvent(
|
||||
@@ -3167,8 +3159,7 @@ nsWindow::OnKeyReleaseEvent(GdkEventKey *aEvent)
|
||||
WidgetKeyboardEvent event(true, NS_KEY_UP, this);
|
||||
KeymapWrapper::InitKeyEvent(event, aEvent);
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
nsEventStatus status = DispatchInputEvent(&event);
|
||||
|
||||
// If the event was consumed, return.
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
@@ -3317,6 +3308,7 @@ nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent)
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasInFullscreen = mSizeState == nsSizeMode_Fullscreen;
|
||||
if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
|
||||
LOG(("\tIconified\n"));
|
||||
mSizeState = nsSizeMode_Minimized;
|
||||
@@ -3343,8 +3335,14 @@ nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent)
|
||||
#endif //ACCESSIBILITY
|
||||
}
|
||||
|
||||
if (mWidgetListener)
|
||||
if (mWidgetListener) {
|
||||
mWidgetListener->SizeModeChanged(mSizeState);
|
||||
|
||||
bool isInFullscreen = mSizeState == nsSizeMode_Fullscreen;
|
||||
if (isInFullscreen != wasInFullscreen) {
|
||||
mWidgetListener->FullscreenChanged(isInFullscreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3386,8 +3384,7 @@ nsWindow::DispatchDragEvent(uint32_t aMsg, const nsIntPoint& aRefPoint,
|
||||
event.refPoint = LayoutDeviceIntPoint::FromUntyped(aRefPoint);
|
||||
event.time = aTime;
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
DispatchInputEvent(&event);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -918,6 +918,23 @@ private:
|
||||
nsRefPtr<APZCTreeManager> mTreeManager;
|
||||
};
|
||||
|
||||
class ChromeProcessSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback {
|
||||
public:
|
||||
explicit ChromeProcessSetAllowedTouchBehaviorCallback(APZCTreeManager* aTreeManager)
|
||||
: mTreeManager(aTreeManager)
|
||||
{}
|
||||
|
||||
void Run(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) const override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
|
||||
mTreeManager.get(), &APZCTreeManager::SetAllowedTouchBehavior,
|
||||
aInputBlockId, aFlags));
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<APZCTreeManager> mTreeManager;
|
||||
};
|
||||
|
||||
class ChromeProcessContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback {
|
||||
public:
|
||||
explicit ChromeProcessContentReceivedInputBlockCallback(APZCTreeManager* aTreeManager)
|
||||
@@ -946,6 +963,7 @@ void nsBaseWidget::ConfigureAPZCTreeManager()
|
||||
mAPZEventState = new APZEventState(this,
|
||||
new ChromeProcessContentReceivedInputBlockCallback(mAPZC));
|
||||
mSetTargetAPZCCallback = new ChromeProcessSetTargetAPZCCallback(mAPZC);
|
||||
mSetAllowedTouchBehaviorCallback = new ChromeProcessSetAllowedTouchBehaviorCallback(mAPZC);
|
||||
|
||||
nsRefPtr<GeckoContentController> controller = CreateRootContentController();
|
||||
if (controller) {
|
||||
@@ -982,6 +1000,10 @@ nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
|
||||
// call into APZEventState::Process*Event() as well.
|
||||
if (WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent()) {
|
||||
if (touchEvent->message == NS_TOUCH_START) {
|
||||
if (gfxPrefs::TouchActionEnabled()) {
|
||||
APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(this, *touchEvent,
|
||||
aInputBlockId, mSetAllowedTouchBehaviorCallback);
|
||||
}
|
||||
APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(), *aEvent,
|
||||
aGuid, aInputBlockId, mSetTargetAPZCCallback);
|
||||
}
|
||||
@@ -996,6 +1018,21 @@ nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
|
||||
return status;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
nsBaseWidget::DispatchInputEvent(WidgetInputEvent* aEvent)
|
||||
{
|
||||
if (mAPZC) {
|
||||
nsEventStatus result = mAPZC->ReceiveInputEvent(*aEvent, nullptr, nullptr);
|
||||
if (result == nsEventStatus_eConsumeNoDefault) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(aEvent, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
nsBaseWidget::DispatchAPZAwareEvent(WidgetInputEvent* aEvent)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ class GeckoContentController;
|
||||
class APZEventState;
|
||||
struct ScrollableLayerGuid;
|
||||
struct SetTargetAPZCCallback;
|
||||
struct SetAllowedTouchBehaviorCallback;
|
||||
}
|
||||
|
||||
class CompositorVsyncDispatcher;
|
||||
@@ -95,6 +96,7 @@ protected:
|
||||
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
|
||||
typedef mozilla::layers::APZEventState APZEventState;
|
||||
typedef mozilla::layers::SetTargetAPZCCallback SetTargetAPZCCallback;
|
||||
typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback;
|
||||
typedef mozilla::ScreenRotation ScreenRotation;
|
||||
|
||||
virtual ~nsBaseWidget();
|
||||
@@ -231,6 +233,10 @@ public:
|
||||
NS_IMETHOD UnregisterTouchWindow() override;
|
||||
NS_IMETHOD_(TextEventDispatcher*) GetTextEventDispatcher() override final;
|
||||
|
||||
// Helper function for dispatching events which are not processed by APZ,
|
||||
// but need to be transformed by APZ.
|
||||
nsEventStatus DispatchInputEvent(mozilla::WidgetInputEvent* aEvent) override;
|
||||
|
||||
// Dispatch an event that must be first be routed through APZ.
|
||||
nsEventStatus DispatchAPZAwareEvent(mozilla::WidgetInputEvent* aEvent) override;
|
||||
|
||||
@@ -453,6 +459,7 @@ protected:
|
||||
nsRefPtr<APZCTreeManager> mAPZC;
|
||||
nsRefPtr<APZEventState> mAPZEventState;
|
||||
nsRefPtr<SetTargetAPZCCallback> mSetTargetAPZCCallback;
|
||||
nsRefPtr<SetAllowedTouchBehaviorCallback> mSetAllowedTouchBehaviorCallback;
|
||||
nsRefPtr<WidgetShutdownObserver> mShutdownObserver;
|
||||
nsRefPtr<TextEventDispatcher> mTextEventDispatcher;
|
||||
nsCursor mCursor;
|
||||
|
||||
@@ -1695,6 +1695,13 @@ class nsIWidget : public nsISupports {
|
||||
*/
|
||||
virtual nsEventStatus DispatchAPZAwareEvent(mozilla::WidgetInputEvent* aEvent) = 0;
|
||||
|
||||
/**
|
||||
* Dispatches an event that must be transformed by APZ first, but is not
|
||||
* actually handled by APZ. If invoked in the child process, it is
|
||||
* forwarded to the parent process synchronously.
|
||||
*/
|
||||
virtual nsEventStatus DispatchInputEvent(mozilla::WidgetInputEvent* aEvent) = 0;
|
||||
|
||||
/**
|
||||
* Enables the dropping of files to a widget (XXX this is temporary)
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user