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:
2020-04-27 17:35:47 +08:00
parent 27046e3600
commit f3297ff565
104 changed files with 3571 additions and 2087 deletions
+6 -22
View File
@@ -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")
+17 -7
View File
@@ -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;
}
+51 -19
View File
@@ -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();
});
}
+7 -1
View File
@@ -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);
};
+8 -4
View File
@@ -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
+8 -4
View File
@@ -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;
}
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+4 -5
View File
@@ -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;
+9 -3
View File
@@ -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() {}
+44
View File
@@ -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;
+1
View File
@@ -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);
+96 -8
View File
@@ -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();
}
+10
View File
@@ -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();
}
+5
View File
@@ -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.
+164 -3
View File
@@ -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)
+60 -2
View File
@@ -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;
};
/**
+34 -5
View File
@@ -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());
}
+12 -1
View File
@@ -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();
+10 -1
View File
@@ -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
+21
View File
@@ -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;
+6
View File
@@ -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);
+95 -62
View File
@@ -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));
+21
View File
@@ -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
};
+23 -28
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+254 -51
View File
@@ -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");
+135
View File
@@ -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();
+9 -2
View File
@@ -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
+4 -2
View File
@@ -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));
+8
View File
@@ -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
View File
@@ -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());
+2 -5
View File
@@ -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;
}
+5 -7
View File
@@ -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
+43 -43
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
/*
+4 -2
View File
@@ -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
View File
@@ -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 = &REGS.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
View File
@@ -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
+10
View File
@@ -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
View File
@@ -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);
+10 -1
View File
@@ -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,
+4 -3
View File
@@ -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;
+1
View File
@@ -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) {
+25 -2
View File
@@ -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;
}
+1
View File
@@ -8,6 +8,7 @@
#define mozilla_JustificationUtils_h_
#include "mozilla/Attributes.h"
#include "nsCoord.h"
namespace mozilla {
+3
View File
@@ -40,6 +40,9 @@ EXPORTS += [
'RubyUtils.h',
'ScrollbarActivity.h',
'Selection.h',
]
EXPORTS.mozilla += [
'WritingModes.h',
]
+3 -4
View File
@@ -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;
+2 -2
View File
@@ -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
View File
@@ -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 -6
View File
@@ -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;
+4 -4
View File
@@ -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;
+5 -4
View File
@@ -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;
+2 -1
View File
@@ -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;
+6 -4
View File
@@ -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;
+3 -2
View File
@@ -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;
+3 -2
View File
@@ -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;
-21
View File
@@ -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));
}
-2
View File
@@ -130,8 +130,6 @@ public:
*/
bool PassPointerEventsToChildren();
nsIntPoint GetChromeDisplacement();
protected:
friend class AsyncFrameInit;
+25
View File
@@ -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,
+4
View File
@@ -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,
+5 -5
View File
@@ -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 {
+6 -5
View File
@@ -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) {
+1 -21
View File
@@ -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"/>
+1 -2
View File
@@ -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();
},
+2 -3
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+10 -1
View File
@@ -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;
}
+3
View File
@@ -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)
+4
View File
@@ -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
View File
@@ -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
+37
View File
@@ -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)
{
+7
View File
@@ -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;
+7
View File
@@ -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